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);
104 #define GST_CAT_DEFAULT qtdemux_debug
106 typedef struct _QtDemuxSegment QtDemuxSegment;
107 typedef struct _QtDemuxSample QtDemuxSample;
109 typedef struct _QtDemuxCencSampleSetInfo QtDemuxCencSampleSetInfo;
111 struct _QtDemuxSample
114 gint32 pts_offset; /* Add this value to timestamp to get the pts */
116 guint64 timestamp; /* DTS In mov time */
117 guint32 duration; /* In mov time */
118 gboolean keyframe; /* TRUE when this packet is a keyframe */
121 /* Macros for converting to/from timescale */
122 #define QTSTREAMTIME_TO_GSTTIME(stream, value) (gst_util_uint64_scale((value), GST_SECOND, (stream)->timescale))
123 #define GSTTIME_TO_QTSTREAMTIME(stream, value) (gst_util_uint64_scale((value), (stream)->timescale, GST_SECOND))
125 #define QTTIME_TO_GSTTIME(qtdemux, value) (gst_util_uint64_scale((value), GST_SECOND, (qtdemux)->timescale))
126 #define GSTTIME_TO_QTTIME(qtdemux, value) (gst_util_uint64_scale((value), (qtdemux)->timescale, GST_SECOND))
128 /* timestamp is the DTS */
129 #define QTSAMPLE_DTS(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp))
130 /* timestamp + offset + cslg_shift is the outgoing PTS */
131 #define QTSAMPLE_PTS(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp + (stream)->cslg_shift + (sample)->pts_offset))
132 /* timestamp + offset is the PTS used for internal seek calcuations */
133 #define QTSAMPLE_PTS_NO_CSLG(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp + (sample)->pts_offset))
134 /* timestamp + duration - dts is the duration */
135 #define QTSAMPLE_DUR_DTS(stream, sample, dts) (QTSTREAMTIME_TO_GSTTIME ((stream), (sample)->timestamp + (sample)->duration) - (dts))
137 #define QTSAMPLE_KEYFRAME(stream,sample) ((stream)->all_keyframe || (sample)->keyframe)
140 * Quicktime has tracks and segments. A track is a continuous piece of
141 * multimedia content. The track is not always played from start to finish but
142 * instead, pieces of the track are 'cut out' and played in sequence. This is
143 * what the segments do.
145 * Inside the track we have keyframes (K) and delta frames. The track has its
146 * own timing, which starts from 0 and extends to end. The position in the track
147 * is called the media_time.
149 * The segments now describe the pieces that should be played from this track
150 * and are basically tuples of media_time/duration/rate entries. We can have
151 * multiple segments and they are all played after one another. An example:
153 * segment 1: media_time: 1 second, duration: 1 second, rate 1
154 * segment 2: media_time: 3 second, duration: 2 second, rate 2
156 * To correctly play back this track, one must play: 1 second of media starting
157 * from media_time 1 followed by 2 seconds of media starting from media_time 3
160 * Each of the segments will be played at a specific time, the first segment at
161 * time 0, the second one after the duration of the first one, etc.. Note that
162 * the time in resulting playback is not identical to the media_time of the
165 * Visually, assuming the track has 4 second of media_time:
168 * .-----------------------------------------------------------.
169 * track: | K.....K.........K........K.......K.......K...........K... |
170 * '-----------------------------------------------------------'
172 * .------------^ ^ .----------^ ^
173 * / .-------------' / .------------------'
175 * .--------------. .--------------.
176 * | segment 1 | | segment 2 |
177 * '--------------' '--------------'
179 * The challenge here is to cut out the right pieces of the track for each of
180 * the playback segments. This fortunately can easily be done with the SEGMENT
181 * events of GStreamer.
183 * For playback of segment 1, we need to provide the decoder with the keyframe
184 * (a), in the above figure, but we must instruct it only to output the decoded
185 * data between second 1 and 2. We do this with a SEGMENT event for 1 to 2, time
186 * position set to the time of the segment: 0.
188 * We then proceed to push data from keyframe (a) to frame (b). The decoder
189 * decodes but clips all before media_time 1.
191 * After finishing a segment, we push out a new SEGMENT event with the clipping
192 * boundaries of the new data.
194 * This is a good usecase for the GStreamer accumulated SEGMENT events.
197 struct _QtDemuxSegment
199 /* global time and duration, all gst time */
201 GstClockTime stop_time;
202 GstClockTime duration;
203 /* media time of trak, all gst time */
204 GstClockTime media_start;
205 GstClockTime media_stop;
207 /* Media start time in trak timescale units */
208 guint32 trak_media_start;
211 #define QTSEGMENT_IS_EMPTY(s) ((s)->media_start == GST_CLOCK_TIME_NONE)
213 /* Used with fragmented MP4 files (mfra atom) */
218 } QtDemuxRandomAccessEntry;
220 typedef struct _QtDemuxStreamStsdEntry
231 /* Numerator/denominator framerate */
234 GstVideoColorimetry colorimetry;
235 guint16 bits_per_sample;
236 guint16 color_table_id;
237 GstMemory *rgb8_palette;
238 guint interlace_mode;
244 guint samples_per_packet;
245 guint samples_per_frame;
246 guint bytes_per_packet;
247 guint bytes_per_sample;
248 guint bytes_per_frame;
251 /* if we use chunks or samples */
255 } QtDemuxStreamStsdEntry;
257 #define CUR_STREAM(s) (&((s)->stsd_entries[(s)->cur_stsd_entry_index]))
259 struct _QtDemuxStream
263 QtDemuxStreamStsdEntry *stsd_entries;
264 guint stsd_entries_length;
265 guint cur_stsd_entry_index;
270 gboolean new_caps; /* If TRUE, caps need to be generated (by
271 * calling _configure_stream()) This happens
272 * for MSS and fragmented streams */
274 gboolean new_stream; /* signals that a stream_start is required */
275 gboolean on_keyframe; /* if this stream last pushed buffer was a
276 * keyframe. This is important to identify
277 * where to stop pushing buffers after a
278 * segment stop time */
280 /* if the stream has a redirect URI in its headers, we store it here */
287 guint64 duration; /* in timescale units */
291 gchar lang_id[4]; /* ISO 639-2T language code */
295 QtDemuxSample *samples;
296 gboolean all_keyframe; /* TRUE when all samples are keyframes (no stss) */
297 guint32 first_duration; /* duration in timescale of first sample, used for figuring out
299 guint32 n_samples_moof; /* sample count in a moof */
300 guint64 duration_moof; /* duration in timescale of a moof, used for figure out
301 * the framerate of fragmented format stream */
302 guint64 duration_last_moof;
304 guint32 offset_in_sample; /* Offset in the current sample, used for
305 * streams which have got exceedingly big
306 * sample size (such as 24s of raw audio).
307 * Only used when max_buffer_size is non-NULL */
308 guint32 max_buffer_size; /* Maximum allowed size for output buffers.
309 * Currently only set for raw audio streams*/
317 gboolean use_allocator;
318 GstAllocator *allocator;
319 GstAllocationParams params;
323 /* when a discontinuity is pending */
326 /* list of buffers to push first */
329 /* if we need to clip this buffer. This is only needed for uncompressed
333 /* buffer needs some custom processing, e.g. subtitles */
334 gboolean need_process;
336 /* current position */
337 guint32 segment_index;
338 guint32 sample_index;
339 GstClockTime time_position; /* in gst time */
340 guint64 accumulated_base;
342 /* the Gst segment we are processing out, used for clipping */
345 /* quicktime segments */
347 QtDemuxSegment *segments;
348 gboolean dummy_segment;
353 GstTagList *stream_tags;
354 gboolean send_global_tags;
356 GstEvent *pending_event;
366 gboolean chunks_are_samples; /* TRUE means treat chunks as samples */
370 GstByteReader co_chunk;
372 guint32 current_chunk;
374 guint32 samples_per_chunk;
375 guint32 stsd_sample_description_id;
376 guint32 stco_sample_index;
378 guint32 sample_size; /* 0 means variable sizes are stored in stsz */
381 guint32 n_samples_per_chunk;
382 guint32 stsc_chunk_index;
383 guint32 stsc_sample_index;
384 guint64 chunk_offset;
387 guint32 stts_samples;
388 guint32 n_sample_times;
389 guint32 stts_sample_index;
391 guint32 stts_duration;
393 gboolean stss_present;
394 guint32 n_sample_syncs;
397 gboolean stps_present;
398 guint32 n_sample_partial_syncs;
400 QtDemuxRandomAccessEntry *ra_entries;
403 const QtDemuxRandomAccessEntry *pending_seek;
406 gboolean ctts_present;
407 guint32 n_composition_times;
409 guint32 ctts_sample_index;
417 gboolean parsed_trex;
418 guint32 def_sample_description_index; /* index is 1-based */
419 guint32 def_sample_duration;
420 guint32 def_sample_size;
421 guint32 def_sample_flags;
425 /* stereoscopic video streams */
426 GstVideoMultiviewMode multiview_mode;
427 GstVideoMultiviewFlags multiview_flags;
429 /* protected streams */
431 guint32 protection_scheme_type;
432 guint32 protection_scheme_version;
433 gpointer protection_scheme_info; /* specific to the protection scheme */
434 GQueue protection_scheme_event_queue;
437 /* Contains properties and cryptographic info for a set of samples from a
438 * track protected using Common Encryption (cenc) */
439 struct _QtDemuxCencSampleSetInfo
441 GstStructure *default_properties;
443 /* @crypto_info holds one GstStructure per sample */
444 GPtrArray *crypto_info;
448 qt_demux_state_string (enum QtDemuxState state)
451 case QTDEMUX_STATE_INITIAL:
453 case QTDEMUX_STATE_HEADER:
455 case QTDEMUX_STATE_MOVIE:
457 case QTDEMUX_STATE_BUFFER_MDAT:
458 return "<BUFFER_MDAT>";
464 static GNode *qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc);
465 static GNode *qtdemux_tree_get_child_by_type_full (GNode * node,
466 guint32 fourcc, GstByteReader * parser);
467 static GNode *qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc);
468 static GNode *qtdemux_tree_get_sibling_by_type_full (GNode * node,
469 guint32 fourcc, GstByteReader * parser);
471 static GstFlowReturn qtdemux_add_fragmented_samples (GstQTDemux * qtdemux);
473 static GstStaticPadTemplate gst_qtdemux_sink_template =
474 GST_STATIC_PAD_TEMPLATE ("sink",
477 GST_STATIC_CAPS ("video/quicktime; video/mj2; audio/x-m4a; "
481 static GstStaticPadTemplate gst_qtdemux_videosrc_template =
482 GST_STATIC_PAD_TEMPLATE ("video_%u",
485 GST_STATIC_CAPS_ANY);
487 static GstStaticPadTemplate gst_qtdemux_audiosrc_template =
488 GST_STATIC_PAD_TEMPLATE ("audio_%u",
491 GST_STATIC_CAPS_ANY);
493 static GstStaticPadTemplate gst_qtdemux_subsrc_template =
494 GST_STATIC_PAD_TEMPLATE ("subtitle_%u",
497 GST_STATIC_CAPS_ANY);
499 #define gst_qtdemux_parent_class parent_class
500 G_DEFINE_TYPE (GstQTDemux, gst_qtdemux, GST_TYPE_ELEMENT);
502 static void gst_qtdemux_dispose (GObject * object);
505 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
506 GstClockTime media_time);
508 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
509 QtDemuxStream * str, gint64 media_offset);
512 static void gst_qtdemux_set_index (GstElement * element, GstIndex * index);
513 static GstIndex *gst_qtdemux_get_index (GstElement * element);
515 static GstStateChangeReturn gst_qtdemux_change_state (GstElement * element,
516 GstStateChange transition);
517 static gboolean qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent);
518 static gboolean qtdemux_sink_activate_mode (GstPad * sinkpad,
519 GstObject * parent, GstPadMode mode, gboolean active);
521 static void gst_qtdemux_loop (GstPad * pad);
522 static GstFlowReturn gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent,
524 static gboolean gst_qtdemux_handle_sink_event (GstPad * pad, GstObject * parent,
526 static gboolean gst_qtdemux_setcaps (GstQTDemux * qtdemux, GstCaps * caps);
527 static gboolean gst_qtdemux_configure_stream (GstQTDemux * qtdemux,
528 QtDemuxStream * stream);
529 static void gst_qtdemux_stream_check_and_change_stsd_index (GstQTDemux * demux,
530 QtDemuxStream * stream);
531 static GstFlowReturn gst_qtdemux_process_adapter (GstQTDemux * demux,
534 static gboolean qtdemux_parse_moov (GstQTDemux * qtdemux,
535 const guint8 * buffer, guint length);
536 static gboolean qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node,
537 const guint8 * buffer, guint length);
538 static gboolean qtdemux_parse_tree (GstQTDemux * qtdemux);
539 static void qtdemux_parse_udta (GstQTDemux * qtdemux, GstTagList * taglist,
542 static void gst_qtdemux_handle_esds (GstQTDemux * qtdemux,
543 QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, GNode * esds,
545 static GstCaps *qtdemux_video_caps (GstQTDemux * qtdemux,
546 QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, guint32 fourcc,
547 const guint8 * stsd_entry_data, gchar ** codec_name);
548 static GstCaps *qtdemux_audio_caps (GstQTDemux * qtdemux,
549 QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, guint32 fourcc,
550 const guint8 * data, int len, gchar ** codec_name);
551 static GstCaps *qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
552 QtDemuxStreamStsdEntry * entry, guint32 fourcc, const guint8 * data,
553 gchar ** codec_name);
554 static GstCaps *qtdemux_generic_caps (GstQTDemux * qtdemux,
555 QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, guint32 fourcc,
556 const guint8 * stsd_entry_data, gchar ** codec_name);
558 static gboolean qtdemux_parse_samples (GstQTDemux * qtdemux,
559 QtDemuxStream * stream, guint32 n);
560 static GstFlowReturn qtdemux_expose_streams (GstQTDemux * qtdemux);
561 static void gst_qtdemux_stream_free (GstQTDemux * qtdemux,
562 QtDemuxStream * stream);
563 static void gst_qtdemux_stream_clear (GstQTDemux * qtdemux,
564 QtDemuxStream * stream);
565 static void gst_qtdemux_remove_stream (GstQTDemux * qtdemux, int index);
566 static GstFlowReturn qtdemux_prepare_streams (GstQTDemux * qtdemux);
567 static void qtdemux_do_allocation (GstQTDemux * qtdemux,
568 QtDemuxStream * stream);
569 static gboolean gst_qtdemux_activate_segment (GstQTDemux * qtdemux,
570 QtDemuxStream * stream, guint32 seg_idx, GstClockTime offset);
571 static gboolean gst_qtdemux_stream_update_segment (GstQTDemux * qtdemux,
572 QtDemuxStream * stream, gint seg_idx, GstClockTime offset,
573 GstClockTime * _start, GstClockTime * _stop);
574 static void gst_qtdemux_send_gap_for_segment (GstQTDemux * demux,
575 QtDemuxStream * stream, gint segment_index, GstClockTime pos);
577 static gboolean qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux);
578 static void check_update_duration (GstQTDemux * qtdemux, GstClockTime duration);
580 static gchar *qtdemux_uuid_bytes_to_string (gconstpointer uuid_bytes);
582 static GstStructure *qtdemux_get_cenc_sample_properties (GstQTDemux * qtdemux,
583 QtDemuxStream * stream, guint sample_index);
584 static void gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux,
586 static void qtdemux_gst_structure_free (GstStructure * gststructure);
589 gst_qtdemux_class_init (GstQTDemuxClass * klass)
591 GObjectClass *gobject_class;
592 GstElementClass *gstelement_class;
594 gobject_class = (GObjectClass *) klass;
595 gstelement_class = (GstElementClass *) klass;
597 parent_class = g_type_class_peek_parent (klass);
599 gobject_class->dispose = gst_qtdemux_dispose;
601 gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_qtdemux_change_state);
603 gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_qtdemux_set_index);
604 gstelement_class->get_index = GST_DEBUG_FUNCPTR (gst_qtdemux_get_index);
607 gst_tag_register_musicbrainz_tags ();
609 gst_element_class_add_static_pad_template (gstelement_class,
610 &gst_qtdemux_sink_template);
611 gst_element_class_add_static_pad_template (gstelement_class,
612 &gst_qtdemux_videosrc_template);
613 gst_element_class_add_static_pad_template (gstelement_class,
614 &gst_qtdemux_audiosrc_template);
615 gst_element_class_add_static_pad_template (gstelement_class,
616 &gst_qtdemux_subsrc_template);
617 gst_element_class_set_static_metadata (gstelement_class, "QuickTime demuxer",
619 "Demultiplex a QuickTime file into audio and video streams",
620 "David Schleef <ds@schleef.org>, Wim Taymans <wim@fluendo.com>");
622 GST_DEBUG_CATEGORY_INIT (qtdemux_debug, "qtdemux", 0, "qtdemux plugin");
627 gst_qtdemux_init (GstQTDemux * qtdemux)
630 gst_pad_new_from_static_template (&gst_qtdemux_sink_template, "sink");
631 gst_pad_set_activate_function (qtdemux->sinkpad, qtdemux_sink_activate);
632 gst_pad_set_activatemode_function (qtdemux->sinkpad,
633 qtdemux_sink_activate_mode);
634 gst_pad_set_chain_function (qtdemux->sinkpad, gst_qtdemux_chain);
635 gst_pad_set_event_function (qtdemux->sinkpad, gst_qtdemux_handle_sink_event);
636 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), qtdemux->sinkpad);
638 qtdemux->state = QTDEMUX_STATE_INITIAL;
639 qtdemux->pullbased = FALSE;
640 qtdemux->posted_redirect = FALSE;
641 qtdemux->neededbytes = 16;
643 qtdemux->adapter = gst_adapter_new ();
645 qtdemux->first_mdat = -1;
646 qtdemux->got_moov = FALSE;
647 qtdemux->mdatoffset = -1;
648 qtdemux->mdatbuffer = NULL;
649 qtdemux->restoredata_buffer = NULL;
650 qtdemux->restoredata_offset = -1;
651 qtdemux->fragment_start = -1;
652 qtdemux->fragment_start_offset = -1;
653 qtdemux->media_caps = NULL;
654 qtdemux->exposed = FALSE;
655 qtdemux->mss_mode = FALSE;
656 qtdemux->pending_newsegment = NULL;
657 qtdemux->upstream_format_is_time = FALSE;
658 qtdemux->have_group_id = FALSE;
659 qtdemux->group_id = G_MAXUINT;
660 qtdemux->cenc_aux_info_offset = 0;
661 qtdemux->cenc_aux_info_sizes = NULL;
662 qtdemux->cenc_aux_sample_count = 0;
663 qtdemux->protection_system_ids = NULL;
664 g_queue_init (&qtdemux->protection_event_queue);
665 gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
666 qtdemux->tag_list = gst_tag_list_new_empty ();
667 gst_tag_list_set_scope (qtdemux->tag_list, GST_TAG_SCOPE_GLOBAL);
668 qtdemux->flowcombiner = gst_flow_combiner_new ();
670 GST_OBJECT_FLAG_SET (qtdemux, GST_ELEMENT_FLAG_INDEXABLE);
674 gst_qtdemux_dispose (GObject * object)
676 GstQTDemux *qtdemux = GST_QTDEMUX (object);
678 if (qtdemux->adapter) {
679 g_object_unref (G_OBJECT (qtdemux->adapter));
680 qtdemux->adapter = NULL;
682 gst_tag_list_unref (qtdemux->tag_list);
683 gst_flow_combiner_free (qtdemux->flowcombiner);
684 g_queue_foreach (&qtdemux->protection_event_queue, (GFunc) gst_event_unref,
686 g_queue_clear (&qtdemux->protection_event_queue);
688 g_free (qtdemux->cenc_aux_info_sizes);
689 qtdemux->cenc_aux_info_sizes = NULL;
691 G_OBJECT_CLASS (parent_class)->dispose (object);
695 gst_qtdemux_post_no_playable_stream_error (GstQTDemux * qtdemux)
697 if (qtdemux->posted_redirect) {
698 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
699 (_("This file contains no playable streams.")),
700 ("no known streams found, a redirect message has been posted"));
702 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
703 (_("This file contains no playable streams.")),
704 ("no known streams found"));
709 _gst_buffer_new_wrapped (gpointer mem, gsize size, GFreeFunc free_func)
711 return gst_buffer_new_wrapped_full (free_func ? 0 : GST_MEMORY_FLAG_READONLY,
712 mem, size, 0, size, mem, free_func);
716 gst_qtdemux_pull_atom (GstQTDemux * qtdemux, guint64 offset, guint64 size,
723 if (G_UNLIKELY (size == 0)) {
725 GstBuffer *tmp = NULL;
727 ret = gst_qtdemux_pull_atom (qtdemux, offset, sizeof (guint32), &tmp);
728 if (ret != GST_FLOW_OK)
731 gst_buffer_map (tmp, &map, GST_MAP_READ);
732 size = QT_UINT32 (map.data);
733 GST_DEBUG_OBJECT (qtdemux, "size 0x%08" G_GINT64_MODIFIER "x", size);
735 gst_buffer_unmap (tmp, &map);
736 gst_buffer_unref (tmp);
739 /* Sanity check: catch bogus sizes (fuzzed/broken files) */
740 if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
741 if (qtdemux->state != QTDEMUX_STATE_MOVIE && qtdemux->got_moov) {
742 /* we're pulling header but already got most interesting bits,
743 * so never mind the rest (e.g. tags) (that much) */
744 GST_WARNING_OBJECT (qtdemux, "atom has bogus size %" G_GUINT64_FORMAT,
748 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
749 (_("This file is invalid and cannot be played.")),
750 ("atom has bogus size %" G_GUINT64_FORMAT, size));
751 return GST_FLOW_ERROR;
755 flow = gst_pad_pull_range (qtdemux->sinkpad, offset, size, buf);
757 if (G_UNLIKELY (flow != GST_FLOW_OK))
760 bsize = gst_buffer_get_size (*buf);
761 /* Catch short reads - we don't want any partial atoms */
762 if (G_UNLIKELY (bsize < size)) {
763 GST_WARNING_OBJECT (qtdemux,
764 "short read: %" G_GSIZE_FORMAT " < %" G_GUINT64_FORMAT, bsize, size);
765 gst_buffer_unref (*buf);
775 gst_qtdemux_src_convert (GstQTDemux * qtdemux, GstPad * pad,
776 GstFormat src_format, gint64 src_value, GstFormat dest_format,
780 QtDemuxStream *stream = gst_pad_get_element_private (pad);
783 if (stream->subtype != FOURCC_vide) {
788 switch (src_format) {
789 case GST_FORMAT_TIME:
790 switch (dest_format) {
791 case GST_FORMAT_BYTES:{
792 index = gst_qtdemux_find_index_linear (qtdemux, stream, src_value);
798 *dest_value = stream->samples[index].offset;
800 GST_DEBUG_OBJECT (qtdemux, "Format Conversion Time->Offset :%"
801 GST_TIME_FORMAT "->%" G_GUINT64_FORMAT,
802 GST_TIME_ARGS (src_value), *dest_value);
810 case GST_FORMAT_BYTES:
811 switch (dest_format) {
812 case GST_FORMAT_TIME:{
814 gst_qtdemux_find_index_for_given_media_offset_linear (qtdemux,
823 QTSTREAMTIME_TO_GSTTIME (stream,
824 stream->samples[index].timestamp);
825 GST_DEBUG_OBJECT (qtdemux,
826 "Format Conversion Offset->Time :%" G_GUINT64_FORMAT "->%"
827 GST_TIME_FORMAT, src_value, GST_TIME_ARGS (*dest_value));
846 gst_qtdemux_get_duration (GstQTDemux * qtdemux, GstClockTime * duration)
848 gboolean res = FALSE;
850 *duration = GST_CLOCK_TIME_NONE;
852 if (qtdemux->duration != 0 &&
853 qtdemux->duration != G_MAXINT64 && qtdemux->timescale != 0) {
854 *duration = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
857 *duration = GST_CLOCK_TIME_NONE;
864 gst_qtdemux_handle_src_query (GstPad * pad, GstObject * parent,
867 gboolean res = FALSE;
868 GstQTDemux *qtdemux = GST_QTDEMUX (parent);
870 GST_LOG_OBJECT (pad, "%s query", GST_QUERY_TYPE_NAME (query));
872 switch (GST_QUERY_TYPE (query)) {
873 case GST_QUERY_POSITION:{
876 gst_query_parse_position (query, &fmt, NULL);
877 if (fmt == GST_FORMAT_TIME
878 && GST_CLOCK_TIME_IS_VALID (qtdemux->segment.position)) {
879 gst_query_set_position (query, GST_FORMAT_TIME,
880 qtdemux->segment.position);
885 case GST_QUERY_DURATION:{
888 gst_query_parse_duration (query, &fmt, NULL);
889 if (fmt == GST_FORMAT_TIME) {
890 /* First try to query upstream */
891 res = gst_pad_query_default (pad, parent, query);
893 GstClockTime duration;
894 if (gst_qtdemux_get_duration (qtdemux, &duration) && duration > 0) {
895 gst_query_set_duration (query, GST_FORMAT_TIME, duration);
902 case GST_QUERY_CONVERT:{
903 GstFormat src_fmt, dest_fmt;
904 gint64 src_value, dest_value = 0;
906 gst_query_parse_convert (query, &src_fmt, &src_value, &dest_fmt, NULL);
908 res = gst_qtdemux_src_convert (qtdemux, pad,
909 src_fmt, src_value, dest_fmt, &dest_value);
911 gst_query_set_convert (query, src_fmt, src_value, dest_fmt, dest_value);
915 case GST_QUERY_FORMATS:
916 gst_query_set_formats (query, 2, GST_FORMAT_TIME, GST_FORMAT_BYTES);
919 case GST_QUERY_SEEKING:{
923 /* try upstream first */
924 res = gst_pad_query_default (pad, parent, query);
927 gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
928 if (fmt == GST_FORMAT_TIME) {
929 GstClockTime duration;
931 gst_qtdemux_get_duration (qtdemux, &duration);
933 if (!qtdemux->pullbased) {
936 /* we might be able with help from upstream */
938 q = gst_query_new_seeking (GST_FORMAT_BYTES);
939 if (gst_pad_peer_query (qtdemux->sinkpad, q)) {
940 gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL);
941 GST_LOG_OBJECT (qtdemux, "upstream BYTE seekable %d", seekable);
945 gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0, duration);
951 case GST_QUERY_SEGMENT:
956 format = qtdemux->segment.format;
959 gst_segment_to_stream_time (&qtdemux->segment, format,
960 qtdemux->segment.start);
961 if ((stop = qtdemux->segment.stop) == -1)
962 stop = qtdemux->segment.duration;
964 stop = gst_segment_to_stream_time (&qtdemux->segment, format, stop);
966 gst_query_set_segment (query, qtdemux->segment.rate, format, start, stop);
971 res = gst_pad_query_default (pad, parent, query);
979 gst_qtdemux_push_tags (GstQTDemux * qtdemux, QtDemuxStream * stream)
981 if (G_LIKELY (stream->pad)) {
982 GST_DEBUG_OBJECT (qtdemux, "Checking pad %s:%s for tags",
983 GST_DEBUG_PAD_NAME (stream->pad));
985 if (!gst_tag_list_is_empty (stream->stream_tags)) {
986 GST_DEBUG_OBJECT (qtdemux, "Sending tags %" GST_PTR_FORMAT,
987 stream->stream_tags);
988 gst_pad_push_event (stream->pad,
989 gst_event_new_tag (gst_tag_list_ref (stream->stream_tags)));
992 if (G_UNLIKELY (stream->send_global_tags)) {
993 GST_DEBUG_OBJECT (qtdemux, "Sending global tags %" GST_PTR_FORMAT,
995 gst_pad_push_event (stream->pad,
996 gst_event_new_tag (gst_tag_list_ref (qtdemux->tag_list)));
997 stream->send_global_tags = FALSE;
1002 /* push event on all source pads; takes ownership of the event */
1004 gst_qtdemux_push_event (GstQTDemux * qtdemux, GstEvent * event)
1007 gboolean has_valid_stream = FALSE;
1008 GstEventType etype = GST_EVENT_TYPE (event);
1010 GST_DEBUG_OBJECT (qtdemux, "pushing %s event on all source pads",
1011 GST_EVENT_TYPE_NAME (event));
1013 for (n = 0; n < qtdemux->n_streams; n++) {
1015 QtDemuxStream *stream = qtdemux->streams[n];
1016 GST_DEBUG_OBJECT (qtdemux, "pushing on pad %i", n);
1018 if ((pad = stream->pad)) {
1019 has_valid_stream = TRUE;
1021 if (etype == GST_EVENT_EOS) {
1022 /* let's not send twice */
1023 if (stream->sent_eos)
1025 stream->sent_eos = TRUE;
1028 gst_pad_push_event (pad, gst_event_ref (event));
1032 gst_event_unref (event);
1034 /* if it is EOS and there are no pads, post an error */
1035 if (!has_valid_stream && etype == GST_EVENT_EOS) {
1036 gst_qtdemux_post_no_playable_stream_error (qtdemux);
1040 /* push a pending newsegment event, if any from the streaming thread */
1042 gst_qtdemux_push_pending_newsegment (GstQTDemux * qtdemux)
1044 if (qtdemux->pending_newsegment) {
1045 gst_qtdemux_push_event (qtdemux, qtdemux->pending_newsegment);
1046 qtdemux->pending_newsegment = NULL;
1056 find_func (QtDemuxSample * s1, gint64 * media_time, gpointer user_data)
1058 if ((gint64) s1->timestamp + s1->pts_offset > *media_time)
1060 if ((gint64) s1->timestamp + s1->pts_offset == *media_time)
1066 /* find the index of the sample that includes the data for @media_time using a
1067 * binary search. Only to be called in optimized cases of linear search below.
1069 * Returns the index of the sample.
1072 gst_qtdemux_find_index (GstQTDemux * qtdemux, QtDemuxStream * str,
1075 QtDemuxSample *result;
1078 /* convert media_time to mov format */
1080 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
1082 result = gst_util_array_binary_search (str->samples, str->stbl_index + 1,
1083 sizeof (QtDemuxSample), (GCompareDataFunc) find_func,
1084 GST_SEARCH_MODE_BEFORE, &media_time, NULL);
1086 if (G_LIKELY (result))
1087 index = result - str->samples;
1096 /* find the index of the sample that includes the data for @media_offset using a
1099 * Returns the index of the sample.
1102 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
1103 QtDemuxStream * str, gint64 media_offset)
1105 QtDemuxSample *result = str->samples;
1108 if (result == NULL || str->n_samples == 0)
1111 if (media_offset == result->offset)
1115 while (index < str->n_samples - 1) {
1116 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
1119 if (media_offset < result->offset)
1130 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
1135 /* find the index of the sample that includes the data for @media_time using a
1136 * linear search, and keeping in mind that not all samples may have been parsed
1137 * yet. If possible, it will delegate to binary search.
1139 * Returns the index of the sample.
1142 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
1143 GstClockTime media_time)
1147 QtDemuxSample *sample;
1149 /* convert media_time to mov format */
1151 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
1153 sample = str->samples;
1154 if (mov_time == sample->timestamp + sample->pts_offset)
1157 /* use faster search if requested time in already parsed range */
1158 sample = str->samples + str->stbl_index;
1159 if (str->stbl_index >= 0 &&
1160 mov_time <= (sample->timestamp + sample->pts_offset))
1161 return gst_qtdemux_find_index (qtdemux, str, media_time);
1163 while (index < str->n_samples - 1) {
1164 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
1167 sample = str->samples + index + 1;
1168 if (mov_time < (sample->timestamp + sample->pts_offset))
1178 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
1183 /* find the index of the keyframe needed to decode the sample at @index
1184 * of stream @str, or of a subsequent keyframe (depending on @next)
1186 * Returns the index of the keyframe.
1189 gst_qtdemux_find_keyframe (GstQTDemux * qtdemux, QtDemuxStream * str,
1190 guint32 index, gboolean next)
1192 guint32 new_index = index;
1194 if (index >= str->n_samples) {
1195 new_index = str->n_samples;
1199 /* all keyframes, return index */
1200 if (str->all_keyframe) {
1205 /* else search until we have a keyframe */
1206 while (new_index < str->n_samples) {
1207 if (next && !qtdemux_parse_samples (qtdemux, str, new_index))
1210 if (str->samples[new_index].keyframe)
1222 if (new_index == str->n_samples) {
1223 GST_DEBUG_OBJECT (qtdemux, "no next keyframe");
1228 GST_DEBUG_OBJECT (qtdemux, "searching for keyframe index %s index %u "
1229 "gave %u", next ? "after" : "before", index, new_index);
1236 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", new_index);
1241 /* find the segment for @time_position for @stream
1243 * Returns the index of the segment containing @time_position.
1244 * Returns the last segment and sets the @eos variable to TRUE
1245 * if the time is beyond the end. @eos may be NULL
1248 gst_qtdemux_find_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
1249 GstClockTime time_position)
1254 GST_LOG_OBJECT (stream->pad, "finding segment for %" GST_TIME_FORMAT,
1255 GST_TIME_ARGS (time_position));
1258 for (i = 0; i < stream->n_segments; i++) {
1259 QtDemuxSegment *segment = &stream->segments[i];
1261 GST_LOG_OBJECT (stream->pad,
1262 "looking at segment %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT,
1263 GST_TIME_ARGS (segment->time), GST_TIME_ARGS (segment->stop_time));
1265 /* For the last segment we include stop_time in the last segment */
1266 if (i < stream->n_segments - 1) {
1267 if (segment->time <= time_position && time_position < segment->stop_time) {
1268 GST_LOG_OBJECT (stream->pad, "segment %d matches", i);
1273 /* Last segment always matches */
1281 /* move the stream @str to the sample position @index.
1283 * Updates @str->sample_index and marks discontinuity if needed.
1286 gst_qtdemux_move_stream (GstQTDemux * qtdemux, QtDemuxStream * str,
1289 /* no change needed */
1290 if (index == str->sample_index)
1293 GST_DEBUG_OBJECT (qtdemux, "moving to sample %u of %u", index,
1296 /* position changed, we have a discont */
1297 str->sample_index = index;
1298 str->offset_in_sample = 0;
1299 /* Each time we move in the stream we store the position where we are
1301 str->from_sample = index;
1302 str->discont = TRUE;
1306 gst_qtdemux_adjust_seek (GstQTDemux * qtdemux, gint64 desired_time,
1307 gboolean use_sparse, gboolean next, gint64 * key_time, gint64 * key_offset)
1310 gint64 min_byte_offset = -1;
1313 min_offset = desired_time;
1315 /* for each stream, find the index of the sample in the segment
1316 * and move back to the previous keyframe. */
1317 for (n = 0; n < qtdemux->n_streams; n++) {
1319 guint32 index, kindex;
1321 GstClockTime media_start;
1322 GstClockTime media_time;
1323 GstClockTime seg_time;
1324 QtDemuxSegment *seg;
1325 gboolean empty_segment = FALSE;
1327 str = qtdemux->streams[n];
1329 if (CUR_STREAM (str)->sparse && !use_sparse)
1332 seg_idx = gst_qtdemux_find_segment (qtdemux, str, desired_time);
1333 GST_DEBUG_OBJECT (qtdemux, "align segment %d", seg_idx);
1335 /* get segment and time in the segment */
1336 seg = &str->segments[seg_idx];
1337 seg_time = (desired_time - seg->time) * seg->rate;
1339 while (QTSEGMENT_IS_EMPTY (seg)) {
1341 empty_segment = TRUE;
1342 GST_DEBUG_OBJECT (str->pad, "Segment %d is empty, moving to next one",
1345 if (seg_idx == str->n_segments)
1347 seg = &str->segments[seg_idx];
1350 if (seg_idx == str->n_segments) {
1351 /* FIXME track shouldn't have the last segment as empty, but if it
1352 * happens we better handle it */
1356 /* get the media time in the segment */
1357 media_start = seg->media_start + seg_time;
1359 /* get the index of the sample with media time */
1360 index = gst_qtdemux_find_index_linear (qtdemux, str, media_start);
1361 GST_DEBUG_OBJECT (qtdemux, "sample for %" GST_TIME_FORMAT " at %u"
1362 " at offset %" G_GUINT64_FORMAT " (empty segment: %d)",
1363 GST_TIME_ARGS (media_start), index, str->samples[index].offset,
1366 /* shift to next frame if we are looking for next keyframe */
1367 if (next && QTSAMPLE_PTS_NO_CSLG (str, &str->samples[index]) < media_start
1368 && index < str->stbl_index)
1371 if (!empty_segment) {
1372 /* find previous keyframe */
1373 kindex = gst_qtdemux_find_keyframe (qtdemux, str, index, next);
1375 /* we will settle for one before if none found after */
1376 if (next && kindex == -1)
1377 kindex = gst_qtdemux_find_keyframe (qtdemux, str, index, FALSE);
1379 /* if the keyframe is at a different position, we need to update the
1380 * requested seek time */
1381 if (index != kindex) {
1384 /* get timestamp of keyframe */
1385 media_time = QTSAMPLE_PTS_NO_CSLG (str, &str->samples[kindex]);
1386 GST_DEBUG_OBJECT (qtdemux,
1387 "keyframe at %u with time %" GST_TIME_FORMAT " at offset %"
1388 G_GUINT64_FORMAT, kindex, GST_TIME_ARGS (media_time),
1389 str->samples[kindex].offset);
1391 /* keyframes in the segment get a chance to change the
1392 * desired_offset. keyframes out of the segment are
1394 if (media_time >= seg->media_start) {
1395 GstClockTime seg_time;
1397 /* this keyframe is inside the segment, convert back to
1399 seg_time = (media_time - seg->media_start) + seg->time;
1400 if ((!next && (seg_time < min_offset)) ||
1401 (next && (seg_time > min_offset)))
1402 min_offset = seg_time;
1407 if (min_byte_offset < 0 || str->samples[index].offset < min_byte_offset)
1408 min_byte_offset = str->samples[index].offset;
1412 *key_time = min_offset;
1414 *key_offset = min_byte_offset;
1418 gst_qtdemux_convert_seek (GstPad * pad, GstFormat * format,
1419 GstSeekType cur_type, gint64 * cur, GstSeekType stop_type, gint64 * stop)
1423 g_return_val_if_fail (format != NULL, FALSE);
1424 g_return_val_if_fail (cur != NULL, FALSE);
1425 g_return_val_if_fail (stop != NULL, FALSE);
1427 if (*format == GST_FORMAT_TIME)
1431 if (cur_type != GST_SEEK_TYPE_NONE)
1432 res = gst_pad_query_convert (pad, *format, *cur, GST_FORMAT_TIME, cur);
1433 if (res && stop_type != GST_SEEK_TYPE_NONE)
1434 res = gst_pad_query_convert (pad, *format, *stop, GST_FORMAT_TIME, stop);
1437 *format = GST_FORMAT_TIME;
1442 /* perform seek in push based mode:
1443 find BYTE position to move to based on time and delegate to upstream
1446 gst_qtdemux_do_push_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1451 GstSeekType cur_type, stop_type;
1452 gint64 cur, stop, key_cur;
1455 gint64 original_stop;
1458 GST_DEBUG_OBJECT (qtdemux, "doing push-based seek");
1460 gst_event_parse_seek (event, &rate, &format, &flags,
1461 &cur_type, &cur, &stop_type, &stop);
1462 seqnum = gst_event_get_seqnum (event);
1464 /* only forward streaming and seeking is possible */
1466 goto unsupported_seek;
1468 /* convert to TIME if needed and possible */
1469 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1473 /* Upstream seek in bytes will have undefined stop, but qtdemux stores
1474 * the original stop position to use when upstream pushes the new segment
1476 original_stop = stop;
1479 /* find reasonable corresponding BYTE position,
1480 * also try to mind about keyframes, since we can not go back a bit for them
1482 /* determining @next here based on SNAP_BEFORE/SNAP_AFTER should
1483 * mostly just work, but let's not yet boldly go there ... */
1484 gst_qtdemux_adjust_seek (qtdemux, cur, FALSE, FALSE, &key_cur, &byte_cur);
1489 GST_DEBUG_OBJECT (qtdemux, "Pushing BYTE seek rate %g, "
1490 "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, byte_cur,
1493 GST_OBJECT_LOCK (qtdemux);
1494 qtdemux->seek_offset = byte_cur;
1495 if (!(flags & GST_SEEK_FLAG_KEY_UNIT)) {
1496 qtdemux->push_seek_start = cur;
1498 qtdemux->push_seek_start = key_cur;
1501 if (stop_type == GST_SEEK_TYPE_NONE) {
1502 qtdemux->push_seek_stop = qtdemux->segment.stop;
1504 qtdemux->push_seek_stop = original_stop;
1506 GST_OBJECT_UNLOCK (qtdemux);
1508 /* BYTE seek event */
1509 event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type, byte_cur,
1511 gst_event_set_seqnum (event, seqnum);
1512 res = gst_pad_push_event (qtdemux->sinkpad, event);
1519 GST_DEBUG_OBJECT (qtdemux, "could not determine byte position to seek to, "
1525 GST_DEBUG_OBJECT (qtdemux, "unsupported seek, seek aborted.");
1530 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1535 /* perform the seek.
1537 * We set all segment_indexes in the streams to unknown and
1538 * adjust the time_position to the desired position. this is enough
1539 * to trigger a segment switch in the streaming thread to start
1540 * streaming from the desired position.
1542 * Keyframe seeking is a little more complicated when dealing with
1543 * segments. Ideally we want to move to the previous keyframe in
1544 * the segment but there might not be a keyframe in the segment. In
1545 * fact, none of the segments could contain a keyframe. We take a
1546 * practical approach: seek to the previous keyframe in the segment,
1547 * if there is none, seek to the beginning of the segment.
1549 * Called with STREAM_LOCK
1552 gst_qtdemux_perform_seek (GstQTDemux * qtdemux, GstSegment * segment,
1553 guint32 seqnum, GstSeekFlags flags)
1555 gint64 desired_offset;
1558 desired_offset = segment->position;
1560 GST_DEBUG_OBJECT (qtdemux, "seeking to %" GST_TIME_FORMAT,
1561 GST_TIME_ARGS (desired_offset));
1563 /* may not have enough fragmented info to do this adjustment,
1564 * and we can't scan (and probably should not) at this time with
1565 * possibly flushing upstream */
1566 if ((flags & GST_SEEK_FLAG_KEY_UNIT) && !qtdemux->fragmented) {
1568 gboolean next, before, after;
1570 before = ! !(flags & GST_SEEK_FLAG_SNAP_BEFORE);
1571 after = ! !(flags & GST_SEEK_FLAG_SNAP_AFTER);
1572 next = after && !before;
1573 if (segment->rate < 0)
1576 gst_qtdemux_adjust_seek (qtdemux, desired_offset, TRUE, next, &min_offset,
1578 GST_DEBUG_OBJECT (qtdemux, "keyframe seek, align to %"
1579 GST_TIME_FORMAT, GST_TIME_ARGS (min_offset));
1580 desired_offset = min_offset;
1583 /* and set all streams to the final position */
1584 gst_flow_combiner_reset (qtdemux->flowcombiner);
1585 qtdemux->segment_seqnum = seqnum;
1586 for (n = 0; n < qtdemux->n_streams; n++) {
1587 QtDemuxStream *stream = qtdemux->streams[n];
1589 stream->time_position = desired_offset;
1590 stream->accumulated_base = 0;
1591 stream->sample_index = -1;
1592 stream->offset_in_sample = 0;
1593 stream->segment_index = -1;
1594 stream->sent_eos = FALSE;
1596 if (segment->flags & GST_SEEK_FLAG_FLUSH)
1597 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
1599 segment->position = desired_offset;
1600 segment->time = desired_offset;
1601 if (segment->rate >= 0) {
1602 segment->start = desired_offset;
1604 /* we stop at the end */
1605 if (segment->stop == -1)
1606 segment->stop = segment->duration;
1608 segment->stop = desired_offset;
1611 if (qtdemux->fragmented)
1612 qtdemux->fragmented_seek_pending = TRUE;
1617 /* do a seek in pull based mode */
1619 gst_qtdemux_do_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1624 GstSeekType cur_type, stop_type;
1628 GstSegment seeksegment;
1629 guint32 seqnum = GST_SEQNUM_INVALID;
1630 GstEvent *flush_event;
1634 GST_DEBUG_OBJECT (qtdemux, "doing seek with event");
1636 gst_event_parse_seek (event, &rate, &format, &flags,
1637 &cur_type, &cur, &stop_type, &stop);
1638 seqnum = gst_event_get_seqnum (event);
1640 /* we have to have a format as the segment format. Try to convert
1642 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1646 GST_DEBUG_OBJECT (qtdemux, "seek format %s", gst_format_get_name (format));
1648 GST_DEBUG_OBJECT (qtdemux, "doing seek without event");
1652 flush = flags & GST_SEEK_FLAG_FLUSH;
1654 /* stop streaming, either by flushing or by pausing the task */
1656 flush_event = gst_event_new_flush_start ();
1657 if (seqnum != GST_SEQNUM_INVALID)
1658 gst_event_set_seqnum (flush_event, seqnum);
1659 /* unlock upstream pull_range */
1660 gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event));
1661 /* make sure out loop function exits */
1662 gst_qtdemux_push_event (qtdemux, flush_event);
1664 /* non flushing seek, pause the task */
1665 gst_pad_pause_task (qtdemux->sinkpad);
1668 /* wait for streaming to finish */
1669 GST_PAD_STREAM_LOCK (qtdemux->sinkpad);
1671 /* copy segment, we need this because we still need the old
1672 * segment when we close the current segment. */
1673 memcpy (&seeksegment, &qtdemux->segment, sizeof (GstSegment));
1676 /* configure the segment with the seek variables */
1677 GST_DEBUG_OBJECT (qtdemux, "configuring seek");
1678 if (!gst_segment_do_seek (&seeksegment, rate, format, flags,
1679 cur_type, cur, stop_type, stop, &update)) {
1681 GST_ERROR_OBJECT (qtdemux, "inconsistent seek values, doing nothing");
1683 /* now do the seek */
1684 ret = gst_qtdemux_perform_seek (qtdemux, &seeksegment, seqnum, flags);
1687 /* now do the seek */
1688 ret = gst_qtdemux_perform_seek (qtdemux, &seeksegment, seqnum, flags);
1691 /* prepare for streaming again */
1693 flush_event = gst_event_new_flush_stop (TRUE);
1694 if (seqnum != GST_SEQNUM_INVALID)
1695 gst_event_set_seqnum (flush_event, seqnum);
1697 gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event));
1698 gst_qtdemux_push_event (qtdemux, flush_event);
1701 /* commit the new segment */
1702 memcpy (&qtdemux->segment, &seeksegment, sizeof (GstSegment));
1704 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
1705 GstMessage *msg = gst_message_new_segment_start (GST_OBJECT_CAST (qtdemux),
1706 qtdemux->segment.format, qtdemux->segment.position);
1707 if (seqnum != GST_SEQNUM_INVALID)
1708 gst_message_set_seqnum (msg, seqnum);
1709 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
1712 /* restart streaming, NEWSEGMENT will be sent from the streaming thread. */
1713 gst_pad_start_task (qtdemux->sinkpad, (GstTaskFunction) gst_qtdemux_loop,
1714 qtdemux->sinkpad, NULL);
1716 GST_PAD_STREAM_UNLOCK (qtdemux->sinkpad);
1723 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1729 qtdemux_ensure_index (GstQTDemux * qtdemux)
1733 GST_DEBUG_OBJECT (qtdemux, "collecting all metadata for all streams");
1735 /* Build complete index */
1736 for (i = 0; i < qtdemux->n_streams; i++) {
1737 QtDemuxStream *stream = qtdemux->streams[i];
1739 if (!qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1))
1747 GST_LOG_OBJECT (qtdemux,
1748 "Building complete index of stream %u for seeking failed!", i);
1754 gst_qtdemux_handle_src_event (GstPad * pad, GstObject * parent,
1757 gboolean res = TRUE;
1758 GstQTDemux *qtdemux = GST_QTDEMUX (parent);
1760 switch (GST_EVENT_TYPE (event)) {
1761 case GST_EVENT_SEEK:
1763 #ifndef GST_DISABLE_GST_DEBUG
1764 GstClockTime ts = gst_util_get_timestamp ();
1766 guint32 seqnum = gst_event_get_seqnum (event);
1768 if (seqnum == qtdemux->segment_seqnum) {
1769 GST_LOG_OBJECT (pad,
1770 "Drop duplicated SEEK event seqnum %" G_GUINT32_FORMAT, seqnum);
1771 gst_event_unref (event);
1775 if (qtdemux->upstream_format_is_time && qtdemux->fragmented) {
1776 /* seek should be handled by upstream, we might need to re-download fragments */
1777 GST_DEBUG_OBJECT (qtdemux,
1778 "let upstream handle seek for fragmented playback");
1782 /* Build complete index for seeking;
1783 * if not a fragmented file at least */
1784 if (!qtdemux->fragmented)
1785 if (!qtdemux_ensure_index (qtdemux))
1787 #ifndef GST_DISABLE_GST_DEBUG
1788 ts = gst_util_get_timestamp () - ts;
1789 GST_INFO_OBJECT (qtdemux,
1790 "Time taken to parse index %" GST_TIME_FORMAT, GST_TIME_ARGS (ts));
1793 if (qtdemux->pullbased) {
1794 res = gst_qtdemux_do_seek (qtdemux, pad, event);
1795 } else if (gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (event))) {
1796 GST_DEBUG_OBJECT (qtdemux, "Upstream successfully seeked");
1798 } else if (qtdemux->state == QTDEMUX_STATE_MOVIE && qtdemux->n_streams
1799 && !qtdemux->fragmented) {
1800 res = gst_qtdemux_do_push_seek (qtdemux, pad, event);
1802 GST_DEBUG_OBJECT (qtdemux,
1803 "ignoring seek in push mode in current state");
1806 gst_event_unref (event);
1810 res = gst_pad_event_default (pad, parent, event);
1820 GST_ERROR_OBJECT (qtdemux, "Index failed");
1821 gst_event_unref (event);
1827 /* Find, for each track, the first sample in coding order that has a file offset >= @byte_pos.
1829 * If @fw is false, the coding order is explored backwards.
1831 * If @set is true, each stream will be moved to its matched sample, or EOS if no matching
1832 * sample is found for that track.
1834 * The stream and sample index of the sample with the minimum offset in the direction explored
1835 * (see @fw) is returned in the output parameters @_stream and @_index respectively.
1837 * @_time is set to the QTSAMPLE_PTS of the matched sample with the minimum QTSAMPLE_PTS in the
1838 * direction explored, which may not always match the QTSAMPLE_PTS of the sample returned in
1839 * @_stream and @_index. */
1841 gst_qtdemux_find_sample (GstQTDemux * qtdemux, gint64 byte_pos, gboolean fw,
1842 gboolean set, QtDemuxStream ** _stream, gint * _index, gint64 * _time)
1845 gint64 time, min_time;
1846 QtDemuxStream *stream;
1852 for (n = 0; n < qtdemux->n_streams; ++n) {
1855 gboolean set_sample;
1857 str = qtdemux->streams[n];
1864 i = str->n_samples - 1;
1868 for (; (i >= 0) && (i < str->n_samples); i += inc) {
1869 if (str->samples[i].size == 0)
1872 if (fw && (str->samples[i].offset < byte_pos))
1875 if (!fw && (str->samples[i].offset + str->samples[i].size > byte_pos))
1878 /* move stream to first available sample */
1880 gst_qtdemux_move_stream (qtdemux, str, i);
1884 /* avoid index from sparse streams since they might be far away */
1885 if (!CUR_STREAM (str)->sparse) {
1886 /* determine min/max time */
1887 time = QTSAMPLE_PTS (str, &str->samples[i]);
1888 if (min_time == -1 || (!fw && time > min_time) ||
1889 (fw && time < min_time)) {
1893 /* determine stream with leading sample, to get its position */
1895 (fw && (str->samples[i].offset < stream->samples[index].offset)) ||
1896 (!fw && (str->samples[i].offset > stream->samples[index].offset))) {
1904 /* no sample for this stream, mark eos */
1906 gst_qtdemux_move_stream (qtdemux, str, str->n_samples);
1917 static QtDemuxStream *
1918 _create_stream (void)
1920 QtDemuxStream *stream;
1922 stream = g_new0 (QtDemuxStream, 1);
1923 /* new streams always need a discont */
1924 stream->discont = TRUE;
1925 /* we enable clipping for raw audio/video streams */
1926 stream->need_clip = FALSE;
1927 stream->need_process = FALSE;
1928 stream->segment_index = -1;
1929 stream->time_position = 0;
1930 stream->sample_index = -1;
1931 stream->offset_in_sample = 0;
1932 stream->new_stream = TRUE;
1933 stream->multiview_mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
1934 stream->multiview_flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
1935 stream->protected = FALSE;
1936 stream->protection_scheme_type = 0;
1937 stream->protection_scheme_version = 0;
1938 stream->protection_scheme_info = NULL;
1939 stream->n_samples_moof = 0;
1940 stream->duration_moof = 0;
1941 stream->duration_last_moof = 0;
1942 stream->alignment = 1;
1943 stream->stream_tags = gst_tag_list_new_empty ();
1944 gst_tag_list_set_scope (stream->stream_tags, GST_TAG_SCOPE_STREAM);
1945 g_queue_init (&stream->protection_scheme_event_queue);
1950 gst_qtdemux_setcaps (GstQTDemux * demux, GstCaps * caps)
1952 GstStructure *structure;
1953 const gchar *variant;
1954 const GstCaps *mediacaps = NULL;
1956 GST_DEBUG_OBJECT (demux, "Sink set caps: %" GST_PTR_FORMAT, caps);
1958 structure = gst_caps_get_structure (caps, 0);
1959 variant = gst_structure_get_string (structure, "variant");
1961 if (variant && strcmp (variant, "mss-fragmented") == 0) {
1962 QtDemuxStream *stream;
1963 const GValue *value;
1965 demux->fragmented = TRUE;
1966 demux->mss_mode = TRUE;
1968 if (demux->n_streams > 1) {
1969 /* can't do this, we can only renegotiate for another mss format */
1973 value = gst_structure_get_value (structure, "media-caps");
1976 const GValue *timescale_v;
1978 /* TODO update when stream changes during playback */
1980 if (demux->n_streams == 0) {
1981 stream = _create_stream ();
1982 demux->streams[demux->n_streams] = stream;
1983 demux->n_streams = 1;
1984 /* mss has no stsd/stsd entry, use id 0 as default */
1985 stream->stsd_entries_length = 1;
1986 stream->stsd_sample_description_id = stream->cur_stsd_entry_index = 0;
1987 stream->stsd_entries = g_new0 (QtDemuxStreamStsdEntry, 1);
1989 stream = demux->streams[0];
1992 timescale_v = gst_structure_get_value (structure, "timescale");
1994 stream->timescale = g_value_get_uint64 (timescale_v);
1996 /* default mss timescale */
1997 stream->timescale = 10000000;
1999 demux->timescale = stream->timescale;
2001 mediacaps = gst_value_get_caps (value);
2002 if (!CUR_STREAM (stream)->caps
2003 || !gst_caps_is_equal_fixed (mediacaps, CUR_STREAM (stream)->caps)) {
2004 GST_DEBUG_OBJECT (demux, "We have a new caps %" GST_PTR_FORMAT,
2006 stream->new_caps = TRUE;
2008 gst_caps_replace (&CUR_STREAM (stream)->caps, (GstCaps *) mediacaps);
2009 structure = gst_caps_get_structure (mediacaps, 0);
2010 if (g_str_has_prefix (gst_structure_get_name (structure), "video")) {
2011 stream->subtype = FOURCC_vide;
2013 gst_structure_get_int (structure, "width", &CUR_STREAM (stream)->width);
2014 gst_structure_get_int (structure, "height",
2015 &CUR_STREAM (stream)->height);
2016 gst_structure_get_fraction (structure, "framerate",
2017 &CUR_STREAM (stream)->fps_n, &CUR_STREAM (stream)->fps_d);
2018 } else if (g_str_has_prefix (gst_structure_get_name (structure), "audio")) {
2020 stream->subtype = FOURCC_soun;
2021 gst_structure_get_int (structure, "channels",
2022 &CUR_STREAM (stream)->n_channels);
2023 gst_structure_get_int (structure, "rate", &rate);
2024 CUR_STREAM (stream)->rate = rate;
2027 gst_caps_replace (&demux->media_caps, (GstCaps *) mediacaps);
2029 demux->mss_mode = FALSE;
2036 gst_qtdemux_reset (GstQTDemux * qtdemux, gboolean hard)
2040 GST_DEBUG_OBJECT (qtdemux, "Resetting demux");
2041 gst_pad_stop_task (qtdemux->sinkpad);
2043 if (hard || qtdemux->upstream_format_is_time) {
2044 qtdemux->state = QTDEMUX_STATE_INITIAL;
2045 qtdemux->neededbytes = 16;
2046 qtdemux->todrop = 0;
2047 qtdemux->pullbased = FALSE;
2048 qtdemux->posted_redirect = FALSE;
2049 qtdemux->first_mdat = -1;
2050 qtdemux->header_size = 0;
2051 qtdemux->mdatoffset = -1;
2052 qtdemux->restoredata_offset = -1;
2053 if (qtdemux->mdatbuffer)
2054 gst_buffer_unref (qtdemux->mdatbuffer);
2055 if (qtdemux->restoredata_buffer)
2056 gst_buffer_unref (qtdemux->restoredata_buffer);
2057 qtdemux->mdatbuffer = NULL;
2058 qtdemux->restoredata_buffer = NULL;
2059 qtdemux->mdatleft = 0;
2060 qtdemux->mdatsize = 0;
2061 if (qtdemux->comp_brands)
2062 gst_buffer_unref (qtdemux->comp_brands);
2063 qtdemux->comp_brands = NULL;
2064 qtdemux->last_moov_offset = -1;
2065 if (qtdemux->moov_node_compressed) {
2066 g_node_destroy (qtdemux->moov_node_compressed);
2067 if (qtdemux->moov_node)
2068 g_free (qtdemux->moov_node->data);
2070 qtdemux->moov_node_compressed = NULL;
2071 if (qtdemux->moov_node)
2072 g_node_destroy (qtdemux->moov_node);
2073 qtdemux->moov_node = NULL;
2074 if (qtdemux->tag_list)
2075 gst_mini_object_unref (GST_MINI_OBJECT_CAST (qtdemux->tag_list));
2076 qtdemux->tag_list = gst_tag_list_new_empty ();
2077 gst_tag_list_set_scope (qtdemux->tag_list, GST_TAG_SCOPE_GLOBAL);
2079 if (qtdemux->element_index)
2080 gst_object_unref (qtdemux->element_index);
2081 qtdemux->element_index = NULL;
2083 qtdemux->major_brand = 0;
2084 if (qtdemux->pending_newsegment)
2085 gst_event_unref (qtdemux->pending_newsegment);
2086 qtdemux->pending_newsegment = NULL;
2087 qtdemux->upstream_format_is_time = FALSE;
2088 qtdemux->upstream_seekable = FALSE;
2089 qtdemux->upstream_size = 0;
2091 qtdemux->fragment_start = -1;
2092 qtdemux->fragment_start_offset = -1;
2093 qtdemux->duration = 0;
2094 qtdemux->moof_offset = 0;
2095 qtdemux->chapters_track_id = 0;
2096 qtdemux->have_group_id = FALSE;
2097 qtdemux->group_id = G_MAXUINT;
2099 g_queue_foreach (&qtdemux->protection_event_queue, (GFunc) gst_event_unref,
2101 g_queue_clear (&qtdemux->protection_event_queue);
2103 qtdemux->offset = 0;
2104 gst_adapter_clear (qtdemux->adapter);
2105 gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
2106 qtdemux->segment_seqnum = GST_SEQNUM_INVALID;
2109 for (n = 0; n < qtdemux->n_streams; n++) {
2110 gst_qtdemux_stream_free (qtdemux, qtdemux->streams[n]);
2111 qtdemux->streams[n] = NULL;
2113 qtdemux->n_streams = 0;
2114 qtdemux->n_video_streams = 0;
2115 qtdemux->n_audio_streams = 0;
2116 qtdemux->n_sub_streams = 0;
2117 qtdemux->exposed = FALSE;
2118 qtdemux->fragmented = FALSE;
2119 qtdemux->mss_mode = FALSE;
2120 gst_caps_replace (&qtdemux->media_caps, NULL);
2121 qtdemux->timescale = 0;
2122 qtdemux->got_moov = FALSE;
2123 if (qtdemux->protection_system_ids) {
2124 g_ptr_array_free (qtdemux->protection_system_ids, TRUE);
2125 qtdemux->protection_system_ids = NULL;
2127 } else if (qtdemux->mss_mode) {
2128 gst_flow_combiner_reset (qtdemux->flowcombiner);
2129 for (n = 0; n < qtdemux->n_streams; n++)
2130 gst_qtdemux_stream_clear (qtdemux, qtdemux->streams[n]);
2132 gst_flow_combiner_reset (qtdemux->flowcombiner);
2133 for (n = 0; n < qtdemux->n_streams; n++) {
2134 qtdemux->streams[n]->sent_eos = FALSE;
2135 qtdemux->streams[n]->time_position = 0;
2136 qtdemux->streams[n]->accumulated_base = 0;
2138 if (!qtdemux->pending_newsegment) {
2139 qtdemux->pending_newsegment = gst_event_new_segment (&qtdemux->segment);
2140 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID)
2141 gst_event_set_seqnum (qtdemux->pending_newsegment,
2142 qtdemux->segment_seqnum);
2148 /* Maps the @segment to the qt edts internal segments and pushes
2149 * the correspnding segment event.
2151 * If it ends up being at a empty segment, a gap will be pushed and the next
2152 * edts segment will be activated in sequence.
2154 * To be used in push-mode only */
2156 gst_qtdemux_map_and_push_segments (GstQTDemux * qtdemux, GstSegment * segment)
2160 for (n = 0; n < qtdemux->n_streams; n++) {
2161 QtDemuxStream *stream = qtdemux->streams[n];
2163 stream->time_position = segment->start;
2165 /* in push mode we should be guaranteed that we will have empty segments
2166 * at the beginning and then one segment after, other scenarios are not
2167 * supported and are discarded when parsing the edts */
2168 for (i = 0; i < stream->n_segments; i++) {
2169 if (stream->segments[i].stop_time > segment->start) {
2170 gst_qtdemux_activate_segment (qtdemux, stream, i,
2171 stream->time_position);
2172 if (QTSEGMENT_IS_EMPTY (&stream->segments[i])) {
2173 /* push the empty segment and move to the next one */
2174 gst_qtdemux_send_gap_for_segment (qtdemux, stream, i,
2175 stream->time_position);
2179 g_assert (i == stream->n_segments - 1);
2186 gst_qtdemux_handle_sink_event (GstPad * sinkpad, GstObject * parent,
2189 GstQTDemux *demux = GST_QTDEMUX (parent);
2190 gboolean res = TRUE;
2192 GST_LOG_OBJECT (demux, "handling %s event", GST_EVENT_TYPE_NAME (event));
2194 switch (GST_EVENT_TYPE (event)) {
2195 case GST_EVENT_SEGMENT:
2198 QtDemuxStream *stream;
2202 /* some debug output */
2203 gst_event_copy_segment (event, &segment);
2204 GST_DEBUG_OBJECT (demux, "received newsegment %" GST_SEGMENT_FORMAT,
2207 /* erase any previously set segment */
2208 gst_event_replace (&demux->pending_newsegment, NULL);
2210 if (segment.format == GST_FORMAT_TIME) {
2211 GST_DEBUG_OBJECT (demux, "new pending_newsegment");
2212 gst_event_replace (&demux->pending_newsegment, event);
2213 demux->upstream_format_is_time = TRUE;
2215 GST_DEBUG_OBJECT (demux, "Not storing upstream newsegment, "
2216 "not in time format");
2218 /* chain will send initial newsegment after pads have been added */
2219 if (demux->state != QTDEMUX_STATE_MOVIE || !demux->n_streams) {
2220 GST_DEBUG_OBJECT (demux, "still starting, eating event");
2225 /* check if this matches a time seek we received previously
2226 * FIXME for backwards compatibility reasons we use the
2227 * seek_offset here to compare. In the future we might want to
2228 * change this to use the seqnum as it uniquely should identify
2229 * the segment that corresponds to the seek. */
2230 GST_DEBUG_OBJECT (demux, "Stored seek offset: %" G_GINT64_FORMAT
2231 ", received segment offset %" G_GINT64_FORMAT,
2232 demux->seek_offset, segment.start);
2233 if (segment.format == GST_FORMAT_BYTES
2234 && demux->seek_offset == segment.start) {
2235 GST_OBJECT_LOCK (demux);
2236 offset = segment.start;
2238 segment.format = GST_FORMAT_TIME;
2239 segment.start = demux->push_seek_start;
2240 segment.stop = demux->push_seek_stop;
2241 GST_DEBUG_OBJECT (demux, "Replaced segment with stored seek "
2242 "segment %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT,
2243 GST_TIME_ARGS (segment.start), GST_TIME_ARGS (segment.stop));
2244 GST_OBJECT_UNLOCK (demux);
2247 /* we only expect a BYTE segment, e.g. following a seek */
2248 if (segment.format == GST_FORMAT_BYTES) {
2249 if (GST_CLOCK_TIME_IS_VALID (segment.start)) {
2250 offset = segment.start;
2252 gst_qtdemux_find_sample (demux, segment.start, TRUE, FALSE, NULL,
2253 NULL, (gint64 *) & segment.start);
2254 if ((gint64) segment.start < 0)
2257 if (GST_CLOCK_TIME_IS_VALID (segment.stop)) {
2258 gst_qtdemux_find_sample (demux, segment.stop, FALSE, FALSE, NULL,
2259 NULL, (gint64 *) & segment.stop);
2260 /* keyframe seeking should already arrange for start >= stop,
2261 * but make sure in other rare cases */
2262 segment.stop = MAX (segment.stop, segment.start);
2264 } else if (segment.format == GST_FORMAT_TIME) {
2265 /* push all data on the adapter before starting this
2267 gst_qtdemux_process_adapter (demux, TRUE);
2269 GST_DEBUG_OBJECT (demux, "unsupported segment format, ignoring");
2273 /* We shouldn't modify upstream driven TIME FORMAT segment */
2274 if (!demux->upstream_format_is_time) {
2275 /* accept upstream's notion of segment and distribute along */
2276 segment.format = GST_FORMAT_TIME;
2277 segment.position = segment.time = segment.start;
2278 segment.duration = demux->segment.duration;
2279 segment.base = gst_segment_to_running_time (&demux->segment,
2280 GST_FORMAT_TIME, demux->segment.position);
2283 gst_segment_copy_into (&segment, &demux->segment);
2284 GST_DEBUG_OBJECT (demux, "Pushing newseg %" GST_SEGMENT_FORMAT, &segment);
2286 /* map segment to internal qt segments and push on each stream */
2287 if (demux->n_streams) {
2288 if (demux->fragmented) {
2289 GstEvent *segment_event = gst_event_new_segment (&segment);
2291 gst_event_replace (&demux->pending_newsegment, NULL);
2292 gst_event_set_seqnum (segment_event, demux->segment_seqnum);
2293 gst_qtdemux_push_event (demux, segment_event);
2295 gst_event_replace (&demux->pending_newsegment, NULL);
2296 gst_qtdemux_map_and_push_segments (demux, &segment);
2300 /* clear leftover in current segment, if any */
2301 gst_adapter_clear (demux->adapter);
2303 /* set up streaming thread */
2304 demux->offset = offset;
2305 if (demux->upstream_format_is_time) {
2306 GST_DEBUG_OBJECT (demux, "Upstream is driving in time format, "
2307 "set values to restart reading from a new atom");
2308 demux->neededbytes = 16;
2311 gst_qtdemux_find_sample (demux, offset, TRUE, TRUE, &stream, &idx,
2314 demux->todrop = stream->samples[idx].offset - offset;
2315 demux->neededbytes = demux->todrop + stream->samples[idx].size;
2317 /* set up for EOS */
2318 demux->neededbytes = -1;
2323 gst_event_unref (event);
2327 case GST_EVENT_FLUSH_START:
2329 if (gst_event_get_seqnum (event) == demux->offset_seek_seqnum) {
2330 gst_event_unref (event);
2335 case GST_EVENT_FLUSH_STOP:
2339 dur = demux->segment.duration;
2340 gst_qtdemux_reset (demux, FALSE);
2341 demux->segment.duration = dur;
2343 if (gst_event_get_seqnum (event) == demux->offset_seek_seqnum) {
2344 gst_event_unref (event);
2350 /* If we are in push mode, and get an EOS before we've seen any streams,
2351 * then error out - we have nowhere to send the EOS */
2352 if (!demux->pullbased) {
2354 gboolean has_valid_stream = FALSE;
2355 for (i = 0; i < demux->n_streams; i++) {
2356 if (demux->streams[i]->pad != NULL) {
2357 has_valid_stream = TRUE;
2361 if (!has_valid_stream)
2362 gst_qtdemux_post_no_playable_stream_error (demux);
2364 GST_DEBUG_OBJECT (demux, "Data still available after EOS: %u",
2365 (guint) gst_adapter_available (demux->adapter));
2366 if (gst_qtdemux_process_adapter (demux, TRUE) != GST_FLOW_OK) {
2372 case GST_EVENT_CAPS:{
2373 GstCaps *caps = NULL;
2375 gst_event_parse_caps (event, &caps);
2376 gst_qtdemux_setcaps (demux, caps);
2378 gst_event_unref (event);
2381 case GST_EVENT_PROTECTION:
2383 const gchar *system_id = NULL;
2385 gst_event_parse_protection (event, &system_id, NULL, NULL);
2386 GST_DEBUG_OBJECT (demux, "Received protection event for system ID %s",
2388 gst_qtdemux_append_protection_system_id (demux, system_id);
2389 /* save the event for later, for source pads that have not been created */
2390 g_queue_push_tail (&demux->protection_event_queue, gst_event_ref (event));
2391 /* send it to all pads that already exist */
2392 gst_qtdemux_push_event (demux, event);
2400 res = gst_pad_event_default (demux->sinkpad, parent, event) & res;
2408 gst_qtdemux_set_index (GstElement * element, GstIndex * index)
2410 GstQTDemux *demux = GST_QTDEMUX (element);
2412 GST_OBJECT_LOCK (demux);
2413 if (demux->element_index)
2414 gst_object_unref (demux->element_index);
2416 demux->element_index = gst_object_ref (index);
2418 demux->element_index = NULL;
2420 GST_OBJECT_UNLOCK (demux);
2421 /* object lock might be taken again */
2423 gst_index_get_writer_id (index, GST_OBJECT (element), &demux->index_id);
2424 GST_DEBUG_OBJECT (demux, "Set index %" GST_PTR_FORMAT "for writer id %d",
2425 demux->element_index, demux->index_id);
2429 gst_qtdemux_get_index (GstElement * element)
2431 GstIndex *result = NULL;
2432 GstQTDemux *demux = GST_QTDEMUX (element);
2434 GST_OBJECT_LOCK (demux);
2435 if (demux->element_index)
2436 result = gst_object_ref (demux->element_index);
2437 GST_OBJECT_UNLOCK (demux);
2439 GST_DEBUG_OBJECT (demux, "Returning index %" GST_PTR_FORMAT, result);
2446 gst_qtdemux_stbl_free (QtDemuxStream * stream)
2448 g_free ((gpointer) stream->stco.data);
2449 stream->stco.data = NULL;
2450 g_free ((gpointer) stream->stsz.data);
2451 stream->stsz.data = NULL;
2452 g_free ((gpointer) stream->stsc.data);
2453 stream->stsc.data = NULL;
2454 g_free ((gpointer) stream->stts.data);
2455 stream->stts.data = NULL;
2456 g_free ((gpointer) stream->stss.data);
2457 stream->stss.data = NULL;
2458 g_free ((gpointer) stream->stps.data);
2459 stream->stps.data = NULL;
2460 g_free ((gpointer) stream->ctts.data);
2461 stream->ctts.data = NULL;
2465 gst_qtdemux_stream_flush_segments_data (GstQTDemux * qtdemux,
2466 QtDemuxStream * stream)
2468 g_free (stream->segments);
2469 stream->segments = NULL;
2470 stream->segment_index = -1;
2471 stream->accumulated_base = 0;
2475 gst_qtdemux_stream_flush_samples_data (GstQTDemux * qtdemux,
2476 QtDemuxStream * stream)
2478 g_free (stream->samples);
2479 stream->samples = NULL;
2480 gst_qtdemux_stbl_free (stream);
2483 g_free (stream->ra_entries);
2484 stream->ra_entries = NULL;
2485 stream->n_ra_entries = 0;
2487 stream->sample_index = -1;
2488 stream->stbl_index = -1;
2489 stream->n_samples = 0;
2490 stream->time_position = 0;
2492 stream->n_samples_moof = 0;
2493 stream->duration_moof = 0;
2494 stream->duration_last_moof = 0;
2498 gst_qtdemux_stream_clear (GstQTDemux * qtdemux, QtDemuxStream * stream)
2501 if (stream->allocator)
2502 gst_object_unref (stream->allocator);
2503 while (stream->buffers) {
2504 gst_buffer_unref (GST_BUFFER_CAST (stream->buffers->data));
2505 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
2507 for (i = 0; i < stream->stsd_entries_length; i++) {
2508 QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[i];
2509 if (entry->rgb8_palette) {
2510 gst_memory_unref (entry->rgb8_palette);
2511 entry->rgb8_palette = NULL;
2513 entry->sparse = FALSE;
2516 gst_tag_list_unref (stream->stream_tags);
2517 stream->stream_tags = gst_tag_list_new_empty ();
2518 gst_tag_list_set_scope (stream->stream_tags, GST_TAG_SCOPE_STREAM);
2519 g_free (stream->redirect_uri);
2520 stream->redirect_uri = NULL;
2521 stream->sent_eos = FALSE;
2522 stream->protected = FALSE;
2523 if (stream->protection_scheme_info) {
2524 if (stream->protection_scheme_type == FOURCC_cenc) {
2525 QtDemuxCencSampleSetInfo *info =
2526 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
2527 if (info->default_properties)
2528 gst_structure_free (info->default_properties);
2529 if (info->crypto_info)
2530 g_ptr_array_free (info->crypto_info, TRUE);
2532 g_free (stream->protection_scheme_info);
2533 stream->protection_scheme_info = NULL;
2535 stream->protection_scheme_type = 0;
2536 stream->protection_scheme_version = 0;
2537 g_queue_foreach (&stream->protection_scheme_event_queue,
2538 (GFunc) gst_event_unref, NULL);
2539 g_queue_clear (&stream->protection_scheme_event_queue);
2540 gst_qtdemux_stream_flush_segments_data (qtdemux, stream);
2541 gst_qtdemux_stream_flush_samples_data (qtdemux, stream);
2545 gst_qtdemux_stream_reset (GstQTDemux * qtdemux, QtDemuxStream * stream)
2548 gst_qtdemux_stream_clear (qtdemux, stream);
2549 for (i = 0; i < stream->stsd_entries_length; i++) {
2550 QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[i];
2552 gst_caps_unref (entry->caps);
2556 g_free (stream->stsd_entries);
2557 stream->stsd_entries = NULL;
2558 stream->stsd_entries_length = 0;
2563 gst_qtdemux_stream_free (GstQTDemux * qtdemux, QtDemuxStream * stream)
2565 gst_qtdemux_stream_reset (qtdemux, stream);
2566 gst_tag_list_unref (stream->stream_tags);
2568 gst_element_remove_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
2569 gst_flow_combiner_remove_pad (qtdemux->flowcombiner, stream->pad);
2575 gst_qtdemux_remove_stream (GstQTDemux * qtdemux, int i)
2577 g_assert (i >= 0 && i < qtdemux->n_streams && qtdemux->streams[i] != NULL);
2579 gst_qtdemux_stream_free (qtdemux, qtdemux->streams[i]);
2580 qtdemux->streams[i] = qtdemux->streams[qtdemux->n_streams - 1];
2581 qtdemux->streams[qtdemux->n_streams - 1] = NULL;
2582 qtdemux->n_streams--;
2585 static GstStateChangeReturn
2586 gst_qtdemux_change_state (GstElement * element, GstStateChange transition)
2588 GstQTDemux *qtdemux = GST_QTDEMUX (element);
2589 GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
2591 switch (transition) {
2592 case GST_STATE_CHANGE_PAUSED_TO_READY:
2598 result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
2600 switch (transition) {
2601 case GST_STATE_CHANGE_PAUSED_TO_READY:{
2602 gst_qtdemux_reset (qtdemux, TRUE);
2613 qtdemux_parse_ftyp (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2615 /* counts as header data */
2616 qtdemux->header_size += length;
2618 /* only consider at least a sufficiently complete ftyp atom */
2622 qtdemux->major_brand = QT_FOURCC (buffer + 8);
2623 GST_DEBUG_OBJECT (qtdemux, "major brand: %" GST_FOURCC_FORMAT,
2624 GST_FOURCC_ARGS (qtdemux->major_brand));
2625 if (qtdemux->comp_brands)
2626 gst_buffer_unref (qtdemux->comp_brands);
2627 buf = qtdemux->comp_brands = gst_buffer_new_and_alloc (length - 16);
2628 gst_buffer_fill (buf, 0, buffer + 16, length - 16);
2633 qtdemux_handle_xmp_taglist (GstQTDemux * qtdemux, GstTagList * taglist,
2634 GstTagList * xmptaglist)
2636 /* Strip out bogus fields */
2638 if (gst_tag_list_get_scope (taglist) == GST_TAG_SCOPE_GLOBAL) {
2639 gst_tag_list_remove_tag (xmptaglist, GST_TAG_VIDEO_CODEC);
2640 gst_tag_list_remove_tag (xmptaglist, GST_TAG_AUDIO_CODEC);
2642 gst_tag_list_remove_tag (xmptaglist, GST_TAG_CONTAINER_FORMAT);
2645 GST_DEBUG_OBJECT (qtdemux, "Found XMP tags %" GST_PTR_FORMAT, xmptaglist);
2647 /* prioritize native tags using _KEEP mode */
2648 gst_tag_list_insert (taglist, xmptaglist, GST_TAG_MERGE_KEEP);
2649 gst_tag_list_unref (xmptaglist);
2654 qtdemux_parse_piff (GstQTDemux * qtdemux, const guint8 * buffer, gint length,
2662 QtDemuxStream *stream;
2663 GstStructure *structure;
2664 QtDemuxCencSampleSetInfo *ss_info = NULL;
2665 const gchar *system_id;
2666 gboolean uses_sub_sample_encryption = FALSE;
2668 if (qtdemux->n_streams == 0)
2671 stream = qtdemux->streams[0];
2673 structure = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
2674 if (!gst_structure_has_name (structure, "application/x-cenc")) {
2675 GST_WARNING_OBJECT (qtdemux,
2676 "Attempting PIFF box parsing on an unencrypted stream.");
2680 gst_structure_get (structure, GST_PROTECTION_SYSTEM_ID_CAPS_FIELD,
2681 G_TYPE_STRING, &system_id, NULL);
2682 gst_qtdemux_append_protection_system_id (qtdemux, system_id);
2684 stream->protected = TRUE;
2685 stream->protection_scheme_type = FOURCC_cenc;
2687 if (!stream->protection_scheme_info)
2688 stream->protection_scheme_info = g_new0 (QtDemuxCencSampleSetInfo, 1);
2690 ss_info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
2692 if (ss_info->default_properties)
2693 gst_structure_free (ss_info->default_properties);
2695 ss_info->default_properties =
2696 gst_structure_new ("application/x-cenc",
2697 "iv_size", G_TYPE_UINT, iv_size, "encrypted", G_TYPE_BOOLEAN, TRUE, NULL);
2699 if (ss_info->crypto_info) {
2700 GST_LOG_OBJECT (qtdemux, "unreffing existing crypto_info");
2701 g_ptr_array_free (ss_info->crypto_info, TRUE);
2702 ss_info->crypto_info = NULL;
2706 gst_byte_reader_init (&br, buffer + offset + 16, length - offset - 16);
2708 if (!gst_byte_reader_get_uint8 (&br, &version)) {
2709 GST_ERROR_OBJECT (qtdemux, "Error getting box's version field");
2713 if (!gst_byte_reader_get_uint24_be (&br, &flags)) {
2714 GST_ERROR_OBJECT (qtdemux, "Error getting box's flags field");
2718 if ((flags & 0x000001)) {
2719 guint32 algorithm_id = 0;
2722 gboolean is_encrypted = TRUE;
2724 if (!gst_byte_reader_get_uint24_le (&br, &algorithm_id)) {
2725 GST_ERROR_OBJECT (qtdemux, "Error getting box's algorithm ID field");
2730 if (algorithm_id == 0) {
2731 is_encrypted = FALSE;
2732 } else if (algorithm_id == 1) {
2733 /* FIXME: maybe store this in properties? */
2734 GST_DEBUG_OBJECT (qtdemux, "AES 128-bits CTR encrypted stream");
2735 } else if (algorithm_id == 2) {
2736 /* FIXME: maybe store this in properties? */
2737 GST_DEBUG_OBJECT (qtdemux, "AES 128-bits CBC encrypted stream");
2740 if (!gst_byte_reader_get_uint8 (&br, &iv_size))
2743 if (!gst_byte_reader_get_data (&br, 16, &kid))
2746 kid_buf = gst_buffer_new_allocate (NULL, 16, NULL);
2747 gst_buffer_fill (kid_buf, 0, kid, 16);
2748 if (ss_info->default_properties)
2749 gst_structure_free (ss_info->default_properties);
2750 ss_info->default_properties =
2751 gst_structure_new ("application/x-cenc",
2752 "iv_size", G_TYPE_UINT, iv_size,
2753 "encrypted", G_TYPE_BOOLEAN, is_encrypted,
2754 "kid", GST_TYPE_BUFFER, kid_buf, NULL);
2755 GST_DEBUG_OBJECT (qtdemux, "default sample properties: "
2756 "is_encrypted=%u, iv_size=%u", is_encrypted, iv_size);
2757 gst_buffer_unref (kid_buf);
2758 } else if ((flags & 0x000002)) {
2759 uses_sub_sample_encryption = TRUE;
2762 if (!gst_byte_reader_get_uint32_be (&br, &qtdemux->cenc_aux_sample_count)) {
2763 GST_ERROR_OBJECT (qtdemux, "Error getting box's sample count field");
2767 ss_info->crypto_info =
2768 g_ptr_array_new_full (qtdemux->cenc_aux_sample_count,
2769 (GDestroyNotify) qtdemux_gst_structure_free);
2771 for (i = 0; i < qtdemux->cenc_aux_sample_count; ++i) {
2772 GstStructure *properties;
2776 properties = qtdemux_get_cenc_sample_properties (qtdemux, stream, i);
2777 if (properties == NULL) {
2778 GST_ERROR_OBJECT (qtdemux, "failed to get properties for sample %u", i);
2782 if (!gst_byte_reader_dup_data (&br, iv_size, &data)) {
2783 GST_ERROR_OBJECT (qtdemux, "IV data not present for sample %u", i);
2784 gst_structure_free (properties);
2787 buf = gst_buffer_new_wrapped (data, iv_size);
2788 gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL);
2789 gst_buffer_unref (buf);
2791 if (uses_sub_sample_encryption) {
2792 guint16 n_subsamples;
2794 if (!gst_byte_reader_get_uint16_be (&br, &n_subsamples)
2795 || n_subsamples == 0) {
2796 GST_ERROR_OBJECT (qtdemux,
2797 "failed to get subsample count for sample %u", i);
2798 gst_structure_free (properties);
2801 GST_LOG_OBJECT (qtdemux, "subsample count: %u", n_subsamples);
2802 if (!gst_byte_reader_dup_data (&br, n_subsamples * 6, &data)) {
2803 GST_ERROR_OBJECT (qtdemux, "failed to get subsample data for sample %u",
2805 gst_structure_free (properties);
2808 buf = gst_buffer_new_wrapped (data, n_subsamples * 6);
2809 gst_structure_set (properties,
2810 "subsample_count", G_TYPE_UINT, n_subsamples,
2811 "subsamples", GST_TYPE_BUFFER, buf, NULL);
2812 gst_buffer_unref (buf);
2814 gst_structure_set (properties, "subsample_count", G_TYPE_UINT, 0, NULL);
2817 g_ptr_array_add (ss_info->crypto_info, properties);
2822 qtdemux_parse_uuid (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2824 static const guint8 xmp_uuid[] = { 0xBE, 0x7A, 0xCF, 0xCB,
2825 0x97, 0xA9, 0x42, 0xE8,
2826 0x9C, 0x71, 0x99, 0x94,
2827 0x91, 0xE3, 0xAF, 0xAC
2829 static const guint8 playready_uuid[] = {
2830 0xd0, 0x8a, 0x4f, 0x18, 0x10, 0xf3, 0x4a, 0x82,
2831 0xb6, 0xc8, 0x32, 0xd8, 0xab, 0xa1, 0x83, 0xd3
2834 static const guint8 piff_sample_encryption_uuid[] = {
2835 0xa2, 0x39, 0x4f, 0x52, 0x5a, 0x9b, 0x4f, 0x14,
2836 0xa2, 0x44, 0x6c, 0x42, 0x7c, 0x64, 0x8d, 0xf4
2841 /* counts as header data */
2842 qtdemux->header_size += length;
2844 offset = (QT_UINT32 (buffer) == 0) ? 16 : 8;
2846 if (length <= offset + 16) {
2847 GST_DEBUG_OBJECT (qtdemux, "uuid atom is too short, skipping");
2851 if (memcmp (buffer + offset, xmp_uuid, 16) == 0) {
2853 GstTagList *taglist;
2855 buf = _gst_buffer_new_wrapped ((guint8 *) buffer + offset + 16,
2856 length - offset - 16, NULL);
2857 taglist = gst_tag_list_from_xmp_buffer (buf);
2858 gst_buffer_unref (buf);
2860 /* make sure we have a usable taglist */
2861 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
2863 qtdemux_handle_xmp_taglist (qtdemux, qtdemux->tag_list, taglist);
2865 } else if (memcmp (buffer + offset, playready_uuid, 16) == 0) {
2867 const gunichar2 *s_utf16;
2870 len = GST_READ_UINT16_LE (buffer + offset + 0x30);
2871 s_utf16 = (const gunichar2 *) (buffer + offset + 0x32);
2872 contents = g_utf16_to_utf8 (s_utf16, len / 2, NULL, NULL, NULL);
2873 GST_ERROR_OBJECT (qtdemux, "contents: %s", contents);
2877 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT,
2878 (_("Cannot play stream because it is encrypted with PlayReady DRM.")),
2880 } else if (memcmp (buffer + offset, piff_sample_encryption_uuid, 16) == 0) {
2881 qtdemux_parse_piff (qtdemux, buffer, length, offset);
2883 GST_DEBUG_OBJECT (qtdemux, "Ignoring unknown uuid: %08x-%08x-%08x-%08x",
2884 GST_READ_UINT32_LE (buffer + offset),
2885 GST_READ_UINT32_LE (buffer + offset + 4),
2886 GST_READ_UINT32_LE (buffer + offset + 8),
2887 GST_READ_UINT32_LE (buffer + offset + 12));
2892 qtdemux_parse_sidx (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2894 GstSidxParser sidx_parser;
2895 GstIsoffParserResult res;
2898 gst_isoff_qt_sidx_parser_init (&sidx_parser);
2901 gst_isoff_qt_sidx_parser_add_data (&sidx_parser, buffer, length,
2903 GST_DEBUG_OBJECT (qtdemux, "sidx parse result: %d", res);
2904 if (res == GST_ISOFF_QT_PARSER_DONE) {
2905 check_update_duration (qtdemux, sidx_parser.cumulative_pts);
2907 gst_isoff_qt_sidx_parser_clear (&sidx_parser);
2910 /* caller verifies at least 8 bytes in buf */
2912 extract_initial_length_and_fourcc (const guint8 * data, guint size,
2913 guint64 * plength, guint32 * pfourcc)
2918 length = QT_UINT32 (data);
2919 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
2920 fourcc = QT_FOURCC (data + 4);
2921 GST_DEBUG ("atom type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
2924 length = G_MAXUINT64;
2925 } else if (length == 1 && size >= 16) {
2926 /* this means we have an extended size, which is the 64 bit value of
2927 * the next 8 bytes */
2928 length = QT_UINT64 (data + 8);
2929 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
2939 qtdemux_parse_mehd (GstQTDemux * qtdemux, GstByteReader * br)
2941 guint32 version = 0;
2942 GstClockTime duration = 0;
2944 if (!gst_byte_reader_get_uint32_be (br, &version))
2949 if (!gst_byte_reader_get_uint64_be (br, &duration))
2954 if (!gst_byte_reader_get_uint32_be (br, &dur))
2959 GST_INFO_OBJECT (qtdemux, "mehd duration: %" G_GUINT64_FORMAT, duration);
2960 qtdemux->duration = duration;
2966 GST_DEBUG_OBJECT (qtdemux, "parsing mehd failed");
2972 qtdemux_parse_trex (GstQTDemux * qtdemux, QtDemuxStream * stream,
2973 guint32 * ds_duration, guint32 * ds_size, guint32 * ds_flags)
2975 if (!stream->parsed_trex && qtdemux->moov_node) {
2977 GstByteReader trex_data;
2979 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
2981 trex = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_trex,
2984 guint32 id = 0, sdi = 0, dur = 0, size = 0, flags = 0;
2986 /* skip version/flags */
2987 if (!gst_byte_reader_skip (&trex_data, 4))
2989 if (!gst_byte_reader_get_uint32_be (&trex_data, &id))
2991 if (id != stream->track_id)
2993 if (!gst_byte_reader_get_uint32_be (&trex_data, &sdi))
2995 if (!gst_byte_reader_get_uint32_be (&trex_data, &dur))
2997 if (!gst_byte_reader_get_uint32_be (&trex_data, &size))
2999 if (!gst_byte_reader_get_uint32_be (&trex_data, &flags))
3002 GST_DEBUG_OBJECT (qtdemux, "fragment defaults for stream %d; "
3003 "duration %d, size %d, flags 0x%x", stream->track_id,
3006 stream->parsed_trex = TRUE;
3007 stream->def_sample_description_index = sdi;
3008 stream->def_sample_duration = dur;
3009 stream->def_sample_size = size;
3010 stream->def_sample_flags = flags;
3013 /* iterate all siblings */
3014 trex = qtdemux_tree_get_sibling_by_type_full (trex, FOURCC_trex,
3020 *ds_duration = stream->def_sample_duration;
3021 *ds_size = stream->def_sample_size;
3022 *ds_flags = stream->def_sample_flags;
3024 /* even then, above values are better than random ... */
3025 if (G_UNLIKELY (!stream->parsed_trex)) {
3026 GST_WARNING_OBJECT (qtdemux,
3027 "failed to find fragment defaults for stream %d", stream->track_id);
3034 /* This method should be called whenever a more accurate duration might
3035 * have been found. It will update all relevant variables if/where needed
3038 check_update_duration (GstQTDemux * qtdemux, GstClockTime duration)
3042 GstClockTime prevdur;
3044 movdur = GSTTIME_TO_QTTIME (qtdemux, duration);
3046 if (movdur > qtdemux->duration) {
3047 prevdur = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
3048 GST_DEBUG_OBJECT (qtdemux,
3049 "Updating total duration to %" GST_TIME_FORMAT " was %" GST_TIME_FORMAT,
3050 GST_TIME_ARGS (duration), GST_TIME_ARGS (prevdur));
3051 qtdemux->duration = movdur;
3052 GST_DEBUG_OBJECT (qtdemux,
3053 "qtdemux->segment.duration: %" GST_TIME_FORMAT " .stop: %"
3054 GST_TIME_FORMAT, GST_TIME_ARGS (qtdemux->segment.duration),
3055 GST_TIME_ARGS (qtdemux->segment.stop));
3056 if (qtdemux->segment.duration == prevdur) {
3057 /* If the current segment has duration/stop identical to previous duration
3058 * update them also (because they were set at that point in time with
3059 * the wrong duration */
3060 /* We convert the value *from* the timescale version to avoid rounding errors */
3061 GstClockTime fixeddur = QTTIME_TO_GSTTIME (qtdemux, movdur);
3062 GST_DEBUG_OBJECT (qtdemux, "Updated segment.duration and segment.stop");
3063 qtdemux->segment.duration = fixeddur;
3064 qtdemux->segment.stop = fixeddur;
3067 for (i = 0; i < qtdemux->n_streams; i++) {
3068 QtDemuxStream *stream = qtdemux->streams[i];
3070 movdur = GSTTIME_TO_QTSTREAMTIME (stream, duration);
3071 if (movdur > stream->duration) {
3072 GST_DEBUG_OBJECT (qtdemux,
3073 "Updating stream #%d duration to %" GST_TIME_FORMAT, i,
3074 GST_TIME_ARGS (duration));
3075 stream->duration = movdur;
3076 /* internal duration tracking state has been updated above, so */
3077 /* preserve an open-ended dummy segment rather than repeatedly updating
3078 * it and spamming downstream accordingly with segment events */
3079 if (stream->dummy_segment &&
3080 GST_CLOCK_TIME_IS_VALID (stream->segments[0].duration)) {
3081 /* Update all dummy values to new duration */
3082 stream->segments[0].stop_time = duration;
3083 stream->segments[0].duration = duration;
3084 stream->segments[0].media_stop = duration;
3086 /* let downstream know we possibly have a new stop time */
3087 if (stream->segment_index != -1) {
3090 if (qtdemux->segment.rate >= 0) {
3091 pos = stream->segment.start;
3093 pos = stream->segment.stop;
3096 gst_qtdemux_stream_update_segment (qtdemux, stream,
3097 stream->segment_index, pos, NULL, NULL);
3106 qtdemux_parse_trun (GstQTDemux * qtdemux, GstByteReader * trun,
3107 QtDemuxStream * stream, guint32 d_sample_duration, guint32 d_sample_size,
3108 guint32 d_sample_flags, gint64 moof_offset, gint64 moof_length,
3109 gint64 * base_offset, gint64 * running_offset, gint64 decode_ts,
3112 GstClockTime gst_ts = GST_CLOCK_TIME_NONE;
3114 gint32 data_offset = 0;
3115 guint32 flags = 0, first_flags = 0, samples_count = 0;
3118 guint entry_size, dur_offset, size_offset, flags_offset = 0, ct_offset = 0;
3119 QtDemuxSample *sample;
3120 gboolean ismv = FALSE;
3121 gint64 initial_offset;
3123 GST_LOG_OBJECT (qtdemux, "parsing trun stream %d; "
3124 "default dur %d, size %d, flags 0x%x, base offset %" G_GINT64_FORMAT ", "
3125 "decode ts %" G_GINT64_FORMAT, stream->track_id, d_sample_duration,
3126 d_sample_size, d_sample_flags, *base_offset, decode_ts);
3128 if (stream->pending_seek && moof_offset < stream->pending_seek->moof_offset) {
3129 GST_INFO_OBJECT (stream->pad, "skipping trun before seek target fragment");
3133 /* presence of stss or not can't really tell us much,
3134 * and flags and so on tend to be marginally reliable in these files */
3135 if (stream->subtype == FOURCC_soun) {
3136 GST_DEBUG_OBJECT (qtdemux,
3137 "sound track in fragmented file; marking all keyframes");
3138 stream->all_keyframe = TRUE;
3141 if (!gst_byte_reader_skip (trun, 1) ||
3142 !gst_byte_reader_get_uint24_be (trun, &flags))
3145 if (!gst_byte_reader_get_uint32_be (trun, &samples_count))
3148 if (flags & TR_DATA_OFFSET) {
3149 /* note this is really signed */
3150 if (!gst_byte_reader_get_int32_be (trun, &data_offset))
3152 GST_LOG_OBJECT (qtdemux, "trun data offset %d", data_offset);
3153 /* default base offset = first byte of moof */
3154 if (*base_offset == -1) {
3155 GST_LOG_OBJECT (qtdemux, "base_offset at moof");
3156 *base_offset = moof_offset;
3158 *running_offset = *base_offset + data_offset;
3160 /* if no offset at all, that would mean data starts at moof start,
3161 * which is a bit wrong and is ismv crappy way, so compensate
3162 * assuming data is in mdat following moof */
3163 if (*base_offset == -1) {
3164 *base_offset = moof_offset + moof_length + 8;
3165 GST_LOG_OBJECT (qtdemux, "base_offset assumed in mdat after moof");
3168 if (*running_offset == -1)
3169 *running_offset = *base_offset;
3172 GST_LOG_OBJECT (qtdemux, "running offset now %" G_GINT64_FORMAT,
3174 GST_LOG_OBJECT (qtdemux, "trun offset %d, flags 0x%x, entries %d",
3175 data_offset, flags, samples_count);
3177 if (flags & TR_FIRST_SAMPLE_FLAGS) {
3178 if (G_UNLIKELY (flags & TR_SAMPLE_FLAGS)) {
3179 GST_DEBUG_OBJECT (qtdemux,
3180 "invalid flags; SAMPLE and FIRST_SAMPLE present, discarding latter");
3181 flags ^= TR_FIRST_SAMPLE_FLAGS;
3183 if (!gst_byte_reader_get_uint32_be (trun, &first_flags))
3185 GST_LOG_OBJECT (qtdemux, "first flags: 0x%x", first_flags);
3189 /* FIXME ? spec says other bits should also be checked to determine
3190 * entry size (and prefix size for that matter) */
3192 dur_offset = size_offset = 0;
3193 if (flags & TR_SAMPLE_DURATION) {
3194 GST_LOG_OBJECT (qtdemux, "entry duration present");
3195 dur_offset = entry_size;
3198 if (flags & TR_SAMPLE_SIZE) {
3199 GST_LOG_OBJECT (qtdemux, "entry size present");
3200 size_offset = entry_size;
3203 if (flags & TR_SAMPLE_FLAGS) {
3204 GST_LOG_OBJECT (qtdemux, "entry flags present");
3205 flags_offset = entry_size;
3208 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
3209 GST_LOG_OBJECT (qtdemux, "entry ct offset present");
3210 ct_offset = entry_size;
3214 if (!qt_atom_parser_has_chunks (trun, samples_count, entry_size))
3216 data = (guint8 *) gst_byte_reader_peek_data_unchecked (trun);
3218 if (stream->n_samples + samples_count >=
3219 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample))
3222 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
3223 stream->n_samples + samples_count, (guint) sizeof (QtDemuxSample),
3224 (stream->n_samples + samples_count) *
3225 sizeof (QtDemuxSample) / (1024.0 * 1024.0));
3227 /* create a new array of samples if it's the first sample parsed */
3228 if (stream->n_samples == 0) {
3229 g_assert (stream->samples == NULL);
3230 stream->samples = g_try_new0 (QtDemuxSample, samples_count);
3231 /* or try to reallocate it with space enough to insert the new samples */
3233 stream->samples = g_try_renew (QtDemuxSample, stream->samples,
3234 stream->n_samples + samples_count);
3235 if (stream->samples == NULL)
3238 if (qtdemux->fragment_start != -1) {
3239 timestamp = GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->fragment_start);
3240 qtdemux->fragment_start = -1;
3242 if (stream->n_samples == 0) {
3243 if (decode_ts > 0) {
3244 timestamp = decode_ts;
3245 } else if (stream->pending_seek != NULL) {
3246 /* if we don't have a timestamp from a tfdt box, we'll use the one
3247 * from the mfra seek table */
3248 GST_INFO_OBJECT (stream->pad, "pending seek ts = %" GST_TIME_FORMAT,
3249 GST_TIME_ARGS (stream->pending_seek->ts));
3251 /* FIXME: this is not fully correct, the timestamp refers to the random
3252 * access sample refered to in the tfra entry, which may not necessarily
3253 * be the first sample in the tfrag/trun (but hopefully/usually is) */
3254 timestamp = GSTTIME_TO_QTSTREAMTIME (stream, stream->pending_seek->ts);
3259 gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
3260 GST_INFO_OBJECT (stream->pad, "first sample ts %" GST_TIME_FORMAT,
3261 GST_TIME_ARGS (gst_ts));
3263 /* subsequent fragments extend stream */
3265 stream->samples[stream->n_samples - 1].timestamp +
3266 stream->samples[stream->n_samples - 1].duration;
3268 /* If this is a GST_FORMAT_BYTES stream and there's a significant
3269 * difference (1 sec.) between decode_ts and timestamp, prefer the
3271 if (has_tfdt && !qtdemux->upstream_format_is_time
3272 && ABSDIFF (decode_ts, timestamp) >
3273 MAX (stream->duration_last_moof / 2,
3274 GSTTIME_TO_QTSTREAMTIME (stream, GST_SECOND))) {
3275 GST_INFO_OBJECT (qtdemux,
3276 "decode_ts (%" GST_TIME_FORMAT ") and timestamp (%" GST_TIME_FORMAT
3277 ") are significantly different (more than %" GST_TIME_FORMAT
3278 "), using decode_ts",
3279 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, decode_ts)),
3280 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, timestamp)),
3281 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream,
3282 MAX (stream->duration_last_moof / 2,
3283 GSTTIME_TO_QTSTREAMTIME (stream, GST_SECOND)))));
3284 timestamp = decode_ts;
3287 gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
3288 GST_INFO_OBJECT (qtdemux, "first sample ts %" GST_TIME_FORMAT
3289 " (extends previous samples)", GST_TIME_ARGS (gst_ts));
3293 initial_offset = *running_offset;
3295 sample = stream->samples + stream->n_samples;
3296 for (i = 0; i < samples_count; i++) {
3297 guint32 dur, size, sflags, ct;
3299 /* first read sample data */
3300 if (flags & TR_SAMPLE_DURATION) {
3301 dur = QT_UINT32 (data + dur_offset);
3303 dur = d_sample_duration;
3305 if (flags & TR_SAMPLE_SIZE) {
3306 size = QT_UINT32 (data + size_offset);
3308 size = d_sample_size;
3310 if (flags & TR_FIRST_SAMPLE_FLAGS) {
3312 sflags = first_flags;
3314 sflags = d_sample_flags;
3316 } else if (flags & TR_SAMPLE_FLAGS) {
3317 sflags = QT_UINT32 (data + flags_offset);
3319 sflags = d_sample_flags;
3321 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
3322 ct = QT_UINT32 (data + ct_offset);
3328 /* fill the sample information */
3329 sample->offset = *running_offset;
3330 sample->pts_offset = ct;
3331 sample->size = size;
3332 sample->timestamp = timestamp;
3333 sample->duration = dur;
3334 /* sample-is-difference-sample */
3335 /* ismv seems to use 0x40 for keyframe, 0xc0 for non-keyframe,
3336 * now idea how it relates to bitfield other than massive LE/BE confusion */
3337 sample->keyframe = ismv ? ((sflags & 0xff) == 0x40) : !(sflags & 0x10000);
3338 *running_offset += size;
3340 stream->duration_moof += dur;
3344 /* Update total duration if needed */
3345 check_update_duration (qtdemux, QTSTREAMTIME_TO_GSTTIME (stream, timestamp));
3347 /* Pre-emptively figure out size of mdat based on trun information.
3348 * If the [mdat] atom is effectivelly read, it will be replaced by the actual
3349 * size, else we will still be able to use this when dealing with gap'ed
3351 qtdemux->mdatleft = *running_offset - initial_offset;
3352 qtdemux->mdatoffset = initial_offset;
3353 qtdemux->mdatsize = qtdemux->mdatleft;
3355 stream->n_samples += samples_count;
3356 stream->n_samples_moof += samples_count;
3358 if (stream->pending_seek != NULL)
3359 stream->pending_seek = NULL;
3365 GST_WARNING_OBJECT (qtdemux, "failed to parse trun");
3370 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
3376 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
3377 "be larger than %uMB (broken file?)", stream->n_samples,
3378 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
3383 /* find stream with @id */
3384 static inline QtDemuxStream *
3385 qtdemux_find_stream (GstQTDemux * qtdemux, guint32 id)
3387 QtDemuxStream *stream;
3391 if (G_UNLIKELY (!id)) {
3392 GST_DEBUG_OBJECT (qtdemux, "invalid track id 0");
3396 /* try to get it fast and simple */
3397 if (G_LIKELY (id <= qtdemux->n_streams)) {
3398 stream = qtdemux->streams[id - 1];
3399 if (G_LIKELY (stream->track_id == id))
3403 /* linear search otherwise */
3404 for (i = 0; i < qtdemux->n_streams; i++) {
3405 stream = qtdemux->streams[i];
3406 if (stream->track_id == id)
3409 if (qtdemux->mss_mode) {
3410 /* mss should have only 1 stream anyway */
3411 return qtdemux->streams[0];
3418 qtdemux_parse_mfhd (GstQTDemux * qtdemux, GstByteReader * mfhd,
3419 guint32 * fragment_number)
3421 if (!gst_byte_reader_skip (mfhd, 4))
3423 if (!gst_byte_reader_get_uint32_be (mfhd, fragment_number))
3428 GST_WARNING_OBJECT (qtdemux, "Failed to parse mfhd atom");
3434 qtdemux_parse_tfhd (GstQTDemux * qtdemux, GstByteReader * tfhd,
3435 QtDemuxStream ** stream, guint32 * default_sample_duration,
3436 guint32 * default_sample_size, guint32 * default_sample_flags,
3437 gint64 * base_offset)
3440 guint32 track_id = 0;
3442 if (!gst_byte_reader_skip (tfhd, 1) ||
3443 !gst_byte_reader_get_uint24_be (tfhd, &flags))
3446 if (!gst_byte_reader_get_uint32_be (tfhd, &track_id))
3449 *stream = qtdemux_find_stream (qtdemux, track_id);
3450 if (G_UNLIKELY (!*stream))
3451 goto unknown_stream;
3453 if (flags & TF_DEFAULT_BASE_IS_MOOF)
3454 *base_offset = qtdemux->moof_offset;
3456 if (flags & TF_BASE_DATA_OFFSET)
3457 if (!gst_byte_reader_get_uint64_be (tfhd, (guint64 *) base_offset))
3460 /* obtain stream defaults */
3461 qtdemux_parse_trex (qtdemux, *stream,
3462 default_sample_duration, default_sample_size, default_sample_flags);
3464 (*stream)->stsd_sample_description_id =
3465 (*stream)->def_sample_description_index - 1;
3467 if (flags & TF_SAMPLE_DESCRIPTION_INDEX) {
3468 guint32 sample_description_index;
3469 if (!gst_byte_reader_get_uint32_be (tfhd, &sample_description_index))
3471 (*stream)->stsd_sample_description_id = sample_description_index - 1;
3474 if (qtdemux->mss_mode) {
3475 /* mss has no stsd entry */
3476 (*stream)->stsd_sample_description_id = 0;
3479 if (flags & TF_DEFAULT_SAMPLE_DURATION)
3480 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_duration))
3483 if (flags & TF_DEFAULT_SAMPLE_SIZE)
3484 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_size))
3487 if (flags & TF_DEFAULT_SAMPLE_FLAGS)
3488 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_flags))
3495 GST_WARNING_OBJECT (qtdemux, "invalid track fragment header");
3500 GST_DEBUG_OBJECT (qtdemux, "unknown stream in tfhd");
3506 qtdemux_parse_tfdt (GstQTDemux * qtdemux, GstByteReader * br,
3507 guint64 * decode_time)
3509 guint32 version = 0;
3511 if (!gst_byte_reader_get_uint32_be (br, &version))
3516 if (!gst_byte_reader_get_uint64_be (br, decode_time))
3519 guint32 dec_time = 0;
3520 if (!gst_byte_reader_get_uint32_be (br, &dec_time))
3522 *decode_time = dec_time;
3525 GST_INFO_OBJECT (qtdemux, "Track fragment decode time: %" G_GUINT64_FORMAT,
3532 GST_DEBUG_OBJECT (qtdemux, "parsing tfdt failed");
3537 /* Returns a pointer to a GstStructure containing the properties of
3538 * the stream sample identified by @sample_index. The caller must unref
3539 * the returned object after use. Returns NULL if unsuccessful. */
3540 static GstStructure *
3541 qtdemux_get_cenc_sample_properties (GstQTDemux * qtdemux,
3542 QtDemuxStream * stream, guint sample_index)
3544 QtDemuxCencSampleSetInfo *info = NULL;
3546 g_return_val_if_fail (stream != NULL, NULL);
3547 g_return_val_if_fail (stream->protected, NULL);
3548 g_return_val_if_fail (stream->protection_scheme_info != NULL, NULL);
3550 info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
3552 /* Currently, cenc properties for groups of samples are not supported, so
3553 * simply return a copy of the default sample properties */
3554 return gst_structure_copy (info->default_properties);
3557 /* Parses the sizes of sample auxiliary information contained within a stream,
3558 * as given in a saiz box. Returns array of sample_count guint8 size values,
3559 * or NULL on failure */
3561 qtdemux_parse_saiz (GstQTDemux * qtdemux, QtDemuxStream * stream,
3562 GstByteReader * br, guint32 * sample_count)
3566 guint8 default_info_size;
3568 g_return_val_if_fail (qtdemux != NULL, NULL);
3569 g_return_val_if_fail (stream != NULL, NULL);
3570 g_return_val_if_fail (br != NULL, NULL);
3571 g_return_val_if_fail (sample_count != NULL, NULL);
3573 if (!gst_byte_reader_get_uint32_be (br, &flags))
3577 /* aux_info_type and aux_info_type_parameter are ignored */
3578 if (!gst_byte_reader_skip (br, 8))
3582 if (!gst_byte_reader_get_uint8 (br, &default_info_size))
3584 GST_DEBUG_OBJECT (qtdemux, "default_info_size: %u", default_info_size);
3586 if (!gst_byte_reader_get_uint32_be (br, sample_count))
3588 GST_DEBUG_OBJECT (qtdemux, "sample_count: %u", *sample_count);
3591 if (default_info_size == 0) {
3592 if (!gst_byte_reader_dup_data (br, *sample_count, &info_sizes)) {
3596 info_sizes = g_new (guint8, *sample_count);
3597 memset (info_sizes, default_info_size, *sample_count);
3603 /* Parses the offset of sample auxiliary information contained within a stream,
3604 * as given in a saio box. Returns TRUE if successful; FALSE otherwise. */
3606 qtdemux_parse_saio (GstQTDemux * qtdemux, QtDemuxStream * stream,
3607 GstByteReader * br, guint32 * info_type, guint32 * info_type_parameter,
3612 guint32 aux_info_type = 0;
3613 guint32 aux_info_type_parameter = 0;
3614 guint32 entry_count;
3617 const guint8 *aux_info_type_data = NULL;
3619 g_return_val_if_fail (qtdemux != NULL, FALSE);
3620 g_return_val_if_fail (stream != NULL, FALSE);
3621 g_return_val_if_fail (br != NULL, FALSE);
3622 g_return_val_if_fail (offset != NULL, FALSE);
3624 if (!gst_byte_reader_get_uint8 (br, &version))
3627 if (!gst_byte_reader_get_uint24_be (br, &flags))
3632 if (!gst_byte_reader_get_data (br, 4, &aux_info_type_data))
3634 aux_info_type = QT_FOURCC (aux_info_type_data);
3636 if (!gst_byte_reader_get_uint32_be (br, &aux_info_type_parameter))
3638 } else if (stream->protected) {
3639 aux_info_type = stream->protection_scheme_type;
3641 aux_info_type = CUR_STREAM (stream)->fourcc;
3645 *info_type = aux_info_type;
3646 if (info_type_parameter)
3647 *info_type_parameter = aux_info_type_parameter;
3649 GST_DEBUG_OBJECT (qtdemux, "aux_info_type: '%" GST_FOURCC_FORMAT "', "
3650 "aux_info_type_parameter: %#06x",
3651 GST_FOURCC_ARGS (aux_info_type), aux_info_type_parameter);
3653 if (!gst_byte_reader_get_uint32_be (br, &entry_count))
3656 if (entry_count != 1) {
3657 GST_ERROR_OBJECT (qtdemux, "multiple offsets are not supported");
3662 if (!gst_byte_reader_get_uint32_be (br, &off_32))
3664 *offset = (guint64) off_32;
3666 if (!gst_byte_reader_get_uint64_be (br, &off_64))
3671 GST_DEBUG_OBJECT (qtdemux, "offset: %" G_GUINT64_FORMAT, *offset);
3676 qtdemux_gst_structure_free (GstStructure * gststructure)
3679 gst_structure_free (gststructure);
3683 /* Parses auxiliary information relating to samples protected using Common
3684 * Encryption (cenc); the format of this information is defined in
3685 * ISO/IEC 23001-7. Returns TRUE if successful; FALSE otherwise. */
3687 qtdemux_parse_cenc_aux_info (GstQTDemux * qtdemux, QtDemuxStream * stream,
3688 GstByteReader * br, guint8 * info_sizes, guint32 sample_count)
3690 QtDemuxCencSampleSetInfo *ss_info = NULL;
3693 GPtrArray *old_crypto_info = NULL;
3694 guint old_entries = 0;
3696 g_return_val_if_fail (qtdemux != NULL, FALSE);
3697 g_return_val_if_fail (stream != NULL, FALSE);
3698 g_return_val_if_fail (br != NULL, FALSE);
3699 g_return_val_if_fail (stream->protected, FALSE);
3700 g_return_val_if_fail (stream->protection_scheme_info != NULL, FALSE);
3702 ss_info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
3704 if (ss_info->crypto_info) {
3705 old_crypto_info = ss_info->crypto_info;
3706 /* Count number of non-null entries remaining at the tail end */
3707 for (i = old_crypto_info->len - 1; i >= 0; i--) {
3708 if (g_ptr_array_index (old_crypto_info, i) == NULL)
3714 ss_info->crypto_info =
3715 g_ptr_array_new_full (sample_count + old_entries,
3716 (GDestroyNotify) qtdemux_gst_structure_free);
3718 /* We preserve old entries because we parse the next moof in advance
3719 * of consuming all samples from the previous moof, and otherwise
3720 * we'd discard the corresponding crypto info for the samples
3721 * from the previous fragment. */
3723 GST_DEBUG_OBJECT (qtdemux, "Preserving %d old crypto info entries",
3725 for (i = old_crypto_info->len - old_entries; i < old_crypto_info->len; i++) {
3726 g_ptr_array_add (ss_info->crypto_info, g_ptr_array_index (old_crypto_info,
3728 g_ptr_array_index (old_crypto_info, i) = NULL;
3732 if (old_crypto_info) {
3733 /* Everything now belongs to the new array */
3734 g_ptr_array_free (old_crypto_info, TRUE);
3737 for (i = 0; i < sample_count; ++i) {
3738 GstStructure *properties;
3739 guint16 n_subsamples = 0;
3744 properties = qtdemux_get_cenc_sample_properties (qtdemux, stream, i);
3745 if (properties == NULL) {
3746 GST_ERROR_OBJECT (qtdemux, "failed to get properties for sample %u", i);
3749 if (!gst_structure_get_uint (properties, "iv_size", &iv_size)) {
3750 GST_ERROR_OBJECT (qtdemux, "failed to get iv_size for sample %u", i);
3751 gst_structure_free (properties);
3754 if (!gst_byte_reader_dup_data (br, iv_size, &data)) {
3755 GST_ERROR_OBJECT (qtdemux, "failed to get IV for sample %u", i);
3756 gst_structure_free (properties);
3759 buf = gst_buffer_new_wrapped (data, iv_size);
3760 gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL);
3761 gst_buffer_unref (buf);
3762 size = info_sizes[i];
3763 if (size > iv_size) {
3764 if (!gst_byte_reader_get_uint16_be (br, &n_subsamples)
3765 || !(n_subsamples > 0)) {
3766 gst_structure_free (properties);
3767 GST_ERROR_OBJECT (qtdemux,
3768 "failed to get subsample count for sample %u", i);
3771 GST_LOG_OBJECT (qtdemux, "subsample count: %u", n_subsamples);
3772 if (!gst_byte_reader_dup_data (br, n_subsamples * 6, &data)) {
3773 GST_ERROR_OBJECT (qtdemux, "failed to get subsample data for sample %u",
3775 gst_structure_free (properties);
3778 buf = gst_buffer_new_wrapped (data, n_subsamples * 6);
3780 gst_structure_free (properties);
3783 gst_structure_set (properties,
3784 "subsample_count", G_TYPE_UINT, n_subsamples,
3785 "subsamples", GST_TYPE_BUFFER, buf, NULL);
3786 gst_buffer_unref (buf);
3788 gst_structure_set (properties, "subsample_count", G_TYPE_UINT, 0, NULL);
3790 g_ptr_array_add (ss_info->crypto_info, properties);
3795 /* Converts a UUID in raw byte form to a string representation, as defined in
3796 * RFC 4122. The caller takes ownership of the returned string and is
3797 * responsible for freeing it after use. */
3799 qtdemux_uuid_bytes_to_string (gconstpointer uuid_bytes)
3801 const guint8 *uuid = (const guint8 *) uuid_bytes;
3803 return g_strdup_printf ("%02x%02x%02x%02x-%02x%02x-%02x%02x-"
3804 "%02x%02x-%02x%02x%02x%02x%02x%02x",
3805 uuid[0], uuid[1], uuid[2], uuid[3],
3806 uuid[4], uuid[5], uuid[6], uuid[7],
3807 uuid[8], uuid[9], uuid[10], uuid[11],
3808 uuid[12], uuid[13], uuid[14], uuid[15]);
3811 /* Parses a Protection System Specific Header box (pssh), as defined in the
3812 * Common Encryption (cenc) standard (ISO/IEC 23001-7), which contains
3813 * information needed by a specific content protection system in order to
3814 * decrypt cenc-protected tracks. Returns TRUE if successful; FALSE
3817 qtdemux_parse_pssh (GstQTDemux * qtdemux, GNode * node)
3819 gchar *sysid_string;
3820 guint32 pssh_size = QT_UINT32 (node->data);
3821 GstBuffer *pssh = NULL;
3822 GstEvent *event = NULL;
3823 guint32 parent_box_type;
3826 if (G_UNLIKELY (pssh_size < 32U)) {
3827 GST_ERROR_OBJECT (qtdemux, "invalid box size");
3832 qtdemux_uuid_bytes_to_string ((const guint8 *) node->data + 12);
3834 gst_qtdemux_append_protection_system_id (qtdemux, sysid_string);
3836 pssh = gst_buffer_new_wrapped (g_memdup (node->data, pssh_size), pssh_size);
3837 GST_LOG_OBJECT (qtdemux, "cenc pssh size: %" G_GSIZE_FORMAT,
3838 gst_buffer_get_size (pssh));
3840 parent_box_type = QT_FOURCC ((const guint8 *) node->parent->data + 4);
3842 /* Push an event containing the pssh box onto the queues of all streams. */
3843 event = gst_event_new_protection (sysid_string, pssh,
3844 (parent_box_type == FOURCC_moov) ? "isobmff/moov" : "isobmff/moof");
3845 for (i = 0; i < qtdemux->n_streams; ++i) {
3846 g_queue_push_tail (&qtdemux->streams[i]->protection_scheme_event_queue,
3847 gst_event_ref (event));
3849 g_free (sysid_string);
3850 gst_event_unref (event);
3851 gst_buffer_unref (pssh);
3856 qtdemux_parse_moof (GstQTDemux * qtdemux, const guint8 * buffer, guint length,
3857 guint64 moof_offset, QtDemuxStream * stream)
3859 GNode *moof_node, *traf_node, *tfhd_node, *trun_node, *tfdt_node, *mfhd_node;
3861 GstByteReader mfhd_data, trun_data, tfhd_data, tfdt_data;
3862 GNode *saiz_node, *saio_node, *pssh_node;
3863 GstByteReader saiz_data, saio_data;
3864 guint32 ds_size = 0, ds_duration = 0, ds_flags = 0;
3865 gint64 base_offset, running_offset;
3868 /* NOTE @stream ignored */
3870 moof_node = g_node_new ((guint8 *) buffer);
3871 qtdemux_parse_node (qtdemux, moof_node, buffer, length);
3872 qtdemux_node_dump (qtdemux, moof_node);
3874 /* Get fragment number from mfhd and check it's valid */
3876 qtdemux_tree_get_child_by_type_full (moof_node, FOURCC_mfhd, &mfhd_data);
3877 if (mfhd_node == NULL)
3879 if (!qtdemux_parse_mfhd (qtdemux, &mfhd_data, &frag_num))
3881 GST_DEBUG_OBJECT (qtdemux, "Fragment #%d", frag_num);
3883 /* unknown base_offset to start with */
3884 base_offset = running_offset = -1;
3885 traf_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_traf);
3887 guint64 decode_time = 0;
3889 /* Fragment Header node */
3891 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfhd,
3895 if (!qtdemux_parse_tfhd (qtdemux, &tfhd_data, &stream, &ds_duration,
3896 &ds_size, &ds_flags, &base_offset))
3899 /* The following code assumes at most a single set of sample auxiliary
3900 * data in the fragment (consisting of a saiz box and a corresponding saio
3901 * box); in theory, however, there could be multiple sets of sample
3902 * auxiliary data in a fragment. */
3904 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saiz,
3907 guint32 info_type = 0;
3909 guint32 info_type_parameter = 0;
3911 g_free (qtdemux->cenc_aux_info_sizes);
3913 qtdemux->cenc_aux_info_sizes =
3914 qtdemux_parse_saiz (qtdemux, stream, &saiz_data,
3915 &qtdemux->cenc_aux_sample_count);
3916 if (qtdemux->cenc_aux_info_sizes == NULL) {
3917 GST_ERROR_OBJECT (qtdemux, "failed to parse saiz box");
3921 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saio,
3924 GST_ERROR_OBJECT (qtdemux, "saiz box without a corresponding saio box");
3925 g_free (qtdemux->cenc_aux_info_sizes);
3926 qtdemux->cenc_aux_info_sizes = NULL;
3930 if (G_UNLIKELY (!qtdemux_parse_saio (qtdemux, stream, &saio_data,
3931 &info_type, &info_type_parameter, &offset))) {
3932 GST_ERROR_OBJECT (qtdemux, "failed to parse saio box");
3933 g_free (qtdemux->cenc_aux_info_sizes);
3934 qtdemux->cenc_aux_info_sizes = NULL;
3937 if (base_offset > -1 && base_offset > qtdemux->moof_offset)
3938 offset += (guint64) (base_offset - qtdemux->moof_offset);
3939 if (info_type == FOURCC_cenc && info_type_parameter == 0U) {
3941 if (offset > length) {
3942 GST_DEBUG_OBJECT (qtdemux, "cenc auxiliary info stored out of moof");
3943 qtdemux->cenc_aux_info_offset = offset;
3945 gst_byte_reader_init (&br, buffer + offset, length - offset);
3946 if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
3947 qtdemux->cenc_aux_info_sizes,
3948 qtdemux->cenc_aux_sample_count)) {
3949 GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
3950 g_free (qtdemux->cenc_aux_info_sizes);
3951 qtdemux->cenc_aux_info_sizes = NULL;
3959 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfdt,
3962 /* We'll use decode_time to interpolate timestamps
3963 * in case the input timestamps are missing */
3964 qtdemux_parse_tfdt (qtdemux, &tfdt_data, &decode_time);
3966 GST_DEBUG_OBJECT (qtdemux, "decode time %" G_GINT64_FORMAT
3967 " (%" GST_TIME_FORMAT ")", decode_time,
3968 GST_TIME_ARGS (stream ? QTSTREAMTIME_TO_GSTTIME (stream,
3969 decode_time) : GST_CLOCK_TIME_NONE));
3971 /* Discard the fragment buffer timestamp info to avoid using it.
3972 * Rely on tfdt instead as it is more accurate than the timestamp
3973 * that is fetched from a manifest/playlist and is usually
3975 qtdemux->fragment_start = -1;
3978 if (G_UNLIKELY (!stream)) {
3979 /* we lost track of offset, we'll need to regain it,
3980 * but can delay complaining until later or avoid doing so altogether */
3984 if (G_UNLIKELY (base_offset < -1))
3987 if (qtdemux->upstream_format_is_time)
3988 gst_qtdemux_stream_flush_samples_data (qtdemux, stream);
3990 /* initialise moof sample data */
3991 stream->n_samples_moof = 0;
3992 stream->duration_last_moof = stream->duration_moof;
3993 stream->duration_moof = 0;
3995 /* Track Run node */
3997 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_trun,
4000 qtdemux_parse_trun (qtdemux, &trun_data, stream,
4001 ds_duration, ds_size, ds_flags, moof_offset, length, &base_offset,
4002 &running_offset, decode_time, (tfdt_node != NULL));
4003 /* iterate all siblings */
4004 trun_node = qtdemux_tree_get_sibling_by_type_full (trun_node, FOURCC_trun,
4008 uuid_node = qtdemux_tree_get_child_by_type (traf_node, FOURCC_uuid);
4010 guint8 *uuid_buffer = (guint8 *) uuid_node->data;
4011 guint32 box_length = QT_UINT32 (uuid_buffer);
4013 qtdemux_parse_uuid (qtdemux, uuid_buffer, box_length);
4016 /* if no new base_offset provided for next traf,
4017 * base is end of current traf */
4018 base_offset = running_offset;
4019 running_offset = -1;
4021 if (stream->n_samples_moof && stream->duration_moof)
4022 stream->new_caps = TRUE;
4025 /* iterate all siblings */
4026 traf_node = qtdemux_tree_get_sibling_by_type (traf_node, FOURCC_traf);
4029 /* parse any protection system info */
4030 pssh_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_pssh);
4032 GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
4033 qtdemux_parse_pssh (qtdemux, pssh_node);
4034 pssh_node = qtdemux_tree_get_sibling_by_type (pssh_node, FOURCC_pssh);
4037 g_node_destroy (moof_node);
4042 GST_DEBUG_OBJECT (qtdemux, "missing tfhd box");
4047 GST_DEBUG_OBJECT (qtdemux, "Missing mfhd box");
4052 GST_DEBUG_OBJECT (qtdemux, "lost offset");
4057 g_node_destroy (moof_node);
4058 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4059 (_("This file is corrupt and cannot be played.")), (NULL));
4065 /* might be used if some day we actually use mfra & co
4066 * for random access to fragments,
4067 * but that will require quite some modifications and much less relying
4068 * on a sample array */
4072 qtdemux_parse_tfra (GstQTDemux * qtdemux, GNode * tfra_node)
4074 QtDemuxStream *stream;
4075 guint32 ver_flags, track_id, len, num_entries, i;
4076 guint value_size, traf_size, trun_size, sample_size;
4077 guint64 time = 0, moof_offset = 0;
4079 GstBuffer *buf = NULL;
4084 gst_byte_reader_init (&tfra, tfra_node->data, QT_UINT32 (tfra_node->data));
4086 if (!gst_byte_reader_skip (&tfra, 8))
4089 if (!gst_byte_reader_get_uint32_be (&tfra, &ver_flags))
4092 if (!gst_byte_reader_get_uint32_be (&tfra, &track_id)
4093 || !gst_byte_reader_get_uint32_be (&tfra, &len)
4094 || !gst_byte_reader_get_uint32_be (&tfra, &num_entries))
4097 GST_DEBUG_OBJECT (qtdemux, "parsing tfra box for track id %u", track_id);
4099 stream = qtdemux_find_stream (qtdemux, track_id);
4101 goto unknown_trackid;
4103 value_size = ((ver_flags >> 24) == 1) ? sizeof (guint64) : sizeof (guint32);
4104 sample_size = (len & 3) + 1;
4105 trun_size = ((len & 12) >> 2) + 1;
4106 traf_size = ((len & 48) >> 4) + 1;
4108 GST_DEBUG_OBJECT (qtdemux, "%u entries, sizes: value %u, traf %u, trun %u, "
4109 "sample %u", num_entries, value_size, traf_size, trun_size, sample_size);
4111 if (num_entries == 0)
4114 if (!qt_atom_parser_has_chunks (&tfra, num_entries,
4115 value_size + value_size + traf_size + trun_size + sample_size))
4118 g_free (stream->ra_entries);
4119 stream->ra_entries = g_new (QtDemuxRandomAccessEntry, num_entries);
4120 stream->n_ra_entries = num_entries;
4122 for (i = 0; i < num_entries; i++) {
4123 qt_atom_parser_get_offset (&tfra, value_size, &time);
4124 qt_atom_parser_get_offset (&tfra, value_size, &moof_offset);
4125 qt_atom_parser_get_uint_with_size_unchecked (&tfra, traf_size);
4126 qt_atom_parser_get_uint_with_size_unchecked (&tfra, trun_size);
4127 qt_atom_parser_get_uint_with_size_unchecked (&tfra, sample_size);
4129 time = QTSTREAMTIME_TO_GSTTIME (stream, time);
4131 GST_LOG_OBJECT (qtdemux, "fragment time: %" GST_TIME_FORMAT ", "
4132 " moof_offset: %" G_GUINT64_FORMAT, GST_TIME_ARGS (time), moof_offset);
4134 stream->ra_entries[i].ts = time;
4135 stream->ra_entries[i].moof_offset = moof_offset;
4137 /* don't want to go through the entire file and read all moofs at startup */
4139 ret = gst_qtdemux_pull_atom (qtdemux, moof_offset, 0, &buf);
4140 if (ret != GST_FLOW_OK)
4142 qtdemux_parse_moof (qtdemux, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf),
4143 moof_offset, stream);
4144 gst_buffer_unref (buf);
4148 check_update_duration (qtdemux, time);
4155 GST_WARNING_OBJECT (qtdemux, "Couldn't find stream for track %u", track_id);
4160 GST_WARNING_OBJECT (qtdemux, "broken traf box, ignoring");
4165 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
4171 qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux)
4173 GstMapInfo mfro_map = GST_MAP_INFO_INIT;
4174 GstMapInfo mfra_map = GST_MAP_INFO_INIT;
4175 GstBuffer *mfro = NULL, *mfra = NULL;
4177 gboolean ret = FALSE;
4178 GNode *mfra_node, *tfra_node;
4179 guint64 mfra_offset = 0;
4180 guint32 fourcc, mfra_size;
4183 /* query upstream size in bytes */
4184 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &len))
4185 goto size_query_failed;
4187 /* mfro box should be at the very end of the file */
4188 flow = gst_qtdemux_pull_atom (qtdemux, len - 16, 16, &mfro);
4189 if (flow != GST_FLOW_OK)
4192 gst_buffer_map (mfro, &mfro_map, GST_MAP_READ);
4194 fourcc = QT_FOURCC (mfro_map.data + 4);
4195 if (fourcc != FOURCC_mfro)
4198 GST_INFO_OBJECT (qtdemux, "Found mfro box");
4199 if (mfro_map.size < 16)
4200 goto invalid_mfro_size;
4202 mfra_size = QT_UINT32 (mfro_map.data + 12);
4203 if (mfra_size >= len)
4204 goto invalid_mfra_size;
4206 mfra_offset = len - mfra_size;
4208 GST_INFO_OBJECT (qtdemux, "mfra offset: %" G_GUINT64_FORMAT ", size %u",
4209 mfra_offset, mfra_size);
4211 /* now get and parse mfra box */
4212 flow = gst_qtdemux_pull_atom (qtdemux, mfra_offset, mfra_size, &mfra);
4213 if (flow != GST_FLOW_OK)
4216 gst_buffer_map (mfra, &mfra_map, GST_MAP_READ);
4218 mfra_node = g_node_new ((guint8 *) mfra_map.data);
4219 qtdemux_parse_node (qtdemux, mfra_node, mfra_map.data, mfra_map.size);
4221 tfra_node = qtdemux_tree_get_child_by_type (mfra_node, FOURCC_tfra);
4224 qtdemux_parse_tfra (qtdemux, tfra_node);
4225 /* iterate all siblings */
4226 tfra_node = qtdemux_tree_get_sibling_by_type (tfra_node, FOURCC_tfra);
4228 g_node_destroy (mfra_node);
4230 GST_INFO_OBJECT (qtdemux, "parsed movie fragment random access box (mfra)");
4236 if (mfro_map.memory != NULL)
4237 gst_buffer_unmap (mfro, &mfro_map);
4238 gst_buffer_unref (mfro);
4241 if (mfra_map.memory != NULL)
4242 gst_buffer_unmap (mfra, &mfra_map);
4243 gst_buffer_unref (mfra);
4250 GST_WARNING_OBJECT (qtdemux, "could not query upstream size");
4255 GST_WARNING_OBJECT (qtdemux, "mfro size is too small");
4260 GST_WARNING_OBJECT (qtdemux, "mfra_size in mfro box is invalid");
4265 GST_WARNING_OBJECT (qtdemux, "bogus mfra offset or size, broken file");
4271 add_offset (guint64 offset, guint64 advance)
4273 /* Avoid 64-bit overflow by clamping */
4274 if (offset > G_MAXUINT64 - advance)
4276 return offset + advance;
4279 static GstFlowReturn
4280 gst_qtdemux_loop_state_header (GstQTDemux * qtdemux)
4284 GstBuffer *buf = NULL;
4285 GstFlowReturn ret = GST_FLOW_OK;
4286 guint64 cur_offset = qtdemux->offset;
4289 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, 16, &buf);
4290 if (G_UNLIKELY (ret != GST_FLOW_OK))
4292 gst_buffer_map (buf, &map, GST_MAP_READ);
4293 if (G_LIKELY (map.size >= 8))
4294 extract_initial_length_and_fourcc (map.data, map.size, &length, &fourcc);
4295 gst_buffer_unmap (buf, &map);
4296 gst_buffer_unref (buf);
4298 /* maybe we already got most we needed, so only consider this eof */
4299 if (G_UNLIKELY (length == 0)) {
4300 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
4301 (_("Invalid atom size.")),
4302 ("Header atom '%" GST_FOURCC_FORMAT "' has empty length",
4303 GST_FOURCC_ARGS (fourcc)));
4310 /* record for later parsing when needed */
4311 if (!qtdemux->moof_offset) {
4312 qtdemux->moof_offset = qtdemux->offset;
4314 if (qtdemux_pull_mfro_mfra (qtdemux)) {
4317 qtdemux->offset += length; /* skip moof and keep going */
4319 if (qtdemux->got_moov) {
4320 GST_INFO_OBJECT (qtdemux, "moof header, got moov, done with headers");
4332 GST_LOG_OBJECT (qtdemux,
4333 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
4334 GST_FOURCC_ARGS (fourcc), cur_offset);
4335 qtdemux->offset = add_offset (qtdemux->offset, length);
4340 GstBuffer *moov = NULL;
4342 if (qtdemux->got_moov) {
4343 GST_DEBUG_OBJECT (qtdemux, "Skipping moov atom as we have one already");
4344 qtdemux->offset = add_offset (qtdemux->offset, length);
4348 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, length, &moov);
4349 if (ret != GST_FLOW_OK)
4351 gst_buffer_map (moov, &map, GST_MAP_READ);
4353 if (length != map.size) {
4354 /* Some files have a 'moov' atom at the end of the file which contains
4355 * a terminal 'free' atom where the body of the atom is missing.
4356 * Check for, and permit, this special case.
4358 if (map.size >= 8) {
4359 guint8 *final_data = map.data + (map.size - 8);
4360 guint32 final_length = QT_UINT32 (final_data);
4361 guint32 final_fourcc = QT_FOURCC (final_data + 4);
4363 if (final_fourcc == FOURCC_free
4364 && map.size + final_length - 8 == length) {
4365 /* Ok, we've found that special case. Allocate a new buffer with
4366 * that free atom actually present. */
4367 GstBuffer *newmoov = gst_buffer_new_and_alloc (length);
4368 gst_buffer_fill (newmoov, 0, map.data, map.size);
4369 gst_buffer_memset (newmoov, map.size, 0, final_length - 8);
4370 gst_buffer_unmap (moov, &map);
4371 gst_buffer_unref (moov);
4373 gst_buffer_map (moov, &map, GST_MAP_READ);
4378 if (length != map.size) {
4379 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4380 (_("This file is incomplete and cannot be played.")),
4381 ("We got less than expected (received %" G_GSIZE_FORMAT
4382 ", wanted %u, offset %" G_GUINT64_FORMAT ")", map.size,
4383 (guint) length, cur_offset));
4384 gst_buffer_unmap (moov, &map);
4385 gst_buffer_unref (moov);
4386 ret = GST_FLOW_ERROR;
4389 qtdemux->offset += length;
4391 qtdemux_parse_moov (qtdemux, map.data, length);
4392 qtdemux_node_dump (qtdemux, qtdemux->moov_node);
4394 qtdemux_parse_tree (qtdemux);
4395 if (qtdemux->moov_node_compressed) {
4396 g_node_destroy (qtdemux->moov_node_compressed);
4397 g_free (qtdemux->moov_node->data);
4399 qtdemux->moov_node_compressed = NULL;
4400 g_node_destroy (qtdemux->moov_node);
4401 qtdemux->moov_node = NULL;
4402 gst_buffer_unmap (moov, &map);
4403 gst_buffer_unref (moov);
4404 qtdemux->got_moov = TRUE;
4410 GstBuffer *ftyp = NULL;
4412 /* extract major brand; might come in handy for ISO vs QT issues */
4413 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &ftyp);
4414 if (ret != GST_FLOW_OK)
4416 qtdemux->offset += length;
4417 gst_buffer_map (ftyp, &map, GST_MAP_READ);
4418 qtdemux_parse_ftyp (qtdemux, map.data, map.size);
4419 gst_buffer_unmap (ftyp, &map);
4420 gst_buffer_unref (ftyp);
4425 GstBuffer *uuid = NULL;
4427 /* uuid are extension atoms */
4428 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &uuid);
4429 if (ret != GST_FLOW_OK)
4431 qtdemux->offset += length;
4432 gst_buffer_map (uuid, &map, GST_MAP_READ);
4433 qtdemux_parse_uuid (qtdemux, map.data, map.size);
4434 gst_buffer_unmap (uuid, &map);
4435 gst_buffer_unref (uuid);
4440 GstBuffer *sidx = NULL;
4441 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &sidx);
4442 if (ret != GST_FLOW_OK)
4444 qtdemux->offset += length;
4445 gst_buffer_map (sidx, &map, GST_MAP_READ);
4446 qtdemux_parse_sidx (qtdemux, map.data, map.size);
4447 gst_buffer_unmap (sidx, &map);
4448 gst_buffer_unref (sidx);
4453 GstBuffer *unknown = NULL;
4455 GST_LOG_OBJECT (qtdemux,
4456 "unknown %08x '%" GST_FOURCC_FORMAT "' of size %" G_GUINT64_FORMAT
4457 " at %" G_GUINT64_FORMAT, fourcc, GST_FOURCC_ARGS (fourcc), length,
4459 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &unknown);
4460 if (ret != GST_FLOW_OK)
4462 gst_buffer_map (unknown, &map, GST_MAP_READ);
4463 GST_MEMDUMP ("Unknown tag", map.data, map.size);
4464 gst_buffer_unmap (unknown, &map);
4465 gst_buffer_unref (unknown);
4466 qtdemux->offset += length;
4472 if (ret == GST_FLOW_EOS && (qtdemux->got_moov || qtdemux->media_caps)) {
4473 /* digested all data, show what we have */
4474 qtdemux_prepare_streams (qtdemux);
4475 ret = qtdemux_expose_streams (qtdemux);
4477 qtdemux->state = QTDEMUX_STATE_MOVIE;
4478 GST_DEBUG_OBJECT (qtdemux, "switching state to STATE_MOVIE (%d)",
4485 /* Seeks to the previous keyframe of the indexed stream and
4486 * aligns other streams with respect to the keyframe timestamp
4487 * of indexed stream. Only called in case of Reverse Playback
4489 static GstFlowReturn
4490 gst_qtdemux_seek_to_previous_keyframe (GstQTDemux * qtdemux)
4493 guint32 seg_idx = 0, k_index = 0;
4494 guint32 ref_seg_idx, ref_k_index;
4495 GstClockTime k_pos = 0, last_stop = 0;
4496 QtDemuxSegment *seg = NULL;
4497 QtDemuxStream *ref_str = NULL;
4498 guint64 seg_media_start_mov; /* segment media start time in mov format */
4501 /* Now we choose an arbitrary stream, get the previous keyframe timestamp
4502 * and finally align all the other streams on that timestamp with their
4503 * respective keyframes */
4504 for (n = 0; n < qtdemux->n_streams; n++) {
4505 QtDemuxStream *str = qtdemux->streams[n];
4507 /* No candidate yet, take the first stream */
4513 /* So that stream has a segment, we prefer video streams */
4514 if (str->subtype == FOURCC_vide) {
4520 if (G_UNLIKELY (!ref_str)) {
4521 GST_DEBUG_OBJECT (qtdemux, "couldn't find any stream");
4525 if (G_UNLIKELY (!ref_str->from_sample)) {
4526 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of the file");
4530 /* So that stream has been playing from from_sample to to_sample. We will
4531 * get the timestamp of the previous sample and search for a keyframe before
4532 * that. For audio streams we do an arbitrary jump in the past (10 samples) */
4533 if (ref_str->subtype == FOURCC_vide) {
4534 k_index = gst_qtdemux_find_keyframe (qtdemux, ref_str,
4535 ref_str->from_sample - 1, FALSE);
4537 if (ref_str->from_sample >= 10)
4538 k_index = ref_str->from_sample - 10;
4544 ref_str->samples[k_index].timestamp +
4545 ref_str->samples[k_index].pts_offset;
4547 /* get current segment for that stream */
4548 seg = &ref_str->segments[ref_str->segment_index];
4549 /* Use segment start in original timescale for comparisons */
4550 seg_media_start_mov = seg->trak_media_start;
4552 GST_LOG_OBJECT (qtdemux, "keyframe index %u ts %" G_GUINT64_FORMAT
4553 " seg start %" G_GUINT64_FORMAT " %" GST_TIME_FORMAT "\n",
4554 k_index, target_ts, seg_media_start_mov,
4555 GST_TIME_ARGS (seg->media_start));
4557 /* Crawl back through segments to find the one containing this I frame */
4558 while (target_ts < seg_media_start_mov) {
4559 GST_DEBUG_OBJECT (qtdemux,
4560 "keyframe position (sample %u) is out of segment %u " " target %"
4561 G_GUINT64_FORMAT " seg start %" G_GUINT64_FORMAT, k_index,
4562 ref_str->segment_index, target_ts, seg_media_start_mov);
4564 if (G_UNLIKELY (!ref_str->segment_index)) {
4565 /* Reached first segment, let's consider it's EOS */
4568 ref_str->segment_index--;
4569 seg = &ref_str->segments[ref_str->segment_index];
4570 /* Use segment start in original timescale for comparisons */
4571 seg_media_start_mov = seg->trak_media_start;
4573 /* Calculate time position of the keyframe and where we should stop */
4575 QTSTREAMTIME_TO_GSTTIME (ref_str,
4576 target_ts - seg->trak_media_start) + seg->time;
4578 QTSTREAMTIME_TO_GSTTIME (ref_str,
4579 ref_str->samples[ref_str->from_sample].timestamp -
4580 seg->trak_media_start) + seg->time;
4582 GST_DEBUG_OBJECT (qtdemux, "preferred stream played from sample %u, "
4583 "now going to sample %u (pts %" GST_TIME_FORMAT ")", ref_str->from_sample,
4584 k_index, GST_TIME_ARGS (k_pos));
4586 /* Set last_stop with the keyframe timestamp we pushed of that stream */
4587 qtdemux->segment.position = last_stop;
4588 GST_DEBUG_OBJECT (qtdemux, "last_stop now is %" GST_TIME_FORMAT,
4589 GST_TIME_ARGS (last_stop));
4591 if (G_UNLIKELY (last_stop < qtdemux->segment.start)) {
4592 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of segment");
4596 ref_seg_idx = ref_str->segment_index;
4597 ref_k_index = k_index;
4599 /* Align them all on this */
4600 for (n = 0; n < qtdemux->n_streams; n++) {
4602 GstClockTime seg_time = 0;
4603 QtDemuxStream *str = qtdemux->streams[n];
4605 /* aligning reference stream again might lead to backing up to yet another
4606 * keyframe (due to timestamp rounding issues),
4607 * potentially putting more load on downstream; so let's try to avoid */
4608 if (str == ref_str) {
4609 seg_idx = ref_seg_idx;
4610 seg = &str->segments[seg_idx];
4611 k_index = ref_k_index;
4612 GST_DEBUG_OBJECT (qtdemux, "reference stream %d segment %d, "
4613 "sample at index %d", n, ref_str->segment_index, k_index);
4615 seg_idx = gst_qtdemux_find_segment (qtdemux, str, k_pos);
4616 GST_DEBUG_OBJECT (qtdemux,
4617 "stream %d align segment %d for keyframe pos %" GST_TIME_FORMAT, n,
4618 seg_idx, GST_TIME_ARGS (k_pos));
4620 /* get segment and time in the segment */
4621 seg = &str->segments[seg_idx];
4622 seg_time = k_pos - seg->time;
4624 /* get the media time in the segment.
4625 * No adjustment for empty "filler" segments */
4626 if (seg->media_start != GST_CLOCK_TIME_NONE)
4627 seg_time += seg->media_start;
4629 /* get the index of the sample with media time */
4630 index = gst_qtdemux_find_index_linear (qtdemux, str, seg_time);
4631 GST_DEBUG_OBJECT (qtdemux,
4632 "stream %d sample for %" GST_TIME_FORMAT " at %u", n,
4633 GST_TIME_ARGS (seg_time), index);
4635 /* find previous keyframe */
4636 k_index = gst_qtdemux_find_keyframe (qtdemux, str, index, FALSE);
4639 /* Remember until where we want to go */
4640 str->to_sample = str->from_sample - 1;
4641 /* Define our time position */
4643 str->samples[k_index].timestamp + str->samples[k_index].pts_offset;
4644 str->time_position = QTSTREAMTIME_TO_GSTTIME (str, target_ts) + seg->time;
4645 if (seg->media_start != GST_CLOCK_TIME_NONE)
4646 str->time_position -= seg->media_start;
4648 /* Now seek back in time */
4649 gst_qtdemux_move_stream (qtdemux, str, k_index);
4650 GST_DEBUG_OBJECT (qtdemux, "stream %d keyframe at %u, time position %"
4651 GST_TIME_FORMAT " playing from sample %u to %u", n, k_index,
4652 GST_TIME_ARGS (str->time_position), str->from_sample, str->to_sample);
4658 return GST_FLOW_EOS;
4662 * Gets the current qt segment start, stop and position for the
4663 * given time offset. This is used in update_segment()
4666 gst_qtdemux_stream_segment_get_boundaries (GstQTDemux * qtdemux,
4667 QtDemuxStream * stream, GstClockTime offset,
4668 GstClockTime * _start, GstClockTime * _stop, GstClockTime * _time)
4670 GstClockTime seg_time;
4671 GstClockTime start, stop, time;
4672 QtDemuxSegment *segment;
4674 segment = &stream->segments[stream->segment_index];
4676 /* get time in this segment */
4677 seg_time = (offset - segment->time) * segment->rate;
4679 GST_LOG_OBJECT (stream->pad, "seg_time %" GST_TIME_FORMAT,
4680 GST_TIME_ARGS (seg_time));
4682 if (G_UNLIKELY (seg_time > segment->duration)) {
4683 GST_LOG_OBJECT (stream->pad,
4684 "seg_time > segment->duration %" GST_TIME_FORMAT,
4685 GST_TIME_ARGS (segment->duration));
4686 seg_time = segment->duration;
4689 /* qtdemux->segment.stop is in outside-time-realm, whereas
4690 * segment->media_stop is in track-time-realm.
4692 * In order to compare the two, we need to bring segment.stop
4693 * into the track-time-realm
4695 * FIXME - does this comment still hold? Don't see any conversion here */
4697 stop = qtdemux->segment.stop;
4698 if (stop == GST_CLOCK_TIME_NONE)
4699 stop = qtdemux->segment.duration;
4700 if (stop == GST_CLOCK_TIME_NONE)
4701 stop = segment->media_stop;
4704 MIN (segment->media_stop, stop - segment->time + segment->media_start);
4706 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
4707 start = segment->time + seg_time;
4709 stop = start - seg_time + segment->duration;
4710 } else if (qtdemux->segment.rate >= 0) {
4711 start = MIN (segment->media_start + seg_time, stop);
4714 if (segment->media_start >= qtdemux->segment.start) {
4715 time = segment->time;
4717 time = segment->time + (qtdemux->segment.start - segment->media_start);
4720 start = MAX (segment->media_start, qtdemux->segment.start);
4721 stop = MIN (segment->media_start + seg_time, stop);
4730 * Updates the qt segment used for the stream and pushes a new segment event
4731 * downstream on this stream's pad.
4734 gst_qtdemux_stream_update_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
4735 gint seg_idx, GstClockTime offset, GstClockTime * _start,
4736 GstClockTime * _stop)
4738 QtDemuxSegment *segment;
4739 GstClockTime start = 0, stop = GST_CLOCK_TIME_NONE, time = 0;
4743 /* update the current segment */
4744 stream->segment_index = seg_idx;
4746 /* get the segment */
4747 segment = &stream->segments[seg_idx];
4749 if (G_UNLIKELY (offset < segment->time)) {
4750 GST_WARNING_OBJECT (stream->pad, "offset < segment->time %" GST_TIME_FORMAT,
4751 GST_TIME_ARGS (segment->time));
4755 /* segment lies beyond total indicated duration */
4756 if (G_UNLIKELY (qtdemux->segment.duration != GST_CLOCK_TIME_NONE &&
4757 segment->time > qtdemux->segment.duration)) {
4758 GST_WARNING_OBJECT (stream->pad, "file duration %" GST_TIME_FORMAT
4759 " < segment->time %" GST_TIME_FORMAT,
4760 GST_TIME_ARGS (qtdemux->segment.duration),
4761 GST_TIME_ARGS (segment->time));
4765 gst_qtdemux_stream_segment_get_boundaries (qtdemux, stream, offset,
4766 &start, &stop, &time);
4768 GST_DEBUG_OBJECT (stream->pad, "new segment %d from %" GST_TIME_FORMAT
4769 " to %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT, seg_idx,
4770 GST_TIME_ARGS (start), GST_TIME_ARGS (stop), GST_TIME_ARGS (time));
4772 /* combine global rate with that of the segment */
4773 rate = segment->rate * qtdemux->segment.rate;
4775 /* Copy flags from main segment */
4776 stream->segment.flags = qtdemux->segment.flags;
4778 /* update the segment values used for clipping */
4779 stream->segment.offset = qtdemux->segment.offset;
4780 stream->segment.base = qtdemux->segment.base + stream->accumulated_base;
4781 stream->segment.applied_rate = qtdemux->segment.applied_rate;
4782 stream->segment.rate = rate;
4783 stream->segment.start = start + QTSTREAMTIME_TO_GSTTIME (stream,
4784 stream->cslg_shift);
4785 stream->segment.stop = stop + QTSTREAMTIME_TO_GSTTIME (stream,
4786 stream->cslg_shift);
4787 stream->segment.time = time;
4788 stream->segment.position = stream->segment.start;
4790 GST_DEBUG_OBJECT (stream->pad, "New segment: %" GST_SEGMENT_FORMAT,
4793 /* now prepare and send the segment */
4795 event = gst_event_new_segment (&stream->segment);
4796 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID) {
4797 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
4799 gst_pad_push_event (stream->pad, event);
4800 /* assume we can send more data now */
4801 GST_PAD_LAST_FLOW_RETURN (stream->pad) = GST_FLOW_OK;
4802 /* clear to send tags on this pad now */
4803 gst_qtdemux_push_tags (qtdemux, stream);
4814 /* activate the given segment number @seg_idx of @stream at time @offset.
4815 * @offset is an absolute global position over all the segments.
4817 * This will push out a NEWSEGMENT event with the right values and
4818 * position the stream index to the first decodable sample before
4822 gst_qtdemux_activate_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
4823 guint32 seg_idx, GstClockTime offset)
4825 QtDemuxSegment *segment;
4826 guint32 index, kf_index;
4827 GstClockTime start = 0, stop = GST_CLOCK_TIME_NONE;
4829 GST_LOG_OBJECT (stream->pad, "activate segment %d, offset %" GST_TIME_FORMAT,
4830 seg_idx, GST_TIME_ARGS (offset));
4832 if (!gst_qtdemux_stream_update_segment (qtdemux, stream, seg_idx, offset,
4836 segment = &stream->segments[stream->segment_index];
4838 /* in the fragmented case, we pick a fragment that starts before our
4839 * desired position and rely on downstream to wait for a keyframe
4840 * (FIXME: doesn't seem to work so well with ismv and wmv, as no parser; the
4841 * tfra entries tells us which trun/sample the key unit is in, but we don't
4842 * make use of this additional information at the moment) */
4843 if (qtdemux->fragmented && !qtdemux->fragmented_seek_pending) {
4844 stream->to_sample = G_MAXUINT32;
4847 /* well, it will be taken care of below */
4848 qtdemux->fragmented_seek_pending = FALSE;
4849 /* FIXME ideally the do_fragmented_seek can be done right here,
4850 * rather than at loop level
4851 * (which might even allow handling edit lists in a fragmented file) */
4854 /* We don't need to look for a sample in push-based */
4855 if (!qtdemux->pullbased)
4858 /* and move to the keyframe before the indicated media time of the
4860 if (G_LIKELY (!QTSEGMENT_IS_EMPTY (segment))) {
4861 if (qtdemux->segment.rate >= 0) {
4862 index = gst_qtdemux_find_index_linear (qtdemux, stream, start);
4863 stream->to_sample = G_MAXUINT32;
4864 GST_DEBUG_OBJECT (stream->pad,
4865 "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
4866 GST_TIME_FORMAT, GST_TIME_ARGS (start), index,
4867 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
4869 index = gst_qtdemux_find_index_linear (qtdemux, stream, stop);
4870 stream->to_sample = index;
4871 GST_DEBUG_OBJECT (stream->pad,
4872 "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
4873 GST_TIME_FORMAT, GST_TIME_ARGS (stop), index,
4874 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
4877 GST_DEBUG_OBJECT (stream->pad, "No need to look for keyframe, "
4878 "this is an empty segment");
4882 /* gst_qtdemux_parse_sample () called from gst_qtdemux_find_index_linear ()
4883 * encountered an error and printed a message so we return appropriately */
4887 /* we're at the right spot */
4888 if (index == stream->sample_index) {
4889 GST_DEBUG_OBJECT (stream->pad, "we are at the right index");
4893 /* find keyframe of the target index */
4894 kf_index = gst_qtdemux_find_keyframe (qtdemux, stream, index, FALSE);
4897 /* indent does stupid stuff with stream->samples[].timestamp */
4899 /* if we move forwards, we don't have to go back to the previous
4900 * keyframe since we already sent that. We can also just jump to
4901 * the keyframe right before the target index if there is one. */
4902 if (index > stream->sample_index) {
4903 /* moving forwards check if we move past a keyframe */
4904 if (kf_index > stream->sample_index) {
4905 GST_DEBUG_OBJECT (stream->pad,
4906 "moving forwards to keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" )", kf_index,
4907 GST_TIME_ARGS (QTSAMPLE_PTS(stream, &stream->samples[kf_index])),
4908 GST_TIME_ARGS (QTSAMPLE_DTS(stream, &stream->samples[kf_index])));
4909 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
4911 GST_DEBUG_OBJECT (stream->pad,
4912 "moving forwards, keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" ) already sent", kf_index,
4913 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[kf_index])),
4914 GST_TIME_ARGS (QTSAMPLE_DTS (stream, &stream->samples[kf_index])));
4917 GST_DEBUG_OBJECT (stream->pad,
4918 "moving backwards to keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" )", kf_index,
4919 GST_TIME_ARGS (QTSAMPLE_PTS(stream, &stream->samples[kf_index])),
4920 GST_TIME_ARGS (QTSAMPLE_DTS(stream, &stream->samples[kf_index])));
4921 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
4929 /* prepare to get the current sample of @stream, getting essential values.
4931 * This function will also prepare and send the segment when needed.
4933 * Return FALSE if the stream is EOS.
4938 gst_qtdemux_prepare_current_sample (GstQTDemux * qtdemux,
4939 QtDemuxStream * stream, gboolean * empty, guint64 * offset, guint * size,
4940 GstClockTime * dts, GstClockTime * pts, GstClockTime * duration,
4941 gboolean * keyframe)
4943 QtDemuxSample *sample;
4944 GstClockTime time_position;
4947 g_return_val_if_fail (stream != NULL, FALSE);
4949 time_position = stream->time_position;
4950 if (G_UNLIKELY (time_position == GST_CLOCK_TIME_NONE))
4953 seg_idx = stream->segment_index;
4954 if (G_UNLIKELY (seg_idx == -1)) {
4955 /* find segment corresponding to time_position if we are looking
4957 seg_idx = gst_qtdemux_find_segment (qtdemux, stream, time_position);
4960 /* different segment, activate it, sample_index will be set. */
4961 if (G_UNLIKELY (stream->segment_index != seg_idx))
4962 gst_qtdemux_activate_segment (qtdemux, stream, seg_idx, time_position);
4964 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (&stream->segments[stream->
4966 QtDemuxSegment *seg = &stream->segments[stream->segment_index];
4968 GST_LOG_OBJECT (qtdemux, "Empty segment activated,"
4969 " prepare empty sample");
4972 *pts = *dts = time_position;
4973 *duration = seg->duration - (time_position - seg->time);
4980 if (stream->sample_index == -1)
4981 stream->sample_index = 0;
4983 GST_LOG_OBJECT (qtdemux, "segment active, index = %u of %u",
4984 stream->sample_index, stream->n_samples);
4986 if (G_UNLIKELY (stream->sample_index >= stream->n_samples)) {
4987 if (!qtdemux->fragmented)
4990 GST_INFO_OBJECT (qtdemux, "out of samples, trying to add more");
4994 GST_OBJECT_LOCK (qtdemux);
4995 flow = qtdemux_add_fragmented_samples (qtdemux);
4996 GST_OBJECT_UNLOCK (qtdemux);
4998 if (flow != GST_FLOW_OK)
5001 while (stream->sample_index >= stream->n_samples);
5004 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
5005 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
5006 stream->sample_index);
5010 /* now get the info for the sample we're at */
5011 sample = &stream->samples[stream->sample_index];
5013 *dts = QTSAMPLE_DTS (stream, sample);
5014 *pts = QTSAMPLE_PTS (stream, sample);
5015 *offset = sample->offset;
5016 *size = sample->size;
5017 *duration = QTSAMPLE_DUR_DTS (stream, sample, *dts);
5018 *keyframe = QTSAMPLE_KEYFRAME (stream, sample);
5025 stream->time_position = GST_CLOCK_TIME_NONE;
5030 /* move to the next sample in @stream.
5032 * Moves to the next segment when needed.
5035 gst_qtdemux_advance_sample (GstQTDemux * qtdemux, QtDemuxStream * stream)
5037 QtDemuxSample *sample;
5038 QtDemuxSegment *segment;
5040 /* get current segment */
5041 segment = &stream->segments[stream->segment_index];
5043 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
5044 GST_DEBUG_OBJECT (qtdemux, "Empty segment, no samples to advance");
5048 if (G_UNLIKELY (stream->sample_index >= stream->to_sample)) {
5049 /* Mark the stream as EOS */
5050 GST_DEBUG_OBJECT (qtdemux,
5051 "reached max allowed sample %u, mark EOS", stream->to_sample);
5052 stream->time_position = GST_CLOCK_TIME_NONE;
5056 /* move to next sample */
5057 stream->sample_index++;
5058 stream->offset_in_sample = 0;
5060 /* reached the last sample, we need the next segment */
5061 if (G_UNLIKELY (stream->sample_index >= stream->n_samples))
5064 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
5065 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
5066 stream->sample_index);
5070 /* get next sample */
5071 sample = &stream->samples[stream->sample_index];
5073 /* see if we are past the segment */
5074 if (G_UNLIKELY (QTSAMPLE_DTS (stream, sample) >= segment->media_stop))
5077 if (QTSAMPLE_DTS (stream, sample) >= segment->media_start) {
5078 /* inside the segment, update time_position, looks very familiar to
5079 * GStreamer segments, doesn't it? */
5080 stream->time_position =
5081 QTSAMPLE_DTS (stream, sample) - segment->media_start + segment->time;
5083 /* not yet in segment, time does not yet increment. This means
5084 * that we are still prerolling keyframes to the decoder so it can
5085 * decode the first sample of the segment. */
5086 stream->time_position = segment->time;
5090 /* move to the next segment */
5093 GST_DEBUG_OBJECT (qtdemux, "segment %d ended ", stream->segment_index);
5095 if (stream->segment_index == stream->n_segments - 1) {
5096 /* are we at the end of the last segment, we're EOS */
5097 stream->time_position = GST_CLOCK_TIME_NONE;
5099 /* else we're only at the end of the current segment */
5100 stream->time_position = segment->stop_time;
5102 /* make sure we select a new segment */
5104 /* accumulate previous segments */
5105 if (GST_CLOCK_TIME_IS_VALID (stream->segment.stop))
5106 stream->accumulated_base +=
5107 (stream->segment.stop -
5108 stream->segment.start) / ABS (stream->segment.rate);
5110 stream->segment_index = -1;
5115 gst_qtdemux_sync_streams (GstQTDemux * demux)
5119 if (demux->n_streams <= 1)
5122 for (i = 0; i < demux->n_streams; i++) {
5123 QtDemuxStream *stream;
5124 GstClockTime end_time;
5126 stream = demux->streams[i];
5131 /* TODO advance time on subtitle streams here, if any some day */
5133 /* some clips/trailers may have unbalanced streams at the end,
5134 * so send EOS on shorter stream to prevent stalling others */
5136 /* do not mess with EOS if SEGMENT seeking */
5137 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT)
5140 if (demux->pullbased) {
5141 /* loop mode is sample time based */
5142 if (!STREAM_IS_EOS (stream))
5145 /* push mode is byte position based */
5146 if (stream->n_samples &&
5147 stream->samples[stream->n_samples - 1].offset >= demux->offset)
5151 if (stream->sent_eos)
5154 /* only act if some gap */
5155 end_time = stream->segments[stream->n_segments - 1].stop_time;
5156 GST_LOG_OBJECT (demux, "current position: %" GST_TIME_FORMAT
5157 ", stream end: %" GST_TIME_FORMAT,
5158 GST_TIME_ARGS (demux->segment.position), GST_TIME_ARGS (end_time));
5159 if (GST_CLOCK_TIME_IS_VALID (end_time)
5160 && (end_time + 2 * GST_SECOND < demux->segment.position)) {
5163 GST_DEBUG_OBJECT (demux, "sending EOS for stream %s",
5164 GST_PAD_NAME (stream->pad));
5165 stream->sent_eos = TRUE;
5166 event = gst_event_new_eos ();
5167 if (demux->segment_seqnum != GST_SEQNUM_INVALID)
5168 gst_event_set_seqnum (event, demux->segment_seqnum);
5169 gst_pad_push_event (stream->pad, event);
5174 /* EOS and NOT_LINKED need to be combined. This means that we return:
5176 * GST_FLOW_NOT_LINKED: when all pads NOT_LINKED.
5177 * GST_FLOW_EOS: when all pads EOS or NOT_LINKED.
5179 static GstFlowReturn
5180 gst_qtdemux_combine_flows (GstQTDemux * demux, QtDemuxStream * stream,
5183 GST_LOG_OBJECT (demux, "flow return: %s", gst_flow_get_name (ret));
5186 ret = gst_flow_combiner_update_pad_flow (demux->flowcombiner, stream->pad,
5189 ret = gst_flow_combiner_update_flow (demux->flowcombiner, ret);
5191 GST_LOG_OBJECT (demux, "combined flow return: %s", gst_flow_get_name (ret));
5195 /* the input buffer metadata must be writable. Returns NULL when the buffer is
5196 * completely clipped
5198 * Should be used only with raw buffers */
5200 gst_qtdemux_clip_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
5203 guint64 start, stop, cstart, cstop, diff;
5204 GstClockTime pts, duration;
5206 gint num_rate, denom_rate;
5211 osize = size = gst_buffer_get_size (buf);
5214 /* depending on the type, setup the clip parameters */
5215 if (stream->subtype == FOURCC_soun) {
5216 frame_size = CUR_STREAM (stream)->bytes_per_frame;
5217 num_rate = GST_SECOND;
5218 denom_rate = (gint) CUR_STREAM (stream)->rate;
5220 } else if (stream->subtype == FOURCC_vide) {
5222 num_rate = CUR_STREAM (stream)->fps_n;
5223 denom_rate = CUR_STREAM (stream)->fps_d;
5228 if (frame_size <= 0)
5229 goto bad_frame_size;
5231 /* we can only clip if we have a valid pts */
5232 pts = GST_BUFFER_PTS (buf);
5233 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (pts)))
5236 duration = GST_BUFFER_DURATION (buf);
5238 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (duration))) {
5240 gst_util_uint64_scale_int (size / frame_size, num_rate, denom_rate);
5244 stop = start + duration;
5246 if (G_UNLIKELY (!gst_segment_clip (&stream->segment,
5247 GST_FORMAT_TIME, start, stop, &cstart, &cstop)))
5250 /* see if some clipping happened */
5251 diff = cstart - start;
5257 /* bring clipped time to samples and to bytes */
5258 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
5261 GST_DEBUG_OBJECT (qtdemux,
5262 "clipping start to %" GST_TIME_FORMAT " %"
5263 G_GUINT64_FORMAT " bytes", GST_TIME_ARGS (cstart), diff);
5269 diff = stop - cstop;
5274 /* bring clipped time to samples and then to bytes */
5275 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
5277 GST_DEBUG_OBJECT (qtdemux,
5278 "clipping stop to %" GST_TIME_FORMAT " %" G_GUINT64_FORMAT
5279 " bytes", GST_TIME_ARGS (cstop), diff);
5284 if (offset != 0 || size != osize)
5285 gst_buffer_resize (buf, offset, size);
5287 GST_BUFFER_DTS (buf) = GST_CLOCK_TIME_NONE;
5288 GST_BUFFER_PTS (buf) = pts;
5289 GST_BUFFER_DURATION (buf) = duration;
5293 /* dropped buffer */
5296 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
5301 GST_DEBUG_OBJECT (qtdemux, "bad frame size");
5306 GST_DEBUG_OBJECT (qtdemux, "no pts on buffer");
5311 GST_DEBUG_OBJECT (qtdemux, "clipped buffer");
5312 gst_buffer_unref (buf);
5318 gst_qtdemux_align_buffer (GstQTDemux * demux,
5319 GstBuffer * buffer, gsize alignment)
5323 gst_buffer_map (buffer, &map, GST_MAP_READ);
5325 if (map.size < sizeof (guintptr)) {
5326 gst_buffer_unmap (buffer, &map);
5330 if (((guintptr) map.data) & (alignment - 1)) {
5331 GstBuffer *new_buffer;
5332 GstAllocationParams params = { 0, alignment - 1, 0, 0, };
5334 new_buffer = gst_buffer_new_allocate (NULL,
5335 gst_buffer_get_size (buffer), ¶ms);
5337 /* Copy data "by hand", so ensure alignment is kept: */
5338 gst_buffer_fill (new_buffer, 0, map.data, map.size);
5340 gst_buffer_copy_into (new_buffer, buffer, GST_BUFFER_COPY_METADATA, 0, -1);
5341 GST_DEBUG_OBJECT (demux,
5342 "We want output aligned on %" G_GSIZE_FORMAT ", reallocated",
5345 gst_buffer_unmap (buffer, &map);
5346 gst_buffer_unref (buffer);
5351 gst_buffer_unmap (buffer, &map);
5355 /* the input buffer metadata must be writable,
5356 * but time/duration etc not yet set and need not be preserved */
5358 gst_qtdemux_process_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
5365 /* not many cases for now */
5366 if (G_UNLIKELY (CUR_STREAM (stream)->fourcc == FOURCC_mp4s)) {
5367 /* send a one time dvd clut event */
5368 if (stream->pending_event && stream->pad)
5369 gst_pad_push_event (stream->pad, stream->pending_event);
5370 stream->pending_event = NULL;
5373 if (G_UNLIKELY (stream->subtype != FOURCC_text
5374 && stream->subtype != FOURCC_sbtl &&
5375 stream->subtype != FOURCC_subp)) {
5379 gst_buffer_map (buf, &map, GST_MAP_READ);
5381 /* empty buffer is sent to terminate previous subtitle */
5382 if (map.size <= 2) {
5383 gst_buffer_unmap (buf, &map);
5384 gst_buffer_unref (buf);
5387 if (stream->subtype == FOURCC_subp) {
5388 /* That's all the processing needed for subpictures */
5389 gst_buffer_unmap (buf, &map);
5393 nsize = GST_READ_UINT16_BE (map.data);
5394 nsize = MIN (nsize, map.size - 2);
5396 GST_LOG_OBJECT (qtdemux, "3GPP timed text subtitle: %d/%" G_GSIZE_FORMAT "",
5399 /* takes care of UTF-8 validation or UTF-16 recognition,
5400 * no other encoding expected */
5401 str = gst_tag_freeform_string_to_utf8 ((gchar *) map.data + 2, nsize, NULL);
5402 gst_buffer_unmap (buf, &map);
5404 gst_buffer_unref (buf);
5405 buf = _gst_buffer_new_wrapped (str, strlen (str), g_free);
5407 /* this should not really happen unless the subtitle is corrupted */
5408 gst_buffer_unref (buf);
5412 /* FIXME ? convert optional subsequent style info to markup */
5417 /* Sets a buffer's attributes properly and pushes it downstream.
5418 * Also checks for additional actions and custom processing that may
5419 * need to be done first.
5421 static GstFlowReturn
5422 gst_qtdemux_decorate_and_push_buffer (GstQTDemux * qtdemux,
5423 QtDemuxStream * stream, GstBuffer * buf,
5424 GstClockTime dts, GstClockTime pts, GstClockTime duration,
5425 gboolean keyframe, GstClockTime position, guint64 byte_position)
5427 GstFlowReturn ret = GST_FLOW_OK;
5429 /* offset the timestamps according to the edit list */
5431 if (G_UNLIKELY (CUR_STREAM (stream)->fourcc == FOURCC_rtsp)) {
5435 gst_buffer_map (buf, &map, GST_MAP_READ);
5436 url = g_strndup ((gchar *) map.data, map.size);
5437 gst_buffer_unmap (buf, &map);
5438 if (url != NULL && strlen (url) != 0) {
5439 /* we have RTSP redirect now */
5440 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
5441 gst_message_new_element (GST_OBJECT_CAST (qtdemux),
5442 gst_structure_new ("redirect",
5443 "new-location", G_TYPE_STRING, url, NULL)));
5444 qtdemux->posted_redirect = TRUE;
5446 GST_WARNING_OBJECT (qtdemux, "Redirect URI of stream is empty, not "
5452 /* position reporting */
5453 if (qtdemux->segment.rate >= 0) {
5454 qtdemux->segment.position = position;
5455 gst_qtdemux_sync_streams (qtdemux);
5458 if (G_UNLIKELY (!stream->pad)) {
5459 GST_DEBUG_OBJECT (qtdemux, "No output pad for stream, ignoring");
5460 gst_buffer_unref (buf);
5464 /* send out pending buffers */
5465 while (stream->buffers) {
5466 GstBuffer *buffer = (GstBuffer *) stream->buffers->data;
5468 if (G_UNLIKELY (stream->discont)) {
5469 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
5470 GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
5471 stream->discont = FALSE;
5473 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
5476 if (stream->alignment > 1)
5477 buffer = gst_qtdemux_align_buffer (qtdemux, buffer, stream->alignment);
5478 gst_pad_push (stream->pad, buffer);
5480 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
5483 /* we're going to modify the metadata */
5484 buf = gst_buffer_make_writable (buf);
5486 if (G_UNLIKELY (stream->need_process))
5487 buf = gst_qtdemux_process_buffer (qtdemux, stream, buf);
5493 GST_BUFFER_DTS (buf) = dts;
5494 GST_BUFFER_PTS (buf) = pts;
5495 GST_BUFFER_DURATION (buf) = duration;
5496 GST_BUFFER_OFFSET (buf) = -1;
5497 GST_BUFFER_OFFSET_END (buf) = -1;
5499 if (G_UNLIKELY (CUR_STREAM (stream)->rgb8_palette))
5500 gst_buffer_append_memory (buf,
5501 gst_memory_ref (CUR_STREAM (stream)->rgb8_palette));
5503 if (G_UNLIKELY (CUR_STREAM (stream)->padding)) {
5504 gst_buffer_resize (buf, CUR_STREAM (stream)->padding, -1);
5507 if (G_UNLIKELY (qtdemux->element_index)) {
5508 GstClockTime stream_time;
5511 gst_segment_to_stream_time (&stream->segment, GST_FORMAT_TIME,
5513 if (GST_CLOCK_TIME_IS_VALID (stream_time)) {
5514 GST_LOG_OBJECT (qtdemux,
5515 "adding association %" GST_TIME_FORMAT "-> %"
5516 G_GUINT64_FORMAT, GST_TIME_ARGS (stream_time), byte_position);
5517 gst_index_add_association (qtdemux->element_index,
5519 keyframe ? GST_ASSOCIATION_FLAG_KEY_UNIT :
5520 GST_ASSOCIATION_FLAG_DELTA_UNIT, GST_FORMAT_TIME, stream_time,
5521 GST_FORMAT_BYTES, byte_position, NULL);
5526 if (stream->need_clip)
5527 buf = gst_qtdemux_clip_buffer (qtdemux, stream, buf);
5529 if (G_UNLIKELY (buf == NULL))
5532 if (G_UNLIKELY (stream->discont)) {
5533 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
5534 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
5535 stream->discont = FALSE;
5537 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
5541 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
5542 stream->on_keyframe = FALSE;
5544 stream->on_keyframe = TRUE;
5548 GST_LOG_OBJECT (qtdemux,
5549 "Pushing buffer with dts %" GST_TIME_FORMAT ", pts %" GST_TIME_FORMAT
5550 ", duration %" GST_TIME_FORMAT " on pad %s", GST_TIME_ARGS (dts),
5551 GST_TIME_ARGS (pts), GST_TIME_ARGS (duration),
5552 GST_PAD_NAME (stream->pad));
5554 if (stream->protected && stream->protection_scheme_type == FOURCC_cenc) {
5555 GstStructure *crypto_info;
5556 QtDemuxCencSampleSetInfo *info =
5557 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
5561 while ((event = g_queue_pop_head (&stream->protection_scheme_event_queue))) {
5562 gst_pad_push_event (stream->pad, event);
5565 if (info->crypto_info == NULL) {
5566 GST_DEBUG_OBJECT (qtdemux, "cenc metadata hasn't been parsed yet");
5567 gst_buffer_unref (buf);
5571 /* The end of the crypto_info array matches our n_samples position,
5572 * so count backward from there */
5573 index = stream->sample_index - stream->n_samples + info->crypto_info->len;
5574 if (G_LIKELY (index >= 0 && index < info->crypto_info->len)) {
5575 /* steal structure from array */
5576 crypto_info = g_ptr_array_index (info->crypto_info, index);
5577 g_ptr_array_index (info->crypto_info, index) = NULL;
5578 GST_LOG_OBJECT (qtdemux, "attaching cenc metadata [%u/%u]", index,
5579 info->crypto_info->len);
5580 if (!crypto_info || !gst_buffer_add_protection_meta (buf, crypto_info))
5581 GST_ERROR_OBJECT (qtdemux, "failed to attach cenc metadata to buffer");
5583 GST_INFO_OBJECT (qtdemux, "No crypto info with index %d and sample %d",
5584 index, stream->sample_index);
5588 if (stream->alignment > 1)
5589 buf = gst_qtdemux_align_buffer (qtdemux, buf, stream->alignment);
5591 ret = gst_pad_push (stream->pad, buf);
5593 if (GST_CLOCK_TIME_IS_VALID (pts) && GST_CLOCK_TIME_IS_VALID (duration)) {
5594 /* mark position in stream, we'll need this to know when to send GAP event */
5595 stream->segment.position = pts + duration;
5602 static const QtDemuxRandomAccessEntry *
5603 gst_qtdemux_stream_seek_fragment (GstQTDemux * qtdemux, QtDemuxStream * stream,
5604 GstClockTime pos, gboolean after)
5606 QtDemuxRandomAccessEntry *entries = stream->ra_entries;
5607 guint n_entries = stream->n_ra_entries;
5610 /* we assume the table is sorted */
5611 for (i = 0; i < n_entries; ++i) {
5612 if (entries[i].ts > pos)
5616 /* FIXME: maybe save first moof_offset somewhere instead, but for now it's
5617 * probably okay to assume that the index lists the very first fragment */
5624 return &entries[i - 1];
5628 gst_qtdemux_do_fragmented_seek (GstQTDemux * qtdemux)
5630 const QtDemuxRandomAccessEntry *best_entry = NULL;
5633 GST_OBJECT_LOCK (qtdemux);
5635 g_assert (qtdemux->n_streams > 0);
5637 /* first see if we can determine where to go to using mfra,
5638 * before we start clearing things */
5639 for (i = 0; i < qtdemux->n_streams; i++) {
5640 const QtDemuxRandomAccessEntry *entry;
5641 QtDemuxStream *stream;
5642 gboolean is_audio_or_video;
5644 stream = qtdemux->streams[i];
5646 if (stream->ra_entries == NULL)
5649 if (stream->subtype == FOURCC_vide || stream->subtype == FOURCC_soun)
5650 is_audio_or_video = TRUE;
5652 is_audio_or_video = FALSE;
5655 gst_qtdemux_stream_seek_fragment (qtdemux, stream,
5656 stream->time_position, !is_audio_or_video);
5658 GST_INFO_OBJECT (stream->pad, "%" GST_TIME_FORMAT " at offset "
5659 "%" G_GUINT64_FORMAT, GST_TIME_ARGS (entry->ts), entry->moof_offset);
5661 stream->pending_seek = entry;
5663 /* decide position to jump to just based on audio/video tracks, not subs */
5664 if (!is_audio_or_video)
5667 if (best_entry == NULL || entry->moof_offset < best_entry->moof_offset)
5671 /* no luck, will handle seek otherwise */
5672 if (best_entry == NULL) {
5673 GST_OBJECT_UNLOCK (qtdemux);
5677 /* ok, now we can prepare for processing as of located moof */
5678 for (i = 0; i < qtdemux->n_streams; i++) {
5679 QtDemuxStream *stream;
5681 stream = qtdemux->streams[i];
5683 g_free (stream->samples);
5684 stream->samples = NULL;
5685 stream->n_samples = 0;
5686 stream->stbl_index = -1; /* no samples have yet been parsed */
5687 stream->sample_index = -1;
5689 if (stream->protection_scheme_info) {
5690 /* Clear out any old cenc crypto info entries as we'll move to a new moof */
5691 if (stream->protection_scheme_type == FOURCC_cenc) {
5692 QtDemuxCencSampleSetInfo *info =
5693 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
5694 if (info->crypto_info) {
5695 g_ptr_array_free (info->crypto_info, TRUE);
5696 info->crypto_info = NULL;
5702 GST_INFO_OBJECT (qtdemux, "seek to %" GST_TIME_FORMAT ", best fragment "
5703 "moof offset: %" G_GUINT64_FORMAT ", ts %" GST_TIME_FORMAT,
5704 GST_TIME_ARGS (qtdemux->streams[0]->time_position),
5705 best_entry->moof_offset, GST_TIME_ARGS (best_entry->ts));
5707 qtdemux->moof_offset = best_entry->moof_offset;
5709 qtdemux_add_fragmented_samples (qtdemux);
5711 GST_OBJECT_UNLOCK (qtdemux);
5715 static GstFlowReturn
5716 gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux)
5718 GstFlowReturn ret = GST_FLOW_OK;
5719 GstBuffer *buf = NULL;
5720 QtDemuxStream *stream;
5721 GstClockTime min_time;
5723 GstClockTime dts = GST_CLOCK_TIME_NONE;
5724 GstClockTime pts = GST_CLOCK_TIME_NONE;
5725 GstClockTime duration = 0;
5726 gboolean keyframe = FALSE;
5727 guint sample_size = 0;
5733 gst_qtdemux_push_pending_newsegment (qtdemux);
5735 if (qtdemux->fragmented_seek_pending) {
5736 GST_INFO_OBJECT (qtdemux, "pending fragmented seek");
5737 if (gst_qtdemux_do_fragmented_seek (qtdemux)) {
5738 GST_INFO_OBJECT (qtdemux, "fragmented seek done!");
5739 qtdemux->fragmented_seek_pending = FALSE;
5741 GST_INFO_OBJECT (qtdemux, "fragmented seek still pending");
5745 /* Figure out the next stream sample to output, min_time is expressed in
5746 * global time and runs over the edit list segments. */
5747 min_time = G_MAXUINT64;
5749 for (i = 0; i < qtdemux->n_streams; i++) {
5750 GstClockTime position;
5752 stream = qtdemux->streams[i];
5753 position = stream->time_position;
5755 /* position of -1 is EOS */
5756 if (position != GST_CLOCK_TIME_NONE && position < min_time) {
5757 min_time = position;
5762 if (G_UNLIKELY (index == -1)) {
5763 GST_DEBUG_OBJECT (qtdemux, "all streams are EOS");
5767 /* check for segment end */
5768 if (G_UNLIKELY (qtdemux->segment.stop != -1
5769 && ((qtdemux->segment.rate >= 0 && qtdemux->segment.stop <= min_time)
5770 || (qtdemux->segment.rate < 0
5771 && qtdemux->segment.start > min_time))
5772 && qtdemux->streams[index]->on_keyframe)) {
5773 GST_DEBUG_OBJECT (qtdemux, "we reached the end of our segment.");
5774 qtdemux->streams[index]->time_position = GST_CLOCK_TIME_NONE;
5778 /* gap events for subtitle streams */
5779 for (i = 0; i < qtdemux->n_streams; i++) {
5780 stream = qtdemux->streams[i];
5781 if (stream->pad && (stream->subtype == FOURCC_subp
5782 || stream->subtype == FOURCC_text
5783 || stream->subtype == FOURCC_sbtl)) {
5784 /* send one second gap events until the stream catches up */
5785 /* gaps can only be sent after segment is activated (segment.stop is no longer -1) */
5786 while (GST_CLOCK_TIME_IS_VALID (stream->segment.stop) &&
5787 GST_CLOCK_TIME_IS_VALID (stream->segment.position) &&
5788 stream->segment.position + GST_SECOND < min_time) {
5790 gst_event_new_gap (stream->segment.position, GST_SECOND);
5791 gst_pad_push_event (stream->pad, gap);
5792 stream->segment.position += GST_SECOND;
5797 stream = qtdemux->streams[index];
5798 /* fetch info for the current sample of this stream */
5799 if (G_UNLIKELY (!gst_qtdemux_prepare_current_sample (qtdemux, stream, &empty,
5800 &offset, &sample_size, &dts, &pts, &duration, &keyframe)))
5803 gst_qtdemux_stream_check_and_change_stsd_index (qtdemux, stream);
5804 if (stream->new_caps) {
5805 gst_qtdemux_configure_stream (qtdemux, stream);
5806 qtdemux_do_allocation (qtdemux, stream);
5809 /* If we're doing a keyframe-only trickmode, only push keyframes on video streams */
5810 if (G_UNLIKELY (qtdemux->
5811 segment.flags & GST_SEGMENT_FLAG_TRICKMODE_KEY_UNITS)) {
5812 if (stream->subtype == FOURCC_vide && !keyframe) {
5813 GST_LOG_OBJECT (qtdemux, "Skipping non-keyframe on stream %d", index);
5818 GST_DEBUG_OBJECT (qtdemux,
5819 "pushing from stream %d, empty %d offset %" G_GUINT64_FORMAT
5820 ", size %d, dts=%" GST_TIME_FORMAT ", pts=%" GST_TIME_FORMAT
5821 ", duration %" GST_TIME_FORMAT, index, empty, offset, sample_size,
5822 GST_TIME_ARGS (dts), GST_TIME_ARGS (pts), GST_TIME_ARGS (duration));
5824 if (G_UNLIKELY (empty)) {
5825 /* empty segment, push a gap if there's a second or more
5826 * difference and move to the next one */
5827 if ((pts + duration - stream->segment.position) >= GST_SECOND)
5828 gst_pad_push_event (stream->pad, gst_event_new_gap (pts, duration));
5829 stream->segment.position = pts + duration;
5833 /* hmm, empty sample, skip and move to next sample */
5834 if (G_UNLIKELY (sample_size <= 0))
5837 /* last pushed sample was out of boundary, goto next sample */
5838 if (G_UNLIKELY (GST_PAD_LAST_FLOW_RETURN (stream->pad) == GST_FLOW_EOS))
5841 if (stream->max_buffer_size == 0 || sample_size <= stream->max_buffer_size) {
5844 GST_DEBUG_OBJECT (qtdemux,
5845 "size %d larger than stream max_buffer_size %d, trimming",
5846 sample_size, stream->max_buffer_size);
5848 MIN (sample_size - stream->offset_in_sample, stream->max_buffer_size);
5851 if (qtdemux->cenc_aux_info_offset > 0) {
5854 GstBuffer *aux_info = NULL;
5856 /* pull the data stored before the sample */
5858 gst_qtdemux_pull_atom (qtdemux, qtdemux->offset,
5859 offset + stream->offset_in_sample - qtdemux->offset, &aux_info);
5860 if (G_UNLIKELY (ret != GST_FLOW_OK))
5862 gst_buffer_map (aux_info, &map, GST_MAP_READ);
5863 GST_DEBUG_OBJECT (qtdemux, "parsing cenc auxiliary info");
5864 gst_byte_reader_init (&br, map.data + 8, map.size);
5865 if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
5866 qtdemux->cenc_aux_info_sizes, qtdemux->cenc_aux_sample_count)) {
5867 GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
5868 gst_buffer_unmap (aux_info, &map);
5869 gst_buffer_unref (aux_info);
5870 ret = GST_FLOW_ERROR;
5873 gst_buffer_unmap (aux_info, &map);
5874 gst_buffer_unref (aux_info);
5877 GST_LOG_OBJECT (qtdemux, "reading %d bytes @ %" G_GUINT64_FORMAT, size,
5880 if (stream->use_allocator) {
5881 /* if we have a per-stream allocator, use it */
5882 buf = gst_buffer_new_allocate (stream->allocator, size, &stream->params);
5885 ret = gst_qtdemux_pull_atom (qtdemux, offset + stream->offset_in_sample,
5887 if (G_UNLIKELY (ret != GST_FLOW_OK))
5890 if (size != sample_size) {
5891 pts += gst_util_uint64_scale_int (GST_SECOND,
5892 stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame,
5895 gst_util_uint64_scale_int (GST_SECOND,
5896 stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame,
5899 gst_util_uint64_scale_int (GST_SECOND,
5900 size / CUR_STREAM (stream)->bytes_per_frame, stream->timescale);
5903 ret = gst_qtdemux_decorate_and_push_buffer (qtdemux, stream, buf,
5904 dts, pts, duration, keyframe, min_time, offset);
5906 if (size != sample_size) {
5907 QtDemuxSample *sample = &stream->samples[stream->sample_index];
5908 QtDemuxSegment *segment = &stream->segments[stream->segment_index];
5910 GstClockTime time_position = QTSTREAMTIME_TO_GSTTIME (stream,
5912 stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame);
5913 if (time_position >= segment->media_start) {
5914 /* inside the segment, update time_position, looks very familiar to
5915 * GStreamer segments, doesn't it? */
5916 stream->time_position = (time_position - segment->media_start) +
5919 /* not yet in segment, time does not yet increment. This means
5920 * that we are still prerolling keyframes to the decoder so it can
5921 * decode the first sample of the segment. */
5922 stream->time_position = segment->time;
5927 ret = gst_qtdemux_combine_flows (qtdemux, stream, ret);
5928 /* ignore unlinked, we will not push on the pad anymore and we will EOS when
5929 * we have no more data for the pad to push */
5930 if (ret == GST_FLOW_EOS)
5933 stream->offset_in_sample += size;
5934 if (stream->offset_in_sample >= sample_size) {
5935 gst_qtdemux_advance_sample (qtdemux, stream);
5940 gst_qtdemux_advance_sample (qtdemux, stream);
5948 GST_DEBUG_OBJECT (qtdemux, "No samples left for any streams - EOS");
5954 GST_DEBUG_OBJECT (qtdemux, "No samples left for stream");
5955 /* EOS will be raised if all are EOS */
5962 gst_qtdemux_loop (GstPad * pad)
5964 GstQTDemux *qtdemux;
5968 qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
5970 cur_offset = qtdemux->offset;
5971 GST_LOG_OBJECT (qtdemux, "loop at position %" G_GUINT64_FORMAT ", state %s",
5972 cur_offset, qt_demux_state_string (qtdemux->state));
5974 switch (qtdemux->state) {
5975 case QTDEMUX_STATE_INITIAL:
5976 case QTDEMUX_STATE_HEADER:
5977 ret = gst_qtdemux_loop_state_header (qtdemux);
5979 case QTDEMUX_STATE_MOVIE:
5980 ret = gst_qtdemux_loop_state_movie (qtdemux);
5981 if (qtdemux->segment.rate < 0 && ret == GST_FLOW_EOS) {
5982 ret = gst_qtdemux_seek_to_previous_keyframe (qtdemux);
5990 /* if something went wrong, pause */
5991 if (ret != GST_FLOW_OK)
5995 gst_object_unref (qtdemux);
6001 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
6002 (NULL), ("streaming stopped, invalid state"));
6003 gst_pad_pause_task (pad);
6004 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
6009 const gchar *reason = gst_flow_get_name (ret);
6011 GST_LOG_OBJECT (qtdemux, "pausing task, reason %s", reason);
6013 gst_pad_pause_task (pad);
6015 /* fatal errors need special actions */
6017 if (ret == GST_FLOW_EOS) {
6018 if (qtdemux->n_streams == 0) {
6019 /* we have no streams, post an error */
6020 gst_qtdemux_post_no_playable_stream_error (qtdemux);
6022 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
6025 if ((stop = qtdemux->segment.stop) == -1)
6026 stop = qtdemux->segment.duration;
6028 if (qtdemux->segment.rate >= 0) {
6029 GstMessage *message;
6032 GST_LOG_OBJECT (qtdemux, "Sending segment done, at end of segment");
6033 message = gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
6034 GST_FORMAT_TIME, stop);
6035 event = gst_event_new_segment_done (GST_FORMAT_TIME, stop);
6036 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID) {
6037 gst_message_set_seqnum (message, qtdemux->segment_seqnum);
6038 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
6040 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), message);
6041 gst_qtdemux_push_event (qtdemux, event);
6043 GstMessage *message;
6046 /* For Reverse Playback */
6047 GST_LOG_OBJECT (qtdemux, "Sending segment done, at start of segment");
6048 message = gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
6049 GST_FORMAT_TIME, qtdemux->segment.start);
6050 event = gst_event_new_segment_done (GST_FORMAT_TIME,
6051 qtdemux->segment.start);
6052 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID) {
6053 gst_message_set_seqnum (message, qtdemux->segment_seqnum);
6054 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
6056 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), message);
6057 gst_qtdemux_push_event (qtdemux, event);
6062 GST_LOG_OBJECT (qtdemux, "Sending EOS at end of segment");
6063 event = gst_event_new_eos ();
6064 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID)
6065 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
6066 gst_qtdemux_push_event (qtdemux, event);
6068 } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
6069 GST_ELEMENT_FLOW_ERROR (qtdemux, ret);
6070 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
6079 * Returns if there are samples to be played.
6082 has_next_entry (GstQTDemux * demux)
6084 QtDemuxStream *stream;
6087 GST_DEBUG_OBJECT (demux, "Checking if there are samples not played yet");
6089 for (i = 0; i < demux->n_streams; i++) {
6090 stream = demux->streams[i];
6092 if (stream->sample_index == -1) {
6093 stream->sample_index = 0;
6094 stream->offset_in_sample = 0;
6097 if (stream->sample_index >= stream->n_samples) {
6098 GST_LOG_OBJECT (demux, "stream %d samples exhausted", i);
6101 GST_DEBUG_OBJECT (demux, "Found a sample");
6105 GST_DEBUG_OBJECT (demux, "There wasn't any next sample");
6112 * Returns the size of the first entry at the current offset.
6113 * If -1, there are none (which means EOS or empty file).
6116 next_entry_size (GstQTDemux * demux)
6118 QtDemuxStream *stream;
6121 guint64 smalloffs = (guint64) - 1;
6122 QtDemuxSample *sample;
6124 GST_LOG_OBJECT (demux, "Finding entry at offset %" G_GUINT64_FORMAT,
6127 for (i = 0; i < demux->n_streams; i++) {
6128 stream = demux->streams[i];
6130 if (stream->sample_index == -1) {
6131 stream->sample_index = 0;
6132 stream->offset_in_sample = 0;
6135 if (stream->sample_index >= stream->n_samples) {
6136 GST_LOG_OBJECT (demux, "stream %d samples exhausted", i);
6140 if (!qtdemux_parse_samples (demux, stream, stream->sample_index)) {
6141 GST_LOG_OBJECT (demux, "Parsing of index %u from stbl atom failed!",
6142 stream->sample_index);
6146 sample = &stream->samples[stream->sample_index];
6148 GST_LOG_OBJECT (demux,
6149 "Checking Stream %d (sample_index:%d / offset:%" G_GUINT64_FORMAT
6150 " / size:%" G_GUINT32_FORMAT ")", i, stream->sample_index,
6151 sample->offset, sample->size);
6153 if (((smalloffs == -1)
6154 || (sample->offset < smalloffs)) && (sample->size)) {
6156 smalloffs = sample->offset;
6160 GST_LOG_OBJECT (demux,
6161 "stream %d offset %" G_GUINT64_FORMAT " demux->offset :%"
6162 G_GUINT64_FORMAT, smallidx, smalloffs, demux->offset);
6167 stream = demux->streams[smallidx];
6168 sample = &stream->samples[stream->sample_index];
6170 if (sample->offset >= demux->offset) {
6171 demux->todrop = sample->offset - demux->offset;
6172 return sample->size + demux->todrop;
6175 GST_DEBUG_OBJECT (demux,
6176 "There wasn't any entry at offset %" G_GUINT64_FORMAT, demux->offset);
6181 gst_qtdemux_post_progress (GstQTDemux * demux, gint num, gint denom)
6183 gint perc = (gint) ((gdouble) num * 100.0 / (gdouble) denom);
6185 gst_element_post_message (GST_ELEMENT_CAST (demux),
6186 gst_message_new_element (GST_OBJECT_CAST (demux),
6187 gst_structure_new ("progress", "percent", G_TYPE_INT, perc, NULL)));
6191 qtdemux_seek_offset (GstQTDemux * demux, guint64 offset)
6196 GST_DEBUG_OBJECT (demux, "Seeking to %" G_GUINT64_FORMAT, offset);
6199 gst_event_new_seek (1.0, GST_FORMAT_BYTES,
6200 GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset,
6201 GST_SEEK_TYPE_NONE, -1);
6203 /* store seqnum to drop flush events, they don't need to reach downstream */
6204 demux->offset_seek_seqnum = gst_event_get_seqnum (event);
6205 res = gst_pad_push_event (demux->sinkpad, event);
6206 demux->offset_seek_seqnum = GST_SEQNUM_INVALID;
6211 /* check for seekable upstream, above and beyond a mere query */
6213 gst_qtdemux_check_seekability (GstQTDemux * demux)
6216 gboolean seekable = FALSE;
6217 gint64 start = -1, stop = -1;
6219 if (demux->upstream_size)
6222 if (demux->upstream_format_is_time)
6225 query = gst_query_new_seeking (GST_FORMAT_BYTES);
6226 if (!gst_pad_peer_query (demux->sinkpad, query)) {
6227 GST_DEBUG_OBJECT (demux, "seeking query failed");
6231 gst_query_parse_seeking (query, NULL, &seekable, &start, &stop);
6233 /* try harder to query upstream size if we didn't get it the first time */
6234 if (seekable && stop == -1) {
6235 GST_DEBUG_OBJECT (demux, "doing duration query to fix up unset stop");
6236 gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &stop);
6239 /* if upstream doesn't know the size, it's likely that it's not seekable in
6240 * practice even if it technically may be seekable */
6241 if (seekable && (start != 0 || stop <= start)) {
6242 GST_DEBUG_OBJECT (demux, "seekable but unknown start/stop -> disable");
6247 gst_query_unref (query);
6249 GST_DEBUG_OBJECT (demux, "seekable: %d (%" G_GUINT64_FORMAT " - %"
6250 G_GUINT64_FORMAT ")", seekable, start, stop);
6251 demux->upstream_seekable = seekable;
6252 demux->upstream_size = seekable ? stop : -1;
6256 gst_qtdemux_drop_data (GstQTDemux * demux, gint bytes)
6258 g_return_if_fail (bytes <= demux->todrop);
6260 GST_LOG_OBJECT (demux, "Dropping %d bytes", bytes);
6261 gst_adapter_flush (demux->adapter, bytes);
6262 demux->neededbytes -= bytes;
6263 demux->offset += bytes;
6264 demux->todrop -= bytes;
6268 gst_qtdemux_check_send_pending_segment (GstQTDemux * demux)
6270 if (G_UNLIKELY (demux->pending_newsegment)) {
6273 gst_qtdemux_push_pending_newsegment (demux);
6274 /* clear to send tags on all streams */
6275 for (i = 0; i < demux->n_streams; i++) {
6276 QtDemuxStream *stream;
6277 stream = demux->streams[i];
6278 gst_qtdemux_push_tags (demux, stream);
6279 if (CUR_STREAM (stream)->sparse) {
6280 GST_INFO_OBJECT (demux, "Sending gap event on stream %d", i);
6281 gst_pad_push_event (stream->pad,
6282 gst_event_new_gap (stream->segment.position, GST_CLOCK_TIME_NONE));
6289 gst_qtdemux_send_gap_for_segment (GstQTDemux * demux,
6290 QtDemuxStream * stream, gint segment_index, GstClockTime pos)
6292 GstClockTime ts, dur;
6297 stream->segments[segment_index].duration - (pos -
6298 stream->segments[segment_index].time);
6299 gap = gst_event_new_gap (ts, dur);
6300 stream->time_position += dur;
6302 GST_DEBUG_OBJECT (stream->pad, "Pushing gap for empty "
6303 "segment: %" GST_PTR_FORMAT, gap);
6304 gst_pad_push_event (stream->pad, gap);
6308 gst_qtdemux_stream_send_initial_gap_segments (GstQTDemux * demux,
6309 QtDemuxStream * stream)
6313 /* Push any initial gap segments before proceeding to the
6315 for (i = 0; i < stream->n_segments; i++) {
6316 gst_qtdemux_activate_segment (demux, stream, i, stream->time_position);
6318 if (QTSEGMENT_IS_EMPTY (&stream->segments[i])) {
6319 gst_qtdemux_send_gap_for_segment (demux, stream, i,
6320 stream->time_position);
6322 /* Only support empty segment at the beginning followed by
6323 * one non-empty segment, this was checked when parsing the
6324 * edts atom, arriving here is unexpected */
6325 g_assert (i + 1 == stream->n_segments);
6331 static GstFlowReturn
6332 gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent, GstBuffer * inbuf)
6336 demux = GST_QTDEMUX (parent);
6338 GST_DEBUG_OBJECT (demux,
6339 "Received buffer pts:%" GST_TIME_FORMAT " dts:%" GST_TIME_FORMAT
6340 " offset:%" G_GUINT64_FORMAT " size:%" G_GSIZE_FORMAT " demux offset:%"
6341 G_GUINT64_FORMAT, GST_TIME_ARGS (GST_BUFFER_PTS (inbuf)),
6342 GST_TIME_ARGS (GST_BUFFER_DTS (inbuf)), GST_BUFFER_OFFSET (inbuf),
6343 gst_buffer_get_size (inbuf), demux->offset);
6345 if (GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_DISCONT)) {
6346 gboolean is_gap_input = FALSE;
6349 GST_DEBUG_OBJECT (demux, "Got DISCONT, marking all streams as DISCONT");
6351 for (i = 0; i < demux->n_streams; i++) {
6352 demux->streams[i]->discont = TRUE;
6355 /* Check if we can land back on our feet in the case where upstream is
6356 * handling the seeking/pushing of samples with gaps in between (like
6357 * in the case of trick-mode DASH for example) */
6358 if (demux->upstream_format_is_time
6359 && GST_BUFFER_OFFSET (inbuf) != GST_BUFFER_OFFSET_NONE) {
6361 for (i = 0; i < demux->n_streams; i++) {
6363 GST_LOG_OBJECT (demux,
6364 "Stream #%d , checking if offset %" G_GUINT64_FORMAT
6365 " is a sample start", i, GST_BUFFER_OFFSET (inbuf));
6367 gst_qtdemux_find_index_for_given_media_offset_linear (demux,
6368 demux->streams[i], GST_BUFFER_OFFSET (inbuf));
6370 QtDemuxSample *sample = &demux->streams[i]->samples[res];
6371 GST_LOG_OBJECT (demux,
6372 "Checking if sample %d from stream %d is valid (offset:%"
6373 G_GUINT64_FORMAT " size:%" G_GUINT32_FORMAT ")", res, i,
6374 sample->offset, sample->size);
6375 if (sample->offset == GST_BUFFER_OFFSET (inbuf)) {
6376 GST_LOG_OBJECT (demux,
6377 "new buffer corresponds to a valid sample : %" G_GUINT32_FORMAT,
6379 is_gap_input = TRUE;
6380 /* We can go back to standard playback mode */
6381 demux->state = QTDEMUX_STATE_MOVIE;
6382 /* Remember which sample this stream is at */
6383 demux->streams[i]->sample_index = res;
6384 /* Finally update all push-based values to the expected values */
6385 demux->neededbytes = demux->streams[i]->samples[res].size;
6386 demux->offset = GST_BUFFER_OFFSET (inbuf);
6388 demux->mdatsize - demux->offset + demux->mdatoffset;
6393 if (!is_gap_input) {
6394 GST_DEBUG_OBJECT (demux, "Resetting, actual DISCONT");
6395 /* Reset state if it's a real discont */
6396 demux->neededbytes = 16;
6397 demux->state = QTDEMUX_STATE_INITIAL;
6398 demux->offset = GST_BUFFER_OFFSET (inbuf);
6399 gst_adapter_clear (demux->adapter);
6402 /* Reverse fragmented playback, need to flush all we have before
6403 * consuming a new fragment.
6404 * The samples array have the timestamps calculated by accumulating the
6405 * durations but this won't work for reverse playback of fragments as
6406 * the timestamps of a subsequent fragment should be smaller than the
6407 * previously received one. */
6408 if (!is_gap_input && demux->fragmented && demux->segment.rate < 0) {
6409 gst_qtdemux_process_adapter (demux, TRUE);
6410 for (i = 0; i < demux->n_streams; i++)
6411 gst_qtdemux_stream_flush_samples_data (demux, demux->streams[i]);
6415 gst_adapter_push (demux->adapter, inbuf);
6417 GST_DEBUG_OBJECT (demux,
6418 "pushing in inbuf %p, neededbytes:%u, available:%" G_GSIZE_FORMAT, inbuf,
6419 demux->neededbytes, gst_adapter_available (demux->adapter));
6421 return gst_qtdemux_process_adapter (demux, FALSE);
6424 static GstFlowReturn
6425 gst_qtdemux_process_adapter (GstQTDemux * demux, gboolean force)
6427 GstFlowReturn ret = GST_FLOW_OK;
6429 /* we never really mean to buffer that much */
6430 if (demux->neededbytes == -1) {
6434 while (((gst_adapter_available (demux->adapter)) >= demux->neededbytes) &&
6435 (ret == GST_FLOW_OK || (ret == GST_FLOW_NOT_LINKED && force))) {
6437 #ifndef GST_DISABLE_GST_DEBUG
6439 guint64 discont_offset, distance_from_discont;
6441 discont_offset = gst_adapter_offset_at_discont (demux->adapter);
6442 distance_from_discont =
6443 gst_adapter_distance_from_discont (demux->adapter);
6445 GST_DEBUG_OBJECT (demux,
6446 "state:%s , demux->neededbytes:%d, demux->offset:%" G_GUINT64_FORMAT
6447 " adapter offset :%" G_GUINT64_FORMAT " (+ %" G_GUINT64_FORMAT
6448 " bytes)", qt_demux_state_string (demux->state), demux->neededbytes,
6449 demux->offset, discont_offset, distance_from_discont);
6453 switch (demux->state) {
6454 case QTDEMUX_STATE_INITIAL:{
6459 gst_qtdemux_check_seekability (demux);
6461 data = gst_adapter_map (demux->adapter, demux->neededbytes);
6463 /* get fourcc/length, set neededbytes */
6464 extract_initial_length_and_fourcc ((guint8 *) data, demux->neededbytes,
6466 gst_adapter_unmap (demux->adapter);
6468 GST_DEBUG_OBJECT (demux, "Peeking found [%" GST_FOURCC_FORMAT "] "
6469 "size: %" G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), size);
6471 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
6472 (_("This file is invalid and cannot be played.")),
6473 ("initial atom '%" GST_FOURCC_FORMAT "' has empty length",
6474 GST_FOURCC_ARGS (fourcc)));
6475 ret = GST_FLOW_ERROR;
6478 if (fourcc == FOURCC_mdat) {
6479 gint next_entry = next_entry_size (demux);
6480 if (demux->n_streams > 0 && (next_entry != -1 || !demux->fragmented)) {
6481 /* we have the headers, start playback */
6482 demux->state = QTDEMUX_STATE_MOVIE;
6483 demux->neededbytes = next_entry;
6484 demux->mdatleft = size;
6485 demux->mdatsize = demux->mdatleft;
6487 /* no headers yet, try to get them */
6490 guint64 old, target;
6493 old = demux->offset;
6494 target = old + size;
6496 /* try to jump over the atom with a seek */
6497 /* only bother if it seems worth doing so,
6498 * and avoids possible upstream/server problems */
6499 if (demux->upstream_seekable &&
6500 demux->upstream_size > 4 * (1 << 20)) {
6501 res = qtdemux_seek_offset (demux, target);
6503 GST_DEBUG_OBJECT (demux, "skipping seek");
6508 GST_DEBUG_OBJECT (demux, "seek success");
6509 /* remember the offset fo the first mdat so we can seek back to it
6510 * after we have the headers */
6511 if (fourcc == FOURCC_mdat && demux->first_mdat == -1) {
6512 demux->first_mdat = old;
6513 GST_DEBUG_OBJECT (demux, "first mdat at %" G_GUINT64_FORMAT,
6516 /* seek worked, continue reading */
6517 demux->offset = target;
6518 demux->neededbytes = 16;
6519 demux->state = QTDEMUX_STATE_INITIAL;
6521 /* seek failed, need to buffer */
6522 demux->offset = old;
6523 GST_DEBUG_OBJECT (demux, "seek failed/skipped");
6524 /* there may be multiple mdat (or alike) buffers */
6526 if (demux->mdatbuffer)
6527 bs = gst_buffer_get_size (demux->mdatbuffer);
6530 if (size + bs > 10 * (1 << 20))
6532 demux->state = QTDEMUX_STATE_BUFFER_MDAT;
6533 demux->neededbytes = size;
6534 if (!demux->mdatbuffer)
6535 demux->mdatoffset = demux->offset;
6538 } else if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
6539 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
6540 (_("This file is invalid and cannot be played.")),
6541 ("atom %" GST_FOURCC_FORMAT " has bogus size %" G_GUINT64_FORMAT,
6542 GST_FOURCC_ARGS (fourcc), size));
6543 ret = GST_FLOW_ERROR;
6546 /* this means we already started buffering and still no moov header,
6547 * let's continue buffering everything till we get moov */
6548 if (demux->mdatbuffer && !(fourcc == FOURCC_moov
6549 || fourcc == FOURCC_moof))
6551 demux->neededbytes = size;
6552 demux->state = QTDEMUX_STATE_HEADER;
6556 case QTDEMUX_STATE_HEADER:{
6560 GST_DEBUG_OBJECT (demux, "In header");
6562 data = gst_adapter_map (demux->adapter, demux->neededbytes);
6564 /* parse the header */
6565 extract_initial_length_and_fourcc (data, demux->neededbytes, NULL,
6567 if (fourcc == FOURCC_moov) {
6570 /* in usual fragmented setup we could try to scan for more
6571 * and end up at the the moov (after mdat) again */
6572 if (demux->got_moov && demux->n_streams > 0 &&
6574 || demux->last_moov_offset == demux->offset)) {
6575 GST_DEBUG_OBJECT (demux,
6576 "Skipping moov atom as we have (this) one already");
6578 GST_DEBUG_OBJECT (demux, "Parsing [moov]");
6580 if (demux->got_moov && demux->fragmented) {
6581 GST_DEBUG_OBJECT (demux,
6582 "Got a second moov, clean up data from old one");
6583 if (demux->moov_node_compressed) {
6584 g_node_destroy (demux->moov_node_compressed);
6585 if (demux->moov_node)
6586 g_free (demux->moov_node->data);
6588 demux->moov_node_compressed = NULL;
6589 if (demux->moov_node)
6590 g_node_destroy (demux->moov_node);
6591 demux->moov_node = NULL;
6593 /* prepare newsegment to send when streaming actually starts */
6594 if (!demux->pending_newsegment) {
6595 demux->pending_newsegment =
6596 gst_event_new_segment (&demux->segment);
6597 if (demux->segment_seqnum != GST_SEQNUM_INVALID)
6598 gst_event_set_seqnum (demux->pending_newsegment,
6599 demux->segment_seqnum);
6603 demux->last_moov_offset = demux->offset;
6605 qtdemux_parse_moov (demux, data, demux->neededbytes);
6606 qtdemux_node_dump (demux, demux->moov_node);
6607 qtdemux_parse_tree (demux);
6608 qtdemux_prepare_streams (demux);
6609 if (!demux->got_moov)
6610 qtdemux_expose_streams (demux);
6613 for (n = 0; n < demux->n_streams; n++) {
6614 QtDemuxStream *stream = demux->streams[n];
6616 gst_qtdemux_configure_stream (demux, stream);
6620 demux->got_moov = TRUE;
6621 gst_qtdemux_check_send_pending_segment (demux);
6623 /* fragmented streams headers shouldn't contain edts atoms */
6624 if (!demux->fragmented) {
6625 for (n = 0; n < demux->n_streams; n++) {
6626 gst_qtdemux_stream_send_initial_gap_segments (demux,
6631 if (demux->moov_node_compressed) {
6632 g_node_destroy (demux->moov_node_compressed);
6633 g_free (demux->moov_node->data);
6635 demux->moov_node_compressed = NULL;
6636 g_node_destroy (demux->moov_node);
6637 demux->moov_node = NULL;
6638 GST_DEBUG_OBJECT (demux, "Finished parsing the header");
6640 } else if (fourcc == FOURCC_moof) {
6641 if ((demux->got_moov || demux->media_caps) && demux->fragmented) {
6643 GstClockTime prev_pts;
6644 guint64 prev_offset;
6645 guint64 adapter_discont_offset, adapter_discont_dist;
6647 GST_DEBUG_OBJECT (demux, "Parsing [moof]");
6650 * The timestamp of the moof buffer is relevant as some scenarios
6651 * won't have the initial timestamp in the atoms. Whenever a new
6652 * buffer has started, we get that buffer's PTS and use it as a base
6653 * timestamp for the trun entries.
6655 * To keep track of the current buffer timestamp and starting point
6656 * we use gst_adapter_prev_pts that gives us the PTS and the distance
6657 * from the beggining of the buffer, with the distance and demux->offset
6658 * we know if it is still the same buffer or not.
6660 prev_pts = gst_adapter_prev_pts (demux->adapter, &dist);
6661 prev_offset = demux->offset - dist;
6662 if (demux->fragment_start_offset == -1
6663 || prev_offset > demux->fragment_start_offset) {
6664 demux->fragment_start_offset = prev_offset;
6665 demux->fragment_start = prev_pts;
6666 GST_DEBUG_OBJECT (demux,
6667 "New fragment start found at: %" G_GUINT64_FORMAT " : %"
6668 GST_TIME_FORMAT, demux->fragment_start_offset,
6669 GST_TIME_ARGS (demux->fragment_start));
6672 /* We can't use prev_offset() here because this would require
6673 * upstream to set consistent and correct offsets on all buffers
6674 * since the discont. Nothing ever did that in the past and we
6675 * would break backwards compatibility here then.
6676 * Instead take the offset we had at the last discont and count
6677 * the bytes from there. This works with old code as there would
6678 * be no discont between moov and moof, and also works with
6679 * adaptivedemux which correctly sets offset and will set the
6680 * DISCONT flag accordingly when needed.
6682 * We also only do this for upstream TIME segments as otherwise
6683 * there are potential backwards compatibility problems with
6684 * seeking in PUSH mode and upstream providing inconsistent
6686 adapter_discont_offset =
6687 gst_adapter_offset_at_discont (demux->adapter);
6688 adapter_discont_dist =
6689 gst_adapter_distance_from_discont (demux->adapter);
6691 GST_DEBUG_OBJECT (demux,
6692 "demux offset %" G_GUINT64_FORMAT " adapter offset %"
6693 G_GUINT64_FORMAT " (+ %" G_GUINT64_FORMAT " bytes)",
6694 demux->offset, adapter_discont_offset, adapter_discont_dist);
6696 if (demux->upstream_format_is_time) {
6697 demux->moof_offset = adapter_discont_offset;
6698 if (demux->moof_offset != GST_BUFFER_OFFSET_NONE)
6699 demux->moof_offset += adapter_discont_dist;
6700 if (demux->moof_offset == GST_BUFFER_OFFSET_NONE)
6701 demux->moof_offset = demux->offset;
6703 demux->moof_offset = demux->offset;
6706 if (!qtdemux_parse_moof (demux, data, demux->neededbytes,
6707 demux->moof_offset, NULL)) {
6708 gst_adapter_unmap (demux->adapter);
6709 ret = GST_FLOW_ERROR;
6712 /* in MSS we need to expose the pads after the first moof as we won't get a moov */
6713 if (demux->mss_mode && !demux->exposed) {
6714 if (!demux->pending_newsegment) {
6715 GST_DEBUG_OBJECT (demux, "new pending_newsegment");
6716 demux->pending_newsegment =
6717 gst_event_new_segment (&demux->segment);
6718 if (demux->segment_seqnum != GST_SEQNUM_INVALID)
6719 gst_event_set_seqnum (demux->pending_newsegment,
6720 demux->segment_seqnum);
6722 qtdemux_expose_streams (demux);
6725 GST_DEBUG_OBJECT (demux, "Discarding [moof]");
6727 } else if (fourcc == FOURCC_ftyp) {
6728 GST_DEBUG_OBJECT (demux, "Parsing [ftyp]");
6729 qtdemux_parse_ftyp (demux, data, demux->neededbytes);
6730 } else if (fourcc == FOURCC_uuid) {
6731 GST_DEBUG_OBJECT (demux, "Parsing [uuid]");
6732 qtdemux_parse_uuid (demux, data, demux->neededbytes);
6733 } else if (fourcc == FOURCC_sidx) {
6734 GST_DEBUG_OBJECT (demux, "Parsing [sidx]");
6735 qtdemux_parse_sidx (demux, data, demux->neededbytes);
6739 /* [styp] is like a [ftyp], but in fragment header. We ignore it for now
6743 /* [free] and [skip] are padding atoms */
6744 GST_DEBUG_OBJECT (demux,
6745 "Skipping fourcc while parsing header : %" GST_FOURCC_FORMAT,
6746 GST_FOURCC_ARGS (fourcc));
6749 GST_WARNING_OBJECT (demux,
6750 "Unknown fourcc while parsing header : %" GST_FOURCC_FORMAT,
6751 GST_FOURCC_ARGS (fourcc));
6752 /* Let's jump that one and go back to initial state */
6756 gst_adapter_unmap (demux->adapter);
6759 if (demux->mdatbuffer && demux->n_streams) {
6760 gsize remaining_data_size = 0;
6762 /* the mdat was before the header */
6763 GST_DEBUG_OBJECT (demux, "We have n_streams:%d and mdatbuffer:%p",
6764 demux->n_streams, demux->mdatbuffer);
6765 /* restore our adapter/offset view of things with upstream;
6766 * put preceding buffered data ahead of current moov data.
6767 * This should also handle evil mdat, moov, mdat cases and alike */
6768 gst_adapter_flush (demux->adapter, demux->neededbytes);
6770 /* Store any remaining data after the mdat for later usage */
6771 remaining_data_size = gst_adapter_available (demux->adapter);
6772 if (remaining_data_size > 0) {
6773 g_assert (demux->restoredata_buffer == NULL);
6774 demux->restoredata_buffer =
6775 gst_adapter_take_buffer (demux->adapter, remaining_data_size);
6776 demux->restoredata_offset = demux->offset + demux->neededbytes;
6777 GST_DEBUG_OBJECT (demux,
6778 "Stored %" G_GSIZE_FORMAT " post mdat bytes at offset %"
6779 G_GUINT64_FORMAT, remaining_data_size,
6780 demux->restoredata_offset);
6783 gst_adapter_push (demux->adapter, demux->mdatbuffer);
6784 demux->mdatbuffer = NULL;
6785 demux->offset = demux->mdatoffset;
6786 demux->neededbytes = next_entry_size (demux);
6787 demux->state = QTDEMUX_STATE_MOVIE;
6788 demux->mdatleft = gst_adapter_available (demux->adapter);
6789 demux->mdatsize = demux->mdatleft;
6791 GST_DEBUG_OBJECT (demux, "Carrying on normally");
6792 gst_adapter_flush (demux->adapter, demux->neededbytes);
6794 /* only go back to the mdat if there are samples to play */
6795 if (demux->got_moov && demux->first_mdat != -1
6796 && has_next_entry (demux)) {
6799 /* we need to seek back */
6800 res = qtdemux_seek_offset (demux, demux->first_mdat);
6802 demux->offset = demux->first_mdat;
6804 GST_DEBUG_OBJECT (demux, "Seek back failed");
6807 demux->offset += demux->neededbytes;
6809 demux->neededbytes = 16;
6810 demux->state = QTDEMUX_STATE_INITIAL;
6815 case QTDEMUX_STATE_BUFFER_MDAT:{
6819 GST_DEBUG_OBJECT (demux, "Got our buffer at offset %" G_GUINT64_FORMAT,
6821 buf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
6822 gst_buffer_extract (buf, 0, fourcc, 4);
6823 GST_DEBUG_OBJECT (demux, "mdatbuffer starts with %" GST_FOURCC_FORMAT,
6824 GST_FOURCC_ARGS (QT_FOURCC (fourcc)));
6825 if (demux->mdatbuffer)
6826 demux->mdatbuffer = gst_buffer_append (demux->mdatbuffer, buf);
6828 demux->mdatbuffer = buf;
6829 demux->offset += demux->neededbytes;
6830 demux->neededbytes = 16;
6831 demux->state = QTDEMUX_STATE_INITIAL;
6832 gst_qtdemux_post_progress (demux, 1, 1);
6836 case QTDEMUX_STATE_MOVIE:{
6837 QtDemuxStream *stream = NULL;
6838 QtDemuxSample *sample;
6840 GstClockTime dts, pts, duration;
6843 GST_DEBUG_OBJECT (demux,
6844 "BEGIN // in MOVIE for offset %" G_GUINT64_FORMAT, demux->offset);
6846 if (demux->fragmented) {
6847 GST_DEBUG_OBJECT (demux, "mdat remaining %" G_GUINT64_FORMAT,
6849 if (G_LIKELY (demux->todrop < demux->mdatleft)) {
6850 /* if needed data starts within this atom,
6851 * then it should not exceed this atom */
6852 if (G_UNLIKELY (demux->neededbytes > demux->mdatleft)) {
6853 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
6854 (_("This file is invalid and cannot be played.")),
6855 ("sample data crosses atom boundary"));
6856 ret = GST_FLOW_ERROR;
6859 demux->mdatleft -= demux->neededbytes;
6861 GST_DEBUG_OBJECT (demux, "data atom emptied; resuming atom scan");
6862 /* so we are dropping more than left in this atom */
6863 gst_qtdemux_drop_data (demux, demux->mdatleft);
6864 demux->mdatleft = 0;
6866 /* need to resume atom parsing so we do not miss any other pieces */
6867 demux->state = QTDEMUX_STATE_INITIAL;
6868 demux->neededbytes = 16;
6870 /* check if there was any stored post mdat data from previous buffers */
6871 if (demux->restoredata_buffer) {
6872 g_assert (gst_adapter_available (demux->adapter) == 0);
6874 gst_adapter_push (demux->adapter, demux->restoredata_buffer);
6875 demux->restoredata_buffer = NULL;
6876 demux->offset = demux->restoredata_offset;
6883 if (demux->todrop) {
6884 if (demux->cenc_aux_info_offset > 0) {
6888 GST_DEBUG_OBJECT (demux, "parsing cenc auxiliary info");
6889 data = gst_adapter_map (demux->adapter, demux->todrop);
6890 gst_byte_reader_init (&br, data + 8, demux->todrop);
6891 if (!qtdemux_parse_cenc_aux_info (demux, demux->streams[0], &br,
6892 demux->cenc_aux_info_sizes, demux->cenc_aux_sample_count)) {
6893 GST_ERROR_OBJECT (demux, "failed to parse cenc auxiliary info");
6894 ret = GST_FLOW_ERROR;
6895 gst_adapter_unmap (demux->adapter);
6896 g_free (demux->cenc_aux_info_sizes);
6897 demux->cenc_aux_info_sizes = NULL;
6900 demux->cenc_aux_info_offset = 0;
6901 g_free (demux->cenc_aux_info_sizes);
6902 demux->cenc_aux_info_sizes = NULL;
6903 gst_adapter_unmap (demux->adapter);
6905 gst_qtdemux_drop_data (demux, demux->todrop);
6909 /* initial newsegment sent here after having added pads,
6910 * possible others in sink_event */
6911 gst_qtdemux_check_send_pending_segment (demux);
6913 /* Figure out which stream this packet belongs to */
6914 for (i = 0; i < demux->n_streams; i++) {
6915 stream = demux->streams[i];
6916 if (stream->sample_index >= stream->n_samples)
6918 GST_LOG_OBJECT (demux,
6919 "Checking stream %d (sample_index:%d / offset:%" G_GUINT64_FORMAT
6920 " / size:%d)", i, stream->sample_index,
6921 stream->samples[stream->sample_index].offset,
6922 stream->samples[stream->sample_index].size);
6924 if (stream->samples[stream->sample_index].offset == demux->offset)
6928 if (G_UNLIKELY (stream == NULL || i == demux->n_streams))
6929 goto unknown_stream;
6931 gst_qtdemux_stream_check_and_change_stsd_index (demux, stream);
6933 if (stream->new_caps) {
6934 gst_qtdemux_configure_stream (demux, stream);
6937 /* Put data in a buffer, set timestamps, caps, ... */
6938 sample = &stream->samples[stream->sample_index];
6940 if (G_LIKELY (!(STREAM_IS_EOS (stream)))) {
6941 GST_DEBUG_OBJECT (demux, "stream : %" GST_FOURCC_FORMAT,
6942 GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
6944 dts = QTSAMPLE_DTS (stream, sample);
6945 pts = QTSAMPLE_PTS (stream, sample);
6946 duration = QTSAMPLE_DUR_DTS (stream, sample, dts);
6947 keyframe = QTSAMPLE_KEYFRAME (stream, sample);
6949 /* check for segment end */
6950 if (G_UNLIKELY (demux->segment.stop != -1
6951 && demux->segment.stop <= pts && stream->on_keyframe)) {
6952 GST_DEBUG_OBJECT (demux, "we reached the end of our segment.");
6953 stream->time_position = GST_CLOCK_TIME_NONE; /* this means EOS */
6955 /* skip this data, stream is EOS */
6956 gst_adapter_flush (demux->adapter, demux->neededbytes);
6957 demux->offset += demux->neededbytes;
6959 /* check if all streams are eos */
6961 for (i = 0; i < demux->n_streams; i++) {
6962 if (!STREAM_IS_EOS (demux->streams[i])) {
6971 gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
6973 /* FIXME: should either be an assert or a plain check */
6974 g_return_val_if_fail (outbuf != NULL, GST_FLOW_ERROR);
6976 ret = gst_qtdemux_decorate_and_push_buffer (demux, stream, outbuf,
6977 dts, pts, duration, keyframe, dts, demux->offset);
6981 ret = gst_qtdemux_combine_flows (demux, stream, ret);
6983 /* skip this data, stream is EOS */
6984 gst_adapter_flush (demux->adapter, demux->neededbytes);
6987 stream->sample_index++;
6988 stream->offset_in_sample = 0;
6990 /* update current offset and figure out size of next buffer */
6991 GST_LOG_OBJECT (demux, "increasing offset %" G_GUINT64_FORMAT " by %u",
6992 demux->offset, demux->neededbytes);
6993 demux->offset += demux->neededbytes;
6994 GST_LOG_OBJECT (demux, "offset is now %" G_GUINT64_FORMAT,
6998 if (ret == GST_FLOW_EOS) {
6999 GST_DEBUG_OBJECT (demux, "All streams are EOS, signal upstream");
7000 demux->neededbytes = -1;
7004 if ((demux->neededbytes = next_entry_size (demux)) == -1) {
7005 if (demux->fragmented) {
7006 GST_DEBUG_OBJECT (demux, "(temporarily) out of fragmented samples");
7007 /* there may be more to follow, only finish this atom */
7008 demux->todrop = demux->mdatleft;
7009 demux->neededbytes = demux->todrop;
7014 if (ret != GST_FLOW_OK && ret != GST_FLOW_NOT_LINKED) {
7015 goto non_ok_unlinked_flow;
7024 /* when buffering movie data, at least show user something is happening */
7025 if (ret == GST_FLOW_OK && demux->state == QTDEMUX_STATE_BUFFER_MDAT &&
7026 gst_adapter_available (demux->adapter) <= demux->neededbytes) {
7027 gst_qtdemux_post_progress (demux, gst_adapter_available (demux->adapter),
7028 demux->neededbytes);
7035 non_ok_unlinked_flow:
7037 GST_DEBUG_OBJECT (demux, "Stopping, combined return flow %s",
7038 gst_flow_get_name (ret));
7043 GST_ELEMENT_ERROR (demux, STREAM, FAILED, (NULL), ("unknown stream found"));
7044 ret = GST_FLOW_ERROR;
7049 GST_DEBUG_OBJECT (demux, "no next entry, EOS");
7055 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
7056 (NULL), ("qtdemuxer invalid state %d", demux->state));
7057 ret = GST_FLOW_ERROR;
7062 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
7063 (NULL), ("no 'moov' atom within the first 10 MB"));
7064 ret = GST_FLOW_ERROR;
7070 qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent)
7075 query = gst_query_new_scheduling ();
7077 if (!gst_pad_peer_query (sinkpad, query)) {
7078 gst_query_unref (query);
7082 pull_mode = gst_query_has_scheduling_mode_with_flags (query,
7083 GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
7084 gst_query_unref (query);
7089 GST_DEBUG_OBJECT (sinkpad, "activating pull");
7090 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
7094 GST_DEBUG_OBJECT (sinkpad, "activating push");
7095 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
7100 qtdemux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
7101 GstPadMode mode, gboolean active)
7104 GstQTDemux *demux = GST_QTDEMUX (parent);
7107 case GST_PAD_MODE_PUSH:
7108 demux->pullbased = FALSE;
7111 case GST_PAD_MODE_PULL:
7113 demux->pullbased = TRUE;
7114 res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_qtdemux_loop,
7117 res = gst_pad_stop_task (sinkpad);
7129 qtdemux_inflate (void *z_buffer, guint z_length, guint * length)
7135 memset (&z, 0, sizeof (z));
7140 if ((ret = inflateInit (&z)) != Z_OK) {
7141 GST_ERROR ("inflateInit() returned %d", ret);
7145 z.next_in = z_buffer;
7146 z.avail_in = z_length;
7148 buffer = (guint8 *) g_malloc (*length);
7149 z.avail_out = *length;
7150 z.next_out = (Bytef *) buffer;
7152 ret = inflate (&z, Z_NO_FLUSH);
7153 if (ret == Z_STREAM_END) {
7155 } else if (ret != Z_OK) {
7156 GST_WARNING ("inflate() returned %d", ret);
7161 buffer = (guint8 *) g_realloc (buffer, *length);
7162 z.next_out = (Bytef *) (buffer + z.total_out);
7163 z.avail_out += 4096;
7164 } while (z.avail_in > 0);
7166 if (ret != Z_STREAM_END) {
7171 *length = z.total_out;
7178 #endif /* HAVE_ZLIB */
7181 qtdemux_parse_moov (GstQTDemux * qtdemux, const guint8 * buffer, guint length)
7185 qtdemux->moov_node = g_node_new ((guint8 *) buffer);
7187 /* counts as header data */
7188 qtdemux->header_size += length;
7190 GST_DEBUG_OBJECT (qtdemux, "parsing 'moov' atom");
7191 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buffer, length);
7193 cmov = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_cmov);
7200 dcom = qtdemux_tree_get_child_by_type (cmov, FOURCC_dcom);
7201 cmvd = qtdemux_tree_get_child_by_type (cmov, FOURCC_cmvd);
7202 if (dcom == NULL || cmvd == NULL)
7203 goto invalid_compression;
7205 dcom_len = QT_UINT32 (dcom->data);
7207 goto invalid_compression;
7209 method = QT_FOURCC ((guint8 *) dcom->data + 8);
7213 guint uncompressed_length;
7214 guint compressed_length;
7218 cmvd_len = QT_UINT32 ((guint8 *) cmvd->data);
7220 goto invalid_compression;
7222 uncompressed_length = QT_UINT32 ((guint8 *) cmvd->data + 8);
7223 compressed_length = cmvd_len - 12;
7224 GST_LOG ("length = %u", uncompressed_length);
7227 (guint8 *) qtdemux_inflate ((guint8 *) cmvd->data + 12,
7228 compressed_length, &uncompressed_length);
7231 qtdemux->moov_node_compressed = qtdemux->moov_node;
7232 qtdemux->moov_node = g_node_new (buf);
7234 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buf,
7235 uncompressed_length);
7239 #endif /* HAVE_ZLIB */
7241 GST_WARNING_OBJECT (qtdemux, "unknown or unhandled header compression "
7242 "type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (method));
7249 invalid_compression:
7251 GST_ERROR_OBJECT (qtdemux, "invalid compressed header");
7257 qtdemux_parse_container (GstQTDemux * qtdemux, GNode * node, const guint8 * buf,
7260 while (G_UNLIKELY (buf < end)) {
7264 if (G_UNLIKELY (buf + 4 > end)) {
7265 GST_LOG_OBJECT (qtdemux, "buffer overrun");
7268 len = QT_UINT32 (buf);
7269 if (G_UNLIKELY (len == 0)) {
7270 GST_LOG_OBJECT (qtdemux, "empty container");
7273 if (G_UNLIKELY (len < 8)) {
7274 GST_WARNING_OBJECT (qtdemux, "length too short (%d < 8)", len);
7277 if (G_UNLIKELY (len > (end - buf))) {
7278 GST_WARNING_OBJECT (qtdemux, "length too long (%d > %d)", len,
7279 (gint) (end - buf));
7283 child = g_node_new ((guint8 *) buf);
7284 g_node_append (node, child);
7285 GST_LOG_OBJECT (qtdemux, "adding new node of len %d", len);
7286 qtdemux_parse_node (qtdemux, child, buf, len);
7294 qtdemux_parse_theora_extension (GstQTDemux * qtdemux, QtDemuxStream * stream,
7297 int len = QT_UINT32 (xdxt->data);
7298 guint8 *buf = xdxt->data;
7299 guint8 *end = buf + len;
7302 /* skip size and type */
7310 size = QT_UINT32 (buf);
7311 type = QT_FOURCC (buf + 4);
7313 GST_LOG_OBJECT (qtdemux, "%p %p", buf, end);
7315 if (buf + size > end || size <= 0)
7321 GST_WARNING_OBJECT (qtdemux, "have cookie %" GST_FOURCC_FORMAT,
7322 GST_FOURCC_ARGS (type));
7326 buffer = gst_buffer_new_and_alloc (size);
7327 gst_buffer_fill (buffer, 0, buf, size);
7328 stream->buffers = g_slist_append (stream->buffers, buffer);
7329 GST_LOG_OBJECT (qtdemux, "parsing theora header");
7332 buffer = gst_buffer_new_and_alloc (size);
7333 gst_buffer_fill (buffer, 0, buf, size);
7334 stream->buffers = g_slist_append (stream->buffers, buffer);
7335 GST_LOG_OBJECT (qtdemux, "parsing theora comment");
7338 buffer = gst_buffer_new_and_alloc (size);
7339 gst_buffer_fill (buffer, 0, buf, size);
7340 stream->buffers = g_slist_append (stream->buffers, buffer);
7341 GST_LOG_OBJECT (qtdemux, "parsing theora codebook");
7344 GST_WARNING_OBJECT (qtdemux,
7345 "unknown theora cookie %" GST_FOURCC_FORMAT,
7346 GST_FOURCC_ARGS (type));
7355 qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node, const guint8 * buffer,
7359 guint32 node_length = 0;
7360 const QtNodeType *type;
7363 GST_LOG_OBJECT (qtdemux, "qtdemux_parse buffer %p length %u", buffer, length);
7365 if (G_UNLIKELY (length < 8))
7366 goto not_enough_data;
7368 node_length = QT_UINT32 (buffer);
7369 fourcc = QT_FOURCC (buffer + 4);
7371 /* ignore empty nodes */
7372 if (G_UNLIKELY (fourcc == 0 || node_length == 8))
7375 type = qtdemux_type_get (fourcc);
7377 end = buffer + length;
7379 GST_LOG_OBJECT (qtdemux,
7380 "parsing '%" GST_FOURCC_FORMAT "', length=%u, name '%s'",
7381 GST_FOURCC_ARGS (fourcc), node_length, type->name);
7383 if (node_length > length)
7384 goto broken_atom_size;
7386 if (type->flags & QT_FLAG_CONTAINER) {
7387 qtdemux_parse_container (qtdemux, node, buffer + 8, end);
7392 if (node_length < 20) {
7393 GST_LOG_OBJECT (qtdemux, "skipping small stsd box");
7396 GST_DEBUG_OBJECT (qtdemux,
7397 "parsing stsd (sample table, sample description) atom");
7398 /* Skip over 8 byte atom hdr + 1 byte version, 3 bytes flags, 4 byte num_entries */
7399 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
7410 /* also read alac (or whatever) in stead of mp4a in the following,
7411 * since a similar layout is used in other cases as well */
7412 if (fourcc == FOURCC_mp4a)
7414 else if (fourcc == FOURCC_fLaC)
7419 /* There are two things we might encounter here: a true mp4a atom, and
7420 an mp4a entry in an stsd atom. The latter is what we're interested
7421 in, and it looks like an atom, but isn't really one. The true mp4a
7422 atom is short, so we detect it based on length here. */
7423 if (length < min_size) {
7424 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
7425 GST_FOURCC_ARGS (fourcc));
7429 /* 'version' here is the sound sample description version. Types 0 and
7430 1 are documented in the QTFF reference, but type 2 is not: it's
7431 described in Apple header files instead (struct SoundDescriptionV2
7433 version = QT_UINT16 (buffer + 16);
7435 GST_DEBUG_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT " version 0x%08x",
7436 GST_FOURCC_ARGS (fourcc), version);
7438 /* parse any esds descriptors */
7450 GST_WARNING_OBJECT (qtdemux,
7451 "unhandled %" GST_FOURCC_FORMAT " version 0x%08x",
7452 GST_FOURCC_ARGS (fourcc), version);
7457 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
7483 /* codec_data is contained inside these atoms, which all have
7484 * the same format. */
7485 /* video sample description size is 86 bytes without extension.
7486 * node_length have to be bigger than 86 bytes because video sample
7487 * description can include extenstions such as esds, fiel, glbl, etc. */
7488 if (node_length < 86) {
7489 GST_WARNING_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT
7490 " sample description length too short (%u < 86)",
7491 GST_FOURCC_ARGS (fourcc), node_length);
7495 GST_DEBUG_OBJECT (qtdemux, "parsing in %" GST_FOURCC_FORMAT,
7496 GST_FOURCC_ARGS (fourcc));
7498 /* version (2 bytes) : this is set to 0, unless a compressor has changed
7500 * revision level (2 bytes) : must be set to 0. */
7501 version = QT_UINT32 (buffer + 16);
7502 GST_DEBUG_OBJECT (qtdemux, "version %08x", version);
7504 /* compressor name : PASCAL string and informative purposes
7505 * first byte : the number of bytes to be displayed.
7506 * it has to be less than 32 because it is reserved
7507 * space of 32 bytes total including itself. */
7508 str_len = QT_UINT8 (buffer + 50);
7510 GST_DEBUG_OBJECT (qtdemux, "compressorname = %.*s", str_len,
7511 (char *) buffer + 51);
7513 GST_WARNING_OBJECT (qtdemux,
7514 "compressorname length too big (%u > 31)", str_len);
7516 GST_MEMDUMP_OBJECT (qtdemux, "video sample description", buffer,
7518 qtdemux_parse_container (qtdemux, node, buffer + 86, end);
7523 GST_DEBUG_OBJECT (qtdemux, "parsing meta atom");
7525 /* You are reading this correctly. QTFF specifies that the
7526 * metadata atom is a short atom, whereas ISO BMFF specifies
7527 * it's a full atom. But since so many people are doing things
7528 * differently, we actually peek into the atom to see which
7531 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
7532 GST_FOURCC_ARGS (fourcc));
7535 if (QT_FOURCC (buffer + 12) == FOURCC_hdlr) {
7536 /* Variant 1: What QTFF specifies. 'meta' is a short header which
7537 * starts with a 'hdlr' atom */
7538 qtdemux_parse_container (qtdemux, node, buffer + 8, end);
7539 } else if (QT_UINT32 (buffer + 8) == 0x00000000) {
7540 /* Variant 2: What ISO BMFF specifies. 'meta' is a _full_ atom
7541 * with version/flags both set to zero */
7542 qtdemux_parse_container (qtdemux, node, buffer + 12, end);
7544 GST_WARNING_OBJECT (qtdemux, "Unknown 'meta' atom format");
7549 GST_MEMDUMP_OBJECT (qtdemux, "mp4s", buffer, end - buffer);
7550 /* Skip 8 byte header, plus 8 byte version + flags + entry_count */
7551 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
7560 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
7561 GST_FOURCC_ARGS (fourcc));
7565 version = QT_UINT32 (buffer + 12);
7566 GST_DEBUG_OBJECT (qtdemux, "parsing XiTh atom version 0x%08x", version);
7573 GST_DEBUG_OBJECT (qtdemux, "unknown version 0x%08x", version);
7578 if (length < offset) {
7579 GST_WARNING_OBJECT (qtdemux,
7580 "skipping too small %" GST_FOURCC_FORMAT " box",
7581 GST_FOURCC_ARGS (fourcc));
7584 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
7590 qtdemux_parse_container (qtdemux, node, buffer + 0x34, end);
7595 qtdemux_parse_uuid (qtdemux, buffer, end - buffer);
7600 qtdemux_parse_container (qtdemux, node, buffer + 36, end);
7604 if (!strcmp (type->name, "unknown"))
7605 GST_MEMDUMP ("Unknown tag", buffer + 4, end - buffer - 4);
7609 GST_LOG_OBJECT (qtdemux, "parsed '%" GST_FOURCC_FORMAT "'",
7610 GST_FOURCC_ARGS (fourcc));
7616 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
7617 (_("This file is corrupt and cannot be played.")),
7618 ("Not enough data for an atom header, got only %u bytes", length));
7623 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
7624 (_("This file is corrupt and cannot be played.")),
7625 ("Atom '%" GST_FOURCC_FORMAT "' has size of %u bytes, but we have only "
7626 "%u bytes available.", GST_FOURCC_ARGS (fourcc), node_length,
7633 qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc)
7637 guint32 child_fourcc;
7639 for (child = g_node_first_child (node); child;
7640 child = g_node_next_sibling (child)) {
7641 buffer = (guint8 *) child->data;
7643 child_fourcc = QT_FOURCC (buffer + 4);
7645 if (G_UNLIKELY (child_fourcc == fourcc)) {
7653 qtdemux_tree_get_child_by_type_full (GNode * node, guint32 fourcc,
7654 GstByteReader * parser)
7658 guint32 child_fourcc, child_len;
7660 for (child = g_node_first_child (node); child;
7661 child = g_node_next_sibling (child)) {
7662 buffer = (guint8 *) child->data;
7664 child_len = QT_UINT32 (buffer);
7665 child_fourcc = QT_FOURCC (buffer + 4);
7667 if (G_UNLIKELY (child_fourcc == fourcc)) {
7668 if (G_UNLIKELY (child_len < (4 + 4)))
7670 /* FIXME: must verify if atom length < parent atom length */
7671 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
7679 qtdemux_tree_get_child_by_index (GNode * node, guint index)
7681 return g_node_nth_child (node, index);
7685 qtdemux_tree_get_sibling_by_type_full (GNode * node, guint32 fourcc,
7686 GstByteReader * parser)
7690 guint32 child_fourcc, child_len;
7692 for (child = g_node_next_sibling (node); child;
7693 child = g_node_next_sibling (child)) {
7694 buffer = (guint8 *) child->data;
7696 child_fourcc = QT_FOURCC (buffer + 4);
7698 if (child_fourcc == fourcc) {
7700 child_len = QT_UINT32 (buffer);
7701 if (G_UNLIKELY (child_len < (4 + 4)))
7703 /* FIXME: must verify if atom length < parent atom length */
7704 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
7713 qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc)
7715 return qtdemux_tree_get_sibling_by_type_full (node, fourcc, NULL);
7719 qtdemux_do_allocation (GstQTDemux * qtdemux, QtDemuxStream * stream)
7721 /* FIXME: This can only reliably work if demuxers have a
7722 * separate streaming thread per srcpad. This should be
7723 * done in a demuxer base class, which integrates parts
7726 * https://bugzilla.gnome.org/show_bug.cgi?id=701856
7731 query = gst_query_new_allocation (stream->caps, FALSE);
7733 if (!gst_pad_peer_query (stream->pad, query)) {
7734 /* not a problem, just debug a little */
7735 GST_DEBUG_OBJECT (qtdemux, "peer ALLOCATION query failed");
7738 if (stream->allocator)
7739 gst_object_unref (stream->allocator);
7741 if (gst_query_get_n_allocation_params (query) > 0) {
7742 /* try the allocator */
7743 gst_query_parse_nth_allocation_param (query, 0, &stream->allocator,
7745 stream->use_allocator = TRUE;
7747 stream->allocator = NULL;
7748 gst_allocation_params_init (&stream->params);
7749 stream->use_allocator = FALSE;
7751 gst_query_unref (query);
7756 gst_qtdemux_configure_protected_caps (GstQTDemux * qtdemux,
7757 QtDemuxStream * stream)
7760 const gchar *selected_system;
7762 g_return_val_if_fail (qtdemux != NULL, FALSE);
7763 g_return_val_if_fail (stream != NULL, FALSE);
7764 g_return_val_if_fail (gst_caps_get_size (CUR_STREAM (stream)->caps) == 1,
7767 if (stream->protection_scheme_type != FOURCC_cenc) {
7768 GST_ERROR_OBJECT (qtdemux, "unsupported protection scheme");
7771 if (qtdemux->protection_system_ids == NULL) {
7772 GST_ERROR_OBJECT (qtdemux, "stream is protected using cenc, but no "
7773 "cenc protection system information has been found");
7776 g_ptr_array_add (qtdemux->protection_system_ids, NULL);
7777 selected_system = gst_protection_select_system ((const gchar **)
7778 qtdemux->protection_system_ids->pdata);
7779 g_ptr_array_remove_index (qtdemux->protection_system_ids,
7780 qtdemux->protection_system_ids->len - 1);
7781 if (!selected_system) {
7782 GST_ERROR_OBJECT (qtdemux, "stream is protected, but no "
7783 "suitable decryptor element has been found");
7787 s = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
7788 if (!gst_structure_has_name (s, "application/x-cenc")) {
7789 gst_structure_set (s,
7790 "original-media-type", G_TYPE_STRING, gst_structure_get_name (s),
7791 GST_PROTECTION_SYSTEM_ID_CAPS_FIELD, G_TYPE_STRING, selected_system,
7793 gst_structure_set_name (s, "application/x-cenc");
7799 gst_qtdemux_configure_stream (GstQTDemux * qtdemux, QtDemuxStream * stream)
7801 if (stream->subtype == FOURCC_vide) {
7802 /* fps is calculated base on the duration of the average framerate since
7803 * qt does not have a fixed framerate. */
7804 gboolean fps_available = TRUE;
7806 if ((stream->n_samples == 1 && stream->first_duration == 0)
7807 || (qtdemux->fragmented && stream->n_samples_moof == 1)) {
7809 CUR_STREAM (stream)->fps_n = 0;
7810 CUR_STREAM (stream)->fps_d = 1;
7812 if (stream->duration == 0 || stream->n_samples < 2) {
7813 CUR_STREAM (stream)->fps_n = stream->timescale;
7814 CUR_STREAM (stream)->fps_d = 1;
7815 fps_available = FALSE;
7817 GstClockTime avg_duration;
7821 /* duration and n_samples can be updated for fragmented format
7822 * so, framerate of fragmented format is calculated using data in a moof */
7823 if (qtdemux->fragmented && stream->n_samples_moof > 0
7824 && stream->duration_moof > 0) {
7825 n_samples = stream->n_samples_moof;
7826 duration = stream->duration_moof;
7828 n_samples = stream->n_samples;
7829 duration = stream->duration;
7832 /* Calculate a framerate, ignoring the first sample which is sometimes truncated */
7833 /* stream->duration is guint64, timescale, n_samples are guint32 */
7835 gst_util_uint64_scale_round (duration -
7836 stream->first_duration, GST_SECOND,
7837 (guint64) (stream->timescale) * (n_samples - 1));
7839 GST_LOG_OBJECT (qtdemux,
7840 "Calculating avg sample duration based on stream (or moof) duration %"
7842 " minus first sample %u, leaving %d samples gives %"
7843 GST_TIME_FORMAT, duration, stream->first_duration,
7844 n_samples - 1, GST_TIME_ARGS (avg_duration));
7846 gst_video_guess_framerate (avg_duration, &CUR_STREAM (stream)->fps_n,
7847 &CUR_STREAM (stream)->fps_d);
7849 GST_DEBUG_OBJECT (qtdemux,
7850 "Calculating framerate, timescale %u gave fps_n %d fps_d %d",
7851 stream->timescale, CUR_STREAM (stream)->fps_n,
7852 CUR_STREAM (stream)->fps_d);
7856 if (CUR_STREAM (stream)->caps) {
7857 CUR_STREAM (stream)->caps =
7858 gst_caps_make_writable (CUR_STREAM (stream)->caps);
7860 gst_caps_set_simple (CUR_STREAM (stream)->caps,
7861 "width", G_TYPE_INT, CUR_STREAM (stream)->width,
7862 "height", G_TYPE_INT, CUR_STREAM (stream)->height, NULL);
7864 /* set framerate if calculated framerate is reliable */
7865 if (fps_available) {
7866 gst_caps_set_simple (CUR_STREAM (stream)->caps,
7867 "framerate", GST_TYPE_FRACTION, CUR_STREAM (stream)->fps_n,
7868 CUR_STREAM (stream)->fps_d, NULL);
7871 /* calculate pixel-aspect-ratio using display width and height */
7872 GST_DEBUG_OBJECT (qtdemux,
7873 "video size %dx%d, target display size %dx%d",
7874 CUR_STREAM (stream)->width, CUR_STREAM (stream)->height,
7875 stream->display_width, stream->display_height);
7876 /* qt file might have pasp atom */
7877 if (CUR_STREAM (stream)->par_w > 0 && CUR_STREAM (stream)->par_h > 0) {
7878 GST_DEBUG_OBJECT (qtdemux, "par %d:%d", CUR_STREAM (stream)->par_w,
7879 CUR_STREAM (stream)->par_h);
7880 gst_caps_set_simple (CUR_STREAM (stream)->caps, "pixel-aspect-ratio",
7881 GST_TYPE_FRACTION, CUR_STREAM (stream)->par_w,
7882 CUR_STREAM (stream)->par_h, NULL);
7883 } else if (stream->display_width > 0 && stream->display_height > 0
7884 && CUR_STREAM (stream)->width > 0
7885 && CUR_STREAM (stream)->height > 0) {
7888 /* calculate the pixel aspect ratio using the display and pixel w/h */
7889 n = stream->display_width * CUR_STREAM (stream)->height;
7890 d = stream->display_height * CUR_STREAM (stream)->width;
7893 GST_DEBUG_OBJECT (qtdemux, "setting PAR to %d/%d", n, d);
7894 CUR_STREAM (stream)->par_w = n;
7895 CUR_STREAM (stream)->par_h = d;
7896 gst_caps_set_simple (CUR_STREAM (stream)->caps, "pixel-aspect-ratio",
7897 GST_TYPE_FRACTION, CUR_STREAM (stream)->par_w,
7898 CUR_STREAM (stream)->par_h, NULL);
7901 if (CUR_STREAM (stream)->interlace_mode > 0) {
7902 if (CUR_STREAM (stream)->interlace_mode == 1) {
7903 gst_caps_set_simple (CUR_STREAM (stream)->caps, "interlace-mode",
7904 G_TYPE_STRING, "progressive", NULL);
7905 } else if (CUR_STREAM (stream)->interlace_mode == 2) {
7906 gst_caps_set_simple (CUR_STREAM (stream)->caps, "interlace-mode",
7907 G_TYPE_STRING, "interleaved", NULL);
7908 if (CUR_STREAM (stream)->field_order == 9) {
7909 gst_caps_set_simple (CUR_STREAM (stream)->caps, "field-order",
7910 G_TYPE_STRING, "top-field-first", NULL);
7911 } else if (CUR_STREAM (stream)->field_order == 14) {
7912 gst_caps_set_simple (CUR_STREAM (stream)->caps, "field-order",
7913 G_TYPE_STRING, "bottom-field-first", NULL);
7918 /* Create incomplete colorimetry here if needed */
7919 if (CUR_STREAM (stream)->colorimetry.range ||
7920 CUR_STREAM (stream)->colorimetry.matrix ||
7921 CUR_STREAM (stream)->colorimetry.transfer
7922 || CUR_STREAM (stream)->colorimetry.primaries) {
7923 gchar *colorimetry =
7924 gst_video_colorimetry_to_string (&CUR_STREAM (stream)->colorimetry);
7925 gst_caps_set_simple (CUR_STREAM (stream)->caps, "colorimetry",
7926 G_TYPE_STRING, colorimetry, NULL);
7927 g_free (colorimetry);
7930 if (stream->multiview_mode != GST_VIDEO_MULTIVIEW_MODE_NONE) {
7931 guint par_w = 1, par_h = 1;
7933 if (CUR_STREAM (stream)->par_w > 0 && CUR_STREAM (stream)->par_h > 0) {
7934 par_w = CUR_STREAM (stream)->par_w;
7935 par_h = CUR_STREAM (stream)->par_h;
7938 if (gst_video_multiview_guess_half_aspect (stream->multiview_mode,
7939 CUR_STREAM (stream)->width, CUR_STREAM (stream)->height, par_w,
7941 stream->multiview_flags |= GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT;
7944 gst_caps_set_simple (CUR_STREAM (stream)->caps,
7945 "multiview-mode", G_TYPE_STRING,
7946 gst_video_multiview_mode_to_caps_string (stream->multiview_mode),
7947 "multiview-flags", GST_TYPE_VIDEO_MULTIVIEW_FLAGSET,
7948 stream->multiview_flags, GST_FLAG_SET_MASK_EXACT, NULL);
7953 else if (stream->subtype == FOURCC_soun) {
7954 if (CUR_STREAM (stream)->caps) {
7955 CUR_STREAM (stream)->caps =
7956 gst_caps_make_writable (CUR_STREAM (stream)->caps);
7957 if (CUR_STREAM (stream)->rate > 0)
7958 gst_caps_set_simple (CUR_STREAM (stream)->caps,
7959 "rate", G_TYPE_INT, (int) CUR_STREAM (stream)->rate, NULL);
7960 if (CUR_STREAM (stream)->n_channels > 0)
7961 gst_caps_set_simple (CUR_STREAM (stream)->caps,
7962 "channels", G_TYPE_INT, CUR_STREAM (stream)->n_channels, NULL);
7963 if (CUR_STREAM (stream)->n_channels > 2) {
7964 /* FIXME: Need to parse the 'chan' atom to get channel layouts
7965 * correctly; this is just the minimum we can do - assume
7966 * we don't actually have any channel positions. */
7967 gst_caps_set_simple (CUR_STREAM (stream)->caps,
7968 "channel-mask", GST_TYPE_BITMASK, G_GUINT64_CONSTANT (0), NULL);
7974 GstCaps *prev_caps = NULL;
7976 GST_PAD_ELEMENT_PRIVATE (stream->pad) = stream;
7977 gst_pad_set_event_function (stream->pad, gst_qtdemux_handle_src_event);
7978 gst_pad_set_query_function (stream->pad, gst_qtdemux_handle_src_query);
7979 gst_pad_set_active (stream->pad, TRUE);
7981 gst_pad_use_fixed_caps (stream->pad);
7983 if (stream->protected) {
7984 if (!gst_qtdemux_configure_protected_caps (qtdemux, stream)) {
7985 GST_ERROR_OBJECT (qtdemux,
7986 "Failed to configure protected stream caps.");
7991 GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT,
7992 CUR_STREAM (stream)->caps);
7993 if (stream->new_stream) {
7996 GstStreamFlags stream_flags = GST_STREAM_FLAG_NONE;
7999 gst_pad_get_sticky_event (qtdemux->sinkpad, GST_EVENT_STREAM_START,
8002 gst_event_parse_stream_flags (event, &stream_flags);
8003 if (gst_event_parse_group_id (event, &qtdemux->group_id))
8004 qtdemux->have_group_id = TRUE;
8006 qtdemux->have_group_id = FALSE;
8007 gst_event_unref (event);
8008 } else if (!qtdemux->have_group_id) {
8009 qtdemux->have_group_id = TRUE;
8010 qtdemux->group_id = gst_util_group_id_next ();
8013 stream->new_stream = FALSE;
8015 gst_pad_create_stream_id_printf (stream->pad,
8016 GST_ELEMENT_CAST (qtdemux), "%03u", stream->track_id);
8017 event = gst_event_new_stream_start (stream_id);
8018 if (qtdemux->have_group_id)
8019 gst_event_set_group_id (event, qtdemux->group_id);
8020 if (stream->disabled)
8021 stream_flags |= GST_STREAM_FLAG_UNSELECT;
8022 if (CUR_STREAM (stream)->sparse) {
8023 stream_flags |= GST_STREAM_FLAG_SPARSE;
8025 stream_flags &= ~GST_STREAM_FLAG_SPARSE;
8027 gst_event_set_stream_flags (event, stream_flags);
8028 gst_pad_push_event (stream->pad, event);
8032 prev_caps = gst_pad_get_current_caps (stream->pad);
8034 if (CUR_STREAM (stream)->caps) {
8036 || !gst_caps_is_equal_fixed (prev_caps, CUR_STREAM (stream)->caps)) {
8037 GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT,
8038 CUR_STREAM (stream)->caps);
8039 gst_pad_set_caps (stream->pad, CUR_STREAM (stream)->caps);
8041 GST_DEBUG_OBJECT (qtdemux, "ignore duplicated caps");
8044 GST_WARNING_OBJECT (qtdemux, "stream without caps");
8048 gst_caps_unref (prev_caps);
8049 stream->new_caps = FALSE;
8055 gst_qtdemux_stream_check_and_change_stsd_index (GstQTDemux * demux,
8056 QtDemuxStream * stream)
8058 if (stream->cur_stsd_entry_index == stream->stsd_sample_description_id)
8061 GST_DEBUG_OBJECT (stream->pad, "Changing stsd index from '%u' to '%u'",
8062 stream->cur_stsd_entry_index, stream->stsd_sample_description_id);
8063 if (G_UNLIKELY (stream->stsd_sample_description_id >=
8064 stream->stsd_entries_length)) {
8065 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
8066 (_("This file is invalid and cannot be played.")),
8067 ("New sample description id is out of bounds (%d >= %d)",
8068 stream->stsd_sample_description_id, stream->stsd_entries_length));
8070 stream->cur_stsd_entry_index = stream->stsd_sample_description_id;
8071 stream->new_caps = TRUE;
8076 gst_qtdemux_add_stream (GstQTDemux * qtdemux,
8077 QtDemuxStream * stream, GstTagList * list)
8079 gboolean ret = TRUE;
8080 /* consistent default for push based mode */
8081 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
8083 if (stream->subtype == FOURCC_vide) {
8084 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
8087 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);
8097 qtdemux->n_video_streams++;
8098 } else if (stream->subtype == FOURCC_soun) {
8099 gchar *name = g_strdup_printf ("audio_%u", qtdemux->n_audio_streams);
8102 gst_pad_new_from_static_template (&gst_qtdemux_audiosrc_template, name);
8104 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8105 gst_object_unref (stream->pad);
8110 qtdemux->n_audio_streams++;
8111 } else if (stream->subtype == FOURCC_strm) {
8112 GST_DEBUG_OBJECT (qtdemux, "stream type, not creating pad");
8113 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
8114 || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt) {
8115 gchar *name = g_strdup_printf ("subtitle_%u", qtdemux->n_sub_streams);
8118 gst_pad_new_from_static_template (&gst_qtdemux_subsrc_template, name);
8120 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8121 gst_object_unref (stream->pad);
8126 qtdemux->n_sub_streams++;
8127 } else if (CUR_STREAM (stream)->caps) {
8128 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
8131 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
8133 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8134 gst_object_unref (stream->pad);
8139 qtdemux->n_video_streams++;
8141 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
8148 GST_DEBUG_OBJECT (qtdemux, "adding pad %s %p to qtdemux %p",
8149 GST_OBJECT_NAME (stream->pad), stream->pad, qtdemux);
8150 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
8151 gst_flow_combiner_add_pad (qtdemux->flowcombiner, stream->pad);
8153 if (stream->stream_tags)
8154 gst_tag_list_unref (stream->stream_tags);
8155 stream->stream_tags = list;
8157 /* global tags go on each pad anyway */
8158 stream->send_global_tags = TRUE;
8159 /* send upstream GST_EVENT_PROTECTION events that were received before
8160 this source pad was created */
8161 for (l = qtdemux->protection_event_queue.head; l != NULL; l = l->next)
8162 gst_pad_push_event (stream->pad, gst_event_ref (l->data));
8166 gst_tag_list_unref (list);
8170 /* find next atom with @fourcc starting at @offset */
8171 static GstFlowReturn
8172 qtdemux_find_atom (GstQTDemux * qtdemux, guint64 * offset,
8173 guint64 * length, guint32 fourcc)
8179 GST_LOG_OBJECT (qtdemux, "finding fourcc %" GST_FOURCC_FORMAT " at offset %"
8180 G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), *offset);
8186 ret = gst_pad_pull_range (qtdemux->sinkpad, *offset, 16, &buf);
8187 if (G_UNLIKELY (ret != GST_FLOW_OK))
8189 if (G_UNLIKELY (gst_buffer_get_size (buf) != 16)) {
8192 gst_buffer_unref (buf);
8195 gst_buffer_map (buf, &map, GST_MAP_READ);
8196 extract_initial_length_and_fourcc (map.data, 16, length, &lfourcc);
8197 gst_buffer_unmap (buf, &map);
8198 gst_buffer_unref (buf);
8200 if (G_UNLIKELY (*length == 0)) {
8201 GST_DEBUG_OBJECT (qtdemux, "invalid length 0");
8202 ret = GST_FLOW_ERROR;
8206 if (lfourcc == fourcc) {
8207 GST_DEBUG_OBJECT (qtdemux, "found fourcc at offset %" G_GUINT64_FORMAT,
8211 GST_LOG_OBJECT (qtdemux,
8212 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
8213 GST_FOURCC_ARGS (fourcc), *offset);
8222 /* might simply have had last one */
8223 GST_DEBUG_OBJECT (qtdemux, "fourcc not found");
8228 /* should only do something in pull mode */
8229 /* call with OBJECT lock */
8230 static GstFlowReturn
8231 qtdemux_add_fragmented_samples (GstQTDemux * qtdemux)
8233 guint64 length, offset;
8234 GstBuffer *buf = NULL;
8235 GstFlowReturn ret = GST_FLOW_OK;
8236 GstFlowReturn res = GST_FLOW_OK;
8239 offset = qtdemux->moof_offset;
8240 GST_DEBUG_OBJECT (qtdemux, "next moof at offset %" G_GUINT64_FORMAT, offset);
8243 GST_DEBUG_OBJECT (qtdemux, "no next moof");
8244 return GST_FLOW_EOS;
8247 /* best not do pull etc with lock held */
8248 GST_OBJECT_UNLOCK (qtdemux);
8250 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
8251 if (ret != GST_FLOW_OK)
8254 ret = gst_qtdemux_pull_atom (qtdemux, offset, length, &buf);
8255 if (G_UNLIKELY (ret != GST_FLOW_OK))
8257 gst_buffer_map (buf, &map, GST_MAP_READ);
8258 if (!qtdemux_parse_moof (qtdemux, map.data, map.size, offset, NULL)) {
8259 gst_buffer_unmap (buf, &map);
8260 gst_buffer_unref (buf);
8265 gst_buffer_unmap (buf, &map);
8266 gst_buffer_unref (buf);
8270 /* look for next moof */
8271 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
8272 if (G_UNLIKELY (ret != GST_FLOW_OK))
8276 GST_OBJECT_LOCK (qtdemux);
8278 qtdemux->moof_offset = offset;
8284 GST_DEBUG_OBJECT (qtdemux, "failed to parse moof");
8286 res = GST_FLOW_ERROR;
8291 /* maybe upstream temporarily flushing */
8292 if (ret != GST_FLOW_FLUSHING) {
8293 GST_DEBUG_OBJECT (qtdemux, "no next moof");
8296 GST_DEBUG_OBJECT (qtdemux, "upstream WRONG_STATE");
8297 /* resume at current position next time */
8304 /* initialise bytereaders for stbl sub-atoms */
8306 qtdemux_stbl_init (GstQTDemux * qtdemux, QtDemuxStream * stream, GNode * stbl)
8308 stream->stbl_index = -1; /* no samples have yet been parsed */
8309 stream->sample_index = -1;
8311 /* time-to-sample atom */
8312 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stts, &stream->stts))
8315 /* copy atom data into a new buffer for later use */
8316 stream->stts.data = g_memdup (stream->stts.data, stream->stts.size);
8318 /* skip version + flags */
8319 if (!gst_byte_reader_skip (&stream->stts, 1 + 3) ||
8320 !gst_byte_reader_get_uint32_be (&stream->stts, &stream->n_sample_times))
8322 GST_LOG_OBJECT (qtdemux, "%u timestamp blocks", stream->n_sample_times);
8324 /* make sure there's enough data */
8325 if (!qt_atom_parser_has_chunks (&stream->stts, stream->n_sample_times, 8)) {
8326 stream->n_sample_times = gst_byte_reader_get_remaining (&stream->stts) / 8;
8327 GST_LOG_OBJECT (qtdemux, "overriding to %u timestamp blocks",
8328 stream->n_sample_times);
8329 if (!stream->n_sample_times)
8333 /* sync sample atom */
8334 stream->stps_present = FALSE;
8335 if ((stream->stss_present =
8336 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stss,
8337 &stream->stss) ? TRUE : FALSE) == TRUE) {
8338 /* copy atom data into a new buffer for later use */
8339 stream->stss.data = g_memdup (stream->stss.data, stream->stss.size);
8341 /* skip version + flags */
8342 if (!gst_byte_reader_skip (&stream->stss, 1 + 3) ||
8343 !gst_byte_reader_get_uint32_be (&stream->stss, &stream->n_sample_syncs))
8346 if (stream->n_sample_syncs) {
8347 /* make sure there's enough data */
8348 if (!qt_atom_parser_has_chunks (&stream->stss, stream->n_sample_syncs, 4))
8352 /* partial sync sample atom */
8353 if ((stream->stps_present =
8354 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stps,
8355 &stream->stps) ? TRUE : FALSE) == TRUE) {
8356 /* copy atom data into a new buffer for later use */
8357 stream->stps.data = g_memdup (stream->stps.data, stream->stps.size);
8359 /* skip version + flags */
8360 if (!gst_byte_reader_skip (&stream->stps, 1 + 3) ||
8361 !gst_byte_reader_get_uint32_be (&stream->stps,
8362 &stream->n_sample_partial_syncs))
8365 /* if there are no entries, the stss table contains the real
8367 if (stream->n_sample_partial_syncs) {
8368 /* make sure there's enough data */
8369 if (!qt_atom_parser_has_chunks (&stream->stps,
8370 stream->n_sample_partial_syncs, 4))
8377 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsz, &stream->stsz))
8380 /* copy atom data into a new buffer for later use */
8381 stream->stsz.data = g_memdup (stream->stsz.data, stream->stsz.size);
8383 /* skip version + flags */
8384 if (!gst_byte_reader_skip (&stream->stsz, 1 + 3) ||
8385 !gst_byte_reader_get_uint32_be (&stream->stsz, &stream->sample_size))
8388 if (!gst_byte_reader_get_uint32_be (&stream->stsz, &stream->n_samples))
8391 if (!stream->n_samples)
8394 /* sample-to-chunk atom */
8395 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsc, &stream->stsc))
8398 /* copy atom data into a new buffer for later use */
8399 stream->stsc.data = g_memdup (stream->stsc.data, stream->stsc.size);
8401 /* skip version + flags */
8402 if (!gst_byte_reader_skip (&stream->stsc, 1 + 3) ||
8403 !gst_byte_reader_get_uint32_be (&stream->stsc,
8404 &stream->n_samples_per_chunk))
8407 GST_DEBUG_OBJECT (qtdemux, "n_samples_per_chunk %u",
8408 stream->n_samples_per_chunk);
8410 /* make sure there's enough data */
8411 if (!qt_atom_parser_has_chunks (&stream->stsc, stream->n_samples_per_chunk,
8417 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stco, &stream->stco))
8418 stream->co_size = sizeof (guint32);
8419 else if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_co64,
8421 stream->co_size = sizeof (guint64);
8425 /* copy atom data into a new buffer for later use */
8426 stream->stco.data = g_memdup (stream->stco.data, stream->stco.size);
8428 /* skip version + flags */
8429 if (!gst_byte_reader_skip (&stream->stco, 1 + 3))
8432 /* chunks_are_samples == TRUE means treat chunks as samples */
8433 stream->chunks_are_samples = stream->sample_size
8434 && !CUR_STREAM (stream)->sampled;
8435 if (stream->chunks_are_samples) {
8436 /* treat chunks as samples */
8437 if (!gst_byte_reader_get_uint32_be (&stream->stco, &stream->n_samples))
8440 /* skip number of entries */
8441 if (!gst_byte_reader_skip (&stream->stco, 4))
8444 /* make sure there are enough data in the stsz atom */
8445 if (!stream->sample_size) {
8446 /* different sizes for each sample */
8447 if (!qt_atom_parser_has_chunks (&stream->stsz, stream->n_samples, 4))
8452 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
8453 stream->n_samples, (guint) sizeof (QtDemuxSample),
8454 stream->n_samples * sizeof (QtDemuxSample) / (1024.0 * 1024.0));
8456 if (stream->n_samples >=
8457 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample)) {
8458 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
8459 "be larger than %uMB (broken file?)", stream->n_samples,
8460 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
8464 g_assert (stream->samples == NULL);
8465 stream->samples = g_try_new0 (QtDemuxSample, stream->n_samples);
8466 if (!stream->samples) {
8467 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
8472 /* composition time-to-sample */
8473 if ((stream->ctts_present =
8474 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_ctts,
8475 &stream->ctts) ? TRUE : FALSE) == TRUE) {
8476 GstByteReader cslg = GST_BYTE_READER_INIT (NULL, 0);
8478 /* copy atom data into a new buffer for later use */
8479 stream->ctts.data = g_memdup (stream->ctts.data, stream->ctts.size);
8481 /* skip version + flags */
8482 if (!gst_byte_reader_skip (&stream->ctts, 1 + 3)
8483 || !gst_byte_reader_get_uint32_be (&stream->ctts,
8484 &stream->n_composition_times))
8487 /* make sure there's enough data */
8488 if (!qt_atom_parser_has_chunks (&stream->ctts, stream->n_composition_times,
8492 /* This is optional, if missing we iterate the ctts */
8493 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_cslg, &cslg)) {
8494 if (!gst_byte_reader_skip (&cslg, 1 + 3)
8495 || !gst_byte_reader_get_uint32_be (&cslg, &stream->cslg_shift)) {
8496 g_free ((gpointer) cslg.data);
8500 gint32 cslg_least = 0;
8501 guint num_entries, pos;
8504 pos = gst_byte_reader_get_pos (&stream->ctts);
8505 num_entries = stream->n_composition_times;
8507 stream->cslg_shift = 0;
8509 for (i = 0; i < num_entries; i++) {
8512 gst_byte_reader_skip_unchecked (&stream->ctts, 4);
8513 offset = gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
8515 if (offset < cslg_least)
8516 cslg_least = offset;
8520 stream->cslg_shift = ABS (cslg_least);
8522 stream->cslg_shift = 0;
8524 /* reset the reader so we can generate sample table */
8525 gst_byte_reader_set_pos (&stream->ctts, pos);
8528 /* Ensure the cslg_shift value is consistent so we can use it
8529 * unconditionnally to produce TS and Segment */
8530 stream->cslg_shift = 0;
8537 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8538 (_("This file is corrupt and cannot be played.")), (NULL));
8543 gst_qtdemux_stbl_free (stream);
8544 if (!qtdemux->fragmented) {
8545 /* not quite good */
8546 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
8549 /* may pick up samples elsewhere */
8555 /* collect samples from the next sample to be parsed up to sample @n for @stream
8556 * by reading the info from @stbl
8558 * This code can be executed from both the streaming thread and the seeking
8559 * thread so it takes the object lock to protect itself
8562 qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream, guint32 n)
8565 QtDemuxSample *samples, *first, *cur, *last;
8566 guint32 n_samples_per_chunk;
8569 GST_LOG_OBJECT (qtdemux, "parsing samples for stream fourcc %"
8570 GST_FOURCC_FORMAT ", pad %s",
8571 GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc),
8572 stream->pad ? GST_PAD_NAME (stream->pad) : "(NULL)");
8574 n_samples = stream->n_samples;
8577 goto out_of_samples;
8579 GST_OBJECT_LOCK (qtdemux);
8580 if (n <= stream->stbl_index)
8581 goto already_parsed;
8583 GST_DEBUG_OBJECT (qtdemux, "parsing up to sample %u", n);
8585 if (!stream->stsz.data) {
8586 /* so we already parsed and passed all the moov samples;
8587 * onto fragmented ones */
8588 g_assert (qtdemux->fragmented);
8592 /* pointer to the sample table */
8593 samples = stream->samples;
8595 /* starts from -1, moves to the next sample index to parse */
8596 stream->stbl_index++;
8598 /* keep track of the first and last sample to fill */
8599 first = &samples[stream->stbl_index];
8602 if (!stream->chunks_are_samples) {
8603 /* set the sample sizes */
8604 if (stream->sample_size == 0) {
8605 /* different sizes for each sample */
8606 for (cur = first; cur <= last; cur++) {
8607 cur->size = gst_byte_reader_get_uint32_be_unchecked (&stream->stsz);
8608 GST_LOG_OBJECT (qtdemux, "sample %d has size %u",
8609 (guint) (cur - samples), cur->size);
8612 /* samples have the same size */
8613 GST_LOG_OBJECT (qtdemux, "all samples have size %u", stream->sample_size);
8614 for (cur = first; cur <= last; cur++)
8615 cur->size = stream->sample_size;
8619 n_samples_per_chunk = stream->n_samples_per_chunk;
8622 for (i = stream->stsc_index; i < n_samples_per_chunk; i++) {
8625 if (stream->stsc_chunk_index >= stream->last_chunk
8626 || stream->stsc_chunk_index < stream->first_chunk) {
8627 stream->first_chunk =
8628 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
8629 stream->samples_per_chunk =
8630 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
8632 stream->stsd_sample_description_id =
8633 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc) - 1;
8635 /* chunk numbers are counted from 1 it seems */
8636 if (G_UNLIKELY (stream->first_chunk == 0))
8639 --stream->first_chunk;
8641 /* the last chunk of each entry is calculated by taking the first chunk
8642 * of the next entry; except if there is no next, where we fake it with
8644 if (G_UNLIKELY (i == (stream->n_samples_per_chunk - 1))) {
8645 stream->last_chunk = G_MAXUINT32;
8647 stream->last_chunk =
8648 gst_byte_reader_peek_uint32_be_unchecked (&stream->stsc);
8649 if (G_UNLIKELY (stream->last_chunk == 0))
8652 --stream->last_chunk;
8655 GST_LOG_OBJECT (qtdemux,
8656 "entry %d has first_chunk %d, last_chunk %d, samples_per_chunk %d"
8657 "sample desc ID: %d", i, stream->first_chunk, stream->last_chunk,
8658 stream->samples_per_chunk, stream->stsd_sample_description_id);
8660 if (G_UNLIKELY (stream->last_chunk < stream->first_chunk))
8663 if (stream->last_chunk != G_MAXUINT32) {
8664 if (!qt_atom_parser_peek_sub (&stream->stco,
8665 stream->first_chunk * stream->co_size,
8666 (stream->last_chunk - stream->first_chunk) * stream->co_size,
8671 stream->co_chunk = stream->stco;
8672 if (!gst_byte_reader_skip (&stream->co_chunk,
8673 stream->first_chunk * stream->co_size))
8677 stream->stsc_chunk_index = stream->first_chunk;
8680 last_chunk = stream->last_chunk;
8682 if (stream->chunks_are_samples) {
8683 cur = &samples[stream->stsc_chunk_index];
8685 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
8688 stream->stsc_chunk_index = j;
8693 qt_atom_parser_get_offset_unchecked (&stream->co_chunk,
8696 GST_LOG_OBJECT (qtdemux, "Created entry %d with offset "
8697 "%" G_GUINT64_FORMAT, j, cur->offset);
8699 if (CUR_STREAM (stream)->samples_per_frame > 0 &&
8700 CUR_STREAM (stream)->bytes_per_frame > 0) {
8702 (stream->samples_per_chunk * CUR_STREAM (stream)->n_channels) /
8703 CUR_STREAM (stream)->samples_per_frame *
8704 CUR_STREAM (stream)->bytes_per_frame;
8706 cur->size = stream->samples_per_chunk;
8709 GST_DEBUG_OBJECT (qtdemux,
8710 "keyframe sample %d: timestamp %" GST_TIME_FORMAT ", size %u",
8711 j, GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream,
8712 stream->stco_sample_index)), cur->size);
8714 cur->timestamp = stream->stco_sample_index;
8715 cur->duration = stream->samples_per_chunk;
8716 cur->keyframe = TRUE;
8719 stream->stco_sample_index += stream->samples_per_chunk;
8721 stream->stsc_chunk_index = j;
8723 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
8724 guint32 samples_per_chunk;
8725 guint64 chunk_offset;
8727 if (!stream->stsc_sample_index
8728 && !qt_atom_parser_get_offset (&stream->co_chunk, stream->co_size,
8729 &stream->chunk_offset))
8732 samples_per_chunk = stream->samples_per_chunk;
8733 chunk_offset = stream->chunk_offset;
8735 for (k = stream->stsc_sample_index; k < samples_per_chunk; k++) {
8736 GST_LOG_OBJECT (qtdemux, "creating entry %d with offset %"
8737 G_GUINT64_FORMAT " and size %d",
8738 (guint) (cur - samples), chunk_offset, cur->size);
8740 cur->offset = chunk_offset;
8741 chunk_offset += cur->size;
8744 if (G_UNLIKELY (cur > last)) {
8746 stream->stsc_sample_index = k + 1;
8747 stream->chunk_offset = chunk_offset;
8748 stream->stsc_chunk_index = j;
8752 stream->stsc_sample_index = 0;
8754 stream->stsc_chunk_index = j;
8756 stream->stsc_index++;
8759 if (stream->chunks_are_samples)
8763 guint32 n_sample_times;
8765 n_sample_times = stream->n_sample_times;
8768 for (i = stream->stts_index; i < n_sample_times; i++) {
8769 guint32 stts_samples;
8770 gint32 stts_duration;
8773 if (stream->stts_sample_index >= stream->stts_samples
8774 || !stream->stts_sample_index) {
8776 stream->stts_samples =
8777 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
8778 stream->stts_duration =
8779 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
8781 GST_LOG_OBJECT (qtdemux, "block %d, %u timestamps, duration %u",
8782 i, stream->stts_samples, stream->stts_duration);
8784 stream->stts_sample_index = 0;
8787 stts_samples = stream->stts_samples;
8788 stts_duration = stream->stts_duration;
8789 stts_time = stream->stts_time;
8791 for (j = stream->stts_sample_index; j < stts_samples; j++) {
8792 GST_DEBUG_OBJECT (qtdemux,
8793 "sample %d: index %d, timestamp %" GST_TIME_FORMAT,
8794 (guint) (cur - samples), j,
8795 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stts_time)));
8797 cur->timestamp = stts_time;
8798 cur->duration = stts_duration;
8800 /* avoid 32-bit wrap-around,
8801 * but still mind possible 'negative' duration */
8802 stts_time += (gint64) stts_duration;
8805 if (G_UNLIKELY (cur > last)) {
8807 stream->stts_time = stts_time;
8808 stream->stts_sample_index = j + 1;
8809 if (stream->stts_sample_index >= stream->stts_samples)
8810 stream->stts_index++;
8814 stream->stts_sample_index = 0;
8815 stream->stts_time = stts_time;
8816 stream->stts_index++;
8818 /* fill up empty timestamps with the last timestamp, this can happen when
8819 * the last samples do not decode and so we don't have timestamps for them.
8820 * We however look at the last timestamp to estimate the track length so we
8821 * need something in here. */
8822 for (; cur < last; cur++) {
8823 GST_DEBUG_OBJECT (qtdemux,
8824 "fill sample %d: timestamp %" GST_TIME_FORMAT,
8825 (guint) (cur - samples),
8826 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stream->stts_time)));
8827 cur->timestamp = stream->stts_time;
8833 /* sample sync, can be NULL */
8834 if (stream->stss_present == TRUE) {
8835 guint32 n_sample_syncs;
8837 n_sample_syncs = stream->n_sample_syncs;
8839 if (!n_sample_syncs) {
8840 GST_DEBUG_OBJECT (qtdemux, "all samples are keyframes");
8841 stream->all_keyframe = TRUE;
8843 for (i = stream->stss_index; i < n_sample_syncs; i++) {
8844 /* note that the first sample is index 1, not 0 */
8847 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stss);
8849 if (G_LIKELY (index > 0 && index <= n_samples)) {
8851 samples[index].keyframe = TRUE;
8852 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
8853 /* and exit if we have enough samples */
8854 if (G_UNLIKELY (index >= n)) {
8861 stream->stss_index = i;
8864 /* stps marks partial sync frames like open GOP I-Frames */
8865 if (stream->stps_present == TRUE) {
8866 guint32 n_sample_partial_syncs;
8868 n_sample_partial_syncs = stream->n_sample_partial_syncs;
8870 /* if there are no entries, the stss table contains the real
8872 if (n_sample_partial_syncs) {
8873 for (i = stream->stps_index; i < n_sample_partial_syncs; i++) {
8874 /* note that the first sample is index 1, not 0 */
8877 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stps);
8879 if (G_LIKELY (index > 0 && index <= n_samples)) {
8881 samples[index].keyframe = TRUE;
8882 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
8883 /* and exit if we have enough samples */
8884 if (G_UNLIKELY (index >= n)) {
8891 stream->stps_index = i;
8895 /* no stss, all samples are keyframes */
8896 stream->all_keyframe = TRUE;
8897 GST_DEBUG_OBJECT (qtdemux, "setting all keyframes");
8902 /* composition time to sample */
8903 if (stream->ctts_present == TRUE) {
8904 guint32 n_composition_times;
8906 gint32 ctts_soffset;
8908 /* Fill in the pts_offsets */
8910 n_composition_times = stream->n_composition_times;
8912 for (i = stream->ctts_index; i < n_composition_times; i++) {
8913 if (stream->ctts_sample_index >= stream->ctts_count
8914 || !stream->ctts_sample_index) {
8915 stream->ctts_count =
8916 gst_byte_reader_get_uint32_be_unchecked (&stream->ctts);
8917 stream->ctts_soffset =
8918 gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
8919 stream->ctts_sample_index = 0;
8922 ctts_count = stream->ctts_count;
8923 ctts_soffset = stream->ctts_soffset;
8925 for (j = stream->ctts_sample_index; j < ctts_count; j++) {
8926 cur->pts_offset = ctts_soffset;
8929 if (G_UNLIKELY (cur > last)) {
8931 stream->ctts_sample_index = j + 1;
8935 stream->ctts_sample_index = 0;
8936 stream->ctts_index++;
8940 stream->stbl_index = n;
8941 /* if index has been completely parsed, free data that is no-longer needed */
8942 if (n + 1 == stream->n_samples) {
8943 gst_qtdemux_stbl_free (stream);
8944 GST_DEBUG_OBJECT (qtdemux, "parsed all available samples;");
8945 if (qtdemux->pullbased) {
8946 GST_DEBUG_OBJECT (qtdemux, "checking for more samples");
8947 while (n + 1 == stream->n_samples)
8948 if (qtdemux_add_fragmented_samples (qtdemux) != GST_FLOW_OK)
8952 GST_OBJECT_UNLOCK (qtdemux);
8959 GST_LOG_OBJECT (qtdemux,
8960 "Tried to parse up to sample %u but this sample has already been parsed",
8962 /* if fragmented, there may be more */
8963 if (qtdemux->fragmented && n == stream->stbl_index)
8965 GST_OBJECT_UNLOCK (qtdemux);
8971 GST_LOG_OBJECT (qtdemux,
8972 "Tried to parse up to sample %u but there are only %u samples", n + 1,
8974 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8975 (_("This file is corrupt and cannot be played.")), (NULL));
8980 GST_OBJECT_UNLOCK (qtdemux);
8981 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8982 (_("This file is corrupt and cannot be played.")), (NULL));
8987 /* collect all segment info for @stream.
8990 qtdemux_parse_segments (GstQTDemux * qtdemux, QtDemuxStream * stream,
8994 /* accept edts if they contain gaps at start and there is only
8995 * one media segment */
8996 gboolean allow_pushbased_edts = TRUE;
8997 gint media_segments_count = 0;
8999 /* parse and prepare segment info from the edit list */
9000 GST_DEBUG_OBJECT (qtdemux, "looking for edit list container");
9001 stream->n_segments = 0;
9002 stream->segments = NULL;
9003 if ((edts = qtdemux_tree_get_child_by_type (trak, FOURCC_edts))) {
9006 gint i, count, entry_size;
9009 const guint8 *buffer;
9013 GST_DEBUG_OBJECT (qtdemux, "looking for edit list");
9014 if (!(elst = qtdemux_tree_get_child_by_type (edts, FOURCC_elst)))
9017 buffer = elst->data;
9019 size = QT_UINT32 (buffer);
9020 /* version, flags, n_segments */
9022 GST_WARNING_OBJECT (qtdemux, "Invalid edit list");
9025 version = QT_UINT8 (buffer + 8);
9026 entry_size = (version == 1) ? 20 : 12;
9028 n_segments = QT_UINT32 (buffer + 12);
9030 if (n_segments > 100000 || size < 16 + n_segments * entry_size) {
9031 GST_WARNING_OBJECT (qtdemux, "Invalid edit list");
9035 /* we might allocate a bit too much, at least allocate 1 segment */
9036 stream->segments = g_new (QtDemuxSegment, MAX (n_segments, 1));
9038 /* segments always start from 0 */
9043 for (i = 0; i < n_segments; i++) {
9046 gboolean time_valid = TRUE;
9047 QtDemuxSegment *segment;
9049 GstClockTime media_start = GST_CLOCK_TIME_NONE;
9052 media_time = QT_UINT64 (buffer + 8);
9053 duration = QT_UINT64 (buffer);
9054 if (media_time == G_MAXUINT64)
9057 media_time = QT_UINT32 (buffer + 4);
9058 duration = QT_UINT32 (buffer);
9059 if (media_time == G_MAXUINT32)
9064 media_start = QTSTREAMTIME_TO_GSTTIME (stream, media_time);
9066 segment = &stream->segments[count++];
9068 /* time and duration expressed in global timescale */
9069 segment->time = stime;
9070 /* add non scaled values so we don't cause roundoff errors */
9071 if (duration || media_start == GST_CLOCK_TIME_NONE) {
9073 stime = QTTIME_TO_GSTTIME (qtdemux, time);
9074 segment->duration = stime - segment->time;
9076 /* zero duration does not imply media_start == media_stop
9077 * but, only specify media_start.*/
9078 stime = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
9079 if (GST_CLOCK_TIME_IS_VALID (stime) && time_valid
9080 && stime >= media_start) {
9081 segment->duration = stime - media_start;
9083 segment->duration = GST_CLOCK_TIME_NONE;
9086 segment->stop_time = stime;
9088 segment->trak_media_start = media_time;
9089 /* media_time expressed in stream timescale */
9091 segment->media_start = media_start;
9092 segment->media_stop = segment->media_start + segment->duration;
9093 media_segments_count++;
9095 segment->media_start = GST_CLOCK_TIME_NONE;
9096 segment->media_stop = GST_CLOCK_TIME_NONE;
9098 rate_int = QT_UINT32 (buffer + ((version == 1) ? 16 : 8));
9100 if (rate_int <= 1) {
9101 /* 0 is not allowed, some programs write 1 instead of the floating point
9103 GST_WARNING_OBJECT (qtdemux, "found suspicious rate %" G_GUINT32_FORMAT,
9107 segment->rate = rate_int / 65536.0;
9110 GST_DEBUG_OBJECT (qtdemux, "created segment %d time %" GST_TIME_FORMAT
9111 ", duration %" GST_TIME_FORMAT ", media_start %" GST_TIME_FORMAT
9112 " (%" G_GUINT64_FORMAT ") , media_stop %" GST_TIME_FORMAT
9113 " stop_time %" GST_TIME_FORMAT " rate %g, (%d) timescale %u",
9114 i, GST_TIME_ARGS (segment->time),
9115 GST_TIME_ARGS (segment->duration),
9116 GST_TIME_ARGS (segment->media_start), media_time,
9117 GST_TIME_ARGS (segment->media_stop),
9118 GST_TIME_ARGS (segment->stop_time), segment->rate, rate_int,
9120 if (segment->stop_time > qtdemux->segment.stop) {
9121 GST_WARNING_OBJECT (qtdemux, "Segment %d "
9122 " extends to %" GST_TIME_FORMAT
9123 " past the end of the file duration %" GST_TIME_FORMAT
9124 " it will be truncated", i, GST_TIME_ARGS (segment->stop_time),
9125 GST_TIME_ARGS (qtdemux->segment.stop));
9126 qtdemux->segment.stop = segment->stop_time;
9129 buffer += entry_size;
9131 GST_DEBUG_OBJECT (qtdemux, "found %d segments", count);
9132 stream->n_segments = count;
9133 if (media_segments_count != 1)
9134 allow_pushbased_edts = FALSE;
9138 /* push based does not handle segments, so act accordingly here,
9139 * and warn if applicable */
9140 if (!qtdemux->pullbased && !allow_pushbased_edts) {
9141 GST_WARNING_OBJECT (qtdemux, "streaming; discarding edit list segments");
9142 /* remove and use default one below, we stream like it anyway */
9143 g_free (stream->segments);
9144 stream->segments = NULL;
9145 stream->n_segments = 0;
9148 /* no segments, create one to play the complete trak */
9149 if (stream->n_segments == 0) {
9150 GstClockTime stream_duration =
9151 QTSTREAMTIME_TO_GSTTIME (stream, stream->duration);
9153 if (stream->segments == NULL)
9154 stream->segments = g_new (QtDemuxSegment, 1);
9156 /* represent unknown our way */
9157 if (stream_duration == 0)
9158 stream_duration = GST_CLOCK_TIME_NONE;
9160 stream->segments[0].time = 0;
9161 stream->segments[0].stop_time = stream_duration;
9162 stream->segments[0].duration = stream_duration;
9163 stream->segments[0].media_start = 0;
9164 stream->segments[0].media_stop = stream_duration;
9165 stream->segments[0].rate = 1.0;
9166 stream->segments[0].trak_media_start = 0;
9168 GST_DEBUG_OBJECT (qtdemux, "created dummy segment %" GST_TIME_FORMAT,
9169 GST_TIME_ARGS (stream_duration));
9170 stream->n_segments = 1;
9171 stream->dummy_segment = TRUE;
9173 GST_DEBUG_OBJECT (qtdemux, "using %d segments", stream->n_segments);
9179 * Parses the stsd atom of a svq3 trak looking for
9180 * the SMI and gama atoms.
9183 qtdemux_parse_svq3_stsd_data (GstQTDemux * qtdemux,
9184 const guint8 * stsd_entry_data, const guint8 ** gamma, GstBuffer ** seqh)
9186 const guint8 *_gamma = NULL;
9187 GstBuffer *_seqh = NULL;
9188 const guint8 *stsd_data = stsd_entry_data;
9189 guint32 length = QT_UINT32 (stsd_data);
9193 GST_WARNING_OBJECT (qtdemux, "stsd too short");
9199 version = QT_UINT16 (stsd_data);
9204 while (length > 8) {
9205 guint32 fourcc, size;
9207 size = QT_UINT32 (stsd_data);
9208 fourcc = QT_FOURCC (stsd_data + 4);
9209 data = stsd_data + 8;
9212 GST_WARNING_OBJECT (qtdemux, "Atom of size 0 found, aborting "
9213 "svq3 atom parsing");
9222 GST_WARNING_OBJECT (qtdemux, "Unexpected size %" G_GUINT32_FORMAT
9223 " for gama atom, expected 12", size);
9228 if (size > 16 && QT_FOURCC (data) == FOURCC_SEQH) {
9230 if (_seqh != NULL) {
9231 GST_WARNING_OBJECT (qtdemux, "Unexpected second SEQH SMI atom "
9232 " found, ignoring");
9234 seqh_size = QT_UINT32 (data + 4);
9235 if (seqh_size > 0) {
9236 _seqh = gst_buffer_new_and_alloc (seqh_size);
9237 gst_buffer_fill (_seqh, 0, data + 8, seqh_size);
9244 GST_WARNING_OBJECT (qtdemux, "Unhandled atom %" GST_FOURCC_FORMAT
9245 " in SVQ3 entry in stsd atom", GST_FOURCC_ARGS (fourcc));
9249 if (size <= length) {
9255 GST_WARNING_OBJECT (qtdemux, "SVQ3 entry too short in stsd atom");
9258 GST_WARNING_OBJECT (qtdemux, "Unexpected version for SVQ3 entry %"
9259 G_GUINT16_FORMAT, version);
9270 gst_buffer_unref (_seqh);
9275 qtdemux_get_rtsp_uri_from_hndl (GstQTDemux * qtdemux, GNode * minf)
9282 * Get 'dinf', to get its child 'dref', that might contain a 'hndl'
9283 * atom that might contain a 'data' atom with the rtsp uri.
9284 * This case was reported in bug #597497, some info about
9285 * the hndl atom can be found in TN1195
9287 dinf = qtdemux_tree_get_child_by_type (minf, FOURCC_dinf);
9288 GST_DEBUG_OBJECT (qtdemux, "Trying to obtain rtsp URI for stream trak");
9291 guint32 dref_num_entries = 0;
9292 if (qtdemux_tree_get_child_by_type_full (dinf, FOURCC_dref, &dref) &&
9293 gst_byte_reader_skip (&dref, 4) &&
9294 gst_byte_reader_get_uint32_be (&dref, &dref_num_entries)) {
9297 /* search dref entries for hndl atom */
9298 for (i = 0; i < dref_num_entries; i++) {
9299 guint32 size = 0, type;
9300 guint8 string_len = 0;
9301 if (gst_byte_reader_get_uint32_be (&dref, &size) &&
9302 qt_atom_parser_get_fourcc (&dref, &type)) {
9303 if (type == FOURCC_hndl) {
9304 GST_DEBUG_OBJECT (qtdemux, "Found hndl atom");
9306 /* skip data reference handle bytes and the
9307 * following pascal string and some extra 4
9308 * bytes I have no idea what are */
9309 if (!gst_byte_reader_skip (&dref, 4) ||
9310 !gst_byte_reader_get_uint8 (&dref, &string_len) ||
9311 !gst_byte_reader_skip (&dref, string_len + 4)) {
9312 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl atom");
9316 /* iterate over the atoms to find the data atom */
9317 while (gst_byte_reader_get_remaining (&dref) >= 8) {
9321 if (gst_byte_reader_get_uint32_be (&dref, &atom_size) &&
9322 qt_atom_parser_get_fourcc (&dref, &atom_type)) {
9323 if (atom_type == FOURCC_data) {
9324 const guint8 *uri_aux = NULL;
9326 /* found the data atom that might contain the rtsp uri */
9327 GST_DEBUG_OBJECT (qtdemux, "Found data atom inside "
9328 "hndl atom, interpreting it as an URI");
9329 if (gst_byte_reader_peek_data (&dref, atom_size - 8,
9331 if (g_strstr_len ((gchar *) uri_aux, 7, "rtsp://") != NULL)
9332 uri = g_strndup ((gchar *) uri_aux, atom_size - 8);
9334 GST_WARNING_OBJECT (qtdemux, "Data atom in hndl atom "
9335 "didn't contain a rtsp address");
9337 GST_WARNING_OBJECT (qtdemux, "Failed to get the data "
9342 /* skipping to the next entry */
9343 if (!gst_byte_reader_skip (&dref, atom_size - 8))
9346 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl child "
9353 /* skip to the next entry */
9354 if (!gst_byte_reader_skip (&dref, size - 8))
9357 GST_WARNING_OBJECT (qtdemux, "Error parsing dref atom");
9360 GST_DEBUG_OBJECT (qtdemux, "Finished parsing dref atom");
9366 #define AMR_NB_ALL_MODES 0x81ff
9367 #define AMR_WB_ALL_MODES 0x83ff
9369 qtdemux_parse_amr_bitrate (GstBuffer * buf, gboolean wb)
9371 /* The 'damr' atom is of the form:
9373 * | vendor | decoder_ver | mode_set | mode_change_period | frames/sample |
9374 * 32 b 8 b 16 b 8 b 8 b
9376 * The highest set bit of the first 7 (AMR-NB) or 8 (AMR-WB) bits of mode_set
9377 * represents the highest mode used in the stream (and thus the maximum
9378 * bitrate), with a couple of special cases as seen below.
9381 /* Map of frame type ID -> bitrate */
9382 static const guint nb_bitrates[] = {
9383 4750, 5150, 5900, 6700, 7400, 7950, 10200, 12200
9385 static const guint wb_bitrates[] = {
9386 6600, 8850, 12650, 14250, 15850, 18250, 19850, 23050, 23850
9392 gst_buffer_map (buf, &map, GST_MAP_READ);
9394 if (map.size != 0x11) {
9395 GST_DEBUG ("Atom should have size 0x11, not %" G_GSIZE_FORMAT, map.size);
9399 if (QT_FOURCC (map.data + 4) != FOURCC_damr) {
9400 GST_DEBUG ("Unknown atom in %" GST_FOURCC_FORMAT,
9401 GST_FOURCC_ARGS (QT_UINT32 (map.data + 4)));
9405 mode_set = QT_UINT16 (map.data + 13);
9407 if (mode_set == (wb ? AMR_WB_ALL_MODES : AMR_NB_ALL_MODES))
9408 max_mode = 7 + (wb ? 1 : 0);
9410 /* AMR-NB modes fo from 0-7, and AMR-WB modes go from 0-8 */
9411 max_mode = g_bit_nth_msf ((gulong) mode_set & (wb ? 0x1ff : 0xff), -1);
9413 if (max_mode == -1) {
9414 GST_DEBUG ("No mode indication was found (mode set) = %x",
9419 gst_buffer_unmap (buf, &map);
9420 return wb ? wb_bitrates[max_mode] : nb_bitrates[max_mode];
9423 gst_buffer_unmap (buf, &map);
9428 qtdemux_parse_transformation_matrix (GstQTDemux * qtdemux,
9429 GstByteReader * reader, guint32 * matrix, const gchar * atom)
9432 * 9 values of 32 bits (fixed point 16.16, except 2 5 and 8 that are 2.30)
9438 if (gst_byte_reader_get_remaining (reader) < 36)
9441 matrix[0] = gst_byte_reader_get_uint32_be_unchecked (reader);
9442 matrix[1] = gst_byte_reader_get_uint32_be_unchecked (reader);
9443 matrix[2] = gst_byte_reader_get_uint32_be_unchecked (reader);
9444 matrix[3] = gst_byte_reader_get_uint32_be_unchecked (reader);
9445 matrix[4] = gst_byte_reader_get_uint32_be_unchecked (reader);
9446 matrix[5] = gst_byte_reader_get_uint32_be_unchecked (reader);
9447 matrix[6] = gst_byte_reader_get_uint32_be_unchecked (reader);
9448 matrix[7] = gst_byte_reader_get_uint32_be_unchecked (reader);
9449 matrix[8] = gst_byte_reader_get_uint32_be_unchecked (reader);
9451 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix from atom %s", atom);
9452 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[0] >> 16,
9453 matrix[0] & 0xFFFF, matrix[1] >> 16, matrix[1] & 0xFF, matrix[2] >> 16,
9455 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[3] >> 16,
9456 matrix[3] & 0xFFFF, matrix[4] >> 16, matrix[4] & 0xFF, matrix[5] >> 16,
9458 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[6] >> 16,
9459 matrix[6] & 0xFFFF, matrix[7] >> 16, matrix[7] & 0xFF, matrix[8] >> 16,
9466 qtdemux_inspect_transformation_matrix (GstQTDemux * qtdemux,
9467 QtDemuxStream * stream, guint32 * matrix, GstTagList ** taglist)
9474 * This macro will only compare value abdegh, it expects cfi to have already
9477 #define QTCHECK_MATRIX(m,a,b,d,e) ((m)[0] == (a << 16) && (m)[1] == (b << 16) && \
9478 (m)[3] == (d << 16) && (m)[4] == (e << 16))
9480 /* only handle the cases where the last column has standard values */
9481 if (matrix[2] == 0 && matrix[5] == 0 && matrix[8] == 1 << 30) {
9482 const gchar *rotation_tag = NULL;
9484 /* no rotation needed */
9485 if (QTCHECK_MATRIX (matrix, 1, 0, 0, 1)) {
9487 } else if (QTCHECK_MATRIX (matrix, 0, 1, G_MAXUINT16, 0)) {
9488 rotation_tag = "rotate-90";
9489 } else if (QTCHECK_MATRIX (matrix, G_MAXUINT16, 0, 0, G_MAXUINT16)) {
9490 rotation_tag = "rotate-180";
9491 } else if (QTCHECK_MATRIX (matrix, 0, G_MAXUINT16, 1, 0)) {
9492 rotation_tag = "rotate-270";
9494 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
9497 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix rotation %s",
9499 if (rotation_tag != NULL) {
9500 if (*taglist == NULL)
9501 *taglist = gst_tag_list_new_empty ();
9502 gst_tag_list_add (*taglist, GST_TAG_MERGE_REPLACE,
9503 GST_TAG_IMAGE_ORIENTATION, rotation_tag, NULL);
9506 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
9510 /* Parses the boxes defined in ISO/IEC 14496-12 that enable support for
9511 * protected streams (sinf, frma, schm and schi); if the protection scheme is
9512 * Common Encryption (cenc), the function will also parse the tenc box (defined
9513 * in ISO/IEC 23001-7). @container points to the node that contains these boxes
9514 * (typically an enc[v|a|t|s] sample entry); the function will set
9515 * @original_fmt to the fourcc of the original unencrypted stream format.
9516 * Returns TRUE if successful; FALSE otherwise. */
9518 qtdemux_parse_protection_scheme_info (GstQTDemux * qtdemux,
9519 QtDemuxStream * stream, GNode * container, guint32 * original_fmt)
9526 g_return_val_if_fail (qtdemux != NULL, FALSE);
9527 g_return_val_if_fail (stream != NULL, FALSE);
9528 g_return_val_if_fail (container != NULL, FALSE);
9529 g_return_val_if_fail (original_fmt != NULL, FALSE);
9531 sinf = qtdemux_tree_get_child_by_type (container, FOURCC_sinf);
9532 if (G_UNLIKELY (!sinf)) {
9533 if (stream->protection_scheme_type == FOURCC_cenc) {
9534 GST_ERROR_OBJECT (qtdemux, "sinf box does not contain schi box, which is "
9535 "mandatory for Common Encryption");
9541 frma = qtdemux_tree_get_child_by_type (sinf, FOURCC_frma);
9542 if (G_UNLIKELY (!frma)) {
9543 GST_ERROR_OBJECT (qtdemux, "sinf box does not contain mandatory frma box");
9547 *original_fmt = QT_FOURCC ((const guint8 *) frma->data + 8);
9548 GST_DEBUG_OBJECT (qtdemux, "original stream format: '%" GST_FOURCC_FORMAT "'",
9549 GST_FOURCC_ARGS (*original_fmt));
9551 schm = qtdemux_tree_get_child_by_type (sinf, FOURCC_schm);
9553 GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schm box");
9556 stream->protection_scheme_type = QT_FOURCC ((const guint8 *) schm->data + 12);
9557 stream->protection_scheme_version =
9558 QT_UINT32 ((const guint8 *) schm->data + 16);
9560 GST_DEBUG_OBJECT (qtdemux,
9561 "protection_scheme_type: %" GST_FOURCC_FORMAT ", "
9562 "protection_scheme_version: %#010x",
9563 GST_FOURCC_ARGS (stream->protection_scheme_type),
9564 stream->protection_scheme_version);
9566 schi = qtdemux_tree_get_child_by_type (sinf, FOURCC_schi);
9568 GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schi box");
9571 if (stream->protection_scheme_type == FOURCC_cenc) {
9572 QtDemuxCencSampleSetInfo *info;
9574 const guint8 *tenc_data;
9575 guint32 isEncrypted;
9577 const guint8 *default_kid;
9580 if (G_UNLIKELY (!stream->protection_scheme_info))
9581 stream->protection_scheme_info =
9582 g_malloc0 (sizeof (QtDemuxCencSampleSetInfo));
9584 info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
9586 tenc = qtdemux_tree_get_child_by_type (schi, FOURCC_tenc);
9588 GST_ERROR_OBJECT (qtdemux, "schi box does not contain tenc box, "
9589 "which is mandatory for Common Encryption");
9592 tenc_data = (const guint8 *) tenc->data + 12;
9593 isEncrypted = QT_UINT24 (tenc_data);
9594 iv_size = QT_UINT8 (tenc_data + 3);
9595 default_kid = (tenc_data + 4);
9596 kid_buf = gst_buffer_new_allocate (NULL, 16, NULL);
9597 gst_buffer_fill (kid_buf, 0, default_kid, 16);
9598 if (info->default_properties)
9599 gst_structure_free (info->default_properties);
9600 info->default_properties =
9601 gst_structure_new ("application/x-cenc",
9602 "iv_size", G_TYPE_UINT, iv_size,
9603 "encrypted", G_TYPE_BOOLEAN, (isEncrypted == 1),
9604 "kid", GST_TYPE_BUFFER, kid_buf, NULL);
9605 GST_DEBUG_OBJECT (qtdemux, "default sample properties: "
9606 "is_encrypted=%u, iv_size=%u", isEncrypted, iv_size);
9607 gst_buffer_unref (kid_buf);
9613 * With each track we associate a new QtDemuxStream that contains all the info
9615 * traks that do not decode to something (like strm traks) will not have a pad.
9618 qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
9635 QtDemuxStream *stream = NULL;
9636 gboolean new_stream = FALSE;
9637 const guint8 *stsd_data;
9638 const guint8 *stsd_entry_data;
9639 guint remaining_stsd_len;
9640 guint stsd_entry_count;
9642 guint16 lang_code; /* quicktime lang code or packed iso code */
9644 guint32 tkhd_flags = 0;
9645 guint8 tkhd_version = 0;
9646 guint32 w = 0, h = 0;
9647 guint value_size, stsd_len, len;
9651 GST_DEBUG_OBJECT (qtdemux, "parse_trak");
9653 if (!qtdemux_tree_get_child_by_type_full (trak, FOURCC_tkhd, &tkhd)
9654 || !gst_byte_reader_get_uint8 (&tkhd, &tkhd_version)
9655 || !gst_byte_reader_get_uint24_be (&tkhd, &tkhd_flags))
9658 /* pick between 64 or 32 bits */
9659 value_size = tkhd_version == 1 ? 8 : 4;
9660 if (!gst_byte_reader_skip (&tkhd, value_size * 2) ||
9661 !gst_byte_reader_get_uint32_be (&tkhd, &track_id))
9664 if (!qtdemux->got_moov) {
9665 if (qtdemux_find_stream (qtdemux, track_id))
9666 goto existing_stream;
9667 stream = _create_stream ();
9668 stream->track_id = track_id;
9671 stream = qtdemux_find_stream (qtdemux, track_id);
9673 GST_WARNING_OBJECT (qtdemux, "Stream not found, going to ignore it");
9677 /* reset reused stream */
9678 gst_qtdemux_stream_reset (qtdemux, stream);
9680 /* need defaults for fragments */
9681 qtdemux_parse_trex (qtdemux, stream, &dummy, &dummy, &dummy);
9683 if ((tkhd_flags & 1) == 0)
9684 stream->disabled = TRUE;
9686 GST_LOG_OBJECT (qtdemux, "track[tkhd] version/flags/id: 0x%02x/%06x/%u",
9687 tkhd_version, tkhd_flags, stream->track_id);
9689 if (!(mdia = qtdemux_tree_get_child_by_type (trak, FOURCC_mdia)))
9692 if (!(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mdhd))) {
9693 /* be nice for some crooked mjp2 files that use mhdr for mdhd */
9694 if (qtdemux->major_brand != FOURCC_mjp2 ||
9695 !(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mhdr)))
9699 len = QT_UINT32 ((guint8 *) mdhd->data);
9700 version = QT_UINT32 ((guint8 *) mdhd->data + 8);
9701 GST_LOG_OBJECT (qtdemux, "track version/flags: %08x", version);
9702 if (version == 0x01000000) {
9705 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 28);
9706 stream->duration = QT_UINT64 ((guint8 *) mdhd->data + 32);
9707 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 36);
9711 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 20);
9712 stream->duration = QT_UINT32 ((guint8 *) mdhd->data + 24);
9713 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 28);
9716 if (lang_code < 0x400) {
9717 qtdemux_lang_map_qt_code_to_iso (stream->lang_id, lang_code);
9718 } else if (lang_code == 0x7fff) {
9719 stream->lang_id[0] = 0; /* unspecified */
9721 stream->lang_id[0] = 0x60 + ((lang_code >> 10) & 0x1F);
9722 stream->lang_id[1] = 0x60 + ((lang_code >> 5) & 0x1F);
9723 stream->lang_id[2] = 0x60 + (lang_code & 0x1F);
9724 stream->lang_id[3] = 0;
9727 GST_LOG_OBJECT (qtdemux, "track timescale: %" G_GUINT32_FORMAT,
9729 GST_LOG_OBJECT (qtdemux, "track duration: %" G_GUINT64_FORMAT,
9731 GST_LOG_OBJECT (qtdemux, "track language code/id: 0x%04x/%s",
9732 lang_code, stream->lang_id);
9734 if (G_UNLIKELY (stream->timescale == 0 || qtdemux->timescale == 0))
9737 if ((tref = qtdemux_tree_get_child_by_type (trak, FOURCC_tref))) {
9738 /* chapters track reference */
9739 GNode *chap = qtdemux_tree_get_child_by_type (tref, FOURCC_chap);
9741 gsize length = GST_READ_UINT32_BE (chap->data);
9742 if (qtdemux->chapters_track_id)
9743 GST_FIXME_OBJECT (qtdemux, "Multiple CHAP tracks");
9746 qtdemux->chapters_track_id =
9747 GST_READ_UINT32_BE ((gint8 *) chap->data + 8);
9752 /* fragmented files may have bogus duration in moov */
9753 if (!qtdemux->fragmented &&
9754 qtdemux->duration != G_MAXINT64 && stream->duration != G_MAXINT32) {
9755 guint64 tdur1, tdur2;
9757 /* don't overflow */
9758 tdur1 = stream->timescale * (guint64) qtdemux->duration;
9759 tdur2 = qtdemux->timescale * (guint64) stream->duration;
9762 * some of those trailers, nowadays, have prologue images that are
9763 * themselves video tracks as well. I haven't really found a way to
9764 * identify those yet, except for just looking at their duration. */
9765 if (tdur1 != 0 && (tdur2 * 10 / tdur1) < 2) {
9766 GST_WARNING_OBJECT (qtdemux,
9767 "Track shorter than 20%% (%" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT
9768 " vs. %" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT ") of the stream "
9769 "found, assuming preview image or something; skipping track",
9770 stream->duration, stream->timescale, qtdemux->duration,
9771 qtdemux->timescale);
9773 gst_qtdemux_stream_free (qtdemux, stream);
9778 if (!(hdlr = qtdemux_tree_get_child_by_type (mdia, FOURCC_hdlr)))
9781 GST_LOG_OBJECT (qtdemux, "track type: %" GST_FOURCC_FORMAT,
9782 GST_FOURCC_ARGS (QT_FOURCC ((guint8 *) hdlr->data + 12)));
9784 len = QT_UINT32 ((guint8 *) hdlr->data);
9786 stream->subtype = QT_FOURCC ((guint8 *) hdlr->data + 16);
9787 GST_LOG_OBJECT (qtdemux, "track subtype: %" GST_FOURCC_FORMAT,
9788 GST_FOURCC_ARGS (stream->subtype));
9790 if (!(minf = qtdemux_tree_get_child_by_type (mdia, FOURCC_minf)))
9793 if (!(stbl = qtdemux_tree_get_child_by_type (minf, FOURCC_stbl)))
9796 /*parse svmi header if existing */
9797 svmi = qtdemux_tree_get_child_by_type (stbl, FOURCC_svmi);
9799 len = QT_UINT32 ((guint8 *) svmi->data);
9800 version = QT_UINT32 ((guint8 *) svmi->data + 8);
9802 GstVideoMultiviewMode mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
9803 GstVideoMultiviewFlags flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
9804 guint8 frame_type, frame_layout;
9806 /* MPEG-A stereo video */
9807 if (qtdemux->major_brand == FOURCC_ss02)
9808 flags |= GST_VIDEO_MULTIVIEW_FLAGS_MIXED_MONO;
9810 frame_type = QT_UINT8 ((guint8 *) svmi->data + 12);
9811 frame_layout = QT_UINT8 ((guint8 *) svmi->data + 13) & 0x01;
9812 switch (frame_type) {
9814 mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
9817 mode = GST_VIDEO_MULTIVIEW_MODE_ROW_INTERLEAVED;
9820 mode = GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME;
9823 /* mode 3 is primary/secondary view sequence, ie
9824 * left/right views in separate tracks. See section 7.2
9825 * of ISO/IEC 23000-11:2009 */
9826 GST_FIXME_OBJECT (qtdemux,
9827 "Implement stereo video in separate streams");
9830 if ((frame_layout & 0x1) == 0)
9831 flags |= GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
9833 GST_LOG_OBJECT (qtdemux,
9834 "StereoVideo: composition type: %u, is_left_first: %u",
9835 frame_type, frame_layout);
9836 stream->multiview_mode = mode;
9837 stream->multiview_flags = flags;
9841 /* parse rest of tkhd */
9842 if (stream->subtype == FOURCC_vide) {
9845 /* version 1 uses some 64-bit ints */
9846 if (!gst_byte_reader_skip (&tkhd, 20 + value_size))
9849 if (!qtdemux_parse_transformation_matrix (qtdemux, &tkhd, matrix, "tkhd"))
9852 if (!gst_byte_reader_get_uint32_be (&tkhd, &w)
9853 || !gst_byte_reader_get_uint32_be (&tkhd, &h))
9856 qtdemux_inspect_transformation_matrix (qtdemux, stream, matrix,
9857 &stream->stream_tags);
9861 if (!(stsd = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsd)))
9863 stsd_data = (const guint8 *) stsd->data;
9865 /* stsd should at least have one entry */
9866 stsd_len = QT_UINT32 (stsd_data);
9867 if (stsd_len < 24) {
9868 /* .. but skip stream with empty stsd produced by some Vivotek cameras */
9869 if (stream->subtype == FOURCC_vivo) {
9871 gst_qtdemux_stream_free (qtdemux, stream);
9878 stream->stsd_entries_length = stsd_entry_count = QT_UINT32 (stsd_data + 12);
9879 stream->stsd_entries = g_new0 (QtDemuxStreamStsdEntry, stsd_entry_count);
9880 GST_LOG_OBJECT (qtdemux, "stsd len: %d", stsd_len);
9881 GST_LOG_OBJECT (qtdemux, "stsd entry count: %u", stsd_entry_count);
9883 stsd_entry_data = stsd_data + 16;
9884 remaining_stsd_len = stsd_len - 16;
9885 for (stsd_index = 0; stsd_index < stsd_entry_count; stsd_index++) {
9887 gchar *codec = NULL;
9888 QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[stsd_index];
9890 /* and that entry should fit within stsd */
9891 len = QT_UINT32 (stsd_entry_data);
9892 if (len > remaining_stsd_len)
9895 entry->fourcc = fourcc = QT_FOURCC (stsd_entry_data + 4);
9896 GST_LOG_OBJECT (qtdemux, "stsd type: %" GST_FOURCC_FORMAT,
9897 GST_FOURCC_ARGS (entry->fourcc));
9898 GST_LOG_OBJECT (qtdemux, "stsd type len: %d", len);
9900 if ((fourcc == FOURCC_drms) || (fourcc == FOURCC_drmi))
9901 goto error_encrypted;
9903 if (fourcc == FOURCC_encv || fourcc == FOURCC_enca) {
9904 /* FIXME this looks wrong, there might be multiple children
9905 * with the same type */
9906 GNode *enc = qtdemux_tree_get_child_by_type (stsd, fourcc);
9907 stream->protected = TRUE;
9908 if (!qtdemux_parse_protection_scheme_info (qtdemux, stream, enc, &fourcc))
9909 GST_ERROR_OBJECT (qtdemux, "Failed to parse protection scheme info");
9912 if (stream->subtype == FOURCC_vide) {
9917 gint depth, palette_size, palette_count;
9918 guint32 *palette_data = NULL;
9920 entry->sampled = TRUE;
9922 stream->display_width = w >> 16;
9923 stream->display_height = h >> 16;
9926 if (len < 86) /* TODO verify */
9929 entry->width = QT_UINT16 (stsd_entry_data + offset + 16);
9930 entry->height = QT_UINT16 (stsd_entry_data + offset + 18);
9931 entry->fps_n = 0; /* this is filled in later */
9932 entry->fps_d = 0; /* this is filled in later */
9933 entry->bits_per_sample = QT_UINT16 (stsd_entry_data + offset + 66);
9934 entry->color_table_id = QT_UINT16 (stsd_entry_data + offset + 68);
9936 /* if color_table_id is 0, ctab atom must follow; however some files
9937 * produced by TMPEGEnc have color_table_id = 0 and no ctab atom, so
9938 * if color table is not present we'll correct the value */
9939 if (entry->color_table_id == 0 &&
9941 || QT_FOURCC (stsd_entry_data + offset + 70) != FOURCC_ctab)) {
9942 entry->color_table_id = -1;
9945 GST_LOG_OBJECT (qtdemux, "width %d, height %d, bps %d, color table id %d",
9946 entry->width, entry->height, entry->bits_per_sample,
9947 entry->color_table_id);
9949 depth = entry->bits_per_sample;
9951 /* more than 32 bits means grayscale */
9952 gray = (depth > 32);
9953 /* low 32 bits specify the depth */
9956 /* different number of palette entries is determined by depth. */
9958 if ((depth == 1) || (depth == 2) || (depth == 4) || (depth == 8))
9959 palette_count = (1 << depth);
9960 palette_size = palette_count * 4;
9962 if (entry->color_table_id) {
9963 switch (palette_count) {
9967 palette_data = g_memdup (ff_qt_default_palette_2, palette_size);
9970 palette_data = g_memdup (ff_qt_default_palette_4, palette_size);
9975 g_memdup (ff_qt_grayscale_palette_16, palette_size);
9977 palette_data = g_memdup (ff_qt_default_palette_16, palette_size);
9982 g_memdup (ff_qt_grayscale_palette_256, palette_size);
9984 palette_data = g_memdup (ff_qt_default_palette_256, palette_size);
9987 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
9988 (_("The video in this file might not play correctly.")),
9989 ("unsupported palette depth %d", depth));
9993 gint i, j, start, end;
9999 start = QT_UINT32 (stsd_entry_data + offset + 70);
10000 palette_count = QT_UINT16 (stsd_entry_data + offset + 74);
10001 end = QT_UINT16 (stsd_entry_data + offset + 76);
10003 GST_LOG_OBJECT (qtdemux, "start %d, end %d, palette_count %d",
10004 start, end, palette_count);
10011 if (len < 94 + (end - start) * 8)
10014 /* palette is always the same size */
10015 palette_data = g_malloc0 (256 * 4);
10016 palette_size = 256 * 4;
10018 for (j = 0, i = start; i <= end; j++, i++) {
10019 guint32 a, r, g, b;
10021 a = QT_UINT16 (stsd_entry_data + offset + 78 + (j * 8));
10022 r = QT_UINT16 (stsd_entry_data + offset + 80 + (j * 8));
10023 g = QT_UINT16 (stsd_entry_data + offset + 82 + (j * 8));
10024 b = QT_UINT16 (stsd_entry_data + offset + 84 + (j * 8));
10026 palette_data[i] = ((a & 0xff00) << 16) | ((r & 0xff00) << 8) |
10027 (g & 0xff00) | (b >> 8);
10032 gst_caps_unref (entry->caps);
10035 qtdemux_video_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
10037 if (G_UNLIKELY (!entry->caps)) {
10038 g_free (palette_data);
10039 goto unknown_stream;
10043 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
10044 GST_TAG_VIDEO_CODEC, codec, NULL);
10049 if (palette_data) {
10052 if (entry->rgb8_palette)
10053 gst_memory_unref (entry->rgb8_palette);
10054 entry->rgb8_palette = gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY,
10055 palette_data, palette_size, 0, palette_size, palette_data, g_free);
10057 s = gst_caps_get_structure (entry->caps, 0);
10059 /* non-raw video has a palette_data property. raw video has the palette as
10060 * an extra plane that we append to the output buffers before we push
10062 if (!gst_structure_has_name (s, "video/x-raw")) {
10063 GstBuffer *palette;
10065 palette = gst_buffer_new ();
10066 gst_buffer_append_memory (palette, entry->rgb8_palette);
10067 entry->rgb8_palette = NULL;
10069 gst_caps_set_simple (entry->caps, "palette_data",
10070 GST_TYPE_BUFFER, palette, NULL);
10071 gst_buffer_unref (palette);
10073 } else if (palette_count != 0) {
10074 GST_ELEMENT_WARNING (qtdemux, STREAM, NOT_IMPLEMENTED,
10075 (NULL), ("Unsupported palette depth %d", depth));
10078 GST_LOG_OBJECT (qtdemux, "frame count: %u",
10079 QT_UINT16 (stsd_entry_data + offset + 32));
10085 /* pick 'the' stsd child */
10086 mp4v = qtdemux_tree_get_child_by_index (stsd, stsd_index);
10087 if (!stream->protected) {
10088 if (QTDEMUX_TREE_NODE_FOURCC (mp4v) != fourcc) {
10092 if (QTDEMUX_TREE_NODE_FOURCC (mp4v) != FOURCC_encv) {
10098 esds = qtdemux_tree_get_child_by_type (mp4v, FOURCC_esds);
10099 pasp = qtdemux_tree_get_child_by_type (mp4v, FOURCC_pasp);
10100 colr = qtdemux_tree_get_child_by_type (mp4v, FOURCC_colr);
10101 fiel = qtdemux_tree_get_child_by_type (mp4v, FOURCC_fiel);
10105 const guint8 *pasp_data = (const guint8 *) pasp->data;
10106 gint len = QT_UINT32 (pasp_data);
10109 CUR_STREAM (stream)->par_w = QT_UINT32 (pasp_data + 8);
10110 CUR_STREAM (stream)->par_h = QT_UINT32 (pasp_data + 12);
10112 CUR_STREAM (stream)->par_w = 0;
10113 CUR_STREAM (stream)->par_h = 0;
10116 CUR_STREAM (stream)->par_w = 0;
10117 CUR_STREAM (stream)->par_h = 0;
10121 const guint8 *fiel_data = (const guint8 *) fiel->data;
10122 gint len = QT_UINT32 (fiel_data);
10125 CUR_STREAM (stream)->interlace_mode = GST_READ_UINT8 (fiel_data + 8);
10126 CUR_STREAM (stream)->field_order = GST_READ_UINT8 (fiel_data + 9);
10131 const guint8 *colr_data = (const guint8 *) colr->data;
10132 gint len = QT_UINT32 (colr_data);
10134 if (len == 19 || len == 18) {
10135 guint32 color_type = GST_READ_UINT32_LE (colr_data + 8);
10137 if (color_type == FOURCC_nclx || color_type == FOURCC_nclc) {
10138 guint16 primaries = GST_READ_UINT16_BE (colr_data + 12);
10139 guint16 transfer_function = GST_READ_UINT16_BE (colr_data + 14);
10140 guint16 matrix = GST_READ_UINT16_BE (colr_data + 16);
10141 gboolean full_range = len == 19 ? colr_data[17] >> 7 : FALSE;
10143 switch (primaries) {
10145 CUR_STREAM (stream)->colorimetry.primaries =
10146 GST_VIDEO_COLOR_PRIMARIES_BT709;
10149 CUR_STREAM (stream)->colorimetry.primaries =
10150 GST_VIDEO_COLOR_PRIMARIES_BT470BG;
10153 CUR_STREAM (stream)->colorimetry.primaries =
10154 GST_VIDEO_COLOR_PRIMARIES_SMPTE170M;
10157 CUR_STREAM (stream)->colorimetry.primaries =
10158 GST_VIDEO_COLOR_PRIMARIES_BT2020;
10164 switch (transfer_function) {
10166 CUR_STREAM (stream)->colorimetry.transfer =
10167 GST_VIDEO_TRANSFER_BT709;
10170 CUR_STREAM (stream)->colorimetry.transfer =
10171 GST_VIDEO_TRANSFER_SMPTE240M;
10179 CUR_STREAM (stream)->colorimetry.matrix =
10180 GST_VIDEO_COLOR_MATRIX_BT709;
10183 CUR_STREAM (stream)->colorimetry.matrix =
10184 GST_VIDEO_COLOR_MATRIX_BT601;
10187 CUR_STREAM (stream)->colorimetry.matrix =
10188 GST_VIDEO_COLOR_MATRIX_SMPTE240M;
10191 CUR_STREAM (stream)->colorimetry.matrix =
10192 GST_VIDEO_COLOR_MATRIX_BT2020;
10198 CUR_STREAM (stream)->colorimetry.range =
10199 full_range ? GST_VIDEO_COLOR_RANGE_0_255 :
10200 GST_VIDEO_COLOR_RANGE_16_235;
10202 GST_DEBUG_OBJECT (qtdemux, "Unsupported color type");
10205 GST_WARNING_OBJECT (qtdemux, "Invalid colr atom size");
10210 gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
10211 stream->stream_tags);
10218 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
10219 const guint8 *avc_data = stsd_entry_data + 0x56;
10222 while (len >= 0x8) {
10225 if (QT_UINT32 (avc_data) <= len)
10226 size = QT_UINT32 (avc_data) - 0x8;
10231 /* No real data, so break out */
10234 switch (QT_FOURCC (avc_data + 0x4)) {
10237 /* parse, if found */
10240 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
10242 /* First 4 bytes are the length of the atom, the next 4 bytes
10243 * are the fourcc, the next 1 byte is the version, and the
10244 * subsequent bytes are profile_tier_level structure like data. */
10245 gst_codec_utils_h264_caps_set_level_and_profile (entry->caps,
10246 avc_data + 8 + 1, size - 1);
10247 buf = gst_buffer_new_and_alloc (size);
10248 gst_buffer_fill (buf, 0, avc_data + 0x8, size);
10249 gst_caps_set_simple (entry->caps,
10250 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10251 gst_buffer_unref (buf);
10259 GST_DEBUG_OBJECT (qtdemux, "found strf codec_data in stsd");
10261 /* First 4 bytes are the length of the atom, the next 4 bytes
10262 * are the fourcc, next 40 bytes are BITMAPINFOHEADER,
10263 * next 1 byte is the version, and the
10264 * subsequent bytes are sequence parameter set like data. */
10266 size -= 40; /* we'll be skipping BITMAPINFOHEADER */
10268 gst_codec_utils_h264_caps_set_level_and_profile
10269 (entry->caps, avc_data + 8 + 40 + 1, size - 1);
10271 buf = gst_buffer_new_and_alloc (size);
10272 gst_buffer_fill (buf, 0, avc_data + 8 + 40, size);
10273 gst_caps_set_simple (entry->caps,
10274 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10275 gst_buffer_unref (buf);
10281 guint avg_bitrate, max_bitrate;
10283 /* bufferSizeDB, maxBitrate and avgBitrate - 4 bytes each */
10287 max_bitrate = QT_UINT32 (avc_data + 0xc);
10288 avg_bitrate = QT_UINT32 (avc_data + 0x10);
10290 if (!max_bitrate && !avg_bitrate)
10293 /* Some muxers seem to swap the average and maximum bitrates
10294 * (I'm looking at you, YouTube), so we swap for sanity. */
10295 if (max_bitrate > 0 && max_bitrate < avg_bitrate) {
10296 guint temp = avg_bitrate;
10298 avg_bitrate = max_bitrate;
10299 max_bitrate = temp;
10302 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
10303 gst_tag_list_add (stream->stream_tags,
10304 GST_TAG_MERGE_REPLACE, GST_TAG_MAXIMUM_BITRATE,
10305 max_bitrate, NULL);
10307 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
10308 gst_tag_list_add (stream->stream_tags,
10309 GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE, avg_bitrate,
10321 avc_data += size + 8;
10330 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
10331 const guint8 *hevc_data = stsd_entry_data + 0x56;
10334 while (len >= 0x8) {
10337 if (QT_UINT32 (hevc_data) <= len)
10338 size = QT_UINT32 (hevc_data) - 0x8;
10343 /* No real data, so break out */
10346 switch (QT_FOURCC (hevc_data + 0x4)) {
10349 /* parse, if found */
10352 GST_DEBUG_OBJECT (qtdemux, "found hvcC codec_data in stsd");
10354 /* First 4 bytes are the length of the atom, the next 4 bytes
10355 * are the fourcc, the next 1 byte is the version, and the
10356 * subsequent bytes are sequence parameter set like data. */
10357 gst_codec_utils_h265_caps_set_level_tier_and_profile
10358 (entry->caps, hevc_data + 8 + 1, size - 1);
10360 buf = gst_buffer_new_and_alloc (size);
10361 gst_buffer_fill (buf, 0, hevc_data + 0x8, size);
10362 gst_caps_set_simple (entry->caps,
10363 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10364 gst_buffer_unref (buf);
10371 hevc_data += size + 8;
10384 GST_DEBUG_OBJECT (qtdemux, "found %" GST_FOURCC_FORMAT,
10385 GST_FOURCC_ARGS (fourcc));
10387 /* codec data might be in glbl extension atom */
10389 qtdemux_tree_get_child_by_type (mp4v, FOURCC_glbl) : NULL;
10395 GST_DEBUG_OBJECT (qtdemux, "found glbl data in stsd");
10397 len = QT_UINT32 (data);
10400 buf = gst_buffer_new_and_alloc (len);
10401 gst_buffer_fill (buf, 0, data + 8, len);
10402 gst_caps_set_simple (entry->caps,
10403 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10404 gst_buffer_unref (buf);
10411 /* see annex I of the jpeg2000 spec */
10412 GNode *jp2h, *ihdr, *colr, *mjp2, *field, *prefix, *cmap, *cdef;
10413 const guint8 *data;
10414 const gchar *colorspace = NULL;
10416 guint32 ncomp_map = 0;
10417 gint32 *comp_map = NULL;
10418 guint32 nchan_def = 0;
10419 gint32 *chan_def = NULL;
10421 GST_DEBUG_OBJECT (qtdemux, "found mjp2");
10422 /* some required atoms */
10423 mjp2 = qtdemux_tree_get_child_by_index (stsd, stsd_index);
10426 jp2h = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2h);
10430 /* number of components; redundant with info in codestream, but useful
10432 ihdr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_ihdr);
10433 if (!ihdr || QT_UINT32 (ihdr->data) != 22)
10435 ncomp = QT_UINT16 (((guint8 *) ihdr->data) + 16);
10437 colr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_colr);
10440 GST_DEBUG_OBJECT (qtdemux, "found colr");
10441 /* extract colour space info */
10442 if (QT_UINT8 ((guint8 *) colr->data + 8) == 1) {
10443 switch (QT_UINT32 ((guint8 *) colr->data + 11)) {
10445 colorspace = "sRGB";
10448 colorspace = "GRAY";
10451 colorspace = "sYUV";
10459 /* colr is required, and only values 16, 17, and 18 are specified,
10460 so error if we have no colorspace */
10463 /* extract component mapping */
10464 cmap = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cmap);
10466 guint32 cmap_len = 0;
10468 cmap_len = QT_UINT32 (cmap->data);
10469 if (cmap_len >= 8) {
10470 /* normal box, subtract off header */
10472 /* cmap: { u16 cmp; u8 mtyp; u8 pcol; }* */
10473 if (cmap_len % 4 == 0) {
10474 ncomp_map = (cmap_len / 4);
10475 comp_map = g_new0 (gint32, ncomp_map);
10476 for (i = 0; i < ncomp_map; i++) {
10479 cmp = QT_UINT16 (((guint8 *) cmap->data) + 8 + i * 4);
10480 mtyp = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 2);
10481 pcol = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 3);
10482 comp_map[i] = (mtyp << 24) | (pcol << 16) | cmp;
10487 /* extract channel definitions */
10488 cdef = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cdef);
10490 guint32 cdef_len = 0;
10492 cdef_len = QT_UINT32 (cdef->data);
10493 if (cdef_len >= 10) {
10494 /* normal box, subtract off header and len */
10496 /* cdef: u16 n; { u16 cn; u16 typ; u16 asoc; }* */
10497 if (cdef_len % 6 == 0) {
10498 nchan_def = (cdef_len / 6);
10499 chan_def = g_new0 (gint32, nchan_def);
10500 for (i = 0; i < nchan_def; i++)
10502 for (i = 0; i < nchan_def; i++) {
10503 guint16 cn, typ, asoc;
10504 cn = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6);
10505 typ = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 2);
10506 asoc = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 4);
10507 if (cn < nchan_def) {
10510 chan_def[cn] = asoc;
10513 chan_def[cn] = 0; /* alpha */
10516 chan_def[cn] = -typ;
10524 gst_caps_set_simple (entry->caps,
10525 "num-components", G_TYPE_INT, ncomp, NULL);
10526 gst_caps_set_simple (entry->caps,
10527 "colorspace", G_TYPE_STRING, colorspace, NULL);
10530 GValue arr = { 0, };
10531 GValue elt = { 0, };
10533 g_value_init (&arr, GST_TYPE_ARRAY);
10534 g_value_init (&elt, G_TYPE_INT);
10535 for (i = 0; i < ncomp_map; i++) {
10536 g_value_set_int (&elt, comp_map[i]);
10537 gst_value_array_append_value (&arr, &elt);
10539 gst_structure_set_value (gst_caps_get_structure (entry->caps, 0),
10540 "component-map", &arr);
10541 g_value_unset (&elt);
10542 g_value_unset (&arr);
10547 GValue arr = { 0, };
10548 GValue elt = { 0, };
10550 g_value_init (&arr, GST_TYPE_ARRAY);
10551 g_value_init (&elt, G_TYPE_INT);
10552 for (i = 0; i < nchan_def; i++) {
10553 g_value_set_int (&elt, chan_def[i]);
10554 gst_value_array_append_value (&arr, &elt);
10556 gst_structure_set_value (gst_caps_get_structure (entry->caps, 0),
10557 "channel-definitions", &arr);
10558 g_value_unset (&elt);
10559 g_value_unset (&arr);
10563 /* some optional atoms */
10564 field = qtdemux_tree_get_child_by_type (mjp2, FOURCC_fiel);
10565 prefix = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2x);
10567 /* indicate possible fields in caps */
10569 data = (guint8 *) field->data + 8;
10571 gst_caps_set_simple (entry->caps, "fields", G_TYPE_INT,
10572 (gint) * data, NULL);
10574 /* add codec_data if provided */
10579 GST_DEBUG_OBJECT (qtdemux, "found prefix data in stsd");
10580 data = prefix->data;
10581 len = QT_UINT32 (data);
10584 buf = gst_buffer_new_and_alloc (len);
10585 gst_buffer_fill (buf, 0, data + 8, len);
10586 gst_caps_set_simple (entry->caps,
10587 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10588 gst_buffer_unref (buf);
10597 GstBuffer *seqh = NULL;
10598 const guint8 *gamma_data = NULL;
10599 gint len = QT_UINT32 (stsd_data); /* FIXME review - why put the whole stsd in codec data? */
10601 qtdemux_parse_svq3_stsd_data (qtdemux, stsd_entry_data, &gamma_data,
10604 gst_caps_set_simple (entry->caps, "applied-gamma", G_TYPE_DOUBLE,
10605 QT_FP32 (gamma_data), NULL);
10608 /* sorry for the bad name, but we don't know what this is, other
10609 * than its own fourcc */
10610 gst_caps_set_simple (entry->caps, "seqh", GST_TYPE_BUFFER, seqh,
10612 gst_buffer_unref (seqh);
10615 GST_DEBUG_OBJECT (qtdemux, "found codec_data in stsd");
10616 buf = gst_buffer_new_and_alloc (len);
10617 gst_buffer_fill (buf, 0, stsd_data, len);
10618 gst_caps_set_simple (entry->caps,
10619 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10620 gst_buffer_unref (buf);
10625 /* https://developer.apple.com/standards/qtff-2001.pdf,
10626 * page 92, "Video Sample Description", under table 3.1 */
10629 const gint compressor_offset =
10630 16 + 4 + 4 * 3 + 2 * 2 + 2 * 4 + 4 + 2;
10631 const gint min_size = compressor_offset + 32 + 2 + 2;
10634 guint16 color_table_id = 0;
10637 GST_DEBUG_OBJECT (qtdemux, "found jpeg");
10639 /* recover information on interlaced/progressive */
10640 jpeg = qtdemux_tree_get_child_by_type (stsd, FOURCC_jpeg);
10644 len = QT_UINT32 (jpeg->data);
10645 GST_DEBUG_OBJECT (qtdemux, "Found jpeg: len %u, need %d", len,
10647 if (len >= min_size) {
10648 gst_byte_reader_init (&br, jpeg->data, len);
10650 gst_byte_reader_skip (&br, compressor_offset + 32 + 2);
10651 gst_byte_reader_get_uint16_le (&br, &color_table_id);
10652 if (color_table_id != 0) {
10653 /* the spec says there can be concatenated chunks in the data, and we want
10654 * to find one called field. Walk through them. */
10655 gint offset = min_size;
10656 while (offset + 8 < len) {
10657 guint32 size = 0, tag;
10658 ok = gst_byte_reader_get_uint32_le (&br, &size);
10659 ok &= gst_byte_reader_get_uint32_le (&br, &tag);
10660 if (!ok || size < 8) {
10661 GST_WARNING_OBJECT (qtdemux,
10662 "Failed to walk optional chunk list");
10665 GST_DEBUG_OBJECT (qtdemux,
10666 "Found optional %4.4s chunk, size %u",
10667 (const char *) &tag, size);
10668 if (tag == FOURCC_fiel) {
10669 guint8 n_fields = 0, ordering = 0;
10670 gst_byte_reader_get_uint8 (&br, &n_fields);
10671 gst_byte_reader_get_uint8 (&br, &ordering);
10672 if (n_fields == 1 || n_fields == 2) {
10673 GST_DEBUG_OBJECT (qtdemux,
10674 "Found fiel tag with %u fields, ordering %u",
10675 n_fields, ordering);
10677 gst_caps_set_simple (CUR_STREAM (stream)->caps,
10678 "interlace-mode", G_TYPE_STRING, "interleaved",
10681 GST_WARNING_OBJECT (qtdemux,
10682 "Found fiel tag with invalid fields (%u)", n_fields);
10688 GST_DEBUG_OBJECT (qtdemux,
10689 "Color table ID is 0, not trying to get interlacedness");
10692 GST_WARNING_OBJECT (qtdemux,
10693 "Length of jpeg chunk is too small, not trying to get interlacedness");
10701 gst_caps_set_simple (entry->caps,
10702 "depth", G_TYPE_INT, QT_UINT16 (stsd_entry_data + offset + 66),
10708 GNode *xith, *xdxt;
10710 GST_DEBUG_OBJECT (qtdemux, "found XiTh");
10711 xith = qtdemux_tree_get_child_by_index (stsd, stsd_index);
10715 xdxt = qtdemux_tree_get_child_by_type (xith, FOURCC_XdxT);
10719 GST_DEBUG_OBJECT (qtdemux, "found XdxT node");
10720 /* collect the headers and store them in a stream list so that we can
10721 * send them out first */
10722 qtdemux_parse_theora_extension (qtdemux, stream, xdxt);
10732 GST_DEBUG_OBJECT (qtdemux, "parse ovc1 header");
10733 ovc1 = qtdemux_tree_get_child_by_index (stsd, stsd_index);
10736 ovc1_data = ovc1->data;
10737 ovc1_len = QT_UINT32 (ovc1_data);
10738 if (ovc1_len <= 198) {
10739 GST_WARNING_OBJECT (qtdemux, "Too small ovc1 header, skipping");
10742 buf = gst_buffer_new_and_alloc (ovc1_len - 198);
10743 gst_buffer_fill (buf, 0, ovc1_data + 198, ovc1_len - 198);
10744 gst_caps_set_simple (entry->caps,
10745 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10746 gst_buffer_unref (buf);
10751 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
10752 const guint8 *vc1_data = stsd_entry_data + 0x56;
10758 if (QT_UINT32 (vc1_data) <= len)
10759 size = QT_UINT32 (vc1_data) - 8;
10764 /* No real data, so break out */
10767 switch (QT_FOURCC (vc1_data + 0x4)) {
10768 case GST_MAKE_FOURCC ('d', 'v', 'c', '1'):
10772 GST_DEBUG_OBJECT (qtdemux, "found dvc1 codec_data in stsd");
10773 buf = gst_buffer_new_and_alloc (size);
10774 gst_buffer_fill (buf, 0, vc1_data + 8, size);
10775 gst_caps_set_simple (entry->caps,
10776 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10777 gst_buffer_unref (buf);
10784 vc1_data += size + 8;
10793 GST_INFO_OBJECT (qtdemux,
10794 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
10795 GST_FOURCC_ARGS (fourcc), entry->caps);
10797 } else if (stream->subtype == FOURCC_soun) {
10799 int version, samplesize;
10800 guint16 compression_id;
10801 gboolean amrwb = FALSE;
10804 /* sample description entry (16) + sound sample description v0 (20) */
10808 version = QT_UINT32 (stsd_entry_data + offset);
10809 entry->n_channels = QT_UINT16 (stsd_entry_data + offset + 8);
10810 samplesize = QT_UINT16 (stsd_entry_data + offset + 10);
10811 compression_id = QT_UINT16 (stsd_entry_data + offset + 12);
10812 entry->rate = QT_FP32 (stsd_entry_data + offset + 16);
10814 GST_LOG_OBJECT (qtdemux, "version/rev: %08x", version);
10815 GST_LOG_OBJECT (qtdemux, "vendor: %08x",
10816 QT_UINT32 (stsd_entry_data + offset + 4));
10817 GST_LOG_OBJECT (qtdemux, "n_channels: %d", entry->n_channels);
10818 GST_LOG_OBJECT (qtdemux, "sample_size: %d", samplesize);
10819 GST_LOG_OBJECT (qtdemux, "compression_id: %d", compression_id);
10820 GST_LOG_OBJECT (qtdemux, "packet size: %d",
10821 QT_UINT16 (stsd_entry_data + offset + 14));
10822 GST_LOG_OBJECT (qtdemux, "sample rate: %g", entry->rate);
10824 if (compression_id == 0xfffe)
10825 entry->sampled = TRUE;
10827 /* first assume uncompressed audio */
10828 entry->bytes_per_sample = samplesize / 8;
10829 entry->samples_per_frame = entry->n_channels;
10830 entry->bytes_per_frame = entry->n_channels * entry->bytes_per_sample;
10831 entry->samples_per_packet = entry->samples_per_frame;
10832 entry->bytes_per_packet = entry->bytes_per_sample;
10836 /* Yes, these have to be hard-coded */
10839 entry->samples_per_packet = 6;
10840 entry->bytes_per_packet = 1;
10841 entry->bytes_per_frame = 1 * entry->n_channels;
10842 entry->bytes_per_sample = 1;
10843 entry->samples_per_frame = 6 * entry->n_channels;
10848 entry->samples_per_packet = 3;
10849 entry->bytes_per_packet = 1;
10850 entry->bytes_per_frame = 1 * entry->n_channels;
10851 entry->bytes_per_sample = 1;
10852 entry->samples_per_frame = 3 * entry->n_channels;
10857 entry->samples_per_packet = 64;
10858 entry->bytes_per_packet = 34;
10859 entry->bytes_per_frame = 34 * entry->n_channels;
10860 entry->bytes_per_sample = 2;
10861 entry->samples_per_frame = 64 * entry->n_channels;
10867 entry->samples_per_packet = 1;
10868 entry->bytes_per_packet = 1;
10869 entry->bytes_per_frame = 1 * entry->n_channels;
10870 entry->bytes_per_sample = 1;
10871 entry->samples_per_frame = 1 * entry->n_channels;
10876 entry->samples_per_packet = 160;
10877 entry->bytes_per_packet = 33;
10878 entry->bytes_per_frame = 33 * entry->n_channels;
10879 entry->bytes_per_sample = 2;
10880 entry->samples_per_frame = 160 * entry->n_channels;
10887 if (version == 0x00010000) {
10888 /* sample description entry (16) + sound sample description v1 (20+16) */
10900 /* only parse extra decoding config for non-pcm audio */
10901 entry->samples_per_packet = QT_UINT32 (stsd_entry_data + offset);
10902 entry->bytes_per_packet = QT_UINT32 (stsd_entry_data + offset + 4);
10903 entry->bytes_per_frame = QT_UINT32 (stsd_entry_data + offset + 8);
10904 entry->bytes_per_sample = QT_UINT32 (stsd_entry_data + offset + 12);
10906 GST_LOG_OBJECT (qtdemux, "samples/packet: %d",
10907 entry->samples_per_packet);
10908 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
10909 entry->bytes_per_packet);
10910 GST_LOG_OBJECT (qtdemux, "bytes/frame: %d",
10911 entry->bytes_per_frame);
10912 GST_LOG_OBJECT (qtdemux, "bytes/sample: %d",
10913 entry->bytes_per_sample);
10915 if (!entry->sampled && entry->bytes_per_packet) {
10916 entry->samples_per_frame = (entry->bytes_per_frame /
10917 entry->bytes_per_packet) * entry->samples_per_packet;
10918 GST_LOG_OBJECT (qtdemux, "samples/frame: %d",
10919 entry->samples_per_frame);
10924 } else if (version == 0x00020000) {
10931 /* sample description entry (16) + sound sample description v2 (56) */
10935 qtfp.val = QT_UINT64 (stsd_entry_data + offset + 4);
10936 entry->rate = qtfp.fp;
10937 entry->n_channels = QT_UINT32 (stsd_entry_data + offset + 12);
10939 GST_LOG_OBJECT (qtdemux, "Sound sample description Version 2");
10940 GST_LOG_OBJECT (qtdemux, "sample rate: %g", entry->rate);
10941 GST_LOG_OBJECT (qtdemux, "n_channels: %d", entry->n_channels);
10942 GST_LOG_OBJECT (qtdemux, "bits/channel: %d",
10943 QT_UINT32 (stsd_entry_data + offset + 20));
10944 GST_LOG_OBJECT (qtdemux, "format flags: %X",
10945 QT_UINT32 (stsd_entry_data + offset + 24));
10946 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
10947 QT_UINT32 (stsd_entry_data + offset + 28));
10948 GST_LOG_OBJECT (qtdemux, "LPCM frames/packet: %d",
10949 QT_UINT32 (stsd_entry_data + offset + 32));
10950 } else if (version != 0x00000) {
10951 GST_WARNING_OBJECT (qtdemux, "unknown audio STSD version %08x",
10956 gst_caps_unref (entry->caps);
10958 entry->caps = qtdemux_audio_caps (qtdemux, stream, entry, fourcc,
10959 stsd_entry_data + 32, len - 16, &codec);
10967 in24 = qtdemux_tree_get_child_by_type (stsd, FOURCC_in24);
10969 enda = qtdemux_tree_get_child_by_type (in24, FOURCC_enda);
10971 wave = qtdemux_tree_get_child_by_type (in24, FOURCC_wave);
10973 enda = qtdemux_tree_get_child_by_type (wave, FOURCC_enda);
10976 int enda_value = QT_UINT16 ((guint8 *) enda->data + 8);
10977 gst_caps_set_simple (entry->caps,
10978 "format", G_TYPE_STRING, (enda_value) ? "S24LE" : "S24BE",
10985 const guint8 *owma_data;
10986 const gchar *codec_name = NULL;
10990 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
10991 /* FIXME this should also be gst_riff_strf_auds,
10992 * but the latter one is actually missing bits-per-sample :( */
10997 gint32 nSamplesPerSec;
10998 gint32 nAvgBytesPerSec;
10999 gint16 nBlockAlign;
11000 gint16 wBitsPerSample;
11003 WAVEFORMATEX *wfex;
11005 GST_DEBUG_OBJECT (qtdemux, "parse owma");
11006 owma_data = stsd_entry_data;
11007 owma_len = QT_UINT32 (owma_data);
11008 if (owma_len <= 54) {
11009 GST_WARNING_OBJECT (qtdemux, "Too small owma header, skipping");
11012 wfex = (WAVEFORMATEX *) (owma_data + 36);
11013 buf = gst_buffer_new_and_alloc (owma_len - 54);
11014 gst_buffer_fill (buf, 0, owma_data + 54, owma_len - 54);
11015 if (wfex->wFormatTag == 0x0161) {
11016 codec_name = "Windows Media Audio";
11018 } else if (wfex->wFormatTag == 0x0162) {
11019 codec_name = "Windows Media Audio 9 Pro";
11021 } else if (wfex->wFormatTag == 0x0163) {
11022 codec_name = "Windows Media Audio 9 Lossless";
11023 /* is that correct? gstffmpegcodecmap.c is missing it, but
11024 * fluendo codec seems to support it */
11028 gst_caps_set_simple (entry->caps,
11029 "codec_data", GST_TYPE_BUFFER, buf,
11030 "wmaversion", G_TYPE_INT, version,
11031 "block_align", G_TYPE_INT,
11032 GST_READ_UINT16_LE (&wfex->nBlockAlign), "bitrate", G_TYPE_INT,
11033 GST_READ_UINT32_LE (&wfex->nAvgBytesPerSec), "width", G_TYPE_INT,
11034 GST_READ_UINT16_LE (&wfex->wBitsPerSample), "depth", G_TYPE_INT,
11035 GST_READ_UINT16_LE (&wfex->wBitsPerSample), NULL);
11036 gst_buffer_unref (buf);
11040 codec = g_strdup (codec_name);
11046 gint len = QT_UINT32 (stsd_entry_data) - offset;
11047 const guint8 *wfex_data = stsd_entry_data + offset;
11048 const gchar *codec_name = NULL;
11050 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
11051 /* FIXME this should also be gst_riff_strf_auds,
11052 * but the latter one is actually missing bits-per-sample :( */
11057 gint32 nSamplesPerSec;
11058 gint32 nAvgBytesPerSec;
11059 gint16 nBlockAlign;
11060 gint16 wBitsPerSample;
11065 /* FIXME: unify with similar wavformatex parsing code above */
11066 GST_DEBUG_OBJECT (qtdemux, "parse wma, looking for wfex");
11072 if (QT_UINT32 (wfex_data) <= len)
11073 size = QT_UINT32 (wfex_data) - 8;
11078 /* No real data, so break out */
11081 switch (QT_FOURCC (wfex_data + 4)) {
11082 case GST_MAKE_FOURCC ('w', 'f', 'e', 'x'):
11084 GST_DEBUG_OBJECT (qtdemux, "found wfex in stsd");
11089 wfex.wFormatTag = GST_READ_UINT16_LE (wfex_data + 8 + 0);
11090 wfex.nChannels = GST_READ_UINT16_LE (wfex_data + 8 + 2);
11091 wfex.nSamplesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 4);
11092 wfex.nAvgBytesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 8);
11093 wfex.nBlockAlign = GST_READ_UINT16_LE (wfex_data + 8 + 12);
11094 wfex.wBitsPerSample = GST_READ_UINT16_LE (wfex_data + 8 + 14);
11095 wfex.cbSize = GST_READ_UINT16_LE (wfex_data + 8 + 16);
11097 GST_LOG_OBJECT (qtdemux, "Found wfex box in stsd:");
11098 GST_LOG_OBJECT (qtdemux, "FormatTag = 0x%04x, Channels = %u, "
11099 "SamplesPerSec = %u, AvgBytesPerSec = %u, BlockAlign = %u, "
11100 "BitsPerSample = %u, Size = %u", wfex.wFormatTag,
11101 wfex.nChannels, wfex.nSamplesPerSec, wfex.nAvgBytesPerSec,
11102 wfex.nBlockAlign, wfex.wBitsPerSample, wfex.cbSize);
11104 if (wfex.wFormatTag == 0x0161) {
11105 codec_name = "Windows Media Audio";
11107 } else if (wfex.wFormatTag == 0x0162) {
11108 codec_name = "Windows Media Audio 9 Pro";
11110 } else if (wfex.wFormatTag == 0x0163) {
11111 codec_name = "Windows Media Audio 9 Lossless";
11112 /* is that correct? gstffmpegcodecmap.c is missing it, but
11113 * fluendo codec seems to support it */
11117 gst_caps_set_simple (entry->caps,
11118 "wmaversion", G_TYPE_INT, version,
11119 "block_align", G_TYPE_INT, wfex.nBlockAlign,
11120 "bitrate", G_TYPE_INT, wfex.nAvgBytesPerSec,
11121 "width", G_TYPE_INT, wfex.wBitsPerSample,
11122 "depth", G_TYPE_INT, wfex.wBitsPerSample, NULL);
11124 if (size > wfex.cbSize) {
11127 buf = gst_buffer_new_and_alloc (size - wfex.cbSize);
11128 gst_buffer_fill (buf, 0, wfex_data + 8 + wfex.cbSize,
11129 size - wfex.cbSize);
11130 gst_caps_set_simple (entry->caps,
11131 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11132 gst_buffer_unref (buf);
11134 GST_WARNING_OBJECT (qtdemux, "no codec data");
11139 codec = g_strdup (codec_name);
11147 wfex_data += size + 8;
11153 const guint8 *opus_data;
11154 guint8 *channel_mapping = NULL;
11157 guint8 channel_mapping_family;
11158 guint8 stream_count;
11159 guint8 coupled_count;
11162 opus_data = stsd_entry_data;
11164 channels = GST_READ_UINT8 (opus_data + 45);
11165 rate = GST_READ_UINT32_LE (opus_data + 48);
11166 channel_mapping_family = GST_READ_UINT8 (opus_data + 54);
11167 stream_count = GST_READ_UINT8 (opus_data + 55);
11168 coupled_count = GST_READ_UINT8 (opus_data + 56);
11170 if (channels > 0) {
11171 channel_mapping = g_malloc (channels * sizeof (guint8));
11172 for (i = 0; i < channels; i++)
11173 channel_mapping[i] = GST_READ_UINT8 (opus_data + i + 57);
11176 entry->caps = gst_codec_utils_opus_create_caps (rate, channels,
11177 channel_mapping_family, stream_count, coupled_count,
11189 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11190 GST_TAG_AUDIO_CODEC, codec, NULL);
11194 /* some bitrate info may have ended up in caps */
11195 s = gst_caps_get_structure (entry->caps, 0);
11196 gst_structure_get_int (s, "bitrate", &bitrate);
11198 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11199 GST_TAG_BITRATE, bitrate, NULL);
11202 mp4a = qtdemux_tree_get_child_by_index (stsd, stsd_index);
11203 if (!stream->protected) {
11205 if (QTDEMUX_TREE_NODE_FOURCC (mp4v) != FOURCC_encv) {
11209 if (stream->protected && fourcc == FOURCC_mp4a) {
11210 if (QTDEMUX_TREE_NODE_FOURCC (mp4a) != FOURCC_enca) {
11214 if (QTDEMUX_TREE_NODE_FOURCC (mp4a) != FOURCC_mp4a) {
11222 wave = qtdemux_tree_get_child_by_type (mp4a, FOURCC_wave);
11224 esds = qtdemux_tree_get_child_by_type (wave, FOURCC_esds);
11226 esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
11230 /* If the fourcc's bottom 16 bits gives 'sm', then the top
11231 16 bits is a byte-swapped wave-style codec identifier,
11232 and we can find a WAVE header internally to a 'wave' atom here.
11233 This can more clearly be thought of as 'ms' as the top 16 bits, and a
11234 codec id as the bottom 16 bits - but byte-swapped to store in QT (which
11237 if ((fourcc & 0xffff) == (('s' << 8) | 'm')) {
11238 if (len < offset + 20) {
11239 GST_WARNING_OBJECT (qtdemux, "No wave atom in MS-style audio");
11241 guint32 datalen = QT_UINT32 (stsd_entry_data + offset + 16);
11242 const guint8 *data = stsd_entry_data + offset + 16;
11244 GNode *waveheadernode;
11246 wavenode = g_node_new ((guint8 *) data);
11247 if (qtdemux_parse_node (qtdemux, wavenode, data, datalen)) {
11248 const guint8 *waveheader;
11251 waveheadernode = qtdemux_tree_get_child_by_type (wavenode, fourcc);
11252 if (waveheadernode) {
11253 waveheader = (const guint8 *) waveheadernode->data;
11254 headerlen = QT_UINT32 (waveheader);
11256 if (headerlen > 8) {
11257 gst_riff_strf_auds *header = NULL;
11258 GstBuffer *headerbuf;
11264 headerbuf = gst_buffer_new_and_alloc (headerlen);
11265 gst_buffer_fill (headerbuf, 0, waveheader, headerlen);
11267 if (gst_riff_parse_strf_auds (GST_ELEMENT_CAST (qtdemux),
11268 headerbuf, &header, &extra)) {
11269 gst_caps_unref (entry->caps);
11270 /* FIXME: Need to do something with the channel reorder map */
11272 gst_riff_create_audio_caps (header->format, NULL, header,
11273 extra, NULL, NULL, NULL);
11276 gst_buffer_unref (extra);
11281 GST_DEBUG ("Didn't find waveheadernode for this codec");
11283 g_node_destroy (wavenode);
11286 gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
11287 stream->stream_tags);
11291 /* FIXME: what is in the chunk? */
11294 gint len = QT_UINT32 (stsd_data);
11296 /* seems to be always = 116 = 0x74 */
11302 gint len = QT_UINT32 (stsd_entry_data);
11305 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x3C);
11307 gst_buffer_fill (buf, 0, stsd_entry_data + 0x3C, len - 0x3C);
11308 gst_caps_set_simple (entry->caps,
11309 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11310 gst_buffer_unref (buf);
11312 gst_caps_set_simple (entry->caps,
11313 "samplesize", G_TYPE_INT, samplesize, NULL);
11318 GNode *alac, *wave = NULL;
11320 /* apparently, m4a has this atom appended directly in the stsd entry,
11321 * while mov has it in a wave atom */
11322 alac = qtdemux_tree_get_child_by_type (stsd, FOURCC_alac);
11324 /* alac now refers to stsd entry atom */
11325 wave = qtdemux_tree_get_child_by_type (alac, FOURCC_wave);
11327 alac = qtdemux_tree_get_child_by_type (wave, FOURCC_alac);
11329 alac = qtdemux_tree_get_child_by_type (alac, FOURCC_alac);
11332 const guint8 *alac_data = alac->data;
11333 gint len = QT_UINT32 (alac->data);
11337 GST_DEBUG_OBJECT (qtdemux,
11338 "discarding alac atom with unexpected len %d", len);
11340 /* codec-data contains alac atom size and prefix,
11341 * ffmpeg likes it that way, not quite gst-ish though ...*/
11342 buf = gst_buffer_new_and_alloc (len);
11343 gst_buffer_fill (buf, 0, alac->data, len);
11344 gst_caps_set_simple (entry->caps,
11345 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11346 gst_buffer_unref (buf);
11348 entry->bytes_per_frame = QT_UINT32 (alac_data + 12);
11349 entry->n_channels = QT_UINT8 (alac_data + 21);
11350 entry->rate = QT_UINT32 (alac_data + 32);
11353 gst_caps_set_simple (entry->caps,
11354 "samplesize", G_TYPE_INT, samplesize, NULL);
11359 /* The codingname of the sample entry is 'fLaC' */
11360 GNode *flac = qtdemux_tree_get_child_by_type (stsd, FOURCC_fLaC);
11363 /* The 'dfLa' box is added to the sample entry to convey
11364 initializing information for the decoder. */
11365 const GNode *dfla =
11366 qtdemux_tree_get_child_by_type (flac, FOURCC_dfLa);
11369 const guint32 len = QT_UINT32 (dfla->data);
11371 /* Must contain at least dfLa box header (12),
11372 * METADATA_BLOCK_HEADER (4), METADATA_BLOCK_STREAMINFO (34) */
11374 GST_DEBUG_OBJECT (qtdemux,
11375 "discarding dfla atom with unexpected len %d", len);
11377 /* skip dfLa header to get the METADATA_BLOCKs */
11378 const guint8 *metadata_blocks = (guint8 *) dfla->data + 12;
11379 const guint32 metadata_blocks_len = len - 12;
11381 gchar *stream_marker = g_strdup ("fLaC");
11382 GstBuffer *block = gst_buffer_new_wrapped (stream_marker,
11383 strlen (stream_marker));
11386 guint32 remainder = 0;
11387 guint32 block_size = 0;
11388 gboolean is_last = FALSE;
11390 GValue array = G_VALUE_INIT;
11391 GValue value = G_VALUE_INIT;
11393 g_value_init (&array, GST_TYPE_ARRAY);
11394 g_value_init (&value, GST_TYPE_BUFFER);
11396 gst_value_set_buffer (&value, block);
11397 gst_value_array_append_value (&array, &value);
11398 g_value_reset (&value);
11400 gst_buffer_unref (block);
11402 /* check there's at least one METADATA_BLOCK_HEADER's worth
11403 * of data, and we haven't already finished parsing */
11404 while (!is_last && ((index + 3) < metadata_blocks_len)) {
11405 remainder = metadata_blocks_len - index;
11407 /* add the METADATA_BLOCK_HEADER size to the signalled size */
11409 (metadata_blocks[index + 1] << 16) +
11410 (metadata_blocks[index + 2] << 8) +
11411 metadata_blocks[index + 3];
11413 /* be careful not to read off end of box */
11414 if (block_size > remainder) {
11418 is_last = metadata_blocks[index] >> 7;
11420 block = gst_buffer_new_and_alloc (block_size);
11422 gst_buffer_fill (block, 0, &metadata_blocks[index],
11425 gst_value_set_buffer (&value, block);
11426 gst_value_array_append_value (&array, &value);
11427 g_value_reset (&value);
11429 gst_buffer_unref (block);
11431 index += block_size;
11434 /* only append the metadata if we successfully read all of it */
11436 gst_structure_set_value (gst_caps_get_structure (CUR_STREAM
11437 (stream)->caps, 0), "streamheader", &array);
11439 GST_WARNING_OBJECT (qtdemux,
11440 "discarding all METADATA_BLOCKs due to invalid "
11441 "block_size %d at idx %d, rem %d", block_size, index,
11445 g_value_unset (&value);
11446 g_value_unset (&array);
11448 /* The sample rate obtained from the stsd may not be accurate
11449 * since it cannot represent rates greater than 65535Hz, so
11450 * override that value with the sample rate from the
11451 * METADATA_BLOCK_STREAMINFO block */
11452 CUR_STREAM (stream)->rate =
11453 (QT_UINT32 (metadata_blocks + 14) >> 12) & 0xFFFFF;
11464 gint len = QT_UINT32 (stsd_entry_data);
11467 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x24);
11470 gst_buffer_fill (buf, 0, stsd_entry_data + 0x24, len - 0x24);
11472 /* If we have enough data, let's try to get the 'damr' atom. See
11473 * the 3GPP container spec (26.244) for more details. */
11474 if ((len - 0x34) > 8 &&
11475 (bitrate = qtdemux_parse_amr_bitrate (buf, amrwb))) {
11476 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11477 GST_TAG_MAXIMUM_BITRATE, bitrate, NULL);
11480 gst_caps_set_simple (entry->caps,
11481 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11482 gst_buffer_unref (buf);
11488 /* mp4a atom withtout ESDS; Attempt to build codec data from atom */
11489 gint len = QT_UINT32 (stsd_entry_data);
11492 guint16 sound_version = QT_UINT16 (stsd_entry_data + 16);
11494 if (sound_version == 1) {
11495 guint16 channels = QT_UINT16 (stsd_entry_data + 24);
11496 guint32 time_scale = QT_UINT32 (stsd_entry_data + 30);
11497 guint8 codec_data[2];
11499 gint profile = 2; /* FIXME: Can this be determined somehow? There doesn't seem to be anything in mp4a atom that specifis compression */
11501 gint sample_rate_index =
11502 gst_codec_utils_aac_get_index_from_sample_rate (time_scale);
11504 /* build AAC codec data */
11505 codec_data[0] = profile << 3;
11506 codec_data[0] |= ((sample_rate_index >> 1) & 0x7);
11507 codec_data[1] = (sample_rate_index & 0x01) << 7;
11508 codec_data[1] |= (channels & 0xF) << 3;
11510 buf = gst_buffer_new_and_alloc (2);
11511 gst_buffer_fill (buf, 0, codec_data, 2);
11512 gst_caps_set_simple (entry->caps,
11513 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11514 gst_buffer_unref (buf);
11520 /* Fully handled elsewhere */
11523 GST_INFO_OBJECT (qtdemux,
11524 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
11528 GST_INFO_OBJECT (qtdemux,
11529 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
11530 GST_FOURCC_ARGS (fourcc), entry->caps);
11532 } else if (stream->subtype == FOURCC_strm) {
11533 if (fourcc == FOURCC_rtsp) {
11534 stream->redirect_uri = qtdemux_get_rtsp_uri_from_hndl (qtdemux, minf);
11536 GST_INFO_OBJECT (qtdemux, "unhandled stream type %" GST_FOURCC_FORMAT,
11537 GST_FOURCC_ARGS (fourcc));
11538 goto unknown_stream;
11540 entry->sampled = TRUE;
11541 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
11542 || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt) {
11544 entry->sampled = TRUE;
11545 entry->sparse = TRUE;
11548 qtdemux_sub_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
11551 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11552 GST_TAG_SUBTITLE_CODEC, codec, NULL);
11557 /* hunt for sort-of codec data */
11561 GNode *mp4s = NULL;
11562 GNode *esds = NULL;
11564 /* look for palette in a stsd->mp4s->esds sub-atom */
11565 mp4s = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4s);
11567 esds = qtdemux_tree_get_child_by_type (mp4s, FOURCC_esds);
11568 if (esds == NULL) {
11570 GST_LOG_OBJECT (qtdemux, "Skipping invalid stsd: no esds child");
11574 gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
11575 stream->stream_tags);
11579 GST_INFO_OBJECT (qtdemux,
11580 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
11583 GST_INFO_OBJECT (qtdemux,
11584 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
11585 GST_FOURCC_ARGS (fourcc), entry->caps);
11587 /* everything in 1 sample */
11588 entry->sampled = TRUE;
11591 qtdemux_generic_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
11594 if (entry->caps == NULL)
11595 goto unknown_stream;
11598 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11599 GST_TAG_SUBTITLE_CODEC, codec, NULL);
11605 /* promote to sampled format */
11606 if (entry->fourcc == FOURCC_samr) {
11607 /* force mono 8000 Hz for AMR */
11608 entry->sampled = TRUE;
11609 entry->n_channels = 1;
11610 entry->rate = 8000;
11611 } else if (entry->fourcc == FOURCC_sawb) {
11612 /* force mono 16000 Hz for AMR-WB */
11613 entry->sampled = TRUE;
11614 entry->n_channels = 1;
11615 entry->rate = 16000;
11616 } else if (entry->fourcc == FOURCC_mp4a) {
11617 entry->sampled = TRUE;
11621 stsd_entry_data += len;
11622 remaining_stsd_len -= len;
11626 /* collect sample information */
11627 if (!qtdemux_stbl_init (qtdemux, stream, stbl))
11628 goto samples_failed;
11630 if (qtdemux->fragmented) {
11633 /* need all moov samples as basis; probably not many if any at all */
11634 /* prevent moof parsing taking of at this time */
11635 offset = qtdemux->moof_offset;
11636 qtdemux->moof_offset = 0;
11637 if (stream->n_samples &&
11638 !qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
11639 qtdemux->moof_offset = offset;
11640 goto samples_failed;
11642 qtdemux->moof_offset = 0;
11643 /* movie duration more reliable in this case (e.g. mehd) */
11644 if (qtdemux->segment.duration &&
11645 GST_CLOCK_TIME_IS_VALID (qtdemux->segment.duration))
11647 GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->segment.duration);
11650 /* configure segments */
11651 if (!qtdemux_parse_segments (qtdemux, stream, trak))
11652 goto segments_failed;
11654 /* add some language tag, if useful */
11655 if (stream->lang_id[0] != '\0' && strcmp (stream->lang_id, "unk") &&
11656 strcmp (stream->lang_id, "und")) {
11657 const gchar *lang_code;
11659 /* convert ISO 639-2 code to ISO 639-1 */
11660 lang_code = gst_tag_get_language_code (stream->lang_id);
11661 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11662 GST_TAG_LANGUAGE_CODE, (lang_code) ? lang_code : stream->lang_id, NULL);
11665 /* Check for UDTA tags */
11666 if ((udta = qtdemux_tree_get_child_by_type (trak, FOURCC_udta))) {
11667 qtdemux_parse_udta (qtdemux, stream->stream_tags, udta);
11670 /* now we are ready to add the stream */
11671 if (qtdemux->n_streams >= GST_QTDEMUX_MAX_STREAMS)
11672 goto too_many_streams;
11674 if (!qtdemux->got_moov) {
11675 qtdemux->streams[qtdemux->n_streams] = stream;
11676 qtdemux->n_streams++;
11677 GST_DEBUG_OBJECT (qtdemux, "n_streams is now %d", qtdemux->n_streams);
11685 GST_INFO_OBJECT (qtdemux, "skip disabled track");
11687 gst_qtdemux_stream_free (qtdemux, stream);
11692 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
11693 (_("This file is corrupt and cannot be played.")), (NULL));
11695 gst_qtdemux_stream_free (qtdemux, stream);
11700 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT, (NULL), (NULL));
11702 gst_qtdemux_stream_free (qtdemux, stream);
11708 /* we posted an error already */
11709 /* free stbl sub-atoms */
11710 gst_qtdemux_stbl_free (stream);
11712 gst_qtdemux_stream_free (qtdemux, stream);
11717 GST_INFO_OBJECT (qtdemux, "stream with track id %i already exists",
11720 gst_qtdemux_stream_free (qtdemux, stream);
11725 GST_INFO_OBJECT (qtdemux, "unknown subtype %" GST_FOURCC_FORMAT,
11726 GST_FOURCC_ARGS (stream->subtype));
11728 gst_qtdemux_stream_free (qtdemux, stream);
11733 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
11734 (_("This file contains too many streams. Only playing first %d"),
11735 GST_QTDEMUX_MAX_STREAMS), (NULL));
11740 /* If we can estimate the overall bitrate, and don't have information about the
11741 * stream bitrate for exactly one stream, this guesses the stream bitrate as
11742 * the overall bitrate minus the sum of the bitrates of all other streams. This
11743 * should be useful for the common case where we have one audio and one video
11744 * stream and can estimate the bitrate of one, but not the other. */
11746 gst_qtdemux_guess_bitrate (GstQTDemux * qtdemux)
11748 QtDemuxStream *stream = NULL;
11749 gint64 size, sys_bitrate, sum_bitrate = 0;
11750 GstClockTime duration;
11754 if (qtdemux->fragmented)
11757 GST_DEBUG_OBJECT (qtdemux, "Looking for streams with unknown bitrate");
11759 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &size)
11761 GST_DEBUG_OBJECT (qtdemux,
11762 "Size in bytes of the stream not known - bailing");
11766 /* Subtract the header size */
11767 GST_DEBUG_OBJECT (qtdemux, "Total size %" G_GINT64_FORMAT ", header size %u",
11768 size, qtdemux->header_size);
11770 if (size < qtdemux->header_size)
11773 size = size - qtdemux->header_size;
11775 if (!gst_qtdemux_get_duration (qtdemux, &duration)) {
11776 GST_DEBUG_OBJECT (qtdemux, "Stream duration not known - bailing");
11780 for (i = 0; i < qtdemux->n_streams; i++) {
11781 switch (qtdemux->streams[i]->subtype) {
11784 GST_DEBUG_OBJECT (qtdemux, "checking bitrate for %" GST_PTR_FORMAT,
11785 CUR_STREAM (qtdemux->streams[i])->caps);
11786 /* retrieve bitrate, prefer avg then max */
11788 if (qtdemux->streams[i]->stream_tags) {
11789 if (gst_tag_list_get_uint (qtdemux->streams[i]->stream_tags,
11790 GST_TAG_MAXIMUM_BITRATE, &bitrate))
11791 GST_DEBUG_OBJECT (qtdemux, "max-bitrate: %u", bitrate);
11792 if (gst_tag_list_get_uint (qtdemux->streams[i]->stream_tags,
11793 GST_TAG_NOMINAL_BITRATE, &bitrate))
11794 GST_DEBUG_OBJECT (qtdemux, "nominal-bitrate: %u", bitrate);
11795 if (gst_tag_list_get_uint (qtdemux->streams[i]->stream_tags,
11796 GST_TAG_BITRATE, &bitrate))
11797 GST_DEBUG_OBJECT (qtdemux, "bitrate: %u", bitrate);
11800 sum_bitrate += bitrate;
11803 GST_DEBUG_OBJECT (qtdemux,
11804 ">1 stream with unknown bitrate - bailing");
11807 stream = qtdemux->streams[i];
11811 /* For other subtypes, we assume no significant impact on bitrate */
11817 GST_DEBUG_OBJECT (qtdemux, "All stream bitrates are known");
11821 sys_bitrate = gst_util_uint64_scale (size, GST_SECOND * 8, duration);
11823 if (sys_bitrate < sum_bitrate) {
11824 /* This can happen, since sum_bitrate might be derived from maximum
11825 * bitrates and not average bitrates */
11826 GST_DEBUG_OBJECT (qtdemux,
11827 "System bitrate less than sum bitrate - bailing");
11831 bitrate = sys_bitrate - sum_bitrate;
11832 GST_DEBUG_OBJECT (qtdemux, "System bitrate = %" G_GINT64_FORMAT
11833 ", Stream bitrate = %u", sys_bitrate, bitrate);
11835 if (!stream->stream_tags)
11836 stream->stream_tags = gst_tag_list_new_empty ();
11838 stream->stream_tags = gst_tag_list_make_writable (stream->stream_tags);
11840 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11841 GST_TAG_BITRATE, bitrate, NULL);
11844 static GstFlowReturn
11845 qtdemux_prepare_streams (GstQTDemux * qtdemux)
11848 GstFlowReturn ret = GST_FLOW_OK;
11850 GST_DEBUG_OBJECT (qtdemux, "prepare streams");
11852 for (i = 0; ret == GST_FLOW_OK && i < qtdemux->n_streams; i++) {
11853 QtDemuxStream *stream = qtdemux->streams[i];
11854 guint32 sample_num = 0;
11856 GST_DEBUG_OBJECT (qtdemux, "stream %d, id %d, fourcc %" GST_FOURCC_FORMAT,
11857 i, stream->track_id, GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
11859 if (qtdemux->fragmented) {
11860 /* need all moov samples first */
11861 GST_OBJECT_LOCK (qtdemux);
11862 while (stream->n_samples == 0)
11863 if ((ret = qtdemux_add_fragmented_samples (qtdemux)) != GST_FLOW_OK)
11865 GST_OBJECT_UNLOCK (qtdemux);
11867 /* discard any stray moof */
11868 qtdemux->moof_offset = 0;
11871 /* prepare braking */
11872 if (ret != GST_FLOW_ERROR)
11875 /* in pull mode, we should have parsed some sample info by now;
11876 * and quite some code will not handle no samples.
11877 * in push mode, we'll just have to deal with it */
11878 if (G_UNLIKELY (qtdemux->pullbased && !stream->n_samples)) {
11879 GST_DEBUG_OBJECT (qtdemux, "no samples for stream; discarding");
11880 gst_qtdemux_remove_stream (qtdemux, i);
11885 /* parse the initial sample for use in setting the frame rate cap */
11886 while (sample_num == 0 && sample_num < stream->n_samples) {
11887 if (!qtdemux_parse_samples (qtdemux, stream, sample_num))
11891 if (stream->n_samples > 0 && stream->stbl_index >= 0) {
11892 stream->first_duration = stream->samples[0].duration;
11893 GST_LOG_OBJECT (qtdemux, "stream %d first duration %u",
11894 stream->track_id, stream->first_duration);
11901 static GstFlowReturn
11902 qtdemux_expose_streams (GstQTDemux * qtdemux)
11905 GSList *oldpads = NULL;
11908 GST_DEBUG_OBJECT (qtdemux, "exposing streams");
11910 for (i = 0; i < qtdemux->n_streams; i++) {
11911 QtDemuxStream *stream = qtdemux->streams[i];
11912 GstPad *oldpad = stream->pad;
11915 GST_DEBUG_OBJECT (qtdemux, "stream %d, id %d, fourcc %" GST_FOURCC_FORMAT,
11916 i, stream->track_id, GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
11918 if ((stream->subtype == FOURCC_text || stream->subtype == FOURCC_sbtl) &&
11919 stream->track_id == qtdemux->chapters_track_id) {
11920 /* TODO - parse chapters track and expose it as GstToc; For now just ignore it
11921 so that it doesn't look like a subtitle track */
11922 gst_qtdemux_remove_stream (qtdemux, i);
11927 /* now we have all info and can expose */
11928 list = stream->stream_tags;
11929 stream->stream_tags = NULL;
11931 oldpads = g_slist_prepend (oldpads, oldpad);
11932 if (!gst_qtdemux_add_stream (qtdemux, stream, list))
11933 return GST_FLOW_ERROR;
11936 gst_qtdemux_guess_bitrate (qtdemux);
11938 gst_element_no_more_pads (GST_ELEMENT_CAST (qtdemux));
11940 for (iter = oldpads; iter; iter = g_slist_next (iter)) {
11941 GstPad *oldpad = iter->data;
11944 event = gst_event_new_eos ();
11945 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID)
11946 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
11948 gst_pad_push_event (oldpad, event);
11949 gst_pad_set_active (oldpad, FALSE);
11950 gst_element_remove_pad (GST_ELEMENT (qtdemux), oldpad);
11951 gst_flow_combiner_remove_pad (qtdemux->flowcombiner, oldpad);
11952 gst_object_unref (oldpad);
11955 /* check if we should post a redirect in case there is a single trak
11956 * and it is a redirecting trak */
11957 if (qtdemux->n_streams == 1 && qtdemux->streams[0]->redirect_uri != NULL) {
11960 GST_INFO_OBJECT (qtdemux, "Issuing a redirect due to a single track with "
11961 "an external content");
11962 m = gst_message_new_element (GST_OBJECT_CAST (qtdemux),
11963 gst_structure_new ("redirect",
11964 "new-location", G_TYPE_STRING, qtdemux->streams[0]->redirect_uri,
11966 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), m);
11967 qtdemux->posted_redirect = TRUE;
11970 for (i = 0; i < qtdemux->n_streams; i++) {
11971 QtDemuxStream *stream = qtdemux->streams[i];
11973 qtdemux_do_allocation (qtdemux, stream);
11976 qtdemux->exposed = TRUE;
11977 return GST_FLOW_OK;
11980 /* check if major or compatible brand is 3GP */
11981 static inline gboolean
11982 qtdemux_is_brand_3gp (GstQTDemux * qtdemux, gboolean major)
11985 return ((qtdemux->major_brand & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
11987 } else if (qtdemux->comp_brands != NULL) {
11991 gboolean res = FALSE;
11993 gst_buffer_map (qtdemux->comp_brands, &map, GST_MAP_READ);
11996 while (size >= 4) {
11997 res = res || ((QT_FOURCC (data) & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
12002 gst_buffer_unmap (qtdemux->comp_brands, &map);
12009 /* check if tag is a spec'ed 3GP tag keyword storing a string */
12010 static inline gboolean
12011 qtdemux_is_string_tag_3gp (GstQTDemux * qtdemux, guint32 fourcc)
12013 return fourcc == FOURCC_cprt || fourcc == FOURCC_gnre || fourcc == FOURCC_titl
12014 || fourcc == FOURCC_dscp || fourcc == FOURCC_perf || fourcc == FOURCC_auth
12015 || fourcc == FOURCC_albm;
12019 qtdemux_tag_add_location (GstQTDemux * qtdemux, GstTagList * taglist,
12020 const char *tag, const char *dummy, GNode * node)
12022 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
12026 gdouble longitude, latitude, altitude;
12029 len = QT_UINT32 (node->data);
12036 /* TODO: language code skipped */
12038 name = gst_tag_freeform_string_to_utf8 (data + offset, -1, env_vars);
12041 /* do not alarm in trivial case, but bail out otherwise */
12042 if (*(data + offset) != 0) {
12043 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8, "
12047 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
12048 GST_TAG_GEO_LOCATION_NAME, name, NULL);
12049 offset += strlen (name);
12053 if (len < offset + 2 + 4 + 4 + 4)
12056 /* +1 +1 = skip null-terminator and location role byte */
12058 /* table in spec says unsigned, semantics say negative has meaning ... */
12059 longitude = QT_SFP32 (data + offset);
12062 latitude = QT_SFP32 (data + offset);
12065 altitude = QT_SFP32 (data + offset);
12067 /* one invalid means all are invalid */
12068 if (longitude >= -180.0 && longitude <= 180.0 &&
12069 latitude >= -90.0 && latitude <= 90.0) {
12070 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
12071 GST_TAG_GEO_LOCATION_LATITUDE, latitude,
12072 GST_TAG_GEO_LOCATION_LONGITUDE, longitude,
12073 GST_TAG_GEO_LOCATION_ELEVATION, altitude, NULL);
12076 /* TODO: no GST_TAG_, so astronomical body and additional notes skipped */
12083 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP location");
12090 qtdemux_tag_add_year (GstQTDemux * qtdemux, GstTagList * taglist,
12091 const char *tag, const char *dummy, GNode * node)
12097 len = QT_UINT32 (node->data);
12101 y = QT_UINT16 ((guint8 *) node->data + 12);
12103 GST_DEBUG_OBJECT (qtdemux, "year: %u is not a valid year", y);
12106 GST_DEBUG_OBJECT (qtdemux, "year: %u", y);
12108 date = g_date_new_dmy (1, 1, y);
12109 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, date, NULL);
12110 g_date_free (date);
12114 qtdemux_tag_add_classification (GstQTDemux * qtdemux, GstTagList * taglist,
12115 const char *tag, const char *dummy, GNode * node)
12118 char *tag_str = NULL;
12123 len = QT_UINT32 (node->data);
12128 entity = (guint8 *) node->data + offset;
12129 if (entity[0] == 0 || entity[1] == 0 || entity[2] == 0 || entity[3] == 0) {
12130 GST_DEBUG_OBJECT (qtdemux,
12131 "classification info: %c%c%c%c invalid classification entity",
12132 entity[0], entity[1], entity[2], entity[3]);
12137 table = QT_UINT16 ((guint8 *) node->data + offset);
12139 /* Language code skipped */
12143 /* Tag format: "XXXX://Y[YYYY]/classification info string"
12144 * XXXX: classification entity, fixed length 4 chars.
12145 * Y[YYYY]: classification table, max 5 chars.
12147 tag_str = g_strdup_printf ("----://%u/%s",
12148 table, (char *) node->data + offset);
12150 /* memcpy To be sure we're preserving byte order */
12151 memcpy (tag_str, entity, 4);
12152 GST_DEBUG_OBJECT (qtdemux, "classification info: %s", tag_str);
12154 gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND, tag, tag_str, NULL);
12163 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP classification");
12169 qtdemux_tag_add_str_full (GstQTDemux * qtdemux, GstTagList * taglist,
12170 const char *tag, const char *dummy, GNode * node)
12172 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
12178 gboolean ret = TRUE;
12179 const gchar *charset = NULL;
12181 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12183 len = QT_UINT32 (data->data);
12184 type = QT_UINT32 ((guint8 *) data->data + 8);
12185 if (type == 0x00000001 && len > 16) {
12186 s = gst_tag_freeform_string_to_utf8 ((char *) data->data + 16, len - 16,
12189 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
12190 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, s, NULL);
12193 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
12197 len = QT_UINT32 (node->data);
12198 type = QT_UINT32 ((guint8 *) node->data + 4);
12199 if ((type >> 24) == 0xa9 && len > 8 + 4) {
12203 /* Type starts with the (C) symbol, so the next data is a list
12204 * of (string size(16), language code(16), string) */
12206 str_len = QT_UINT16 ((guint8 *) node->data + 8);
12207 lang_code = QT_UINT16 ((guint8 *) node->data + 10);
12209 /* the string + fourcc + size + 2 16bit fields,
12210 * means that there are more tags in this atom */
12211 if (len > str_len + 8 + 4) {
12212 /* TODO how to represent the same tag in different languages? */
12213 GST_WARNING_OBJECT (qtdemux, "Ignoring metadata entry with multiple "
12214 "text alternatives, reading only first one");
12218 len = MIN (len, str_len + 8 + 4); /* remove trailing strings that we don't use */
12219 GST_DEBUG_OBJECT (qtdemux, "found international text tag");
12221 if (lang_code < 0x800) { /* MAC encoded string */
12224 } else if (len > 14 && qtdemux_is_string_tag_3gp (qtdemux,
12225 QT_FOURCC ((guint8 *) node->data + 4))) {
12226 guint32 type = QT_UINT32 ((guint8 *) node->data + 8);
12228 /* we go for 3GP style encoding if major brands claims so,
12229 * or if no hope for data be ok UTF-8, and compatible 3GP brand present */
12230 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
12231 (qtdemux_is_brand_3gp (qtdemux, FALSE) &&
12232 ((type & 0x00FFFFFF) == 0x0) && (type >> 24 <= 0xF))) {
12234 /* 16-bit Language code is ignored here as well */
12235 GST_DEBUG_OBJECT (qtdemux, "found 3gpp text tag");
12242 GST_DEBUG_OBJECT (qtdemux, "found normal text tag");
12243 ret = FALSE; /* may have to fallback */
12246 GError *err = NULL;
12248 s = g_convert ((gchar *) node->data + offset, len - offset, "utf8",
12249 charset, NULL, NULL, &err);
12251 GST_DEBUG_OBJECT (qtdemux, "Failed to convert string from charset %s:"
12252 " %s(%d): %s", charset, g_quark_to_string (err->domain), err->code,
12254 g_error_free (err);
12257 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
12258 len - offset, env_vars);
12261 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
12262 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, s, NULL);
12266 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
12273 qtdemux_tag_add_str (GstQTDemux * qtdemux, GstTagList * taglist,
12274 const char *tag, const char *dummy, GNode * node)
12276 qtdemux_tag_add_str_full (qtdemux, taglist, tag, dummy, node);
12280 qtdemux_tag_add_keywords (GstQTDemux * qtdemux, GstTagList * taglist,
12281 const char *tag, const char *dummy, GNode * node)
12283 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
12285 char *s, *t, *k = NULL;
12290 /* first try normal string tag if major brand not 3GP */
12291 if (!qtdemux_is_brand_3gp (qtdemux, TRUE)) {
12292 if (!qtdemux_tag_add_str_full (qtdemux, taglist, tag, dummy, node)) {
12293 /* hm, that did not work, maybe 3gpp storage in non-3gpp major brand;
12294 * let's try it 3gpp way after minor safety check */
12296 if (QT_UINT32 (data) < 15 || !qtdemux_is_brand_3gp (qtdemux, FALSE))
12302 GST_DEBUG_OBJECT (qtdemux, "found 3gpp keyword tag");
12306 len = QT_UINT32 (data);
12310 count = QT_UINT8 (data + 14);
12312 for (; count; count--) {
12315 if (offset + 1 > len)
12317 slen = QT_UINT8 (data + offset);
12319 if (offset + slen > len)
12321 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
12324 GST_DEBUG_OBJECT (qtdemux, "adding keyword %s", GST_STR_NULL (s));
12326 t = g_strjoin (",", k, s, NULL);
12334 GST_DEBUG_OBJECT (qtdemux, "failed to convert keyword to UTF-8");
12341 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (k));
12342 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, k, NULL);
12351 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP keywords");
12357 qtdemux_tag_add_num (GstQTDemux * qtdemux, GstTagList * taglist,
12358 const char *tag1, const char *tag2, GNode * node)
12365 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12367 len = QT_UINT32 (data->data);
12368 type = QT_UINT32 ((guint8 *) data->data + 8);
12369 if (type == 0x00000000 && len >= 22) {
12370 n1 = QT_UINT16 ((guint8 *) data->data + 18);
12371 n2 = QT_UINT16 ((guint8 *) data->data + 20);
12373 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag1, n1);
12374 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, n1, NULL);
12377 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag2, n2);
12378 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag2, n2, NULL);
12385 qtdemux_tag_add_tmpo (GstQTDemux * qtdemux, GstTagList * taglist,
12386 const char *tag1, const char *dummy, GNode * node)
12393 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12395 len = QT_UINT32 (data->data);
12396 type = QT_UINT32 ((guint8 *) data->data + 8);
12397 GST_DEBUG_OBJECT (qtdemux, "have tempo tag, type=%d,len=%d", type, len);
12398 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
12399 if ((type == 0x00000015 || type == 0x0000000f) && len >= 18) {
12400 n1 = QT_UINT16 ((guint8 *) data->data + 16);
12402 /* do not add bpm=0 */
12403 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", n1);
12404 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, (gdouble) n1,
12412 qtdemux_tag_add_uint32 (GstQTDemux * qtdemux, GstTagList * taglist,
12413 const char *tag1, const char *dummy, GNode * node)
12420 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12422 len = QT_UINT32 (data->data);
12423 type = QT_UINT32 ((guint8 *) data->data + 8);
12424 GST_DEBUG_OBJECT (qtdemux, "have %s tag, type=%d,len=%d", tag1, type, len);
12425 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
12426 if ((type == 0x00000015 || type == 0x0000000f) && len >= 20) {
12427 num = QT_UINT32 ((guint8 *) data->data + 16);
12429 /* do not add num=0 */
12430 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", num);
12431 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, num, NULL);
12438 qtdemux_tag_add_covr (GstQTDemux * qtdemux, GstTagList * taglist,
12439 const char *tag1, const char *dummy, GNode * node)
12446 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12448 len = QT_UINT32 (data->data);
12449 type = QT_UINT32 ((guint8 *) data->data + 8);
12450 GST_DEBUG_OBJECT (qtdemux, "have covr tag, type=%d,len=%d", type, len);
12451 if ((type == 0x0000000d || type == 0x0000000e) && len > 16) {
12452 GstTagImageType image_type;
12454 if (gst_tag_list_get_tag_size (taglist, GST_TAG_IMAGE) == 0)
12455 image_type = GST_TAG_IMAGE_TYPE_FRONT_COVER;
12457 image_type = GST_TAG_IMAGE_TYPE_NONE;
12460 gst_tag_image_data_to_image_sample ((guint8 *) data->data + 16,
12461 len - 16, image_type))) {
12462 GST_DEBUG_OBJECT (qtdemux, "adding tag size %d", len - 16);
12463 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, sample, NULL);
12464 gst_sample_unref (sample);
12471 qtdemux_tag_add_date (GstQTDemux * qtdemux, GstTagList * taglist,
12472 const char *tag, const char *dummy, GNode * node)
12479 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12481 len = QT_UINT32 (data->data);
12482 type = QT_UINT32 ((guint8 *) data->data + 8);
12483 if (type == 0x00000001 && len > 16) {
12484 guint y, m = 1, d = 1;
12487 s = g_strndup ((char *) data->data + 16, len - 16);
12488 GST_DEBUG_OBJECT (qtdemux, "adding date '%s'", s);
12489 ret = sscanf (s, "%u-%u-%u", &y, &m, &d);
12490 if (ret >= 1 && y > 1500 && y < 3000) {
12493 date = g_date_new_dmy (d, m, y);
12494 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, date, NULL);
12495 g_date_free (date);
12497 GST_DEBUG_OBJECT (qtdemux, "could not parse date string '%s'", s);
12505 qtdemux_tag_add_gnre (GstQTDemux * qtdemux, GstTagList * taglist,
12506 const char *tag, const char *dummy, GNode * node)
12510 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12512 /* re-route to normal string tag if major brand says so
12513 * or no data atom and compatible brand suggests so */
12514 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
12515 (qtdemux_is_brand_3gp (qtdemux, FALSE) && !data)) {
12516 qtdemux_tag_add_str (qtdemux, taglist, tag, dummy, node);
12521 guint len, type, n;
12523 len = QT_UINT32 (data->data);
12524 type = QT_UINT32 ((guint8 *) data->data + 8);
12525 if (type == 0x00000000 && len >= 18) {
12526 n = QT_UINT16 ((guint8 *) data->data + 16);
12528 const gchar *genre;
12530 genre = gst_tag_id3_genre_get (n - 1);
12531 if (genre != NULL) {
12532 GST_DEBUG_OBJECT (qtdemux, "adding %d [%s]", n, genre);
12533 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, genre, NULL);
12541 qtdemux_add_double_tag_from_str (GstQTDemux * demux, GstTagList * taglist,
12542 const gchar * tag, guint8 * data, guint32 datasize)
12547 /* make a copy to have \0 at the end */
12548 datacopy = g_strndup ((gchar *) data, datasize);
12550 /* convert the str to double */
12551 if (sscanf (datacopy, "%lf", &value) == 1) {
12552 GST_DEBUG_OBJECT (demux, "adding tag: %s [%s]", tag, datacopy);
12553 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, value, NULL);
12555 GST_WARNING_OBJECT (demux, "Failed to parse double from string: %s",
12563 qtdemux_tag_add_revdns (GstQTDemux * demux, GstTagList * taglist,
12564 const char *tag, const char *tag_bis, GNode * node)
12573 const gchar *meanstr;
12574 const gchar *namestr;
12576 /* checking the whole ---- atom size for consistency */
12577 if (QT_UINT32 (node->data) <= 4 + 12 + 12 + 16) {
12578 GST_WARNING_OBJECT (demux, "Tag ---- atom is too small, ignoring");
12582 mean = qtdemux_tree_get_child_by_type (node, FOURCC_mean);
12584 GST_WARNING_OBJECT (demux, "No 'mean' atom found");
12588 meansize = QT_UINT32 (mean->data);
12589 if (meansize <= 12) {
12590 GST_WARNING_OBJECT (demux, "Small mean atom, ignoring the whole tag");
12593 meanstr = ((gchar *) mean->data) + 12;
12596 name = qtdemux_tree_get_child_by_type (node, FOURCC_name);
12598 GST_WARNING_OBJECT (demux, "'name' atom not found, ignoring tag");
12602 namesize = QT_UINT32 (name->data);
12603 if (namesize <= 12) {
12604 GST_WARNING_OBJECT (demux, "'name' atom is too small, ignoring tag");
12607 namestr = ((gchar *) name->data) + 12;
12615 * uint24 - data type
12619 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12621 GST_WARNING_OBJECT (demux, "No data atom in this tag");
12624 datasize = QT_UINT32 (data->data);
12625 if (datasize <= 16) {
12626 GST_WARNING_OBJECT (demux, "Data atom too small");
12629 datatype = QT_UINT32 (((gchar *) data->data) + 8) & 0xFFFFFF;
12631 if ((strncmp (meanstr, "com.apple.iTunes", meansize) == 0) ||
12632 (strncmp (meanstr, "org.hydrogenaudio.replaygain", meansize) == 0)) {
12633 static const struct
12635 const gchar name[28];
12636 const gchar tag[28];
12639 "replaygain_track_gain", GST_TAG_TRACK_GAIN}, {
12640 "replaygain_track_peak", GST_TAG_TRACK_PEAK}, {
12641 "replaygain_album_gain", GST_TAG_ALBUM_GAIN}, {
12642 "replaygain_album_peak", GST_TAG_ALBUM_PEAK}, {
12643 "MusicBrainz Track Id", GST_TAG_MUSICBRAINZ_TRACKID}, {
12644 "MusicBrainz Artist Id", GST_TAG_MUSICBRAINZ_ARTISTID}, {
12645 "MusicBrainz Album Id", GST_TAG_MUSICBRAINZ_ALBUMID}, {
12646 "MusicBrainz Album Artist Id", GST_TAG_MUSICBRAINZ_ALBUMARTISTID}
12650 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
12651 if (!g_ascii_strncasecmp (tags[i].name, namestr, namesize)) {
12652 switch (gst_tag_get_type (tags[i].tag)) {
12653 case G_TYPE_DOUBLE:
12654 qtdemux_add_double_tag_from_str (demux, taglist, tags[i].tag,
12655 ((guint8 *) data->data) + 16, datasize - 16);
12657 case G_TYPE_STRING:
12658 qtdemux_tag_add_str (demux, taglist, tags[i].tag, NULL, node);
12667 if (i == G_N_ELEMENTS (tags))
12677 #ifndef GST_DISABLE_GST_DEBUG
12679 gchar *namestr_dbg;
12680 gchar *meanstr_dbg;
12682 meanstr_dbg = g_strndup (meanstr, meansize);
12683 namestr_dbg = g_strndup (namestr, namesize);
12685 GST_WARNING_OBJECT (demux, "This tag %s:%s type:%u is not mapped, "
12686 "file a bug at bugzilla.gnome.org", meanstr_dbg, namestr_dbg, datatype);
12688 g_free (namestr_dbg);
12689 g_free (meanstr_dbg);
12696 qtdemux_tag_add_id32 (GstQTDemux * demux, GstTagList * taglist, const char *tag,
12697 const char *tag_bis, GNode * node)
12702 GstTagList *id32_taglist = NULL;
12704 GST_LOG_OBJECT (demux, "parsing ID32");
12707 len = GST_READ_UINT32_BE (data);
12709 /* need at least full box and language tag */
12713 buf = gst_buffer_new_allocate (NULL, len - 14, NULL);
12714 gst_buffer_fill (buf, 0, data + 14, len - 14);
12716 id32_taglist = gst_tag_list_from_id3v2_tag (buf);
12717 if (id32_taglist) {
12718 GST_LOG_OBJECT (demux, "parsing ok");
12719 gst_tag_list_insert (taglist, id32_taglist, GST_TAG_MERGE_KEEP);
12720 gst_tag_list_unref (id32_taglist);
12722 GST_LOG_OBJECT (demux, "parsing failed");
12725 gst_buffer_unref (buf);
12728 typedef void (*GstQTDemuxAddTagFunc) (GstQTDemux * demux, GstTagList * taglist,
12729 const char *tag, const char *tag_bis, GNode * node);
12732 FOURCC_pcst -> if media is a podcast -> bool
12733 FOURCC_cpil -> if media is part of a compilation -> bool
12734 FOURCC_pgap -> if media is part of a gapless context -> bool
12735 FOURCC_tven -> the tv episode id e.g. S01E23 -> str
12738 static const struct
12741 const gchar *gst_tag;
12742 const gchar *gst_tag_bis;
12743 const GstQTDemuxAddTagFunc func;
12746 FOURCC__nam, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
12747 FOURCC_titl, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
12748 FOURCC__grp, GST_TAG_GROUPING, NULL, qtdemux_tag_add_str}, {
12749 FOURCC__wrt, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
12750 FOURCC__ART, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
12751 FOURCC_aART, GST_TAG_ALBUM_ARTIST, NULL, qtdemux_tag_add_str}, {
12752 FOURCC_perf, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
12753 FOURCC_auth, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
12754 FOURCC__alb, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
12755 FOURCC_albm, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
12756 FOURCC_cprt, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
12757 FOURCC__cpy, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
12758 FOURCC__cmt, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
12759 FOURCC__des, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
12760 FOURCC_desc, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
12761 FOURCC_dscp, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
12762 FOURCC__lyr, GST_TAG_LYRICS, NULL, qtdemux_tag_add_str}, {
12763 FOURCC__day, GST_TAG_DATE, NULL, qtdemux_tag_add_date}, {
12764 FOURCC_yrrc, GST_TAG_DATE, NULL, qtdemux_tag_add_year}, {
12765 FOURCC__too, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
12766 FOURCC__inf, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
12767 FOURCC_trkn, GST_TAG_TRACK_NUMBER, GST_TAG_TRACK_COUNT, qtdemux_tag_add_num}, {
12768 FOURCC_disk, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
12769 qtdemux_tag_add_num}, {
12770 FOURCC_disc, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
12771 qtdemux_tag_add_num}, {
12772 FOURCC__gen, GST_TAG_GENRE, NULL, qtdemux_tag_add_str}, {
12773 FOURCC_gnre, GST_TAG_GENRE, NULL, qtdemux_tag_add_gnre}, {
12774 FOURCC_tmpo, GST_TAG_BEATS_PER_MINUTE, NULL, qtdemux_tag_add_tmpo}, {
12775 FOURCC_covr, GST_TAG_IMAGE, NULL, qtdemux_tag_add_covr}, {
12776 FOURCC_sonm, GST_TAG_TITLE_SORTNAME, NULL, qtdemux_tag_add_str}, {
12777 FOURCC_soal, GST_TAG_ALBUM_SORTNAME, NULL, qtdemux_tag_add_str}, {
12778 FOURCC_soar, GST_TAG_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
12779 FOURCC_soaa, GST_TAG_ALBUM_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
12780 FOURCC_soco, GST_TAG_COMPOSER_SORTNAME, NULL, qtdemux_tag_add_str}, {
12781 FOURCC_sosn, GST_TAG_SHOW_SORTNAME, NULL, qtdemux_tag_add_str}, {
12782 FOURCC_tvsh, GST_TAG_SHOW_NAME, NULL, qtdemux_tag_add_str}, {
12783 FOURCC_tvsn, GST_TAG_SHOW_SEASON_NUMBER, NULL, qtdemux_tag_add_uint32}, {
12784 FOURCC_tves, GST_TAG_SHOW_EPISODE_NUMBER, NULL, qtdemux_tag_add_uint32}, {
12785 FOURCC_kywd, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_keywords}, {
12786 FOURCC_keyw, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_str}, {
12787 FOURCC__enc, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
12788 FOURCC_loci, GST_TAG_GEO_LOCATION_NAME, NULL, qtdemux_tag_add_location}, {
12789 FOURCC_clsf, GST_QT_DEMUX_CLASSIFICATION_TAG, NULL,
12790 qtdemux_tag_add_classification}, {
12791 FOURCC__mak, GST_TAG_DEVICE_MANUFACTURER, NULL, qtdemux_tag_add_str}, {
12792 FOURCC__mod, GST_TAG_DEVICE_MODEL, NULL, qtdemux_tag_add_str}, {
12793 FOURCC__swr, GST_TAG_APPLICATION_NAME, NULL, qtdemux_tag_add_str}, {
12795 /* This is a special case, some tags are stored in this
12796 * 'reverse dns naming', according to:
12797 * http://atomicparsley.sourceforge.net/mpeg-4files.html and
12800 FOURCC_____, "", NULL, qtdemux_tag_add_revdns}, {
12801 /* see http://www.mp4ra.org/specs.html for ID32 in meta box */
12802 FOURCC_ID32, "", NULL, qtdemux_tag_add_id32}
12805 struct _GstQtDemuxTagList
12808 GstTagList *taglist;
12810 typedef struct _GstQtDemuxTagList GstQtDemuxTagList;
12813 qtdemux_tag_add_blob (GNode * node, GstQtDemuxTagList * qtdemuxtaglist)
12819 const gchar *style;
12824 GstQTDemux *demux = qtdemuxtaglist->demux;
12825 GstTagList *taglist = qtdemuxtaglist->taglist;
12828 len = QT_UINT32 (data);
12829 buf = gst_buffer_new_and_alloc (len);
12830 gst_buffer_fill (buf, 0, data, len);
12832 /* heuristic to determine style of tag */
12833 if (QT_FOURCC (data + 4) == FOURCC_____ ||
12834 (len > 8 + 12 && QT_FOURCC (data + 12) == FOURCC_data))
12836 else if (demux->major_brand == FOURCC_qt__)
12837 style = "quicktime";
12838 /* fall back to assuming iso/3gp tag style */
12842 /* santize the name for the caps. */
12843 for (i = 0; i < 4; i++) {
12844 guint8 d = data[4 + i];
12845 if (g_ascii_isalnum (d))
12846 ndata[i] = g_ascii_tolower (d);
12851 media_type = g_strdup_printf ("application/x-gst-qt-%c%c%c%c-tag",
12852 ndata[0], ndata[1], ndata[2], ndata[3]);
12853 GST_DEBUG_OBJECT (demux, "media type %s", media_type);
12855 s = gst_structure_new (media_type, "style", G_TYPE_STRING, style, NULL);
12856 sample = gst_sample_new (buf, NULL, NULL, s);
12857 gst_buffer_unref (buf);
12858 g_free (media_type);
12860 GST_DEBUG_OBJECT (demux, "adding private tag; size %d, info %" GST_PTR_FORMAT,
12863 gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND,
12864 GST_QT_DEMUX_PRIVATE_TAG, sample, NULL);
12866 gst_sample_unref (sample);
12870 qtdemux_parse_udta (GstQTDemux * qtdemux, GstTagList * taglist, GNode * udta)
12877 GstQtDemuxTagList demuxtaglist;
12879 demuxtaglist.demux = qtdemux;
12880 demuxtaglist.taglist = taglist;
12882 meta = qtdemux_tree_get_child_by_type (udta, FOURCC_meta);
12883 if (meta != NULL) {
12884 ilst = qtdemux_tree_get_child_by_type (meta, FOURCC_ilst);
12885 if (ilst == NULL) {
12886 GST_LOG_OBJECT (qtdemux, "no ilst");
12891 GST_LOG_OBJECT (qtdemux, "no meta so using udta itself");
12895 while (i < G_N_ELEMENTS (add_funcs)) {
12896 node = qtdemux_tree_get_child_by_type (ilst, add_funcs[i].fourcc);
12900 len = QT_UINT32 (node->data);
12902 GST_DEBUG_OBJECT (qtdemux, "too small tag atom %" GST_FOURCC_FORMAT,
12903 GST_FOURCC_ARGS (add_funcs[i].fourcc));
12905 add_funcs[i].func (qtdemux, taglist, add_funcs[i].gst_tag,
12906 add_funcs[i].gst_tag_bis, node);
12908 g_node_destroy (node);
12914 /* parsed nodes have been removed, pass along remainder as blob */
12915 g_node_children_foreach (ilst, G_TRAVERSE_ALL,
12916 (GNodeForeachFunc) qtdemux_tag_add_blob, &demuxtaglist);
12918 /* parse up XMP_ node if existing */
12919 xmp_ = qtdemux_tree_get_child_by_type (udta, FOURCC_XMP_);
12920 if (xmp_ != NULL) {
12922 GstTagList *xmptaglist;
12924 buf = _gst_buffer_new_wrapped (((guint8 *) xmp_->data) + 8,
12925 QT_UINT32 ((guint8 *) xmp_->data) - 8, NULL);
12926 xmptaglist = gst_tag_list_from_xmp_buffer (buf);
12927 gst_buffer_unref (buf);
12929 qtdemux_handle_xmp_taglist (qtdemux, taglist, xmptaglist);
12931 GST_DEBUG_OBJECT (qtdemux, "No XMP_ node found");
12937 GstStructure *structure; /* helper for sort function */
12939 guint min_req_bitrate;
12940 guint min_req_qt_version;
12944 qtdemux_redirects_sort_func (gconstpointer a, gconstpointer b)
12946 GstQtReference *ref_a = (GstQtReference *) a;
12947 GstQtReference *ref_b = (GstQtReference *) b;
12949 if (ref_b->min_req_qt_version != ref_a->min_req_qt_version)
12950 return ref_b->min_req_qt_version - ref_a->min_req_qt_version;
12952 /* known bitrates go before unknown; higher bitrates go first */
12953 return ref_b->min_req_bitrate - ref_a->min_req_bitrate;
12956 /* sort the redirects and post a message for the application.
12959 qtdemux_process_redirects (GstQTDemux * qtdemux, GList * references)
12961 GstQtReference *best;
12964 GValue list_val = { 0, };
12967 g_assert (references != NULL);
12969 references = g_list_sort (references, qtdemux_redirects_sort_func);
12971 best = (GstQtReference *) references->data;
12973 g_value_init (&list_val, GST_TYPE_LIST);
12975 for (l = references; l != NULL; l = l->next) {
12976 GstQtReference *ref = (GstQtReference *) l->data;
12977 GValue struct_val = { 0, };
12979 ref->structure = gst_structure_new ("redirect",
12980 "new-location", G_TYPE_STRING, ref->location, NULL);
12982 if (ref->min_req_bitrate > 0) {
12983 gst_structure_set (ref->structure, "minimum-bitrate", G_TYPE_INT,
12984 ref->min_req_bitrate, NULL);
12987 g_value_init (&struct_val, GST_TYPE_STRUCTURE);
12988 g_value_set_boxed (&struct_val, ref->structure);
12989 gst_value_list_append_value (&list_val, &struct_val);
12990 g_value_unset (&struct_val);
12991 /* don't free anything here yet, since we need best->structure below */
12994 g_assert (best != NULL);
12995 s = gst_structure_copy (best->structure);
12997 if (g_list_length (references) > 1) {
12998 gst_structure_set_value (s, "locations", &list_val);
13001 g_value_unset (&list_val);
13003 for (l = references; l != NULL; l = l->next) {
13004 GstQtReference *ref = (GstQtReference *) l->data;
13006 gst_structure_free (ref->structure);
13007 g_free (ref->location);
13010 g_list_free (references);
13012 GST_INFO_OBJECT (qtdemux, "posting redirect message: %" GST_PTR_FORMAT, s);
13013 msg = gst_message_new_element (GST_OBJECT_CAST (qtdemux), s);
13014 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
13015 qtdemux->posted_redirect = TRUE;
13018 /* look for redirect nodes, collect all redirect information and
13022 qtdemux_parse_redirects (GstQTDemux * qtdemux)
13024 GNode *rmra, *rmda, *rdrf;
13026 rmra = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_rmra);
13028 GList *redirects = NULL;
13030 rmda = qtdemux_tree_get_child_by_type (rmra, FOURCC_rmda);
13032 GstQtReference ref = { NULL, NULL, 0, 0 };
13033 GNode *rmdr, *rmvc;
13035 if ((rmdr = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmdr))) {
13036 ref.min_req_bitrate = QT_UINT32 ((guint8 *) rmdr->data + 12);
13037 GST_LOG_OBJECT (qtdemux, "data rate atom, required bitrate = %u",
13038 ref.min_req_bitrate);
13041 if ((rmvc = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmvc))) {
13042 guint32 package = QT_FOURCC ((guint8 *) rmvc->data + 12);
13043 guint version = QT_UINT32 ((guint8 *) rmvc->data + 16);
13045 #ifndef GST_DISABLE_GST_DEBUG
13046 guint bitmask = QT_UINT32 ((guint8 *) rmvc->data + 20);
13048 guint check_type = QT_UINT16 ((guint8 *) rmvc->data + 24);
13050 GST_LOG_OBJECT (qtdemux,
13051 "version check atom [%" GST_FOURCC_FORMAT "], version=0x%08x"
13052 ", mask=%08x, check_type=%u", GST_FOURCC_ARGS (package), version,
13053 bitmask, check_type);
13054 if (package == FOURCC_qtim && check_type == 0) {
13055 ref.min_req_qt_version = version;
13059 rdrf = qtdemux_tree_get_child_by_type (rmda, FOURCC_rdrf);
13065 ref_len = QT_UINT32 ((guint8 *) rdrf->data);
13066 if (ref_len > 20) {
13067 ref_type = QT_FOURCC ((guint8 *) rdrf->data + 12);
13068 ref_data = (guint8 *) rdrf->data + 20;
13069 if (ref_type == FOURCC_alis) {
13070 guint record_len, record_version, fn_len;
13072 if (ref_len > 70) {
13073 /* MacOSX alias record, google for alias-layout.txt */
13074 record_len = QT_UINT16 (ref_data + 4);
13075 record_version = QT_UINT16 (ref_data + 4 + 2);
13076 fn_len = QT_UINT8 (ref_data + 50);
13077 if (record_len > 50 && record_version == 2 && fn_len > 0) {
13078 ref.location = g_strndup ((gchar *) ref_data + 51, fn_len);
13081 GST_WARNING_OBJECT (qtdemux, "Invalid rdrf/alis size (%u < 70)",
13084 } else if (ref_type == FOURCC_url_) {
13085 ref.location = g_strndup ((gchar *) ref_data, ref_len - 8);
13087 GST_DEBUG_OBJECT (qtdemux,
13088 "unknown rdrf reference type %" GST_FOURCC_FORMAT,
13089 GST_FOURCC_ARGS (ref_type));
13091 if (ref.location != NULL) {
13092 GST_INFO_OBJECT (qtdemux, "New location: %s", ref.location);
13094 g_list_prepend (redirects, g_memdup (&ref, sizeof (ref)));
13096 GST_WARNING_OBJECT (qtdemux,
13097 "Failed to extract redirect location from rdrf atom");
13100 GST_WARNING_OBJECT (qtdemux, "Invalid rdrf size (%u < 20)", ref_len);
13104 /* look for others */
13105 rmda = qtdemux_tree_get_sibling_by_type (rmda, FOURCC_rmda);
13108 if (redirects != NULL) {
13109 qtdemux_process_redirects (qtdemux, redirects);
13115 static GstTagList *
13116 qtdemux_add_container_format (GstQTDemux * qtdemux, GstTagList * tags)
13120 if (tags == NULL) {
13121 tags = gst_tag_list_new_empty ();
13122 gst_tag_list_set_scope (tags, GST_TAG_SCOPE_GLOBAL);
13125 if (qtdemux->major_brand == FOURCC_mjp2)
13126 fmt = "Motion JPEG 2000";
13127 else if ((qtdemux->major_brand & 0xffff) == FOURCC_3g__)
13129 else if (qtdemux->major_brand == FOURCC_qt__)
13131 else if (qtdemux->fragmented)
13134 fmt = "ISO MP4/M4A";
13136 GST_LOG_OBJECT (qtdemux, "mapped %" GST_FOURCC_FORMAT " to '%s'",
13137 GST_FOURCC_ARGS (qtdemux->major_brand), fmt);
13139 gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_CONTAINER_FORMAT,
13145 /* we have read the complete moov node now.
13146 * This function parses all of the relevant info, creates the traks and
13147 * prepares all data structures for playback
13150 qtdemux_parse_tree (GstQTDemux * qtdemux)
13156 GstClockTime duration;
13158 guint64 creation_time;
13159 GstDateTime *datetime = NULL;
13162 /* make sure we have a usable taglist */
13163 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
13165 mvhd = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvhd);
13166 if (mvhd == NULL) {
13167 GST_LOG_OBJECT (qtdemux, "No mvhd node found, looking for redirects.");
13168 return qtdemux_parse_redirects (qtdemux);
13171 version = QT_UINT8 ((guint8 *) mvhd->data + 8);
13172 if (version == 1) {
13173 creation_time = QT_UINT64 ((guint8 *) mvhd->data + 12);
13174 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 28);
13175 qtdemux->duration = QT_UINT64 ((guint8 *) mvhd->data + 32);
13176 } else if (version == 0) {
13177 creation_time = QT_UINT32 ((guint8 *) mvhd->data + 12);
13178 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 20);
13179 qtdemux->duration = QT_UINT32 ((guint8 *) mvhd->data + 24);
13181 GST_WARNING_OBJECT (qtdemux, "Unhandled mvhd version %d", version);
13185 /* Moving qt creation time (secs since 1904) to unix time */
13186 if (creation_time != 0) {
13187 /* Try to use epoch first as it should be faster and more commonly found */
13188 if (creation_time >= QTDEMUX_SECONDS_FROM_1904_TO_1970) {
13191 creation_time -= QTDEMUX_SECONDS_FROM_1904_TO_1970;
13192 /* some data cleansing sanity */
13193 g_get_current_time (&now);
13194 if (now.tv_sec + 24 * 3600 < creation_time) {
13195 GST_DEBUG_OBJECT (qtdemux, "discarding bogus future creation time");
13197 datetime = gst_date_time_new_from_unix_epoch_utc (creation_time);
13200 GDateTime *base_dt = g_date_time_new_utc (1904, 1, 1, 0, 0, 0);
13201 GDateTime *dt, *dt_local;
13203 dt = g_date_time_add_seconds (base_dt, creation_time);
13204 dt_local = g_date_time_to_local (dt);
13205 datetime = gst_date_time_new_from_g_date_time (dt_local);
13207 g_date_time_unref (base_dt);
13208 g_date_time_unref (dt);
13212 /* Use KEEP as explicit tags should have a higher priority than mvhd tag */
13213 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_KEEP, GST_TAG_DATE_TIME,
13215 gst_date_time_unref (datetime);
13218 GST_INFO_OBJECT (qtdemux, "timescale: %u", qtdemux->timescale);
13219 GST_INFO_OBJECT (qtdemux, "duration: %" G_GUINT64_FORMAT, qtdemux->duration);
13221 /* check for fragmented file and get some (default) data */
13222 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
13225 GstByteReader mehd_data;
13227 /* let track parsing or anyone know weird stuff might happen ... */
13228 qtdemux->fragmented = TRUE;
13230 /* compensate for total duration */
13231 mehd = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_mehd, &mehd_data);
13233 qtdemux_parse_mehd (qtdemux, &mehd_data);
13236 /* set duration in the segment info */
13237 gst_qtdemux_get_duration (qtdemux, &duration);
13239 qtdemux->segment.duration = duration;
13240 /* also do not exceed duration; stop is set that way post seek anyway,
13241 * and segment activation falls back to duration,
13242 * whereas loop only checks stop, so let's align this here as well */
13243 qtdemux->segment.stop = duration;
13246 /* parse all traks */
13247 trak = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_trak);
13249 qtdemux_parse_trak (qtdemux, trak);
13250 /* iterate all siblings */
13251 trak = qtdemux_tree_get_sibling_by_type (trak, FOURCC_trak);
13254 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
13257 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_udta);
13259 qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
13261 GST_LOG_OBJECT (qtdemux, "No udta node found.");
13264 /* maybe also some tags in meta box */
13265 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_meta);
13267 GST_DEBUG_OBJECT (qtdemux, "Parsing meta box for tags.");
13268 qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
13270 GST_LOG_OBJECT (qtdemux, "No meta node found.");
13273 /* parse any protection system info */
13274 pssh = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_pssh);
13276 GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
13277 qtdemux_parse_pssh (qtdemux, pssh);
13278 pssh = qtdemux_tree_get_sibling_by_type (pssh, FOURCC_pssh);
13281 qtdemux->tag_list = qtdemux_add_container_format (qtdemux, qtdemux->tag_list);
13286 /* taken from ffmpeg */
13288 read_descr_size (guint8 * ptr, guint8 * end, guint8 ** end_out)
13300 len = (len << 7) | (c & 0x7f);
13308 /* this can change the codec originally present in @list */
13310 gst_qtdemux_handle_esds (GstQTDemux * qtdemux, QtDemuxStream * stream,
13311 QtDemuxStreamStsdEntry * entry, GNode * esds, GstTagList * list)
13313 int len = QT_UINT32 (esds->data);
13314 guint8 *ptr = esds->data;
13315 guint8 *end = ptr + len;
13317 guint8 *data_ptr = NULL;
13319 guint8 object_type_id = 0;
13320 const char *codec_name = NULL;
13321 GstCaps *caps = NULL;
13323 GST_MEMDUMP_OBJECT (qtdemux, "esds", ptr, len);
13325 GST_DEBUG_OBJECT (qtdemux, "version/flags = %08x", QT_UINT32 (ptr));
13327 while (ptr + 1 < end) {
13328 tag = QT_UINT8 (ptr);
13329 GST_DEBUG_OBJECT (qtdemux, "tag = %02x", tag);
13331 len = read_descr_size (ptr, end, &ptr);
13332 GST_DEBUG_OBJECT (qtdemux, "len = %d", len);
13334 /* Check the stated amount of data is available for reading */
13335 if (len < 0 || ptr + len > end)
13339 case ES_DESCRIPTOR_TAG:
13340 GST_DEBUG_OBJECT (qtdemux, "ID %04x", QT_UINT16 (ptr));
13341 GST_DEBUG_OBJECT (qtdemux, "priority %04x", QT_UINT8 (ptr + 2));
13344 case DECODER_CONFIG_DESC_TAG:{
13345 guint max_bitrate, avg_bitrate;
13347 object_type_id = QT_UINT8 (ptr);
13348 max_bitrate = QT_UINT32 (ptr + 5);
13349 avg_bitrate = QT_UINT32 (ptr + 9);
13350 GST_DEBUG_OBJECT (qtdemux, "object_type_id %02x", object_type_id);
13351 GST_DEBUG_OBJECT (qtdemux, "stream_type %02x", QT_UINT8 (ptr + 1));
13352 GST_DEBUG_OBJECT (qtdemux, "buffer_size_db %02x", QT_UINT24 (ptr + 2));
13353 GST_DEBUG_OBJECT (qtdemux, "max bitrate %u", max_bitrate);
13354 GST_DEBUG_OBJECT (qtdemux, "avg bitrate %u", avg_bitrate);
13355 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
13356 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
13357 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
13359 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
13360 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
13361 avg_bitrate, NULL);
13366 case DECODER_SPECIFIC_INFO_TAG:
13367 GST_MEMDUMP_OBJECT (qtdemux, "data", ptr, len);
13368 if (object_type_id == 0xe0 && len == 0x40) {
13374 GST_DEBUG_OBJECT (qtdemux,
13375 "Have VOBSUB palette. Creating palette event");
13376 /* move to decConfigDescr data and read palette */
13378 for (i = 0; i < 16; i++) {
13379 clut[i] = QT_UINT32 (data);
13383 s = gst_structure_new ("application/x-gst-dvd", "event",
13384 G_TYPE_STRING, "dvd-spu-clut-change",
13385 "clut00", G_TYPE_INT, clut[0], "clut01", G_TYPE_INT, clut[1],
13386 "clut02", G_TYPE_INT, clut[2], "clut03", G_TYPE_INT, clut[3],
13387 "clut04", G_TYPE_INT, clut[4], "clut05", G_TYPE_INT, clut[5],
13388 "clut06", G_TYPE_INT, clut[6], "clut07", G_TYPE_INT, clut[7],
13389 "clut08", G_TYPE_INT, clut[8], "clut09", G_TYPE_INT, clut[9],
13390 "clut10", G_TYPE_INT, clut[10], "clut11", G_TYPE_INT, clut[11],
13391 "clut12", G_TYPE_INT, clut[12], "clut13", G_TYPE_INT, clut[13],
13392 "clut14", G_TYPE_INT, clut[14], "clut15", G_TYPE_INT, clut[15],
13395 /* store event and trigger custom processing */
13396 stream->pending_event =
13397 gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s);
13399 /* Generic codec_data handler puts it on the caps */
13406 case SL_CONFIG_DESC_TAG:
13407 GST_DEBUG_OBJECT (qtdemux, "data %02x", QT_UINT8 (ptr));
13411 GST_DEBUG_OBJECT (qtdemux, "Unknown/unhandled descriptor tag %02x",
13413 GST_MEMDUMP_OBJECT (qtdemux, "descriptor data", ptr, len);
13419 /* object_type_id in the esds atom in mp4a and mp4v tells us which codec is
13420 * in use, and should also be used to override some other parameters for some
13422 switch (object_type_id) {
13423 case 0x20: /* MPEG-4 */
13424 /* 4 bytes for the visual_object_sequence_start_code and 1 byte for the
13425 * profile_and_level_indication */
13426 if (data_ptr != NULL && data_len >= 5 &&
13427 GST_READ_UINT32_BE (data_ptr) == 0x000001b0) {
13428 gst_codec_utils_mpeg4video_caps_set_level_and_profile (entry->caps,
13429 data_ptr + 4, data_len - 4);
13431 break; /* Nothing special needed here */
13432 case 0x21: /* H.264 */
13433 codec_name = "H.264 / AVC";
13434 caps = gst_caps_new_simple ("video/x-h264",
13435 "stream-format", G_TYPE_STRING, "avc",
13436 "alignment", G_TYPE_STRING, "au", NULL);
13438 case 0x40: /* AAC (any) */
13439 case 0x66: /* AAC Main */
13440 case 0x67: /* AAC LC */
13441 case 0x68: /* AAC SSR */
13442 /* Override channels and rate based on the codec_data, as it's often
13444 /* Only do so for basic setup without HE-AAC extension */
13445 if (data_ptr && data_len == 2) {
13446 guint channels, rate;
13448 channels = gst_codec_utils_aac_get_channels (data_ptr, data_len);
13450 entry->n_channels = channels;
13452 rate = gst_codec_utils_aac_get_sample_rate (data_ptr, data_len);
13454 entry->rate = rate;
13457 /* Set level and profile if possible */
13458 if (data_ptr != NULL && data_len >= 2) {
13459 gst_codec_utils_aac_caps_set_level_and_profile (entry->caps,
13460 data_ptr, data_len);
13462 const gchar *profile_str = NULL;
13465 guint8 *codec_data;
13466 gint rate_idx, profile;
13468 /* No codec_data, let's invent something.
13469 * FIXME: This is wrong for SBR! */
13471 GST_WARNING_OBJECT (qtdemux, "No codec_data for AAC available");
13473 buffer = gst_buffer_new_and_alloc (2);
13474 gst_buffer_map (buffer, &map, GST_MAP_WRITE);
13475 codec_data = map.data;
13478 gst_codec_utils_aac_get_index_from_sample_rate (CUR_STREAM
13481 switch (object_type_id) {
13483 profile_str = "main";
13487 profile_str = "lc";
13491 profile_str = "ssr";
13499 codec_data[0] = ((profile + 1) << 3) | ((rate_idx & 0xE) >> 1);
13501 ((rate_idx & 0x1) << 7) | (CUR_STREAM (stream)->n_channels << 3);
13503 gst_buffer_unmap (buffer, &map);
13504 gst_caps_set_simple (CUR_STREAM (stream)->caps, "codec_data",
13505 GST_TYPE_BUFFER, buffer, NULL);
13506 gst_buffer_unref (buffer);
13509 gst_caps_set_simple (CUR_STREAM (stream)->caps, "profile",
13510 G_TYPE_STRING, profile_str, NULL);
13514 case 0x60: /* MPEG-2, various profiles */
13520 codec_name = "MPEG-2 video";
13521 caps = gst_caps_new_simple ("video/mpeg",
13522 "mpegversion", G_TYPE_INT, 2,
13523 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13525 case 0x69: /* MPEG-2 BC audio */
13526 case 0x6B: /* MPEG-1 audio */
13527 caps = gst_caps_new_simple ("audio/mpeg",
13528 "mpegversion", G_TYPE_INT, 1, NULL);
13529 codec_name = "MPEG-1 audio";
13531 case 0x6A: /* MPEG-1 */
13532 codec_name = "MPEG-1 video";
13533 caps = gst_caps_new_simple ("video/mpeg",
13534 "mpegversion", G_TYPE_INT, 1,
13535 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13537 case 0x6C: /* MJPEG */
13539 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
13541 codec_name = "Motion-JPEG";
13543 case 0x6D: /* PNG */
13545 gst_caps_new_simple ("image/png", "parsed", G_TYPE_BOOLEAN, TRUE,
13547 codec_name = "PNG still images";
13549 case 0x6E: /* JPEG2000 */
13550 codec_name = "JPEG-2000";
13551 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
13553 case 0xA4: /* Dirac */
13554 codec_name = "Dirac";
13555 caps = gst_caps_new_empty_simple ("video/x-dirac");
13557 case 0xA5: /* AC3 */
13558 codec_name = "AC-3 audio";
13559 caps = gst_caps_new_simple ("audio/x-ac3",
13560 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
13562 case 0xA9: /* AC3 */
13563 codec_name = "DTS audio";
13564 caps = gst_caps_new_simple ("audio/x-dts",
13565 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
13567 case 0xE1: /* QCELP */
13568 /* QCELP, the codec_data is a riff tag (little endian) with
13569 * 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). */
13570 caps = gst_caps_new_empty_simple ("audio/qcelp");
13571 codec_name = "QCELP";
13577 /* If we have a replacement caps, then change our caps for this stream */
13579 gst_caps_unref (entry->caps);
13580 entry->caps = caps;
13583 if (codec_name && list)
13584 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
13585 GST_TAG_AUDIO_CODEC, codec_name, NULL);
13587 /* Add the codec_data attribute to caps, if we have it */
13591 buffer = gst_buffer_new_and_alloc (data_len);
13592 gst_buffer_fill (buffer, 0, data_ptr, data_len);
13594 GST_DEBUG_OBJECT (qtdemux, "setting codec_data from esds");
13595 GST_MEMDUMP_OBJECT (qtdemux, "codec_data from esds", data_ptr, data_len);
13597 gst_caps_set_simple (entry->caps, "codec_data", GST_TYPE_BUFFER,
13599 gst_buffer_unref (buffer);
13604 static inline GstCaps *
13605 _get_unknown_codec_name (const gchar * type, guint32 fourcc)
13609 char *s, fourstr[5];
13611 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
13612 for (i = 0; i < 4; i++) {
13613 if (!g_ascii_isalnum (fourstr[i]))
13616 s = g_strdup_printf ("%s/x-gst-fourcc-%s", type, g_strstrip (fourstr));
13617 caps = gst_caps_new_empty_simple (s);
13622 #define _codec(name) \
13624 if (codec_name) { \
13625 *codec_name = g_strdup (name); \
13630 qtdemux_video_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
13631 QtDemuxStreamStsdEntry * entry, guint32 fourcc,
13632 const guint8 * stsd_entry_data, gchar ** codec_name)
13634 GstCaps *caps = NULL;
13635 GstVideoFormat format = GST_VIDEO_FORMAT_UNKNOWN;
13639 _codec ("PNG still images");
13640 caps = gst_caps_new_empty_simple ("image/png");
13643 _codec ("JPEG still images");
13645 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
13648 case GST_MAKE_FOURCC ('m', 'j', 'p', 'a'):
13649 case GST_MAKE_FOURCC ('A', 'V', 'D', 'J'):
13650 case GST_MAKE_FOURCC ('M', 'J', 'P', 'G'):
13651 case GST_MAKE_FOURCC ('d', 'm', 'b', '1'):
13652 _codec ("Motion-JPEG");
13654 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
13657 case GST_MAKE_FOURCC ('m', 'j', 'p', 'b'):
13658 _codec ("Motion-JPEG format B");
13659 caps = gst_caps_new_empty_simple ("video/x-mjpeg-b");
13662 _codec ("JPEG-2000");
13663 /* override to what it should be according to spec, avoid palette_data */
13664 entry->bits_per_sample = 24;
13665 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
13668 _codec ("Sorensen video v.3");
13669 caps = gst_caps_new_simple ("video/x-svq",
13670 "svqversion", G_TYPE_INT, 3, NULL);
13672 case GST_MAKE_FOURCC ('s', 'v', 'q', 'i'):
13673 case GST_MAKE_FOURCC ('S', 'V', 'Q', '1'):
13674 _codec ("Sorensen video v.1");
13675 caps = gst_caps_new_simple ("video/x-svq",
13676 "svqversion", G_TYPE_INT, 1, NULL);
13678 case GST_MAKE_FOURCC ('W', 'R', 'A', 'W'):
13679 caps = gst_caps_new_empty_simple ("video/x-raw");
13680 gst_caps_set_simple (caps, "format", G_TYPE_STRING, "RGB8P", NULL);
13681 _codec ("Windows Raw RGB");
13682 stream->alignment = 32;
13688 bps = QT_UINT16 (stsd_entry_data + 82);
13691 format = GST_VIDEO_FORMAT_RGB15;
13694 format = GST_VIDEO_FORMAT_RGB16;
13697 format = GST_VIDEO_FORMAT_RGB;
13700 format = GST_VIDEO_FORMAT_ARGB;
13708 case GST_MAKE_FOURCC ('y', 'v', '1', '2'):
13709 format = GST_VIDEO_FORMAT_I420;
13711 case GST_MAKE_FOURCC ('y', 'u', 'v', '2'):
13712 case GST_MAKE_FOURCC ('Y', 'u', 'v', '2'):
13713 format = GST_VIDEO_FORMAT_I420;
13716 case GST_MAKE_FOURCC ('2', 'V', 'u', 'y'):
13717 format = GST_VIDEO_FORMAT_UYVY;
13719 case GST_MAKE_FOURCC ('v', '3', '0', '8'):
13720 format = GST_VIDEO_FORMAT_v308;
13722 case GST_MAKE_FOURCC ('v', '2', '1', '6'):
13723 format = GST_VIDEO_FORMAT_v216;
13726 format = GST_VIDEO_FORMAT_v210;
13728 case GST_MAKE_FOURCC ('r', '2', '1', '0'):
13729 format = GST_VIDEO_FORMAT_r210;
13731 /* Packed YUV 4:4:4 10 bit in 32 bits, complex
13732 case GST_MAKE_FOURCC ('v', '4', '1', '0'):
13733 format = GST_VIDEO_FORMAT_v410;
13736 /* Packed YUV 4:4:4:4 8 bit in 32 bits
13737 * but different order than AYUV
13738 case GST_MAKE_FOURCC ('v', '4', '0', '8'):
13739 format = GST_VIDEO_FORMAT_v408;
13742 case GST_MAKE_FOURCC ('m', 'p', 'e', 'g'):
13743 case GST_MAKE_FOURCC ('m', 'p', 'g', '1'):
13744 _codec ("MPEG-1 video");
13745 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
13746 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13748 case GST_MAKE_FOURCC ('h', 'd', 'v', '1'): /* HDV 720p30 */
13749 case GST_MAKE_FOURCC ('h', 'd', 'v', '2'): /* HDV 1080i60 */
13750 case GST_MAKE_FOURCC ('h', 'd', 'v', '3'): /* HDV 1080i50 */
13751 case GST_MAKE_FOURCC ('h', 'd', 'v', '4'): /* HDV 720p24 */
13752 case GST_MAKE_FOURCC ('h', 'd', 'v', '5'): /* HDV 720p25 */
13753 case GST_MAKE_FOURCC ('h', 'd', 'v', '6'): /* HDV 1080p24 */
13754 case GST_MAKE_FOURCC ('h', 'd', 'v', '7'): /* HDV 1080p25 */
13755 case GST_MAKE_FOURCC ('h', 'd', 'v', '8'): /* HDV 1080p30 */
13756 case GST_MAKE_FOURCC ('h', 'd', 'v', '9'): /* HDV 720p60 */
13757 case GST_MAKE_FOURCC ('h', 'd', 'v', 'a'): /* HDV 720p50 */
13758 case GST_MAKE_FOURCC ('m', 'x', '5', 'n'): /* MPEG2 IMX NTSC 525/60 50mb/s produced by FCP */
13759 case GST_MAKE_FOURCC ('m', 'x', '5', 'p'): /* MPEG2 IMX PAL 625/60 50mb/s produced by FCP */
13760 case GST_MAKE_FOURCC ('m', 'x', '4', 'n'): /* MPEG2 IMX NTSC 525/60 40mb/s produced by FCP */
13761 case GST_MAKE_FOURCC ('m', 'x', '4', 'p'): /* MPEG2 IMX PAL 625/60 40mb/s produced by FCP */
13762 case GST_MAKE_FOURCC ('m', 'x', '3', 'n'): /* MPEG2 IMX NTSC 525/60 30mb/s produced by FCP */
13763 case GST_MAKE_FOURCC ('m', 'x', '3', 'p'): /* MPEG2 IMX PAL 625/50 30mb/s produced by FCP */
13764 case GST_MAKE_FOURCC ('x', 'd', 'v', '1'): /* XDCAM HD 720p30 35Mb/s */
13765 case GST_MAKE_FOURCC ('x', 'd', 'v', '2'): /* XDCAM HD 1080i60 35Mb/s */
13766 case GST_MAKE_FOURCC ('x', 'd', 'v', '3'): /* XDCAM HD 1080i50 35Mb/s */
13767 case GST_MAKE_FOURCC ('x', 'd', 'v', '4'): /* XDCAM HD 720p24 35Mb/s */
13768 case GST_MAKE_FOURCC ('x', 'd', 'v', '5'): /* XDCAM HD 720p25 35Mb/s */
13769 case GST_MAKE_FOURCC ('x', 'd', 'v', '6'): /* XDCAM HD 1080p24 35Mb/s */
13770 case GST_MAKE_FOURCC ('x', 'd', 'v', '7'): /* XDCAM HD 1080p25 35Mb/s */
13771 case GST_MAKE_FOURCC ('x', 'd', 'v', '8'): /* XDCAM HD 1080p30 35Mb/s */
13772 case GST_MAKE_FOURCC ('x', 'd', 'v', '9'): /* XDCAM HD 720p60 35Mb/s */
13773 case GST_MAKE_FOURCC ('x', 'd', 'v', 'a'): /* XDCAM HD 720p50 35Mb/s */
13774 case GST_MAKE_FOURCC ('x', 'd', 'v', 'b'): /* XDCAM EX 1080i60 50Mb/s CBR */
13775 case GST_MAKE_FOURCC ('x', 'd', 'v', 'c'): /* XDCAM EX 1080i50 50Mb/s CBR */
13776 case GST_MAKE_FOURCC ('x', 'd', 'v', 'd'): /* XDCAM HD 1080p24 50Mb/s CBR */
13777 case GST_MAKE_FOURCC ('x', 'd', 'v', 'e'): /* XDCAM HD 1080p25 50Mb/s CBR */
13778 case GST_MAKE_FOURCC ('x', 'd', 'v', 'f'): /* XDCAM HD 1080p30 50Mb/s CBR */
13779 case GST_MAKE_FOURCC ('x', 'd', '5', '1'): /* XDCAM HD422 720p30 50Mb/s CBR */
13780 case GST_MAKE_FOURCC ('x', 'd', '5', '4'): /* XDCAM HD422 720p24 50Mb/s CBR */
13781 case GST_MAKE_FOURCC ('x', 'd', '5', '5'): /* XDCAM HD422 720p25 50Mb/s CBR */
13782 case GST_MAKE_FOURCC ('x', 'd', '5', '9'): /* XDCAM HD422 720p60 50Mb/s CBR */
13783 case GST_MAKE_FOURCC ('x', 'd', '5', 'a'): /* XDCAM HD422 720p50 50Mb/s CBR */
13784 case GST_MAKE_FOURCC ('x', 'd', '5', 'b'): /* XDCAM HD422 1080i50 50Mb/s CBR */
13785 case GST_MAKE_FOURCC ('x', 'd', '5', 'c'): /* XDCAM HD422 1080i50 50Mb/s CBR */
13786 case GST_MAKE_FOURCC ('x', 'd', '5', 'd'): /* XDCAM HD422 1080p24 50Mb/s CBR */
13787 case GST_MAKE_FOURCC ('x', 'd', '5', 'e'): /* XDCAM HD422 1080p25 50Mb/s CBR */
13788 case GST_MAKE_FOURCC ('x', 'd', '5', 'f'): /* XDCAM HD422 1080p30 50Mb/s CBR */
13789 case GST_MAKE_FOURCC ('x', 'd', 'h', 'd'): /* XDCAM HD 540p */
13790 case GST_MAKE_FOURCC ('x', 'd', 'h', '2'): /* XDCAM HD422 540p */
13791 case GST_MAKE_FOURCC ('A', 'V', 'm', 'p'): /* AVID IMX PAL */
13792 case GST_MAKE_FOURCC ('m', 'p', 'g', '2'): /* AVID IMX PAL */
13793 case GST_MAKE_FOURCC ('m', 'p', '2', 'v'): /* AVID IMX PAL */
13794 case GST_MAKE_FOURCC ('m', '2', 'v', '1'):
13795 _codec ("MPEG-2 video");
13796 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 2,
13797 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13799 case GST_MAKE_FOURCC ('g', 'i', 'f', ' '):
13800 _codec ("GIF still images");
13801 caps = gst_caps_new_empty_simple ("image/gif");
13804 case GST_MAKE_FOURCC ('H', '2', '6', '3'):
13806 case GST_MAKE_FOURCC ('U', '2', '6', '3'):
13808 /* ffmpeg uses the height/width props, don't know why */
13809 caps = gst_caps_new_simple ("video/x-h263",
13810 "variant", G_TYPE_STRING, "itu", NULL);
13814 _codec ("MPEG-4 video");
13815 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
13816 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13818 case GST_MAKE_FOURCC ('3', 'i', 'v', 'd'):
13819 case GST_MAKE_FOURCC ('3', 'I', 'V', 'D'):
13820 _codec ("Microsoft MPEG-4 4.3"); /* FIXME? */
13821 caps = gst_caps_new_simple ("video/x-msmpeg",
13822 "msmpegversion", G_TYPE_INT, 43, NULL);
13824 case GST_MAKE_FOURCC ('D', 'I', 'V', '3'):
13826 caps = gst_caps_new_simple ("video/x-divx",
13827 "divxversion", G_TYPE_INT, 3, NULL);
13829 case GST_MAKE_FOURCC ('D', 'I', 'V', 'X'):
13830 case GST_MAKE_FOURCC ('d', 'i', 'v', 'x'):
13832 caps = gst_caps_new_simple ("video/x-divx",
13833 "divxversion", G_TYPE_INT, 4, NULL);
13835 case GST_MAKE_FOURCC ('D', 'X', '5', '0'):
13837 caps = gst_caps_new_simple ("video/x-divx",
13838 "divxversion", G_TYPE_INT, 5, NULL);
13841 case GST_MAKE_FOURCC ('F', 'F', 'V', '1'):
13843 caps = gst_caps_new_simple ("video/x-ffv",
13844 "ffvversion", G_TYPE_INT, 1, NULL);
13847 case GST_MAKE_FOURCC ('3', 'I', 'V', '1'):
13848 case GST_MAKE_FOURCC ('3', 'I', 'V', '2'):
13853 case GST_MAKE_FOURCC ('U', 'M', 'P', '4'):
13854 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
13855 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13859 case GST_MAKE_FOURCC ('c', 'v', 'i', 'd'):
13860 _codec ("Cinepak");
13861 caps = gst_caps_new_empty_simple ("video/x-cinepak");
13863 case GST_MAKE_FOURCC ('q', 'd', 'r', 'w'):
13864 _codec ("Apple QuickDraw");
13865 caps = gst_caps_new_empty_simple ("video/x-qdrw");
13867 case GST_MAKE_FOURCC ('r', 'p', 'z', 'a'):
13868 _codec ("Apple video");
13869 caps = gst_caps_new_empty_simple ("video/x-apple-video");
13873 _codec ("H.264 / AVC");
13874 caps = gst_caps_new_simple ("video/x-h264",
13875 "stream-format", G_TYPE_STRING, "avc",
13876 "alignment", G_TYPE_STRING, "au", NULL);
13879 _codec ("H.264 / AVC");
13880 caps = gst_caps_new_simple ("video/x-h264",
13881 "stream-format", G_TYPE_STRING, "avc3",
13882 "alignment", G_TYPE_STRING, "au", NULL);
13886 _codec ("H.265 / HEVC");
13887 caps = gst_caps_new_simple ("video/x-h265",
13888 "stream-format", G_TYPE_STRING, "hvc1",
13889 "alignment", G_TYPE_STRING, "au", NULL);
13892 _codec ("H.265 / HEVC");
13893 caps = gst_caps_new_simple ("video/x-h265",
13894 "stream-format", G_TYPE_STRING, "hev1",
13895 "alignment", G_TYPE_STRING, "au", NULL);
13898 _codec ("Run-length encoding");
13899 caps = gst_caps_new_simple ("video/x-rle",
13900 "layout", G_TYPE_STRING, "quicktime", NULL);
13903 _codec ("Run-length encoding");
13904 caps = gst_caps_new_simple ("video/x-rle",
13905 "layout", G_TYPE_STRING, "microsoft", NULL);
13907 case GST_MAKE_FOURCC ('I', 'V', '3', '2'):
13908 case GST_MAKE_FOURCC ('i', 'v', '3', '2'):
13909 _codec ("Indeo Video 3");
13910 caps = gst_caps_new_simple ("video/x-indeo",
13911 "indeoversion", G_TYPE_INT, 3, NULL);
13913 case GST_MAKE_FOURCC ('I', 'V', '4', '1'):
13914 case GST_MAKE_FOURCC ('i', 'v', '4', '1'):
13915 _codec ("Intel Video 4");
13916 caps = gst_caps_new_simple ("video/x-indeo",
13917 "indeoversion", G_TYPE_INT, 4, NULL);
13921 case GST_MAKE_FOURCC ('d', 'v', 's', 'd'):
13922 case GST_MAKE_FOURCC ('D', 'V', 'S', 'D'):
13923 case GST_MAKE_FOURCC ('d', 'v', 'c', 's'):
13924 case GST_MAKE_FOURCC ('D', 'V', 'C', 'S'):
13925 case GST_MAKE_FOURCC ('d', 'v', '2', '5'):
13926 case GST_MAKE_FOURCC ('d', 'v', 'p', 'p'):
13927 _codec ("DV Video");
13928 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 25,
13929 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13931 case FOURCC_dv5n: /* DVCPRO50 NTSC */
13932 case FOURCC_dv5p: /* DVCPRO50 PAL */
13933 _codec ("DVCPro50 Video");
13934 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 50,
13935 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13937 case GST_MAKE_FOURCC ('d', 'v', 'h', '5'): /* DVCPRO HD 50i produced by FCP */
13938 case GST_MAKE_FOURCC ('d', 'v', 'h', '6'): /* DVCPRO HD 60i produced by FCP */
13939 _codec ("DVCProHD Video");
13940 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 100,
13941 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13943 case GST_MAKE_FOURCC ('s', 'm', 'c', ' '):
13944 _codec ("Apple Graphics (SMC)");
13945 caps = gst_caps_new_empty_simple ("video/x-smc");
13947 case GST_MAKE_FOURCC ('V', 'P', '3', '1'):
13949 caps = gst_caps_new_empty_simple ("video/x-vp3");
13951 case GST_MAKE_FOURCC ('V', 'P', '6', 'F'):
13952 _codec ("VP6 Flash");
13953 caps = gst_caps_new_empty_simple ("video/x-vp6-flash");
13957 caps = gst_caps_new_empty_simple ("video/x-theora");
13958 /* theora uses one byte of padding in the data stream because it does not
13959 * allow 0 sized packets while theora does */
13960 entry->padding = 1;
13964 caps = gst_caps_new_empty_simple ("video/x-dirac");
13966 case GST_MAKE_FOURCC ('t', 'i', 'f', 'f'):
13967 _codec ("TIFF still images");
13968 caps = gst_caps_new_empty_simple ("image/tiff");
13970 case GST_MAKE_FOURCC ('i', 'c', 'o', 'd'):
13971 _codec ("Apple Intermediate Codec");
13972 caps = gst_caps_from_string ("video/x-apple-intermediate-codec");
13974 case GST_MAKE_FOURCC ('A', 'V', 'd', 'n'):
13975 _codec ("AVID DNxHD");
13976 caps = gst_caps_from_string ("video/x-dnxhd");
13980 _codec ("On2 VP8");
13981 caps = gst_caps_from_string ("video/x-vp8");
13984 _codec ("Google VP9");
13985 caps = gst_caps_from_string ("video/x-vp9");
13988 _codec ("Apple ProRes LT");
13990 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "lt",
13994 _codec ("Apple ProRes HQ");
13996 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "hq",
14000 _codec ("Apple ProRes");
14002 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14006 _codec ("Apple ProRes Proxy");
14008 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14012 _codec ("Apple ProRes 4444");
14014 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14018 _codec ("Apple ProRes 4444 XQ");
14020 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14024 _codec ("GoPro CineForm");
14025 caps = gst_caps_from_string ("video/x-cineform");
14030 caps = gst_caps_new_simple ("video/x-wmv",
14031 "wmvversion", G_TYPE_INT, 3, "format", G_TYPE_STRING, "WVC1", NULL);
14033 case GST_MAKE_FOURCC ('k', 'p', 'c', 'd'):
14036 caps = _get_unknown_codec_name ("video", fourcc);
14041 if (format != GST_VIDEO_FORMAT_UNKNOWN) {
14044 gst_video_info_init (&info);
14045 gst_video_info_set_format (&info, format, entry->width, entry->height);
14047 caps = gst_video_info_to_caps (&info);
14048 *codec_name = gst_pb_utils_get_codec_description (caps);
14050 /* enable clipping for raw video streams */
14051 stream->need_clip = TRUE;
14052 stream->alignment = 32;
14059 round_up_pow2 (guint n)
14071 qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
14072 QtDemuxStreamStsdEntry * entry, guint32 fourcc, const guint8 * data,
14073 int len, gchar ** codec_name)
14076 const GstStructure *s;
14079 GstAudioFormat format = 0;
14082 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
14084 depth = entry->bytes_per_packet * 8;
14087 case GST_MAKE_FOURCC ('N', 'O', 'N', 'E'):
14089 /* 8-bit audio is unsigned */
14091 format = GST_AUDIO_FORMAT_U8;
14092 /* otherwise it's signed and big-endian just like 'twos' */
14094 endian = G_BIG_ENDIAN;
14101 endian = G_LITTLE_ENDIAN;
14104 format = gst_audio_format_build_integer (TRUE, endian, depth, depth);
14106 str = g_strdup_printf ("Raw %d-bit PCM audio", depth);
14110 caps = gst_caps_new_simple ("audio/x-raw",
14111 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
14112 "layout", G_TYPE_STRING, "interleaved", NULL);
14113 stream->alignment = GST_ROUND_UP_8 (depth);
14114 stream->alignment = round_up_pow2 (stream->alignment);
14117 case GST_MAKE_FOURCC ('f', 'l', '6', '4'):
14118 _codec ("Raw 64-bit floating-point audio");
14119 caps = gst_caps_new_simple ("audio/x-raw",
14120 "format", G_TYPE_STRING, "F64BE",
14121 "layout", G_TYPE_STRING, "interleaved", NULL);
14122 stream->alignment = 8;
14124 case GST_MAKE_FOURCC ('f', 'l', '3', '2'):
14125 _codec ("Raw 32-bit floating-point audio");
14126 caps = gst_caps_new_simple ("audio/x-raw",
14127 "format", G_TYPE_STRING, "F32BE",
14128 "layout", G_TYPE_STRING, "interleaved", NULL);
14129 stream->alignment = 4;
14132 _codec ("Raw 24-bit PCM audio");
14133 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
14135 caps = gst_caps_new_simple ("audio/x-raw",
14136 "format", G_TYPE_STRING, "S24BE",
14137 "layout", G_TYPE_STRING, "interleaved", NULL);
14138 stream->alignment = 4;
14140 case GST_MAKE_FOURCC ('i', 'n', '3', '2'):
14141 _codec ("Raw 32-bit PCM audio");
14142 caps = gst_caps_new_simple ("audio/x-raw",
14143 "format", G_TYPE_STRING, "S32BE",
14144 "layout", G_TYPE_STRING, "interleaved", NULL);
14145 stream->alignment = 4;
14147 case GST_MAKE_FOURCC ('s', '1', '6', 'l'):
14148 _codec ("Raw 16-bit PCM audio");
14149 caps = gst_caps_new_simple ("audio/x-raw",
14150 "format", G_TYPE_STRING, "S16LE",
14151 "layout", G_TYPE_STRING, "interleaved", NULL);
14152 stream->alignment = 2;
14155 _codec ("Mu-law audio");
14156 caps = gst_caps_new_empty_simple ("audio/x-mulaw");
14159 _codec ("A-law audio");
14160 caps = gst_caps_new_empty_simple ("audio/x-alaw");
14164 _codec ("Microsoft ADPCM");
14165 /* Microsoft ADPCM-ACM code 2 */
14166 caps = gst_caps_new_simple ("audio/x-adpcm",
14167 "layout", G_TYPE_STRING, "microsoft", NULL);
14171 _codec ("DVI/IMA ADPCM");
14172 caps = gst_caps_new_simple ("audio/x-adpcm",
14173 "layout", G_TYPE_STRING, "dvi", NULL);
14177 _codec ("DVI/Intel IMA ADPCM");
14178 /* FIXME DVI/Intel IMA ADPCM/ACM code 17 */
14179 caps = gst_caps_new_simple ("audio/x-adpcm",
14180 "layout", G_TYPE_STRING, "quicktime", NULL);
14184 /* MPEG layer 3, CBR only (pre QT4.1) */
14186 _codec ("MPEG-1 layer 3");
14187 /* MPEG layer 3, CBR & VBR (QT4.1 and later) */
14188 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 3,
14189 "mpegversion", G_TYPE_INT, 1, NULL);
14191 case GST_MAKE_FOURCC ('.', 'm', 'p', '2'):
14192 _codec ("MPEG-1 layer 2");
14194 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 2,
14195 "mpegversion", G_TYPE_INT, 1, NULL);
14198 case GST_MAKE_FOURCC ('e', 'c', '-', '3'):
14199 _codec ("EAC-3 audio");
14200 caps = gst_caps_new_simple ("audio/x-eac3",
14201 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14202 entry->sampled = TRUE;
14204 case GST_MAKE_FOURCC ('s', 'a', 'c', '3'): // Nero Recode
14206 _codec ("AC-3 audio");
14207 caps = gst_caps_new_simple ("audio/x-ac3",
14208 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14209 entry->sampled = TRUE;
14211 case GST_MAKE_FOURCC ('d', 't', 's', 'c'):
14212 case GST_MAKE_FOURCC ('D', 'T', 'S', ' '):
14213 _codec ("DTS audio");
14214 caps = gst_caps_new_simple ("audio/x-dts",
14215 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14216 entry->sampled = TRUE;
14218 case GST_MAKE_FOURCC ('d', 't', 's', 'h'): // DTS-HD
14219 case GST_MAKE_FOURCC ('d', 't', 's', 'l'): // DTS-HD Lossless
14220 _codec ("DTS-HD audio");
14221 caps = gst_caps_new_simple ("audio/x-dts",
14222 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14223 entry->sampled = TRUE;
14227 caps = gst_caps_new_simple ("audio/x-mace",
14228 "maceversion", G_TYPE_INT, 3, NULL);
14232 caps = gst_caps_new_simple ("audio/x-mace",
14233 "maceversion", G_TYPE_INT, 6, NULL);
14235 case GST_MAKE_FOURCC ('O', 'g', 'g', 'V'):
14237 caps = gst_caps_new_empty_simple ("application/ogg");
14239 case GST_MAKE_FOURCC ('d', 'v', 'c', 'a'):
14240 _codec ("DV audio");
14241 caps = gst_caps_new_empty_simple ("audio/x-dv");
14244 _codec ("MPEG-4 AAC audio");
14245 caps = gst_caps_new_simple ("audio/mpeg",
14246 "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE,
14247 "stream-format", G_TYPE_STRING, "raw", NULL);
14249 case GST_MAKE_FOURCC ('Q', 'D', 'M', 'C'):
14250 _codec ("QDesign Music");
14251 caps = gst_caps_new_empty_simple ("audio/x-qdm");
14254 _codec ("QDesign Music v.2");
14255 /* FIXME: QDesign music version 2 (no constant) */
14256 if (FALSE && data) {
14257 caps = gst_caps_new_simple ("audio/x-qdm2",
14258 "framesize", G_TYPE_INT, QT_UINT32 (data + 52),
14259 "bitrate", G_TYPE_INT, QT_UINT32 (data + 40),
14260 "blocksize", G_TYPE_INT, QT_UINT32 (data + 44), NULL);
14262 caps = gst_caps_new_empty_simple ("audio/x-qdm2");
14266 _codec ("GSM audio");
14267 caps = gst_caps_new_empty_simple ("audio/x-gsm");
14270 _codec ("AMR audio");
14271 caps = gst_caps_new_empty_simple ("audio/AMR");
14274 _codec ("AMR-WB audio");
14275 caps = gst_caps_new_empty_simple ("audio/AMR-WB");
14278 _codec ("Quicktime IMA ADPCM");
14279 caps = gst_caps_new_simple ("audio/x-adpcm",
14280 "layout", G_TYPE_STRING, "quicktime", NULL);
14283 _codec ("Apple lossless audio");
14284 caps = gst_caps_new_empty_simple ("audio/x-alac");
14287 _codec ("Free Lossless Audio Codec");
14288 caps = gst_caps_new_simple ("audio/x-flac",
14289 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14291 case GST_MAKE_FOURCC ('Q', 'c', 'l', 'p'):
14292 _codec ("QualComm PureVoice");
14293 caps = gst_caps_from_string ("audio/qcelp");
14298 caps = gst_caps_new_empty_simple ("audio/x-wma");
14302 caps = gst_caps_new_empty_simple ("audio/x-opus");
14309 GstAudioFormat format;
14312 FLAG_IS_FLOAT = 0x1,
14313 FLAG_IS_BIG_ENDIAN = 0x2,
14314 FLAG_IS_SIGNED = 0x4,
14315 FLAG_IS_PACKED = 0x8,
14316 FLAG_IS_ALIGNED_HIGH = 0x10,
14317 FLAG_IS_NON_INTERLEAVED = 0x20
14319 _codec ("Raw LPCM audio");
14321 if (data && len >= 36) {
14322 depth = QT_UINT32 (data + 24);
14323 flags = QT_UINT32 (data + 28);
14324 width = QT_UINT32 (data + 32) * 8 / entry->n_channels;
14326 if ((flags & FLAG_IS_FLOAT) == 0) {
14331 if ((flags & FLAG_IS_ALIGNED_HIGH))
14334 format = gst_audio_format_build_integer ((flags & FLAG_IS_SIGNED) ?
14335 TRUE : FALSE, (flags & FLAG_IS_BIG_ENDIAN) ?
14336 G_BIG_ENDIAN : G_LITTLE_ENDIAN, width, depth);
14337 caps = gst_caps_new_simple ("audio/x-raw",
14338 "format", G_TYPE_STRING,
14340 GST_AUDIO_FORMAT_UNKNOWN ? gst_audio_format_to_string (format) :
14341 "UNKNOWN", "layout", G_TYPE_STRING,
14342 (flags & FLAG_IS_NON_INTERLEAVED) ? "non-interleaved" :
14343 "interleaved", NULL);
14344 stream->alignment = GST_ROUND_UP_8 (depth);
14345 stream->alignment = round_up_pow2 (stream->alignment);
14350 if (flags & FLAG_IS_BIG_ENDIAN)
14351 format = GST_AUDIO_FORMAT_F64BE;
14353 format = GST_AUDIO_FORMAT_F64LE;
14355 if (flags & FLAG_IS_BIG_ENDIAN)
14356 format = GST_AUDIO_FORMAT_F32BE;
14358 format = GST_AUDIO_FORMAT_F32LE;
14360 caps = gst_caps_new_simple ("audio/x-raw",
14361 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
14362 "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
14363 "non-interleaved" : "interleaved", NULL);
14364 stream->alignment = width / 8;
14368 case GST_MAKE_FOURCC ('q', 't', 'v', 'r'):
14372 caps = _get_unknown_codec_name ("audio", fourcc);
14378 GstCaps *templ_caps =
14379 gst_static_pad_template_get_caps (&gst_qtdemux_audiosrc_template);
14380 GstCaps *intersection = gst_caps_intersect (caps, templ_caps);
14381 gst_caps_unref (caps);
14382 gst_caps_unref (templ_caps);
14383 caps = intersection;
14386 /* enable clipping for raw audio streams */
14387 s = gst_caps_get_structure (caps, 0);
14388 name = gst_structure_get_name (s);
14389 if (g_str_has_prefix (name, "audio/x-raw")) {
14390 stream->need_clip = TRUE;
14391 stream->max_buffer_size = 4096 * entry->bytes_per_frame;
14392 GST_DEBUG ("setting max buffer size to %d", stream->max_buffer_size);
14398 qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
14399 QtDemuxStreamStsdEntry * entry, guint32 fourcc,
14400 const guint8 * stsd_entry_data, gchar ** codec_name)
14404 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
14408 _codec ("DVD subtitle");
14409 caps = gst_caps_new_empty_simple ("subpicture/x-dvd");
14410 stream->need_process = TRUE;
14413 _codec ("Quicktime timed text");
14416 _codec ("3GPP timed text");
14418 caps = gst_caps_new_simple ("text/x-raw", "format", G_TYPE_STRING,
14420 /* actual text piece needs to be extracted */
14421 stream->need_process = TRUE;
14424 _codec ("XML subtitles");
14425 caps = gst_caps_new_empty_simple ("application/ttml+xml");
14429 caps = _get_unknown_codec_name ("text", fourcc);
14437 qtdemux_generic_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
14438 QtDemuxStreamStsdEntry * entry, guint32 fourcc,
14439 const guint8 * stsd_entry_data, gchar ** codec_name)
14445 _codec ("MPEG 1 video");
14446 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
14447 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14457 gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux,
14458 const gchar * system_id)
14462 if (!qtdemux->protection_system_ids)
14463 qtdemux->protection_system_ids =
14464 g_ptr_array_new_with_free_func ((GDestroyNotify) g_free);
14465 /* Check whether we already have an entry for this system ID. */
14466 for (i = 0; i < qtdemux->protection_system_ids->len; ++i) {
14467 const gchar *id = g_ptr_array_index (qtdemux->protection_system_ids, i);
14468 if (g_ascii_strcasecmp (system_id, id) == 0) {
14472 GST_DEBUG_OBJECT (qtdemux, "Adding cenc protection system ID %s", system_id);
14473 g_ptr_array_add (qtdemux->protection_system_ids, g_ascii_strdown (system_id,