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.
13 * This library is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU Library General Public
15 * License as published by the Free Software Foundation; either
16 * version 2 of the License, or (at your option) any later version.
18 * This library is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * Library General Public License for more details.
23 * You should have received a copy of the GNU Library General Public
24 * License along with this library; if not, write to the
25 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
26 * Boston, MA 02110-1301, USA.
30 * SECTION:element-qtdemux
32 * Demuxes a .mov file into raw or compressed audio and/or video streams.
34 * This element supports both push and pull-based scheduling, depending on the
35 * capabilities of the upstream elements.
38 * <title>Example launch line</title>
40 * 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
41 * ]| Play (parse and decode) a .mov file and try to output it to
42 * an automatically detected soundcard and videosink. If the MOV file contains
43 * compressed audio or video data, this will only work if you have the
44 * right decoder elements/plugins installed.
52 #include "gst/gst-i18n-plugin.h"
54 #include <glib/gprintf.h>
55 #include <gst/tag/tag.h>
56 #include <gst/audio/audio.h>
57 #include <gst/video/video.h>
59 #include "qtatomparser.h"
60 #include "qtdemux_types.h"
61 #include "qtdemux_dump.h"
63 #include "descriptors.h"
64 #include "qtdemux_lang.h"
66 #include "qtpalette.h"
68 #include "gst/riff/riff-media.h"
69 #include "gst/riff/riff-read.h"
71 #include <gst/pbutils/pbutils.h>
78 #include <gst/math-compat.h>
84 /* max. size considered 'sane' for non-mdat atoms */
85 #define QTDEMUX_MAX_ATOM_SIZE (25*1024*1024)
87 /* if the sample index is larger than this, something is likely wrong */
88 #define QTDEMUX_MAX_SAMPLE_INDEX_SIZE (50*1024*1024)
90 /* For converting qt creation times to unix epoch times */
91 #define QTDEMUX_SECONDS_PER_DAY (60 * 60 * 24)
92 #define QTDEMUX_LEAP_YEARS_FROM_1904_TO_1970 17
93 #define QTDEMUX_SECONDS_FROM_1904_TO_1970 (((1970 - 1904) * (guint64) 365 + \
94 QTDEMUX_LEAP_YEARS_FROM_1904_TO_1970) * QTDEMUX_SECONDS_PER_DAY)
96 #define STREAM_IS_EOS(s) (s->time_position == GST_CLOCK_TIME_NONE)
98 GST_DEBUG_CATEGORY (qtdemux_debug);
100 typedef struct _QtDemuxSegment QtDemuxSegment;
101 typedef struct _QtDemuxSample QtDemuxSample;
103 typedef struct _QtDemuxCencSampleSetInfo QtDemuxCencSampleSetInfo;
105 struct _QtDemuxSample
108 gint32 pts_offset; /* Add this value to timestamp to get the pts */
110 guint64 timestamp; /* DTS In mov time */
111 guint32 duration; /* In mov time */
112 gboolean keyframe; /* TRUE when this packet is a keyframe */
115 /* Macros for converting to/from timescale */
116 #define QTSTREAMTIME_TO_GSTTIME(stream, value) (gst_util_uint64_scale((value), GST_SECOND, (stream)->timescale))
117 #define GSTTIME_TO_QTSTREAMTIME(stream, value) (gst_util_uint64_scale((value), (stream)->timescale, GST_SECOND))
119 #define QTTIME_TO_GSTTIME(qtdemux, value) (gst_util_uint64_scale((value), GST_SECOND, (qtdemux)->timescale))
120 #define GSTTIME_TO_QTTIME(qtdemux, value) (gst_util_uint64_scale((value), (qtdemux)->timescale, GST_SECOND))
122 /* timestamp is the DTS */
123 #define QTSAMPLE_DTS(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp))
124 /* timestamp + offset is the PTS */
125 #define QTSAMPLE_PTS(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp + (stream)->cslg_shift + (sample)->pts_offset))
126 /* timestamp + duration - dts is the duration */
127 #define QTSAMPLE_DUR_DTS(stream, sample, dts) (QTSTREAMTIME_TO_GSTTIME ((stream), (sample)->timestamp + (sample)->duration) - (dts))
129 #define QTSAMPLE_KEYFRAME(stream,sample) ((stream)->all_keyframe || (sample)->keyframe)
132 * Quicktime has tracks and segments. A track is a continuous piece of
133 * multimedia content. The track is not always played from start to finish but
134 * instead, pieces of the track are 'cut out' and played in sequence. This is
135 * what the segments do.
137 * Inside the track we have keyframes (K) and delta frames. The track has its
138 * own timing, which starts from 0 and extends to end. The position in the track
139 * is called the media_time.
141 * The segments now describe the pieces that should be played from this track
142 * and are basically tuples of media_time/duration/rate entries. We can have
143 * multiple segments and they are all played after one another. An example:
145 * segment 1: media_time: 1 second, duration: 1 second, rate 1
146 * segment 2: media_time: 3 second, duration: 2 second, rate 2
148 * To correctly play back this track, one must play: 1 second of media starting
149 * from media_time 1 followed by 2 seconds of media starting from media_time 3
152 * Each of the segments will be played at a specific time, the first segment at
153 * time 0, the second one after the duration of the first one, etc.. Note that
154 * the time in resulting playback is not identical to the media_time of the
157 * Visually, assuming the track has 4 second of media_time:
160 * .-----------------------------------------------------------.
161 * track: | K.....K.........K........K.......K.......K...........K... |
162 * '-----------------------------------------------------------'
164 * .------------^ ^ .----------^ ^
165 * / .-------------' / .------------------'
167 * .--------------. .--------------.
168 * | segment 1 | | segment 2 |
169 * '--------------' '--------------'
171 * The challenge here is to cut out the right pieces of the track for each of
172 * the playback segments. This fortunately can easily be done with the SEGMENT
173 * events of GStreamer.
175 * For playback of segment 1, we need to provide the decoder with the keyframe
176 * (a), in the above figure, but we must instruct it only to output the decoded
177 * data between second 1 and 2. We do this with a SEGMENT event for 1 to 2, time
178 * position set to the time of the segment: 0.
180 * We then proceed to push data from keyframe (a) to frame (b). The decoder
181 * decodes but clips all before media_time 1.
183 * After finishing a segment, we push out a new SEGMENT event with the clipping
184 * boundaries of the new data.
186 * This is a good usecase for the GStreamer accumulated SEGMENT events.
189 struct _QtDemuxSegment
191 /* global time and duration, all gst time */
193 GstClockTime stop_time;
194 GstClockTime duration;
195 /* media time of trak, all gst time */
196 GstClockTime media_start;
197 GstClockTime media_stop;
199 /* Media start time in trak timescale units */
200 guint32 trak_media_start;
203 #define QTSEGMENT_IS_EMPTY(s) ((s)->media_start == GST_CLOCK_TIME_NONE)
205 /* Used with fragmented MP4 files (mfra atom) */
210 } QtDemuxRandomAccessEntry;
212 struct _QtDemuxStream
222 gboolean new_caps; /* If TRUE, caps need to be generated (by
223 * calling _configure_stream()) This happens
224 * for MSS and fragmented streams */
226 gboolean new_stream; /* signals that a stream_start is required */
227 gboolean on_keyframe; /* if this stream last pushed buffer was a
228 * keyframe. This is important to identify
229 * where to stop pushing buffers after a
230 * segment stop time */
232 /* if the stream has a redirect URI in its headers, we store it here */
239 guint64 duration; /* in timescale units */
243 gchar lang_id[4]; /* ISO 639-2T language code */
247 QtDemuxSample *samples;
248 gboolean all_keyframe; /* TRUE when all samples are keyframes (no stss) */
249 guint32 first_duration; /* duration in timescale of first sample, used for figuring out
251 guint32 n_samples_moof; /* sample count in a moof */
252 guint64 duration_moof; /* duration in timescale of a moof, used for figure out
253 * the framerate of fragmented format stream */
255 guint32 offset_in_sample; /* Offset in the current sample, used for
256 * streams which have got exceedingly big
257 * sample size (such as 24s of raw audio).
258 * Only used when max_buffer_size is non-NULL */
259 guint32 max_buffer_size; /* Maximum allowed size for output buffers.
260 * Currently only set for raw audio streams*/
262 /* if we use chunks or samples */
274 /* Numerator/denominator framerate */
277 guint16 bits_per_sample;
278 guint16 color_table_id;
279 GstMemory *rgb8_palette;
284 guint samples_per_packet;
285 guint samples_per_frame;
286 guint bytes_per_packet;
287 guint bytes_per_sample;
288 guint bytes_per_frame;
292 gboolean use_allocator;
293 GstAllocator *allocator;
294 GstAllocationParams params;
296 /* when a discontinuity is pending */
299 /* list of buffers to push first */
302 /* if we need to clip this buffer. This is only needed for uncompressed
306 /* buffer needs some custom processing, e.g. subtitles */
307 gboolean need_process;
309 /* current position */
310 guint32 segment_index;
311 guint32 sample_index;
312 GstClockTime time_position; /* in gst time */
313 guint64 accumulated_base;
315 /* the Gst segment we are processing out, used for clipping */
318 /* quicktime segments */
320 QtDemuxSegment *segments;
321 gboolean dummy_segment;
326 GstTagList *pending_tags;
327 gboolean send_global_tags;
329 GstEvent *pending_event;
339 gboolean chunks_are_samples; /* TRUE means treat chunks as samples */
343 GstByteReader co_chunk;
345 guint32 current_chunk;
347 guint32 samples_per_chunk;
348 guint32 stco_sample_index;
350 guint32 sample_size; /* 0 means variable sizes are stored in stsz */
353 guint32 n_samples_per_chunk;
354 guint32 stsc_chunk_index;
355 guint32 stsc_sample_index;
356 guint64 chunk_offset;
359 guint32 stts_samples;
360 guint32 n_sample_times;
361 guint32 stts_sample_index;
363 guint32 stts_duration;
365 gboolean stss_present;
366 guint32 n_sample_syncs;
369 gboolean stps_present;
370 guint32 n_sample_partial_syncs;
372 QtDemuxRandomAccessEntry *ra_entries;
375 const QtDemuxRandomAccessEntry *pending_seek;
378 gboolean ctts_present;
379 guint32 n_composition_times;
381 guint32 ctts_sample_index;
389 gboolean parsed_trex;
390 guint32 def_sample_duration;
391 guint32 def_sample_size;
392 guint32 def_sample_flags;
396 /* stereoscopic video streams */
397 GstVideoMultiviewMode multiview_mode;
398 GstVideoMultiviewFlags multiview_flags;
400 /* protected streams */
402 guint32 protection_scheme_type;
403 guint32 protection_scheme_version;
404 gpointer protection_scheme_info; /* specific to the protection scheme */
405 GQueue protection_scheme_event_queue;
408 /* Contains properties and cryptographic info for a set of samples from a
409 * track protected using Common Encryption (cenc) */
410 struct _QtDemuxCencSampleSetInfo
412 GstStructure *default_properties;
414 /* @crypto_info holds one GstStructure per sample */
415 GPtrArray *crypto_info;
419 qt_demux_state_string (enum QtDemuxState state)
422 case QTDEMUX_STATE_INITIAL:
424 case QTDEMUX_STATE_HEADER:
426 case QTDEMUX_STATE_MOVIE:
428 case QTDEMUX_STATE_BUFFER_MDAT:
429 return "<BUFFER_MDAT>";
435 static GNode *qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc);
436 static GNode *qtdemux_tree_get_child_by_type_full (GNode * node,
437 guint32 fourcc, GstByteReader * parser);
438 static GNode *qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc);
439 static GNode *qtdemux_tree_get_sibling_by_type_full (GNode * node,
440 guint32 fourcc, GstByteReader * parser);
442 static GstFlowReturn qtdemux_add_fragmented_samples (GstQTDemux * qtdemux);
444 static GstStaticPadTemplate gst_qtdemux_sink_template =
445 GST_STATIC_PAD_TEMPLATE ("sink",
448 GST_STATIC_CAPS ("video/quicktime; video/mj2; audio/x-m4a; "
452 static GstStaticPadTemplate gst_qtdemux_videosrc_template =
453 GST_STATIC_PAD_TEMPLATE ("video_%u",
456 GST_STATIC_CAPS_ANY);
458 static GstStaticPadTemplate gst_qtdemux_audiosrc_template =
459 GST_STATIC_PAD_TEMPLATE ("audio_%u",
462 GST_STATIC_CAPS_ANY);
464 static GstStaticPadTemplate gst_qtdemux_subsrc_template =
465 GST_STATIC_PAD_TEMPLATE ("subtitle_%u",
468 GST_STATIC_CAPS_ANY);
470 #define gst_qtdemux_parent_class parent_class
471 G_DEFINE_TYPE (GstQTDemux, gst_qtdemux, GST_TYPE_ELEMENT);
473 static void gst_qtdemux_dispose (GObject * object);
476 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
477 GstClockTime media_time);
479 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
480 QtDemuxStream * str, gint64 media_offset);
483 static void gst_qtdemux_set_index (GstElement * element, GstIndex * index);
484 static GstIndex *gst_qtdemux_get_index (GstElement * element);
486 static GstStateChangeReturn gst_qtdemux_change_state (GstElement * element,
487 GstStateChange transition);
488 static gboolean qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent);
489 static gboolean qtdemux_sink_activate_mode (GstPad * sinkpad,
490 GstObject * parent, GstPadMode mode, gboolean active);
492 static void gst_qtdemux_loop (GstPad * pad);
493 static GstFlowReturn gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent,
495 static gboolean gst_qtdemux_handle_sink_event (GstPad * pad, GstObject * parent,
497 static gboolean gst_qtdemux_setcaps (GstQTDemux * qtdemux, GstCaps * caps);
498 static gboolean gst_qtdemux_configure_stream (GstQTDemux * qtdemux,
499 QtDemuxStream * stream);
500 static GstFlowReturn gst_qtdemux_process_adapter (GstQTDemux * demux,
503 static gboolean qtdemux_parse_moov (GstQTDemux * qtdemux,
504 const guint8 * buffer, guint length);
505 static gboolean qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node,
506 const guint8 * buffer, guint length);
507 static gboolean qtdemux_parse_tree (GstQTDemux * qtdemux);
508 static void qtdemux_parse_udta (GstQTDemux * qtdemux, GstTagList * taglist,
511 static void gst_qtdemux_handle_esds (GstQTDemux * qtdemux,
512 QtDemuxStream * stream, GNode * esds, GstTagList * list);
513 static GstCaps *qtdemux_video_caps (GstQTDemux * qtdemux,
514 QtDemuxStream * stream, guint32 fourcc, const guint8 * stsd_data,
515 gchar ** codec_name);
516 static GstCaps *qtdemux_audio_caps (GstQTDemux * qtdemux,
517 QtDemuxStream * stream, guint32 fourcc, const guint8 * data, int len,
518 gchar ** codec_name);
519 static GstCaps *qtdemux_sub_caps (GstQTDemux * qtdemux,
520 QtDemuxStream * stream, guint32 fourcc, const guint8 * data,
521 gchar ** codec_name);
522 static GstCaps *qtdemux_generic_caps (GstQTDemux * qtdemux,
523 QtDemuxStream * stream, guint32 fourcc, const guint8 * stsd_data,
524 gchar ** codec_name);
526 static gboolean qtdemux_parse_samples (GstQTDemux * qtdemux,
527 QtDemuxStream * stream, guint32 n);
528 static GstFlowReturn qtdemux_expose_streams (GstQTDemux * qtdemux);
529 static void gst_qtdemux_stream_free (GstQTDemux * qtdemux,
530 QtDemuxStream * stream);
531 static void gst_qtdemux_stream_clear (GstQTDemux * qtdemux,
532 QtDemuxStream * stream);
533 static void gst_qtdemux_remove_stream (GstQTDemux * qtdemux, int index);
534 static GstFlowReturn qtdemux_prepare_streams (GstQTDemux * qtdemux);
535 static void qtdemux_do_allocation (GstQTDemux * qtdemux,
536 QtDemuxStream * stream);
537 static gboolean gst_qtdemux_activate_segment (GstQTDemux * qtdemux,
538 QtDemuxStream * stream, guint32 seg_idx, GstClockTime offset);
539 static gboolean gst_qtdemux_stream_update_segment (GstQTDemux * qtdemux,
540 QtDemuxStream * stream, gint seg_idx, GstClockTime offset,
541 GstClockTime * _start, GstClockTime * _stop);
542 static void gst_qtdemux_send_gap_for_segment (GstQTDemux * demux,
543 QtDemuxStream * stream, gint segment_index, GstClockTime pos);
545 static gboolean qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux);
546 static void check_update_duration (GstQTDemux * qtdemux, GstClockTime duration);
548 static gchar *qtdemux_uuid_bytes_to_string (gconstpointer uuid_bytes);
550 static GstStructure *qtdemux_get_cenc_sample_properties (GstQTDemux * qtdemux,
551 QtDemuxStream * stream, guint sample_index);
552 static void gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux,
554 static void qtdemux_gst_structure_free (GstStructure * gststructure);
557 gst_qtdemux_class_init (GstQTDemuxClass * klass)
559 GObjectClass *gobject_class;
560 GstElementClass *gstelement_class;
562 gobject_class = (GObjectClass *) klass;
563 gstelement_class = (GstElementClass *) klass;
565 parent_class = g_type_class_peek_parent (klass);
567 gobject_class->dispose = gst_qtdemux_dispose;
569 gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_qtdemux_change_state);
571 gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_qtdemux_set_index);
572 gstelement_class->get_index = GST_DEBUG_FUNCPTR (gst_qtdemux_get_index);
575 gst_tag_register_musicbrainz_tags ();
577 gst_element_class_add_static_pad_template (gstelement_class,
578 &gst_qtdemux_sink_template);
579 gst_element_class_add_static_pad_template (gstelement_class,
580 &gst_qtdemux_videosrc_template);
581 gst_element_class_add_static_pad_template (gstelement_class,
582 &gst_qtdemux_audiosrc_template);
583 gst_element_class_add_static_pad_template (gstelement_class,
584 &gst_qtdemux_subsrc_template);
585 gst_element_class_set_static_metadata (gstelement_class, "QuickTime demuxer",
587 "Demultiplex a QuickTime file into audio and video streams",
588 "David Schleef <ds@schleef.org>, Wim Taymans <wim@fluendo.com>");
590 GST_DEBUG_CATEGORY_INIT (qtdemux_debug, "qtdemux", 0, "qtdemux plugin");
595 gst_qtdemux_init (GstQTDemux * qtdemux)
598 gst_pad_new_from_static_template (&gst_qtdemux_sink_template, "sink");
599 gst_pad_set_activate_function (qtdemux->sinkpad, qtdemux_sink_activate);
600 gst_pad_set_activatemode_function (qtdemux->sinkpad,
601 qtdemux_sink_activate_mode);
602 gst_pad_set_chain_function (qtdemux->sinkpad, gst_qtdemux_chain);
603 gst_pad_set_event_function (qtdemux->sinkpad, gst_qtdemux_handle_sink_event);
604 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), qtdemux->sinkpad);
606 qtdemux->state = QTDEMUX_STATE_INITIAL;
607 qtdemux->pullbased = FALSE;
608 qtdemux->posted_redirect = FALSE;
609 qtdemux->neededbytes = 16;
611 qtdemux->adapter = gst_adapter_new ();
613 qtdemux->first_mdat = -1;
614 qtdemux->got_moov = FALSE;
615 qtdemux->mdatoffset = -1;
616 qtdemux->mdatbuffer = NULL;
617 qtdemux->restoredata_buffer = NULL;
618 qtdemux->restoredata_offset = -1;
619 qtdemux->fragment_start = -1;
620 qtdemux->fragment_start_offset = -1;
621 qtdemux->media_caps = NULL;
622 qtdemux->exposed = FALSE;
623 qtdemux->mss_mode = FALSE;
624 qtdemux->pending_newsegment = NULL;
625 qtdemux->upstream_format_is_time = FALSE;
626 qtdemux->have_group_id = FALSE;
627 qtdemux->group_id = G_MAXUINT;
628 qtdemux->cenc_aux_info_offset = 0;
629 qtdemux->cenc_aux_info_sizes = NULL;
630 qtdemux->cenc_aux_sample_count = 0;
631 qtdemux->protection_system_ids = NULL;
632 g_queue_init (&qtdemux->protection_event_queue);
633 gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
634 qtdemux->flowcombiner = gst_flow_combiner_new ();
636 GST_OBJECT_FLAG_SET (qtdemux, GST_ELEMENT_FLAG_INDEXABLE);
640 gst_qtdemux_dispose (GObject * object)
642 GstQTDemux *qtdemux = GST_QTDEMUX (object);
644 if (qtdemux->adapter) {
645 g_object_unref (G_OBJECT (qtdemux->adapter));
646 qtdemux->adapter = NULL;
648 gst_flow_combiner_free (qtdemux->flowcombiner);
649 g_queue_foreach (&qtdemux->protection_event_queue, (GFunc) gst_event_unref,
651 g_queue_clear (&qtdemux->protection_event_queue);
653 g_free (qtdemux->cenc_aux_info_sizes);
654 qtdemux->cenc_aux_info_sizes = NULL;
656 G_OBJECT_CLASS (parent_class)->dispose (object);
660 gst_qtdemux_post_no_playable_stream_error (GstQTDemux * qtdemux)
662 if (qtdemux->posted_redirect) {
663 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
664 (_("This file contains no playable streams.")),
665 ("no known streams found, a redirect message has been posted"));
667 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
668 (_("This file contains no playable streams.")),
669 ("no known streams found"));
674 _gst_buffer_new_wrapped (gpointer mem, gsize size, GFreeFunc free_func)
676 return gst_buffer_new_wrapped_full (free_func ? 0 : GST_MEMORY_FLAG_READONLY,
677 mem, size, 0, size, mem, free_func);
681 gst_qtdemux_pull_atom (GstQTDemux * qtdemux, guint64 offset, guint64 size,
688 if (G_UNLIKELY (size == 0)) {
690 GstBuffer *tmp = NULL;
692 ret = gst_qtdemux_pull_atom (qtdemux, offset, sizeof (guint32), &tmp);
693 if (ret != GST_FLOW_OK)
696 gst_buffer_map (tmp, &map, GST_MAP_READ);
697 size = QT_UINT32 (map.data);
698 GST_DEBUG_OBJECT (qtdemux, "size 0x%08" G_GINT64_MODIFIER "x", size);
700 gst_buffer_unmap (tmp, &map);
701 gst_buffer_unref (tmp);
704 /* Sanity check: catch bogus sizes (fuzzed/broken files) */
705 if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
706 if (qtdemux->state != QTDEMUX_STATE_MOVIE && qtdemux->got_moov) {
707 /* we're pulling header but already got most interesting bits,
708 * so never mind the rest (e.g. tags) (that much) */
709 GST_WARNING_OBJECT (qtdemux, "atom has bogus size %" G_GUINT64_FORMAT,
713 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
714 (_("This file is invalid and cannot be played.")),
715 ("atom has bogus size %" G_GUINT64_FORMAT, size));
716 return GST_FLOW_ERROR;
720 flow = gst_pad_pull_range (qtdemux->sinkpad, offset, size, buf);
722 if (G_UNLIKELY (flow != GST_FLOW_OK))
725 bsize = gst_buffer_get_size (*buf);
726 /* Catch short reads - we don't want any partial atoms */
727 if (G_UNLIKELY (bsize < size)) {
728 GST_WARNING_OBJECT (qtdemux,
729 "short read: %" G_GSIZE_FORMAT " < %" G_GUINT64_FORMAT, bsize, size);
730 gst_buffer_unref (*buf);
740 gst_qtdemux_src_convert (GstQTDemux * qtdemux, GstPad * pad,
741 GstFormat src_format, gint64 src_value, GstFormat dest_format,
745 QtDemuxStream *stream = gst_pad_get_element_private (pad);
748 if (stream->subtype != FOURCC_vide) {
753 switch (src_format) {
754 case GST_FORMAT_TIME:
755 switch (dest_format) {
756 case GST_FORMAT_BYTES:{
757 index = gst_qtdemux_find_index_linear (qtdemux, stream, src_value);
763 *dest_value = stream->samples[index].offset;
765 GST_DEBUG_OBJECT (qtdemux, "Format Conversion Time->Offset :%"
766 GST_TIME_FORMAT "->%" G_GUINT64_FORMAT,
767 GST_TIME_ARGS (src_value), *dest_value);
775 case GST_FORMAT_BYTES:
776 switch (dest_format) {
777 case GST_FORMAT_TIME:{
779 gst_qtdemux_find_index_for_given_media_offset_linear (qtdemux,
788 QTSTREAMTIME_TO_GSTTIME (stream,
789 stream->samples[index].timestamp);
790 GST_DEBUG_OBJECT (qtdemux,
791 "Format Conversion Offset->Time :%" G_GUINT64_FORMAT "->%"
792 GST_TIME_FORMAT, src_value, GST_TIME_ARGS (*dest_value));
811 gst_qtdemux_get_duration (GstQTDemux * qtdemux, GstClockTime * duration)
813 gboolean res = FALSE;
815 *duration = GST_CLOCK_TIME_NONE;
817 if (qtdemux->duration != 0 &&
818 qtdemux->duration != G_MAXINT64 && qtdemux->timescale != 0) {
819 *duration = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
822 *duration = GST_CLOCK_TIME_NONE;
829 gst_qtdemux_handle_src_query (GstPad * pad, GstObject * parent,
832 gboolean res = FALSE;
833 GstQTDemux *qtdemux = GST_QTDEMUX (parent);
835 GST_LOG_OBJECT (pad, "%s query", GST_QUERY_TYPE_NAME (query));
837 switch (GST_QUERY_TYPE (query)) {
838 case GST_QUERY_POSITION:{
841 gst_query_parse_position (query, &fmt, NULL);
842 if (fmt == GST_FORMAT_TIME
843 && GST_CLOCK_TIME_IS_VALID (qtdemux->segment.position)) {
844 gst_query_set_position (query, GST_FORMAT_TIME,
845 qtdemux->segment.position);
850 case GST_QUERY_DURATION:{
853 gst_query_parse_duration (query, &fmt, NULL);
854 if (fmt == GST_FORMAT_TIME) {
855 /* First try to query upstream */
856 res = gst_pad_query_default (pad, parent, query);
858 GstClockTime duration;
859 if (gst_qtdemux_get_duration (qtdemux, &duration) && duration > 0) {
860 gst_query_set_duration (query, GST_FORMAT_TIME, duration);
867 case GST_QUERY_CONVERT:{
868 GstFormat src_fmt, dest_fmt;
869 gint64 src_value, dest_value = 0;
871 gst_query_parse_convert (query, &src_fmt, &src_value, &dest_fmt, NULL);
873 res = gst_qtdemux_src_convert (qtdemux, pad,
874 src_fmt, src_value, dest_fmt, &dest_value);
876 gst_query_set_convert (query, src_fmt, src_value, dest_fmt, dest_value);
881 case GST_QUERY_FORMATS:
882 gst_query_set_formats (query, 2, GST_FORMAT_TIME, GST_FORMAT_BYTES);
885 case GST_QUERY_SEEKING:{
889 /* try upstream first */
890 res = gst_pad_query_default (pad, parent, query);
893 gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
894 if (fmt == GST_FORMAT_TIME) {
895 GstClockTime duration;
897 gst_qtdemux_get_duration (qtdemux, &duration);
899 if (!qtdemux->pullbased) {
902 /* we might be able with help from upstream */
904 q = gst_query_new_seeking (GST_FORMAT_BYTES);
905 if (gst_pad_peer_query (qtdemux->sinkpad, q)) {
906 gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL);
907 GST_LOG_OBJECT (qtdemux, "upstream BYTE seekable %d", seekable);
911 gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0, duration);
917 case GST_QUERY_SEGMENT:
922 format = qtdemux->segment.format;
925 gst_segment_to_stream_time (&qtdemux->segment, format,
926 qtdemux->segment.start);
927 if ((stop = qtdemux->segment.stop) == -1)
928 stop = qtdemux->segment.duration;
930 stop = gst_segment_to_stream_time (&qtdemux->segment, format, stop);
932 gst_query_set_segment (query, qtdemux->segment.rate, format, start, stop);
937 res = gst_pad_query_default (pad, parent, query);
945 gst_qtdemux_push_tags (GstQTDemux * qtdemux, QtDemuxStream * stream)
947 if (G_LIKELY (stream->pad)) {
948 GST_DEBUG_OBJECT (qtdemux, "Checking pad %s:%s for tags",
949 GST_DEBUG_PAD_NAME (stream->pad));
951 if (G_UNLIKELY (stream->pending_tags)) {
952 GST_DEBUG_OBJECT (qtdemux, "Sending tags %" GST_PTR_FORMAT,
953 stream->pending_tags);
954 gst_pad_push_event (stream->pad,
955 gst_event_new_tag (stream->pending_tags));
956 stream->pending_tags = NULL;
959 if (G_UNLIKELY (stream->send_global_tags && qtdemux->tag_list)) {
960 GST_DEBUG_OBJECT (qtdemux, "Sending global tags %" GST_PTR_FORMAT,
962 gst_pad_push_event (stream->pad,
963 gst_event_new_tag (gst_tag_list_ref (qtdemux->tag_list)));
964 stream->send_global_tags = FALSE;
969 /* push event on all source pads; takes ownership of the event */
971 gst_qtdemux_push_event (GstQTDemux * qtdemux, GstEvent * event)
974 gboolean has_valid_stream = FALSE;
975 GstEventType etype = GST_EVENT_TYPE (event);
977 GST_DEBUG_OBJECT (qtdemux, "pushing %s event on all source pads",
978 GST_EVENT_TYPE_NAME (event));
980 for (n = 0; n < qtdemux->n_streams; n++) {
982 QtDemuxStream *stream = qtdemux->streams[n];
983 GST_DEBUG_OBJECT (qtdemux, "pushing on pad %i", n);
985 if ((pad = stream->pad)) {
986 has_valid_stream = TRUE;
988 if (etype == GST_EVENT_EOS) {
989 /* let's not send twice */
990 if (stream->sent_eos)
992 stream->sent_eos = TRUE;
995 gst_pad_push_event (pad, gst_event_ref (event));
999 gst_event_unref (event);
1001 /* if it is EOS and there are no pads, post an error */
1002 if (!has_valid_stream && etype == GST_EVENT_EOS) {
1003 gst_qtdemux_post_no_playable_stream_error (qtdemux);
1007 /* push a pending newsegment event, if any from the streaming thread */
1009 gst_qtdemux_push_pending_newsegment (GstQTDemux * qtdemux)
1011 if (qtdemux->pending_newsegment) {
1012 gst_qtdemux_push_event (qtdemux, qtdemux->pending_newsegment);
1013 qtdemux->pending_newsegment = NULL;
1023 find_func (QtDemuxSample * s1, gint64 * media_time, gpointer user_data)
1025 if ((gint64) s1->timestamp + s1->pts_offset > *media_time)
1027 if ((gint64) s1->timestamp + s1->pts_offset == *media_time)
1033 /* find the index of the sample that includes the data for @media_time using a
1034 * binary search. Only to be called in optimized cases of linear search below.
1036 * Returns the index of the sample.
1039 gst_qtdemux_find_index (GstQTDemux * qtdemux, QtDemuxStream * str,
1042 QtDemuxSample *result;
1045 /* convert media_time to mov format */
1047 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
1049 result = gst_util_array_binary_search (str->samples, str->stbl_index + 1,
1050 sizeof (QtDemuxSample), (GCompareDataFunc) find_func,
1051 GST_SEARCH_MODE_BEFORE, &media_time, NULL);
1053 if (G_LIKELY (result))
1054 index = result - str->samples;
1063 /* find the index of the sample that includes the data for @media_offset using a
1066 * Returns the index of the sample.
1069 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
1070 QtDemuxStream * str, gint64 media_offset)
1072 QtDemuxSample *result = str->samples;
1075 if (result == NULL || str->n_samples == 0)
1078 if (media_offset == result->offset)
1082 while (index < str->n_samples - 1) {
1083 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
1086 if (media_offset < result->offset)
1097 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
1102 /* find the index of the sample that includes the data for @media_time using a
1103 * linear search, and keeping in mind that not all samples may have been parsed
1104 * yet. If possible, it will delegate to binary search.
1106 * Returns the index of the sample.
1109 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
1110 GstClockTime media_time)
1114 QtDemuxSample *sample;
1116 /* convert media_time to mov format */
1118 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
1120 sample = str->samples;
1121 if (mov_time == sample->timestamp + sample->pts_offset)
1124 /* use faster search if requested time in already parsed range */
1125 sample = str->samples + str->stbl_index;
1126 if (str->stbl_index >= 0 &&
1127 mov_time <= (sample->timestamp + sample->pts_offset))
1128 return gst_qtdemux_find_index (qtdemux, str, media_time);
1130 while (index < str->n_samples - 1) {
1131 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
1134 sample = str->samples + index + 1;
1135 if (mov_time < (sample->timestamp + sample->pts_offset))
1145 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
1150 /* find the index of the keyframe needed to decode the sample at @index
1153 * Returns the index of the keyframe.
1156 gst_qtdemux_find_keyframe (GstQTDemux * qtdemux, QtDemuxStream * str,
1159 guint32 new_index = index;
1161 if (index >= str->n_samples) {
1162 new_index = str->n_samples;
1166 /* all keyframes, return index */
1167 if (str->all_keyframe) {
1172 /* else go back until we have a keyframe */
1174 if (str->samples[new_index].keyframe)
1184 GST_DEBUG_OBJECT (qtdemux, "searching for keyframe index before index %u "
1185 "gave %u", index, new_index);
1190 /* find the segment for @time_position for @stream
1192 * Returns the index of the segment containing @time_position.
1193 * Returns the last segment and sets the @eos variable to TRUE
1194 * if the time is beyond the end. @eos may be NULL
1197 gst_qtdemux_find_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
1198 GstClockTime time_position)
1203 GST_LOG_OBJECT (stream->pad, "finding segment for %" GST_TIME_FORMAT,
1204 GST_TIME_ARGS (time_position));
1207 for (i = 0; i < stream->n_segments; i++) {
1208 QtDemuxSegment *segment = &stream->segments[i];
1210 GST_LOG_OBJECT (stream->pad,
1211 "looking at segment %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT,
1212 GST_TIME_ARGS (segment->time), GST_TIME_ARGS (segment->stop_time));
1214 /* For the last segment we include stop_time in the last segment */
1215 if (i < stream->n_segments - 1) {
1216 if (segment->time <= time_position && time_position < segment->stop_time) {
1217 GST_LOG_OBJECT (stream->pad, "segment %d matches", i);
1222 /* Last segment always matches */
1230 /* move the stream @str to the sample position @index.
1232 * Updates @str->sample_index and marks discontinuity if needed.
1235 gst_qtdemux_move_stream (GstQTDemux * qtdemux, QtDemuxStream * str,
1238 /* no change needed */
1239 if (index == str->sample_index)
1242 GST_DEBUG_OBJECT (qtdemux, "moving to sample %u of %u", index,
1245 /* position changed, we have a discont */
1246 str->sample_index = index;
1247 str->offset_in_sample = 0;
1248 /* Each time we move in the stream we store the position where we are
1250 str->from_sample = index;
1251 str->discont = TRUE;
1255 gst_qtdemux_adjust_seek (GstQTDemux * qtdemux, gint64 desired_time,
1256 gboolean use_sparse, gint64 * key_time, gint64 * key_offset)
1259 gint64 min_byte_offset = -1;
1262 min_offset = desired_time;
1264 /* for each stream, find the index of the sample in the segment
1265 * and move back to the previous keyframe. */
1266 for (n = 0; n < qtdemux->n_streams; n++) {
1268 guint32 index, kindex;
1270 GstClockTime media_start;
1271 GstClockTime media_time;
1272 GstClockTime seg_time;
1273 QtDemuxSegment *seg;
1274 gboolean empty_segment = FALSE;
1276 str = qtdemux->streams[n];
1278 if (str->sparse && !use_sparse)
1281 seg_idx = gst_qtdemux_find_segment (qtdemux, str, desired_time);
1282 GST_DEBUG_OBJECT (qtdemux, "align segment %d", seg_idx);
1284 /* get segment and time in the segment */
1285 seg = &str->segments[seg_idx];
1286 seg_time = (desired_time - seg->time) * seg->rate;
1288 while (QTSEGMENT_IS_EMPTY (seg)) {
1290 empty_segment = TRUE;
1291 GST_DEBUG_OBJECT (str->pad, "Segment %d is empty, moving to next one",
1294 if (seg_idx == str->n_segments)
1296 seg = &str->segments[seg_idx];
1299 if (seg_idx == str->n_segments) {
1300 /* FIXME track shouldn't have the last segment as empty, but if it
1301 * happens we better handle it */
1305 /* get the media time in the segment */
1306 media_start = seg->media_start + seg_time;
1308 /* get the index of the sample with media time */
1309 index = gst_qtdemux_find_index_linear (qtdemux, str, media_start);
1310 GST_DEBUG_OBJECT (qtdemux, "sample for %" GST_TIME_FORMAT " at %u"
1311 " at offset %" G_GUINT64_FORMAT " (empty segment: %d)",
1312 GST_TIME_ARGS (media_start), index, str->samples[index].offset,
1315 if (!empty_segment) {
1316 /* find previous keyframe */
1317 kindex = gst_qtdemux_find_keyframe (qtdemux, str, index);
1319 /* if the keyframe is at a different position, we need to update the
1320 * requested seek time */
1321 if (index != kindex) {
1324 /* get timestamp of keyframe */
1325 media_time = QTSAMPLE_DTS (str, &str->samples[kindex]);
1326 GST_DEBUG_OBJECT (qtdemux,
1327 "keyframe at %u with time %" GST_TIME_FORMAT " at offset %"
1328 G_GUINT64_FORMAT, kindex, GST_TIME_ARGS (media_time),
1329 str->samples[kindex].offset);
1331 /* keyframes in the segment get a chance to change the
1332 * desired_offset. keyframes out of the segment are
1334 if (media_time >= seg->media_start) {
1335 GstClockTime seg_time;
1337 /* this keyframe is inside the segment, convert back to
1339 seg_time = (media_time - seg->media_start) + seg->time;
1340 if (seg_time < min_offset)
1341 min_offset = seg_time;
1346 if (min_byte_offset < 0 || str->samples[index].offset < min_byte_offset)
1347 min_byte_offset = str->samples[index].offset;
1351 *key_time = min_offset;
1353 *key_offset = min_byte_offset;
1357 gst_qtdemux_convert_seek (GstPad * pad, GstFormat * format,
1358 GstSeekType cur_type, gint64 * cur, GstSeekType stop_type, gint64 * stop)
1362 g_return_val_if_fail (format != NULL, FALSE);
1363 g_return_val_if_fail (cur != NULL, FALSE);
1364 g_return_val_if_fail (stop != NULL, FALSE);
1366 if (*format == GST_FORMAT_TIME)
1370 if (cur_type != GST_SEEK_TYPE_NONE)
1371 res = gst_pad_query_convert (pad, *format, *cur, GST_FORMAT_TIME, cur);
1372 if (res && stop_type != GST_SEEK_TYPE_NONE)
1373 res = gst_pad_query_convert (pad, *format, *stop, GST_FORMAT_TIME, stop);
1376 *format = GST_FORMAT_TIME;
1381 /* perform seek in push based mode:
1382 find BYTE position to move to based on time and delegate to upstream
1385 gst_qtdemux_do_push_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1390 GstSeekType cur_type, stop_type;
1391 gint64 cur, stop, key_cur;
1394 gint64 original_stop;
1397 GST_DEBUG_OBJECT (qtdemux, "doing push-based seek");
1399 gst_event_parse_seek (event, &rate, &format, &flags,
1400 &cur_type, &cur, &stop_type, &stop);
1401 seqnum = gst_event_get_seqnum (event);
1403 /* only forward streaming and seeking is possible */
1405 goto unsupported_seek;
1407 /* convert to TIME if needed and possible */
1408 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1412 /* Upstream seek in bytes will have undefined stop, but qtdemux stores
1413 * the original stop position to use when upstream pushes the new segment
1415 original_stop = stop;
1418 /* find reasonable corresponding BYTE position,
1419 * also try to mind about keyframes, since we can not go back a bit for them
1421 gst_qtdemux_adjust_seek (qtdemux, cur, FALSE, &key_cur, &byte_cur);
1426 GST_DEBUG_OBJECT (qtdemux, "Pushing BYTE seek rate %g, "
1427 "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, byte_cur,
1430 GST_OBJECT_LOCK (qtdemux);
1431 qtdemux->seek_offset = byte_cur;
1432 if (!(flags & GST_SEEK_FLAG_KEY_UNIT)) {
1433 qtdemux->push_seek_start = cur;
1435 qtdemux->push_seek_start = key_cur;
1438 if (stop_type == GST_SEEK_TYPE_NONE) {
1439 qtdemux->push_seek_stop = qtdemux->segment.stop;
1441 qtdemux->push_seek_stop = original_stop;
1443 GST_OBJECT_UNLOCK (qtdemux);
1445 /* BYTE seek event */
1446 event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type, byte_cur,
1448 gst_event_set_seqnum (event, seqnum);
1449 res = gst_pad_push_event (qtdemux->sinkpad, event);
1456 GST_DEBUG_OBJECT (qtdemux, "could not determine byte position to seek to, "
1462 GST_DEBUG_OBJECT (qtdemux, "unsupported seek, seek aborted.");
1467 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1472 /* perform the seek.
1474 * We set all segment_indexes in the streams to unknown and
1475 * adjust the time_position to the desired position. this is enough
1476 * to trigger a segment switch in the streaming thread to start
1477 * streaming from the desired position.
1479 * Keyframe seeking is a little more complicated when dealing with
1480 * segments. Ideally we want to move to the previous keyframe in
1481 * the segment but there might not be a keyframe in the segment. In
1482 * fact, none of the segments could contain a keyframe. We take a
1483 * practical approach: seek to the previous keyframe in the segment,
1484 * if there is none, seek to the beginning of the segment.
1486 * Called with STREAM_LOCK
1489 gst_qtdemux_perform_seek (GstQTDemux * qtdemux, GstSegment * segment,
1490 guint32 seqnum, GstSeekFlags flags)
1492 gint64 desired_offset;
1495 desired_offset = segment->position;
1497 GST_DEBUG_OBJECT (qtdemux, "seeking to %" GST_TIME_FORMAT,
1498 GST_TIME_ARGS (desired_offset));
1500 /* may not have enough fragmented info to do this adjustment,
1501 * and we can't scan (and probably should not) at this time with
1502 * possibly flushing upstream */
1503 if ((flags & GST_SEEK_FLAG_KEY_UNIT) && !qtdemux->fragmented) {
1506 gst_qtdemux_adjust_seek (qtdemux, desired_offset, TRUE, &min_offset, NULL);
1507 GST_DEBUG_OBJECT (qtdemux, "keyframe seek, align to %"
1508 GST_TIME_FORMAT, GST_TIME_ARGS (min_offset));
1509 desired_offset = min_offset;
1512 /* and set all streams to the final position */
1513 gst_flow_combiner_reset (qtdemux->flowcombiner);
1514 qtdemux->segment_seqnum = seqnum;
1515 for (n = 0; n < qtdemux->n_streams; n++) {
1516 QtDemuxStream *stream = qtdemux->streams[n];
1518 stream->time_position = desired_offset;
1519 stream->accumulated_base = 0;
1520 stream->sample_index = -1;
1521 stream->offset_in_sample = 0;
1522 stream->segment_index = -1;
1523 stream->sent_eos = FALSE;
1525 if (segment->flags & GST_SEEK_FLAG_FLUSH)
1526 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
1528 segment->position = desired_offset;
1529 segment->time = desired_offset;
1530 if (segment->rate >= 0) {
1531 segment->start = desired_offset;
1533 /* we stop at the end */
1534 if (segment->stop == -1)
1535 segment->stop = segment->duration;
1537 segment->stop = desired_offset;
1540 if (qtdemux->fragmented)
1541 qtdemux->fragmented_seek_pending = TRUE;
1546 /* do a seek in pull based mode */
1548 gst_qtdemux_do_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1553 GstSeekType cur_type, stop_type;
1557 GstSegment seeksegment;
1559 GstEvent *flush_event;
1562 GST_DEBUG_OBJECT (qtdemux, "doing seek with event");
1564 gst_event_parse_seek (event, &rate, &format, &flags,
1565 &cur_type, &cur, &stop_type, &stop);
1566 seqnum = gst_event_get_seqnum (event);
1568 /* we have to have a format as the segment format. Try to convert
1570 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1574 GST_DEBUG_OBJECT (qtdemux, "seek format %s", gst_format_get_name (format));
1576 GST_DEBUG_OBJECT (qtdemux, "doing seek without event");
1580 flush = flags & GST_SEEK_FLAG_FLUSH;
1582 /* stop streaming, either by flushing or by pausing the task */
1584 flush_event = gst_event_new_flush_start ();
1586 gst_event_set_seqnum (flush_event, seqnum);
1587 /* unlock upstream pull_range */
1588 gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event));
1589 /* make sure out loop function exits */
1590 gst_qtdemux_push_event (qtdemux, flush_event);
1592 /* non flushing seek, pause the task */
1593 gst_pad_pause_task (qtdemux->sinkpad);
1596 /* wait for streaming to finish */
1597 GST_PAD_STREAM_LOCK (qtdemux->sinkpad);
1599 /* copy segment, we need this because we still need the old
1600 * segment when we close the current segment. */
1601 memcpy (&seeksegment, &qtdemux->segment, sizeof (GstSegment));
1604 /* configure the segment with the seek variables */
1605 GST_DEBUG_OBJECT (qtdemux, "configuring seek");
1606 gst_segment_do_seek (&seeksegment, rate, format, flags,
1607 cur_type, cur, stop_type, stop, &update);
1610 /* now do the seek, this actually never returns FALSE */
1611 gst_qtdemux_perform_seek (qtdemux, &seeksegment, seqnum, flags);
1613 /* prepare for streaming again */
1615 flush_event = gst_event_new_flush_stop (TRUE);
1617 gst_event_set_seqnum (flush_event, seqnum);
1619 gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event));
1620 gst_qtdemux_push_event (qtdemux, flush_event);
1623 /* commit the new segment */
1624 memcpy (&qtdemux->segment, &seeksegment, sizeof (GstSegment));
1626 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
1627 GstMessage *msg = gst_message_new_segment_start (GST_OBJECT_CAST (qtdemux),
1628 qtdemux->segment.format, qtdemux->segment.position);
1630 gst_message_set_seqnum (msg, seqnum);
1631 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
1634 /* restart streaming, NEWSEGMENT will be sent from the streaming thread. */
1635 gst_pad_start_task (qtdemux->sinkpad, (GstTaskFunction) gst_qtdemux_loop,
1636 qtdemux->sinkpad, NULL);
1638 GST_PAD_STREAM_UNLOCK (qtdemux->sinkpad);
1645 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1651 qtdemux_ensure_index (GstQTDemux * qtdemux)
1655 GST_DEBUG_OBJECT (qtdemux, "collecting all metadata for all streams");
1657 /* Build complete index */
1658 for (i = 0; i < qtdemux->n_streams; i++) {
1659 QtDemuxStream *stream = qtdemux->streams[i];
1661 if (!qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1))
1669 GST_LOG_OBJECT (qtdemux,
1670 "Building complete index of stream %u for seeking failed!", i);
1676 gst_qtdemux_handle_src_event (GstPad * pad, GstObject * parent,
1679 gboolean res = TRUE;
1680 GstQTDemux *qtdemux = GST_QTDEMUX (parent);
1682 switch (GST_EVENT_TYPE (event)) {
1683 case GST_EVENT_SEEK:
1685 #ifndef GST_DISABLE_GST_DEBUG
1686 GstClockTime ts = gst_util_get_timestamp ();
1689 if (qtdemux->upstream_format_is_time && qtdemux->fragmented) {
1690 /* seek should be handled by upstream, we might need to re-download fragments */
1691 GST_DEBUG_OBJECT (qtdemux,
1692 "let upstream handle seek for fragmented playback");
1696 /* Build complete index for seeking;
1697 * if not a fragmented file at least */
1698 if (!qtdemux->fragmented)
1699 if (!qtdemux_ensure_index (qtdemux))
1701 #ifndef GST_DISABLE_GST_DEBUG
1702 ts = gst_util_get_timestamp () - ts;
1703 GST_INFO_OBJECT (qtdemux,
1704 "Time taken to parse index %" GST_TIME_FORMAT, GST_TIME_ARGS (ts));
1707 if (qtdemux->pullbased) {
1708 res = gst_qtdemux_do_seek (qtdemux, pad, event);
1709 } else if (gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (event))) {
1710 GST_DEBUG_OBJECT (qtdemux, "Upstream successfully seeked");
1712 } else if (qtdemux->state == QTDEMUX_STATE_MOVIE && qtdemux->n_streams
1713 && !qtdemux->fragmented) {
1714 res = gst_qtdemux_do_push_seek (qtdemux, pad, event);
1716 GST_DEBUG_OBJECT (qtdemux,
1717 "ignoring seek in push mode in current state");
1720 gst_event_unref (event);
1723 case GST_EVENT_NAVIGATION:
1725 gst_event_unref (event);
1729 res = gst_pad_event_default (pad, parent, event);
1739 GST_ERROR_OBJECT (qtdemux, "Index failed");
1740 gst_event_unref (event);
1746 /* stream/index return sample that is min/max w.r.t. byte position,
1747 * time is min/max w.r.t. time of samples,
1748 * the latter need not be time of the former sample */
1750 gst_qtdemux_find_sample (GstQTDemux * qtdemux, gint64 byte_pos, gboolean fw,
1751 gboolean set, QtDemuxStream ** _stream, gint * _index, gint64 * _time)
1754 gint64 time, min_time;
1755 QtDemuxStream *stream;
1761 for (n = 0; n < qtdemux->n_streams; ++n) {
1764 gboolean set_sample;
1766 str = qtdemux->streams[n];
1773 i = str->n_samples - 1;
1777 for (; (i >= 0) && (i < str->n_samples); i += inc) {
1778 if (str->samples[i].size == 0)
1781 if (fw && (str->samples[i].offset < byte_pos))
1784 if (!fw && (str->samples[i].offset + str->samples[i].size > byte_pos))
1787 /* move stream to first available sample */
1789 gst_qtdemux_move_stream (qtdemux, str, i);
1793 /* avoid index from sparse streams since they might be far away */
1795 /* determine min/max time */
1796 time = QTSAMPLE_PTS (str, &str->samples[i]);
1797 if (min_time == -1 || (!fw && time > min_time) ||
1798 (fw && time < min_time)) {
1802 /* determine stream with leading sample, to get its position */
1804 (fw && (str->samples[i].offset < stream->samples[index].offset)) ||
1805 (!fw && (str->samples[i].offset > stream->samples[index].offset))) {
1813 /* no sample for this stream, mark eos */
1815 gst_qtdemux_move_stream (qtdemux, str, str->n_samples);
1826 static QtDemuxStream *
1827 _create_stream (void)
1829 QtDemuxStream *stream;
1831 stream = g_new0 (QtDemuxStream, 1);
1832 /* new streams always need a discont */
1833 stream->discont = TRUE;
1834 /* we enable clipping for raw audio/video streams */
1835 stream->need_clip = FALSE;
1836 stream->need_process = FALSE;
1837 stream->segment_index = -1;
1838 stream->time_position = 0;
1839 stream->sample_index = -1;
1840 stream->offset_in_sample = 0;
1841 stream->new_stream = TRUE;
1842 stream->multiview_mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
1843 stream->multiview_flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
1844 stream->protected = FALSE;
1845 stream->protection_scheme_type = 0;
1846 stream->protection_scheme_version = 0;
1847 stream->protection_scheme_info = NULL;
1848 stream->n_samples_moof = 0;
1849 stream->duration_moof = 0;
1850 g_queue_init (&stream->protection_scheme_event_queue);
1855 gst_qtdemux_setcaps (GstQTDemux * demux, GstCaps * caps)
1857 GstStructure *structure;
1858 const gchar *variant;
1859 const GstCaps *mediacaps = NULL;
1861 GST_DEBUG_OBJECT (demux, "Sink set caps: %" GST_PTR_FORMAT, caps);
1863 structure = gst_caps_get_structure (caps, 0);
1864 variant = gst_structure_get_string (structure, "variant");
1866 if (variant && strcmp (variant, "mss-fragmented") == 0) {
1867 QtDemuxStream *stream;
1868 const GValue *value;
1870 demux->fragmented = TRUE;
1871 demux->mss_mode = TRUE;
1873 if (demux->n_streams > 1) {
1874 /* can't do this, we can only renegotiate for another mss format */
1878 value = gst_structure_get_value (structure, "media-caps");
1881 const GValue *timescale_v;
1883 /* TODO update when stream changes during playback */
1885 if (demux->n_streams == 0) {
1886 stream = _create_stream ();
1887 demux->streams[demux->n_streams] = stream;
1888 demux->n_streams = 1;
1890 stream = demux->streams[0];
1893 timescale_v = gst_structure_get_value (structure, "timescale");
1895 stream->timescale = g_value_get_uint64 (timescale_v);
1897 /* default mss timescale */
1898 stream->timescale = 10000000;
1900 demux->timescale = stream->timescale;
1902 mediacaps = gst_value_get_caps (value);
1903 if (!stream->caps || !gst_caps_is_equal_fixed (mediacaps, stream->caps)) {
1904 GST_DEBUG_OBJECT (demux, "We have a new caps %" GST_PTR_FORMAT,
1906 stream->new_caps = TRUE;
1908 gst_caps_replace (&stream->caps, (GstCaps *) mediacaps);
1909 structure = gst_caps_get_structure (mediacaps, 0);
1910 if (g_str_has_prefix (gst_structure_get_name (structure), "video")) {
1911 stream->subtype = FOURCC_vide;
1913 gst_structure_get_int (structure, "width", &stream->width);
1914 gst_structure_get_int (structure, "height", &stream->height);
1915 gst_structure_get_fraction (structure, "framerate", &stream->fps_n,
1917 } else if (g_str_has_prefix (gst_structure_get_name (structure), "audio")) {
1919 stream->subtype = FOURCC_soun;
1920 gst_structure_get_int (structure, "channels", &stream->n_channels);
1921 gst_structure_get_int (structure, "rate", &rate);
1922 stream->rate = rate;
1925 gst_caps_replace (&demux->media_caps, (GstCaps *) mediacaps);
1927 demux->mss_mode = FALSE;
1934 gst_qtdemux_reset (GstQTDemux * qtdemux, gboolean hard)
1938 GST_DEBUG_OBJECT (qtdemux, "Resetting demux");
1939 gst_pad_stop_task (qtdemux->sinkpad);
1941 if (hard || qtdemux->upstream_format_is_time) {
1942 qtdemux->state = QTDEMUX_STATE_INITIAL;
1943 qtdemux->neededbytes = 16;
1944 qtdemux->todrop = 0;
1945 qtdemux->pullbased = FALSE;
1946 qtdemux->posted_redirect = FALSE;
1947 qtdemux->first_mdat = -1;
1948 qtdemux->header_size = 0;
1949 qtdemux->mdatoffset = -1;
1950 qtdemux->restoredata_offset = -1;
1951 if (qtdemux->mdatbuffer)
1952 gst_buffer_unref (qtdemux->mdatbuffer);
1953 if (qtdemux->restoredata_buffer)
1954 gst_buffer_unref (qtdemux->restoredata_buffer);
1955 qtdemux->mdatbuffer = NULL;
1956 qtdemux->restoredata_buffer = NULL;
1957 qtdemux->mdatleft = 0;
1958 if (qtdemux->comp_brands)
1959 gst_buffer_unref (qtdemux->comp_brands);
1960 qtdemux->comp_brands = NULL;
1961 qtdemux->last_moov_offset = -1;
1962 if (qtdemux->moov_node)
1963 g_node_destroy (qtdemux->moov_node);
1964 qtdemux->moov_node = NULL;
1965 qtdemux->moov_node_compressed = NULL;
1966 if (qtdemux->tag_list)
1967 gst_mini_object_unref (GST_MINI_OBJECT_CAST (qtdemux->tag_list));
1968 qtdemux->tag_list = NULL;
1970 if (qtdemux->element_index)
1971 gst_object_unref (qtdemux->element_index);
1972 qtdemux->element_index = NULL;
1974 qtdemux->major_brand = 0;
1975 if (qtdemux->pending_newsegment)
1976 gst_event_unref (qtdemux->pending_newsegment);
1977 qtdemux->pending_newsegment = NULL;
1978 qtdemux->upstream_format_is_time = FALSE;
1979 qtdemux->upstream_seekable = FALSE;
1980 qtdemux->upstream_size = 0;
1982 qtdemux->fragment_start = -1;
1983 qtdemux->fragment_start_offset = -1;
1984 qtdemux->duration = 0;
1985 qtdemux->moof_offset = 0;
1986 qtdemux->chapters_track_id = 0;
1987 qtdemux->have_group_id = FALSE;
1988 qtdemux->group_id = G_MAXUINT;
1990 g_queue_foreach (&qtdemux->protection_event_queue, (GFunc) gst_event_unref,
1992 g_queue_clear (&qtdemux->protection_event_queue);
1994 qtdemux->offset = 0;
1995 gst_adapter_clear (qtdemux->adapter);
1996 gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
1997 qtdemux->segment_seqnum = 0;
2000 for (n = 0; n < qtdemux->n_streams; n++) {
2001 gst_qtdemux_stream_free (qtdemux, qtdemux->streams[n]);
2002 qtdemux->streams[n] = NULL;
2004 qtdemux->n_streams = 0;
2005 qtdemux->n_video_streams = 0;
2006 qtdemux->n_audio_streams = 0;
2007 qtdemux->n_sub_streams = 0;
2008 qtdemux->exposed = FALSE;
2009 qtdemux->fragmented = FALSE;
2010 qtdemux->mss_mode = FALSE;
2011 gst_caps_replace (&qtdemux->media_caps, NULL);
2012 qtdemux->timescale = 0;
2013 qtdemux->got_moov = FALSE;
2014 if (qtdemux->protection_system_ids) {
2015 g_ptr_array_free (qtdemux->protection_system_ids, TRUE);
2016 qtdemux->protection_system_ids = NULL;
2018 } else if (qtdemux->mss_mode) {
2019 gst_flow_combiner_reset (qtdemux->flowcombiner);
2020 for (n = 0; n < qtdemux->n_streams; n++)
2021 gst_qtdemux_stream_clear (qtdemux, qtdemux->streams[n]);
2023 gst_flow_combiner_reset (qtdemux->flowcombiner);
2024 for (n = 0; n < qtdemux->n_streams; n++) {
2025 qtdemux->streams[n]->sent_eos = FALSE;
2026 qtdemux->streams[n]->time_position = 0;
2027 qtdemux->streams[n]->accumulated_base = 0;
2029 if (!qtdemux->pending_newsegment) {
2030 qtdemux->pending_newsegment = gst_event_new_segment (&qtdemux->segment);
2031 if (qtdemux->segment_seqnum)
2032 gst_event_set_seqnum (qtdemux->pending_newsegment,
2033 qtdemux->segment_seqnum);
2039 /* Maps the @segment to the qt edts internal segments and pushes
2040 * the correspnding segment event.
2042 * If it ends up being at a empty segment, a gap will be pushed and the next
2043 * edts segment will be activated in sequence.
2045 * To be used in push-mode only */
2047 gst_qtdemux_map_and_push_segments (GstQTDemux * qtdemux, GstSegment * segment)
2051 for (n = 0; n < qtdemux->n_streams; n++) {
2052 QtDemuxStream *stream = qtdemux->streams[n];
2054 stream->time_position = segment->start;
2056 /* in push mode we should be guaranteed that we will have empty segments
2057 * at the beginning and then one segment after, other scenarios are not
2058 * supported and are discarded when parsing the edts */
2059 for (i = 0; i < stream->n_segments; i++) {
2060 if (stream->segments[i].stop_time > segment->start) {
2061 gst_qtdemux_activate_segment (qtdemux, stream, i,
2062 stream->time_position);
2063 if (QTSEGMENT_IS_EMPTY (&stream->segments[i])) {
2064 /* push the empty segment and move to the next one */
2065 gst_qtdemux_send_gap_for_segment (qtdemux, stream, i,
2066 stream->time_position);
2070 g_assert (i == stream->n_segments - 1);
2077 gst_qtdemux_handle_sink_event (GstPad * sinkpad, GstObject * parent,
2080 GstQTDemux *demux = GST_QTDEMUX (parent);
2081 gboolean res = TRUE;
2083 GST_LOG_OBJECT (demux, "handling %s event", GST_EVENT_TYPE_NAME (event));
2085 switch (GST_EVENT_TYPE (event)) {
2086 case GST_EVENT_SEGMENT:
2089 QtDemuxStream *stream;
2093 /* some debug output */
2094 gst_event_copy_segment (event, &segment);
2095 GST_DEBUG_OBJECT (demux, "received newsegment %" GST_SEGMENT_FORMAT,
2098 /* erase any previously set segment */
2099 gst_event_replace (&demux->pending_newsegment, NULL);
2101 if (segment.format == GST_FORMAT_TIME) {
2102 GST_DEBUG_OBJECT (demux, "new pending_newsegment");
2103 gst_event_replace (&demux->pending_newsegment, event);
2104 demux->upstream_format_is_time = TRUE;
2106 GST_DEBUG_OBJECT (demux, "Not storing upstream newsegment, "
2107 "not in time format");
2109 /* chain will send initial newsegment after pads have been added */
2110 if (demux->state != QTDEMUX_STATE_MOVIE || !demux->n_streams) {
2111 GST_DEBUG_OBJECT (demux, "still starting, eating event");
2116 /* check if this matches a time seek we received previously
2117 * FIXME for backwards compatibility reasons we use the
2118 * seek_offset here to compare. In the future we might want to
2119 * change this to use the seqnum as it uniquely should identify
2120 * the segment that corresponds to the seek. */
2121 GST_DEBUG_OBJECT (demux, "Stored seek offset: %" G_GINT64_FORMAT
2122 ", received segment offset %" G_GINT64_FORMAT,
2123 demux->seek_offset, segment.start);
2124 if (segment.format == GST_FORMAT_BYTES
2125 && demux->seek_offset == segment.start) {
2126 GST_OBJECT_LOCK (demux);
2127 offset = segment.start;
2129 segment.format = GST_FORMAT_TIME;
2130 segment.start = demux->push_seek_start;
2131 segment.stop = demux->push_seek_stop;
2132 GST_DEBUG_OBJECT (demux, "Replaced segment with stored seek "
2133 "segment %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT,
2134 GST_TIME_ARGS (segment.start), GST_TIME_ARGS (segment.stop));
2135 GST_OBJECT_UNLOCK (demux);
2138 /* we only expect a BYTE segment, e.g. following a seek */
2139 if (segment.format == GST_FORMAT_BYTES) {
2140 if (GST_CLOCK_TIME_IS_VALID (segment.start)) {
2141 offset = segment.start;
2143 gst_qtdemux_find_sample (demux, segment.start, TRUE, FALSE, NULL,
2144 NULL, (gint64 *) & segment.start);
2145 if ((gint64) segment.start < 0)
2148 if (GST_CLOCK_TIME_IS_VALID (segment.stop)) {
2149 gst_qtdemux_find_sample (demux, segment.stop, FALSE, FALSE, NULL,
2150 NULL, (gint64 *) & segment.stop);
2151 /* keyframe seeking should already arrange for start >= stop,
2152 * but make sure in other rare cases */
2153 segment.stop = MAX (segment.stop, segment.start);
2155 } else if (segment.format == GST_FORMAT_TIME) {
2156 /* push all data on the adapter before starting this
2158 gst_qtdemux_process_adapter (demux, TRUE);
2160 GST_DEBUG_OBJECT (demux, "unsupported segment format, ignoring");
2164 /* accept upstream's notion of segment and distribute along */
2165 segment.format = GST_FORMAT_TIME;
2166 segment.position = segment.time = segment.start;
2167 segment.duration = demux->segment.duration;
2168 segment.base = gst_segment_to_running_time (&demux->segment,
2169 GST_FORMAT_TIME, demux->segment.position);
2171 gst_segment_copy_into (&segment, &demux->segment);
2172 GST_DEBUG_OBJECT (demux, "Pushing newseg %" GST_SEGMENT_FORMAT, &segment);
2174 /* map segment to internal qt segments and push on each stream */
2175 if (demux->n_streams) {
2176 if (demux->fragmented) {
2177 GstEvent *segment_event = gst_event_new_segment (&segment);
2179 gst_event_replace (&demux->pending_newsegment, NULL);
2180 gst_event_set_seqnum (segment_event, demux->segment_seqnum);
2181 gst_qtdemux_push_event (demux, segment_event);
2183 gst_event_replace (&demux->pending_newsegment, NULL);
2184 gst_qtdemux_map_and_push_segments (demux, &segment);
2188 /* clear leftover in current segment, if any */
2189 gst_adapter_clear (demux->adapter);
2191 /* set up streaming thread */
2192 demux->offset = offset;
2193 if (demux->upstream_format_is_time) {
2194 GST_DEBUG_OBJECT (demux, "Upstream is driving in time format, "
2195 "set values to restart reading from a new atom");
2196 demux->neededbytes = 16;
2199 gst_qtdemux_find_sample (demux, offset, TRUE, TRUE, &stream, &idx,
2202 demux->todrop = stream->samples[idx].offset - offset;
2203 demux->neededbytes = demux->todrop + stream->samples[idx].size;
2205 /* set up for EOS */
2206 demux->neededbytes = -1;
2211 gst_event_unref (event);
2215 case GST_EVENT_FLUSH_START:
2217 if (gst_event_get_seqnum (event) == demux->offset_seek_seqnum) {
2218 gst_event_unref (event);
2223 case GST_EVENT_FLUSH_STOP:
2227 dur = demux->segment.duration;
2228 gst_qtdemux_reset (demux, FALSE);
2229 demux->segment.duration = dur;
2231 if (gst_event_get_seqnum (event) == demux->offset_seek_seqnum) {
2232 gst_event_unref (event);
2238 /* If we are in push mode, and get an EOS before we've seen any streams,
2239 * then error out - we have nowhere to send the EOS */
2240 if (!demux->pullbased) {
2242 gboolean has_valid_stream = FALSE;
2243 for (i = 0; i < demux->n_streams; i++) {
2244 if (demux->streams[i]->pad != NULL) {
2245 has_valid_stream = TRUE;
2249 if (!has_valid_stream)
2250 gst_qtdemux_post_no_playable_stream_error (demux);
2252 GST_DEBUG_OBJECT (demux, "Data still available after EOS: %u",
2253 (guint) gst_adapter_available (demux->adapter));
2254 if (gst_qtdemux_process_adapter (demux, TRUE) != GST_FLOW_OK) {
2260 case GST_EVENT_CAPS:{
2261 GstCaps *caps = NULL;
2263 gst_event_parse_caps (event, &caps);
2264 gst_qtdemux_setcaps (demux, caps);
2266 gst_event_unref (event);
2269 case GST_EVENT_PROTECTION:
2271 const gchar *system_id = NULL;
2273 gst_event_parse_protection (event, &system_id, NULL, NULL);
2274 GST_DEBUG_OBJECT (demux, "Received protection event for system ID %s",
2276 gst_qtdemux_append_protection_system_id (demux, system_id);
2277 /* save the event for later, for source pads that have not been created */
2278 g_queue_push_tail (&demux->protection_event_queue, gst_event_ref (event));
2279 /* send it to all pads that already exist */
2280 gst_qtdemux_push_event (demux, event);
2288 res = gst_pad_event_default (demux->sinkpad, parent, event) & res;
2296 gst_qtdemux_set_index (GstElement * element, GstIndex * index)
2298 GstQTDemux *demux = GST_QTDEMUX (element);
2300 GST_OBJECT_LOCK (demux);
2301 if (demux->element_index)
2302 gst_object_unref (demux->element_index);
2304 demux->element_index = gst_object_ref (index);
2306 demux->element_index = NULL;
2308 GST_OBJECT_UNLOCK (demux);
2309 /* object lock might be taken again */
2311 gst_index_get_writer_id (index, GST_OBJECT (element), &demux->index_id);
2312 GST_DEBUG_OBJECT (demux, "Set index %" GST_PTR_FORMAT "for writer id %d",
2313 demux->element_index, demux->index_id);
2317 gst_qtdemux_get_index (GstElement * element)
2319 GstIndex *result = NULL;
2320 GstQTDemux *demux = GST_QTDEMUX (element);
2322 GST_OBJECT_LOCK (demux);
2323 if (demux->element_index)
2324 result = gst_object_ref (demux->element_index);
2325 GST_OBJECT_UNLOCK (demux);
2327 GST_DEBUG_OBJECT (demux, "Returning index %" GST_PTR_FORMAT, result);
2334 gst_qtdemux_stbl_free (QtDemuxStream * stream)
2336 g_free ((gpointer) stream->stco.data);
2337 stream->stco.data = NULL;
2338 g_free ((gpointer) stream->stsz.data);
2339 stream->stsz.data = NULL;
2340 g_free ((gpointer) stream->stsc.data);
2341 stream->stsc.data = NULL;
2342 g_free ((gpointer) stream->stts.data);
2343 stream->stts.data = NULL;
2344 g_free ((gpointer) stream->stss.data);
2345 stream->stss.data = NULL;
2346 g_free ((gpointer) stream->stps.data);
2347 stream->stps.data = NULL;
2348 g_free ((gpointer) stream->ctts.data);
2349 stream->ctts.data = NULL;
2353 gst_qtdemux_stream_flush_segments_data (GstQTDemux * qtdemux,
2354 QtDemuxStream * stream)
2356 g_free (stream->segments);
2357 stream->segments = NULL;
2358 stream->segment_index = -1;
2359 stream->accumulated_base = 0;
2363 gst_qtdemux_stream_flush_samples_data (GstQTDemux * qtdemux,
2364 QtDemuxStream * stream)
2366 g_free (stream->samples);
2367 stream->samples = NULL;
2368 gst_qtdemux_stbl_free (stream);
2371 g_free (stream->ra_entries);
2372 stream->ra_entries = NULL;
2373 stream->n_ra_entries = 0;
2375 stream->sample_index = -1;
2376 stream->stbl_index = -1;
2377 stream->n_samples = 0;
2378 stream->time_position = 0;
2380 stream->n_samples_moof = 0;
2381 stream->duration_moof = 0;
2385 gst_qtdemux_stream_clear (GstQTDemux * qtdemux, QtDemuxStream * stream)
2387 if (stream->allocator)
2388 gst_object_unref (stream->allocator);
2389 while (stream->buffers) {
2390 gst_buffer_unref (GST_BUFFER_CAST (stream->buffers->data));
2391 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
2393 if (stream->rgb8_palette) {
2394 gst_memory_unref (stream->rgb8_palette);
2395 stream->rgb8_palette = NULL;
2398 if (stream->pending_tags)
2399 gst_tag_list_unref (stream->pending_tags);
2400 stream->pending_tags = NULL;
2401 g_free (stream->redirect_uri);
2402 stream->redirect_uri = NULL;
2403 stream->sent_eos = FALSE;
2404 stream->sparse = FALSE;
2405 stream->protected = FALSE;
2406 if (stream->protection_scheme_info) {
2407 if (stream->protection_scheme_type == FOURCC_cenc) {
2408 QtDemuxCencSampleSetInfo *info =
2409 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
2410 if (info->default_properties)
2411 gst_structure_free (info->default_properties);
2412 if (info->crypto_info)
2413 g_ptr_array_free (info->crypto_info, TRUE);
2415 g_free (stream->protection_scheme_info);
2416 stream->protection_scheme_info = NULL;
2418 stream->protection_scheme_type = 0;
2419 stream->protection_scheme_version = 0;
2420 g_queue_foreach (&stream->protection_scheme_event_queue,
2421 (GFunc) gst_event_unref, NULL);
2422 g_queue_clear (&stream->protection_scheme_event_queue);
2423 gst_qtdemux_stream_flush_segments_data (qtdemux, stream);
2424 gst_qtdemux_stream_flush_samples_data (qtdemux, stream);
2428 gst_qtdemux_stream_free (GstQTDemux * qtdemux, QtDemuxStream * stream)
2430 gst_qtdemux_stream_clear (qtdemux, stream);
2432 gst_caps_unref (stream->caps);
2433 stream->caps = NULL;
2435 gst_element_remove_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
2436 gst_flow_combiner_remove_pad (qtdemux->flowcombiner, stream->pad);
2442 gst_qtdemux_remove_stream (GstQTDemux * qtdemux, int i)
2444 g_assert (i >= 0 && i < qtdemux->n_streams && qtdemux->streams[i] != NULL);
2446 gst_qtdemux_stream_free (qtdemux, qtdemux->streams[i]);
2447 qtdemux->streams[i] = qtdemux->streams[qtdemux->n_streams - 1];
2448 qtdemux->streams[qtdemux->n_streams - 1] = NULL;
2449 qtdemux->n_streams--;
2452 static GstStateChangeReturn
2453 gst_qtdemux_change_state (GstElement * element, GstStateChange transition)
2455 GstQTDemux *qtdemux = GST_QTDEMUX (element);
2456 GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
2458 switch (transition) {
2459 case GST_STATE_CHANGE_PAUSED_TO_READY:
2465 result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
2467 switch (transition) {
2468 case GST_STATE_CHANGE_PAUSED_TO_READY:{
2469 gst_qtdemux_reset (qtdemux, TRUE);
2480 qtdemux_parse_ftyp (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2482 /* counts as header data */
2483 qtdemux->header_size += length;
2485 /* only consider at least a sufficiently complete ftyp atom */
2489 qtdemux->major_brand = QT_FOURCC (buffer + 8);
2490 GST_DEBUG_OBJECT (qtdemux, "major brand: %" GST_FOURCC_FORMAT,
2491 GST_FOURCC_ARGS (qtdemux->major_brand));
2492 if (qtdemux->comp_brands)
2493 gst_buffer_unref (qtdemux->comp_brands);
2494 buf = qtdemux->comp_brands = gst_buffer_new_and_alloc (length - 16);
2495 gst_buffer_fill (buf, 0, buffer + 16, length - 16);
2500 qtdemux_handle_xmp_taglist (GstQTDemux * qtdemux, GstTagList * taglist,
2501 GstTagList * xmptaglist)
2503 /* Strip out bogus fields */
2505 if (gst_tag_list_get_scope (taglist) == GST_TAG_SCOPE_GLOBAL) {
2506 gst_tag_list_remove_tag (xmptaglist, GST_TAG_VIDEO_CODEC);
2507 gst_tag_list_remove_tag (xmptaglist, GST_TAG_AUDIO_CODEC);
2509 gst_tag_list_remove_tag (xmptaglist, GST_TAG_CONTAINER_FORMAT);
2512 GST_DEBUG_OBJECT (qtdemux, "Found XMP tags %" GST_PTR_FORMAT, xmptaglist);
2514 /* prioritize native tags using _KEEP mode */
2515 gst_tag_list_insert (taglist, xmptaglist, GST_TAG_MERGE_KEEP);
2516 gst_tag_list_unref (xmptaglist);
2521 qtdemux_parse_piff (GstQTDemux * qtdemux, const guint8 * buffer, gint length,
2529 QtDemuxStream *stream;
2530 GstStructure *structure;
2531 QtDemuxCencSampleSetInfo *ss_info = NULL;
2532 const gchar *system_id;
2533 gboolean uses_sub_sample_encryption = FALSE;
2535 if (qtdemux->n_streams == 0)
2538 stream = qtdemux->streams[0];
2540 structure = gst_caps_get_structure (stream->caps, 0);
2541 if (!gst_structure_has_name (structure, "application/x-cenc")) {
2542 GST_WARNING_OBJECT (qtdemux,
2543 "Attempting PIFF box parsing on an unencrypted stream.");
2547 gst_structure_get (structure, GST_PROTECTION_SYSTEM_ID_CAPS_FIELD,
2548 G_TYPE_STRING, &system_id, NULL);
2549 gst_qtdemux_append_protection_system_id (qtdemux, system_id);
2551 stream->protected = TRUE;
2552 stream->protection_scheme_type = FOURCC_cenc;
2554 if (!stream->protection_scheme_info)
2555 stream->protection_scheme_info = g_new0 (QtDemuxCencSampleSetInfo, 1);
2557 ss_info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
2559 if (ss_info->default_properties)
2560 gst_structure_free (ss_info->default_properties);
2562 ss_info->default_properties =
2563 gst_structure_new ("application/x-cenc",
2564 "iv_size", G_TYPE_UINT, iv_size, "encrypted", G_TYPE_BOOLEAN, TRUE, NULL);
2566 if (ss_info->crypto_info) {
2567 GST_LOG_OBJECT (qtdemux, "unreffing existing crypto_info");
2568 g_ptr_array_free (ss_info->crypto_info, TRUE);
2569 ss_info->crypto_info = NULL;
2573 gst_byte_reader_init (&br, buffer + offset + 16, length - offset - 16);
2575 if (!gst_byte_reader_get_uint8 (&br, &version)) {
2576 GST_ERROR_OBJECT (qtdemux, "Error getting box's version field");
2580 if (!gst_byte_reader_get_uint24_be (&br, &flags)) {
2581 GST_ERROR_OBJECT (qtdemux, "Error getting box's flags field");
2585 if ((flags & 0x000001)) {
2586 guint32 algorithm_id = 0;
2589 gboolean is_encrypted = TRUE;
2591 if (!gst_byte_reader_get_uint24_le (&br, &algorithm_id)) {
2592 GST_ERROR_OBJECT (qtdemux, "Error getting box's algorithm ID field");
2597 if (algorithm_id == 0) {
2598 is_encrypted = FALSE;
2599 } else if (algorithm_id == 1) {
2600 /* FIXME: maybe store this in properties? */
2601 GST_DEBUG_OBJECT (qtdemux, "AES 128-bits CTR encrypted stream");
2602 } else if (algorithm_id == 2) {
2603 /* FIXME: maybe store this in properties? */
2604 GST_DEBUG_OBJECT (qtdemux, "AES 128-bits CBC encrypted stream");
2607 if (!gst_byte_reader_get_uint8 (&br, &iv_size))
2610 if (!gst_byte_reader_get_data (&br, 16, &kid))
2613 kid_buf = gst_buffer_new_allocate (NULL, 16, NULL);
2614 gst_buffer_fill (kid_buf, 0, kid, 16);
2615 if (ss_info->default_properties)
2616 gst_structure_free (ss_info->default_properties);
2617 ss_info->default_properties =
2618 gst_structure_new ("application/x-cenc",
2619 "iv_size", G_TYPE_UINT, iv_size,
2620 "encrypted", G_TYPE_BOOLEAN, is_encrypted,
2621 "kid", GST_TYPE_BUFFER, kid_buf, NULL);
2622 GST_DEBUG_OBJECT (qtdemux, "default sample properties: "
2623 "is_encrypted=%u, iv_size=%u", is_encrypted, iv_size);
2624 gst_buffer_unref (kid_buf);
2625 } else if ((flags & 0x000002)) {
2626 uses_sub_sample_encryption = TRUE;
2629 if (!gst_byte_reader_get_uint32_be (&br, &qtdemux->cenc_aux_sample_count)) {
2630 GST_ERROR_OBJECT (qtdemux, "Error getting box's sample count field");
2634 ss_info->crypto_info =
2635 g_ptr_array_new_full (qtdemux->cenc_aux_sample_count,
2636 (GDestroyNotify) qtdemux_gst_structure_free);
2638 for (i = 0; i < qtdemux->cenc_aux_sample_count; ++i) {
2639 GstStructure *properties;
2643 properties = qtdemux_get_cenc_sample_properties (qtdemux, stream, i);
2644 if (properties == NULL) {
2645 GST_ERROR_OBJECT (qtdemux, "failed to get properties for sample %u", i);
2649 if (!gst_byte_reader_dup_data (&br, iv_size, &data)) {
2650 GST_ERROR_OBJECT (qtdemux, "IV data not present for sample %u", i);
2651 gst_structure_free (properties);
2654 buf = gst_buffer_new_wrapped (data, iv_size);
2655 gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL);
2656 gst_buffer_unref (buf);
2658 if (uses_sub_sample_encryption) {
2659 guint16 n_subsamples;
2661 if (!gst_byte_reader_get_uint16_be (&br, &n_subsamples)
2662 || n_subsamples == 0) {
2663 GST_ERROR_OBJECT (qtdemux,
2664 "failed to get subsample count for sample %u", i);
2665 gst_structure_free (properties);
2668 GST_LOG_OBJECT (qtdemux, "subsample count: %u", n_subsamples);
2669 if (!gst_byte_reader_dup_data (&br, n_subsamples * 6, &data)) {
2670 GST_ERROR_OBJECT (qtdemux, "failed to get subsample data for sample %u",
2672 gst_structure_free (properties);
2675 buf = gst_buffer_new_wrapped (data, n_subsamples * 6);
2676 gst_structure_set (properties,
2677 "subsample_count", G_TYPE_UINT, n_subsamples,
2678 "subsamples", GST_TYPE_BUFFER, buf, NULL);
2679 gst_buffer_unref (buf);
2681 gst_structure_set (properties, "subsample_count", G_TYPE_UINT, 0, NULL);
2684 g_ptr_array_add (ss_info->crypto_info, properties);
2689 qtdemux_parse_uuid (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2691 static const guint8 xmp_uuid[] = { 0xBE, 0x7A, 0xCF, 0xCB,
2692 0x97, 0xA9, 0x42, 0xE8,
2693 0x9C, 0x71, 0x99, 0x94,
2694 0x91, 0xE3, 0xAF, 0xAC
2696 static const guint8 playready_uuid[] = {
2697 0xd0, 0x8a, 0x4f, 0x18, 0x10, 0xf3, 0x4a, 0x82,
2698 0xb6, 0xc8, 0x32, 0xd8, 0xab, 0xa1, 0x83, 0xd3
2701 static const guint8 piff_sample_encryption_uuid[] = {
2702 0xa2, 0x39, 0x4f, 0x52, 0x5a, 0x9b, 0x4f, 0x14,
2703 0xa2, 0x44, 0x6c, 0x42, 0x7c, 0x64, 0x8d, 0xf4
2708 /* counts as header data */
2709 qtdemux->header_size += length;
2711 offset = (QT_UINT32 (buffer) == 0) ? 16 : 8;
2713 if (length <= offset + 16) {
2714 GST_DEBUG_OBJECT (qtdemux, "uuid atom is too short, skipping");
2718 if (memcmp (buffer + offset, xmp_uuid, 16) == 0) {
2720 GstTagList *taglist;
2722 buf = _gst_buffer_new_wrapped ((guint8 *) buffer + offset + 16,
2723 length - offset - 16, NULL);
2724 taglist = gst_tag_list_from_xmp_buffer (buf);
2725 gst_buffer_unref (buf);
2727 qtdemux_handle_xmp_taglist (qtdemux, qtdemux->tag_list, taglist);
2729 } else if (memcmp (buffer + offset, playready_uuid, 16) == 0) {
2731 const gunichar2 *s_utf16;
2734 len = GST_READ_UINT16_LE (buffer + offset + 0x30);
2735 s_utf16 = (const gunichar2 *) (buffer + offset + 0x32);
2736 contents = g_utf16_to_utf8 (s_utf16, len / 2, NULL, NULL, NULL);
2737 GST_ERROR_OBJECT (qtdemux, "contents: %s", contents);
2741 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT,
2742 (_("Cannot play stream because it is encrypted with PlayReady DRM.")),
2744 } else if (memcmp (buffer + offset, piff_sample_encryption_uuid, 16) == 0) {
2745 qtdemux_parse_piff (qtdemux, buffer, length, offset);
2747 GST_DEBUG_OBJECT (qtdemux, "Ignoring unknown uuid: %08x-%08x-%08x-%08x",
2748 GST_READ_UINT32_LE (buffer + offset),
2749 GST_READ_UINT32_LE (buffer + offset + 4),
2750 GST_READ_UINT32_LE (buffer + offset + 8),
2751 GST_READ_UINT32_LE (buffer + offset + 12));
2756 qtdemux_parse_sidx (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2758 GstSidxParser sidx_parser;
2759 GstIsoffParserResult res;
2762 gst_isoff_qt_sidx_parser_init (&sidx_parser);
2765 gst_isoff_qt_sidx_parser_add_data (&sidx_parser, buffer, length,
2767 GST_DEBUG_OBJECT (qtdemux, "sidx parse result: %d", res);
2768 if (res == GST_ISOFF_QT_PARSER_DONE) {
2769 check_update_duration (qtdemux, sidx_parser.cumulative_pts);
2771 gst_isoff_qt_sidx_parser_clear (&sidx_parser);
2774 /* caller verifies at least 8 bytes in buf */
2776 extract_initial_length_and_fourcc (const guint8 * data, guint size,
2777 guint64 * plength, guint32 * pfourcc)
2782 length = QT_UINT32 (data);
2783 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
2784 fourcc = QT_FOURCC (data + 4);
2785 GST_DEBUG ("atom type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
2788 length = G_MAXUINT64;
2789 } else if (length == 1 && size >= 16) {
2790 /* this means we have an extended size, which is the 64 bit value of
2791 * the next 8 bytes */
2792 length = QT_UINT64 (data + 8);
2793 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
2803 qtdemux_parse_mehd (GstQTDemux * qtdemux, GstByteReader * br)
2805 guint32 version = 0;
2806 GstClockTime duration = 0;
2808 if (!gst_byte_reader_get_uint32_be (br, &version))
2813 if (!gst_byte_reader_get_uint64_be (br, &duration))
2818 if (!gst_byte_reader_get_uint32_be (br, &dur))
2823 GST_INFO_OBJECT (qtdemux, "mehd duration: %" G_GUINT64_FORMAT, duration);
2824 qtdemux->duration = duration;
2830 GST_DEBUG_OBJECT (qtdemux, "parsing mehd failed");
2836 qtdemux_parse_trex (GstQTDemux * qtdemux, QtDemuxStream * stream,
2837 guint32 * ds_duration, guint32 * ds_size, guint32 * ds_flags)
2839 if (!stream->parsed_trex && qtdemux->moov_node) {
2841 GstByteReader trex_data;
2843 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
2845 trex = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_trex,
2848 guint32 id = 0, dur = 0, size = 0, flags = 0, dummy = 0;
2850 /* skip version/flags */
2851 if (!gst_byte_reader_skip (&trex_data, 4))
2853 if (!gst_byte_reader_get_uint32_be (&trex_data, &id))
2855 if (id != stream->track_id)
2857 /* sample description index; ignore */
2858 if (!gst_byte_reader_get_uint32_be (&trex_data, &dummy))
2860 if (!gst_byte_reader_get_uint32_be (&trex_data, &dur))
2862 if (!gst_byte_reader_get_uint32_be (&trex_data, &size))
2864 if (!gst_byte_reader_get_uint32_be (&trex_data, &flags))
2867 GST_DEBUG_OBJECT (qtdemux, "fragment defaults for stream %d; "
2868 "duration %d, size %d, flags 0x%x", stream->track_id,
2871 stream->parsed_trex = TRUE;
2872 stream->def_sample_duration = dur;
2873 stream->def_sample_size = size;
2874 stream->def_sample_flags = flags;
2877 /* iterate all siblings */
2878 trex = qtdemux_tree_get_sibling_by_type_full (trex, FOURCC_trex,
2884 *ds_duration = stream->def_sample_duration;
2885 *ds_size = stream->def_sample_size;
2886 *ds_flags = stream->def_sample_flags;
2888 /* even then, above values are better than random ... */
2889 if (G_UNLIKELY (!stream->parsed_trex)) {
2890 GST_WARNING_OBJECT (qtdemux,
2891 "failed to find fragment defaults for stream %d", stream->track_id);
2898 /* This method should be called whenever a more accurate duration might
2899 * have been found. It will update all relevant variables if/where needed
2902 check_update_duration (GstQTDemux * qtdemux, GstClockTime duration)
2906 GstClockTime prevdur;
2908 movdur = GSTTIME_TO_QTTIME (qtdemux, duration);
2910 if (movdur > qtdemux->duration) {
2911 prevdur = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
2912 GST_DEBUG_OBJECT (qtdemux,
2913 "Updating total duration to %" GST_TIME_FORMAT " was %" GST_TIME_FORMAT,
2914 GST_TIME_ARGS (duration), GST_TIME_ARGS (prevdur));
2915 qtdemux->duration = movdur;
2916 GST_DEBUG_OBJECT (qtdemux,
2917 "qtdemux->segment.duration: %" GST_TIME_FORMAT " .stop: %"
2918 GST_TIME_FORMAT, GST_TIME_ARGS (qtdemux->segment.duration),
2919 GST_TIME_ARGS (qtdemux->segment.stop));
2920 if (qtdemux->segment.duration == prevdur) {
2921 /* If the current segment has duration/stop identical to previous duration
2922 * update them also (because they were set at that point in time with
2923 * the wrong duration */
2924 /* We convert the value *from* the timescale version to avoid rounding errors */
2925 GstClockTime fixeddur = QTTIME_TO_GSTTIME (qtdemux, movdur);
2926 GST_DEBUG_OBJECT (qtdemux, "Updated segment.duration and segment.stop");
2927 qtdemux->segment.duration = fixeddur;
2928 qtdemux->segment.stop = fixeddur;
2931 for (i = 0; i < qtdemux->n_streams; i++) {
2932 QtDemuxStream *stream = qtdemux->streams[i];
2934 movdur = GSTTIME_TO_QTSTREAMTIME (stream, duration);
2935 if (movdur > stream->duration) {
2936 GST_DEBUG_OBJECT (qtdemux,
2937 "Updating stream #%d duration to %" GST_TIME_FORMAT, i,
2938 GST_TIME_ARGS (duration));
2939 stream->duration = movdur;
2940 if (stream->dummy_segment) {
2941 /* Update all dummy values to new duration */
2942 stream->segments[0].stop_time = duration;
2943 stream->segments[0].duration = duration;
2944 stream->segments[0].media_stop = duration;
2946 /* let downstream know we possibly have a new stop time */
2947 if (stream->segment_index != -1) {
2950 if (qtdemux->segment.rate >= 0) {
2951 pos = stream->segment.start;
2953 pos = stream->segment.stop;
2956 gst_qtdemux_stream_update_segment (qtdemux, stream,
2957 stream->segment_index, pos, NULL, NULL);
2966 qtdemux_parse_trun (GstQTDemux * qtdemux, GstByteReader * trun,
2967 QtDemuxStream * stream, guint32 d_sample_duration, guint32 d_sample_size,
2968 guint32 d_sample_flags, gint64 moof_offset, gint64 moof_length,
2969 gint64 * base_offset, gint64 * running_offset, gint64 decode_ts)
2971 GstClockTime gst_ts = GST_CLOCK_TIME_NONE;
2973 gint32 data_offset = 0;
2974 guint32 flags = 0, first_flags = 0, samples_count = 0;
2977 guint entry_size, dur_offset, size_offset, flags_offset = 0, ct_offset = 0;
2978 QtDemuxSample *sample;
2979 gboolean ismv = FALSE;
2981 GST_LOG_OBJECT (qtdemux, "parsing trun stream %d; "
2982 "default dur %d, size %d, flags 0x%x, base offset %" G_GINT64_FORMAT ", "
2983 "decode ts %" G_GINT64_FORMAT, stream->track_id, d_sample_duration,
2984 d_sample_size, d_sample_flags, *base_offset, decode_ts);
2986 if (stream->pending_seek && moof_offset < stream->pending_seek->moof_offset) {
2987 GST_INFO_OBJECT (stream->pad, "skipping trun before seek target fragment");
2991 /* presence of stss or not can't really tell us much,
2992 * and flags and so on tend to be marginally reliable in these files */
2993 if (stream->subtype == FOURCC_soun) {
2994 GST_DEBUG_OBJECT (qtdemux,
2995 "sound track in fragmented file; marking all keyframes");
2996 stream->all_keyframe = TRUE;
2999 if (!gst_byte_reader_skip (trun, 1) ||
3000 !gst_byte_reader_get_uint24_be (trun, &flags))
3003 if (!gst_byte_reader_get_uint32_be (trun, &samples_count))
3006 if (flags & TR_DATA_OFFSET) {
3007 /* note this is really signed */
3008 if (!gst_byte_reader_get_int32_be (trun, &data_offset))
3010 GST_LOG_OBJECT (qtdemux, "trun data offset %d", data_offset);
3011 /* default base offset = first byte of moof */
3012 if (*base_offset == -1) {
3013 GST_LOG_OBJECT (qtdemux, "base_offset at moof");
3014 *base_offset = moof_offset;
3016 *running_offset = *base_offset + data_offset;
3018 /* if no offset at all, that would mean data starts at moof start,
3019 * which is a bit wrong and is ismv crappy way, so compensate
3020 * assuming data is in mdat following moof */
3021 if (*base_offset == -1) {
3022 *base_offset = moof_offset + moof_length + 8;
3023 GST_LOG_OBJECT (qtdemux, "base_offset assumed in mdat after moof");
3026 if (*running_offset == -1)
3027 *running_offset = *base_offset;
3030 GST_LOG_OBJECT (qtdemux, "running offset now %" G_GINT64_FORMAT,
3032 GST_LOG_OBJECT (qtdemux, "trun offset %d, flags 0x%x, entries %d",
3033 data_offset, flags, samples_count);
3035 if (flags & TR_FIRST_SAMPLE_FLAGS) {
3036 if (G_UNLIKELY (flags & TR_SAMPLE_FLAGS)) {
3037 GST_DEBUG_OBJECT (qtdemux,
3038 "invalid flags; SAMPLE and FIRST_SAMPLE present, discarding latter");
3039 flags ^= TR_FIRST_SAMPLE_FLAGS;
3041 if (!gst_byte_reader_get_uint32_be (trun, &first_flags))
3043 GST_LOG_OBJECT (qtdemux, "first flags: 0x%x", first_flags);
3047 /* FIXME ? spec says other bits should also be checked to determine
3048 * entry size (and prefix size for that matter) */
3050 dur_offset = size_offset = 0;
3051 if (flags & TR_SAMPLE_DURATION) {
3052 GST_LOG_OBJECT (qtdemux, "entry duration present");
3053 dur_offset = entry_size;
3056 if (flags & TR_SAMPLE_SIZE) {
3057 GST_LOG_OBJECT (qtdemux, "entry size present");
3058 size_offset = entry_size;
3061 if (flags & TR_SAMPLE_FLAGS) {
3062 GST_LOG_OBJECT (qtdemux, "entry flags present");
3063 flags_offset = entry_size;
3066 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
3067 GST_LOG_OBJECT (qtdemux, "entry ct offset present");
3068 ct_offset = entry_size;
3072 if (!qt_atom_parser_has_chunks (trun, samples_count, entry_size))
3074 data = (guint8 *) gst_byte_reader_peek_data_unchecked (trun);
3076 if (stream->n_samples + samples_count >=
3077 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample))
3080 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
3081 stream->n_samples + samples_count, (guint) sizeof (QtDemuxSample),
3082 (stream->n_samples + samples_count) *
3083 sizeof (QtDemuxSample) / (1024.0 * 1024.0));
3085 /* create a new array of samples if it's the first sample parsed */
3086 if (stream->n_samples == 0) {
3087 g_assert (stream->samples == NULL);
3088 stream->samples = g_try_new0 (QtDemuxSample, samples_count);
3089 /* or try to reallocate it with space enough to insert the new samples */
3091 stream->samples = g_try_renew (QtDemuxSample, stream->samples,
3092 stream->n_samples + samples_count);
3093 if (stream->samples == NULL)
3096 if (qtdemux->fragment_start != -1) {
3097 timestamp = GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->fragment_start);
3098 qtdemux->fragment_start = -1;
3100 if (stream->n_samples == 0) {
3101 if (decode_ts > 0) {
3102 timestamp = decode_ts;
3103 } else if (stream->pending_seek != NULL) {
3104 /* if we don't have a timestamp from a tfdt box, we'll use the one
3105 * from the mfra seek table */
3106 GST_INFO_OBJECT (stream->pad, "pending seek ts = %" GST_TIME_FORMAT,
3107 GST_TIME_ARGS (stream->pending_seek->ts));
3109 /* FIXME: this is not fully correct, the timestamp refers to the random
3110 * access sample refered to in the tfra entry, which may not necessarily
3111 * be the first sample in the tfrag/trun (but hopefully/usually is) */
3112 timestamp = GSTTIME_TO_QTSTREAMTIME (stream, stream->pending_seek->ts);
3117 gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
3118 GST_INFO_OBJECT (stream->pad, "first sample ts %" GST_TIME_FORMAT,
3119 GST_TIME_ARGS (gst_ts));
3121 /* subsequent fragments extend stream */
3123 stream->samples[stream->n_samples - 1].timestamp +
3124 stream->samples[stream->n_samples - 1].duration;
3126 gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
3127 GST_INFO_OBJECT (qtdemux, "first sample ts %" GST_TIME_FORMAT
3128 " (extends previous samples)", GST_TIME_ARGS (gst_ts));
3132 sample = stream->samples + stream->n_samples;
3133 for (i = 0; i < samples_count; i++) {
3134 guint32 dur, size, sflags, ct;
3136 /* first read sample data */
3137 if (flags & TR_SAMPLE_DURATION) {
3138 dur = QT_UINT32 (data + dur_offset);
3140 dur = d_sample_duration;
3142 if (flags & TR_SAMPLE_SIZE) {
3143 size = QT_UINT32 (data + size_offset);
3145 size = d_sample_size;
3147 if (flags & TR_FIRST_SAMPLE_FLAGS) {
3149 sflags = first_flags;
3151 sflags = d_sample_flags;
3153 } else if (flags & TR_SAMPLE_FLAGS) {
3154 sflags = QT_UINT32 (data + flags_offset);
3156 sflags = d_sample_flags;
3158 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
3159 ct = QT_UINT32 (data + ct_offset);
3165 /* fill the sample information */
3166 sample->offset = *running_offset;
3167 sample->pts_offset = ct;
3168 sample->size = size;
3169 sample->timestamp = timestamp;
3170 sample->duration = dur;
3171 /* sample-is-difference-sample */
3172 /* ismv seems to use 0x40 for keyframe, 0xc0 for non-keyframe,
3173 * now idea how it relates to bitfield other than massive LE/BE confusion */
3174 sample->keyframe = ismv ? ((sflags & 0xff) == 0x40) : !(sflags & 0x10000);
3175 *running_offset += size;
3177 stream->duration_moof += dur;
3181 /* Update total duration if needed */
3182 check_update_duration (qtdemux, QTSTREAMTIME_TO_GSTTIME (stream, timestamp));
3184 stream->n_samples += samples_count;
3185 stream->n_samples_moof += samples_count;
3187 if (stream->pending_seek != NULL)
3188 stream->pending_seek = NULL;
3194 GST_WARNING_OBJECT (qtdemux, "failed to parse trun");
3199 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
3205 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
3206 "be larger than %uMB (broken file?)", stream->n_samples,
3207 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
3212 /* find stream with @id */
3213 static inline QtDemuxStream *
3214 qtdemux_find_stream (GstQTDemux * qtdemux, guint32 id)
3216 QtDemuxStream *stream;
3220 if (G_UNLIKELY (!id)) {
3221 GST_DEBUG_OBJECT (qtdemux, "invalid track id 0");
3225 /* try to get it fast and simple */
3226 if (G_LIKELY (id <= qtdemux->n_streams)) {
3227 stream = qtdemux->streams[id - 1];
3228 if (G_LIKELY (stream->track_id == id))
3232 /* linear search otherwise */
3233 for (i = 0; i < qtdemux->n_streams; i++) {
3234 stream = qtdemux->streams[i];
3235 if (stream->track_id == id)
3238 if (qtdemux->mss_mode) {
3239 /* mss should have only 1 stream anyway */
3240 return qtdemux->streams[0];
3247 qtdemux_parse_mfhd (GstQTDemux * qtdemux, GstByteReader * mfhd,
3248 guint32 * fragment_number)
3250 if (!gst_byte_reader_skip (mfhd, 4))
3252 if (!gst_byte_reader_get_uint32_be (mfhd, fragment_number))
3257 GST_WARNING_OBJECT (qtdemux, "Failed to parse mfhd atom");
3263 qtdemux_parse_tfhd (GstQTDemux * qtdemux, GstByteReader * tfhd,
3264 QtDemuxStream ** stream, guint32 * default_sample_duration,
3265 guint32 * default_sample_size, guint32 * default_sample_flags,
3266 gint64 * base_offset)
3269 guint32 track_id = 0;
3271 if (!gst_byte_reader_skip (tfhd, 1) ||
3272 !gst_byte_reader_get_uint24_be (tfhd, &flags))
3275 if (!gst_byte_reader_get_uint32_be (tfhd, &track_id))
3278 *stream = qtdemux_find_stream (qtdemux, track_id);
3279 if (G_UNLIKELY (!*stream))
3280 goto unknown_stream;
3282 if (flags & TF_DEFAULT_BASE_IS_MOOF)
3283 *base_offset = qtdemux->moof_offset;
3285 if (flags & TF_BASE_DATA_OFFSET)
3286 if (!gst_byte_reader_get_uint64_be (tfhd, (guint64 *) base_offset))
3289 /* obtain stream defaults */
3290 qtdemux_parse_trex (qtdemux, *stream,
3291 default_sample_duration, default_sample_size, default_sample_flags);
3293 /* FIXME: Handle TF_SAMPLE_DESCRIPTION_INDEX properly */
3294 if (flags & TF_SAMPLE_DESCRIPTION_INDEX)
3295 if (!gst_byte_reader_skip (tfhd, 4))
3298 if (flags & TF_DEFAULT_SAMPLE_DURATION)
3299 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_duration))
3302 if (flags & TF_DEFAULT_SAMPLE_SIZE)
3303 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_size))
3306 if (flags & TF_DEFAULT_SAMPLE_FLAGS)
3307 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_flags))
3314 GST_WARNING_OBJECT (qtdemux, "invalid track fragment header");
3319 GST_DEBUG_OBJECT (qtdemux, "unknown stream in tfhd");
3325 qtdemux_parse_tfdt (GstQTDemux * qtdemux, GstByteReader * br,
3326 guint64 * decode_time)
3328 guint32 version = 0;
3330 if (!gst_byte_reader_get_uint32_be (br, &version))
3335 if (!gst_byte_reader_get_uint64_be (br, decode_time))
3338 guint32 dec_time = 0;
3339 if (!gst_byte_reader_get_uint32_be (br, &dec_time))
3341 *decode_time = dec_time;
3344 GST_INFO_OBJECT (qtdemux, "Track fragment decode time: %" G_GUINT64_FORMAT,
3351 GST_DEBUG_OBJECT (qtdemux, "parsing tfdt failed");
3356 /* Returns a pointer to a GstStructure containing the properties of
3357 * the stream sample identified by @sample_index. The caller must unref
3358 * the returned object after use. Returns NULL if unsuccessful. */
3359 static GstStructure *
3360 qtdemux_get_cenc_sample_properties (GstQTDemux * qtdemux,
3361 QtDemuxStream * stream, guint sample_index)
3363 QtDemuxCencSampleSetInfo *info = NULL;
3365 g_return_val_if_fail (stream != NULL, NULL);
3366 g_return_val_if_fail (stream->protected, NULL);
3367 g_return_val_if_fail (stream->protection_scheme_info != NULL, NULL);
3369 info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
3371 /* Currently, cenc properties for groups of samples are not supported, so
3372 * simply return a copy of the default sample properties */
3373 return gst_structure_copy (info->default_properties);
3376 /* Parses the sizes of sample auxiliary information contained within a stream,
3377 * as given in a saiz box. Returns array of sample_count guint8 size values,
3378 * or NULL on failure */
3380 qtdemux_parse_saiz (GstQTDemux * qtdemux, QtDemuxStream * stream,
3381 GstByteReader * br, guint32 * sample_count)
3385 guint8 default_info_size;
3387 g_return_val_if_fail (qtdemux != NULL, NULL);
3388 g_return_val_if_fail (stream != NULL, NULL);
3389 g_return_val_if_fail (br != NULL, NULL);
3390 g_return_val_if_fail (sample_count != NULL, NULL);
3392 if (!gst_byte_reader_get_uint32_be (br, &flags))
3396 /* aux_info_type and aux_info_type_parameter are ignored */
3397 if (!gst_byte_reader_skip (br, 8))
3401 if (!gst_byte_reader_get_uint8 (br, &default_info_size))
3403 GST_DEBUG_OBJECT (qtdemux, "default_info_size: %u", default_info_size);
3405 if (!gst_byte_reader_get_uint32_be (br, sample_count))
3407 GST_DEBUG_OBJECT (qtdemux, "sample_count: %u", *sample_count);
3410 if (default_info_size == 0) {
3411 if (!gst_byte_reader_dup_data (br, *sample_count, &info_sizes)) {
3415 info_sizes = g_new (guint8, *sample_count);
3416 memset (info_sizes, default_info_size, *sample_count);
3422 /* Parses the offset of sample auxiliary information contained within a stream,
3423 * as given in a saio box. Returns TRUE if successful; FALSE otherwise. */
3425 qtdemux_parse_saio (GstQTDemux * qtdemux, QtDemuxStream * stream,
3426 GstByteReader * br, guint32 * info_type, guint32 * info_type_parameter,
3431 guint32 aux_info_type = 0;
3432 guint32 aux_info_type_parameter = 0;
3433 guint32 entry_count;
3436 const guint8 *aux_info_type_data = NULL;
3438 g_return_val_if_fail (qtdemux != NULL, FALSE);
3439 g_return_val_if_fail (stream != NULL, FALSE);
3440 g_return_val_if_fail (br != NULL, FALSE);
3441 g_return_val_if_fail (offset != NULL, FALSE);
3443 if (!gst_byte_reader_get_uint8 (br, &version))
3446 if (!gst_byte_reader_get_uint24_be (br, &flags))
3451 if (!gst_byte_reader_get_data (br, 4, &aux_info_type_data))
3453 aux_info_type = QT_FOURCC (aux_info_type_data);
3455 if (!gst_byte_reader_get_uint32_be (br, &aux_info_type_parameter))
3457 } else if (stream->protected) {
3458 aux_info_type = stream->protection_scheme_type;
3460 aux_info_type = stream->fourcc;
3464 *info_type = aux_info_type;
3465 if (info_type_parameter)
3466 *info_type_parameter = aux_info_type_parameter;
3468 GST_DEBUG_OBJECT (qtdemux, "aux_info_type: '%" GST_FOURCC_FORMAT "', "
3469 "aux_info_type_parameter: %#06x",
3470 GST_FOURCC_ARGS (aux_info_type), aux_info_type_parameter);
3472 if (!gst_byte_reader_get_uint32_be (br, &entry_count))
3475 if (entry_count != 1) {
3476 GST_ERROR_OBJECT (qtdemux, "multiple offsets are not supported");
3481 if (!gst_byte_reader_get_uint32_be (br, &off_32))
3483 *offset = (guint64) off_32;
3485 if (!gst_byte_reader_get_uint64_be (br, &off_64))
3490 GST_DEBUG_OBJECT (qtdemux, "offset: %" G_GUINT64_FORMAT, *offset);
3495 qtdemux_gst_structure_free (GstStructure * gststructure)
3498 gst_structure_free (gststructure);
3502 /* Parses auxiliary information relating to samples protected using Common
3503 * Encryption (cenc); the format of this information is defined in
3504 * ISO/IEC 23001-7. Returns TRUE if successful; FALSE otherwise. */
3506 qtdemux_parse_cenc_aux_info (GstQTDemux * qtdemux, QtDemuxStream * stream,
3507 GstByteReader * br, guint8 * info_sizes, guint32 sample_count)
3509 QtDemuxCencSampleSetInfo *ss_info = NULL;
3513 g_return_val_if_fail (qtdemux != NULL, FALSE);
3514 g_return_val_if_fail (stream != NULL, FALSE);
3515 g_return_val_if_fail (br != NULL, FALSE);
3516 g_return_val_if_fail (stream->protected, FALSE);
3517 g_return_val_if_fail (stream->protection_scheme_info != NULL, FALSE);
3519 ss_info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
3521 if (ss_info->crypto_info) {
3522 GST_LOG_OBJECT (qtdemux, "unreffing existing crypto_info");
3523 g_ptr_array_free (ss_info->crypto_info, TRUE);
3526 ss_info->crypto_info =
3527 g_ptr_array_new_full (sample_count,
3528 (GDestroyNotify) qtdemux_gst_structure_free);
3530 for (i = 0; i < sample_count; ++i) {
3531 GstStructure *properties;
3532 guint16 n_subsamples = 0;
3537 properties = qtdemux_get_cenc_sample_properties (qtdemux, stream, i);
3538 if (properties == NULL) {
3539 GST_ERROR_OBJECT (qtdemux, "failed to get properties for sample %u", i);
3542 if (!gst_structure_get_uint (properties, "iv_size", &iv_size)) {
3543 GST_ERROR_OBJECT (qtdemux, "failed to get iv_size for sample %u", i);
3544 gst_structure_free (properties);
3547 if (!gst_byte_reader_dup_data (br, iv_size, &data)) {
3548 GST_ERROR_OBJECT (qtdemux, "failed to get IV for sample %u", i);
3549 gst_structure_free (properties);
3552 buf = gst_buffer_new_wrapped (data, iv_size);
3553 gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL);
3554 gst_buffer_unref (buf);
3555 size = info_sizes[i];
3556 if (size > iv_size) {
3557 if (!gst_byte_reader_get_uint16_be (br, &n_subsamples)
3558 || !(n_subsamples > 0)) {
3559 gst_structure_free (properties);
3560 GST_ERROR_OBJECT (qtdemux,
3561 "failed to get subsample count for sample %u", i);
3564 GST_LOG_OBJECT (qtdemux, "subsample count: %u", n_subsamples);
3565 if (!gst_byte_reader_dup_data (br, n_subsamples * 6, &data)) {
3566 GST_ERROR_OBJECT (qtdemux, "failed to get subsample data for sample %u",
3568 gst_structure_free (properties);
3571 buf = gst_buffer_new_wrapped (data, n_subsamples * 6);
3573 gst_structure_free (properties);
3576 gst_structure_set (properties,
3577 "subsample_count", G_TYPE_UINT, n_subsamples,
3578 "subsamples", GST_TYPE_BUFFER, buf, NULL);
3579 gst_buffer_unref (buf);
3581 gst_structure_set (properties, "subsample_count", G_TYPE_UINT, 0, NULL);
3583 g_ptr_array_add (ss_info->crypto_info, properties);
3588 /* Converts a UUID in raw byte form to a string representation, as defined in
3589 * RFC 4122. The caller takes ownership of the returned string and is
3590 * responsible for freeing it after use. */
3592 qtdemux_uuid_bytes_to_string (gconstpointer uuid_bytes)
3594 const guint8 *uuid = (const guint8 *) uuid_bytes;
3596 return g_strdup_printf ("%02x%02x%02x%02x-%02x%02x-%02x%02x-"
3597 "%02x%02x-%02x%02x%02x%02x%02x%02x",
3598 uuid[0], uuid[1], uuid[2], uuid[3],
3599 uuid[4], uuid[5], uuid[6], uuid[7],
3600 uuid[8], uuid[9], uuid[10], uuid[11],
3601 uuid[12], uuid[13], uuid[14], uuid[15]);
3604 /* Parses a Protection System Specific Header box (pssh), as defined in the
3605 * Common Encryption (cenc) standard (ISO/IEC 23001-7), which contains
3606 * information needed by a specific content protection system in order to
3607 * decrypt cenc-protected tracks. Returns TRUE if successful; FALSE
3610 qtdemux_parse_pssh (GstQTDemux * qtdemux, GNode * node)
3612 gchar *sysid_string;
3613 guint32 pssh_size = QT_UINT32 (node->data);
3614 GstBuffer *pssh = NULL;
3615 GstEvent *event = NULL;
3616 guint32 parent_box_type;
3619 if (G_UNLIKELY (pssh_size < 32U)) {
3620 GST_ERROR_OBJECT (qtdemux, "invalid box size");
3625 qtdemux_uuid_bytes_to_string ((const guint8 *) node->data + 12);
3627 gst_qtdemux_append_protection_system_id (qtdemux, sysid_string);
3629 pssh = gst_buffer_new_wrapped (g_memdup (node->data, pssh_size), pssh_size);
3630 GST_LOG_OBJECT (qtdemux, "cenc pssh size: %" G_GSIZE_FORMAT,
3631 gst_buffer_get_size (pssh));
3633 parent_box_type = QT_FOURCC ((const guint8 *) node->parent->data + 4);
3635 /* Push an event containing the pssh box onto the queues of all streams. */
3636 event = gst_event_new_protection (sysid_string, pssh,
3637 (parent_box_type == FOURCC_moov) ? "isobmff/moov" : "isobmff/moof");
3638 for (i = 0; i < qtdemux->n_streams; ++i) {
3639 g_queue_push_tail (&qtdemux->streams[i]->protection_scheme_event_queue,
3640 gst_event_ref (event));
3642 g_free (sysid_string);
3643 gst_event_unref (event);
3644 gst_buffer_unref (pssh);
3649 qtdemux_parse_moof (GstQTDemux * qtdemux, const guint8 * buffer, guint length,
3650 guint64 moof_offset, QtDemuxStream * stream)
3652 GNode *moof_node, *traf_node, *tfhd_node, *trun_node, *tfdt_node, *mfhd_node;
3654 GstByteReader mfhd_data, trun_data, tfhd_data, tfdt_data;
3655 GNode *saiz_node, *saio_node, *pssh_node;
3656 GstByteReader saiz_data, saio_data;
3657 guint32 ds_size = 0, ds_duration = 0, ds_flags = 0;
3658 gint64 base_offset, running_offset;
3661 /* NOTE @stream ignored */
3663 moof_node = g_node_new ((guint8 *) buffer);
3664 qtdemux_parse_node (qtdemux, moof_node, buffer, length);
3665 qtdemux_node_dump (qtdemux, moof_node);
3667 /* Get fragment number from mfhd and check it's valid */
3669 qtdemux_tree_get_child_by_type_full (moof_node, FOURCC_mfhd, &mfhd_data);
3670 if (mfhd_node == NULL)
3672 if (!qtdemux_parse_mfhd (qtdemux, &mfhd_data, &frag_num))
3674 GST_DEBUG_OBJECT (qtdemux, "Fragment #%d", frag_num);
3676 /* unknown base_offset to start with */
3677 base_offset = running_offset = -1;
3678 traf_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_traf);
3680 guint64 decode_time = 0;
3682 /* Fragment Header node */
3684 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfhd,
3688 if (!qtdemux_parse_tfhd (qtdemux, &tfhd_data, &stream, &ds_duration,
3689 &ds_size, &ds_flags, &base_offset))
3692 /* The following code assumes at most a single set of sample auxiliary
3693 * data in the fragment (consisting of a saiz box and a corresponding saio
3694 * box); in theory, however, there could be multiple sets of sample
3695 * auxiliary data in a fragment. */
3697 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saiz,
3700 guint32 info_type = 0;
3702 guint32 info_type_parameter = 0;
3704 g_free (qtdemux->cenc_aux_info_sizes);
3706 qtdemux->cenc_aux_info_sizes =
3707 qtdemux_parse_saiz (qtdemux, stream, &saiz_data,
3708 &qtdemux->cenc_aux_sample_count);
3709 if (qtdemux->cenc_aux_info_sizes == NULL) {
3710 GST_ERROR_OBJECT (qtdemux, "failed to parse saiz box");
3714 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saio,
3717 GST_ERROR_OBJECT (qtdemux, "saiz box without a corresponding saio box");
3718 g_free (qtdemux->cenc_aux_info_sizes);
3719 qtdemux->cenc_aux_info_sizes = NULL;
3723 if (G_UNLIKELY (!qtdemux_parse_saio (qtdemux, stream, &saio_data,
3724 &info_type, &info_type_parameter, &offset))) {
3725 GST_ERROR_OBJECT (qtdemux, "failed to parse saio box");
3726 g_free (qtdemux->cenc_aux_info_sizes);
3727 qtdemux->cenc_aux_info_sizes = NULL;
3730 if (base_offset > -1 && base_offset > qtdemux->moof_offset)
3731 offset += (guint64) (base_offset - qtdemux->moof_offset);
3732 if (info_type == FOURCC_cenc && info_type_parameter == 0U) {
3734 if (offset > length) {
3735 GST_DEBUG_OBJECT (qtdemux, "cenc auxiliary info stored out of moof");
3736 qtdemux->cenc_aux_info_offset = offset;
3738 gst_byte_reader_init (&br, buffer + offset, length - offset);
3739 if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
3740 qtdemux->cenc_aux_info_sizes,
3741 qtdemux->cenc_aux_sample_count)) {
3742 GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
3743 g_free (qtdemux->cenc_aux_info_sizes);
3744 qtdemux->cenc_aux_info_sizes = NULL;
3752 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfdt,
3755 /* We'll use decode_time to interpolate timestamps
3756 * in case the input timestamps are missing */
3757 qtdemux_parse_tfdt (qtdemux, &tfdt_data, &decode_time);
3759 GST_DEBUG_OBJECT (qtdemux, "decode time %" G_GINT64_FORMAT
3760 " (%" GST_TIME_FORMAT ")", decode_time,
3761 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, decode_time)));
3763 /* Discard the fragment buffer timestamp info to avoid using it.
3764 * Rely on tfdt instead as it is more accurate than the timestamp
3765 * that is fetched from a manifest/playlist and is usually
3767 qtdemux->fragment_start = -1;
3770 if (G_UNLIKELY (!stream)) {
3771 /* we lost track of offset, we'll need to regain it,
3772 * but can delay complaining until later or avoid doing so altogether */
3776 if (G_UNLIKELY (base_offset < -1))
3779 if (qtdemux->upstream_format_is_time)
3780 gst_qtdemux_stream_flush_samples_data (qtdemux, stream);
3782 /* initialise moof sample data */
3783 stream->n_samples_moof = 0;
3784 stream->duration_moof = 0;
3786 /* Track Run node */
3788 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_trun,
3791 qtdemux_parse_trun (qtdemux, &trun_data, stream,
3792 ds_duration, ds_size, ds_flags, moof_offset, length, &base_offset,
3793 &running_offset, decode_time);
3794 /* iterate all siblings */
3795 trun_node = qtdemux_tree_get_sibling_by_type_full (trun_node, FOURCC_trun,
3799 uuid_node = qtdemux_tree_get_child_by_type (traf_node, FOURCC_uuid);
3801 guint8 *uuid_buffer = (guint8 *) uuid_node->data;
3802 guint32 box_length = QT_UINT32 (uuid_buffer);
3804 qtdemux_parse_uuid (qtdemux, uuid_buffer, box_length);
3807 /* if no new base_offset provided for next traf,
3808 * base is end of current traf */
3809 base_offset = running_offset;
3810 running_offset = -1;
3812 if (stream->n_samples_moof && stream->duration_moof)
3813 stream->new_caps = TRUE;
3816 /* iterate all siblings */
3817 traf_node = qtdemux_tree_get_sibling_by_type (traf_node, FOURCC_traf);
3820 /* parse any protection system info */
3821 pssh_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_pssh);
3823 GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
3824 qtdemux_parse_pssh (qtdemux, pssh_node);
3825 pssh_node = qtdemux_tree_get_sibling_by_type (pssh_node, FOURCC_pssh);
3828 g_node_destroy (moof_node);
3833 GST_DEBUG_OBJECT (qtdemux, "missing tfhd box");
3838 GST_DEBUG_OBJECT (qtdemux, "Missing mfhd box");
3843 GST_DEBUG_OBJECT (qtdemux, "lost offset");
3848 g_node_destroy (moof_node);
3849 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
3850 (_("This file is corrupt and cannot be played.")), (NULL));
3856 /* might be used if some day we actually use mfra & co
3857 * for random access to fragments,
3858 * but that will require quite some modifications and much less relying
3859 * on a sample array */
3863 qtdemux_parse_tfra (GstQTDemux * qtdemux, GNode * tfra_node)
3865 QtDemuxStream *stream;
3866 guint32 ver_flags, track_id, len, num_entries, i;
3867 guint value_size, traf_size, trun_size, sample_size;
3868 guint64 time = 0, moof_offset = 0;
3870 GstBuffer *buf = NULL;
3875 gst_byte_reader_init (&tfra, tfra_node->data, QT_UINT32 (tfra_node->data));
3877 if (!gst_byte_reader_skip (&tfra, 8))
3880 if (!gst_byte_reader_get_uint32_be (&tfra, &ver_flags))
3883 if (!gst_byte_reader_get_uint32_be (&tfra, &track_id)
3884 || !gst_byte_reader_get_uint32_be (&tfra, &len)
3885 || !gst_byte_reader_get_uint32_be (&tfra, &num_entries))
3888 GST_DEBUG_OBJECT (qtdemux, "parsing tfra box for track id %u", track_id);
3890 stream = qtdemux_find_stream (qtdemux, track_id);
3892 goto unknown_trackid;
3894 value_size = ((ver_flags >> 24) == 1) ? sizeof (guint64) : sizeof (guint32);
3895 sample_size = (len & 3) + 1;
3896 trun_size = ((len & 12) >> 2) + 1;
3897 traf_size = ((len & 48) >> 4) + 1;
3899 GST_DEBUG_OBJECT (qtdemux, "%u entries, sizes: value %u, traf %u, trun %u, "
3900 "sample %u", num_entries, value_size, traf_size, trun_size, sample_size);
3902 if (num_entries == 0)
3905 if (!qt_atom_parser_has_chunks (&tfra, num_entries,
3906 value_size + value_size + traf_size + trun_size + sample_size))
3909 g_free (stream->ra_entries);
3910 stream->ra_entries = g_new (QtDemuxRandomAccessEntry, num_entries);
3911 stream->n_ra_entries = num_entries;
3913 for (i = 0; i < num_entries; i++) {
3914 qt_atom_parser_get_offset (&tfra, value_size, &time);
3915 qt_atom_parser_get_offset (&tfra, value_size, &moof_offset);
3916 qt_atom_parser_get_uint_with_size_unchecked (&tfra, traf_size);
3917 qt_atom_parser_get_uint_with_size_unchecked (&tfra, trun_size);
3918 qt_atom_parser_get_uint_with_size_unchecked (&tfra, sample_size);
3920 time = QTSTREAMTIME_TO_GSTTIME (stream, time);
3922 GST_LOG_OBJECT (qtdemux, "fragment time: %" GST_TIME_FORMAT ", "
3923 " moof_offset: %" G_GUINT64_FORMAT, GST_TIME_ARGS (time), moof_offset);
3925 stream->ra_entries[i].ts = time;
3926 stream->ra_entries[i].moof_offset = moof_offset;
3928 /* don't want to go through the entire file and read all moofs at startup */
3930 ret = gst_qtdemux_pull_atom (qtdemux, moof_offset, 0, &buf);
3931 if (ret != GST_FLOW_OK)
3933 qtdemux_parse_moof (qtdemux, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf),
3934 moof_offset, stream);
3935 gst_buffer_unref (buf);
3939 check_update_duration (qtdemux, time);
3946 GST_WARNING_OBJECT (qtdemux, "Couldn't find stream for track %u", track_id);
3951 GST_WARNING_OBJECT (qtdemux, "broken traf box, ignoring");
3956 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
3962 qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux)
3964 GstMapInfo mfro_map = GST_MAP_INFO_INIT;
3965 GstMapInfo mfra_map = GST_MAP_INFO_INIT;
3966 GstBuffer *mfro = NULL, *mfra = NULL;
3968 gboolean ret = FALSE;
3969 GNode *mfra_node, *tfra_node;
3970 guint64 mfra_offset = 0;
3971 guint32 fourcc, mfra_size;
3974 /* query upstream size in bytes */
3975 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &len))
3976 goto size_query_failed;
3978 /* mfro box should be at the very end of the file */
3979 flow = gst_qtdemux_pull_atom (qtdemux, len - 16, 16, &mfro);
3980 if (flow != GST_FLOW_OK)
3983 gst_buffer_map (mfro, &mfro_map, GST_MAP_READ);
3985 fourcc = QT_FOURCC (mfro_map.data + 4);
3986 if (fourcc != FOURCC_mfro)
3989 GST_INFO_OBJECT (qtdemux, "Found mfro box");
3990 if (mfro_map.size < 16)
3991 goto invalid_mfro_size;
3993 mfra_size = QT_UINT32 (mfro_map.data + 12);
3994 if (mfra_size >= len)
3995 goto invalid_mfra_size;
3997 mfra_offset = len - mfra_size;
3999 GST_INFO_OBJECT (qtdemux, "mfra offset: %" G_GUINT64_FORMAT ", size %u",
4000 mfra_offset, mfra_size);
4002 /* now get and parse mfra box */
4003 flow = gst_qtdemux_pull_atom (qtdemux, mfra_offset, mfra_size, &mfra);
4004 if (flow != GST_FLOW_OK)
4007 gst_buffer_map (mfra, &mfra_map, GST_MAP_READ);
4009 mfra_node = g_node_new ((guint8 *) mfra_map.data);
4010 qtdemux_parse_node (qtdemux, mfra_node, mfra_map.data, mfra_map.size);
4012 tfra_node = qtdemux_tree_get_child_by_type (mfra_node, FOURCC_tfra);
4015 qtdemux_parse_tfra (qtdemux, tfra_node);
4016 /* iterate all siblings */
4017 tfra_node = qtdemux_tree_get_sibling_by_type (tfra_node, FOURCC_tfra);
4019 g_node_destroy (mfra_node);
4021 GST_INFO_OBJECT (qtdemux, "parsed movie fragment random access box (mfra)");
4027 if (mfro_map.memory != NULL)
4028 gst_buffer_unmap (mfro, &mfro_map);
4029 gst_buffer_unref (mfro);
4032 if (mfra_map.memory != NULL)
4033 gst_buffer_unmap (mfra, &mfra_map);
4034 gst_buffer_unref (mfra);
4041 GST_WARNING_OBJECT (qtdemux, "could not query upstream size");
4046 GST_WARNING_OBJECT (qtdemux, "mfro size is too small");
4051 GST_WARNING_OBJECT (qtdemux, "mfra_size in mfro box is invalid");
4056 GST_WARNING_OBJECT (qtdemux, "bogus mfra offset or size, broken file");
4062 add_offset (guint64 offset, guint64 advance)
4064 /* Avoid 64-bit overflow by clamping */
4065 if (offset > G_MAXUINT64 - advance)
4067 return offset + advance;
4070 static GstFlowReturn
4071 gst_qtdemux_loop_state_header (GstQTDemux * qtdemux)
4075 GstBuffer *buf = NULL;
4076 GstFlowReturn ret = GST_FLOW_OK;
4077 guint64 cur_offset = qtdemux->offset;
4080 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, 16, &buf);
4081 if (G_UNLIKELY (ret != GST_FLOW_OK))
4083 gst_buffer_map (buf, &map, GST_MAP_READ);
4084 if (G_LIKELY (map.size >= 8))
4085 extract_initial_length_and_fourcc (map.data, map.size, &length, &fourcc);
4086 gst_buffer_unmap (buf, &map);
4087 gst_buffer_unref (buf);
4089 /* maybe we already got most we needed, so only consider this eof */
4090 if (G_UNLIKELY (length == 0)) {
4091 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
4092 (_("Invalid atom size.")),
4093 ("Header atom '%" GST_FOURCC_FORMAT "' has empty length",
4094 GST_FOURCC_ARGS (fourcc)));
4101 /* record for later parsing when needed */
4102 if (!qtdemux->moof_offset) {
4103 qtdemux->moof_offset = qtdemux->offset;
4105 if (qtdemux_pull_mfro_mfra (qtdemux)) {
4108 qtdemux->offset += length; /* skip moof and keep going */
4110 if (qtdemux->got_moov) {
4111 GST_INFO_OBJECT (qtdemux, "moof header, got moov, done with headers");
4122 GST_LOG_OBJECT (qtdemux,
4123 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
4124 GST_FOURCC_ARGS (fourcc), cur_offset);
4125 qtdemux->offset = add_offset (qtdemux->offset, length);
4130 GstBuffer *moov = NULL;
4132 if (qtdemux->got_moov) {
4133 GST_DEBUG_OBJECT (qtdemux, "Skipping moov atom as we have one already");
4134 qtdemux->offset = add_offset (qtdemux->offset, length);
4138 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, length, &moov);
4139 if (ret != GST_FLOW_OK)
4141 gst_buffer_map (moov, &map, GST_MAP_READ);
4143 if (length != map.size) {
4144 /* Some files have a 'moov' atom at the end of the file which contains
4145 * a terminal 'free' atom where the body of the atom is missing.
4146 * Check for, and permit, this special case.
4148 if (map.size >= 8) {
4149 guint8 *final_data = map.data + (map.size - 8);
4150 guint32 final_length = QT_UINT32 (final_data);
4151 guint32 final_fourcc = QT_FOURCC (final_data + 4);
4153 if (final_fourcc == FOURCC_free
4154 && map.size + final_length - 8 == length) {
4155 /* Ok, we've found that special case. Allocate a new buffer with
4156 * that free atom actually present. */
4157 GstBuffer *newmoov = gst_buffer_new_and_alloc (length);
4158 gst_buffer_fill (newmoov, 0, map.data, map.size);
4159 gst_buffer_memset (newmoov, map.size, 0, final_length - 8);
4160 gst_buffer_unmap (moov, &map);
4161 gst_buffer_unref (moov);
4163 gst_buffer_map (moov, &map, GST_MAP_READ);
4168 if (length != map.size) {
4169 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4170 (_("This file is incomplete and cannot be played.")),
4171 ("We got less than expected (received %" G_GSIZE_FORMAT
4172 ", wanted %u, offset %" G_GUINT64_FORMAT ")", map.size,
4173 (guint) length, cur_offset));
4174 gst_buffer_unmap (moov, &map);
4175 gst_buffer_unref (moov);
4176 ret = GST_FLOW_ERROR;
4179 qtdemux->offset += length;
4181 qtdemux_parse_moov (qtdemux, map.data, length);
4182 qtdemux_node_dump (qtdemux, qtdemux->moov_node);
4184 qtdemux_parse_tree (qtdemux);
4185 g_node_destroy (qtdemux->moov_node);
4186 gst_buffer_unmap (moov, &map);
4187 gst_buffer_unref (moov);
4188 qtdemux->moov_node = NULL;
4189 qtdemux->got_moov = TRUE;
4195 GstBuffer *ftyp = NULL;
4197 /* extract major brand; might come in handy for ISO vs QT issues */
4198 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &ftyp);
4199 if (ret != GST_FLOW_OK)
4201 qtdemux->offset += length;
4202 gst_buffer_map (ftyp, &map, GST_MAP_READ);
4203 qtdemux_parse_ftyp (qtdemux, map.data, map.size);
4204 gst_buffer_unmap (ftyp, &map);
4205 gst_buffer_unref (ftyp);
4210 GstBuffer *uuid = NULL;
4212 /* uuid are extension atoms */
4213 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &uuid);
4214 if (ret != GST_FLOW_OK)
4216 qtdemux->offset += length;
4217 gst_buffer_map (uuid, &map, GST_MAP_READ);
4218 qtdemux_parse_uuid (qtdemux, map.data, map.size);
4219 gst_buffer_unmap (uuid, &map);
4220 gst_buffer_unref (uuid);
4225 GstBuffer *sidx = NULL;
4226 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &sidx);
4227 if (ret != GST_FLOW_OK)
4229 qtdemux->offset += length;
4230 gst_buffer_map (sidx, &map, GST_MAP_READ);
4231 qtdemux_parse_sidx (qtdemux, map.data, map.size);
4232 gst_buffer_unmap (sidx, &map);
4233 gst_buffer_unref (sidx);
4238 GstBuffer *unknown = NULL;
4240 GST_LOG_OBJECT (qtdemux,
4241 "unknown %08x '%" GST_FOURCC_FORMAT "' of size %" G_GUINT64_FORMAT
4242 " at %" G_GUINT64_FORMAT, fourcc, GST_FOURCC_ARGS (fourcc), length,
4244 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &unknown);
4245 if (ret != GST_FLOW_OK)
4247 gst_buffer_map (unknown, &map, GST_MAP_READ);
4248 GST_MEMDUMP ("Unknown tag", map.data, map.size);
4249 gst_buffer_unmap (unknown, &map);
4250 gst_buffer_unref (unknown);
4251 qtdemux->offset += length;
4257 if (ret == GST_FLOW_EOS && (qtdemux->got_moov || qtdemux->media_caps)) {
4258 /* digested all data, show what we have */
4259 qtdemux_prepare_streams (qtdemux);
4260 ret = qtdemux_expose_streams (qtdemux);
4262 qtdemux->state = QTDEMUX_STATE_MOVIE;
4263 GST_DEBUG_OBJECT (qtdemux, "switching state to STATE_MOVIE (%d)",
4270 /* Seeks to the previous keyframe of the indexed stream and
4271 * aligns other streams with respect to the keyframe timestamp
4272 * of indexed stream. Only called in case of Reverse Playback
4274 static GstFlowReturn
4275 gst_qtdemux_seek_to_previous_keyframe (GstQTDemux * qtdemux)
4278 guint32 seg_idx = 0, k_index = 0;
4279 guint32 ref_seg_idx, ref_k_index;
4280 GstClockTime k_pos = 0, last_stop = 0;
4281 QtDemuxSegment *seg = NULL;
4282 QtDemuxStream *ref_str = NULL;
4283 guint64 seg_media_start_mov; /* segment media start time in mov format */
4286 /* Now we choose an arbitrary stream, get the previous keyframe timestamp
4287 * and finally align all the other streams on that timestamp with their
4288 * respective keyframes */
4289 for (n = 0; n < qtdemux->n_streams; n++) {
4290 QtDemuxStream *str = qtdemux->streams[n];
4292 /* No candidate yet, take the first stream */
4298 /* So that stream has a segment, we prefer video streams */
4299 if (str->subtype == FOURCC_vide) {
4305 if (G_UNLIKELY (!ref_str)) {
4306 GST_DEBUG_OBJECT (qtdemux, "couldn't find any stream");
4310 if (G_UNLIKELY (!ref_str->from_sample)) {
4311 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of the file");
4315 /* So that stream has been playing from from_sample to to_sample. We will
4316 * get the timestamp of the previous sample and search for a keyframe before
4317 * that. For audio streams we do an arbitrary jump in the past (10 samples) */
4318 if (ref_str->subtype == FOURCC_vide) {
4319 k_index = gst_qtdemux_find_keyframe (qtdemux, ref_str,
4320 ref_str->from_sample - 1);
4322 if (ref_str->from_sample >= 10)
4323 k_index = ref_str->from_sample - 10;
4329 ref_str->samples[k_index].timestamp +
4330 ref_str->samples[k_index].pts_offset;
4332 /* get current segment for that stream */
4333 seg = &ref_str->segments[ref_str->segment_index];
4334 /* Use segment start in original timescale for comparisons */
4335 seg_media_start_mov = seg->trak_media_start;
4337 GST_LOG_OBJECT (qtdemux, "keyframe index %u ts %" G_GUINT64_FORMAT
4338 " seg start %" G_GUINT64_FORMAT " %" GST_TIME_FORMAT "\n",
4339 k_index, target_ts, seg_media_start_mov,
4340 GST_TIME_ARGS (seg->media_start));
4342 /* Crawl back through segments to find the one containing this I frame */
4343 while (target_ts < seg_media_start_mov) {
4344 GST_DEBUG_OBJECT (qtdemux,
4345 "keyframe position (sample %u) is out of segment %u " " target %"
4346 G_GUINT64_FORMAT " seg start %" G_GUINT64_FORMAT, k_index,
4347 ref_str->segment_index, target_ts, seg_media_start_mov);
4349 if (G_UNLIKELY (!ref_str->segment_index)) {
4350 /* Reached first segment, let's consider it's EOS */
4353 ref_str->segment_index--;
4354 seg = &ref_str->segments[ref_str->segment_index];
4355 /* Use segment start in original timescale for comparisons */
4356 seg_media_start_mov = seg->trak_media_start;
4358 /* Calculate time position of the keyframe and where we should stop */
4360 QTSTREAMTIME_TO_GSTTIME (ref_str,
4361 target_ts - seg->trak_media_start) + seg->time;
4363 QTSTREAMTIME_TO_GSTTIME (ref_str,
4364 ref_str->samples[ref_str->from_sample].timestamp -
4365 seg->trak_media_start) + seg->time;
4367 GST_DEBUG_OBJECT (qtdemux, "preferred stream played from sample %u, "
4368 "now going to sample %u (pts %" GST_TIME_FORMAT ")", ref_str->from_sample,
4369 k_index, GST_TIME_ARGS (k_pos));
4371 /* Set last_stop with the keyframe timestamp we pushed of that stream */
4372 qtdemux->segment.position = last_stop;
4373 GST_DEBUG_OBJECT (qtdemux, "last_stop now is %" GST_TIME_FORMAT,
4374 GST_TIME_ARGS (last_stop));
4376 if (G_UNLIKELY (last_stop < qtdemux->segment.start)) {
4377 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of segment");
4381 ref_seg_idx = ref_str->segment_index;
4382 ref_k_index = k_index;
4384 /* Align them all on this */
4385 for (n = 0; n < qtdemux->n_streams; n++) {
4387 GstClockTime seg_time = 0;
4388 QtDemuxStream *str = qtdemux->streams[n];
4390 /* aligning reference stream again might lead to backing up to yet another
4391 * keyframe (due to timestamp rounding issues),
4392 * potentially putting more load on downstream; so let's try to avoid */
4393 if (str == ref_str) {
4394 seg_idx = ref_seg_idx;
4395 seg = &str->segments[seg_idx];
4396 k_index = ref_k_index;
4397 GST_DEBUG_OBJECT (qtdemux, "reference stream %d segment %d, "
4398 "sample at index %d", n, ref_str->segment_index, k_index);
4400 seg_idx = gst_qtdemux_find_segment (qtdemux, str, k_pos);
4401 GST_DEBUG_OBJECT (qtdemux,
4402 "stream %d align segment %d for keyframe pos %" GST_TIME_FORMAT, n,
4403 seg_idx, GST_TIME_ARGS (k_pos));
4405 /* get segment and time in the segment */
4406 seg = &str->segments[seg_idx];
4407 seg_time = k_pos - seg->time;
4409 /* get the media time in the segment.
4410 * No adjustment for empty "filler" segments */
4411 if (seg->media_start != GST_CLOCK_TIME_NONE)
4412 seg_time += seg->media_start;
4414 /* get the index of the sample with media time */
4415 index = gst_qtdemux_find_index_linear (qtdemux, str, seg_time);
4416 GST_DEBUG_OBJECT (qtdemux,
4417 "stream %d sample for %" GST_TIME_FORMAT " at %u", n,
4418 GST_TIME_ARGS (seg_time), index);
4420 /* find previous keyframe */
4421 k_index = gst_qtdemux_find_keyframe (qtdemux, str, index);
4424 /* Remember until where we want to go */
4425 str->to_sample = str->from_sample - 1;
4426 /* Define our time position */
4428 str->samples[k_index].timestamp + str->samples[k_index].pts_offset;
4429 str->time_position = QTSTREAMTIME_TO_GSTTIME (str, target_ts) + seg->time;
4430 if (seg->media_start != GST_CLOCK_TIME_NONE)
4431 str->time_position -= seg->media_start;
4433 /* Now seek back in time */
4434 gst_qtdemux_move_stream (qtdemux, str, k_index);
4435 GST_DEBUG_OBJECT (qtdemux, "stream %d keyframe at %u, time position %"
4436 GST_TIME_FORMAT " playing from sample %u to %u", n, k_index,
4437 GST_TIME_ARGS (str->time_position), str->from_sample, str->to_sample);
4443 return GST_FLOW_EOS;
4447 * Gets the current qt segment start, stop and position for the
4448 * given time offset. This is used in update_segment()
4451 gst_qtdemux_stream_segment_get_boundaries (GstQTDemux * qtdemux,
4452 QtDemuxStream * stream, GstClockTime offset,
4453 GstClockTime * _start, GstClockTime * _stop, GstClockTime * _time)
4455 GstClockTime seg_time;
4456 GstClockTime start, stop, time;
4457 QtDemuxSegment *segment;
4459 segment = &stream->segments[stream->segment_index];
4461 /* get time in this segment */
4462 seg_time = (offset - segment->time) * segment->rate;
4464 GST_LOG_OBJECT (stream->pad, "seg_time %" GST_TIME_FORMAT,
4465 GST_TIME_ARGS (seg_time));
4467 if (G_UNLIKELY (seg_time > segment->duration)) {
4468 GST_LOG_OBJECT (stream->pad,
4469 "seg_time > segment->duration %" GST_TIME_FORMAT,
4470 GST_TIME_ARGS (segment->duration));
4471 seg_time = segment->duration;
4474 /* qtdemux->segment.stop is in outside-time-realm, whereas
4475 * segment->media_stop is in track-time-realm.
4477 * In order to compare the two, we need to bring segment.stop
4478 * into the track-time-realm
4480 * FIXME - does this comment still hold? Don't see any conversion here */
4482 stop = qtdemux->segment.stop;
4483 if (stop == GST_CLOCK_TIME_NONE)
4484 stop = qtdemux->segment.duration;
4485 if (stop == GST_CLOCK_TIME_NONE)
4486 stop = segment->media_stop;
4489 MIN (segment->media_stop, stop - segment->time + segment->media_start);
4491 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
4492 start = segment->time + seg_time;
4494 stop = start - seg_time + segment->duration;
4495 } else if (qtdemux->segment.rate >= 0) {
4496 start = MIN (segment->media_start + seg_time, stop);
4499 if (segment->media_start >= qtdemux->segment.start) {
4500 time = segment->time;
4502 time = segment->time + (qtdemux->segment.start - segment->media_start);
4505 start = MAX (segment->media_start, qtdemux->segment.start);
4506 stop = MIN (segment->media_start + seg_time, stop);
4515 * Updates the qt segment used for the stream and pushes a new segment event
4516 * downstream on this stream's pad.
4519 gst_qtdemux_stream_update_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
4520 gint seg_idx, GstClockTime offset, GstClockTime * _start,
4521 GstClockTime * _stop)
4523 QtDemuxSegment *segment;
4524 GstClockTime start = 0, stop = GST_CLOCK_TIME_NONE, time = 0;
4528 /* update the current segment */
4529 stream->segment_index = seg_idx;
4531 /* get the segment */
4532 segment = &stream->segments[seg_idx];
4534 if (G_UNLIKELY (offset < segment->time)) {
4535 GST_WARNING_OBJECT (stream->pad, "offset < segment->time %" GST_TIME_FORMAT,
4536 GST_TIME_ARGS (segment->time));
4540 /* segment lies beyond total indicated duration */
4541 if (G_UNLIKELY (qtdemux->segment.duration != GST_CLOCK_TIME_NONE &&
4542 segment->time > qtdemux->segment.duration)) {
4543 GST_WARNING_OBJECT (stream->pad, "file duration %" GST_TIME_FORMAT
4544 " < segment->time %" GST_TIME_FORMAT,
4545 GST_TIME_ARGS (qtdemux->segment.duration),
4546 GST_TIME_ARGS (segment->time));
4550 gst_qtdemux_stream_segment_get_boundaries (qtdemux, stream, offset,
4551 &start, &stop, &time);
4553 GST_DEBUG_OBJECT (stream->pad, "new segment %d from %" GST_TIME_FORMAT
4554 " to %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT, seg_idx,
4555 GST_TIME_ARGS (start), GST_TIME_ARGS (stop), GST_TIME_ARGS (time));
4557 /* combine global rate with that of the segment */
4558 rate = segment->rate * qtdemux->segment.rate;
4560 /* Copy flags from main segment */
4561 stream->segment.flags = qtdemux->segment.flags;
4563 /* update the segment values used for clipping */
4564 stream->segment.offset = qtdemux->segment.offset;
4565 stream->segment.base = qtdemux->segment.base + stream->accumulated_base;
4566 stream->segment.applied_rate = qtdemux->segment.applied_rate;
4567 stream->segment.rate = rate;
4568 stream->segment.start = start + QTSTREAMTIME_TO_GSTTIME (stream,
4569 stream->cslg_shift);
4570 stream->segment.stop = stop + QTSTREAMTIME_TO_GSTTIME (stream,
4571 stream->cslg_shift);
4572 stream->segment.time = time;
4573 stream->segment.position = stream->segment.start;
4575 GST_DEBUG_OBJECT (stream->pad, "New segment: %" GST_SEGMENT_FORMAT,
4578 /* now prepare and send the segment */
4580 event = gst_event_new_segment (&stream->segment);
4581 if (qtdemux->segment_seqnum) {
4582 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
4584 gst_pad_push_event (stream->pad, event);
4585 /* assume we can send more data now */
4586 GST_PAD_LAST_FLOW_RETURN (stream->pad) = GST_FLOW_OK;
4587 /* clear to send tags on this pad now */
4588 gst_qtdemux_push_tags (qtdemux, stream);
4599 /* activate the given segment number @seg_idx of @stream at time @offset.
4600 * @offset is an absolute global position over all the segments.
4602 * This will push out a NEWSEGMENT event with the right values and
4603 * position the stream index to the first decodable sample before
4607 gst_qtdemux_activate_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
4608 guint32 seg_idx, GstClockTime offset)
4610 QtDemuxSegment *segment;
4611 guint32 index, kf_index;
4612 GstClockTime start = 0, stop = GST_CLOCK_TIME_NONE;
4614 GST_LOG_OBJECT (stream->pad, "activate segment %d, offset %" GST_TIME_FORMAT,
4615 seg_idx, GST_TIME_ARGS (offset));
4617 if (!gst_qtdemux_stream_update_segment (qtdemux, stream, seg_idx, offset,
4621 segment = &stream->segments[stream->segment_index];
4623 /* in the fragmented case, we pick a fragment that starts before our
4624 * desired position and rely on downstream to wait for a keyframe
4625 * (FIXME: doesn't seem to work so well with ismv and wmv, as no parser; the
4626 * tfra entries tells us which trun/sample the key unit is in, but we don't
4627 * make use of this additional information at the moment) */
4628 if (qtdemux->fragmented) {
4629 stream->to_sample = G_MAXUINT32;
4633 /* We don't need to look for a sample in push-based */
4634 if (!qtdemux->pullbased)
4637 /* and move to the keyframe before the indicated media time of the
4639 if (G_LIKELY (!QTSEGMENT_IS_EMPTY (segment))) {
4640 if (qtdemux->segment.rate >= 0) {
4641 index = gst_qtdemux_find_index_linear (qtdemux, stream, start);
4642 stream->to_sample = G_MAXUINT32;
4643 GST_DEBUG_OBJECT (stream->pad,
4644 "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
4645 GST_TIME_FORMAT, GST_TIME_ARGS (start), index,
4646 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
4648 index = gst_qtdemux_find_index_linear (qtdemux, stream, stop);
4649 stream->to_sample = index;
4650 GST_DEBUG_OBJECT (stream->pad,
4651 "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
4652 GST_TIME_FORMAT, GST_TIME_ARGS (stop), index,
4653 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
4656 GST_DEBUG_OBJECT (stream->pad, "No need to look for keyframe, "
4657 "this is an empty segment");
4661 /* gst_qtdemux_parse_sample () called from gst_qtdemux_find_index_linear ()
4662 * encountered an error and printed a message so we return appropriately */
4666 /* we're at the right spot */
4667 if (index == stream->sample_index) {
4668 GST_DEBUG_OBJECT (stream->pad, "we are at the right index");
4672 /* find keyframe of the target index */
4673 kf_index = gst_qtdemux_find_keyframe (qtdemux, stream, index);
4676 /* indent does stupid stuff with stream->samples[].timestamp */
4678 /* if we move forwards, we don't have to go back to the previous
4679 * keyframe since we already sent that. We can also just jump to
4680 * the keyframe right before the target index if there is one. */
4681 if (index > stream->sample_index) {
4682 /* moving forwards check if we move past a keyframe */
4683 if (kf_index > stream->sample_index) {
4684 GST_DEBUG_OBJECT (stream->pad,
4685 "moving forwards to keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" )", kf_index,
4686 GST_TIME_ARGS (QTSAMPLE_PTS(stream, &stream->samples[kf_index])),
4687 GST_TIME_ARGS (QTSAMPLE_DTS(stream, &stream->samples[kf_index])));
4688 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
4690 GST_DEBUG_OBJECT (stream->pad,
4691 "moving forwards, keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" ) already sent", kf_index,
4692 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[kf_index])),
4693 GST_TIME_ARGS (QTSAMPLE_DTS (stream, &stream->samples[kf_index])));
4696 GST_DEBUG_OBJECT (stream->pad,
4697 "moving backwards to keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" )", kf_index,
4698 GST_TIME_ARGS (QTSAMPLE_PTS(stream, &stream->samples[kf_index])),
4699 GST_TIME_ARGS (QTSAMPLE_DTS(stream, &stream->samples[kf_index])));
4700 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
4708 /* prepare to get the current sample of @stream, getting essential values.
4710 * This function will also prepare and send the segment when needed.
4712 * Return FALSE if the stream is EOS.
4717 gst_qtdemux_prepare_current_sample (GstQTDemux * qtdemux,
4718 QtDemuxStream * stream, gboolean * empty, guint64 * offset, guint * size,
4719 GstClockTime * dts, GstClockTime * pts, GstClockTime * duration,
4720 gboolean * keyframe)
4722 QtDemuxSample *sample;
4723 GstClockTime time_position;
4726 g_return_val_if_fail (stream != NULL, FALSE);
4728 time_position = stream->time_position;
4729 if (G_UNLIKELY (time_position == GST_CLOCK_TIME_NONE))
4732 seg_idx = stream->segment_index;
4733 if (G_UNLIKELY (seg_idx == -1)) {
4734 /* find segment corresponding to time_position if we are looking
4736 seg_idx = gst_qtdemux_find_segment (qtdemux, stream, time_position);
4739 /* different segment, activate it, sample_index will be set. */
4740 if (G_UNLIKELY (stream->segment_index != seg_idx))
4741 gst_qtdemux_activate_segment (qtdemux, stream, seg_idx, time_position);
4743 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (&stream->segments[stream->
4745 QtDemuxSegment *seg = &stream->segments[stream->segment_index];
4747 GST_LOG_OBJECT (qtdemux, "Empty segment activated,"
4748 " prepare empty sample");
4751 *pts = *dts = time_position;
4752 *duration = seg->duration - (time_position - seg->time);
4759 if (stream->sample_index == -1)
4760 stream->sample_index = 0;
4762 GST_LOG_OBJECT (qtdemux, "segment active, index = %u of %u",
4763 stream->sample_index, stream->n_samples);
4765 if (G_UNLIKELY (stream->sample_index >= stream->n_samples)) {
4766 if (!qtdemux->fragmented)
4769 GST_INFO_OBJECT (qtdemux, "out of samples, trying to add more");
4773 GST_OBJECT_LOCK (qtdemux);
4774 flow = qtdemux_add_fragmented_samples (qtdemux);
4775 GST_OBJECT_UNLOCK (qtdemux);
4777 if (flow != GST_FLOW_OK)
4780 while (stream->sample_index >= stream->n_samples);
4783 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
4784 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
4785 stream->sample_index);
4789 /* now get the info for the sample we're at */
4790 sample = &stream->samples[stream->sample_index];
4792 *dts = QTSAMPLE_DTS (stream, sample);
4793 *pts = QTSAMPLE_PTS (stream, sample);
4794 *offset = sample->offset;
4795 *size = sample->size;
4796 *duration = QTSAMPLE_DUR_DTS (stream, sample, *dts);
4797 *keyframe = QTSAMPLE_KEYFRAME (stream, sample);
4804 stream->time_position = GST_CLOCK_TIME_NONE;
4809 /* move to the next sample in @stream.
4811 * Moves to the next segment when needed.
4814 gst_qtdemux_advance_sample (GstQTDemux * qtdemux, QtDemuxStream * stream)
4816 QtDemuxSample *sample;
4817 QtDemuxSegment *segment;
4819 /* get current segment */
4820 segment = &stream->segments[stream->segment_index];
4822 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
4823 GST_DEBUG_OBJECT (qtdemux, "Empty segment, no samples to advance");
4827 if (G_UNLIKELY (stream->sample_index >= stream->to_sample)) {
4828 /* Mark the stream as EOS */
4829 GST_DEBUG_OBJECT (qtdemux,
4830 "reached max allowed sample %u, mark EOS", stream->to_sample);
4831 stream->time_position = GST_CLOCK_TIME_NONE;
4835 /* move to next sample */
4836 stream->sample_index++;
4837 stream->offset_in_sample = 0;
4839 /* reached the last sample, we need the next segment */
4840 if (G_UNLIKELY (stream->sample_index >= stream->n_samples))
4843 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
4844 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
4845 stream->sample_index);
4849 /* get next sample */
4850 sample = &stream->samples[stream->sample_index];
4852 /* see if we are past the segment */
4853 if (G_UNLIKELY (QTSAMPLE_DTS (stream, sample) >= segment->media_stop))
4856 if (QTSAMPLE_DTS (stream, sample) >= segment->media_start) {
4857 /* inside the segment, update time_position, looks very familiar to
4858 * GStreamer segments, doesn't it? */
4859 stream->time_position =
4860 QTSAMPLE_DTS (stream, sample) - segment->media_start + segment->time;
4862 /* not yet in segment, time does not yet increment. This means
4863 * that we are still prerolling keyframes to the decoder so it can
4864 * decode the first sample of the segment. */
4865 stream->time_position = segment->time;
4869 /* move to the next segment */
4872 GST_DEBUG_OBJECT (qtdemux, "segment %d ended ", stream->segment_index);
4874 if (stream->segment_index == stream->n_segments - 1) {
4875 /* are we at the end of the last segment, we're EOS */
4876 stream->time_position = GST_CLOCK_TIME_NONE;
4878 /* else we're only at the end of the current segment */
4879 stream->time_position = segment->stop_time;
4881 /* make sure we select a new segment */
4883 /* accumulate previous segments */
4884 if (GST_CLOCK_TIME_IS_VALID (stream->segment.stop))
4885 stream->accumulated_base +=
4886 (stream->segment.stop -
4887 stream->segment.start) / ABS (stream->segment.rate);
4889 stream->segment_index = -1;
4894 gst_qtdemux_sync_streams (GstQTDemux * demux)
4898 if (demux->n_streams <= 1)
4901 for (i = 0; i < demux->n_streams; i++) {
4902 QtDemuxStream *stream;
4903 GstClockTime end_time;
4905 stream = demux->streams[i];
4910 /* TODO advance time on subtitle streams here, if any some day */
4912 /* some clips/trailers may have unbalanced streams at the end,
4913 * so send EOS on shorter stream to prevent stalling others */
4915 /* do not mess with EOS if SEGMENT seeking */
4916 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT)
4919 if (demux->pullbased) {
4920 /* loop mode is sample time based */
4921 if (!STREAM_IS_EOS (stream))
4924 /* push mode is byte position based */
4925 if (stream->n_samples &&
4926 stream->samples[stream->n_samples - 1].offset >= demux->offset)
4930 if (stream->sent_eos)
4933 /* only act if some gap */
4934 end_time = stream->segments[stream->n_segments - 1].stop_time;
4935 GST_LOG_OBJECT (demux, "current position: %" GST_TIME_FORMAT
4936 ", stream end: %" GST_TIME_FORMAT,
4937 GST_TIME_ARGS (demux->segment.position), GST_TIME_ARGS (end_time));
4938 if (GST_CLOCK_TIME_IS_VALID (end_time)
4939 && (end_time + 2 * GST_SECOND < demux->segment.position)) {
4942 GST_DEBUG_OBJECT (demux, "sending EOS for stream %s",
4943 GST_PAD_NAME (stream->pad));
4944 stream->sent_eos = TRUE;
4945 event = gst_event_new_eos ();
4946 if (demux->segment_seqnum)
4947 gst_event_set_seqnum (event, demux->segment_seqnum);
4948 gst_pad_push_event (stream->pad, event);
4953 /* EOS and NOT_LINKED need to be combined. This means that we return:
4955 * GST_FLOW_NOT_LINKED: when all pads NOT_LINKED.
4956 * GST_FLOW_EOS: when all pads EOS or NOT_LINKED.
4958 static GstFlowReturn
4959 gst_qtdemux_combine_flows (GstQTDemux * demux, QtDemuxStream * stream,
4962 GST_LOG_OBJECT (demux, "flow return: %s", gst_flow_get_name (ret));
4965 ret = gst_flow_combiner_update_pad_flow (demux->flowcombiner, stream->pad,
4968 ret = gst_flow_combiner_update_flow (demux->flowcombiner, ret);
4970 GST_LOG_OBJECT (demux, "combined flow return: %s", gst_flow_get_name (ret));
4974 /* the input buffer metadata must be writable. Returns NULL when the buffer is
4975 * completely clipped
4977 * Should be used only with raw buffers */
4979 gst_qtdemux_clip_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
4982 guint64 start, stop, cstart, cstop, diff;
4983 GstClockTime pts, duration;
4985 gint num_rate, denom_rate;
4990 osize = size = gst_buffer_get_size (buf);
4993 /* depending on the type, setup the clip parameters */
4994 if (stream->subtype == FOURCC_soun) {
4995 frame_size = stream->bytes_per_frame;
4996 num_rate = GST_SECOND;
4997 denom_rate = (gint) stream->rate;
4999 } else if (stream->subtype == FOURCC_vide) {
5001 num_rate = stream->fps_n;
5002 denom_rate = stream->fps_d;
5007 if (frame_size <= 0)
5008 goto bad_frame_size;
5010 /* we can only clip if we have a valid pts */
5011 pts = GST_BUFFER_PTS (buf);
5012 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (pts)))
5015 duration = GST_BUFFER_DURATION (buf);
5017 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (duration))) {
5019 gst_util_uint64_scale_int (size / frame_size, num_rate, denom_rate);
5023 stop = start + duration;
5025 if (G_UNLIKELY (!gst_segment_clip (&stream->segment,
5026 GST_FORMAT_TIME, start, stop, &cstart, &cstop)))
5029 /* see if some clipping happened */
5030 diff = cstart - start;
5036 /* bring clipped time to samples and to bytes */
5037 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
5040 GST_DEBUG_OBJECT (qtdemux,
5041 "clipping start to %" GST_TIME_FORMAT " %"
5042 G_GUINT64_FORMAT " bytes", GST_TIME_ARGS (cstart), diff);
5048 diff = stop - cstop;
5053 /* bring clipped time to samples and then to bytes */
5054 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
5056 GST_DEBUG_OBJECT (qtdemux,
5057 "clipping stop to %" GST_TIME_FORMAT " %" G_GUINT64_FORMAT
5058 " bytes", GST_TIME_ARGS (cstop), diff);
5063 if (offset != 0 || size != osize)
5064 gst_buffer_resize (buf, offset, size);
5066 GST_BUFFER_DTS (buf) = GST_CLOCK_TIME_NONE;
5067 GST_BUFFER_PTS (buf) = pts;
5068 GST_BUFFER_DURATION (buf) = duration;
5072 /* dropped buffer */
5075 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
5080 GST_DEBUG_OBJECT (qtdemux, "bad frame size");
5085 GST_DEBUG_OBJECT (qtdemux, "no pts on buffer");
5090 GST_DEBUG_OBJECT (qtdemux, "clipped buffer");
5091 gst_buffer_unref (buf);
5096 /* the input buffer metadata must be writable,
5097 * but time/duration etc not yet set and need not be preserved */
5099 gst_qtdemux_process_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
5106 /* not many cases for now */
5107 if (G_UNLIKELY (stream->fourcc == FOURCC_mp4s)) {
5108 /* send a one time dvd clut event */
5109 if (stream->pending_event && stream->pad)
5110 gst_pad_push_event (stream->pad, stream->pending_event);
5111 stream->pending_event = NULL;
5114 if (G_UNLIKELY (stream->subtype != FOURCC_text
5115 && stream->subtype != FOURCC_sbtl &&
5116 stream->subtype != FOURCC_subp)) {
5120 gst_buffer_map (buf, &map, GST_MAP_READ);
5122 /* empty buffer is sent to terminate previous subtitle */
5123 if (map.size <= 2) {
5124 gst_buffer_unmap (buf, &map);
5125 gst_buffer_unref (buf);
5128 if (stream->subtype == FOURCC_subp) {
5129 /* That's all the processing needed for subpictures */
5130 gst_buffer_unmap (buf, &map);
5134 nsize = GST_READ_UINT16_BE (map.data);
5135 nsize = MIN (nsize, map.size - 2);
5137 GST_LOG_OBJECT (qtdemux, "3GPP timed text subtitle: %d/%" G_GSIZE_FORMAT "",
5140 /* takes care of UTF-8 validation or UTF-16 recognition,
5141 * no other encoding expected */
5142 str = gst_tag_freeform_string_to_utf8 ((gchar *) map.data + 2, nsize, NULL);
5143 gst_buffer_unmap (buf, &map);
5145 gst_buffer_unref (buf);
5146 buf = _gst_buffer_new_wrapped (str, strlen (str), g_free);
5148 /* this should not really happen unless the subtitle is corrupted */
5149 gst_buffer_unref (buf);
5153 /* FIXME ? convert optional subsequent style info to markup */
5158 /* Sets a buffer's attributes properly and pushes it downstream.
5159 * Also checks for additional actions and custom processing that may
5160 * need to be done first.
5162 static GstFlowReturn
5163 gst_qtdemux_decorate_and_push_buffer (GstQTDemux * qtdemux,
5164 QtDemuxStream * stream, GstBuffer * buf,
5165 GstClockTime dts, GstClockTime pts, GstClockTime duration,
5166 gboolean keyframe, GstClockTime position, guint64 byte_position)
5168 GstFlowReturn ret = GST_FLOW_OK;
5170 /* offset the timestamps according to the edit list */
5172 if (G_UNLIKELY (stream->fourcc == FOURCC_rtsp)) {
5176 gst_buffer_map (buf, &map, GST_MAP_READ);
5177 url = g_strndup ((gchar *) map.data, map.size);
5178 gst_buffer_unmap (buf, &map);
5179 if (url != NULL && strlen (url) != 0) {
5180 /* we have RTSP redirect now */
5181 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
5182 gst_message_new_element (GST_OBJECT_CAST (qtdemux),
5183 gst_structure_new ("redirect",
5184 "new-location", G_TYPE_STRING, url, NULL)));
5185 qtdemux->posted_redirect = TRUE;
5187 GST_WARNING_OBJECT (qtdemux, "Redirect URI of stream is empty, not "
5193 /* position reporting */
5194 if (qtdemux->segment.rate >= 0) {
5195 qtdemux->segment.position = position;
5196 gst_qtdemux_sync_streams (qtdemux);
5199 if (G_UNLIKELY (!stream->pad)) {
5200 GST_DEBUG_OBJECT (qtdemux, "No output pad for stream, ignoring");
5201 gst_buffer_unref (buf);
5205 /* send out pending buffers */
5206 while (stream->buffers) {
5207 GstBuffer *buffer = (GstBuffer *) stream->buffers->data;
5209 if (G_UNLIKELY (stream->discont)) {
5210 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
5211 GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
5212 stream->discont = FALSE;
5214 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
5217 gst_pad_push (stream->pad, buffer);
5219 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
5222 /* we're going to modify the metadata */
5223 buf = gst_buffer_make_writable (buf);
5225 if (G_UNLIKELY (stream->need_process))
5226 buf = gst_qtdemux_process_buffer (qtdemux, stream, buf);
5232 GST_BUFFER_DTS (buf) = dts;
5233 GST_BUFFER_PTS (buf) = pts;
5234 GST_BUFFER_DURATION (buf) = duration;
5235 GST_BUFFER_OFFSET (buf) = -1;
5236 GST_BUFFER_OFFSET_END (buf) = -1;
5238 if (G_UNLIKELY (stream->rgb8_palette))
5239 gst_buffer_append_memory (buf, gst_memory_ref (stream->rgb8_palette));
5241 if (G_UNLIKELY (stream->padding)) {
5242 gst_buffer_resize (buf, stream->padding, -1);
5245 if (G_UNLIKELY (qtdemux->element_index)) {
5246 GstClockTime stream_time;
5249 gst_segment_to_stream_time (&stream->segment, GST_FORMAT_TIME,
5251 if (GST_CLOCK_TIME_IS_VALID (stream_time)) {
5252 GST_LOG_OBJECT (qtdemux,
5253 "adding association %" GST_TIME_FORMAT "-> %"
5254 G_GUINT64_FORMAT, GST_TIME_ARGS (stream_time), byte_position);
5255 gst_index_add_association (qtdemux->element_index,
5257 keyframe ? GST_ASSOCIATION_FLAG_KEY_UNIT :
5258 GST_ASSOCIATION_FLAG_DELTA_UNIT, GST_FORMAT_TIME, stream_time,
5259 GST_FORMAT_BYTES, byte_position, NULL);
5264 if (stream->need_clip)
5265 buf = gst_qtdemux_clip_buffer (qtdemux, stream, buf);
5267 if (G_UNLIKELY (buf == NULL))
5270 if (G_UNLIKELY (stream->discont)) {
5271 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
5272 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
5273 stream->discont = FALSE;
5275 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
5279 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
5280 stream->on_keyframe = FALSE;
5282 stream->on_keyframe = TRUE;
5286 GST_LOG_OBJECT (qtdemux,
5287 "Pushing buffer with dts %" GST_TIME_FORMAT ", pts %" GST_TIME_FORMAT
5288 ", duration %" GST_TIME_FORMAT " on pad %s", GST_TIME_ARGS (dts),
5289 GST_TIME_ARGS (pts), GST_TIME_ARGS (duration),
5290 GST_PAD_NAME (stream->pad));
5292 if (stream->protected && stream->protection_scheme_type == FOURCC_cenc) {
5293 GstStructure *crypto_info;
5294 QtDemuxCencSampleSetInfo *info =
5295 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
5299 while ((event = g_queue_pop_head (&stream->protection_scheme_event_queue))) {
5300 gst_pad_push_event (stream->pad, event);
5303 if (qtdemux->cenc_aux_info_offset > 0 && info->crypto_info == NULL) {
5304 GST_DEBUG_OBJECT (qtdemux, "cenc metadata hasn't been parsed yet");
5305 gst_buffer_unref (buf);
5309 index = stream->sample_index - (stream->n_samples - info->crypto_info->len);
5310 if (G_LIKELY (index >= 0 && index < info->crypto_info->len)) {
5311 /* steal structure from array */
5312 crypto_info = g_ptr_array_index (info->crypto_info, index);
5313 g_ptr_array_index (info->crypto_info, index) = NULL;
5314 GST_LOG_OBJECT (qtdemux, "attaching cenc metadata [%u]", index);
5315 if (!crypto_info || !gst_buffer_add_protection_meta (buf, crypto_info))
5316 GST_ERROR_OBJECT (qtdemux, "failed to attach cenc metadata to buffer");
5320 ret = gst_pad_push (stream->pad, buf);
5322 if (GST_CLOCK_TIME_IS_VALID (pts) && GST_CLOCK_TIME_IS_VALID (duration)) {
5323 /* mark position in stream, we'll need this to know when to send GAP event */
5324 stream->segment.position = pts + duration;
5331 static const QtDemuxRandomAccessEntry *
5332 gst_qtdemux_stream_seek_fragment (GstQTDemux * qtdemux, QtDemuxStream * stream,
5333 GstClockTime pos, gboolean after)
5335 QtDemuxRandomAccessEntry *entries = stream->ra_entries;
5336 guint n_entries = stream->n_ra_entries;
5339 /* we assume the table is sorted */
5340 for (i = 0; i < n_entries; ++i) {
5341 if (entries[i].ts > pos)
5345 /* FIXME: maybe save first moof_offset somewhere instead, but for now it's
5346 * probably okay to assume that the index lists the very first fragment */
5353 return &entries[i - 1];
5357 gst_qtdemux_do_fragmented_seek (GstQTDemux * qtdemux)
5359 const QtDemuxRandomAccessEntry *best_entry = NULL;
5362 GST_OBJECT_LOCK (qtdemux);
5364 g_assert (qtdemux->n_streams > 0);
5366 for (i = 0; i < qtdemux->n_streams; i++) {
5367 const QtDemuxRandomAccessEntry *entry;
5368 QtDemuxStream *stream;
5369 gboolean is_audio_or_video;
5371 stream = qtdemux->streams[i];
5373 g_free (stream->samples);
5374 stream->samples = NULL;
5375 stream->n_samples = 0;
5376 stream->stbl_index = -1; /* no samples have yet been parsed */
5377 stream->sample_index = -1;
5379 if (stream->ra_entries == NULL)
5382 if (stream->subtype == FOURCC_vide || stream->subtype == FOURCC_soun)
5383 is_audio_or_video = TRUE;
5385 is_audio_or_video = FALSE;
5388 gst_qtdemux_stream_seek_fragment (qtdemux, stream,
5389 stream->time_position, !is_audio_or_video);
5391 GST_INFO_OBJECT (stream->pad, "%" GST_TIME_FORMAT " at offset "
5392 "%" G_GUINT64_FORMAT, GST_TIME_ARGS (entry->ts), entry->moof_offset);
5394 stream->pending_seek = entry;
5396 /* decide position to jump to just based on audio/video tracks, not subs */
5397 if (!is_audio_or_video)
5400 if (best_entry == NULL || entry->moof_offset < best_entry->moof_offset)
5404 if (best_entry == NULL) {
5405 GST_OBJECT_UNLOCK (qtdemux);
5409 GST_INFO_OBJECT (qtdemux, "seek to %" GST_TIME_FORMAT ", best fragment "
5410 "moof offset: %" G_GUINT64_FORMAT ", ts %" GST_TIME_FORMAT,
5411 GST_TIME_ARGS (qtdemux->streams[0]->time_position),
5412 best_entry->moof_offset, GST_TIME_ARGS (best_entry->ts));
5414 qtdemux->moof_offset = best_entry->moof_offset;
5416 qtdemux_add_fragmented_samples (qtdemux);
5418 GST_OBJECT_UNLOCK (qtdemux);
5422 static GstFlowReturn
5423 gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux)
5425 GstFlowReturn ret = GST_FLOW_OK;
5426 GstBuffer *buf = NULL;
5427 QtDemuxStream *stream;
5428 GstClockTime min_time;
5430 GstClockTime dts = GST_CLOCK_TIME_NONE;
5431 GstClockTime pts = GST_CLOCK_TIME_NONE;
5432 GstClockTime duration = 0;
5433 gboolean keyframe = FALSE;
5434 guint sample_size = 0;
5440 gst_qtdemux_push_pending_newsegment (qtdemux);
5442 if (qtdemux->fragmented_seek_pending) {
5443 GST_INFO_OBJECT (qtdemux, "pending fragmented seek");
5444 gst_qtdemux_do_fragmented_seek (qtdemux);
5445 GST_INFO_OBJECT (qtdemux, "fragmented seek done!");
5446 qtdemux->fragmented_seek_pending = FALSE;
5449 /* Figure out the next stream sample to output, min_time is expressed in
5450 * global time and runs over the edit list segments. */
5451 min_time = G_MAXUINT64;
5453 for (i = 0; i < qtdemux->n_streams; i++) {
5454 GstClockTime position;
5456 stream = qtdemux->streams[i];
5457 position = stream->time_position;
5459 /* position of -1 is EOS */
5460 if (position != GST_CLOCK_TIME_NONE && position < min_time) {
5461 min_time = position;
5466 if (G_UNLIKELY (index == -1)) {
5467 GST_DEBUG_OBJECT (qtdemux, "all streams are EOS");
5471 /* check for segment end */
5472 if (G_UNLIKELY (qtdemux->segment.stop != -1
5473 && ((qtdemux->segment.rate >= 0 && qtdemux->segment.stop <= min_time)
5474 || (qtdemux->segment.rate < 0
5475 && qtdemux->segment.start > min_time))
5476 && qtdemux->streams[index]->on_keyframe)) {
5477 GST_DEBUG_OBJECT (qtdemux, "we reached the end of our segment.");
5478 qtdemux->streams[index]->time_position = GST_CLOCK_TIME_NONE;
5482 /* gap events for subtitle streams */
5483 for (i = 0; i < qtdemux->n_streams; i++) {
5484 stream = qtdemux->streams[i];
5485 if (stream->pad && (stream->subtype == FOURCC_subp
5486 || stream->subtype == FOURCC_text
5487 || stream->subtype == FOURCC_sbtl)) {
5488 /* send one second gap events until the stream catches up */
5489 /* gaps can only be sent after segment is activated (segment.stop is no longer -1) */
5490 while (GST_CLOCK_TIME_IS_VALID (stream->segment.stop) &&
5491 GST_CLOCK_TIME_IS_VALID (stream->segment.position) &&
5492 stream->segment.position + GST_SECOND < min_time) {
5494 gst_event_new_gap (stream->segment.position, GST_SECOND);
5495 gst_pad_push_event (stream->pad, gap);
5496 stream->segment.position += GST_SECOND;
5501 stream = qtdemux->streams[index];
5502 if (stream->new_caps) {
5503 gst_qtdemux_configure_stream (qtdemux, stream);
5504 qtdemux_do_allocation (qtdemux, stream);
5507 /* fetch info for the current sample of this stream */
5508 if (G_UNLIKELY (!gst_qtdemux_prepare_current_sample (qtdemux, stream, &empty,
5509 &offset, &sample_size, &dts, &pts, &duration, &keyframe)))
5512 /* If we're doing a keyframe-only trickmode, only push keyframes on video streams */
5513 if (G_UNLIKELY (qtdemux->
5514 segment.flags & GST_SEGMENT_FLAG_TRICKMODE_KEY_UNITS)) {
5515 if (stream->subtype == FOURCC_vide && !keyframe) {
5516 GST_LOG_OBJECT (qtdemux, "Skipping non-keyframe on stream %d", index);
5521 GST_DEBUG_OBJECT (qtdemux,
5522 "pushing from stream %d, empty %d offset %" G_GUINT64_FORMAT
5523 ", size %d, dts=%" GST_TIME_FORMAT ", pts=%" GST_TIME_FORMAT
5524 ", duration %" GST_TIME_FORMAT, index, empty, offset, sample_size,
5525 GST_TIME_ARGS (dts), GST_TIME_ARGS (pts), GST_TIME_ARGS (duration));
5527 if (G_UNLIKELY (empty)) {
5528 /* empty segment, push a gap and move to the next one */
5529 gst_pad_push_event (stream->pad, gst_event_new_gap (pts, duration));
5530 stream->segment.position = pts + duration;
5534 /* hmm, empty sample, skip and move to next sample */
5535 if (G_UNLIKELY (sample_size <= 0))
5538 /* last pushed sample was out of boundary, goto next sample */
5539 if (G_UNLIKELY (GST_PAD_LAST_FLOW_RETURN (stream->pad) == GST_FLOW_EOS))
5542 if (stream->max_buffer_size == 0 || sample_size <= stream->max_buffer_size) {
5545 GST_DEBUG_OBJECT (qtdemux,
5546 "size %d larger than stream max_buffer_size %d, trimming",
5547 sample_size, stream->max_buffer_size);
5549 MIN (sample_size - stream->offset_in_sample, stream->max_buffer_size);
5552 if (qtdemux->cenc_aux_info_offset > 0) {
5555 GstBuffer *aux_info = NULL;
5557 /* pull the data stored before the sample */
5559 gst_qtdemux_pull_atom (qtdemux, qtdemux->offset,
5560 offset + stream->offset_in_sample - qtdemux->offset, &aux_info);
5561 if (G_UNLIKELY (ret != GST_FLOW_OK))
5563 gst_buffer_map (aux_info, &map, GST_MAP_READ);
5564 GST_DEBUG_OBJECT (qtdemux, "parsing cenc auxiliary info");
5565 gst_byte_reader_init (&br, map.data + 8, map.size);
5566 if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
5567 qtdemux->cenc_aux_info_sizes, qtdemux->cenc_aux_sample_count)) {
5568 GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
5569 gst_buffer_unmap (aux_info, &map);
5570 gst_buffer_unref (aux_info);
5571 ret = GST_FLOW_ERROR;
5574 gst_buffer_unmap (aux_info, &map);
5575 gst_buffer_unref (aux_info);
5578 GST_LOG_OBJECT (qtdemux, "reading %d bytes @ %" G_GUINT64_FORMAT, size,
5581 if (stream->use_allocator) {
5582 /* if we have a per-stream allocator, use it */
5583 buf = gst_buffer_new_allocate (stream->allocator, size, &stream->params);
5586 ret = gst_qtdemux_pull_atom (qtdemux, offset + stream->offset_in_sample,
5588 if (G_UNLIKELY (ret != GST_FLOW_OK))
5591 if (size != sample_size) {
5592 pts += gst_util_uint64_scale_int (GST_SECOND,
5593 stream->offset_in_sample / stream->bytes_per_frame, stream->timescale);
5594 dts += gst_util_uint64_scale_int (GST_SECOND,
5595 stream->offset_in_sample / stream->bytes_per_frame, stream->timescale);
5596 duration = gst_util_uint64_scale_int (GST_SECOND,
5597 size / stream->bytes_per_frame, stream->timescale);
5600 ret = gst_qtdemux_decorate_and_push_buffer (qtdemux, stream, buf,
5601 dts, pts, duration, keyframe, min_time, offset);
5603 if (size != sample_size) {
5604 QtDemuxSample *sample = &stream->samples[stream->sample_index];
5605 QtDemuxSegment *segment = &stream->segments[stream->segment_index];
5607 GstClockTime time_position = QTSTREAMTIME_TO_GSTTIME (stream,
5608 sample->timestamp + stream->offset_in_sample / stream->bytes_per_frame);
5609 if (time_position >= segment->media_start) {
5610 /* inside the segment, update time_position, looks very familiar to
5611 * GStreamer segments, doesn't it? */
5612 stream->time_position = (time_position - segment->media_start) +
5615 /* not yet in segment, time does not yet increment. This means
5616 * that we are still prerolling keyframes to the decoder so it can
5617 * decode the first sample of the segment. */
5618 stream->time_position = segment->time;
5623 ret = gst_qtdemux_combine_flows (qtdemux, stream, ret);
5624 /* ignore unlinked, we will not push on the pad anymore and we will EOS when
5625 * we have no more data for the pad to push */
5626 if (ret == GST_FLOW_EOS)
5629 stream->offset_in_sample += size;
5630 if (stream->offset_in_sample >= sample_size) {
5631 gst_qtdemux_advance_sample (qtdemux, stream);
5636 gst_qtdemux_advance_sample (qtdemux, stream);
5644 GST_DEBUG_OBJECT (qtdemux, "No samples left for any streams - EOS");
5650 GST_DEBUG_OBJECT (qtdemux, "No samples left for stream");
5651 /* EOS will be raised if all are EOS */
5658 gst_qtdemux_loop (GstPad * pad)
5660 GstQTDemux *qtdemux;
5664 qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
5666 cur_offset = qtdemux->offset;
5667 GST_LOG_OBJECT (qtdemux, "loop at position %" G_GUINT64_FORMAT ", state %s",
5668 cur_offset, qt_demux_state_string (qtdemux->state));
5670 switch (qtdemux->state) {
5671 case QTDEMUX_STATE_INITIAL:
5672 case QTDEMUX_STATE_HEADER:
5673 ret = gst_qtdemux_loop_state_header (qtdemux);
5675 case QTDEMUX_STATE_MOVIE:
5676 ret = gst_qtdemux_loop_state_movie (qtdemux);
5677 if (qtdemux->segment.rate < 0 && ret == GST_FLOW_EOS) {
5678 ret = gst_qtdemux_seek_to_previous_keyframe (qtdemux);
5686 /* if something went wrong, pause */
5687 if (ret != GST_FLOW_OK)
5691 gst_object_unref (qtdemux);
5697 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
5698 (NULL), ("streaming stopped, invalid state"));
5699 gst_pad_pause_task (pad);
5700 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
5705 const gchar *reason = gst_flow_get_name (ret);
5707 GST_LOG_OBJECT (qtdemux, "pausing task, reason %s", reason);
5709 gst_pad_pause_task (pad);
5711 /* fatal errors need special actions */
5713 if (ret == GST_FLOW_EOS) {
5714 if (qtdemux->n_streams == 0) {
5715 /* we have no streams, post an error */
5716 gst_qtdemux_post_no_playable_stream_error (qtdemux);
5718 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
5721 if ((stop = qtdemux->segment.stop) == -1)
5722 stop = qtdemux->segment.duration;
5724 if (qtdemux->segment.rate >= 0) {
5725 GstMessage *message;
5728 GST_LOG_OBJECT (qtdemux, "Sending segment done, at end of segment");
5729 message = gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
5730 GST_FORMAT_TIME, stop);
5731 event = gst_event_new_segment_done (GST_FORMAT_TIME, stop);
5732 if (qtdemux->segment_seqnum) {
5733 gst_message_set_seqnum (message, qtdemux->segment_seqnum);
5734 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
5736 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), message);
5737 gst_qtdemux_push_event (qtdemux, event);
5739 GstMessage *message;
5742 /* For Reverse Playback */
5743 GST_LOG_OBJECT (qtdemux, "Sending segment done, at start of segment");
5744 message = gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
5745 GST_FORMAT_TIME, qtdemux->segment.start);
5746 event = gst_event_new_segment_done (GST_FORMAT_TIME,
5747 qtdemux->segment.start);
5748 if (qtdemux->segment_seqnum) {
5749 gst_message_set_seqnum (message, qtdemux->segment_seqnum);
5750 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
5752 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), message);
5753 gst_qtdemux_push_event (qtdemux, event);
5758 GST_LOG_OBJECT (qtdemux, "Sending EOS at end of segment");
5759 event = gst_event_new_eos ();
5760 if (qtdemux->segment_seqnum)
5761 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
5762 gst_qtdemux_push_event (qtdemux, event);
5764 } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
5765 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
5766 (NULL), ("streaming stopped, reason %s", reason));
5767 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
5776 * Returns if there are samples to be played.
5779 has_next_entry (GstQTDemux * demux)
5781 QtDemuxStream *stream;
5784 GST_DEBUG_OBJECT (demux, "Checking if there are samples not played yet");
5786 for (i = 0; i < demux->n_streams; i++) {
5787 stream = demux->streams[i];
5789 if (stream->sample_index == -1) {
5790 stream->sample_index = 0;
5791 stream->offset_in_sample = 0;
5794 if (stream->sample_index >= stream->n_samples) {
5795 GST_LOG_OBJECT (demux, "stream %d samples exhausted", i);
5798 GST_DEBUG_OBJECT (demux, "Found a sample");
5802 GST_DEBUG_OBJECT (demux, "There wasn't any next sample");
5809 * Returns the size of the first entry at the current offset.
5810 * If -1, there are none (which means EOS or empty file).
5813 next_entry_size (GstQTDemux * demux)
5815 QtDemuxStream *stream;
5818 guint64 smalloffs = (guint64) - 1;
5819 QtDemuxSample *sample;
5821 GST_LOG_OBJECT (demux, "Finding entry at offset %" G_GUINT64_FORMAT,
5824 for (i = 0; i < demux->n_streams; i++) {
5825 stream = demux->streams[i];
5827 if (stream->sample_index == -1) {
5828 stream->sample_index = 0;
5829 stream->offset_in_sample = 0;
5832 if (stream->sample_index >= stream->n_samples) {
5833 GST_LOG_OBJECT (demux, "stream %d samples exhausted", i);
5837 if (!qtdemux_parse_samples (demux, stream, stream->sample_index)) {
5838 GST_LOG_OBJECT (demux, "Parsing of index %u from stbl atom failed!",
5839 stream->sample_index);
5843 sample = &stream->samples[stream->sample_index];
5845 GST_LOG_OBJECT (demux,
5846 "Checking Stream %d (sample_index:%d / offset:%" G_GUINT64_FORMAT
5847 " / size:%" G_GUINT32_FORMAT ")", i, stream->sample_index,
5848 sample->offset, sample->size);
5850 if (((smalloffs == -1)
5851 || (sample->offset < smalloffs)) && (sample->size)) {
5853 smalloffs = sample->offset;
5857 GST_LOG_OBJECT (demux,
5858 "stream %d offset %" G_GUINT64_FORMAT " demux->offset :%"
5859 G_GUINT64_FORMAT, smallidx, smalloffs, demux->offset);
5864 stream = demux->streams[smallidx];
5865 sample = &stream->samples[stream->sample_index];
5867 if (sample->offset >= demux->offset) {
5868 demux->todrop = sample->offset - demux->offset;
5869 return sample->size + demux->todrop;
5872 GST_DEBUG_OBJECT (demux,
5873 "There wasn't any entry at offset %" G_GUINT64_FORMAT, demux->offset);
5878 gst_qtdemux_post_progress (GstQTDemux * demux, gint num, gint denom)
5880 gint perc = (gint) ((gdouble) num * 100.0 / (gdouble) denom);
5882 gst_element_post_message (GST_ELEMENT_CAST (demux),
5883 gst_message_new_element (GST_OBJECT_CAST (demux),
5884 gst_structure_new ("progress", "percent", G_TYPE_INT, perc, NULL)));
5888 qtdemux_seek_offset (GstQTDemux * demux, guint64 offset)
5893 GST_DEBUG_OBJECT (demux, "Seeking to %" G_GUINT64_FORMAT, offset);
5896 gst_event_new_seek (1.0, GST_FORMAT_BYTES,
5897 GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset,
5898 GST_SEEK_TYPE_NONE, -1);
5900 /* store seqnum to drop flush events, they don't need to reach downstream */
5901 demux->offset_seek_seqnum = gst_event_get_seqnum (event);
5902 res = gst_pad_push_event (demux->sinkpad, event);
5903 demux->offset_seek_seqnum = 0;
5908 /* check for seekable upstream, above and beyond a mere query */
5910 gst_qtdemux_check_seekability (GstQTDemux * demux)
5913 gboolean seekable = FALSE;
5914 gint64 start = -1, stop = -1;
5916 if (demux->upstream_size)
5919 query = gst_query_new_seeking (GST_FORMAT_BYTES);
5920 if (!gst_pad_peer_query (demux->sinkpad, query)) {
5921 GST_DEBUG_OBJECT (demux, "seeking query failed");
5925 gst_query_parse_seeking (query, NULL, &seekable, &start, &stop);
5927 /* try harder to query upstream size if we didn't get it the first time */
5928 if (seekable && stop == -1) {
5929 GST_DEBUG_OBJECT (demux, "doing duration query to fix up unset stop");
5930 gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &stop);
5933 /* if upstream doesn't know the size, it's likely that it's not seekable in
5934 * practice even if it technically may be seekable */
5935 if (seekable && (start != 0 || stop <= start)) {
5936 GST_DEBUG_OBJECT (demux, "seekable but unknown start/stop -> disable");
5941 gst_query_unref (query);
5943 GST_DEBUG_OBJECT (demux, "seekable: %d (%" G_GUINT64_FORMAT " - %"
5944 G_GUINT64_FORMAT ")", seekable, start, stop);
5945 demux->upstream_seekable = seekable;
5946 demux->upstream_size = seekable ? stop : -1;
5950 gst_qtdemux_drop_data (GstQTDemux * demux, gint bytes)
5952 g_return_if_fail (bytes <= demux->todrop);
5954 GST_LOG_OBJECT (demux, "Dropping %d bytes", bytes);
5955 gst_adapter_flush (demux->adapter, bytes);
5956 demux->neededbytes -= bytes;
5957 demux->offset += bytes;
5958 demux->todrop -= bytes;
5962 gst_qtdemux_check_send_pending_segment (GstQTDemux * demux)
5964 if (G_UNLIKELY (demux->pending_newsegment)) {
5967 gst_qtdemux_push_pending_newsegment (demux);
5968 /* clear to send tags on all streams */
5969 for (i = 0; i < demux->n_streams; i++) {
5970 QtDemuxStream *stream;
5971 stream = demux->streams[i];
5972 gst_qtdemux_push_tags (demux, stream);
5973 if (stream->sparse) {
5974 GST_INFO_OBJECT (demux, "Sending gap event on stream %d", i);
5975 gst_pad_push_event (stream->pad,
5976 gst_event_new_gap (stream->segment.position, GST_CLOCK_TIME_NONE));
5983 gst_qtdemux_send_gap_for_segment (GstQTDemux * demux,
5984 QtDemuxStream * stream, gint segment_index, GstClockTime pos)
5986 GstClockTime ts, dur;
5991 stream->segments[segment_index].duration - (pos -
5992 stream->segments[segment_index].time);
5993 gap = gst_event_new_gap (ts, dur);
5994 stream->time_position += dur;
5996 GST_DEBUG_OBJECT (stream->pad, "Pushing gap for empty "
5997 "segment: %" GST_PTR_FORMAT, gap);
5998 gst_pad_push_event (stream->pad, gap);
6002 gst_qtdemux_stream_send_initial_gap_segments (GstQTDemux * demux,
6003 QtDemuxStream * stream)
6007 /* Push any initial gap segments before proceeding to the
6009 for (i = 0; i < stream->n_segments; i++) {
6010 gst_qtdemux_activate_segment (demux, stream, i, stream->time_position);
6012 if (QTSEGMENT_IS_EMPTY (&stream->segments[i])) {
6013 gst_qtdemux_send_gap_for_segment (demux, stream, i,
6014 stream->time_position);
6016 /* Only support empty segment at the beginning followed by
6017 * one non-empty segment, this was checked when parsing the
6018 * edts atom, arriving here is unexpected */
6019 g_assert (i + 1 == stream->n_segments);
6025 static GstFlowReturn
6026 gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent, GstBuffer * inbuf)
6030 demux = GST_QTDEMUX (parent);
6032 GST_DEBUG_OBJECT (demux,
6033 "Received buffer pts:%" GST_TIME_FORMAT " dts:%" GST_TIME_FORMAT
6034 " offset:%" G_GUINT64_FORMAT " size:%" G_GSIZE_FORMAT,
6035 GST_TIME_ARGS (GST_BUFFER_PTS (inbuf)),
6036 GST_TIME_ARGS (GST_BUFFER_DTS (inbuf)), GST_BUFFER_OFFSET (inbuf),
6037 gst_buffer_get_size (inbuf));
6039 if (GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_DISCONT)) {
6042 GST_DEBUG_OBJECT (demux, "Got DISCONT, marking all streams as DISCONT");
6044 for (i = 0; i < demux->n_streams; i++) {
6045 demux->streams[i]->discont = TRUE;
6048 /* Reverse fragmented playback, need to flush all we have before
6049 * consuming a new fragment.
6050 * The samples array have the timestamps calculated by accumulating the
6051 * durations but this won't work for reverse playback of fragments as
6052 * the timestamps of a subsequent fragment should be smaller than the
6053 * previously received one. */
6054 if (demux->fragmented && demux->segment.rate < 0) {
6055 gst_qtdemux_process_adapter (demux, TRUE);
6056 for (i = 0; i < demux->n_streams; i++)
6057 gst_qtdemux_stream_flush_samples_data (demux, demux->streams[i]);
6061 gst_adapter_push (demux->adapter, inbuf);
6063 GST_DEBUG_OBJECT (demux,
6064 "pushing in inbuf %p, neededbytes:%u, available:%" G_GSIZE_FORMAT, inbuf,
6065 demux->neededbytes, gst_adapter_available (demux->adapter));
6067 return gst_qtdemux_process_adapter (demux, FALSE);
6070 static GstFlowReturn
6071 gst_qtdemux_process_adapter (GstQTDemux * demux, gboolean force)
6073 GstFlowReturn ret = GST_FLOW_OK;
6075 /* we never really mean to buffer that much */
6076 if (demux->neededbytes == -1) {
6080 while (((gst_adapter_available (demux->adapter)) >= demux->neededbytes) &&
6081 (ret == GST_FLOW_OK || (ret == GST_FLOW_NOT_LINKED && force))) {
6083 GST_DEBUG_OBJECT (demux,
6084 "state:%s , demux->neededbytes:%d, demux->offset:%" G_GUINT64_FORMAT,
6085 qt_demux_state_string (demux->state), demux->neededbytes,
6088 switch (demux->state) {
6089 case QTDEMUX_STATE_INITIAL:{
6094 gst_qtdemux_check_seekability (demux);
6096 data = gst_adapter_map (demux->adapter, demux->neededbytes);
6098 /* get fourcc/length, set neededbytes */
6099 extract_initial_length_and_fourcc ((guint8 *) data, demux->neededbytes,
6101 gst_adapter_unmap (demux->adapter);
6103 GST_DEBUG_OBJECT (demux, "Peeking found [%" GST_FOURCC_FORMAT "] "
6104 "size: %" G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), size);
6106 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
6107 (_("This file is invalid and cannot be played.")),
6108 ("initial atom '%" GST_FOURCC_FORMAT "' has empty length",
6109 GST_FOURCC_ARGS (fourcc)));
6110 ret = GST_FLOW_ERROR;
6113 if (fourcc == FOURCC_mdat) {
6114 gint next_entry = next_entry_size (demux);
6115 if (demux->n_streams > 0 && (next_entry != -1 || !demux->fragmented)) {
6116 /* we have the headers, start playback */
6117 demux->state = QTDEMUX_STATE_MOVIE;
6118 demux->neededbytes = next_entry;
6119 demux->mdatleft = size;
6121 /* no headers yet, try to get them */
6124 guint64 old, target;
6127 old = demux->offset;
6128 target = old + size;
6130 /* try to jump over the atom with a seek */
6131 /* only bother if it seems worth doing so,
6132 * and avoids possible upstream/server problems */
6133 if (demux->upstream_seekable &&
6134 demux->upstream_size > 4 * (1 << 20)) {
6135 res = qtdemux_seek_offset (demux, target);
6137 GST_DEBUG_OBJECT (demux, "skipping seek");
6142 GST_DEBUG_OBJECT (demux, "seek success");
6143 /* remember the offset fo the first mdat so we can seek back to it
6144 * after we have the headers */
6145 if (fourcc == FOURCC_mdat && demux->first_mdat == -1) {
6146 demux->first_mdat = old;
6147 GST_DEBUG_OBJECT (demux, "first mdat at %" G_GUINT64_FORMAT,
6150 /* seek worked, continue reading */
6151 demux->offset = target;
6152 demux->neededbytes = 16;
6153 demux->state = QTDEMUX_STATE_INITIAL;
6155 /* seek failed, need to buffer */
6156 demux->offset = old;
6157 GST_DEBUG_OBJECT (demux, "seek failed/skipped");
6158 /* there may be multiple mdat (or alike) buffers */
6160 if (demux->mdatbuffer)
6161 bs = gst_buffer_get_size (demux->mdatbuffer);
6164 if (size + bs > 10 * (1 << 20))
6166 demux->state = QTDEMUX_STATE_BUFFER_MDAT;
6167 demux->neededbytes = size;
6168 if (!demux->mdatbuffer)
6169 demux->mdatoffset = demux->offset;
6172 } else if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
6173 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
6174 (_("This file is invalid and cannot be played.")),
6175 ("atom %" GST_FOURCC_FORMAT " has bogus size %" G_GUINT64_FORMAT,
6176 GST_FOURCC_ARGS (fourcc), size));
6177 ret = GST_FLOW_ERROR;
6180 /* this means we already started buffering and still no moov header,
6181 * let's continue buffering everything till we get moov */
6182 if (demux->mdatbuffer && !(fourcc == FOURCC_moov
6183 || fourcc == FOURCC_moof))
6185 demux->neededbytes = size;
6186 demux->state = QTDEMUX_STATE_HEADER;
6190 case QTDEMUX_STATE_HEADER:{
6194 GST_DEBUG_OBJECT (demux, "In header");
6196 data = gst_adapter_map (demux->adapter, demux->neededbytes);
6198 /* parse the header */
6199 extract_initial_length_and_fourcc (data, demux->neededbytes, NULL,
6201 if (fourcc == FOURCC_moov) {
6204 /* in usual fragmented setup we could try to scan for more
6205 * and end up at the the moov (after mdat) again */
6206 if (demux->got_moov && demux->n_streams > 0 &&
6208 || demux->last_moov_offset == demux->offset)) {
6209 GST_DEBUG_OBJECT (demux,
6210 "Skipping moov atom as we have (this) one already");
6212 GST_DEBUG_OBJECT (demux, "Parsing [moov]");
6214 if (demux->got_moov && demux->fragmented) {
6215 GST_DEBUG_OBJECT (demux,
6216 "Got a second moov, clean up data from old one");
6217 if (demux->moov_node)
6218 g_node_destroy (demux->moov_node);
6219 demux->moov_node = NULL;
6220 demux->moov_node_compressed = NULL;
6222 /* prepare newsegment to send when streaming actually starts */
6223 if (!demux->pending_newsegment) {
6224 demux->pending_newsegment =
6225 gst_event_new_segment (&demux->segment);
6226 if (demux->segment_seqnum)
6227 gst_event_set_seqnum (demux->pending_newsegment,
6228 demux->segment_seqnum);
6232 demux->last_moov_offset = demux->offset;
6234 qtdemux_parse_moov (demux, data, demux->neededbytes);
6235 qtdemux_node_dump (demux, demux->moov_node);
6236 qtdemux_parse_tree (demux);
6237 qtdemux_prepare_streams (demux);
6238 if (!demux->got_moov)
6239 qtdemux_expose_streams (demux);
6242 for (n = 0; n < demux->n_streams; n++) {
6243 QtDemuxStream *stream = demux->streams[n];
6245 gst_qtdemux_configure_stream (demux, stream);
6249 demux->got_moov = TRUE;
6250 gst_qtdemux_check_send_pending_segment (demux);
6252 /* fragmented streams headers shouldn't contain edts atoms */
6253 if (!demux->fragmented) {
6254 for (n = 0; n < demux->n_streams; n++) {
6255 gst_qtdemux_stream_send_initial_gap_segments (demux,
6260 g_node_destroy (demux->moov_node);
6261 demux->moov_node = NULL;
6262 GST_DEBUG_OBJECT (demux, "Finished parsing the header");
6264 } else if (fourcc == FOURCC_moof) {
6265 if ((demux->got_moov || demux->media_caps) && demux->fragmented) {
6267 GstClockTime prev_pts;
6268 guint64 prev_offset;
6270 GST_DEBUG_OBJECT (demux, "Parsing [moof]");
6273 * The timestamp of the moof buffer is relevant as some scenarios
6274 * won't have the initial timestamp in the atoms. Whenever a new
6275 * buffer has started, we get that buffer's PTS and use it as a base
6276 * timestamp for the trun entries.
6278 * To keep track of the current buffer timestamp and starting point
6279 * we use gst_adapter_prev_pts that gives us the PTS and the distance
6280 * from the beggining of the buffer, with the distance and demux->offset
6281 * we know if it is still the same buffer or not.
6283 prev_pts = gst_adapter_prev_pts (demux->adapter, &dist);
6284 prev_offset = demux->offset - dist;
6285 if (demux->fragment_start_offset == -1
6286 || prev_offset > demux->fragment_start_offset) {
6287 demux->fragment_start_offset = prev_offset;
6288 demux->fragment_start = prev_pts;
6289 GST_DEBUG_OBJECT (demux,
6290 "New fragment start found at: %" G_GUINT64_FORMAT " : %"
6291 GST_TIME_FORMAT, demux->fragment_start_offset,
6292 GST_TIME_ARGS (demux->fragment_start));
6295 demux->moof_offset = demux->offset;
6296 if (!qtdemux_parse_moof (demux, data, demux->neededbytes,
6297 demux->offset, NULL)) {
6298 gst_adapter_unmap (demux->adapter);
6299 ret = GST_FLOW_ERROR;
6302 /* in MSS we need to expose the pads after the first moof as we won't get a moov */
6303 if (demux->mss_mode && !demux->exposed) {
6304 if (!demux->pending_newsegment) {
6305 GST_DEBUG_OBJECT (demux, "new pending_newsegment");
6306 demux->pending_newsegment =
6307 gst_event_new_segment (&demux->segment);
6308 if (demux->segment_seqnum)
6309 gst_event_set_seqnum (demux->pending_newsegment,
6310 demux->segment_seqnum);
6312 qtdemux_expose_streams (demux);
6315 GST_DEBUG_OBJECT (demux, "Discarding [moof]");
6317 } else if (fourcc == FOURCC_ftyp) {
6318 GST_DEBUG_OBJECT (demux, "Parsing [ftyp]");
6319 qtdemux_parse_ftyp (demux, data, demux->neededbytes);
6320 } else if (fourcc == FOURCC_uuid) {
6321 GST_DEBUG_OBJECT (demux, "Parsing [uuid]");
6322 qtdemux_parse_uuid (demux, data, demux->neededbytes);
6323 } else if (fourcc == FOURCC_sidx) {
6324 GST_DEBUG_OBJECT (demux, "Parsing [sidx]");
6325 qtdemux_parse_sidx (demux, data, demux->neededbytes);
6327 GST_WARNING_OBJECT (demux,
6328 "Unknown fourcc while parsing header : %" GST_FOURCC_FORMAT,
6329 GST_FOURCC_ARGS (fourcc));
6330 /* Let's jump that one and go back to initial state */
6332 gst_adapter_unmap (demux->adapter);
6335 if (demux->mdatbuffer && demux->n_streams) {
6336 gsize remaining_data_size = 0;
6338 /* the mdat was before the header */
6339 GST_DEBUG_OBJECT (demux, "We have n_streams:%d and mdatbuffer:%p",
6340 demux->n_streams, demux->mdatbuffer);
6341 /* restore our adapter/offset view of things with upstream;
6342 * put preceding buffered data ahead of current moov data.
6343 * This should also handle evil mdat, moov, mdat cases and alike */
6344 gst_adapter_flush (demux->adapter, demux->neededbytes);
6346 /* Store any remaining data after the mdat for later usage */
6347 remaining_data_size = gst_adapter_available (demux->adapter);
6348 if (remaining_data_size > 0) {
6349 g_assert (demux->restoredata_buffer == NULL);
6350 demux->restoredata_buffer =
6351 gst_adapter_take_buffer (demux->adapter, remaining_data_size);
6352 demux->restoredata_offset = demux->offset + demux->neededbytes;
6353 GST_DEBUG_OBJECT (demux,
6354 "Stored %" G_GSIZE_FORMAT " post mdat bytes at offset %"
6355 G_GUINT64_FORMAT, remaining_data_size,
6356 demux->restoredata_offset);
6359 gst_adapter_push (demux->adapter, demux->mdatbuffer);
6360 demux->mdatbuffer = NULL;
6361 demux->offset = demux->mdatoffset;
6362 demux->neededbytes = next_entry_size (demux);
6363 demux->state = QTDEMUX_STATE_MOVIE;
6364 demux->mdatleft = gst_adapter_available (demux->adapter);
6366 GST_DEBUG_OBJECT (demux, "Carrying on normally");
6367 gst_adapter_flush (demux->adapter, demux->neededbytes);
6369 /* only go back to the mdat if there are samples to play */
6370 if (demux->got_moov && demux->first_mdat != -1
6371 && has_next_entry (demux)) {
6374 /* we need to seek back */
6375 res = qtdemux_seek_offset (demux, demux->first_mdat);
6377 demux->offset = demux->first_mdat;
6379 GST_DEBUG_OBJECT (demux, "Seek back failed");
6382 demux->offset += demux->neededbytes;
6384 demux->neededbytes = 16;
6385 demux->state = QTDEMUX_STATE_INITIAL;
6390 case QTDEMUX_STATE_BUFFER_MDAT:{
6394 GST_DEBUG_OBJECT (demux, "Got our buffer at offset %" G_GUINT64_FORMAT,
6396 buf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
6397 gst_buffer_extract (buf, 0, fourcc, 4);
6398 GST_DEBUG_OBJECT (demux, "mdatbuffer starts with %" GST_FOURCC_FORMAT,
6399 GST_FOURCC_ARGS (QT_FOURCC (fourcc)));
6400 if (demux->mdatbuffer)
6401 demux->mdatbuffer = gst_buffer_append (demux->mdatbuffer, buf);
6403 demux->mdatbuffer = buf;
6404 demux->offset += demux->neededbytes;
6405 demux->neededbytes = 16;
6406 demux->state = QTDEMUX_STATE_INITIAL;
6407 gst_qtdemux_post_progress (demux, 1, 1);
6411 case QTDEMUX_STATE_MOVIE:{
6412 QtDemuxStream *stream = NULL;
6413 QtDemuxSample *sample;
6415 GstClockTime dts, pts, duration;
6418 GST_DEBUG_OBJECT (demux,
6419 "BEGIN // in MOVIE for offset %" G_GUINT64_FORMAT, demux->offset);
6421 if (demux->fragmented) {
6422 GST_DEBUG_OBJECT (demux, "mdat remaining %" G_GUINT64_FORMAT,
6424 if (G_LIKELY (demux->todrop < demux->mdatleft)) {
6425 /* if needed data starts within this atom,
6426 * then it should not exceed this atom */
6427 if (G_UNLIKELY (demux->neededbytes > demux->mdatleft)) {
6428 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
6429 (_("This file is invalid and cannot be played.")),
6430 ("sample data crosses atom boundary"));
6431 ret = GST_FLOW_ERROR;
6434 demux->mdatleft -= demux->neededbytes;
6436 GST_DEBUG_OBJECT (demux, "data atom emptied; resuming atom scan");
6437 /* so we are dropping more than left in this atom */
6438 gst_qtdemux_drop_data (demux, demux->mdatleft);
6439 demux->mdatleft = 0;
6441 /* need to resume atom parsing so we do not miss any other pieces */
6442 demux->state = QTDEMUX_STATE_INITIAL;
6443 demux->neededbytes = 16;
6445 /* check if there was any stored post mdat data from previous buffers */
6446 if (demux->restoredata_buffer) {
6447 g_assert (gst_adapter_available (demux->adapter) == 0);
6449 gst_adapter_push (demux->adapter, demux->restoredata_buffer);
6450 demux->restoredata_buffer = NULL;
6451 demux->offset = demux->restoredata_offset;
6458 if (demux->todrop) {
6459 if (demux->cenc_aux_info_offset > 0) {
6463 GST_DEBUG_OBJECT (demux, "parsing cenc auxiliary info");
6464 data = gst_adapter_map (demux->adapter, demux->todrop);
6465 gst_byte_reader_init (&br, data + 8, demux->todrop);
6466 if (!qtdemux_parse_cenc_aux_info (demux, demux->streams[0], &br,
6467 demux->cenc_aux_info_sizes, demux->cenc_aux_sample_count)) {
6468 GST_ERROR_OBJECT (demux, "failed to parse cenc auxiliary info");
6469 ret = GST_FLOW_ERROR;
6470 gst_adapter_unmap (demux->adapter);
6471 g_free (demux->cenc_aux_info_sizes);
6472 demux->cenc_aux_info_sizes = NULL;
6475 demux->cenc_aux_info_offset = 0;
6476 g_free (demux->cenc_aux_info_sizes);
6477 demux->cenc_aux_info_sizes = NULL;
6478 gst_adapter_unmap (demux->adapter);
6480 gst_qtdemux_drop_data (demux, demux->todrop);
6484 /* initial newsegment sent here after having added pads,
6485 * possible others in sink_event */
6486 gst_qtdemux_check_send_pending_segment (demux);
6488 /* Figure out which stream this packet belongs to */
6489 for (i = 0; i < demux->n_streams; i++) {
6490 stream = demux->streams[i];
6491 if (stream->sample_index >= stream->n_samples)
6493 GST_LOG_OBJECT (demux,
6494 "Checking stream %d (sample_index:%d / offset:%" G_GUINT64_FORMAT
6495 " / size:%d)", i, stream->sample_index,
6496 stream->samples[stream->sample_index].offset,
6497 stream->samples[stream->sample_index].size);
6499 if (stream->samples[stream->sample_index].offset == demux->offset)
6503 if (G_UNLIKELY (stream == NULL || i == demux->n_streams))
6504 goto unknown_stream;
6506 if (stream->new_caps) {
6507 gst_qtdemux_configure_stream (demux, stream);
6510 /* Put data in a buffer, set timestamps, caps, ... */
6511 sample = &stream->samples[stream->sample_index];
6513 if (G_LIKELY (!(STREAM_IS_EOS (stream)))) {
6514 GST_DEBUG_OBJECT (demux, "stream : %" GST_FOURCC_FORMAT,
6515 GST_FOURCC_ARGS (stream->fourcc));
6517 dts = QTSAMPLE_DTS (stream, sample);
6518 pts = QTSAMPLE_PTS (stream, sample);
6519 duration = QTSAMPLE_DUR_DTS (stream, sample, dts);
6520 keyframe = QTSAMPLE_KEYFRAME (stream, sample);
6522 /* check for segment end */
6523 if (G_UNLIKELY (demux->segment.stop != -1
6524 && demux->segment.stop <= pts && stream->on_keyframe)) {
6525 GST_DEBUG_OBJECT (demux, "we reached the end of our segment.");
6526 stream->time_position = GST_CLOCK_TIME_NONE; /* this means EOS */
6528 /* skip this data, stream is EOS */
6529 gst_adapter_flush (demux->adapter, demux->neededbytes);
6531 /* check if all streams are eos */
6533 for (i = 0; i < demux->n_streams; i++) {
6534 if (!STREAM_IS_EOS (demux->streams[i])) {
6540 if (ret == GST_FLOW_EOS) {
6541 GST_DEBUG_OBJECT (demux, "All streams are EOS, signal upstream");
6548 gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
6550 /* FIXME: should either be an assert or a plain check */
6551 g_return_val_if_fail (outbuf != NULL, GST_FLOW_ERROR);
6553 ret = gst_qtdemux_decorate_and_push_buffer (demux, stream, outbuf,
6554 dts, pts, duration, keyframe, dts, demux->offset);
6558 ret = gst_qtdemux_combine_flows (demux, stream, ret);
6559 if (ret != GST_FLOW_OK && ret != GST_FLOW_NOT_LINKED)
6560 goto non_ok_unlinked_flow;
6562 /* skip this data, stream is EOS */
6563 gst_adapter_flush (demux->adapter, demux->neededbytes);
6566 stream->sample_index++;
6567 stream->offset_in_sample = 0;
6569 /* update current offset and figure out size of next buffer */
6570 GST_LOG_OBJECT (demux, "increasing offset %" G_GUINT64_FORMAT " by %u",
6571 demux->offset, demux->neededbytes);
6572 demux->offset += demux->neededbytes;
6573 GST_LOG_OBJECT (demux, "offset is now %" G_GUINT64_FORMAT,
6576 if ((demux->neededbytes = next_entry_size (demux)) == -1) {
6577 if (demux->fragmented) {
6578 GST_DEBUG_OBJECT (demux, "(temporarily) out of fragmented samples");
6579 /* there may be more to follow, only finish this atom */
6580 demux->todrop = demux->mdatleft;
6581 demux->neededbytes = demux->todrop;
6593 /* when buffering movie data, at least show user something is happening */
6594 if (ret == GST_FLOW_OK && demux->state == QTDEMUX_STATE_BUFFER_MDAT &&
6595 gst_adapter_available (demux->adapter) <= demux->neededbytes) {
6596 gst_qtdemux_post_progress (demux, gst_adapter_available (demux->adapter),
6597 demux->neededbytes);
6604 non_ok_unlinked_flow:
6606 GST_DEBUG_OBJECT (demux, "Stopping, combined return flow %s",
6607 gst_flow_get_name (ret));
6612 GST_ELEMENT_ERROR (demux, STREAM, FAILED, (NULL), ("unknown stream found"));
6613 ret = GST_FLOW_ERROR;
6618 GST_DEBUG_OBJECT (demux, "no next entry, EOS");
6624 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
6625 (NULL), ("qtdemuxer invalid state %d", demux->state));
6626 ret = GST_FLOW_ERROR;
6631 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
6632 (NULL), ("no 'moov' atom within the first 10 MB"));
6633 ret = GST_FLOW_ERROR;
6639 qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent)
6644 query = gst_query_new_scheduling ();
6646 if (!gst_pad_peer_query (sinkpad, query)) {
6647 gst_query_unref (query);
6651 pull_mode = gst_query_has_scheduling_mode_with_flags (query,
6652 GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
6653 gst_query_unref (query);
6658 GST_DEBUG_OBJECT (sinkpad, "activating pull");
6659 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
6663 GST_DEBUG_OBJECT (sinkpad, "activating push");
6664 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
6669 qtdemux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
6670 GstPadMode mode, gboolean active)
6673 GstQTDemux *demux = GST_QTDEMUX (parent);
6676 case GST_PAD_MODE_PUSH:
6677 demux->pullbased = FALSE;
6680 case GST_PAD_MODE_PULL:
6682 demux->pullbased = TRUE;
6683 res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_qtdemux_loop,
6686 res = gst_pad_stop_task (sinkpad);
6698 qtdemux_zalloc (void *opaque, unsigned int items, unsigned int size)
6700 return g_malloc (items * size);
6704 qtdemux_zfree (void *opaque, void *addr)
6710 qtdemux_inflate (void *z_buffer, guint z_length, guint length)
6716 z = g_new0 (z_stream, 1);
6717 z->zalloc = qtdemux_zalloc;
6718 z->zfree = qtdemux_zfree;
6721 z->next_in = z_buffer;
6722 z->avail_in = z_length;
6724 buffer = (guint8 *) g_malloc (length);
6725 ret = inflateInit (z);
6726 while (z->avail_in > 0) {
6727 if (z->avail_out == 0) {
6729 buffer = (guint8 *) g_realloc (buffer, length);
6730 z->next_out = buffer + z->total_out;
6731 z->avail_out = 1024;
6733 ret = inflate (z, Z_SYNC_FLUSH);
6737 if (ret != Z_STREAM_END) {
6738 g_warning ("inflate() returned %d", ret);
6744 #endif /* HAVE_ZLIB */
6747 qtdemux_parse_moov (GstQTDemux * qtdemux, const guint8 * buffer, guint length)
6751 qtdemux->moov_node = g_node_new ((guint8 *) buffer);
6753 /* counts as header data */
6754 qtdemux->header_size += length;
6756 GST_DEBUG_OBJECT (qtdemux, "parsing 'moov' atom");
6757 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buffer, length);
6759 cmov = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_cmov);
6765 dcom = qtdemux_tree_get_child_by_type (cmov, FOURCC_dcom);
6766 cmvd = qtdemux_tree_get_child_by_type (cmov, FOURCC_cmvd);
6767 if (dcom == NULL || cmvd == NULL)
6768 goto invalid_compression;
6770 method = QT_FOURCC ((guint8 *) dcom->data + 8);
6774 guint uncompressed_length;
6775 guint compressed_length;
6778 uncompressed_length = QT_UINT32 ((guint8 *) cmvd->data + 8);
6779 compressed_length = QT_UINT32 ((guint8 *) cmvd->data + 4) - 12;
6780 GST_LOG ("length = %u", uncompressed_length);
6783 (guint8 *) qtdemux_inflate ((guint8 *) cmvd->data + 12,
6784 compressed_length, uncompressed_length);
6786 qtdemux->moov_node_compressed = qtdemux->moov_node;
6787 qtdemux->moov_node = g_node_new (buf);
6789 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buf,
6790 uncompressed_length);
6793 #endif /* HAVE_ZLIB */
6795 GST_WARNING_OBJECT (qtdemux, "unknown or unhandled header compression "
6796 "type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (method));
6803 invalid_compression:
6805 GST_ERROR_OBJECT (qtdemux, "invalid compressed header");
6811 qtdemux_parse_container (GstQTDemux * qtdemux, GNode * node, const guint8 * buf,
6814 while (G_UNLIKELY (buf < end)) {
6818 if (G_UNLIKELY (buf + 4 > end)) {
6819 GST_LOG_OBJECT (qtdemux, "buffer overrun");
6822 len = QT_UINT32 (buf);
6823 if (G_UNLIKELY (len == 0)) {
6824 GST_LOG_OBJECT (qtdemux, "empty container");
6827 if (G_UNLIKELY (len < 8)) {
6828 GST_WARNING_OBJECT (qtdemux, "length too short (%d < 8)", len);
6831 if (G_UNLIKELY (len > (end - buf))) {
6832 GST_WARNING_OBJECT (qtdemux, "length too long (%d > %d)", len,
6833 (gint) (end - buf));
6837 child = g_node_new ((guint8 *) buf);
6838 g_node_append (node, child);
6839 GST_LOG_OBJECT (qtdemux, "adding new node of len %d", len);
6840 qtdemux_parse_node (qtdemux, child, buf, len);
6848 qtdemux_parse_theora_extension (GstQTDemux * qtdemux, QtDemuxStream * stream,
6851 int len = QT_UINT32 (xdxt->data);
6852 guint8 *buf = xdxt->data;
6853 guint8 *end = buf + len;
6856 /* skip size and type */
6864 size = QT_UINT32 (buf);
6865 type = QT_FOURCC (buf + 4);
6867 GST_LOG_OBJECT (qtdemux, "%p %p", buf, end);
6869 if (buf + size > end || size <= 0)
6875 GST_WARNING_OBJECT (qtdemux, "have cookie %" GST_FOURCC_FORMAT,
6876 GST_FOURCC_ARGS (type));
6880 buffer = gst_buffer_new_and_alloc (size);
6881 gst_buffer_fill (buffer, 0, buf, size);
6882 stream->buffers = g_slist_append (stream->buffers, buffer);
6883 GST_LOG_OBJECT (qtdemux, "parsing theora header");
6886 buffer = gst_buffer_new_and_alloc (size);
6887 gst_buffer_fill (buffer, 0, buf, size);
6888 stream->buffers = g_slist_append (stream->buffers, buffer);
6889 GST_LOG_OBJECT (qtdemux, "parsing theora comment");
6892 buffer = gst_buffer_new_and_alloc (size);
6893 gst_buffer_fill (buffer, 0, buf, size);
6894 stream->buffers = g_slist_append (stream->buffers, buffer);
6895 GST_LOG_OBJECT (qtdemux, "parsing theora codebook");
6898 GST_WARNING_OBJECT (qtdemux,
6899 "unknown theora cookie %" GST_FOURCC_FORMAT,
6900 GST_FOURCC_ARGS (type));
6909 qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node, const guint8 * buffer,
6913 guint32 node_length = 0;
6914 const QtNodeType *type;
6917 GST_LOG_OBJECT (qtdemux, "qtdemux_parse buffer %p length %u", buffer, length);
6919 if (G_UNLIKELY (length < 8))
6920 goto not_enough_data;
6922 node_length = QT_UINT32 (buffer);
6923 fourcc = QT_FOURCC (buffer + 4);
6925 /* ignore empty nodes */
6926 if (G_UNLIKELY (fourcc == 0 || node_length == 8))
6929 type = qtdemux_type_get (fourcc);
6931 end = buffer + length;
6933 GST_LOG_OBJECT (qtdemux,
6934 "parsing '%" GST_FOURCC_FORMAT "', length=%u, name '%s'",
6935 GST_FOURCC_ARGS (fourcc), node_length, type->name);
6937 if (node_length > length)
6938 goto broken_atom_size;
6940 if (type->flags & QT_FLAG_CONTAINER) {
6941 qtdemux_parse_container (qtdemux, node, buffer + 8, end);
6946 if (node_length < 20) {
6947 GST_LOG_OBJECT (qtdemux, "skipping small stsd box");
6950 GST_DEBUG_OBJECT (qtdemux,
6951 "parsing stsd (sample table, sample description) atom");
6952 /* Skip over 8 byte atom hdr + 1 byte version, 3 bytes flags, 4 byte num_entries */
6953 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
6963 /* also read alac (or whatever) in stead of mp4a in the following,
6964 * since a similar layout is used in other cases as well */
6965 if (fourcc == FOURCC_mp4a)
6970 /* There are two things we might encounter here: a true mp4a atom, and
6971 an mp4a entry in an stsd atom. The latter is what we're interested
6972 in, and it looks like an atom, but isn't really one. The true mp4a
6973 atom is short, so we detect it based on length here. */
6974 if (length < min_size) {
6975 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
6976 GST_FOURCC_ARGS (fourcc));
6980 /* 'version' here is the sound sample description version. Types 0 and
6981 1 are documented in the QTFF reference, but type 2 is not: it's
6982 described in Apple header files instead (struct SoundDescriptionV2
6984 version = QT_UINT16 (buffer + 16);
6986 GST_DEBUG_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT " version 0x%08x",
6987 GST_FOURCC_ARGS (fourcc), version);
6989 /* parse any esds descriptors */
7001 GST_WARNING_OBJECT (qtdemux,
7002 "unhandled %" GST_FOURCC_FORMAT " version 0x%08x",
7003 GST_FOURCC_ARGS (fourcc), version);
7008 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
7025 /* codec_data is contained inside these atoms, which all have
7026 * the same format. */
7028 GST_DEBUG_OBJECT (qtdemux, "parsing in %" GST_FOURCC_FORMAT,
7029 GST_FOURCC_ARGS (fourcc));
7030 version = QT_UINT32 (buffer + 16);
7031 GST_DEBUG_OBJECT (qtdemux, "version %08x", version);
7032 if (1 || version == 0x00000000) {
7033 buf = buffer + 0x32;
7035 /* FIXME Quicktime uses PASCAL string while
7036 * the iso format uses C strings. Check the file
7037 * type before attempting to parse the string here. */
7038 tlen = QT_UINT8 (buf);
7039 GST_DEBUG_OBJECT (qtdemux, "tlen = %d", tlen);
7041 GST_DEBUG_OBJECT (qtdemux, "string = %.*s", tlen, (char *) buf);
7042 /* the string has a reserved space of 32 bytes so skip
7043 * the remaining 31 */
7045 buf += 4; /* and 4 bytes reserved */
7047 GST_MEMDUMP_OBJECT (qtdemux, "mp4v", buf, end - buf);
7049 qtdemux_parse_container (qtdemux, node, buf, end);
7055 GST_MEMDUMP_OBJECT (qtdemux, "H264", buffer, end - buffer);
7056 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
7061 GST_MEMDUMP_OBJECT (qtdemux, "avc1", buffer, end - buffer);
7062 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
7067 GST_MEMDUMP_OBJECT (qtdemux, "avc3", buffer, end - buffer);
7068 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
7073 GST_MEMDUMP_OBJECT (qtdemux, "H265", buffer, end - buffer);
7074 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
7079 GST_MEMDUMP_OBJECT (qtdemux, "hvc1", buffer, end - buffer);
7080 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
7085 GST_MEMDUMP_OBJECT (qtdemux, "hev1", buffer, end - buffer);
7086 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
7091 qtdemux_parse_container (qtdemux, node, buffer + 86, end);
7096 GST_DEBUG_OBJECT (qtdemux, "parsing meta atom");
7097 qtdemux_parse_container (qtdemux, node, buffer + 12, end);
7102 GST_MEMDUMP_OBJECT (qtdemux, "mp4s", buffer, end - buffer);
7103 /* Skip 8 byte header, plus 8 byte version + flags + entry_count */
7104 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
7112 version = QT_UINT32 (buffer + 12);
7113 GST_DEBUG_OBJECT (qtdemux, "parsing XiTh atom version 0x%08x", version);
7120 GST_DEBUG_OBJECT (qtdemux, "unknown version 0x%08x", version);
7125 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
7130 qtdemux_parse_container (qtdemux, node, buffer + 0x34, end);
7135 qtdemux_parse_uuid (qtdemux, buffer, end - buffer);
7140 qtdemux_parse_container (qtdemux, node, buffer + 86, end);
7145 qtdemux_parse_container (qtdemux, node, buffer + 36, end);
7149 if (!strcmp (type->name, "unknown"))
7150 GST_MEMDUMP ("Unknown tag", buffer + 4, end - buffer - 4);
7154 GST_LOG_OBJECT (qtdemux, "parsed '%" GST_FOURCC_FORMAT "'",
7155 GST_FOURCC_ARGS (fourcc));
7161 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
7162 (_("This file is corrupt and cannot be played.")),
7163 ("Not enough data for an atom header, got only %u bytes", length));
7168 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
7169 (_("This file is corrupt and cannot be played.")),
7170 ("Atom '%" GST_FOURCC_FORMAT "' has size of %u bytes, but we have only "
7171 "%u bytes available.", GST_FOURCC_ARGS (fourcc), node_length,
7178 qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc)
7182 guint32 child_fourcc;
7184 for (child = g_node_first_child (node); child;
7185 child = g_node_next_sibling (child)) {
7186 buffer = (guint8 *) child->data;
7188 child_fourcc = QT_FOURCC (buffer + 4);
7190 if (G_UNLIKELY (child_fourcc == fourcc)) {
7198 qtdemux_tree_get_child_by_type_full (GNode * node, guint32 fourcc,
7199 GstByteReader * parser)
7203 guint32 child_fourcc, child_len;
7205 for (child = g_node_first_child (node); child;
7206 child = g_node_next_sibling (child)) {
7207 buffer = (guint8 *) child->data;
7209 child_len = QT_UINT32 (buffer);
7210 child_fourcc = QT_FOURCC (buffer + 4);
7212 if (G_UNLIKELY (child_fourcc == fourcc)) {
7213 if (G_UNLIKELY (child_len < (4 + 4)))
7215 /* FIXME: must verify if atom length < parent atom length */
7216 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
7224 qtdemux_tree_get_sibling_by_type_full (GNode * node, guint32 fourcc,
7225 GstByteReader * parser)
7229 guint32 child_fourcc, child_len;
7231 for (child = g_node_next_sibling (node); child;
7232 child = g_node_next_sibling (child)) {
7233 buffer = (guint8 *) child->data;
7235 child_fourcc = QT_FOURCC (buffer + 4);
7237 if (child_fourcc == fourcc) {
7239 child_len = QT_UINT32 (buffer);
7240 if (G_UNLIKELY (child_len < (4 + 4)))
7242 /* FIXME: must verify if atom length < parent atom length */
7243 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
7252 qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc)
7254 return qtdemux_tree_get_sibling_by_type_full (node, fourcc, NULL);
7258 qtdemux_do_allocation (GstQTDemux * qtdemux, QtDemuxStream * stream)
7260 /* FIXME: This can only reliably work if demuxers have a
7261 * separate streaming thread per srcpad. This should be
7262 * done in a demuxer base class, which integrates parts
7265 * https://bugzilla.gnome.org/show_bug.cgi?id=701856
7270 query = gst_query_new_allocation (stream->caps, FALSE);
7272 if (!gst_pad_peer_query (stream->pad, query)) {
7273 /* not a problem, just debug a little */
7274 GST_DEBUG_OBJECT (qtdemux, "peer ALLOCATION query failed");
7277 if (stream->allocator)
7278 gst_object_unref (stream->allocator);
7280 if (gst_query_get_n_allocation_params (query) > 0) {
7281 /* try the allocator */
7282 gst_query_parse_nth_allocation_param (query, 0, &stream->allocator,
7284 stream->use_allocator = TRUE;
7286 stream->allocator = NULL;
7287 gst_allocation_params_init (&stream->params);
7288 stream->use_allocator = FALSE;
7290 gst_query_unref (query);
7295 gst_qtdemux_configure_protected_caps (GstQTDemux * qtdemux,
7296 QtDemuxStream * stream)
7299 const gchar *selected_system;
7301 g_return_val_if_fail (qtdemux != NULL, FALSE);
7302 g_return_val_if_fail (stream != NULL, FALSE);
7303 g_return_val_if_fail (gst_caps_get_size (stream->caps) == 1, FALSE);
7305 if (stream->protection_scheme_type != FOURCC_cenc) {
7306 GST_ERROR_OBJECT (qtdemux, "unsupported protection scheme");
7309 if (qtdemux->protection_system_ids == NULL) {
7310 GST_ERROR_OBJECT (qtdemux, "stream is protected using cenc, but no "
7311 "cenc protection system information has been found");
7314 g_ptr_array_add (qtdemux->protection_system_ids, NULL);
7315 selected_system = gst_protection_select_system ((const gchar **)
7316 qtdemux->protection_system_ids->pdata);
7317 g_ptr_array_remove_index (qtdemux->protection_system_ids,
7318 qtdemux->protection_system_ids->len - 1);
7319 if (!selected_system) {
7320 GST_ERROR_OBJECT (qtdemux, "stream is protected, but no "
7321 "suitable decryptor element has been found");
7325 s = gst_caps_get_structure (stream->caps, 0);
7326 if (!gst_structure_has_name (s, "application/x-cenc")) {
7327 gst_structure_set (s,
7328 "original-media-type", G_TYPE_STRING, gst_structure_get_name (s),
7329 GST_PROTECTION_SYSTEM_ID_CAPS_FIELD, G_TYPE_STRING, selected_system,
7331 gst_structure_set_name (s, "application/x-cenc");
7337 gst_qtdemux_configure_stream (GstQTDemux * qtdemux, QtDemuxStream * stream)
7339 if (stream->subtype == FOURCC_vide) {
7340 /* fps is calculated base on the duration of the average framerate since
7341 * qt does not have a fixed framerate. */
7342 gboolean fps_available = TRUE;
7344 if ((stream->n_samples == 1) && (stream->first_duration == 0)) {
7349 if (stream->duration == 0 || stream->n_samples < 2) {
7350 stream->fps_n = stream->timescale;
7352 fps_available = FALSE;
7354 GstClockTime avg_duration;
7358 /* duration and n_samples can be updated for fragmented format
7359 * so, framerate of fragmented format is calculated using data in a moof */
7360 if (qtdemux->fragmented && stream->n_samples_moof > 0
7361 && stream->duration_moof > 0) {
7362 n_samples = stream->n_samples_moof;
7363 duration = stream->duration_moof;
7365 n_samples = stream->n_samples;
7366 duration = stream->duration;
7369 /* Calculate a framerate, ignoring the first sample which is sometimes truncated */
7370 /* stream->duration is guint64, timescale, n_samples are guint32 */
7372 gst_util_uint64_scale_round (duration -
7373 stream->first_duration, GST_SECOND,
7374 (guint64) (stream->timescale) * (n_samples - 1));
7376 GST_LOG_OBJECT (qtdemux,
7377 "Calculating avg sample duration based on stream (or moof) duration %"
7379 " minus first sample %u, leaving %d samples gives %"
7380 GST_TIME_FORMAT, duration, stream->first_duration,
7381 n_samples - 1, GST_TIME_ARGS (avg_duration));
7383 gst_video_guess_framerate (avg_duration, &stream->fps_n,
7386 GST_DEBUG_OBJECT (qtdemux,
7387 "Calculating framerate, timescale %u gave fps_n %d fps_d %d",
7388 stream->timescale, stream->fps_n, stream->fps_d);
7393 stream->caps = gst_caps_make_writable (stream->caps);
7395 gst_caps_set_simple (stream->caps,
7396 "width", G_TYPE_INT, stream->width,
7397 "height", G_TYPE_INT, stream->height, NULL);
7399 /* set framerate if calculated framerate is reliable */
7400 if (fps_available) {
7401 gst_caps_set_simple (stream->caps,
7402 "framerate", GST_TYPE_FRACTION, stream->fps_n, stream->fps_d, NULL);
7405 /* calculate pixel-aspect-ratio using display width and height */
7406 GST_DEBUG_OBJECT (qtdemux,
7407 "video size %dx%d, target display size %dx%d", stream->width,
7408 stream->height, stream->display_width, stream->display_height);
7409 /* qt file might have pasp atom */
7410 if (stream->par_w > 0 && stream->par_h > 0) {
7411 GST_DEBUG_OBJECT (qtdemux, "par %d:%d", stream->par_w, stream->par_h);
7412 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
7413 GST_TYPE_FRACTION, stream->par_w, stream->par_h, NULL);
7414 } else if (stream->display_width > 0 && stream->display_height > 0 &&
7415 stream->width > 0 && stream->height > 0) {
7418 /* calculate the pixel aspect ratio using the display and pixel w/h */
7419 n = stream->display_width * stream->height;
7420 d = stream->display_height * stream->width;
7423 GST_DEBUG_OBJECT (qtdemux, "setting PAR to %d/%d", n, d);
7426 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
7427 GST_TYPE_FRACTION, stream->par_w, stream->par_h, NULL);
7430 if (stream->multiview_mode != GST_VIDEO_MULTIVIEW_MODE_NONE) {
7431 guint par_w = 1, par_h = 1;
7433 if (stream->par_w > 0 && stream->par_h > 0) {
7434 par_w = stream->par_w;
7435 par_h = stream->par_h;
7438 if (gst_video_multiview_guess_half_aspect (stream->multiview_mode,
7439 stream->width, stream->height, par_w, par_h)) {
7440 stream->multiview_flags |= GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT;
7443 gst_caps_set_simple (stream->caps,
7444 "multiview-mode", G_TYPE_STRING,
7445 gst_video_multiview_mode_to_caps_string (stream->multiview_mode),
7446 "multiview-flags", GST_TYPE_VIDEO_MULTIVIEW_FLAGSET,
7447 stream->multiview_flags, GST_FLAG_SET_MASK_EXACT, NULL);
7452 else if (stream->subtype == FOURCC_soun) {
7454 stream->caps = gst_caps_make_writable (stream->caps);
7455 if (stream->rate > 0)
7456 gst_caps_set_simple (stream->caps,
7457 "rate", G_TYPE_INT, (int) stream->rate, NULL);
7458 if (stream->n_channels > 0)
7459 gst_caps_set_simple (stream->caps,
7460 "channels", G_TYPE_INT, stream->n_channels, NULL);
7461 if (stream->n_channels > 2) {
7462 /* FIXME: Need to parse the 'chan' atom to get channel layouts
7463 * correctly; this is just the minimum we can do - assume
7464 * we don't actually have any channel positions. */
7465 gst_caps_set_simple (stream->caps,
7466 "channel-mask", GST_TYPE_BITMASK, G_GUINT64_CONSTANT (0), NULL);
7472 GstCaps *prev_caps = NULL;
7474 GST_PAD_ELEMENT_PRIVATE (stream->pad) = stream;
7475 gst_pad_set_event_function (stream->pad, gst_qtdemux_handle_src_event);
7476 gst_pad_set_query_function (stream->pad, gst_qtdemux_handle_src_query);
7477 gst_pad_set_active (stream->pad, TRUE);
7479 gst_pad_use_fixed_caps (stream->pad);
7481 if (stream->protected) {
7482 if (!gst_qtdemux_configure_protected_caps (qtdemux, stream)) {
7483 GST_ERROR_OBJECT (qtdemux,
7484 "Failed to configure protected stream caps.");
7489 if (stream->new_stream) {
7492 GstStreamFlags stream_flags;
7495 gst_pad_get_sticky_event (qtdemux->sinkpad, GST_EVENT_STREAM_START,
7498 if (gst_event_parse_group_id (event, &qtdemux->group_id))
7499 qtdemux->have_group_id = TRUE;
7501 qtdemux->have_group_id = FALSE;
7502 gst_event_unref (event);
7503 } else if (!qtdemux->have_group_id) {
7504 qtdemux->have_group_id = TRUE;
7505 qtdemux->group_id = gst_util_group_id_next ();
7508 stream->new_stream = FALSE;
7510 gst_pad_create_stream_id_printf (stream->pad,
7511 GST_ELEMENT_CAST (qtdemux), "%03u", stream->track_id);
7512 event = gst_event_new_stream_start (stream_id);
7513 if (qtdemux->have_group_id)
7514 gst_event_set_group_id (event, qtdemux->group_id);
7515 stream_flags = GST_STREAM_FLAG_NONE;
7516 if (stream->disabled)
7517 stream_flags |= GST_STREAM_FLAG_UNSELECT;
7519 stream_flags |= GST_STREAM_FLAG_SPARSE;
7520 gst_event_set_stream_flags (event, stream_flags);
7521 gst_pad_push_event (stream->pad, event);
7525 prev_caps = gst_pad_get_current_caps (stream->pad);
7527 if (!prev_caps || !gst_caps_is_equal_fixed (prev_caps, stream->caps)) {
7528 GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT, stream->caps);
7529 gst_pad_set_caps (stream->pad, stream->caps);
7531 GST_DEBUG_OBJECT (qtdemux, "ignore duplicated caps");
7535 gst_caps_unref (prev_caps);
7536 stream->new_caps = FALSE;
7542 gst_qtdemux_add_stream (GstQTDemux * qtdemux,
7543 QtDemuxStream * stream, GstTagList * list)
7545 gboolean ret = TRUE;
7546 /* consistent default for push based mode */
7547 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
7549 if (stream->subtype == FOURCC_vide) {
7550 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
7553 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
7556 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
7557 gst_object_unref (stream->pad);
7563 qtdemux->n_video_streams++;
7564 } else if (stream->subtype == FOURCC_soun) {
7565 gchar *name = g_strdup_printf ("audio_%u", qtdemux->n_audio_streams);
7568 gst_pad_new_from_static_template (&gst_qtdemux_audiosrc_template, name);
7570 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
7571 gst_object_unref (stream->pad);
7576 qtdemux->n_audio_streams++;
7577 } else if (stream->subtype == FOURCC_strm) {
7578 GST_DEBUG_OBJECT (qtdemux, "stream type, not creating pad");
7579 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
7580 || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt) {
7581 gchar *name = g_strdup_printf ("subtitle_%u", qtdemux->n_sub_streams);
7584 gst_pad_new_from_static_template (&gst_qtdemux_subsrc_template, name);
7586 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
7587 gst_object_unref (stream->pad);
7592 qtdemux->n_sub_streams++;
7593 } else if (stream->caps) {
7594 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
7597 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
7599 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
7600 gst_object_unref (stream->pad);
7605 qtdemux->n_video_streams++;
7607 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
7614 GST_DEBUG_OBJECT (qtdemux, "adding pad %s %p to qtdemux %p",
7615 GST_OBJECT_NAME (stream->pad), stream->pad, qtdemux);
7616 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
7617 gst_flow_combiner_add_pad (qtdemux->flowcombiner, stream->pad);
7619 if (stream->pending_tags)
7620 gst_tag_list_unref (stream->pending_tags);
7621 stream->pending_tags = list;
7623 /* global tags go on each pad anyway */
7624 stream->send_global_tags = TRUE;
7625 /* send upstream GST_EVENT_PROTECTION events that were received before
7626 this source pad was created */
7627 for (l = qtdemux->protection_event_queue.head; l != NULL; l = l->next)
7628 gst_pad_push_event (stream->pad, gst_event_ref (l->data));
7632 gst_tag_list_unref (list);
7636 /* find next atom with @fourcc starting at @offset */
7637 static GstFlowReturn
7638 qtdemux_find_atom (GstQTDemux * qtdemux, guint64 * offset,
7639 guint64 * length, guint32 fourcc)
7645 GST_LOG_OBJECT (qtdemux, "finding fourcc %" GST_FOURCC_FORMAT " at offset %"
7646 G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), *offset);
7652 ret = gst_pad_pull_range (qtdemux->sinkpad, *offset, 16, &buf);
7653 if (G_UNLIKELY (ret != GST_FLOW_OK))
7655 if (G_UNLIKELY (gst_buffer_get_size (buf) != 16)) {
7658 gst_buffer_unref (buf);
7661 gst_buffer_map (buf, &map, GST_MAP_READ);
7662 extract_initial_length_and_fourcc (map.data, 16, length, &lfourcc);
7663 gst_buffer_unmap (buf, &map);
7664 gst_buffer_unref (buf);
7666 if (G_UNLIKELY (*length == 0)) {
7667 GST_DEBUG_OBJECT (qtdemux, "invalid length 0");
7668 ret = GST_FLOW_ERROR;
7672 if (lfourcc == fourcc) {
7673 GST_DEBUG_OBJECT (qtdemux, "found fourcc at offset %" G_GUINT64_FORMAT,
7677 GST_LOG_OBJECT (qtdemux,
7678 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
7679 GST_FOURCC_ARGS (fourcc), *offset);
7688 /* might simply have had last one */
7689 GST_DEBUG_OBJECT (qtdemux, "fourcc not found");
7694 /* should only do something in pull mode */
7695 /* call with OBJECT lock */
7696 static GstFlowReturn
7697 qtdemux_add_fragmented_samples (GstQTDemux * qtdemux)
7699 guint64 length, offset;
7700 GstBuffer *buf = NULL;
7701 GstFlowReturn ret = GST_FLOW_OK;
7702 GstFlowReturn res = GST_FLOW_OK;
7705 offset = qtdemux->moof_offset;
7706 GST_DEBUG_OBJECT (qtdemux, "next moof at offset %" G_GUINT64_FORMAT, offset);
7709 GST_DEBUG_OBJECT (qtdemux, "no next moof");
7710 return GST_FLOW_EOS;
7713 /* best not do pull etc with lock held */
7714 GST_OBJECT_UNLOCK (qtdemux);
7716 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
7717 if (ret != GST_FLOW_OK)
7720 ret = gst_qtdemux_pull_atom (qtdemux, offset, length, &buf);
7721 if (G_UNLIKELY (ret != GST_FLOW_OK))
7723 gst_buffer_map (buf, &map, GST_MAP_READ);
7724 if (!qtdemux_parse_moof (qtdemux, map.data, map.size, offset, NULL)) {
7725 gst_buffer_unmap (buf, &map);
7726 gst_buffer_unref (buf);
7731 gst_buffer_unmap (buf, &map);
7732 gst_buffer_unref (buf);
7736 /* look for next moof */
7737 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
7738 if (G_UNLIKELY (ret != GST_FLOW_OK))
7742 GST_OBJECT_LOCK (qtdemux);
7744 qtdemux->moof_offset = offset;
7750 GST_DEBUG_OBJECT (qtdemux, "failed to parse moof");
7752 res = GST_FLOW_ERROR;
7757 /* maybe upstream temporarily flushing */
7758 if (ret != GST_FLOW_FLUSHING) {
7759 GST_DEBUG_OBJECT (qtdemux, "no next moof");
7762 GST_DEBUG_OBJECT (qtdemux, "upstream WRONG_STATE");
7763 /* resume at current position next time */
7770 /* initialise bytereaders for stbl sub-atoms */
7772 qtdemux_stbl_init (GstQTDemux * qtdemux, QtDemuxStream * stream, GNode * stbl)
7774 stream->stbl_index = -1; /* no samples have yet been parsed */
7775 stream->sample_index = -1;
7777 /* time-to-sample atom */
7778 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stts, &stream->stts))
7781 /* copy atom data into a new buffer for later use */
7782 stream->stts.data = g_memdup (stream->stts.data, stream->stts.size);
7784 /* skip version + flags */
7785 if (!gst_byte_reader_skip (&stream->stts, 1 + 3) ||
7786 !gst_byte_reader_get_uint32_be (&stream->stts, &stream->n_sample_times))
7788 GST_LOG_OBJECT (qtdemux, "%u timestamp blocks", stream->n_sample_times);
7790 /* make sure there's enough data */
7791 if (!qt_atom_parser_has_chunks (&stream->stts, stream->n_sample_times, 8)) {
7792 stream->n_sample_times = gst_byte_reader_get_remaining (&stream->stts) / 8;
7793 GST_LOG_OBJECT (qtdemux, "overriding to %u timestamp blocks",
7794 stream->n_sample_times);
7795 if (!stream->n_sample_times)
7799 /* sync sample atom */
7800 stream->stps_present = FALSE;
7801 if ((stream->stss_present =
7802 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stss,
7803 &stream->stss) ? TRUE : FALSE) == TRUE) {
7804 /* copy atom data into a new buffer for later use */
7805 stream->stss.data = g_memdup (stream->stss.data, stream->stss.size);
7807 /* skip version + flags */
7808 if (!gst_byte_reader_skip (&stream->stss, 1 + 3) ||
7809 !gst_byte_reader_get_uint32_be (&stream->stss, &stream->n_sample_syncs))
7812 if (stream->n_sample_syncs) {
7813 /* make sure there's enough data */
7814 if (!qt_atom_parser_has_chunks (&stream->stss, stream->n_sample_syncs, 4))
7818 /* partial sync sample atom */
7819 if ((stream->stps_present =
7820 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stps,
7821 &stream->stps) ? TRUE : FALSE) == TRUE) {
7822 /* copy atom data into a new buffer for later use */
7823 stream->stps.data = g_memdup (stream->stps.data, stream->stps.size);
7825 /* skip version + flags */
7826 if (!gst_byte_reader_skip (&stream->stps, 1 + 3) ||
7827 !gst_byte_reader_get_uint32_be (&stream->stps,
7828 &stream->n_sample_partial_syncs))
7831 /* if there are no entries, the stss table contains the real
7833 if (stream->n_sample_partial_syncs) {
7834 /* make sure there's enough data */
7835 if (!qt_atom_parser_has_chunks (&stream->stps,
7836 stream->n_sample_partial_syncs, 4))
7843 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsz, &stream->stsz))
7846 /* copy atom data into a new buffer for later use */
7847 stream->stsz.data = g_memdup (stream->stsz.data, stream->stsz.size);
7849 /* skip version + flags */
7850 if (!gst_byte_reader_skip (&stream->stsz, 1 + 3) ||
7851 !gst_byte_reader_get_uint32_be (&stream->stsz, &stream->sample_size))
7854 if (!gst_byte_reader_get_uint32_be (&stream->stsz, &stream->n_samples))
7857 if (!stream->n_samples)
7860 /* sample-to-chunk atom */
7861 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsc, &stream->stsc))
7864 /* copy atom data into a new buffer for later use */
7865 stream->stsc.data = g_memdup (stream->stsc.data, stream->stsc.size);
7867 /* skip version + flags */
7868 if (!gst_byte_reader_skip (&stream->stsc, 1 + 3) ||
7869 !gst_byte_reader_get_uint32_be (&stream->stsc,
7870 &stream->n_samples_per_chunk))
7873 GST_DEBUG_OBJECT (qtdemux, "n_samples_per_chunk %u",
7874 stream->n_samples_per_chunk);
7876 /* make sure there's enough data */
7877 if (!qt_atom_parser_has_chunks (&stream->stsc, stream->n_samples_per_chunk,
7883 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stco, &stream->stco))
7884 stream->co_size = sizeof (guint32);
7885 else if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_co64,
7887 stream->co_size = sizeof (guint64);
7891 /* copy atom data into a new buffer for later use */
7892 stream->stco.data = g_memdup (stream->stco.data, stream->stco.size);
7894 /* skip version + flags */
7895 if (!gst_byte_reader_skip (&stream->stco, 1 + 3))
7898 /* chunks_are_samples == TRUE means treat chunks as samples */
7899 stream->chunks_are_samples = stream->sample_size && !stream->sampled;
7900 if (stream->chunks_are_samples) {
7901 /* treat chunks as samples */
7902 if (!gst_byte_reader_get_uint32_be (&stream->stco, &stream->n_samples))
7905 /* skip number of entries */
7906 if (!gst_byte_reader_skip (&stream->stco, 4))
7909 /* make sure there are enough data in the stsz atom */
7910 if (!stream->sample_size) {
7911 /* different sizes for each sample */
7912 if (!qt_atom_parser_has_chunks (&stream->stsz, stream->n_samples, 4))
7917 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
7918 stream->n_samples, (guint) sizeof (QtDemuxSample),
7919 stream->n_samples * sizeof (QtDemuxSample) / (1024.0 * 1024.0));
7921 if (stream->n_samples >=
7922 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample)) {
7923 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
7924 "be larger than %uMB (broken file?)", stream->n_samples,
7925 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
7929 g_assert (stream->samples == NULL);
7930 stream->samples = g_try_new0 (QtDemuxSample, stream->n_samples);
7931 if (!stream->samples) {
7932 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
7937 /* composition time-to-sample */
7938 if ((stream->ctts_present =
7939 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_ctts,
7940 &stream->ctts) ? TRUE : FALSE) == TRUE) {
7941 GstByteReader cslg = GST_BYTE_READER_INIT (NULL, 0);
7943 /* copy atom data into a new buffer for later use */
7944 stream->ctts.data = g_memdup (stream->ctts.data, stream->ctts.size);
7946 /* skip version + flags */
7947 if (!gst_byte_reader_skip (&stream->ctts, 1 + 3)
7948 || !gst_byte_reader_get_uint32_be (&stream->ctts,
7949 &stream->n_composition_times))
7952 /* make sure there's enough data */
7953 if (!qt_atom_parser_has_chunks (&stream->ctts, stream->n_composition_times,
7957 /* This is optional, if missing we iterate the ctts */
7958 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_cslg, &cslg)) {
7959 if (!gst_byte_reader_skip (&cslg, 1 + 3)
7960 || !gst_byte_reader_get_uint32_be (&cslg, &stream->cslg_shift)) {
7961 g_free ((gpointer) cslg.data);
7965 gint32 cslg_least = 0;
7966 guint num_entries, pos;
7969 pos = gst_byte_reader_get_pos (&stream->ctts);
7970 num_entries = stream->n_composition_times;
7972 stream->cslg_shift = 0;
7974 for (i = 0; i < num_entries; i++) {
7977 gst_byte_reader_skip_unchecked (&stream->ctts, 4);
7978 offset = gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
7980 if (offset < cslg_least)
7981 cslg_least = offset;
7985 stream->cslg_shift = ABS (cslg_least);
7987 stream->cslg_shift = 0;
7989 /* reset the reader so we can generate sample table */
7990 gst_byte_reader_set_pos (&stream->ctts, pos);
7993 /* Ensure the cslg_shift value is consistent so we can use it
7994 * unconditionnally to produce TS and Segment */
7995 stream->cslg_shift = 0;
8002 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8003 (_("This file is corrupt and cannot be played.")), (NULL));
8008 gst_qtdemux_stbl_free (stream);
8009 if (!qtdemux->fragmented) {
8010 /* not quite good */
8011 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
8014 /* may pick up samples elsewhere */
8020 /* collect samples from the next sample to be parsed up to sample @n for @stream
8021 * by reading the info from @stbl
8023 * This code can be executed from both the streaming thread and the seeking
8024 * thread so it takes the object lock to protect itself
8027 qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream, guint32 n)
8030 QtDemuxSample *samples, *first, *cur, *last;
8031 guint32 n_samples_per_chunk;
8034 GST_LOG_OBJECT (qtdemux, "parsing samples for stream fourcc %"
8035 GST_FOURCC_FORMAT ", pad %s", GST_FOURCC_ARGS (stream->fourcc),
8036 stream->pad ? GST_PAD_NAME (stream->pad) : "(NULL)");
8038 n_samples = stream->n_samples;
8041 goto out_of_samples;
8043 GST_OBJECT_LOCK (qtdemux);
8044 if (n <= stream->stbl_index)
8045 goto already_parsed;
8047 GST_DEBUG_OBJECT (qtdemux, "parsing up to sample %u", n);
8049 if (!stream->stsz.data) {
8050 /* so we already parsed and passed all the moov samples;
8051 * onto fragmented ones */
8052 g_assert (qtdemux->fragmented);
8056 /* pointer to the sample table */
8057 samples = stream->samples;
8059 /* starts from -1, moves to the next sample index to parse */
8060 stream->stbl_index++;
8062 /* keep track of the first and last sample to fill */
8063 first = &samples[stream->stbl_index];
8066 if (!stream->chunks_are_samples) {
8067 /* set the sample sizes */
8068 if (stream->sample_size == 0) {
8069 /* different sizes for each sample */
8070 for (cur = first; cur <= last; cur++) {
8071 cur->size = gst_byte_reader_get_uint32_be_unchecked (&stream->stsz);
8072 GST_LOG_OBJECT (qtdemux, "sample %d has size %u",
8073 (guint) (cur - samples), cur->size);
8076 /* samples have the same size */
8077 GST_LOG_OBJECT (qtdemux, "all samples have size %u", stream->sample_size);
8078 for (cur = first; cur <= last; cur++)
8079 cur->size = stream->sample_size;
8083 n_samples_per_chunk = stream->n_samples_per_chunk;
8086 for (i = stream->stsc_index; i < n_samples_per_chunk; i++) {
8089 if (stream->stsc_chunk_index >= stream->last_chunk
8090 || stream->stsc_chunk_index < stream->first_chunk) {
8091 stream->first_chunk =
8092 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
8093 stream->samples_per_chunk =
8094 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
8095 gst_byte_reader_skip_unchecked (&stream->stsc, 4);
8097 /* chunk numbers are counted from 1 it seems */
8098 if (G_UNLIKELY (stream->first_chunk == 0))
8101 --stream->first_chunk;
8103 /* the last chunk of each entry is calculated by taking the first chunk
8104 * of the next entry; except if there is no next, where we fake it with
8106 if (G_UNLIKELY (i == (stream->n_samples_per_chunk - 1))) {
8107 stream->last_chunk = G_MAXUINT32;
8109 stream->last_chunk =
8110 gst_byte_reader_peek_uint32_be_unchecked (&stream->stsc);
8111 if (G_UNLIKELY (stream->last_chunk == 0))
8114 --stream->last_chunk;
8117 GST_LOG_OBJECT (qtdemux,
8118 "entry %d has first_chunk %d, last_chunk %d, samples_per_chunk %d", i,
8119 stream->first_chunk, stream->last_chunk, stream->samples_per_chunk);
8121 if (G_UNLIKELY (stream->last_chunk < stream->first_chunk))
8124 if (stream->last_chunk != G_MAXUINT32) {
8125 if (!qt_atom_parser_peek_sub (&stream->stco,
8126 stream->first_chunk * stream->co_size,
8127 (stream->last_chunk - stream->first_chunk) * stream->co_size,
8132 stream->co_chunk = stream->stco;
8133 if (!gst_byte_reader_skip (&stream->co_chunk,
8134 stream->first_chunk * stream->co_size))
8138 stream->stsc_chunk_index = stream->first_chunk;
8141 last_chunk = stream->last_chunk;
8143 if (stream->chunks_are_samples) {
8144 cur = &samples[stream->stsc_chunk_index];
8146 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
8149 stream->stsc_chunk_index = j;
8154 qt_atom_parser_get_offset_unchecked (&stream->co_chunk,
8157 GST_LOG_OBJECT (qtdemux, "Created entry %d with offset "
8158 "%" G_GUINT64_FORMAT, j, cur->offset);
8160 if (stream->samples_per_frame * stream->bytes_per_frame) {
8162 (stream->samples_per_chunk * stream->n_channels) /
8163 stream->samples_per_frame * stream->bytes_per_frame;
8165 cur->size = stream->samples_per_chunk;
8168 GST_DEBUG_OBJECT (qtdemux,
8169 "keyframe sample %d: timestamp %" GST_TIME_FORMAT ", size %u",
8170 j, GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream,
8171 stream->stco_sample_index)), cur->size);
8173 cur->timestamp = stream->stco_sample_index;
8174 cur->duration = stream->samples_per_chunk;
8175 cur->keyframe = TRUE;
8178 stream->stco_sample_index += stream->samples_per_chunk;
8180 stream->stsc_chunk_index = j;
8182 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
8183 guint32 samples_per_chunk;
8184 guint64 chunk_offset;
8186 if (!stream->stsc_sample_index
8187 && !qt_atom_parser_get_offset (&stream->co_chunk, stream->co_size,
8188 &stream->chunk_offset))
8191 samples_per_chunk = stream->samples_per_chunk;
8192 chunk_offset = stream->chunk_offset;
8194 for (k = stream->stsc_sample_index; k < samples_per_chunk; k++) {
8195 GST_LOG_OBJECT (qtdemux, "creating entry %d with offset %"
8196 G_GUINT64_FORMAT " and size %d",
8197 (guint) (cur - samples), chunk_offset, cur->size);
8199 cur->offset = chunk_offset;
8200 chunk_offset += cur->size;
8203 if (G_UNLIKELY (cur > last)) {
8205 stream->stsc_sample_index = k + 1;
8206 stream->chunk_offset = chunk_offset;
8207 stream->stsc_chunk_index = j;
8211 stream->stsc_sample_index = 0;
8213 stream->stsc_chunk_index = j;
8215 stream->stsc_index++;
8218 if (stream->chunks_are_samples)
8222 guint32 n_sample_times;
8224 n_sample_times = stream->n_sample_times;
8227 for (i = stream->stts_index; i < n_sample_times; i++) {
8228 guint32 stts_samples;
8229 gint32 stts_duration;
8232 if (stream->stts_sample_index >= stream->stts_samples
8233 || !stream->stts_sample_index) {
8235 stream->stts_samples =
8236 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
8237 stream->stts_duration =
8238 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
8240 GST_LOG_OBJECT (qtdemux, "block %d, %u timestamps, duration %u",
8241 i, stream->stts_samples, stream->stts_duration);
8243 stream->stts_sample_index = 0;
8246 stts_samples = stream->stts_samples;
8247 stts_duration = stream->stts_duration;
8248 stts_time = stream->stts_time;
8250 for (j = stream->stts_sample_index; j < stts_samples; j++) {
8251 GST_DEBUG_OBJECT (qtdemux,
8252 "sample %d: index %d, timestamp %" GST_TIME_FORMAT,
8253 (guint) (cur - samples), j,
8254 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stts_time)));
8256 cur->timestamp = stts_time;
8257 cur->duration = stts_duration;
8259 /* avoid 32-bit wrap-around,
8260 * but still mind possible 'negative' duration */
8261 stts_time += (gint64) stts_duration;
8264 if (G_UNLIKELY (cur > last)) {
8266 stream->stts_time = stts_time;
8267 stream->stts_sample_index = j + 1;
8271 stream->stts_sample_index = 0;
8272 stream->stts_time = stts_time;
8273 stream->stts_index++;
8275 /* fill up empty timestamps with the last timestamp, this can happen when
8276 * the last samples do not decode and so we don't have timestamps for them.
8277 * We however look at the last timestamp to estimate the track length so we
8278 * need something in here. */
8279 for (; cur < last; cur++) {
8280 GST_DEBUG_OBJECT (qtdemux,
8281 "fill sample %d: timestamp %" GST_TIME_FORMAT,
8282 (guint) (cur - samples),
8283 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stream->stts_time)));
8284 cur->timestamp = stream->stts_time;
8290 /* sample sync, can be NULL */
8291 if (stream->stss_present == TRUE) {
8292 guint32 n_sample_syncs;
8294 n_sample_syncs = stream->n_sample_syncs;
8296 if (!n_sample_syncs) {
8297 GST_DEBUG_OBJECT (qtdemux, "all samples are keyframes");
8298 stream->all_keyframe = TRUE;
8300 for (i = stream->stss_index; i < n_sample_syncs; i++) {
8301 /* note that the first sample is index 1, not 0 */
8304 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stss);
8306 if (G_LIKELY (index > 0 && index <= n_samples)) {
8308 samples[index].keyframe = TRUE;
8309 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
8310 /* and exit if we have enough samples */
8311 if (G_UNLIKELY (index >= n)) {
8318 stream->stss_index = i;
8321 /* stps marks partial sync frames like open GOP I-Frames */
8322 if (stream->stps_present == TRUE) {
8323 guint32 n_sample_partial_syncs;
8325 n_sample_partial_syncs = stream->n_sample_partial_syncs;
8327 /* if there are no entries, the stss table contains the real
8329 if (n_sample_partial_syncs) {
8330 for (i = stream->stps_index; i < n_sample_partial_syncs; i++) {
8331 /* note that the first sample is index 1, not 0 */
8334 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stps);
8336 if (G_LIKELY (index > 0 && index <= n_samples)) {
8338 samples[index].keyframe = TRUE;
8339 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
8340 /* and exit if we have enough samples */
8341 if (G_UNLIKELY (index >= n)) {
8348 stream->stps_index = i;
8352 /* no stss, all samples are keyframes */
8353 stream->all_keyframe = TRUE;
8354 GST_DEBUG_OBJECT (qtdemux, "setting all keyframes");
8359 /* composition time to sample */
8360 if (stream->ctts_present == TRUE) {
8361 guint32 n_composition_times;
8363 gint32 ctts_soffset;
8365 /* Fill in the pts_offsets */
8367 n_composition_times = stream->n_composition_times;
8369 for (i = stream->ctts_index; i < n_composition_times; i++) {
8370 if (stream->ctts_sample_index >= stream->ctts_count
8371 || !stream->ctts_sample_index) {
8372 stream->ctts_count =
8373 gst_byte_reader_get_uint32_be_unchecked (&stream->ctts);
8374 stream->ctts_soffset =
8375 gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
8376 stream->ctts_sample_index = 0;
8379 ctts_count = stream->ctts_count;
8380 ctts_soffset = stream->ctts_soffset;
8382 for (j = stream->ctts_sample_index; j < ctts_count; j++) {
8383 cur->pts_offset = ctts_soffset;
8386 if (G_UNLIKELY (cur > last)) {
8388 stream->ctts_sample_index = j + 1;
8392 stream->ctts_sample_index = 0;
8393 stream->ctts_index++;
8397 stream->stbl_index = n;
8398 /* if index has been completely parsed, free data that is no-longer needed */
8399 if (n + 1 == stream->n_samples) {
8400 gst_qtdemux_stbl_free (stream);
8401 GST_DEBUG_OBJECT (qtdemux, "parsed all available samples;");
8402 if (qtdemux->pullbased) {
8403 GST_DEBUG_OBJECT (qtdemux, "checking for more samples");
8404 while (n + 1 == stream->n_samples)
8405 if (qtdemux_add_fragmented_samples (qtdemux) != GST_FLOW_OK)
8409 GST_OBJECT_UNLOCK (qtdemux);
8416 GST_LOG_OBJECT (qtdemux,
8417 "Tried to parse up to sample %u but this sample has already been parsed",
8419 /* if fragmented, there may be more */
8420 if (qtdemux->fragmented && n == stream->stbl_index)
8422 GST_OBJECT_UNLOCK (qtdemux);
8428 GST_LOG_OBJECT (qtdemux,
8429 "Tried to parse up to sample %u but there are only %u samples", n + 1,
8431 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8432 (_("This file is corrupt and cannot be played.")), (NULL));
8437 GST_OBJECT_UNLOCK (qtdemux);
8438 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8439 (_("This file is corrupt and cannot be played.")), (NULL));
8444 /* collect all segment info for @stream.
8447 qtdemux_parse_segments (GstQTDemux * qtdemux, QtDemuxStream * stream,
8451 /* accept edts if they contain gaps at start and there is only
8452 * one media segment */
8453 gboolean allow_pushbased_edts = TRUE;
8454 gint media_segments_count = 0;
8456 /* parse and prepare segment info from the edit list */
8457 GST_DEBUG_OBJECT (qtdemux, "looking for edit list container");
8458 stream->n_segments = 0;
8459 stream->segments = NULL;
8460 if ((edts = qtdemux_tree_get_child_by_type (trak, FOURCC_edts))) {
8463 gint i, count, entry_size;
8469 GST_DEBUG_OBJECT (qtdemux, "looking for edit list");
8470 if (!(elst = qtdemux_tree_get_child_by_type (edts, FOURCC_elst)))
8473 buffer = elst->data;
8475 version = QT_UINT8 (buffer + 8);
8476 entry_size = (version == 1) ? 20 : 12;
8478 n_segments = QT_UINT32 (buffer + 12);
8480 /* we might allocate a bit too much, at least allocate 1 segment */
8481 stream->segments = g_new (QtDemuxSegment, MAX (n_segments, 1));
8483 /* segments always start from 0 */
8487 for (i = 0; i < n_segments; i++) {
8490 gboolean time_valid = TRUE;
8491 QtDemuxSegment *segment;
8493 GstClockTime media_start = GST_CLOCK_TIME_NONE;
8496 media_time = QT_UINT64 (buffer + 24 + i * entry_size);
8497 duration = QT_UINT64 (buffer + 16 + i * entry_size);
8498 if (media_time == G_MAXUINT64)
8501 media_time = QT_UINT32 (buffer + 20 + i * entry_size);
8502 duration = QT_UINT32 (buffer + 16 + i * entry_size);
8503 if (media_time == G_MAXUINT32)
8508 media_start = QTSTREAMTIME_TO_GSTTIME (stream, media_time);
8510 segment = &stream->segments[count++];
8512 /* time and duration expressed in global timescale */
8513 segment->time = stime;
8514 /* add non scaled values so we don't cause roundoff errors */
8515 if (duration || media_start == GST_CLOCK_TIME_NONE) {
8517 stime = QTTIME_TO_GSTTIME (qtdemux, time);
8518 segment->duration = stime - segment->time;
8520 /* zero duration does not imply media_start == media_stop
8521 * but, only specify media_start.*/
8522 stime = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
8523 if (GST_CLOCK_TIME_IS_VALID (stime) && time_valid
8524 && stime >= media_start) {
8525 segment->duration = stime - media_start;
8527 segment->duration = GST_CLOCK_TIME_NONE;
8530 segment->stop_time = stime;
8532 segment->trak_media_start = media_time;
8533 /* media_time expressed in stream timescale */
8535 segment->media_start = media_start;
8536 segment->media_stop = segment->media_start + segment->duration;
8537 media_segments_count++;
8539 segment->media_start = GST_CLOCK_TIME_NONE;
8540 segment->media_stop = GST_CLOCK_TIME_NONE;
8543 QT_UINT32 (buffer + ((version == 1) ? 32 : 24) + i * entry_size);
8545 if (rate_int <= 1) {
8546 /* 0 is not allowed, some programs write 1 instead of the floating point
8548 GST_WARNING_OBJECT (qtdemux, "found suspicious rate %" G_GUINT32_FORMAT,
8552 segment->rate = rate_int / 65536.0;
8555 GST_DEBUG_OBJECT (qtdemux, "created segment %d time %" GST_TIME_FORMAT
8556 ", duration %" GST_TIME_FORMAT ", media_start %" GST_TIME_FORMAT
8557 " (%" G_GUINT64_FORMAT ") , media_stop %" GST_TIME_FORMAT
8558 " stop_time %" GST_TIME_FORMAT " rate %g, (%d) timescale %u",
8559 i, GST_TIME_ARGS (segment->time),
8560 GST_TIME_ARGS (segment->duration),
8561 GST_TIME_ARGS (segment->media_start), media_time,
8562 GST_TIME_ARGS (segment->media_stop),
8563 GST_TIME_ARGS (segment->stop_time), segment->rate, rate_int,
8565 if (segment->stop_time > qtdemux->segment.stop) {
8566 GST_WARNING_OBJECT (qtdemux, "Segment %d "
8567 " extends to %" GST_TIME_FORMAT
8568 " past the end of the file duration %" GST_TIME_FORMAT
8569 " it will be truncated", i, GST_TIME_ARGS (segment->stop_time),
8570 GST_TIME_ARGS (qtdemux->segment.stop));
8571 qtdemux->segment.stop = segment->stop_time;
8574 GST_DEBUG_OBJECT (qtdemux, "found %d segments", count);
8575 stream->n_segments = count;
8576 if (media_segments_count != 1)
8577 allow_pushbased_edts = FALSE;
8581 /* push based does not handle segments, so act accordingly here,
8582 * and warn if applicable */
8583 if (!qtdemux->pullbased && !allow_pushbased_edts) {
8584 GST_WARNING_OBJECT (qtdemux, "streaming; discarding edit list segments");
8585 /* remove and use default one below, we stream like it anyway */
8586 g_free (stream->segments);
8587 stream->segments = NULL;
8588 stream->n_segments = 0;
8591 /* no segments, create one to play the complete trak */
8592 if (stream->n_segments == 0) {
8593 GstClockTime stream_duration =
8594 QTSTREAMTIME_TO_GSTTIME (stream, stream->duration);
8596 if (stream->segments == NULL)
8597 stream->segments = g_new (QtDemuxSegment, 1);
8599 /* represent unknown our way */
8600 if (stream_duration == 0)
8601 stream_duration = GST_CLOCK_TIME_NONE;
8603 stream->segments[0].time = 0;
8604 stream->segments[0].stop_time = stream_duration;
8605 stream->segments[0].duration = stream_duration;
8606 stream->segments[0].media_start = 0;
8607 stream->segments[0].media_stop = stream_duration;
8608 stream->segments[0].rate = 1.0;
8609 stream->segments[0].trak_media_start = 0;
8611 GST_DEBUG_OBJECT (qtdemux, "created dummy segment %" GST_TIME_FORMAT,
8612 GST_TIME_ARGS (stream_duration));
8613 stream->n_segments = 1;
8614 stream->dummy_segment = TRUE;
8616 GST_DEBUG_OBJECT (qtdemux, "using %d segments", stream->n_segments);
8622 * Parses the stsd atom of a svq3 trak looking for
8623 * the SMI and gama atoms.
8626 qtdemux_parse_svq3_stsd_data (GstQTDemux * qtdemux, GNode * stsd,
8627 guint8 ** gamma, GstBuffer ** seqh)
8629 guint8 *_gamma = NULL;
8630 GstBuffer *_seqh = NULL;
8631 guint8 *stsd_data = stsd->data;
8632 guint32 length = QT_UINT32 (stsd_data);
8636 GST_WARNING_OBJECT (qtdemux, "stsd too short");
8642 version = QT_UINT16 (stsd_data);
8647 while (length > 8) {
8648 guint32 fourcc, size;
8650 size = QT_UINT32 (stsd_data);
8651 fourcc = QT_FOURCC (stsd_data + 4);
8652 data = stsd_data + 8;
8655 GST_WARNING_OBJECT (qtdemux, "Atom of size 0 found, aborting "
8656 "svq3 atom parsing");
8665 GST_WARNING_OBJECT (qtdemux, "Unexpected size %" G_GUINT32_FORMAT
8666 " for gama atom, expected 12", size);
8671 if (size > 16 && QT_FOURCC (data) == FOURCC_SEQH) {
8673 if (_seqh != NULL) {
8674 GST_WARNING_OBJECT (qtdemux, "Unexpected second SEQH SMI atom "
8675 " found, ignoring");
8677 seqh_size = QT_UINT32 (data + 4);
8678 if (seqh_size > 0) {
8679 _seqh = gst_buffer_new_and_alloc (seqh_size);
8680 gst_buffer_fill (_seqh, 0, data + 8, seqh_size);
8687 GST_WARNING_OBJECT (qtdemux, "Unhandled atom %" GST_FOURCC_FORMAT
8688 " in SVQ3 entry in stsd atom", GST_FOURCC_ARGS (fourcc));
8692 if (size <= length) {
8698 GST_WARNING_OBJECT (qtdemux, "SVQ3 entry too short in stsd atom");
8701 GST_WARNING_OBJECT (qtdemux, "Unexpected version for SVQ3 entry %"
8702 G_GUINT16_FORMAT, version);
8713 gst_buffer_unref (_seqh);
8718 qtdemux_get_rtsp_uri_from_hndl (GstQTDemux * qtdemux, GNode * minf)
8725 * Get 'dinf', to get its child 'dref', that might contain a 'hndl'
8726 * atom that might contain a 'data' atom with the rtsp uri.
8727 * This case was reported in bug #597497, some info about
8728 * the hndl atom can be found in TN1195
8730 dinf = qtdemux_tree_get_child_by_type (minf, FOURCC_dinf);
8731 GST_DEBUG_OBJECT (qtdemux, "Trying to obtain rtsp URI for stream trak");
8734 guint32 dref_num_entries = 0;
8735 if (qtdemux_tree_get_child_by_type_full (dinf, FOURCC_dref, &dref) &&
8736 gst_byte_reader_skip (&dref, 4) &&
8737 gst_byte_reader_get_uint32_be (&dref, &dref_num_entries)) {
8740 /* search dref entries for hndl atom */
8741 for (i = 0; i < dref_num_entries; i++) {
8742 guint32 size = 0, type;
8743 guint8 string_len = 0;
8744 if (gst_byte_reader_get_uint32_be (&dref, &size) &&
8745 qt_atom_parser_get_fourcc (&dref, &type)) {
8746 if (type == FOURCC_hndl) {
8747 GST_DEBUG_OBJECT (qtdemux, "Found hndl atom");
8749 /* skip data reference handle bytes and the
8750 * following pascal string and some extra 4
8751 * bytes I have no idea what are */
8752 if (!gst_byte_reader_skip (&dref, 4) ||
8753 !gst_byte_reader_get_uint8 (&dref, &string_len) ||
8754 !gst_byte_reader_skip (&dref, string_len + 4)) {
8755 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl atom");
8759 /* iterate over the atoms to find the data atom */
8760 while (gst_byte_reader_get_remaining (&dref) >= 8) {
8764 if (gst_byte_reader_get_uint32_be (&dref, &atom_size) &&
8765 qt_atom_parser_get_fourcc (&dref, &atom_type)) {
8766 if (atom_type == FOURCC_data) {
8767 const guint8 *uri_aux = NULL;
8769 /* found the data atom that might contain the rtsp uri */
8770 GST_DEBUG_OBJECT (qtdemux, "Found data atom inside "
8771 "hndl atom, interpreting it as an URI");
8772 if (gst_byte_reader_peek_data (&dref, atom_size - 8,
8774 if (g_strstr_len ((gchar *) uri_aux, 7, "rtsp://") != NULL)
8775 uri = g_strndup ((gchar *) uri_aux, atom_size - 8);
8777 GST_WARNING_OBJECT (qtdemux, "Data atom in hndl atom "
8778 "didn't contain a rtsp address");
8780 GST_WARNING_OBJECT (qtdemux, "Failed to get the data "
8785 /* skipping to the next entry */
8786 if (!gst_byte_reader_skip (&dref, atom_size - 8))
8789 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl child "
8796 /* skip to the next entry */
8797 if (!gst_byte_reader_skip (&dref, size - 8))
8800 GST_WARNING_OBJECT (qtdemux, "Error parsing dref atom");
8803 GST_DEBUG_OBJECT (qtdemux, "Finished parsing dref atom");
8809 #define AMR_NB_ALL_MODES 0x81ff
8810 #define AMR_WB_ALL_MODES 0x83ff
8812 qtdemux_parse_amr_bitrate (GstBuffer * buf, gboolean wb)
8814 /* The 'damr' atom is of the form:
8816 * | vendor | decoder_ver | mode_set | mode_change_period | frames/sample |
8817 * 32 b 8 b 16 b 8 b 8 b
8819 * The highest set bit of the first 7 (AMR-NB) or 8 (AMR-WB) bits of mode_set
8820 * represents the highest mode used in the stream (and thus the maximum
8821 * bitrate), with a couple of special cases as seen below.
8824 /* Map of frame type ID -> bitrate */
8825 static const guint nb_bitrates[] = {
8826 4750, 5150, 5900, 6700, 7400, 7950, 10200, 12200
8828 static const guint wb_bitrates[] = {
8829 6600, 8850, 12650, 14250, 15850, 18250, 19850, 23050, 23850
8835 gst_buffer_map (buf, &map, GST_MAP_READ);
8837 if (map.size != 0x11) {
8838 GST_DEBUG ("Atom should have size 0x11, not %" G_GSIZE_FORMAT, map.size);
8842 if (QT_FOURCC (map.data + 4) != FOURCC_damr) {
8843 GST_DEBUG ("Unknown atom in %" GST_FOURCC_FORMAT,
8844 GST_FOURCC_ARGS (QT_UINT32 (map.data + 4)));
8848 mode_set = QT_UINT16 (map.data + 13);
8850 if (mode_set == (wb ? AMR_WB_ALL_MODES : AMR_NB_ALL_MODES))
8851 max_mode = 7 + (wb ? 1 : 0);
8853 /* AMR-NB modes fo from 0-7, and AMR-WB modes go from 0-8 */
8854 max_mode = g_bit_nth_msf ((gulong) mode_set & (wb ? 0x1ff : 0xff), -1);
8856 if (max_mode == -1) {
8857 GST_DEBUG ("No mode indication was found (mode set) = %x",
8862 gst_buffer_unmap (buf, &map);
8863 return wb ? wb_bitrates[max_mode] : nb_bitrates[max_mode];
8866 gst_buffer_unmap (buf, &map);
8871 qtdemux_parse_transformation_matrix (GstQTDemux * qtdemux,
8872 GstByteReader * reader, guint32 * matrix, const gchar * atom)
8875 * 9 values of 32 bits (fixed point 16.16, except 2 5 and 8 that are 2.30)
8881 if (gst_byte_reader_get_remaining (reader) < 36)
8884 matrix[0] = gst_byte_reader_get_uint32_be_unchecked (reader);
8885 matrix[1] = gst_byte_reader_get_uint32_be_unchecked (reader);
8886 matrix[2] = gst_byte_reader_get_uint32_be_unchecked (reader);
8887 matrix[3] = gst_byte_reader_get_uint32_be_unchecked (reader);
8888 matrix[4] = gst_byte_reader_get_uint32_be_unchecked (reader);
8889 matrix[5] = gst_byte_reader_get_uint32_be_unchecked (reader);
8890 matrix[6] = gst_byte_reader_get_uint32_be_unchecked (reader);
8891 matrix[7] = gst_byte_reader_get_uint32_be_unchecked (reader);
8892 matrix[8] = gst_byte_reader_get_uint32_be_unchecked (reader);
8894 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix from atom %s", atom);
8895 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[0] >> 16,
8896 matrix[0] & 0xFFFF, matrix[1] >> 16, matrix[1] & 0xFF, matrix[2] >> 16,
8898 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[3] >> 16,
8899 matrix[3] & 0xFFFF, matrix[4] >> 16, matrix[4] & 0xFF, matrix[5] >> 16,
8901 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[6] >> 16,
8902 matrix[6] & 0xFFFF, matrix[7] >> 16, matrix[7] & 0xFF, matrix[8] >> 16,
8909 qtdemux_inspect_transformation_matrix (GstQTDemux * qtdemux,
8910 QtDemuxStream * stream, guint32 * matrix, GstTagList ** taglist)
8917 * This macro will only compare value abdegh, it expects cfi to have already
8920 #define QTCHECK_MATRIX(m,a,b,d,e) ((m)[0] == (a << 16) && (m)[1] == (b << 16) && \
8921 (m)[3] == (d << 16) && (m)[4] == (e << 16))
8923 /* only handle the cases where the last column has standard values */
8924 if (matrix[2] == 0 && matrix[5] == 0 && matrix[8] == 1 << 30) {
8925 const gchar *rotation_tag = NULL;
8927 /* no rotation needed */
8928 if (QTCHECK_MATRIX (matrix, 1, 0, 0, 1)) {
8930 } else if (QTCHECK_MATRIX (matrix, 0, 1, G_MAXUINT16, 0)) {
8931 rotation_tag = "rotate-90";
8932 } else if (QTCHECK_MATRIX (matrix, G_MAXUINT16, 0, 0, G_MAXUINT16)) {
8933 rotation_tag = "rotate-180";
8934 } else if (QTCHECK_MATRIX (matrix, 0, G_MAXUINT16, 1, 0)) {
8935 rotation_tag = "rotate-270";
8937 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
8940 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix rotation %s",
8942 if (rotation_tag != NULL) {
8943 if (*taglist == NULL)
8944 *taglist = gst_tag_list_new_empty ();
8945 gst_tag_list_add (*taglist, GST_TAG_MERGE_REPLACE,
8946 GST_TAG_IMAGE_ORIENTATION, rotation_tag, NULL);
8949 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
8953 /* Parses the boxes defined in ISO/IEC 14496-12 that enable support for
8954 * protected streams (sinf, frma, schm and schi); if the protection scheme is
8955 * Common Encryption (cenc), the function will also parse the tenc box (defined
8956 * in ISO/IEC 23001-7). @container points to the node that contains these boxes
8957 * (typically an enc[v|a|t|s] sample entry); the function will set
8958 * @original_fmt to the fourcc of the original unencrypted stream format.
8959 * Returns TRUE if successful; FALSE otherwise. */
8961 qtdemux_parse_protection_scheme_info (GstQTDemux * qtdemux,
8962 QtDemuxStream * stream, GNode * container, guint32 * original_fmt)
8969 g_return_val_if_fail (qtdemux != NULL, FALSE);
8970 g_return_val_if_fail (stream != NULL, FALSE);
8971 g_return_val_if_fail (container != NULL, FALSE);
8972 g_return_val_if_fail (original_fmt != NULL, FALSE);
8974 sinf = qtdemux_tree_get_child_by_type (container, FOURCC_sinf);
8975 if (G_UNLIKELY (!sinf)) {
8976 if (stream->protection_scheme_type == FOURCC_cenc) {
8977 GST_ERROR_OBJECT (qtdemux, "sinf box does not contain schi box, which is "
8978 "mandatory for Common Encryption");
8984 frma = qtdemux_tree_get_child_by_type (sinf, FOURCC_frma);
8985 if (G_UNLIKELY (!frma)) {
8986 GST_ERROR_OBJECT (qtdemux, "sinf box does not contain mandatory frma box");
8990 *original_fmt = QT_FOURCC ((const guint8 *) frma->data + 8);
8991 GST_DEBUG_OBJECT (qtdemux, "original stream format: '%" GST_FOURCC_FORMAT "'",
8992 GST_FOURCC_ARGS (*original_fmt));
8994 schm = qtdemux_tree_get_child_by_type (sinf, FOURCC_schm);
8996 GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schm box");
8999 stream->protection_scheme_type = QT_FOURCC ((const guint8 *) schm->data + 12);
9000 stream->protection_scheme_version =
9001 QT_UINT32 ((const guint8 *) schm->data + 16);
9003 GST_DEBUG_OBJECT (qtdemux,
9004 "protection_scheme_type: %" GST_FOURCC_FORMAT ", "
9005 "protection_scheme_version: %#010x",
9006 GST_FOURCC_ARGS (stream->protection_scheme_type),
9007 stream->protection_scheme_version);
9009 schi = qtdemux_tree_get_child_by_type (sinf, FOURCC_schi);
9011 GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schi box");
9014 if (stream->protection_scheme_type == FOURCC_cenc) {
9015 QtDemuxCencSampleSetInfo *info;
9017 const guint8 *tenc_data;
9018 guint32 isEncrypted;
9020 const guint8 *default_kid;
9023 if (G_UNLIKELY (!stream->protection_scheme_info))
9024 stream->protection_scheme_info =
9025 g_malloc0 (sizeof (QtDemuxCencSampleSetInfo));
9027 info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
9029 tenc = qtdemux_tree_get_child_by_type (schi, FOURCC_tenc);
9031 GST_ERROR_OBJECT (qtdemux, "schi box does not contain tenc box, "
9032 "which is mandatory for Common Encryption");
9035 tenc_data = (const guint8 *) tenc->data + 12;
9036 isEncrypted = QT_UINT24 (tenc_data);
9037 iv_size = QT_UINT8 (tenc_data + 3);
9038 default_kid = (tenc_data + 4);
9039 kid_buf = gst_buffer_new_allocate (NULL, 16, NULL);
9040 gst_buffer_fill (kid_buf, 0, default_kid, 16);
9041 if (info->default_properties)
9042 gst_structure_free (info->default_properties);
9043 info->default_properties =
9044 gst_structure_new ("application/x-cenc",
9045 "iv_size", G_TYPE_UINT, iv_size,
9046 "encrypted", G_TYPE_BOOLEAN, (isEncrypted == 1),
9047 "kid", GST_TYPE_BUFFER, kid_buf, NULL);
9048 GST_DEBUG_OBJECT (qtdemux, "default sample properties: "
9049 "is_encrypted=%u, iv_size=%u", isEncrypted, iv_size);
9050 gst_buffer_unref (kid_buf);
9056 * With each track we associate a new QtDemuxStream that contains all the info
9058 * traks that do not decode to something (like strm traks) will not have a pad.
9061 qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
9080 QtDemuxStream *stream = NULL;
9081 gboolean new_stream = FALSE;
9082 gchar *codec = NULL;
9083 const guint8 *stsd_data;
9084 guint16 lang_code; /* quicktime lang code or packed iso code */
9086 guint32 tkhd_flags = 0;
9087 guint8 tkhd_version = 0;
9089 guint value_size, stsd_len, len;
9093 GST_DEBUG_OBJECT (qtdemux, "parse_trak");
9095 if (!qtdemux_tree_get_child_by_type_full (trak, FOURCC_tkhd, &tkhd)
9096 || !gst_byte_reader_get_uint8 (&tkhd, &tkhd_version)
9097 || !gst_byte_reader_get_uint24_be (&tkhd, &tkhd_flags))
9100 /* pick between 64 or 32 bits */
9101 value_size = tkhd_version == 1 ? 8 : 4;
9102 if (!gst_byte_reader_skip (&tkhd, value_size * 2) ||
9103 !gst_byte_reader_get_uint32_be (&tkhd, &track_id))
9106 if (!qtdemux->got_moov) {
9107 if (qtdemux_find_stream (qtdemux, track_id))
9108 goto existing_stream;
9109 stream = _create_stream ();
9110 stream->track_id = track_id;
9113 stream = qtdemux_find_stream (qtdemux, track_id);
9115 GST_WARNING_OBJECT (qtdemux, "Stream not found, going to ignore it");
9119 /* flush samples data from this track from previous moov */
9120 gst_qtdemux_stream_flush_segments_data (qtdemux, stream);
9121 gst_qtdemux_stream_flush_samples_data (qtdemux, stream);
9123 /* need defaults for fragments */
9124 qtdemux_parse_trex (qtdemux, stream, &dummy, &dummy, &dummy);
9126 if (stream->pending_tags == NULL)
9127 stream->pending_tags = gst_tag_list_new_empty ();
9129 if ((tkhd_flags & 1) == 0)
9130 stream->disabled = TRUE;
9132 GST_LOG_OBJECT (qtdemux, "track[tkhd] version/flags/id: 0x%02x/%06x/%u",
9133 tkhd_version, tkhd_flags, stream->track_id);
9135 if (!(mdia = qtdemux_tree_get_child_by_type (trak, FOURCC_mdia)))
9138 if (!(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mdhd))) {
9139 /* be nice for some crooked mjp2 files that use mhdr for mdhd */
9140 if (qtdemux->major_brand != FOURCC_mjp2 ||
9141 !(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mhdr)))
9145 len = QT_UINT32 ((guint8 *) mdhd->data);
9146 version = QT_UINT32 ((guint8 *) mdhd->data + 8);
9147 GST_LOG_OBJECT (qtdemux, "track version/flags: %08x", version);
9148 if (version == 0x01000000) {
9151 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 28);
9152 stream->duration = QT_UINT64 ((guint8 *) mdhd->data + 32);
9153 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 36);
9157 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 20);
9158 stream->duration = QT_UINT32 ((guint8 *) mdhd->data + 24);
9159 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 28);
9162 if (lang_code < 0x400) {
9163 qtdemux_lang_map_qt_code_to_iso (stream->lang_id, lang_code);
9164 } else if (lang_code == 0x7fff) {
9165 stream->lang_id[0] = 0; /* unspecified */
9167 stream->lang_id[0] = 0x60 + ((lang_code >> 10) & 0x1F);
9168 stream->lang_id[1] = 0x60 + ((lang_code >> 5) & 0x1F);
9169 stream->lang_id[2] = 0x60 + (lang_code & 0x1F);
9170 stream->lang_id[3] = 0;
9173 GST_LOG_OBJECT (qtdemux, "track timescale: %" G_GUINT32_FORMAT,
9175 GST_LOG_OBJECT (qtdemux, "track duration: %" G_GUINT64_FORMAT,
9177 GST_LOG_OBJECT (qtdemux, "track language code/id: 0x%04x/%s",
9178 lang_code, stream->lang_id);
9180 if (G_UNLIKELY (stream->timescale == 0 || qtdemux->timescale == 0))
9183 if ((tref = qtdemux_tree_get_child_by_type (trak, FOURCC_tref))) {
9184 /* chapters track reference */
9185 GNode *chap = qtdemux_tree_get_child_by_type (tref, FOURCC_chap);
9187 gsize length = GST_READ_UINT32_BE (chap->data);
9188 if (qtdemux->chapters_track_id)
9189 GST_FIXME_OBJECT (qtdemux, "Multiple CHAP tracks");
9192 qtdemux->chapters_track_id =
9193 GST_READ_UINT32_BE ((gint8 *) chap->data + 8);
9198 /* fragmented files may have bogus duration in moov */
9199 if (!qtdemux->fragmented &&
9200 qtdemux->duration != G_MAXINT64 && stream->duration != G_MAXINT32) {
9201 guint64 tdur1, tdur2;
9203 /* don't overflow */
9204 tdur1 = stream->timescale * (guint64) qtdemux->duration;
9205 tdur2 = qtdemux->timescale * (guint64) stream->duration;
9208 * some of those trailers, nowadays, have prologue images that are
9209 * themselves video tracks as well. I haven't really found a way to
9210 * identify those yet, except for just looking at their duration. */
9211 if (tdur1 != 0 && (tdur2 * 10 / tdur1) < 2) {
9212 GST_WARNING_OBJECT (qtdemux,
9213 "Track shorter than 20%% (%" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT
9214 " vs. %" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT ") of the stream "
9215 "found, assuming preview image or something; skipping track",
9216 stream->duration, stream->timescale, qtdemux->duration,
9217 qtdemux->timescale);
9219 gst_qtdemux_stream_free (qtdemux, stream);
9224 if (!(hdlr = qtdemux_tree_get_child_by_type (mdia, FOURCC_hdlr)))
9227 GST_LOG_OBJECT (qtdemux, "track type: %" GST_FOURCC_FORMAT,
9228 GST_FOURCC_ARGS (QT_FOURCC ((guint8 *) hdlr->data + 12)));
9230 len = QT_UINT32 ((guint8 *) hdlr->data);
9232 stream->subtype = QT_FOURCC ((guint8 *) hdlr->data + 16);
9233 GST_LOG_OBJECT (qtdemux, "track subtype: %" GST_FOURCC_FORMAT,
9234 GST_FOURCC_ARGS (stream->subtype));
9236 if (!(minf = qtdemux_tree_get_child_by_type (mdia, FOURCC_minf)))
9239 if (!(stbl = qtdemux_tree_get_child_by_type (minf, FOURCC_stbl)))
9242 /*parse svmi header if existing */
9243 svmi = qtdemux_tree_get_child_by_type (stbl, FOURCC_svmi);
9245 len = QT_UINT32 ((guint8 *) svmi->data);
9246 version = QT_UINT32 ((guint8 *) svmi->data + 8);
9248 GstVideoMultiviewMode mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
9249 GstVideoMultiviewFlags flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
9250 guint8 frame_type, frame_layout;
9252 /* MPEG-A stereo video */
9253 if (qtdemux->major_brand == FOURCC_ss02)
9254 flags |= GST_VIDEO_MULTIVIEW_FLAGS_MIXED_MONO;
9256 frame_type = QT_UINT8 ((guint8 *) svmi->data + 12);
9257 frame_layout = QT_UINT8 ((guint8 *) svmi->data + 13) & 0x01;
9258 switch (frame_type) {
9260 mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
9263 mode = GST_VIDEO_MULTIVIEW_MODE_ROW_INTERLEAVED;
9266 mode = GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME;
9269 /* mode 3 is primary/secondary view sequence, ie
9270 * left/right views in separate tracks. See section 7.2
9271 * of ISO/IEC 23000-11:2009 */
9272 GST_FIXME_OBJECT (qtdemux,
9273 "Implement stereo video in separate streams");
9276 if ((frame_layout & 0x1) == 0)
9277 flags |= GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
9279 GST_LOG_OBJECT (qtdemux,
9280 "StereoVideo: composition type: %u, is_left_first: %u",
9281 frame_type, frame_layout);
9282 stream->multiview_mode = mode;
9283 stream->multiview_flags = flags;
9288 if (!(stsd = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsd)))
9290 stsd_data = (const guint8 *) stsd->data;
9292 /* stsd should at least have one entry */
9293 stsd_len = QT_UINT32 (stsd_data);
9294 if (stsd_len < 24) {
9295 /* .. but skip stream with empty stsd produced by some Vivotek cameras */
9296 if (stream->subtype == FOURCC_vivo) {
9298 gst_qtdemux_stream_free (qtdemux, stream);
9305 GST_LOG_OBJECT (qtdemux, "stsd len: %d", stsd_len);
9307 /* and that entry should fit within stsd */
9308 len = QT_UINT32 (stsd_data + 16);
9309 if (len > stsd_len + 16)
9312 stream->fourcc = fourcc = QT_FOURCC (stsd_data + 16 + 4);
9313 GST_LOG_OBJECT (qtdemux, "stsd type: %" GST_FOURCC_FORMAT,
9314 GST_FOURCC_ARGS (stream->fourcc));
9315 GST_LOG_OBJECT (qtdemux, "stsd type len: %d", len);
9317 if ((fourcc == FOURCC_drms) || (fourcc == FOURCC_drmi))
9318 goto error_encrypted;
9320 if (fourcc == FOURCC_encv || fourcc == FOURCC_enca) {
9321 GNode *enc = qtdemux_tree_get_child_by_type (stsd, fourcc);
9322 stream->protected = TRUE;
9323 if (!qtdemux_parse_protection_scheme_info (qtdemux, stream, enc, &fourcc))
9324 GST_ERROR_OBJECT (qtdemux, "Failed to parse protection scheme info");
9327 if (stream->subtype == FOURCC_vide) {
9328 guint32 w = 0, h = 0;
9330 gint depth, palette_size, palette_count;
9332 guint32 *palette_data = NULL;
9334 stream->sampled = TRUE;
9336 /* version 1 uses some 64-bit ints */
9337 if (!gst_byte_reader_skip (&tkhd, 20 + value_size))
9340 if (!qtdemux_parse_transformation_matrix (qtdemux, &tkhd, matrix, "tkhd"))
9343 if (!gst_byte_reader_get_uint32_be (&tkhd, &w)
9344 || !gst_byte_reader_get_uint32_be (&tkhd, &h))
9347 stream->display_width = w >> 16;
9348 stream->display_height = h >> 16;
9350 qtdemux_inspect_transformation_matrix (qtdemux, stream, matrix,
9351 &stream->pending_tags);
9357 stream->width = QT_UINT16 (stsd_data + offset + 32);
9358 stream->height = QT_UINT16 (stsd_data + offset + 34);
9359 stream->fps_n = 0; /* this is filled in later */
9360 stream->fps_d = 0; /* this is filled in later */
9361 stream->bits_per_sample = QT_UINT16 (stsd_data + offset + 82);
9362 stream->color_table_id = QT_UINT16 (stsd_data + offset + 84);
9364 /* if color_table_id is 0, ctab atom must follow; however some files
9365 * produced by TMPEGEnc have color_table_id = 0 and no ctab atom, so
9366 * if color table is not present we'll correct the value */
9367 if (stream->color_table_id == 0 &&
9368 (len < 90 || QT_FOURCC (stsd_data + offset + 86) != FOURCC_ctab)) {
9369 stream->color_table_id = -1;
9372 GST_LOG_OBJECT (qtdemux, "width %d, height %d, bps %d, color table id %d",
9373 stream->width, stream->height, stream->bits_per_sample,
9374 stream->color_table_id);
9376 depth = stream->bits_per_sample;
9378 /* more than 32 bits means grayscale */
9379 gray = (depth > 32);
9380 /* low 32 bits specify the depth */
9383 /* different number of palette entries is determined by depth. */
9385 if ((depth == 1) || (depth == 2) || (depth == 4) || (depth == 8))
9386 palette_count = (1 << depth);
9387 palette_size = palette_count * 4;
9389 if (stream->color_table_id) {
9390 switch (palette_count) {
9394 palette_data = g_memdup (ff_qt_default_palette_2, palette_size);
9397 palette_data = g_memdup (ff_qt_default_palette_4, palette_size);
9401 palette_data = g_memdup (ff_qt_grayscale_palette_16, palette_size);
9403 palette_data = g_memdup (ff_qt_default_palette_16, palette_size);
9407 palette_data = g_memdup (ff_qt_grayscale_palette_256, palette_size);
9409 palette_data = g_memdup (ff_qt_default_palette_256, palette_size);
9412 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
9413 (_("The video in this file might not play correctly.")),
9414 ("unsupported palette depth %d", depth));
9418 gint i, j, start, end;
9424 start = QT_UINT32 (stsd_data + offset + 86);
9425 palette_count = QT_UINT16 (stsd_data + offset + 90);
9426 end = QT_UINT16 (stsd_data + offset + 92);
9428 GST_LOG_OBJECT (qtdemux, "start %d, end %d, palette_count %d",
9429 start, end, palette_count);
9436 if (len < 94 + (end - start) * 8)
9439 /* palette is always the same size */
9440 palette_data = g_malloc0 (256 * 4);
9441 palette_size = 256 * 4;
9443 for (j = 0, i = start; i <= end; j++, i++) {
9446 a = QT_UINT16 (stsd_data + offset + 94 + (j * 8));
9447 r = QT_UINT16 (stsd_data + offset + 96 + (j * 8));
9448 g = QT_UINT16 (stsd_data + offset + 98 + (j * 8));
9449 b = QT_UINT16 (stsd_data + offset + 100 + (j * 8));
9451 palette_data[i] = ((a & 0xff00) << 16) | ((r & 0xff00) << 8) |
9452 (g & 0xff00) | (b >> 8);
9457 gst_caps_unref (stream->caps);
9460 qtdemux_video_caps (qtdemux, stream, fourcc, stsd_data, &codec);
9461 if (G_UNLIKELY (!stream->caps)) {
9462 g_free (palette_data);
9463 goto unknown_stream;
9467 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
9468 GST_TAG_VIDEO_CODEC, codec, NULL);
9477 if (stream->rgb8_palette)
9478 gst_memory_unref (stream->rgb8_palette);
9479 stream->rgb8_palette = gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY,
9480 palette_data, palette_size, 0, palette_size, palette_data, g_free);
9482 s = gst_caps_get_structure (stream->caps, 0);
9484 /* non-raw video has a palette_data property. raw video has the palette as
9485 * an extra plane that we append to the output buffers before we push
9487 if (!gst_structure_has_name (s, "video/x-raw")) {
9490 palette = gst_buffer_new ();
9491 gst_buffer_append_memory (palette, stream->rgb8_palette);
9492 stream->rgb8_palette = NULL;
9494 gst_caps_set_simple (stream->caps, "palette_data",
9495 GST_TYPE_BUFFER, palette, NULL);
9496 gst_buffer_unref (palette);
9498 } else if (palette_count != 0) {
9499 GST_ELEMENT_WARNING (qtdemux, STREAM, NOT_IMPLEMENTED,
9500 (NULL), ("Unsupported palette depth %d", depth));
9503 GST_LOG_OBJECT (qtdemux, "frame count: %u",
9504 QT_UINT16 (stsd_data + offset + 48));
9508 /* pick 'the' stsd child */
9509 if (!stream->protected)
9510 mp4v = qtdemux_tree_get_child_by_type (stsd, fourcc);
9512 mp4v = qtdemux_tree_get_child_by_type (stsd, FOURCC_encv);
9515 esds = qtdemux_tree_get_child_by_type (mp4v, FOURCC_esds);
9516 pasp = qtdemux_tree_get_child_by_type (mp4v, FOURCC_pasp);
9520 const guint8 *pasp_data = (const guint8 *) pasp->data;
9522 stream->par_w = QT_UINT32 (pasp_data + 8);
9523 stream->par_h = QT_UINT32 (pasp_data + 12);
9530 gst_qtdemux_handle_esds (qtdemux, stream, esds, stream->pending_tags);
9537 gint len = QT_UINT32 (stsd_data) - 0x66;
9538 const guint8 *avc_data = stsd_data + 0x66;
9541 while (len >= 0x8) {
9544 if (QT_UINT32 (avc_data) <= len)
9545 size = QT_UINT32 (avc_data) - 0x8;
9550 /* No real data, so break out */
9553 switch (QT_FOURCC (avc_data + 0x4)) {
9556 /* parse, if found */
9559 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
9561 /* First 4 bytes are the length of the atom, the next 4 bytes
9562 * are the fourcc, the next 1 byte is the version, and the
9563 * subsequent bytes are profile_tier_level structure like data. */
9564 gst_codec_utils_h264_caps_set_level_and_profile (stream->caps,
9565 avc_data + 8 + 1, size - 1);
9566 buf = gst_buffer_new_and_alloc (size);
9567 gst_buffer_fill (buf, 0, avc_data + 0x8, size);
9568 gst_caps_set_simple (stream->caps,
9569 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9570 gst_buffer_unref (buf);
9578 GST_DEBUG_OBJECT (qtdemux, "found strf codec_data in stsd");
9580 /* First 4 bytes are the length of the atom, the next 4 bytes
9581 * are the fourcc, next 40 bytes are BITMAPINFOHEADER,
9582 * next 1 byte is the version, and the
9583 * subsequent bytes are sequence parameter set like data. */
9585 size -= 40; /* we'll be skipping BITMAPINFOHEADER */
9587 gst_codec_utils_h264_caps_set_level_and_profile (stream->caps,
9588 avc_data + 8 + 40 + 1, size - 1);
9590 buf = gst_buffer_new_and_alloc (size);
9591 gst_buffer_fill (buf, 0, avc_data + 8 + 40, size);
9592 gst_caps_set_simple (stream->caps,
9593 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9594 gst_buffer_unref (buf);
9600 guint avg_bitrate, max_bitrate;
9602 /* bufferSizeDB, maxBitrate and avgBitrate - 4 bytes each */
9606 max_bitrate = QT_UINT32 (avc_data + 0xc);
9607 avg_bitrate = QT_UINT32 (avc_data + 0x10);
9609 if (!max_bitrate && !avg_bitrate)
9612 /* Some muxers seem to swap the average and maximum bitrates
9613 * (I'm looking at you, YouTube), so we swap for sanity. */
9614 if (max_bitrate > 0 && max_bitrate < avg_bitrate) {
9615 guint temp = avg_bitrate;
9617 avg_bitrate = max_bitrate;
9621 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
9622 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
9623 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
9625 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
9626 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
9627 GST_TAG_BITRATE, avg_bitrate, NULL);
9638 avc_data += size + 8;
9647 gint len = QT_UINT32 (stsd_data) - 0x66;
9648 const guint8 *hevc_data = stsd_data + 0x66;
9651 while (len >= 0x8) {
9654 if (QT_UINT32 (hevc_data) <= len)
9655 size = QT_UINT32 (hevc_data) - 0x8;
9660 /* No real data, so break out */
9663 switch (QT_FOURCC (hevc_data + 0x4)) {
9666 /* parse, if found */
9669 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
9671 /* First 4 bytes are the length of the atom, the next 4 bytes
9672 * are the fourcc, the next 1 byte is the version, and the
9673 * subsequent bytes are sequence parameter set like data. */
9674 gst_codec_utils_h265_caps_set_level_tier_and_profile
9675 (stream->caps, hevc_data + 8 + 1, size - 1);
9677 buf = gst_buffer_new_and_alloc (size);
9678 gst_buffer_fill (buf, 0, hevc_data + 0x8, size);
9679 gst_caps_set_simple (stream->caps,
9680 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9681 gst_buffer_unref (buf);
9688 hevc_data += size + 8;
9699 GST_DEBUG_OBJECT (qtdemux, "found %" GST_FOURCC_FORMAT,
9700 GST_FOURCC_ARGS (fourcc));
9702 /* codec data might be in glbl extension atom */
9704 qtdemux_tree_get_child_by_type (mp4v, FOURCC_glbl) : NULL;
9710 GST_DEBUG_OBJECT (qtdemux, "found glbl data in stsd");
9712 len = QT_UINT32 (data);
9715 buf = gst_buffer_new_and_alloc (len);
9716 gst_buffer_fill (buf, 0, data + 8, len);
9717 gst_caps_set_simple (stream->caps,
9718 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9719 gst_buffer_unref (buf);
9726 /* see annex I of the jpeg2000 spec */
9727 GNode *jp2h, *ihdr, *colr, *mjp2, *field, *prefix, *cmap, *cdef;
9729 const gchar *colorspace = NULL;
9731 guint32 ncomp_map = 0;
9732 gint32 *comp_map = NULL;
9733 guint32 nchan_def = 0;
9734 gint32 *chan_def = NULL;
9736 GST_DEBUG_OBJECT (qtdemux, "found mjp2");
9737 /* some required atoms */
9738 mjp2 = qtdemux_tree_get_child_by_type (stsd, FOURCC_mjp2);
9741 jp2h = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2h);
9745 /* number of components; redundant with info in codestream, but useful
9747 ihdr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_ihdr);
9748 if (!ihdr || QT_UINT32 (ihdr->data) != 22)
9750 ncomp = QT_UINT16 (((guint8 *) ihdr->data) + 16);
9752 colr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_colr);
9755 GST_DEBUG_OBJECT (qtdemux, "found colr");
9756 /* extract colour space info */
9757 if (QT_UINT8 ((guint8 *) colr->data + 8) == 1) {
9758 switch (QT_UINT32 ((guint8 *) colr->data + 11)) {
9760 colorspace = "sRGB";
9763 colorspace = "GRAY";
9766 colorspace = "sYUV";
9774 /* colr is required, and only values 16, 17, and 18 are specified,
9775 so error if we have no colorspace */
9778 /* extract component mapping */
9779 cmap = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cmap);
9781 guint32 cmap_len = 0;
9783 cmap_len = QT_UINT32 (cmap->data);
9784 if (cmap_len >= 8) {
9785 /* normal box, subtract off header */
9787 /* cmap: { u16 cmp; u8 mtyp; u8 pcol; }* */
9788 if (cmap_len % 4 == 0) {
9789 ncomp_map = (cmap_len / 4);
9790 comp_map = g_new0 (gint32, ncomp_map);
9791 for (i = 0; i < ncomp_map; i++) {
9794 cmp = QT_UINT16 (((guint8 *) cmap->data) + 8 + i * 4);
9795 mtyp = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 2);
9796 pcol = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 3);
9797 comp_map[i] = (mtyp << 24) | (pcol << 16) | cmp;
9802 /* extract channel definitions */
9803 cdef = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cdef);
9805 guint32 cdef_len = 0;
9807 cdef_len = QT_UINT32 (cdef->data);
9808 if (cdef_len >= 10) {
9809 /* normal box, subtract off header and len */
9811 /* cdef: u16 n; { u16 cn; u16 typ; u16 asoc; }* */
9812 if (cdef_len % 6 == 0) {
9813 nchan_def = (cdef_len / 6);
9814 chan_def = g_new0 (gint32, nchan_def);
9815 for (i = 0; i < nchan_def; i++)
9817 for (i = 0; i < nchan_def; i++) {
9818 guint16 cn, typ, asoc;
9819 cn = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6);
9820 typ = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 2);
9821 asoc = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 4);
9822 if (cn < nchan_def) {
9825 chan_def[cn] = asoc;
9828 chan_def[cn] = 0; /* alpha */
9831 chan_def[cn] = -typ;
9839 gst_caps_set_simple (stream->caps,
9840 "num-components", G_TYPE_INT, ncomp, NULL);
9841 gst_caps_set_simple (stream->caps,
9842 "colorspace", G_TYPE_STRING, colorspace, NULL);
9845 GValue arr = { 0, };
9846 GValue elt = { 0, };
9848 g_value_init (&arr, GST_TYPE_ARRAY);
9849 g_value_init (&elt, G_TYPE_INT);
9850 for (i = 0; i < ncomp_map; i++) {
9851 g_value_set_int (&elt, comp_map[i]);
9852 gst_value_array_append_value (&arr, &elt);
9854 gst_structure_set_value (gst_caps_get_structure (stream->caps, 0),
9855 "component-map", &arr);
9856 g_value_unset (&elt);
9857 g_value_unset (&arr);
9862 GValue arr = { 0, };
9863 GValue elt = { 0, };
9865 g_value_init (&arr, GST_TYPE_ARRAY);
9866 g_value_init (&elt, G_TYPE_INT);
9867 for (i = 0; i < nchan_def; i++) {
9868 g_value_set_int (&elt, chan_def[i]);
9869 gst_value_array_append_value (&arr, &elt);
9871 gst_structure_set_value (gst_caps_get_structure (stream->caps, 0),
9872 "channel-definitions", &arr);
9873 g_value_unset (&elt);
9874 g_value_unset (&arr);
9878 /* some optional atoms */
9879 field = qtdemux_tree_get_child_by_type (mjp2, FOURCC_fiel);
9880 prefix = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2x);
9882 /* indicate possible fields in caps */
9884 data = (guint8 *) field->data + 8;
9886 gst_caps_set_simple (stream->caps, "fields", G_TYPE_INT,
9887 (gint) * data, NULL);
9889 /* add codec_data if provided */
9894 GST_DEBUG_OBJECT (qtdemux, "found prefix data in stsd");
9895 data = prefix->data;
9896 len = QT_UINT32 (data);
9899 buf = gst_buffer_new_and_alloc (len);
9900 gst_buffer_fill (buf, 0, data + 8, len);
9901 gst_caps_set_simple (stream->caps,
9902 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9903 gst_buffer_unref (buf);
9912 GstBuffer *seqh = NULL;
9913 guint8 *gamma_data = NULL;
9914 gint len = QT_UINT32 (stsd_data);
9916 qtdemux_parse_svq3_stsd_data (qtdemux, stsd, &gamma_data, &seqh);
9918 gst_caps_set_simple (stream->caps, "applied-gamma", G_TYPE_DOUBLE,
9919 QT_FP32 (gamma_data), NULL);
9922 /* sorry for the bad name, but we don't know what this is, other
9923 * than its own fourcc */
9924 gst_caps_set_simple (stream->caps, "seqh", GST_TYPE_BUFFER, seqh,
9928 GST_DEBUG_OBJECT (qtdemux, "found codec_data in stsd");
9929 buf = gst_buffer_new_and_alloc (len);
9930 gst_buffer_fill (buf, 0, stsd_data, len);
9931 gst_caps_set_simple (stream->caps,
9932 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9933 gst_buffer_unref (buf);
9939 gst_caps_set_simple (stream->caps,
9940 "depth", G_TYPE_INT, QT_UINT16 (stsd_data + offset + 82), NULL);
9947 GST_DEBUG_OBJECT (qtdemux, "found XiTh");
9948 xith = qtdemux_tree_get_child_by_type (stsd, FOURCC_XiTh);
9952 xdxt = qtdemux_tree_get_child_by_type (xith, FOURCC_XdxT);
9956 GST_DEBUG_OBJECT (qtdemux, "found XdxT node");
9957 /* collect the headers and store them in a stream list so that we can
9958 * send them out first */
9959 qtdemux_parse_theora_extension (qtdemux, stream, xdxt);
9969 GST_DEBUG_OBJECT (qtdemux, "parse ovc1 header");
9970 ovc1 = qtdemux_tree_get_child_by_type (stsd, FOURCC_ovc1);
9973 ovc1_data = ovc1->data;
9974 ovc1_len = QT_UINT32 (ovc1_data);
9975 if (ovc1_len <= 198) {
9976 GST_WARNING_OBJECT (qtdemux, "Too small ovc1 header, skipping");
9979 buf = gst_buffer_new_and_alloc (ovc1_len - 198);
9980 gst_buffer_fill (buf, 0, ovc1_data + 198, ovc1_len - 198);
9981 gst_caps_set_simple (stream->caps,
9982 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9983 gst_buffer_unref (buf);
9988 gint len = QT_UINT32 (stsd_data) - 0x66;
9989 const guint8 *vc1_data = stsd_data + 0x66;
9995 if (QT_UINT32 (vc1_data) <= len)
9996 size = QT_UINT32 (vc1_data) - 8;
10001 /* No real data, so break out */
10004 switch (QT_FOURCC (vc1_data + 0x4)) {
10005 case GST_MAKE_FOURCC ('d', 'v', 'c', '1'):
10009 GST_DEBUG_OBJECT (qtdemux, "found dvc1 codec_data in stsd");
10010 buf = gst_buffer_new_and_alloc (size);
10011 gst_buffer_fill (buf, 0, vc1_data + 8, size);
10012 gst_caps_set_simple (stream->caps,
10013 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10014 gst_buffer_unref (buf);
10021 vc1_data += size + 8;
10030 GST_INFO_OBJECT (qtdemux,
10031 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
10032 GST_FOURCC_ARGS (fourcc), stream->caps);
10034 } else if (stream->subtype == FOURCC_soun) {
10035 int version, samplesize;
10036 guint16 compression_id;
10037 gboolean amrwb = FALSE;
10040 /* sample description entry (16) + sound sample description v0 (20) */
10044 version = QT_UINT32 (stsd_data + offset);
10045 stream->n_channels = QT_UINT16 (stsd_data + offset + 8);
10046 samplesize = QT_UINT16 (stsd_data + offset + 10);
10047 compression_id = QT_UINT16 (stsd_data + offset + 12);
10048 stream->rate = QT_FP32 (stsd_data + offset + 16);
10050 GST_LOG_OBJECT (qtdemux, "version/rev: %08x", version);
10051 GST_LOG_OBJECT (qtdemux, "vendor: %08x",
10052 QT_UINT32 (stsd_data + offset + 4));
10053 GST_LOG_OBJECT (qtdemux, "n_channels: %d", stream->n_channels);
10054 GST_LOG_OBJECT (qtdemux, "sample_size: %d", samplesize);
10055 GST_LOG_OBJECT (qtdemux, "compression_id: %d", compression_id);
10056 GST_LOG_OBJECT (qtdemux, "packet size: %d",
10057 QT_UINT16 (stsd_data + offset + 14));
10058 GST_LOG_OBJECT (qtdemux, "sample rate: %g", stream->rate);
10060 if (compression_id == 0xfffe)
10061 stream->sampled = TRUE;
10063 /* first assume uncompressed audio */
10064 stream->bytes_per_sample = samplesize / 8;
10065 stream->samples_per_frame = stream->n_channels;
10066 stream->bytes_per_frame = stream->n_channels * stream->bytes_per_sample;
10067 stream->samples_per_packet = stream->samples_per_frame;
10068 stream->bytes_per_packet = stream->bytes_per_sample;
10072 /* Yes, these have to be hard-coded */
10075 stream->samples_per_packet = 6;
10076 stream->bytes_per_packet = 1;
10077 stream->bytes_per_frame = 1 * stream->n_channels;
10078 stream->bytes_per_sample = 1;
10079 stream->samples_per_frame = 6 * stream->n_channels;
10084 stream->samples_per_packet = 3;
10085 stream->bytes_per_packet = 1;
10086 stream->bytes_per_frame = 1 * stream->n_channels;
10087 stream->bytes_per_sample = 1;
10088 stream->samples_per_frame = 3 * stream->n_channels;
10093 stream->samples_per_packet = 64;
10094 stream->bytes_per_packet = 34;
10095 stream->bytes_per_frame = 34 * stream->n_channels;
10096 stream->bytes_per_sample = 2;
10097 stream->samples_per_frame = 64 * stream->n_channels;
10103 stream->samples_per_packet = 1;
10104 stream->bytes_per_packet = 1;
10105 stream->bytes_per_frame = 1 * stream->n_channels;
10106 stream->bytes_per_sample = 1;
10107 stream->samples_per_frame = 1 * stream->n_channels;
10112 stream->samples_per_packet = 160;
10113 stream->bytes_per_packet = 33;
10114 stream->bytes_per_frame = 33 * stream->n_channels;
10115 stream->bytes_per_sample = 2;
10116 stream->samples_per_frame = 160 * stream->n_channels;
10123 if (version == 0x00010000) {
10124 /* sample description entry (16) + sound sample description v1 (20+16) */
10135 /* only parse extra decoding config for non-pcm audio */
10136 stream->samples_per_packet = QT_UINT32 (stsd_data + offset);
10137 stream->bytes_per_packet = QT_UINT32 (stsd_data + offset + 4);
10138 stream->bytes_per_frame = QT_UINT32 (stsd_data + offset + 8);
10139 stream->bytes_per_sample = QT_UINT32 (stsd_data + offset + 12);
10141 GST_LOG_OBJECT (qtdemux, "samples/packet: %d",
10142 stream->samples_per_packet);
10143 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
10144 stream->bytes_per_packet);
10145 GST_LOG_OBJECT (qtdemux, "bytes/frame: %d",
10146 stream->bytes_per_frame);
10147 GST_LOG_OBJECT (qtdemux, "bytes/sample: %d",
10148 stream->bytes_per_sample);
10150 if (!stream->sampled && stream->bytes_per_packet) {
10151 stream->samples_per_frame = (stream->bytes_per_frame /
10152 stream->bytes_per_packet) * stream->samples_per_packet;
10153 GST_LOG_OBJECT (qtdemux, "samples/frame: %d",
10154 stream->samples_per_frame);
10159 } else if (version == 0x00020000) {
10166 /* sample description entry (16) + sound sample description v2 (56) */
10170 qtfp.val = QT_UINT64 (stsd_data + offset + 4);
10171 stream->rate = qtfp.fp;
10172 stream->n_channels = QT_UINT32 (stsd_data + offset + 12);
10174 GST_LOG_OBJECT (qtdemux, "Sound sample description Version 2");
10175 GST_LOG_OBJECT (qtdemux, "sample rate: %g", stream->rate);
10176 GST_LOG_OBJECT (qtdemux, "n_channels: %d", stream->n_channels);
10177 GST_LOG_OBJECT (qtdemux, "bits/channel: %d",
10178 QT_UINT32 (stsd_data + offset + 20));
10179 GST_LOG_OBJECT (qtdemux, "format flags: %X",
10180 QT_UINT32 (stsd_data + offset + 24));
10181 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
10182 QT_UINT32 (stsd_data + offset + 28));
10183 GST_LOG_OBJECT (qtdemux, "LPCM frames/packet: %d",
10184 QT_UINT32 (stsd_data + offset + 32));
10185 } else if (version != 0x00000) {
10186 GST_WARNING_OBJECT (qtdemux, "unknown audio STSD version %08x", version);
10190 gst_caps_unref (stream->caps);
10192 stream->caps = qtdemux_audio_caps (qtdemux, stream, fourcc,
10193 stsd_data + 32, len - 16, &codec);
10201 in24 = qtdemux_tree_get_child_by_type (stsd, FOURCC_in24);
10203 enda = qtdemux_tree_get_child_by_type (in24, FOURCC_enda);
10205 wave = qtdemux_tree_get_child_by_type (in24, FOURCC_wave);
10207 enda = qtdemux_tree_get_child_by_type (wave, FOURCC_enda);
10210 int enda_value = QT_UINT16 ((guint8 *) enda->data + 8);
10211 gst_caps_set_simple (stream->caps,
10212 "format", G_TYPE_STRING, (enda_value) ? "S24LE" : "S24BE", NULL);
10219 const guint8 *owma_data;
10220 const gchar *codec_name = NULL;
10224 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
10225 /* FIXME this should also be gst_riff_strf_auds,
10226 * but the latter one is actually missing bits-per-sample :( */
10231 gint32 nSamplesPerSec;
10232 gint32 nAvgBytesPerSec;
10233 gint16 nBlockAlign;
10234 gint16 wBitsPerSample;
10237 WAVEFORMATEX *wfex;
10239 GST_DEBUG_OBJECT (qtdemux, "parse owma");
10240 owma = qtdemux_tree_get_child_by_type (stsd, FOURCC_owma);
10243 owma_data = owma->data;
10244 owma_len = QT_UINT32 (owma_data);
10245 if (owma_len <= 54) {
10246 GST_WARNING_OBJECT (qtdemux, "Too small owma header, skipping");
10249 wfex = (WAVEFORMATEX *) (owma_data + 36);
10250 buf = gst_buffer_new_and_alloc (owma_len - 54);
10251 gst_buffer_fill (buf, 0, owma_data + 54, owma_len - 54);
10252 if (wfex->wFormatTag == 0x0161) {
10253 codec_name = "Windows Media Audio";
10255 } else if (wfex->wFormatTag == 0x0162) {
10256 codec_name = "Windows Media Audio 9 Pro";
10258 } else if (wfex->wFormatTag == 0x0163) {
10259 codec_name = "Windows Media Audio 9 Lossless";
10260 /* is that correct? gstffmpegcodecmap.c is missing it, but
10261 * fluendo codec seems to support it */
10265 gst_caps_set_simple (stream->caps,
10266 "codec_data", GST_TYPE_BUFFER, buf,
10267 "wmaversion", G_TYPE_INT, version,
10268 "block_align", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->nBlockAlign),
10269 "bitrate", G_TYPE_INT, GST_READ_UINT32_LE (&wfex->nAvgBytesPerSec),
10270 "width", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->wBitsPerSample),
10271 "depth", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->wBitsPerSample),
10273 gst_buffer_unref (buf);
10277 codec = g_strdup (codec_name);
10283 gint len = QT_UINT32 (stsd_data) - offset;
10284 const guint8 *wfex_data = stsd_data + offset;
10285 const gchar *codec_name = NULL;
10287 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
10288 /* FIXME this should also be gst_riff_strf_auds,
10289 * but the latter one is actually missing bits-per-sample :( */
10294 gint32 nSamplesPerSec;
10295 gint32 nAvgBytesPerSec;
10296 gint16 nBlockAlign;
10297 gint16 wBitsPerSample;
10302 /* FIXME: unify with similar wavformatex parsing code above */
10303 GST_DEBUG_OBJECT (qtdemux, "parse wma, looking for wfex");
10309 if (QT_UINT32 (wfex_data) <= len)
10310 size = QT_UINT32 (wfex_data) - 8;
10315 /* No real data, so break out */
10318 switch (QT_FOURCC (wfex_data + 4)) {
10319 case GST_MAKE_FOURCC ('w', 'f', 'e', 'x'):
10321 GST_DEBUG_OBJECT (qtdemux, "found wfex in stsd");
10326 wfex.wFormatTag = GST_READ_UINT16_LE (wfex_data + 8 + 0);
10327 wfex.nChannels = GST_READ_UINT16_LE (wfex_data + 8 + 2);
10328 wfex.nSamplesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 4);
10329 wfex.nAvgBytesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 8);
10330 wfex.nBlockAlign = GST_READ_UINT16_LE (wfex_data + 8 + 12);
10331 wfex.wBitsPerSample = GST_READ_UINT16_LE (wfex_data + 8 + 14);
10332 wfex.cbSize = GST_READ_UINT16_LE (wfex_data + 8 + 16);
10334 GST_LOG_OBJECT (qtdemux, "Found wfex box in stsd:");
10335 GST_LOG_OBJECT (qtdemux, "FormatTag = 0x%04x, Channels = %u, "
10336 "SamplesPerSec = %u, AvgBytesPerSec = %u, BlockAlign = %u, "
10337 "BitsPerSample = %u, Size = %u", wfex.wFormatTag,
10338 wfex.nChannels, wfex.nSamplesPerSec, wfex.nAvgBytesPerSec,
10339 wfex.nBlockAlign, wfex.wBitsPerSample, wfex.cbSize);
10341 if (wfex.wFormatTag == 0x0161) {
10342 codec_name = "Windows Media Audio";
10344 } else if (wfex.wFormatTag == 0x0162) {
10345 codec_name = "Windows Media Audio 9 Pro";
10347 } else if (wfex.wFormatTag == 0x0163) {
10348 codec_name = "Windows Media Audio 9 Lossless";
10349 /* is that correct? gstffmpegcodecmap.c is missing it, but
10350 * fluendo codec seems to support it */
10354 gst_caps_set_simple (stream->caps,
10355 "wmaversion", G_TYPE_INT, version,
10356 "block_align", G_TYPE_INT, wfex.nBlockAlign,
10357 "bitrate", G_TYPE_INT, wfex.nAvgBytesPerSec,
10358 "width", G_TYPE_INT, wfex.wBitsPerSample,
10359 "depth", G_TYPE_INT, wfex.wBitsPerSample, NULL);
10361 if (size > wfex.cbSize) {
10364 buf = gst_buffer_new_and_alloc (size - wfex.cbSize);
10365 gst_buffer_fill (buf, 0, wfex_data + 8 + wfex.cbSize,
10366 size - wfex.cbSize);
10367 gst_caps_set_simple (stream->caps,
10368 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10369 gst_buffer_unref (buf);
10371 GST_WARNING_OBJECT (qtdemux, "no codec data");
10376 codec = g_strdup (codec_name);
10384 wfex_data += size + 8;
10391 const guint8 *opus_data;
10392 guint8 *channel_mapping = NULL;
10395 guint8 channel_mapping_family;
10396 guint8 stream_count;
10397 guint8 coupled_count;
10400 opus = qtdemux_tree_get_child_by_type (stsd, FOURCC_opus);
10401 opus_data = opus->data;
10403 channels = GST_READ_UINT8 (opus_data + 45);
10404 rate = GST_READ_UINT32_LE (opus_data + 48);
10405 channel_mapping_family = GST_READ_UINT8 (opus_data + 54);
10406 stream_count = GST_READ_UINT8 (opus_data + 55);
10407 coupled_count = GST_READ_UINT8 (opus_data + 56);
10409 if (channels > 0) {
10410 channel_mapping = g_malloc (channels * sizeof (guint8));
10411 for (i = 0; i < channels; i++)
10412 channel_mapping[i] = GST_READ_UINT8 (opus_data + i + 57);
10415 stream->caps = gst_codec_utils_opus_create_caps (rate, channels,
10416 channel_mapping_family, stream_count, coupled_count,
10428 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
10429 GST_TAG_AUDIO_CODEC, codec, NULL);
10433 /* some bitrate info may have ended up in caps */
10434 s = gst_caps_get_structure (stream->caps, 0);
10435 gst_structure_get_int (s, "bitrate", &bitrate);
10437 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
10438 GST_TAG_BITRATE, bitrate, NULL);
10441 if (stream->protected && fourcc == FOURCC_mp4a)
10442 mp4a = qtdemux_tree_get_child_by_type (stsd, FOURCC_enca);
10444 mp4a = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4a);
10449 wave = qtdemux_tree_get_child_by_type (mp4a, FOURCC_wave);
10451 esds = qtdemux_tree_get_child_by_type (wave, FOURCC_esds);
10453 esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
10457 /* If the fourcc's bottom 16 bits gives 'sm', then the top
10458 16 bits is a byte-swapped wave-style codec identifier,
10459 and we can find a WAVE header internally to a 'wave' atom here.
10460 This can more clearly be thought of as 'ms' as the top 16 bits, and a
10461 codec id as the bottom 16 bits - but byte-swapped to store in QT (which
10464 if ((fourcc & 0xffff) == (('s' << 8) | 'm')) {
10465 if (len < offset + 20) {
10466 GST_WARNING_OBJECT (qtdemux, "No wave atom in MS-style audio");
10468 guint32 datalen = QT_UINT32 (stsd_data + offset + 16);
10469 const guint8 *data = stsd_data + offset + 16;
10471 GNode *waveheadernode;
10473 wavenode = g_node_new ((guint8 *) data);
10474 if (qtdemux_parse_node (qtdemux, wavenode, data, datalen)) {
10475 const guint8 *waveheader;
10478 waveheadernode = qtdemux_tree_get_child_by_type (wavenode, fourcc);
10479 if (waveheadernode) {
10480 waveheader = (const guint8 *) waveheadernode->data;
10481 headerlen = QT_UINT32 (waveheader);
10483 if (headerlen > 8) {
10484 gst_riff_strf_auds *header = NULL;
10485 GstBuffer *headerbuf;
10491 headerbuf = gst_buffer_new_and_alloc (headerlen);
10492 gst_buffer_fill (headerbuf, 0, waveheader, headerlen);
10494 if (gst_riff_parse_strf_auds (GST_ELEMENT_CAST (qtdemux),
10495 headerbuf, &header, &extra)) {
10496 gst_caps_unref (stream->caps);
10497 /* FIXME: Need to do something with the channel reorder map */
10498 stream->caps = gst_riff_create_audio_caps (header->format, NULL,
10499 header, extra, NULL, NULL, NULL);
10502 gst_buffer_unref (extra);
10507 GST_DEBUG ("Didn't find waveheadernode for this codec");
10509 g_node_destroy (wavenode);
10512 gst_qtdemux_handle_esds (qtdemux, stream, esds, stream->pending_tags);
10516 /* FIXME: what is in the chunk? */
10519 gint len = QT_UINT32 (stsd_data);
10521 /* seems to be always = 116 = 0x74 */
10527 gint len = QT_UINT32 (stsd_data);
10530 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x4C);
10532 gst_buffer_fill (buf, 0, stsd_data + 0x4C, len - 0x4C);
10533 gst_caps_set_simple (stream->caps,
10534 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10535 gst_buffer_unref (buf);
10537 gst_caps_set_simple (stream->caps,
10538 "samplesize", G_TYPE_INT, samplesize, NULL);
10543 GNode *alac, *wave = NULL;
10545 /* apparently, m4a has this atom appended directly in the stsd entry,
10546 * while mov has it in a wave atom */
10547 alac = qtdemux_tree_get_child_by_type (stsd, FOURCC_alac);
10549 /* alac now refers to stsd entry atom */
10550 wave = qtdemux_tree_get_child_by_type (alac, FOURCC_wave);
10552 alac = qtdemux_tree_get_child_by_type (wave, FOURCC_alac);
10554 alac = qtdemux_tree_get_child_by_type (alac, FOURCC_alac);
10557 const guint8 *alac_data = alac->data;
10558 gint len = QT_UINT32 (alac->data);
10562 GST_DEBUG_OBJECT (qtdemux,
10563 "discarding alac atom with unexpected len %d", len);
10565 /* codec-data contains alac atom size and prefix,
10566 * ffmpeg likes it that way, not quite gst-ish though ...*/
10567 buf = gst_buffer_new_and_alloc (len);
10568 gst_buffer_fill (buf, 0, alac->data, len);
10569 gst_caps_set_simple (stream->caps,
10570 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10571 gst_buffer_unref (buf);
10573 stream->bytes_per_frame = QT_UINT32 (alac_data + 12);
10574 stream->n_channels = QT_UINT8 (alac_data + 21);
10575 stream->rate = QT_UINT32 (alac_data + 32);
10578 gst_caps_set_simple (stream->caps,
10579 "samplesize", G_TYPE_INT, samplesize, NULL);
10587 gint len = QT_UINT32 (stsd_data);
10590 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x34);
10593 gst_buffer_fill (buf, 0, stsd_data + 0x34, len - 0x34);
10595 /* If we have enough data, let's try to get the 'damr' atom. See
10596 * the 3GPP container spec (26.244) for more details. */
10597 if ((len - 0x34) > 8 &&
10598 (bitrate = qtdemux_parse_amr_bitrate (buf, amrwb))) {
10599 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
10600 GST_TAG_MAXIMUM_BITRATE, bitrate, NULL);
10603 gst_caps_set_simple (stream->caps,
10604 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10605 gst_buffer_unref (buf);
10611 /* mp4a atom withtout ESDS; Attempt to build codec data from atom */
10612 gint len = QT_UINT32 (stsd_data);
10615 guint16 sound_version = QT_UINT16 (stsd_data + 32);
10617 if (sound_version == 1) {
10618 guint16 channels = QT_UINT16 (stsd_data + 40);
10619 guint32 time_scale = QT_UINT32 (stsd_data + 46);
10620 guint8 codec_data[2];
10622 gint profile = 2; /* FIXME: Can this be determined somehow? There doesn't seem to be anything in mp4a atom that specifis compression */
10624 gint sample_rate_index =
10625 gst_codec_utils_aac_get_index_from_sample_rate (time_scale);
10627 /* build AAC codec data */
10628 codec_data[0] = profile << 3;
10629 codec_data[0] |= ((sample_rate_index >> 1) & 0x7);
10630 codec_data[1] = (sample_rate_index & 0x01) << 7;
10631 codec_data[1] |= (channels & 0xF) << 3;
10633 buf = gst_buffer_new_and_alloc (2);
10634 gst_buffer_fill (buf, 0, codec_data, 2);
10635 gst_caps_set_simple (stream->caps,
10636 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10637 gst_buffer_unref (buf);
10643 GST_INFO_OBJECT (qtdemux,
10644 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
10648 GST_INFO_OBJECT (qtdemux,
10649 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
10650 GST_FOURCC_ARGS (fourcc), stream->caps);
10652 } else if (stream->subtype == FOURCC_strm) {
10653 if (fourcc == FOURCC_rtsp) {
10654 stream->redirect_uri = qtdemux_get_rtsp_uri_from_hndl (qtdemux, minf);
10656 GST_INFO_OBJECT (qtdemux, "unhandled stream type %" GST_FOURCC_FORMAT,
10657 GST_FOURCC_ARGS (fourcc));
10658 goto unknown_stream;
10660 stream->sampled = TRUE;
10661 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
10662 || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt) {
10664 stream->sampled = TRUE;
10665 stream->sparse = TRUE;
10668 qtdemux_sub_caps (qtdemux, stream, fourcc, stsd_data, &codec);
10670 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
10671 GST_TAG_SUBTITLE_CODEC, codec, NULL);
10676 /* hunt for sort-of codec data */
10680 GNode *mp4s = NULL;
10681 GNode *esds = NULL;
10683 /* look for palette in a stsd->mp4s->esds sub-atom */
10684 mp4s = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4s);
10686 esds = qtdemux_tree_get_child_by_type (mp4s, FOURCC_esds);
10687 if (esds == NULL) {
10689 GST_LOG_OBJECT (qtdemux, "Skipping invalid stsd: no esds child");
10693 gst_qtdemux_handle_esds (qtdemux, stream, esds, stream->pending_tags);
10697 GST_INFO_OBJECT (qtdemux,
10698 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
10701 GST_INFO_OBJECT (qtdemux,
10702 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
10703 GST_FOURCC_ARGS (fourcc), stream->caps);
10705 /* everything in 1 sample */
10706 stream->sampled = TRUE;
10709 qtdemux_generic_caps (qtdemux, stream, fourcc, stsd_data, &codec);
10711 if (stream->caps == NULL)
10712 goto unknown_stream;
10715 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
10716 GST_TAG_SUBTITLE_CODEC, codec, NULL);
10722 /* promote to sampled format */
10723 if (stream->fourcc == FOURCC_samr) {
10724 /* force mono 8000 Hz for AMR */
10725 stream->sampled = TRUE;
10726 stream->n_channels = 1;
10727 stream->rate = 8000;
10728 } else if (stream->fourcc == FOURCC_sawb) {
10729 /* force mono 16000 Hz for AMR-WB */
10730 stream->sampled = TRUE;
10731 stream->n_channels = 1;
10732 stream->rate = 16000;
10733 } else if (stream->fourcc == FOURCC_mp4a) {
10734 stream->sampled = TRUE;
10737 /* collect sample information */
10738 if (!qtdemux_stbl_init (qtdemux, stream, stbl))
10739 goto samples_failed;
10741 if (qtdemux->fragmented) {
10744 /* need all moov samples as basis; probably not many if any at all */
10745 /* prevent moof parsing taking of at this time */
10746 offset = qtdemux->moof_offset;
10747 qtdemux->moof_offset = 0;
10748 if (stream->n_samples &&
10749 !qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
10750 qtdemux->moof_offset = offset;
10751 goto samples_failed;
10753 qtdemux->moof_offset = 0;
10754 /* movie duration more reliable in this case (e.g. mehd) */
10755 if (qtdemux->segment.duration &&
10756 GST_CLOCK_TIME_IS_VALID (qtdemux->segment.duration))
10758 GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->segment.duration);
10761 /* configure segments */
10762 if (!qtdemux_parse_segments (qtdemux, stream, trak))
10763 goto segments_failed;
10765 /* add some language tag, if useful */
10766 if (stream->lang_id[0] != '\0' && strcmp (stream->lang_id, "unk") &&
10767 strcmp (stream->lang_id, "und")) {
10768 const gchar *lang_code;
10770 /* convert ISO 639-2 code to ISO 639-1 */
10771 lang_code = gst_tag_get_language_code (stream->lang_id);
10772 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
10773 GST_TAG_LANGUAGE_CODE, (lang_code) ? lang_code : stream->lang_id, NULL);
10776 /* Check for UDTA tags */
10777 if ((udta = qtdemux_tree_get_child_by_type (trak, FOURCC_udta))) {
10778 qtdemux_parse_udta (qtdemux, stream->pending_tags, udta);
10781 /* now we are ready to add the stream */
10782 if (qtdemux->n_streams >= GST_QTDEMUX_MAX_STREAMS)
10783 goto too_many_streams;
10785 if (!qtdemux->got_moov) {
10786 qtdemux->streams[qtdemux->n_streams] = stream;
10787 qtdemux->n_streams++;
10788 GST_DEBUG_OBJECT (qtdemux, "n_streams is now %d", qtdemux->n_streams);
10796 GST_INFO_OBJECT (qtdemux, "skip disabled track");
10798 gst_qtdemux_stream_free (qtdemux, stream);
10803 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
10804 (_("This file is corrupt and cannot be played.")), (NULL));
10806 gst_qtdemux_stream_free (qtdemux, stream);
10811 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT, (NULL), (NULL));
10813 gst_qtdemux_stream_free (qtdemux, stream);
10819 /* we posted an error already */
10820 /* free stbl sub-atoms */
10821 gst_qtdemux_stbl_free (stream);
10823 gst_qtdemux_stream_free (qtdemux, stream);
10828 GST_INFO_OBJECT (qtdemux, "stream with track id %i already exists",
10831 gst_qtdemux_stream_free (qtdemux, stream);
10836 GST_INFO_OBJECT (qtdemux, "unknown subtype %" GST_FOURCC_FORMAT,
10837 GST_FOURCC_ARGS (stream->subtype));
10839 gst_qtdemux_stream_free (qtdemux, stream);
10844 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
10845 (_("This file contains too many streams. Only playing first %d"),
10846 GST_QTDEMUX_MAX_STREAMS), (NULL));
10851 /* If we can estimate the overall bitrate, and don't have information about the
10852 * stream bitrate for exactly one stream, this guesses the stream bitrate as
10853 * the overall bitrate minus the sum of the bitrates of all other streams. This
10854 * should be useful for the common case where we have one audio and one video
10855 * stream and can estimate the bitrate of one, but not the other. */
10857 gst_qtdemux_guess_bitrate (GstQTDemux * qtdemux)
10859 QtDemuxStream *stream = NULL;
10860 gint64 size, sys_bitrate, sum_bitrate = 0;
10861 GstClockTime duration;
10865 if (qtdemux->fragmented)
10868 GST_DEBUG_OBJECT (qtdemux, "Looking for streams with unknown bitrate");
10870 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &size)
10872 GST_DEBUG_OBJECT (qtdemux,
10873 "Size in bytes of the stream not known - bailing");
10877 /* Subtract the header size */
10878 GST_DEBUG_OBJECT (qtdemux, "Total size %" G_GINT64_FORMAT ", header size %u",
10879 size, qtdemux->header_size);
10881 if (size < qtdemux->header_size)
10884 size = size - qtdemux->header_size;
10886 if (!gst_qtdemux_get_duration (qtdemux, &duration)) {
10887 GST_DEBUG_OBJECT (qtdemux, "Stream duration not known - bailing");
10891 for (i = 0; i < qtdemux->n_streams; i++) {
10892 switch (qtdemux->streams[i]->subtype) {
10895 GST_DEBUG_OBJECT (qtdemux, "checking bitrate for %" GST_PTR_FORMAT,
10896 qtdemux->streams[i]->caps);
10897 /* retrieve bitrate, prefer avg then max */
10899 if (qtdemux->streams[i]->pending_tags) {
10900 gst_tag_list_get_uint (qtdemux->streams[i]->pending_tags,
10901 GST_TAG_MAXIMUM_BITRATE, &bitrate);
10902 GST_DEBUG_OBJECT (qtdemux, "max-bitrate: %u", bitrate);
10903 gst_tag_list_get_uint (qtdemux->streams[i]->pending_tags,
10904 GST_TAG_NOMINAL_BITRATE, &bitrate);
10905 GST_DEBUG_OBJECT (qtdemux, "nominal-bitrate: %u", bitrate);
10906 gst_tag_list_get_uint (qtdemux->streams[i]->pending_tags,
10907 GST_TAG_BITRATE, &bitrate);
10908 GST_DEBUG_OBJECT (qtdemux, "bitrate: %u", bitrate);
10911 sum_bitrate += bitrate;
10914 GST_DEBUG_OBJECT (qtdemux,
10915 ">1 stream with unknown bitrate - bailing");
10918 stream = qtdemux->streams[i];
10922 /* For other subtypes, we assume no significant impact on bitrate */
10928 GST_DEBUG_OBJECT (qtdemux, "All stream bitrates are known");
10932 sys_bitrate = gst_util_uint64_scale (size, GST_SECOND * 8, duration);
10934 if (sys_bitrate < sum_bitrate) {
10935 /* This can happen, since sum_bitrate might be derived from maximum
10936 * bitrates and not average bitrates */
10937 GST_DEBUG_OBJECT (qtdemux,
10938 "System bitrate less than sum bitrate - bailing");
10942 bitrate = sys_bitrate - sum_bitrate;
10943 GST_DEBUG_OBJECT (qtdemux, "System bitrate = %" G_GINT64_FORMAT
10944 ", Stream bitrate = %u", sys_bitrate, bitrate);
10946 if (!stream->pending_tags)
10947 stream->pending_tags = gst_tag_list_new_empty ();
10949 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
10950 GST_TAG_BITRATE, bitrate, NULL);
10953 static GstFlowReturn
10954 qtdemux_prepare_streams (GstQTDemux * qtdemux)
10957 GstFlowReturn ret = GST_FLOW_OK;
10959 GST_DEBUG_OBJECT (qtdemux, "prepare streams");
10961 for (i = 0; ret == GST_FLOW_OK && i < qtdemux->n_streams; i++) {
10962 QtDemuxStream *stream = qtdemux->streams[i];
10963 guint32 sample_num = 0;
10965 GST_DEBUG_OBJECT (qtdemux, "stream %d, id %d, fourcc %" GST_FOURCC_FORMAT,
10966 i, stream->track_id, GST_FOURCC_ARGS (stream->fourcc));
10968 if (qtdemux->fragmented) {
10969 /* need all moov samples first */
10970 GST_OBJECT_LOCK (qtdemux);
10971 while (stream->n_samples == 0)
10972 if ((ret = qtdemux_add_fragmented_samples (qtdemux)) != GST_FLOW_OK)
10974 GST_OBJECT_UNLOCK (qtdemux);
10976 /* discard any stray moof */
10977 qtdemux->moof_offset = 0;
10980 /* prepare braking */
10981 if (ret != GST_FLOW_ERROR)
10984 /* in pull mode, we should have parsed some sample info by now;
10985 * and quite some code will not handle no samples.
10986 * in push mode, we'll just have to deal with it */
10987 if (G_UNLIKELY (qtdemux->pullbased && !stream->n_samples)) {
10988 GST_DEBUG_OBJECT (qtdemux, "no samples for stream; discarding");
10989 gst_qtdemux_remove_stream (qtdemux, i);
10994 /* parse the initial sample for use in setting the frame rate cap */
10995 while (sample_num == 0 && sample_num < stream->n_samples) {
10996 if (!qtdemux_parse_samples (qtdemux, stream, sample_num))
11000 if (stream->n_samples > 0 && stream->stbl_index >= 0) {
11001 stream->first_duration = stream->samples[0].duration;
11002 GST_LOG_OBJECT (qtdemux, "stream %d first duration %u",
11003 stream->track_id, stream->first_duration);
11010 static GstFlowReturn
11011 qtdemux_expose_streams (GstQTDemux * qtdemux)
11014 GstFlowReturn ret = GST_FLOW_OK;
11015 GSList *oldpads = NULL;
11018 GST_DEBUG_OBJECT (qtdemux, "exposing streams");
11020 for (i = 0; ret == GST_FLOW_OK && i < qtdemux->n_streams; i++) {
11021 QtDemuxStream *stream = qtdemux->streams[i];
11022 GstPad *oldpad = stream->pad;
11025 GST_DEBUG_OBJECT (qtdemux, "stream %d, id %d, fourcc %" GST_FOURCC_FORMAT,
11026 i, stream->track_id, GST_FOURCC_ARGS (stream->fourcc));
11028 if ((stream->subtype == FOURCC_text || stream->subtype == FOURCC_sbtl) &&
11029 stream->track_id == qtdemux->chapters_track_id) {
11030 /* TODO - parse chapters track and expose it as GstToc; For now just ignore it
11031 so that it doesn't look like a subtitle track */
11032 gst_qtdemux_remove_stream (qtdemux, i);
11037 /* now we have all info and can expose */
11038 list = stream->pending_tags;
11039 stream->pending_tags = NULL;
11041 oldpads = g_slist_prepend (oldpads, oldpad);
11042 if (!gst_qtdemux_add_stream (qtdemux, stream, list))
11043 return GST_FLOW_ERROR;
11046 gst_qtdemux_guess_bitrate (qtdemux);
11048 gst_element_no_more_pads (GST_ELEMENT_CAST (qtdemux));
11050 for (iter = oldpads; iter; iter = g_slist_next (iter)) {
11051 GstPad *oldpad = iter->data;
11054 event = gst_event_new_eos ();
11055 if (qtdemux->segment_seqnum)
11056 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
11058 gst_pad_push_event (oldpad, event);
11059 gst_pad_set_active (oldpad, FALSE);
11060 gst_element_remove_pad (GST_ELEMENT (qtdemux), oldpad);
11061 gst_flow_combiner_remove_pad (qtdemux->flowcombiner, oldpad);
11062 gst_object_unref (oldpad);
11065 /* check if we should post a redirect in case there is a single trak
11066 * and it is a redirecting trak */
11067 if (qtdemux->n_streams == 1 && qtdemux->streams[0]->redirect_uri != NULL) {
11070 GST_INFO_OBJECT (qtdemux, "Issuing a redirect due to a single track with "
11071 "an external content");
11072 m = gst_message_new_element (GST_OBJECT_CAST (qtdemux),
11073 gst_structure_new ("redirect",
11074 "new-location", G_TYPE_STRING, qtdemux->streams[0]->redirect_uri,
11076 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), m);
11077 qtdemux->posted_redirect = TRUE;
11080 for (i = 0; i < qtdemux->n_streams; i++) {
11081 QtDemuxStream *stream = qtdemux->streams[i];
11083 qtdemux_do_allocation (qtdemux, stream);
11086 qtdemux->exposed = TRUE;
11090 /* check if major or compatible brand is 3GP */
11091 static inline gboolean
11092 qtdemux_is_brand_3gp (GstQTDemux * qtdemux, gboolean major)
11095 return ((qtdemux->major_brand & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
11097 } else if (qtdemux->comp_brands != NULL) {
11101 gboolean res = FALSE;
11103 gst_buffer_map (qtdemux->comp_brands, &map, GST_MAP_READ);
11106 while (size >= 4) {
11107 res = res || ((QT_FOURCC (data) & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
11112 gst_buffer_unmap (qtdemux->comp_brands, &map);
11119 /* check if tag is a spec'ed 3GP tag keyword storing a string */
11120 static inline gboolean
11121 qtdemux_is_string_tag_3gp (GstQTDemux * qtdemux, guint32 fourcc)
11123 return fourcc == FOURCC_cprt || fourcc == FOURCC_gnre || fourcc == FOURCC_titl
11124 || fourcc == FOURCC_dscp || fourcc == FOURCC_perf || fourcc == FOURCC_auth
11125 || fourcc == FOURCC_albm;
11129 qtdemux_tag_add_location (GstQTDemux * qtdemux, GstTagList * taglist,
11130 const char *tag, const char *dummy, GNode * node)
11132 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
11136 gdouble longitude, latitude, altitude;
11139 len = QT_UINT32 (node->data);
11146 /* TODO: language code skipped */
11148 name = gst_tag_freeform_string_to_utf8 (data + offset, -1, env_vars);
11151 /* do not alarm in trivial case, but bail out otherwise */
11152 if (*(data + offset) != 0) {
11153 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8, "
11157 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
11158 GST_TAG_GEO_LOCATION_NAME, name, NULL);
11159 offset += strlen (name);
11163 if (len < offset + 2 + 4 + 4 + 4)
11166 /* +1 +1 = skip null-terminator and location role byte */
11168 /* table in spec says unsigned, semantics say negative has meaning ... */
11169 longitude = QT_SFP32 (data + offset);
11172 latitude = QT_SFP32 (data + offset);
11175 altitude = QT_SFP32 (data + offset);
11177 /* one invalid means all are invalid */
11178 if (longitude >= -180.0 && longitude <= 180.0 &&
11179 latitude >= -90.0 && latitude <= 90.0) {
11180 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
11181 GST_TAG_GEO_LOCATION_LATITUDE, latitude,
11182 GST_TAG_GEO_LOCATION_LONGITUDE, longitude,
11183 GST_TAG_GEO_LOCATION_ELEVATION, altitude, NULL);
11186 /* TODO: no GST_TAG_, so astronomical body and additional notes skipped */
11193 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP location");
11200 qtdemux_tag_add_year (GstQTDemux * qtdemux, GstTagList * taglist,
11201 const char *tag, const char *dummy, GNode * node)
11207 len = QT_UINT32 (node->data);
11211 y = QT_UINT16 ((guint8 *) node->data + 12);
11213 GST_DEBUG_OBJECT (qtdemux, "year: %u is not a valid year", y);
11216 GST_DEBUG_OBJECT (qtdemux, "year: %u", y);
11218 date = g_date_new_dmy (1, 1, y);
11219 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, date, NULL);
11220 g_date_free (date);
11224 qtdemux_tag_add_classification (GstQTDemux * qtdemux, GstTagList * taglist,
11225 const char *tag, const char *dummy, GNode * node)
11228 char *tag_str = NULL;
11233 len = QT_UINT32 (node->data);
11238 entity = (guint8 *) node->data + offset;
11239 if (entity[0] == 0 || entity[1] == 0 || entity[2] == 0 || entity[3] == 0) {
11240 GST_DEBUG_OBJECT (qtdemux,
11241 "classification info: %c%c%c%c invalid classification entity",
11242 entity[0], entity[1], entity[2], entity[3]);
11247 table = QT_UINT16 ((guint8 *) node->data + offset);
11249 /* Language code skipped */
11253 /* Tag format: "XXXX://Y[YYYY]/classification info string"
11254 * XXXX: classification entity, fixed length 4 chars.
11255 * Y[YYYY]: classification table, max 5 chars.
11257 tag_str = g_strdup_printf ("----://%u/%s",
11258 table, (char *) node->data + offset);
11260 /* memcpy To be sure we're preserving byte order */
11261 memcpy (tag_str, entity, 4);
11262 GST_DEBUG_OBJECT (qtdemux, "classification info: %s", tag_str);
11264 gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND, tag, tag_str, NULL);
11273 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP classification");
11279 qtdemux_tag_add_str_full (GstQTDemux * qtdemux, GstTagList * taglist,
11280 const char *tag, const char *dummy, GNode * node)
11282 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
11288 gboolean ret = TRUE;
11289 const gchar *charset = NULL;
11291 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
11293 len = QT_UINT32 (data->data);
11294 type = QT_UINT32 ((guint8 *) data->data + 8);
11295 if (type == 0x00000001 && len > 16) {
11296 s = gst_tag_freeform_string_to_utf8 ((char *) data->data + 16, len - 16,
11299 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
11300 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, s, NULL);
11303 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
11307 len = QT_UINT32 (node->data);
11308 type = QT_UINT32 ((guint8 *) node->data + 4);
11309 if ((type >> 24) == 0xa9) {
11313 /* Type starts with the (C) symbol, so the next data is a list
11314 * of (string size(16), language code(16), string) */
11316 str_len = QT_UINT16 ((guint8 *) node->data + 8);
11317 lang_code = QT_UINT16 ((guint8 *) node->data + 10);
11319 /* the string + fourcc + size + 2 16bit fields,
11320 * means that there are more tags in this atom */
11321 if (len > str_len + 8 + 4) {
11322 /* TODO how to represent the same tag in different languages? */
11323 GST_WARNING_OBJECT (qtdemux, "Ignoring metadata entry with multiple "
11324 "text alternatives, reading only first one");
11328 len = str_len + 8 + 4; /* remove trailing strings that we don't use */
11329 GST_DEBUG_OBJECT (qtdemux, "found international text tag");
11331 if (lang_code < 0x800) { /* MAC encoded string */
11334 } else if (len > 14 && qtdemux_is_string_tag_3gp (qtdemux,
11335 QT_FOURCC ((guint8 *) node->data + 4))) {
11336 guint32 type = QT_UINT32 ((guint8 *) node->data + 8);
11338 /* we go for 3GP style encoding if major brands claims so,
11339 * or if no hope for data be ok UTF-8, and compatible 3GP brand present */
11340 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
11341 (qtdemux_is_brand_3gp (qtdemux, FALSE) &&
11342 ((type & 0x00FFFFFF) == 0x0) && (type >> 24 <= 0xF))) {
11344 /* 16-bit Language code is ignored here as well */
11345 GST_DEBUG_OBJECT (qtdemux, "found 3gpp text tag");
11352 GST_DEBUG_OBJECT (qtdemux, "found normal text tag");
11353 ret = FALSE; /* may have to fallback */
11356 GError *err = NULL;
11358 s = g_convert ((gchar *) node->data + offset, len - offset, "utf8",
11359 charset, NULL, NULL, &err);
11361 GST_DEBUG_OBJECT (qtdemux, "Failed to convert string from charset %s:"
11362 " %s(%d): %s", charset, g_quark_to_string (err->domain), err->code,
11364 g_error_free (err);
11367 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
11368 len - offset, env_vars);
11371 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
11372 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, s, NULL);
11376 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
11383 qtdemux_tag_add_str (GstQTDemux * qtdemux, GstTagList * taglist,
11384 const char *tag, const char *dummy, GNode * node)
11386 qtdemux_tag_add_str_full (qtdemux, taglist, tag, dummy, node);
11390 qtdemux_tag_add_keywords (GstQTDemux * qtdemux, GstTagList * taglist,
11391 const char *tag, const char *dummy, GNode * node)
11393 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
11395 char *s, *t, *k = NULL;
11400 /* first try normal string tag if major brand not 3GP */
11401 if (!qtdemux_is_brand_3gp (qtdemux, TRUE)) {
11402 if (!qtdemux_tag_add_str_full (qtdemux, taglist, tag, dummy, node)) {
11403 /* hm, that did not work, maybe 3gpp storage in non-3gpp major brand;
11404 * let's try it 3gpp way after minor safety check */
11406 if (QT_UINT32 (data) < 15 || !qtdemux_is_brand_3gp (qtdemux, FALSE))
11412 GST_DEBUG_OBJECT (qtdemux, "found 3gpp keyword tag");
11416 len = QT_UINT32 (data);
11420 count = QT_UINT8 (data + 14);
11422 for (; count; count--) {
11425 if (offset + 1 > len)
11427 slen = QT_UINT8 (data + offset);
11429 if (offset + slen > len)
11431 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
11434 GST_DEBUG_OBJECT (qtdemux, "adding keyword %s", GST_STR_NULL (s));
11436 t = g_strjoin (",", k, s, NULL);
11444 GST_DEBUG_OBJECT (qtdemux, "failed to convert keyword to UTF-8");
11451 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (k));
11452 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, k, NULL);
11461 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP keywords");
11467 qtdemux_tag_add_num (GstQTDemux * qtdemux, GstTagList * taglist,
11468 const char *tag1, const char *tag2, GNode * node)
11475 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
11477 len = QT_UINT32 (data->data);
11478 type = QT_UINT32 ((guint8 *) data->data + 8);
11479 if (type == 0x00000000 && len >= 22) {
11480 n1 = QT_UINT16 ((guint8 *) data->data + 18);
11481 n2 = QT_UINT16 ((guint8 *) data->data + 20);
11483 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag1, n1);
11484 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, n1, NULL);
11487 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag2, n2);
11488 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag2, n2, NULL);
11495 qtdemux_tag_add_tmpo (GstQTDemux * qtdemux, GstTagList * taglist,
11496 const char *tag1, const char *dummy, GNode * node)
11503 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
11505 len = QT_UINT32 (data->data);
11506 type = QT_UINT32 ((guint8 *) data->data + 8);
11507 GST_DEBUG_OBJECT (qtdemux, "have tempo tag, type=%d,len=%d", type, len);
11508 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
11509 if ((type == 0x00000015 || type == 0x0000000f) && len >= 18) {
11510 n1 = QT_UINT16 ((guint8 *) data->data + 16);
11512 /* do not add bpm=0 */
11513 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", n1);
11514 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, (gdouble) n1,
11522 qtdemux_tag_add_uint32 (GstQTDemux * qtdemux, GstTagList * taglist,
11523 const char *tag1, const char *dummy, GNode * node)
11530 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
11532 len = QT_UINT32 (data->data);
11533 type = QT_UINT32 ((guint8 *) data->data + 8);
11534 GST_DEBUG_OBJECT (qtdemux, "have %s tag, type=%d,len=%d", tag1, type, len);
11535 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
11536 if ((type == 0x00000015 || type == 0x0000000f) && len >= 20) {
11537 num = QT_UINT32 ((guint8 *) data->data + 16);
11539 /* do not add num=0 */
11540 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", num);
11541 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, num, NULL);
11548 qtdemux_tag_add_covr (GstQTDemux * qtdemux, GstTagList * taglist,
11549 const char *tag1, const char *dummy, GNode * node)
11556 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
11558 len = QT_UINT32 (data->data);
11559 type = QT_UINT32 ((guint8 *) data->data + 8);
11560 GST_DEBUG_OBJECT (qtdemux, "have covr tag, type=%d,len=%d", type, len);
11561 if ((type == 0x0000000d || type == 0x0000000e) && len > 16) {
11563 gst_tag_image_data_to_image_sample ((guint8 *) data->data + 16,
11564 len - 16, GST_TAG_IMAGE_TYPE_NONE))) {
11565 GST_DEBUG_OBJECT (qtdemux, "adding tag size %d", len - 16);
11566 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, sample, NULL);
11567 gst_sample_unref (sample);
11574 qtdemux_tag_add_date (GstQTDemux * qtdemux, GstTagList * taglist,
11575 const char *tag, const char *dummy, GNode * node)
11582 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
11584 len = QT_UINT32 (data->data);
11585 type = QT_UINT32 ((guint8 *) data->data + 8);
11586 if (type == 0x00000001 && len > 16) {
11587 guint y, m = 1, d = 1;
11590 s = g_strndup ((char *) data->data + 16, len - 16);
11591 GST_DEBUG_OBJECT (qtdemux, "adding date '%s'", s);
11592 ret = sscanf (s, "%u-%u-%u", &y, &m, &d);
11593 if (ret >= 1 && y > 1500 && y < 3000) {
11596 date = g_date_new_dmy (d, m, y);
11597 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, date, NULL);
11598 g_date_free (date);
11600 GST_DEBUG_OBJECT (qtdemux, "could not parse date string '%s'", s);
11608 qtdemux_tag_add_gnre (GstQTDemux * qtdemux, GstTagList * taglist,
11609 const char *tag, const char *dummy, GNode * node)
11613 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
11615 /* re-route to normal string tag if major brand says so
11616 * or no data atom and compatible brand suggests so */
11617 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
11618 (qtdemux_is_brand_3gp (qtdemux, FALSE) && !data)) {
11619 qtdemux_tag_add_str (qtdemux, taglist, tag, dummy, node);
11624 guint len, type, n;
11626 len = QT_UINT32 (data->data);
11627 type = QT_UINT32 ((guint8 *) data->data + 8);
11628 if (type == 0x00000000 && len >= 18) {
11629 n = QT_UINT16 ((guint8 *) data->data + 16);
11631 const gchar *genre;
11633 genre = gst_tag_id3_genre_get (n - 1);
11634 if (genre != NULL) {
11635 GST_DEBUG_OBJECT (qtdemux, "adding %d [%s]", n, genre);
11636 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, genre, NULL);
11644 qtdemux_add_double_tag_from_str (GstQTDemux * demux, GstTagList * taglist,
11645 const gchar * tag, guint8 * data, guint32 datasize)
11650 /* make a copy to have \0 at the end */
11651 datacopy = g_strndup ((gchar *) data, datasize);
11653 /* convert the str to double */
11654 if (sscanf (datacopy, "%lf", &value) == 1) {
11655 GST_DEBUG_OBJECT (demux, "adding tag: %s [%s]", tag, datacopy);
11656 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, value, NULL);
11658 GST_WARNING_OBJECT (demux, "Failed to parse double from string: %s",
11666 qtdemux_tag_add_revdns (GstQTDemux * demux, GstTagList * taglist,
11667 const char *tag, const char *tag_bis, GNode * node)
11676 const gchar *meanstr;
11677 const gchar *namestr;
11679 /* checking the whole ---- atom size for consistency */
11680 if (QT_UINT32 (node->data) <= 4 + 12 + 12 + 16) {
11681 GST_WARNING_OBJECT (demux, "Tag ---- atom is too small, ignoring");
11685 mean = qtdemux_tree_get_child_by_type (node, FOURCC_mean);
11687 GST_WARNING_OBJECT (demux, "No 'mean' atom found");
11691 meansize = QT_UINT32 (mean->data);
11692 if (meansize <= 12) {
11693 GST_WARNING_OBJECT (demux, "Small mean atom, ignoring the whole tag");
11696 meanstr = ((gchar *) mean->data) + 12;
11699 name = qtdemux_tree_get_child_by_type (node, FOURCC_name);
11701 GST_WARNING_OBJECT (demux, "'name' atom not found, ignoring tag");
11705 namesize = QT_UINT32 (name->data);
11706 if (namesize <= 12) {
11707 GST_WARNING_OBJECT (demux, "'name' atom is too small, ignoring tag");
11710 namestr = ((gchar *) name->data) + 12;
11718 * uint24 - data type
11722 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
11724 GST_WARNING_OBJECT (demux, "No data atom in this tag");
11727 datasize = QT_UINT32 (data->data);
11728 if (datasize <= 16) {
11729 GST_WARNING_OBJECT (demux, "Data atom too small");
11732 datatype = QT_UINT32 (((gchar *) data->data) + 8) & 0xFFFFFF;
11734 if ((strncmp (meanstr, "com.apple.iTunes", meansize) == 0) ||
11735 (strncmp (meanstr, "org.hydrogenaudio.replaygain", meansize) == 0)) {
11736 static const struct
11738 const gchar name[28];
11739 const gchar tag[28];
11742 "replaygain_track_gain", GST_TAG_TRACK_GAIN}, {
11743 "replaygain_track_peak", GST_TAG_TRACK_PEAK}, {
11744 "replaygain_album_gain", GST_TAG_ALBUM_GAIN}, {
11745 "replaygain_album_peak", GST_TAG_ALBUM_PEAK}, {
11746 "MusicBrainz Track Id", GST_TAG_MUSICBRAINZ_TRACKID}, {
11747 "MusicBrainz Artist Id", GST_TAG_MUSICBRAINZ_ARTISTID}, {
11748 "MusicBrainz Album Id", GST_TAG_MUSICBRAINZ_ALBUMID}, {
11749 "MusicBrainz Album Artist Id", GST_TAG_MUSICBRAINZ_ALBUMARTISTID}
11753 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
11754 if (!g_ascii_strncasecmp (tags[i].name, namestr, namesize)) {
11755 switch (gst_tag_get_type (tags[i].tag)) {
11756 case G_TYPE_DOUBLE:
11757 qtdemux_add_double_tag_from_str (demux, taglist, tags[i].tag,
11758 ((guint8 *) data->data) + 16, datasize - 16);
11760 case G_TYPE_STRING:
11761 qtdemux_tag_add_str (demux, taglist, tags[i].tag, NULL, node);
11770 if (i == G_N_ELEMENTS (tags))
11780 #ifndef GST_DISABLE_GST_DEBUG
11782 gchar *namestr_dbg;
11783 gchar *meanstr_dbg;
11785 meanstr_dbg = g_strndup (meanstr, meansize);
11786 namestr_dbg = g_strndup (namestr, namesize);
11788 GST_WARNING_OBJECT (demux, "This tag %s:%s type:%u is not mapped, "
11789 "file a bug at bugzilla.gnome.org", meanstr_dbg, namestr_dbg, datatype);
11791 g_free (namestr_dbg);
11792 g_free (meanstr_dbg);
11799 qtdemux_tag_add_id32 (GstQTDemux * demux, GstTagList * taglist, const char *tag,
11800 const char *tag_bis, GNode * node)
11805 GstTagList *id32_taglist = NULL;
11807 GST_LOG_OBJECT (demux, "parsing ID32");
11810 len = GST_READ_UINT32_BE (data);
11812 /* need at least full box and language tag */
11816 buf = gst_buffer_new_allocate (NULL, len - 14, NULL);
11817 gst_buffer_fill (buf, 0, data + 14, len - 14);
11819 id32_taglist = gst_tag_list_from_id3v2_tag (buf);
11820 if (id32_taglist) {
11821 GST_LOG_OBJECT (demux, "parsing ok");
11822 gst_tag_list_insert (taglist, id32_taglist, GST_TAG_MERGE_KEEP);
11823 gst_tag_list_unref (id32_taglist);
11825 GST_LOG_OBJECT (demux, "parsing failed");
11828 gst_buffer_unref (buf);
11831 typedef void (*GstQTDemuxAddTagFunc) (GstQTDemux * demux, GstTagList * taglist,
11832 const char *tag, const char *tag_bis, GNode * node);
11835 FOURCC_pcst -> if media is a podcast -> bool
11836 FOURCC_cpil -> if media is part of a compilation -> bool
11837 FOURCC_pgap -> if media is part of a gapless context -> bool
11838 FOURCC_tven -> the tv episode id e.g. S01E23 -> str
11841 static const struct
11844 const gchar *gst_tag;
11845 const gchar *gst_tag_bis;
11846 const GstQTDemuxAddTagFunc func;
11849 FOURCC__nam, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
11850 FOURCC_titl, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
11851 FOURCC__grp, GST_TAG_GROUPING, NULL, qtdemux_tag_add_str}, {
11852 FOURCC__wrt, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
11853 FOURCC__ART, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
11854 FOURCC_aART, GST_TAG_ALBUM_ARTIST, NULL, qtdemux_tag_add_str}, {
11855 FOURCC_perf, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
11856 FOURCC_auth, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
11857 FOURCC__alb, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
11858 FOURCC_albm, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
11859 FOURCC_cprt, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
11860 FOURCC__cpy, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
11861 FOURCC__cmt, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
11862 FOURCC__des, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
11863 FOURCC_desc, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
11864 FOURCC_dscp, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
11865 FOURCC__lyr, GST_TAG_LYRICS, NULL, qtdemux_tag_add_str}, {
11866 FOURCC__day, GST_TAG_DATE, NULL, qtdemux_tag_add_date}, {
11867 FOURCC_yrrc, GST_TAG_DATE, NULL, qtdemux_tag_add_year}, {
11868 FOURCC__too, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
11869 FOURCC__inf, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
11870 FOURCC_trkn, GST_TAG_TRACK_NUMBER, GST_TAG_TRACK_COUNT, qtdemux_tag_add_num}, {
11871 FOURCC_disk, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
11872 qtdemux_tag_add_num}, {
11873 FOURCC_disc, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
11874 qtdemux_tag_add_num}, {
11875 FOURCC__gen, GST_TAG_GENRE, NULL, qtdemux_tag_add_str}, {
11876 FOURCC_gnre, GST_TAG_GENRE, NULL, qtdemux_tag_add_gnre}, {
11877 FOURCC_tmpo, GST_TAG_BEATS_PER_MINUTE, NULL, qtdemux_tag_add_tmpo}, {
11878 FOURCC_covr, GST_TAG_PREVIEW_IMAGE, NULL, qtdemux_tag_add_covr}, {
11879 FOURCC_sonm, GST_TAG_TITLE_SORTNAME, NULL, qtdemux_tag_add_str}, {
11880 FOURCC_soal, GST_TAG_ALBUM_SORTNAME, NULL, qtdemux_tag_add_str}, {
11881 FOURCC_soar, GST_TAG_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
11882 FOURCC_soaa, GST_TAG_ALBUM_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
11883 FOURCC_soco, GST_TAG_COMPOSER_SORTNAME, NULL, qtdemux_tag_add_str}, {
11884 FOURCC_sosn, GST_TAG_SHOW_SORTNAME, NULL, qtdemux_tag_add_str}, {
11885 FOURCC_tvsh, GST_TAG_SHOW_NAME, NULL, qtdemux_tag_add_str}, {
11886 FOURCC_tvsn, GST_TAG_SHOW_SEASON_NUMBER, NULL, qtdemux_tag_add_uint32}, {
11887 FOURCC_tves, GST_TAG_SHOW_EPISODE_NUMBER, NULL, qtdemux_tag_add_uint32}, {
11888 FOURCC_kywd, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_keywords}, {
11889 FOURCC_keyw, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_str}, {
11890 FOURCC__enc, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
11891 FOURCC_loci, GST_TAG_GEO_LOCATION_NAME, NULL, qtdemux_tag_add_location}, {
11892 FOURCC_clsf, GST_QT_DEMUX_CLASSIFICATION_TAG, NULL,
11893 qtdemux_tag_add_classification}, {
11894 FOURCC__mak, GST_TAG_DEVICE_MANUFACTURER, NULL, qtdemux_tag_add_str}, {
11895 FOURCC__mod, GST_TAG_DEVICE_MODEL, NULL, qtdemux_tag_add_str}, {
11896 FOURCC__swr, GST_TAG_APPLICATION_NAME, NULL, qtdemux_tag_add_str}, {
11898 /* This is a special case, some tags are stored in this
11899 * 'reverse dns naming', according to:
11900 * http://atomicparsley.sourceforge.net/mpeg-4files.html and
11903 FOURCC_____, "", NULL, qtdemux_tag_add_revdns}, {
11904 /* see http://www.mp4ra.org/specs.html for ID32 in meta box */
11905 FOURCC_ID32, "", NULL, qtdemux_tag_add_id32}
11908 struct _GstQtDemuxTagList
11911 GstTagList *taglist;
11913 typedef struct _GstQtDemuxTagList GstQtDemuxTagList;
11916 qtdemux_tag_add_blob (GNode * node, GstQtDemuxTagList * qtdemuxtaglist)
11922 const gchar *style;
11927 GstQTDemux *demux = qtdemuxtaglist->demux;
11928 GstTagList *taglist = qtdemuxtaglist->taglist;
11931 len = QT_UINT32 (data);
11932 buf = gst_buffer_new_and_alloc (len);
11933 gst_buffer_fill (buf, 0, data, len);
11935 /* heuristic to determine style of tag */
11936 if (QT_FOURCC (data + 4) == FOURCC_____ ||
11937 (len > 8 + 12 && QT_FOURCC (data + 12) == FOURCC_data))
11939 else if (demux->major_brand == FOURCC_qt__)
11940 style = "quicktime";
11941 /* fall back to assuming iso/3gp tag style */
11945 /* santize the name for the caps. */
11946 for (i = 0; i < 4; i++) {
11947 guint8 d = data[4 + i];
11948 if (g_ascii_isalnum (d))
11949 ndata[i] = g_ascii_tolower (d);
11954 media_type = g_strdup_printf ("application/x-gst-qt-%c%c%c%c-tag",
11955 ndata[0], ndata[1], ndata[2], ndata[3]);
11956 GST_DEBUG_OBJECT (demux, "media type %s", media_type);
11958 s = gst_structure_new (media_type, "style", G_TYPE_STRING, style, NULL);
11959 sample = gst_sample_new (buf, NULL, NULL, s);
11960 gst_buffer_unref (buf);
11961 g_free (media_type);
11963 GST_DEBUG_OBJECT (demux, "adding private tag; size %d, info %" GST_PTR_FORMAT,
11966 gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND,
11967 GST_QT_DEMUX_PRIVATE_TAG, sample, NULL);
11969 gst_sample_unref (sample);
11973 qtdemux_parse_udta (GstQTDemux * qtdemux, GstTagList * taglist, GNode * udta)
11980 GstQtDemuxTagList demuxtaglist;
11982 demuxtaglist.demux = qtdemux;
11983 demuxtaglist.taglist = taglist;
11985 meta = qtdemux_tree_get_child_by_type (udta, FOURCC_meta);
11986 if (meta != NULL) {
11987 ilst = qtdemux_tree_get_child_by_type (meta, FOURCC_ilst);
11988 if (ilst == NULL) {
11989 GST_LOG_OBJECT (qtdemux, "no ilst");
11994 GST_LOG_OBJECT (qtdemux, "no meta so using udta itself");
11998 while (i < G_N_ELEMENTS (add_funcs)) {
11999 node = qtdemux_tree_get_child_by_type (ilst, add_funcs[i].fourcc);
12003 len = QT_UINT32 (node->data);
12005 GST_DEBUG_OBJECT (qtdemux, "too small tag atom %" GST_FOURCC_FORMAT,
12006 GST_FOURCC_ARGS (add_funcs[i].fourcc));
12008 add_funcs[i].func (qtdemux, taglist, add_funcs[i].gst_tag,
12009 add_funcs[i].gst_tag_bis, node);
12011 g_node_destroy (node);
12017 /* parsed nodes have been removed, pass along remainder as blob */
12018 g_node_children_foreach (ilst, G_TRAVERSE_ALL,
12019 (GNodeForeachFunc) qtdemux_tag_add_blob, &demuxtaglist);
12021 /* parse up XMP_ node if existing */
12022 xmp_ = qtdemux_tree_get_child_by_type (udta, FOURCC_XMP_);
12023 if (xmp_ != NULL) {
12025 GstTagList *xmptaglist;
12027 buf = _gst_buffer_new_wrapped (((guint8 *) xmp_->data) + 8,
12028 QT_UINT32 ((guint8 *) xmp_->data) - 8, NULL);
12029 xmptaglist = gst_tag_list_from_xmp_buffer (buf);
12030 gst_buffer_unref (buf);
12032 qtdemux_handle_xmp_taglist (qtdemux, taglist, xmptaglist);
12034 GST_DEBUG_OBJECT (qtdemux, "No XMP_ node found");
12040 GstStructure *structure; /* helper for sort function */
12042 guint min_req_bitrate;
12043 guint min_req_qt_version;
12047 qtdemux_redirects_sort_func (gconstpointer a, gconstpointer b)
12049 GstQtReference *ref_a = (GstQtReference *) a;
12050 GstQtReference *ref_b = (GstQtReference *) b;
12052 if (ref_b->min_req_qt_version != ref_a->min_req_qt_version)
12053 return ref_b->min_req_qt_version - ref_a->min_req_qt_version;
12055 /* known bitrates go before unknown; higher bitrates go first */
12056 return ref_b->min_req_bitrate - ref_a->min_req_bitrate;
12059 /* sort the redirects and post a message for the application.
12062 qtdemux_process_redirects (GstQTDemux * qtdemux, GList * references)
12064 GstQtReference *best;
12067 GValue list_val = { 0, };
12070 g_assert (references != NULL);
12072 references = g_list_sort (references, qtdemux_redirects_sort_func);
12074 best = (GstQtReference *) references->data;
12076 g_value_init (&list_val, GST_TYPE_LIST);
12078 for (l = references; l != NULL; l = l->next) {
12079 GstQtReference *ref = (GstQtReference *) l->data;
12080 GValue struct_val = { 0, };
12082 ref->structure = gst_structure_new ("redirect",
12083 "new-location", G_TYPE_STRING, ref->location, NULL);
12085 if (ref->min_req_bitrate > 0) {
12086 gst_structure_set (ref->structure, "minimum-bitrate", G_TYPE_INT,
12087 ref->min_req_bitrate, NULL);
12090 g_value_init (&struct_val, GST_TYPE_STRUCTURE);
12091 g_value_set_boxed (&struct_val, ref->structure);
12092 gst_value_list_append_value (&list_val, &struct_val);
12093 g_value_unset (&struct_val);
12094 /* don't free anything here yet, since we need best->structure below */
12097 g_assert (best != NULL);
12098 s = gst_structure_copy (best->structure);
12100 if (g_list_length (references) > 1) {
12101 gst_structure_set_value (s, "locations", &list_val);
12104 g_value_unset (&list_val);
12106 for (l = references; l != NULL; l = l->next) {
12107 GstQtReference *ref = (GstQtReference *) l->data;
12109 gst_structure_free (ref->structure);
12110 g_free (ref->location);
12113 g_list_free (references);
12115 GST_INFO_OBJECT (qtdemux, "posting redirect message: %" GST_PTR_FORMAT, s);
12116 msg = gst_message_new_element (GST_OBJECT_CAST (qtdemux), s);
12117 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
12118 qtdemux->posted_redirect = TRUE;
12121 /* look for redirect nodes, collect all redirect information and
12125 qtdemux_parse_redirects (GstQTDemux * qtdemux)
12127 GNode *rmra, *rmda, *rdrf;
12129 rmra = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_rmra);
12131 GList *redirects = NULL;
12133 rmda = qtdemux_tree_get_child_by_type (rmra, FOURCC_rmda);
12135 GstQtReference ref = { NULL, NULL, 0, 0 };
12136 GNode *rmdr, *rmvc;
12138 if ((rmdr = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmdr))) {
12139 ref.min_req_bitrate = QT_UINT32 ((guint8 *) rmdr->data + 12);
12140 GST_LOG_OBJECT (qtdemux, "data rate atom, required bitrate = %u",
12141 ref.min_req_bitrate);
12144 if ((rmvc = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmvc))) {
12145 guint32 package = QT_FOURCC ((guint8 *) rmvc->data + 12);
12146 guint version = QT_UINT32 ((guint8 *) rmvc->data + 16);
12148 #ifndef GST_DISABLE_GST_DEBUG
12149 guint bitmask = QT_UINT32 ((guint8 *) rmvc->data + 20);
12151 guint check_type = QT_UINT16 ((guint8 *) rmvc->data + 24);
12153 GST_LOG_OBJECT (qtdemux,
12154 "version check atom [%" GST_FOURCC_FORMAT "], version=0x%08x"
12155 ", mask=%08x, check_type=%u", GST_FOURCC_ARGS (package), version,
12156 bitmask, check_type);
12157 if (package == FOURCC_qtim && check_type == 0) {
12158 ref.min_req_qt_version = version;
12162 rdrf = qtdemux_tree_get_child_by_type (rmda, FOURCC_rdrf);
12168 ref_len = QT_UINT32 ((guint8 *) rdrf->data);
12169 if (ref_len > 20) {
12170 ref_type = QT_FOURCC ((guint8 *) rdrf->data + 12);
12171 ref_data = (guint8 *) rdrf->data + 20;
12172 if (ref_type == FOURCC_alis) {
12173 guint record_len, record_version, fn_len;
12175 if (ref_len > 70) {
12176 /* MacOSX alias record, google for alias-layout.txt */
12177 record_len = QT_UINT16 (ref_data + 4);
12178 record_version = QT_UINT16 (ref_data + 4 + 2);
12179 fn_len = QT_UINT8 (ref_data + 50);
12180 if (record_len > 50 && record_version == 2 && fn_len > 0) {
12181 ref.location = g_strndup ((gchar *) ref_data + 51, fn_len);
12184 GST_WARNING_OBJECT (qtdemux, "Invalid rdrf/alis size (%u < 70)",
12187 } else if (ref_type == FOURCC_url_) {
12188 ref.location = g_strndup ((gchar *) ref_data, ref_len - 8);
12190 GST_DEBUG_OBJECT (qtdemux,
12191 "unknown rdrf reference type %" GST_FOURCC_FORMAT,
12192 GST_FOURCC_ARGS (ref_type));
12194 if (ref.location != NULL) {
12195 GST_INFO_OBJECT (qtdemux, "New location: %s", ref.location);
12197 g_list_prepend (redirects, g_memdup (&ref, sizeof (ref)));
12199 GST_WARNING_OBJECT (qtdemux,
12200 "Failed to extract redirect location from rdrf atom");
12203 GST_WARNING_OBJECT (qtdemux, "Invalid rdrf size (%u < 20)", ref_len);
12207 /* look for others */
12208 rmda = qtdemux_tree_get_sibling_by_type (rmda, FOURCC_rmda);
12211 if (redirects != NULL) {
12212 qtdemux_process_redirects (qtdemux, redirects);
12218 static GstTagList *
12219 qtdemux_add_container_format (GstQTDemux * qtdemux, GstTagList * tags)
12223 if (tags == NULL) {
12224 tags = gst_tag_list_new_empty ();
12225 gst_tag_list_set_scope (tags, GST_TAG_SCOPE_GLOBAL);
12228 if (qtdemux->major_brand == FOURCC_mjp2)
12229 fmt = "Motion JPEG 2000";
12230 else if ((qtdemux->major_brand & 0xffff) == FOURCC_3g__)
12232 else if (qtdemux->major_brand == FOURCC_qt__)
12234 else if (qtdemux->fragmented)
12237 fmt = "ISO MP4/M4A";
12239 GST_LOG_OBJECT (qtdemux, "mapped %" GST_FOURCC_FORMAT " to '%s'",
12240 GST_FOURCC_ARGS (qtdemux->major_brand), fmt);
12242 gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_CONTAINER_FORMAT,
12248 /* we have read the complete moov node now.
12249 * This function parses all of the relevant info, creates the traks and
12250 * prepares all data structures for playback
12253 qtdemux_parse_tree (GstQTDemux * qtdemux)
12259 GstClockTime duration;
12261 guint64 creation_time;
12262 GstDateTime *datetime = NULL;
12265 /* make sure we have a usable taglist */
12266 if (!qtdemux->tag_list) {
12267 qtdemux->tag_list = gst_tag_list_new_empty ();
12268 gst_tag_list_set_scope (qtdemux->tag_list, GST_TAG_SCOPE_GLOBAL);
12270 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
12273 mvhd = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvhd);
12274 if (mvhd == NULL) {
12275 GST_LOG_OBJECT (qtdemux, "No mvhd node found, looking for redirects.");
12276 return qtdemux_parse_redirects (qtdemux);
12279 version = QT_UINT8 ((guint8 *) mvhd->data + 8);
12280 if (version == 1) {
12281 creation_time = QT_UINT64 ((guint8 *) mvhd->data + 12);
12282 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 28);
12283 qtdemux->duration = QT_UINT64 ((guint8 *) mvhd->data + 32);
12284 } else if (version == 0) {
12285 creation_time = QT_UINT32 ((guint8 *) mvhd->data + 12);
12286 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 20);
12287 qtdemux->duration = QT_UINT32 ((guint8 *) mvhd->data + 24);
12289 GST_WARNING_OBJECT (qtdemux, "Unhandled mvhd version %d", version);
12293 /* Moving qt creation time (secs since 1904) to unix time */
12294 if (creation_time != 0) {
12295 /* Try to use epoch first as it should be faster and more commonly found */
12296 if (creation_time >= QTDEMUX_SECONDS_FROM_1904_TO_1970) {
12299 creation_time -= QTDEMUX_SECONDS_FROM_1904_TO_1970;
12300 /* some data cleansing sanity */
12301 g_get_current_time (&now);
12302 if (now.tv_sec + 24 * 3600 < creation_time) {
12303 GST_DEBUG_OBJECT (qtdemux, "discarding bogus future creation time");
12305 datetime = gst_date_time_new_from_unix_epoch_utc (creation_time);
12308 GDateTime *base_dt = g_date_time_new_utc (1904, 1, 1, 0, 0, 0);
12309 GDateTime *dt, *dt_local;
12311 dt = g_date_time_add_seconds (base_dt, creation_time);
12312 dt_local = g_date_time_to_local (dt);
12313 datetime = gst_date_time_new_from_g_date_time (dt_local);
12315 g_date_time_unref (base_dt);
12316 g_date_time_unref (dt);
12320 /* Use KEEP as explicit tags should have a higher priority than mvhd tag */
12321 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_KEEP, GST_TAG_DATE_TIME,
12323 gst_date_time_unref (datetime);
12326 GST_INFO_OBJECT (qtdemux, "timescale: %u", qtdemux->timescale);
12327 GST_INFO_OBJECT (qtdemux, "duration: %" G_GUINT64_FORMAT, qtdemux->duration);
12329 /* check for fragmented file and get some (default) data */
12330 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
12333 GstByteReader mehd_data;
12335 /* let track parsing or anyone know weird stuff might happen ... */
12336 qtdemux->fragmented = TRUE;
12338 /* compensate for total duration */
12339 mehd = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_mehd, &mehd_data);
12341 qtdemux_parse_mehd (qtdemux, &mehd_data);
12344 /* set duration in the segment info */
12345 gst_qtdemux_get_duration (qtdemux, &duration);
12347 qtdemux->segment.duration = duration;
12348 /* also do not exceed duration; stop is set that way post seek anyway,
12349 * and segment activation falls back to duration,
12350 * whereas loop only checks stop, so let's align this here as well */
12351 qtdemux->segment.stop = duration;
12354 /* parse all traks */
12355 trak = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_trak);
12357 qtdemux_parse_trak (qtdemux, trak);
12358 /* iterate all siblings */
12359 trak = qtdemux_tree_get_sibling_by_type (trak, FOURCC_trak);
12362 if (!qtdemux->tag_list) {
12363 GST_DEBUG_OBJECT (qtdemux, "new tag list");
12364 qtdemux->tag_list = gst_tag_list_new_empty ();
12365 gst_tag_list_set_scope (qtdemux->tag_list, GST_TAG_SCOPE_GLOBAL);
12367 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
12371 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_udta);
12373 qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
12375 GST_LOG_OBJECT (qtdemux, "No udta node found.");
12378 /* maybe also some tags in meta box */
12379 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_meta);
12381 GST_DEBUG_OBJECT (qtdemux, "Parsing meta box for tags.");
12382 qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
12384 GST_LOG_OBJECT (qtdemux, "No meta node found.");
12387 /* parse any protection system info */
12388 pssh = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_pssh);
12390 GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
12391 qtdemux_parse_pssh (qtdemux, pssh);
12392 pssh = qtdemux_tree_get_sibling_by_type (pssh, FOURCC_pssh);
12395 qtdemux->tag_list = qtdemux_add_container_format (qtdemux, qtdemux->tag_list);
12400 /* taken from ffmpeg */
12402 read_descr_size (guint8 * ptr, guint8 * end, guint8 ** end_out)
12414 len = (len << 7) | (c & 0x7f);
12422 /* this can change the codec originally present in @list */
12424 gst_qtdemux_handle_esds (GstQTDemux * qtdemux, QtDemuxStream * stream,
12425 GNode * esds, GstTagList * list)
12427 int len = QT_UINT32 (esds->data);
12428 guint8 *ptr = esds->data;
12429 guint8 *end = ptr + len;
12431 guint8 *data_ptr = NULL;
12433 guint8 object_type_id = 0;
12434 const char *codec_name = NULL;
12435 GstCaps *caps = NULL;
12437 GST_MEMDUMP_OBJECT (qtdemux, "esds", ptr, len);
12439 GST_DEBUG_OBJECT (qtdemux, "version/flags = %08x", QT_UINT32 (ptr));
12441 while (ptr + 1 < end) {
12442 tag = QT_UINT8 (ptr);
12443 GST_DEBUG_OBJECT (qtdemux, "tag = %02x", tag);
12445 len = read_descr_size (ptr, end, &ptr);
12446 GST_DEBUG_OBJECT (qtdemux, "len = %d", len);
12448 /* Check the stated amount of data is available for reading */
12449 if (len < 0 || ptr + len > end)
12453 case ES_DESCRIPTOR_TAG:
12454 GST_DEBUG_OBJECT (qtdemux, "ID %04x", QT_UINT16 (ptr));
12455 GST_DEBUG_OBJECT (qtdemux, "priority %04x", QT_UINT8 (ptr + 2));
12458 case DECODER_CONFIG_DESC_TAG:{
12459 guint max_bitrate, avg_bitrate;
12461 object_type_id = QT_UINT8 (ptr);
12462 max_bitrate = QT_UINT32 (ptr + 5);
12463 avg_bitrate = QT_UINT32 (ptr + 9);
12464 GST_DEBUG_OBJECT (qtdemux, "object_type_id %02x", object_type_id);
12465 GST_DEBUG_OBJECT (qtdemux, "stream_type %02x", QT_UINT8 (ptr + 1));
12466 GST_DEBUG_OBJECT (qtdemux, "buffer_size_db %02x", QT_UINT24 (ptr + 2));
12467 GST_DEBUG_OBJECT (qtdemux, "max bitrate %u", max_bitrate);
12468 GST_DEBUG_OBJECT (qtdemux, "avg bitrate %u", avg_bitrate);
12469 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
12470 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
12471 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
12473 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
12474 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
12475 avg_bitrate, NULL);
12480 case DECODER_SPECIFIC_INFO_TAG:
12481 GST_MEMDUMP_OBJECT (qtdemux, "data", ptr, len);
12482 if (object_type_id == 0xe0 && len == 0x40) {
12488 GST_DEBUG_OBJECT (qtdemux,
12489 "Have VOBSUB palette. Creating palette event");
12490 /* move to decConfigDescr data and read palette */
12492 for (i = 0; i < 16; i++) {
12493 clut[i] = QT_UINT32 (data);
12497 s = gst_structure_new ("application/x-gst-dvd", "event",
12498 G_TYPE_STRING, "dvd-spu-clut-change",
12499 "clut00", G_TYPE_INT, clut[0], "clut01", G_TYPE_INT, clut[1],
12500 "clut02", G_TYPE_INT, clut[2], "clut03", G_TYPE_INT, clut[3],
12501 "clut04", G_TYPE_INT, clut[4], "clut05", G_TYPE_INT, clut[5],
12502 "clut06", G_TYPE_INT, clut[6], "clut07", G_TYPE_INT, clut[7],
12503 "clut08", G_TYPE_INT, clut[8], "clut09", G_TYPE_INT, clut[9],
12504 "clut10", G_TYPE_INT, clut[10], "clut11", G_TYPE_INT, clut[11],
12505 "clut12", G_TYPE_INT, clut[12], "clut13", G_TYPE_INT, clut[13],
12506 "clut14", G_TYPE_INT, clut[14], "clut15", G_TYPE_INT, clut[15],
12509 /* store event and trigger custom processing */
12510 stream->pending_event =
12511 gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s);
12513 /* Generic codec_data handler puts it on the caps */
12520 case SL_CONFIG_DESC_TAG:
12521 GST_DEBUG_OBJECT (qtdemux, "data %02x", QT_UINT8 (ptr));
12525 GST_DEBUG_OBJECT (qtdemux, "Unknown/unhandled descriptor tag %02x",
12527 GST_MEMDUMP_OBJECT (qtdemux, "descriptor data", ptr, len);
12533 /* object_type_id in the esds atom in mp4a and mp4v tells us which codec is
12534 * in use, and should also be used to override some other parameters for some
12536 switch (object_type_id) {
12537 case 0x20: /* MPEG-4 */
12538 /* 4 bytes for the visual_object_sequence_start_code and 1 byte for the
12539 * profile_and_level_indication */
12540 if (data_ptr != NULL && data_len >= 5 &&
12541 GST_READ_UINT32_BE (data_ptr) == 0x000001b0) {
12542 gst_codec_utils_mpeg4video_caps_set_level_and_profile (stream->caps,
12543 data_ptr + 4, data_len - 4);
12545 break; /* Nothing special needed here */
12546 case 0x21: /* H.264 */
12547 codec_name = "H.264 / AVC";
12548 caps = gst_caps_new_simple ("video/x-h264",
12549 "stream-format", G_TYPE_STRING, "avc",
12550 "alignment", G_TYPE_STRING, "au", NULL);
12552 case 0x40: /* AAC (any) */
12553 case 0x66: /* AAC Main */
12554 case 0x67: /* AAC LC */
12555 case 0x68: /* AAC SSR */
12556 /* Override channels and rate based on the codec_data, as it's often
12558 /* Only do so for basic setup without HE-AAC extension */
12559 if (data_ptr && data_len == 2) {
12560 guint channels, rate;
12562 channels = gst_codec_utils_aac_get_channels (data_ptr, data_len);
12564 stream->n_channels = channels;
12566 rate = gst_codec_utils_aac_get_sample_rate (data_ptr, data_len);
12568 stream->rate = rate;
12571 /* Set level and profile if possible */
12572 if (data_ptr != NULL && data_len >= 2) {
12573 gst_codec_utils_aac_caps_set_level_and_profile (stream->caps,
12574 data_ptr, data_len);
12577 case 0x60: /* MPEG-2, various profiles */
12583 codec_name = "MPEG-2 video";
12584 caps = gst_caps_new_simple ("video/mpeg",
12585 "mpegversion", G_TYPE_INT, 2,
12586 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
12588 case 0x69: /* MPEG-2 BC audio */
12589 case 0x6B: /* MPEG-1 audio */
12590 caps = gst_caps_new_simple ("audio/mpeg",
12591 "mpegversion", G_TYPE_INT, 1, "parsed", G_TYPE_BOOLEAN, TRUE, NULL);
12592 codec_name = "MPEG-1 audio";
12594 case 0x6A: /* MPEG-1 */
12595 codec_name = "MPEG-1 video";
12596 caps = gst_caps_new_simple ("video/mpeg",
12597 "mpegversion", G_TYPE_INT, 1,
12598 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
12600 case 0x6C: /* MJPEG */
12602 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
12604 codec_name = "Motion-JPEG";
12606 case 0x6D: /* PNG */
12608 gst_caps_new_simple ("image/png", "parsed", G_TYPE_BOOLEAN, TRUE,
12610 codec_name = "PNG still images";
12612 case 0x6E: /* JPEG2000 */
12613 codec_name = "JPEG-2000";
12614 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
12616 case 0xA4: /* Dirac */
12617 codec_name = "Dirac";
12618 caps = gst_caps_new_empty_simple ("video/x-dirac");
12620 case 0xA5: /* AC3 */
12621 codec_name = "AC-3 audio";
12622 caps = gst_caps_new_simple ("audio/x-ac3",
12623 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
12625 case 0xA9: /* AC3 */
12626 codec_name = "DTS audio";
12627 caps = gst_caps_new_simple ("audio/x-dts",
12628 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
12630 case 0xE1: /* QCELP */
12631 /* QCELP, the codec_data is a riff tag (little endian) with
12632 * 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). */
12633 caps = gst_caps_new_empty_simple ("audio/qcelp");
12634 codec_name = "QCELP";
12640 /* If we have a replacement caps, then change our caps for this stream */
12642 gst_caps_unref (stream->caps);
12643 stream->caps = caps;
12646 if (codec_name && list)
12647 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
12648 GST_TAG_AUDIO_CODEC, codec_name, NULL);
12650 /* Add the codec_data attribute to caps, if we have it */
12654 buffer = gst_buffer_new_and_alloc (data_len);
12655 gst_buffer_fill (buffer, 0, data_ptr, data_len);
12657 GST_DEBUG_OBJECT (qtdemux, "setting codec_data from esds");
12658 GST_MEMDUMP_OBJECT (qtdemux, "codec_data from esds", data_ptr, data_len);
12660 gst_caps_set_simple (stream->caps, "codec_data", GST_TYPE_BUFFER,
12662 gst_buffer_unref (buffer);
12667 #define _codec(name) \
12669 if (codec_name) { \
12670 *codec_name = g_strdup (name); \
12675 qtdemux_video_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
12676 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
12678 GstCaps *caps = NULL;
12679 GstVideoFormat format = GST_VIDEO_FORMAT_UNKNOWN;
12682 case GST_MAKE_FOURCC ('p', 'n', 'g', ' '):
12683 _codec ("PNG still images");
12684 caps = gst_caps_new_empty_simple ("image/png");
12687 _codec ("JPEG still images");
12689 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
12692 case GST_MAKE_FOURCC ('m', 'j', 'p', 'a'):
12693 case GST_MAKE_FOURCC ('A', 'V', 'D', 'J'):
12694 case GST_MAKE_FOURCC ('M', 'J', 'P', 'G'):
12695 case GST_MAKE_FOURCC ('d', 'm', 'b', '1'):
12696 _codec ("Motion-JPEG");
12698 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
12701 case GST_MAKE_FOURCC ('m', 'j', 'p', 'b'):
12702 _codec ("Motion-JPEG format B");
12703 caps = gst_caps_new_empty_simple ("video/x-mjpeg-b");
12706 _codec ("JPEG-2000");
12707 /* override to what it should be according to spec, avoid palette_data */
12708 stream->bits_per_sample = 24;
12709 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
12712 _codec ("Sorensen video v.3");
12713 caps = gst_caps_new_simple ("video/x-svq",
12714 "svqversion", G_TYPE_INT, 3, NULL);
12716 case GST_MAKE_FOURCC ('s', 'v', 'q', 'i'):
12717 case GST_MAKE_FOURCC ('S', 'V', 'Q', '1'):
12718 _codec ("Sorensen video v.1");
12719 caps = gst_caps_new_simple ("video/x-svq",
12720 "svqversion", G_TYPE_INT, 1, NULL);
12722 case GST_MAKE_FOURCC ('W', 'R', 'A', 'W'):
12723 caps = gst_caps_new_empty_simple ("video/x-raw");
12724 gst_caps_set_simple (caps, "format", G_TYPE_STRING, "RGB8P", NULL);
12725 _codec ("Windows Raw RGB");
12731 bps = QT_UINT16 (stsd_data + 98);
12734 format = GST_VIDEO_FORMAT_RGB15;
12737 format = GST_VIDEO_FORMAT_RGB16;
12740 format = GST_VIDEO_FORMAT_RGB;
12743 format = GST_VIDEO_FORMAT_ARGB;
12751 case GST_MAKE_FOURCC ('y', 'v', '1', '2'):
12752 format = GST_VIDEO_FORMAT_I420;
12754 case GST_MAKE_FOURCC ('y', 'u', 'v', '2'):
12755 case GST_MAKE_FOURCC ('Y', 'u', 'v', '2'):
12756 format = GST_VIDEO_FORMAT_I420;
12759 case GST_MAKE_FOURCC ('2', 'V', 'u', 'y'):
12760 format = GST_VIDEO_FORMAT_UYVY;
12762 case GST_MAKE_FOURCC ('v', '3', '0', '8'):
12763 format = GST_VIDEO_FORMAT_v308;
12765 case GST_MAKE_FOURCC ('v', '2', '1', '6'):
12766 format = GST_VIDEO_FORMAT_v216;
12769 format = GST_VIDEO_FORMAT_v210;
12771 case GST_MAKE_FOURCC ('r', '2', '1', '0'):
12772 format = GST_VIDEO_FORMAT_r210;
12774 /* Packed YUV 4:4:4 10 bit in 32 bits, complex
12775 case GST_MAKE_FOURCC ('v', '4', '1', '0'):
12776 format = GST_VIDEO_FORMAT_v410;
12779 /* Packed YUV 4:4:4:4 8 bit in 32 bits
12780 * but different order than AYUV
12781 case GST_MAKE_FOURCC ('v', '4', '0', '8'):
12782 format = GST_VIDEO_FORMAT_v408;
12785 case GST_MAKE_FOURCC ('m', 'p', 'e', 'g'):
12786 case GST_MAKE_FOURCC ('m', 'p', 'g', '1'):
12787 _codec ("MPEG-1 video");
12788 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
12789 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
12791 case GST_MAKE_FOURCC ('h', 'd', 'v', '1'): /* HDV 720p30 */
12792 case GST_MAKE_FOURCC ('h', 'd', 'v', '2'): /* HDV 1080i60 */
12793 case GST_MAKE_FOURCC ('h', 'd', 'v', '3'): /* HDV 1080i50 */
12794 case GST_MAKE_FOURCC ('h', 'd', 'v', '4'): /* HDV 720p24 */
12795 case GST_MAKE_FOURCC ('h', 'd', 'v', '5'): /* HDV 720p25 */
12796 case GST_MAKE_FOURCC ('h', 'd', 'v', '6'): /* HDV 1080p24 */
12797 case GST_MAKE_FOURCC ('h', 'd', 'v', '7'): /* HDV 1080p25 */
12798 case GST_MAKE_FOURCC ('h', 'd', 'v', '8'): /* HDV 1080p30 */
12799 case GST_MAKE_FOURCC ('h', 'd', 'v', '9'): /* HDV 720p60 */
12800 case GST_MAKE_FOURCC ('h', 'd', 'v', 'a'): /* HDV 720p50 */
12801 case GST_MAKE_FOURCC ('m', 'x', '5', 'n'): /* MPEG2 IMX NTSC 525/60 50mb/s produced by FCP */
12802 case GST_MAKE_FOURCC ('m', 'x', '5', 'p'): /* MPEG2 IMX PAL 625/60 50mb/s produced by FCP */
12803 case GST_MAKE_FOURCC ('m', 'x', '4', 'n'): /* MPEG2 IMX NTSC 525/60 40mb/s produced by FCP */
12804 case GST_MAKE_FOURCC ('m', 'x', '4', 'p'): /* MPEG2 IMX PAL 625/60 40mb/s produced by FCP */
12805 case GST_MAKE_FOURCC ('m', 'x', '3', 'n'): /* MPEG2 IMX NTSC 525/60 30mb/s produced by FCP */
12806 case GST_MAKE_FOURCC ('m', 'x', '3', 'p'): /* MPEG2 IMX PAL 625/50 30mb/s produced by FCP */
12807 case GST_MAKE_FOURCC ('x', 'd', 'v', '1'): /* XDCAM HD 720p30 35Mb/s */
12808 case GST_MAKE_FOURCC ('x', 'd', 'v', '2'): /* XDCAM HD 1080i60 35Mb/s */
12809 case GST_MAKE_FOURCC ('x', 'd', 'v', '3'): /* XDCAM HD 1080i50 35Mb/s */
12810 case GST_MAKE_FOURCC ('x', 'd', 'v', '4'): /* XDCAM HD 720p24 35Mb/s */
12811 case GST_MAKE_FOURCC ('x', 'd', 'v', '5'): /* XDCAM HD 720p25 35Mb/s */
12812 case GST_MAKE_FOURCC ('x', 'd', 'v', '6'): /* XDCAM HD 1080p24 35Mb/s */
12813 case GST_MAKE_FOURCC ('x', 'd', 'v', '7'): /* XDCAM HD 1080p25 35Mb/s */
12814 case GST_MAKE_FOURCC ('x', 'd', 'v', '8'): /* XDCAM HD 1080p30 35Mb/s */
12815 case GST_MAKE_FOURCC ('x', 'd', 'v', '9'): /* XDCAM HD 720p60 35Mb/s */
12816 case GST_MAKE_FOURCC ('x', 'd', 'v', 'a'): /* XDCAM HD 720p50 35Mb/s */
12817 case GST_MAKE_FOURCC ('x', 'd', 'v', 'b'): /* XDCAM EX 1080i60 50Mb/s CBR */
12818 case GST_MAKE_FOURCC ('x', 'd', 'v', 'c'): /* XDCAM EX 1080i50 50Mb/s CBR */
12819 case GST_MAKE_FOURCC ('x', 'd', 'v', 'd'): /* XDCAM HD 1080p24 50Mb/s CBR */
12820 case GST_MAKE_FOURCC ('x', 'd', 'v', 'e'): /* XDCAM HD 1080p25 50Mb/s CBR */
12821 case GST_MAKE_FOURCC ('x', 'd', 'v', 'f'): /* XDCAM HD 1080p30 50Mb/s CBR */
12822 case GST_MAKE_FOURCC ('x', 'd', '5', '1'): /* XDCAM HD422 720p30 50Mb/s CBR */
12823 case GST_MAKE_FOURCC ('x', 'd', '5', '4'): /* XDCAM HD422 720p24 50Mb/s CBR */
12824 case GST_MAKE_FOURCC ('x', 'd', '5', '5'): /* XDCAM HD422 720p25 50Mb/s CBR */
12825 case GST_MAKE_FOURCC ('x', 'd', '5', '9'): /* XDCAM HD422 720p60 50Mb/s CBR */
12826 case GST_MAKE_FOURCC ('x', 'd', '5', 'a'): /* XDCAM HD422 720p50 50Mb/s CBR */
12827 case GST_MAKE_FOURCC ('x', 'd', '5', 'b'): /* XDCAM HD422 1080i50 50Mb/s CBR */
12828 case GST_MAKE_FOURCC ('x', 'd', '5', 'c'): /* XDCAM HD422 1080i50 50Mb/s CBR */
12829 case GST_MAKE_FOURCC ('x', 'd', '5', 'd'): /* XDCAM HD422 1080p24 50Mb/s CBR */
12830 case GST_MAKE_FOURCC ('x', 'd', '5', 'e'): /* XDCAM HD422 1080p25 50Mb/s CBR */
12831 case GST_MAKE_FOURCC ('x', 'd', '5', 'f'): /* XDCAM HD422 1080p30 50Mb/s CBR */
12832 case GST_MAKE_FOURCC ('x', 'd', 'h', 'd'): /* XDCAM HD 540p */
12833 case GST_MAKE_FOURCC ('x', 'd', 'h', '2'): /* XDCAM HD422 540p */
12834 case GST_MAKE_FOURCC ('A', 'V', 'm', 'p'): /* AVID IMX PAL */
12835 case GST_MAKE_FOURCC ('m', 'p', 'g', '2'): /* AVID IMX PAL */
12836 case GST_MAKE_FOURCC ('m', 'p', '2', 'v'): /* AVID IMX PAL */
12837 _codec ("MPEG-2 video");
12838 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 2,
12839 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
12841 case GST_MAKE_FOURCC ('g', 'i', 'f', ' '):
12842 _codec ("GIF still images");
12843 caps = gst_caps_new_empty_simple ("image/gif");
12846 case GST_MAKE_FOURCC ('H', '2', '6', '3'):
12848 case GST_MAKE_FOURCC ('U', '2', '6', '3'):
12850 /* ffmpeg uses the height/width props, don't know why */
12851 caps = gst_caps_new_simple ("video/x-h263",
12852 "variant", G_TYPE_STRING, "itu", NULL);
12856 _codec ("MPEG-4 video");
12857 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
12858 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
12860 case GST_MAKE_FOURCC ('3', 'i', 'v', 'd'):
12861 case GST_MAKE_FOURCC ('3', 'I', 'V', 'D'):
12862 _codec ("Microsoft MPEG-4 4.3"); /* FIXME? */
12863 caps = gst_caps_new_simple ("video/x-msmpeg",
12864 "msmpegversion", G_TYPE_INT, 43, NULL);
12866 case GST_MAKE_FOURCC ('D', 'I', 'V', '3'):
12868 caps = gst_caps_new_simple ("video/x-divx",
12869 "divxversion", G_TYPE_INT, 3, NULL);
12871 case GST_MAKE_FOURCC ('D', 'I', 'V', 'X'):
12872 case GST_MAKE_FOURCC ('d', 'i', 'v', 'x'):
12874 caps = gst_caps_new_simple ("video/x-divx",
12875 "divxversion", G_TYPE_INT, 4, NULL);
12877 case GST_MAKE_FOURCC ('D', 'X', '5', '0'):
12879 caps = gst_caps_new_simple ("video/x-divx",
12880 "divxversion", G_TYPE_INT, 5, NULL);
12883 case GST_MAKE_FOURCC ('F', 'F', 'V', '1'):
12885 caps = gst_caps_new_simple ("video/x-ffv",
12886 "ffvversion", G_TYPE_INT, 1, NULL);
12889 case GST_MAKE_FOURCC ('3', 'I', 'V', '1'):
12890 case GST_MAKE_FOURCC ('3', 'I', 'V', '2'):
12891 case GST_MAKE_FOURCC ('X', 'V', 'I', 'D'):
12892 case GST_MAKE_FOURCC ('x', 'v', 'i', 'd'):
12894 case GST_MAKE_FOURCC ('U', 'M', 'P', '4'):
12895 caps = gst_caps_new_simple ("video/mpeg",
12896 "mpegversion", G_TYPE_INT, 4, NULL);
12900 case GST_MAKE_FOURCC ('c', 'v', 'i', 'd'):
12901 _codec ("Cinepak");
12902 caps = gst_caps_new_empty_simple ("video/x-cinepak");
12904 case GST_MAKE_FOURCC ('q', 'd', 'r', 'w'):
12905 _codec ("Apple QuickDraw");
12906 caps = gst_caps_new_empty_simple ("video/x-qdrw");
12908 case GST_MAKE_FOURCC ('r', 'p', 'z', 'a'):
12909 _codec ("Apple video");
12910 caps = gst_caps_new_empty_simple ("video/x-apple-video");
12914 _codec ("H.264 / AVC");
12915 caps = gst_caps_new_simple ("video/x-h264",
12916 "stream-format", G_TYPE_STRING, "avc",
12917 "alignment", G_TYPE_STRING, "au", NULL);
12920 _codec ("H.264 / AVC");
12921 caps = gst_caps_new_simple ("video/x-h264",
12922 "stream-format", G_TYPE_STRING, "avc3",
12923 "alignment", G_TYPE_STRING, "au", NULL);
12927 _codec ("H.265 / HEVC");
12928 caps = gst_caps_new_simple ("video/x-h265",
12929 "stream-format", G_TYPE_STRING, "hvc1",
12930 "alignment", G_TYPE_STRING, "au", NULL);
12933 _codec ("H.265 / HEVC");
12934 caps = gst_caps_new_simple ("video/x-h265",
12935 "stream-format", G_TYPE_STRING, "hev1",
12936 "alignment", G_TYPE_STRING, "au", NULL);
12939 _codec ("Run-length encoding");
12940 caps = gst_caps_new_simple ("video/x-rle",
12941 "layout", G_TYPE_STRING, "quicktime", NULL);
12944 _codec ("Run-length encoding");
12945 caps = gst_caps_new_simple ("video/x-rle",
12946 "layout", G_TYPE_STRING, "microsoft", NULL);
12948 case GST_MAKE_FOURCC ('I', 'V', '3', '2'):
12949 case GST_MAKE_FOURCC ('i', 'v', '3', '2'):
12950 _codec ("Indeo Video 3");
12951 caps = gst_caps_new_simple ("video/x-indeo",
12952 "indeoversion", G_TYPE_INT, 3, NULL);
12954 case GST_MAKE_FOURCC ('I', 'V', '4', '1'):
12955 case GST_MAKE_FOURCC ('i', 'v', '4', '1'):
12956 _codec ("Intel Video 4");
12957 caps = gst_caps_new_simple ("video/x-indeo",
12958 "indeoversion", G_TYPE_INT, 4, NULL);
12962 case GST_MAKE_FOURCC ('d', 'v', 's', 'd'):
12963 case GST_MAKE_FOURCC ('D', 'V', 'S', 'D'):
12964 case GST_MAKE_FOURCC ('d', 'v', 'c', 's'):
12965 case GST_MAKE_FOURCC ('D', 'V', 'C', 'S'):
12966 case GST_MAKE_FOURCC ('d', 'v', '2', '5'):
12967 case GST_MAKE_FOURCC ('d', 'v', 'p', 'p'):
12968 _codec ("DV Video");
12969 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 25,
12970 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
12972 case FOURCC_dv5n: /* DVCPRO50 NTSC */
12973 case FOURCC_dv5p: /* DVCPRO50 PAL */
12974 _codec ("DVCPro50 Video");
12975 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 50,
12976 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
12978 case GST_MAKE_FOURCC ('d', 'v', 'h', '5'): /* DVCPRO HD 50i produced by FCP */
12979 case GST_MAKE_FOURCC ('d', 'v', 'h', '6'): /* DVCPRO HD 60i produced by FCP */
12980 _codec ("DVCProHD Video");
12981 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 100,
12982 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
12984 case GST_MAKE_FOURCC ('s', 'm', 'c', ' '):
12985 _codec ("Apple Graphics (SMC)");
12986 caps = gst_caps_new_empty_simple ("video/x-smc");
12988 case GST_MAKE_FOURCC ('V', 'P', '3', '1'):
12990 caps = gst_caps_new_empty_simple ("video/x-vp3");
12992 case GST_MAKE_FOURCC ('V', 'P', '6', 'F'):
12993 _codec ("VP6 Flash");
12994 caps = gst_caps_new_empty_simple ("video/x-vp6-flash");
12998 caps = gst_caps_new_empty_simple ("video/x-theora");
12999 /* theora uses one byte of padding in the data stream because it does not
13000 * allow 0 sized packets while theora does */
13001 stream->padding = 1;
13005 caps = gst_caps_new_empty_simple ("video/x-dirac");
13007 case GST_MAKE_FOURCC ('t', 'i', 'f', 'f'):
13008 _codec ("TIFF still images");
13009 caps = gst_caps_new_empty_simple ("image/tiff");
13011 case GST_MAKE_FOURCC ('i', 'c', 'o', 'd'):
13012 _codec ("Apple Intermediate Codec");
13013 caps = gst_caps_from_string ("video/x-apple-intermediate-codec");
13015 case GST_MAKE_FOURCC ('A', 'V', 'd', 'n'):
13016 _codec ("AVID DNxHD");
13017 caps = gst_caps_from_string ("video/x-dnxhd");
13020 _codec ("On2 VP8");
13021 caps = gst_caps_from_string ("video/x-vp8");
13024 _codec ("Apple ProRes LT");
13026 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "lt",
13030 _codec ("Apple ProRes HQ");
13032 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "hq",
13036 _codec ("Apple ProRes");
13038 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
13042 _codec ("Apple ProRes Proxy");
13044 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
13048 _codec ("Apple ProRes 4444");
13050 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
13056 caps = gst_caps_new_simple ("video/x-wmv",
13057 "wmvversion", G_TYPE_INT, 3, "format", G_TYPE_STRING, "WVC1", NULL);
13059 case GST_MAKE_FOURCC ('k', 'p', 'c', 'd'):
13062 char *s, fourstr[5];
13064 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
13065 s = g_strdup_printf ("video/x-gst-fourcc-%s", g_strstrip (fourstr));
13066 caps = gst_caps_new_empty_simple (s);
13072 if (format != GST_VIDEO_FORMAT_UNKNOWN) {
13075 gst_video_info_init (&info);
13076 gst_video_info_set_format (&info, format, stream->width, stream->height);
13078 caps = gst_video_info_to_caps (&info);
13079 *codec_name = gst_pb_utils_get_codec_description (caps);
13081 /* enable clipping for raw video streams */
13082 stream->need_clip = TRUE;
13089 qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
13090 guint32 fourcc, const guint8 * data, int len, gchar ** codec_name)
13093 const GstStructure *s;
13096 GstAudioFormat format = 0;
13099 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
13101 depth = stream->bytes_per_packet * 8;
13104 case GST_MAKE_FOURCC ('N', 'O', 'N', 'E'):
13106 /* 8-bit audio is unsigned */
13108 format = GST_AUDIO_FORMAT_U8;
13109 /* otherwise it's signed and big-endian just like 'twos' */
13111 endian = G_BIG_ENDIAN;
13118 endian = G_LITTLE_ENDIAN;
13121 format = gst_audio_format_build_integer (TRUE, endian, depth, depth);
13123 str = g_strdup_printf ("Raw %d-bit PCM audio", depth);
13127 caps = gst_caps_new_simple ("audio/x-raw",
13128 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
13129 "layout", G_TYPE_STRING, "interleaved", NULL);
13132 case GST_MAKE_FOURCC ('f', 'l', '6', '4'):
13133 _codec ("Raw 64-bit floating-point audio");
13134 caps = gst_caps_new_simple ("audio/x-raw",
13135 "format", G_TYPE_STRING, "F64BE",
13136 "layout", G_TYPE_STRING, "interleaved", NULL);
13138 case GST_MAKE_FOURCC ('f', 'l', '3', '2'):
13139 _codec ("Raw 32-bit floating-point audio");
13140 caps = gst_caps_new_simple ("audio/x-raw",
13141 "format", G_TYPE_STRING, "F32BE",
13142 "layout", G_TYPE_STRING, "interleaved", NULL);
13145 _codec ("Raw 24-bit PCM audio");
13146 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
13148 caps = gst_caps_new_simple ("audio/x-raw",
13149 "format", G_TYPE_STRING, "S24BE",
13150 "layout", G_TYPE_STRING, "interleaved", NULL);
13152 case GST_MAKE_FOURCC ('i', 'n', '3', '2'):
13153 _codec ("Raw 32-bit PCM audio");
13154 caps = gst_caps_new_simple ("audio/x-raw",
13155 "format", G_TYPE_STRING, "S32BE",
13156 "layout", G_TYPE_STRING, "interleaved", NULL);
13159 _codec ("Mu-law audio");
13160 caps = gst_caps_new_empty_simple ("audio/x-mulaw");
13163 _codec ("A-law audio");
13164 caps = gst_caps_new_empty_simple ("audio/x-alaw");
13168 _codec ("Microsoft ADPCM");
13169 /* Microsoft ADPCM-ACM code 2 */
13170 caps = gst_caps_new_simple ("audio/x-adpcm",
13171 "layout", G_TYPE_STRING, "microsoft", NULL);
13175 _codec ("DVI/IMA ADPCM");
13176 caps = gst_caps_new_simple ("audio/x-adpcm",
13177 "layout", G_TYPE_STRING, "dvi", NULL);
13181 _codec ("DVI/Intel IMA ADPCM");
13182 /* FIXME DVI/Intel IMA ADPCM/ACM code 17 */
13183 caps = gst_caps_new_simple ("audio/x-adpcm",
13184 "layout", G_TYPE_STRING, "quicktime", NULL);
13188 /* MPEG layer 3, CBR only (pre QT4.1) */
13190 _codec ("MPEG-1 layer 3");
13191 /* MPEG layer 3, CBR & VBR (QT4.1 and later) */
13192 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 3,
13193 "mpegversion", G_TYPE_INT, 1, NULL);
13196 case GST_MAKE_FOURCC ('e', 'c', '-', '3'):
13197 _codec ("EAC-3 audio");
13198 caps = gst_caps_new_simple ("audio/x-eac3",
13199 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
13200 stream->sampled = TRUE;
13202 case GST_MAKE_FOURCC ('s', 'a', 'c', '3'): // Nero Recode
13204 _codec ("AC-3 audio");
13205 caps = gst_caps_new_simple ("audio/x-ac3",
13206 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
13207 stream->sampled = TRUE;
13209 case GST_MAKE_FOURCC ('d', 't', 's', 'c'):
13210 case GST_MAKE_FOURCC ('D', 'T', 'S', ' '):
13211 _codec ("DTS audio");
13212 caps = gst_caps_new_simple ("audio/x-dts",
13213 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
13214 stream->sampled = TRUE;
13216 case GST_MAKE_FOURCC ('d', 't', 's', 'h'): // DTS-HD
13217 case GST_MAKE_FOURCC ('d', 't', 's', 'l'): // DTS-HD Lossless
13218 _codec ("DTS-HD audio");
13219 caps = gst_caps_new_simple ("audio/x-dts",
13220 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
13221 stream->sampled = TRUE;
13225 caps = gst_caps_new_simple ("audio/x-mace",
13226 "maceversion", G_TYPE_INT, 3, NULL);
13230 caps = gst_caps_new_simple ("audio/x-mace",
13231 "maceversion", G_TYPE_INT, 6, NULL);
13233 case GST_MAKE_FOURCC ('O', 'g', 'g', 'V'):
13235 caps = gst_caps_new_empty_simple ("application/ogg");
13237 case GST_MAKE_FOURCC ('d', 'v', 'c', 'a'):
13238 _codec ("DV audio");
13239 caps = gst_caps_new_empty_simple ("audio/x-dv");
13242 _codec ("MPEG-4 AAC audio");
13243 caps = gst_caps_new_simple ("audio/mpeg",
13244 "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE,
13245 "stream-format", G_TYPE_STRING, "raw", NULL);
13247 case GST_MAKE_FOURCC ('Q', 'D', 'M', 'C'):
13248 _codec ("QDesign Music");
13249 caps = gst_caps_new_empty_simple ("audio/x-qdm");
13252 _codec ("QDesign Music v.2");
13253 /* FIXME: QDesign music version 2 (no constant) */
13254 if (FALSE && data) {
13255 caps = gst_caps_new_simple ("audio/x-qdm2",
13256 "framesize", G_TYPE_INT, QT_UINT32 (data + 52),
13257 "bitrate", G_TYPE_INT, QT_UINT32 (data + 40),
13258 "blocksize", G_TYPE_INT, QT_UINT32 (data + 44), NULL);
13260 caps = gst_caps_new_empty_simple ("audio/x-qdm2");
13264 _codec ("GSM audio");
13265 caps = gst_caps_new_empty_simple ("audio/x-gsm");
13268 _codec ("AMR audio");
13269 caps = gst_caps_new_empty_simple ("audio/AMR");
13272 _codec ("AMR-WB audio");
13273 caps = gst_caps_new_empty_simple ("audio/AMR-WB");
13276 _codec ("Quicktime IMA ADPCM");
13277 caps = gst_caps_new_simple ("audio/x-adpcm",
13278 "layout", G_TYPE_STRING, "quicktime", NULL);
13281 _codec ("Apple lossless audio");
13282 caps = gst_caps_new_empty_simple ("audio/x-alac");
13284 case GST_MAKE_FOURCC ('Q', 'c', 'l', 'p'):
13285 _codec ("QualComm PureVoice");
13286 caps = gst_caps_from_string ("audio/qcelp");
13291 caps = gst_caps_new_empty_simple ("audio/x-wma");
13295 caps = gst_caps_new_empty_simple ("audio/x-opus");
13297 case GST_MAKE_FOURCC ('l', 'p', 'c', 'm'):
13302 GstAudioFormat format;
13305 FLAG_IS_FLOAT = 0x1,
13306 FLAG_IS_BIG_ENDIAN = 0x2,
13307 FLAG_IS_SIGNED = 0x4,
13308 FLAG_IS_PACKED = 0x8,
13309 FLAG_IS_ALIGNED_HIGH = 0x10,
13310 FLAG_IS_NON_INTERLEAVED = 0x20
13312 _codec ("Raw LPCM audio");
13314 if (data && len >= 56) {
13315 depth = QT_UINT32 (data + 40);
13316 flags = QT_UINT32 (data + 44);
13317 width = QT_UINT32 (data + 48) * 8 / stream->n_channels;
13319 if ((flags & FLAG_IS_FLOAT) == 0) {
13324 format = gst_audio_format_build_integer ((flags & FLAG_IS_SIGNED) ?
13325 TRUE : FALSE, (flags & FLAG_IS_BIG_ENDIAN) ?
13326 G_BIG_ENDIAN : G_LITTLE_ENDIAN, width, depth);
13327 caps = gst_caps_new_simple ("audio/x-raw",
13328 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
13329 "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
13330 "non-interleaved" : "interleaved", NULL);
13335 if (flags & FLAG_IS_BIG_ENDIAN)
13336 format = GST_AUDIO_FORMAT_F64BE;
13338 format = GST_AUDIO_FORMAT_F64LE;
13340 if (flags & FLAG_IS_BIG_ENDIAN)
13341 format = GST_AUDIO_FORMAT_F32BE;
13343 format = GST_AUDIO_FORMAT_F32LE;
13345 caps = gst_caps_new_simple ("audio/x-raw",
13346 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
13347 "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
13348 "non-interleaved" : "interleaved", NULL);
13352 case GST_MAKE_FOURCC ('q', 't', 'v', 'r'):
13356 char *s, fourstr[5];
13358 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
13359 s = g_strdup_printf ("audio/x-gst-fourcc-%s", g_strstrip (fourstr));
13360 caps = gst_caps_new_empty_simple (s);
13367 GstCaps *templ_caps =
13368 gst_static_pad_template_get_caps (&gst_qtdemux_audiosrc_template);
13369 GstCaps *intersection = gst_caps_intersect (caps, templ_caps);
13370 gst_caps_unref (caps);
13371 gst_caps_unref (templ_caps);
13372 caps = intersection;
13375 /* enable clipping for raw audio streams */
13376 s = gst_caps_get_structure (caps, 0);
13377 name = gst_structure_get_name (s);
13378 if (g_str_has_prefix (name, "audio/x-raw")) {
13379 stream->need_clip = TRUE;
13380 stream->max_buffer_size = 4096 * stream->bytes_per_frame;
13381 GST_DEBUG ("setting max buffer size to %d", stream->max_buffer_size);
13387 qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
13388 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
13392 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
13396 _codec ("DVD subtitle");
13397 caps = gst_caps_new_empty_simple ("subpicture/x-dvd");
13398 stream->need_process = TRUE;
13401 _codec ("Quicktime timed text");
13404 _codec ("3GPP timed text");
13406 caps = gst_caps_new_simple ("text/x-raw", "format", G_TYPE_STRING,
13408 /* actual text piece needs to be extracted */
13409 stream->need_process = TRUE;
13412 _codec ("XML subtitles");
13413 caps = gst_caps_new_empty_simple ("application/ttml+xml");
13417 char *s, fourstr[5];
13419 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
13420 s = g_strdup_printf ("text/x-gst-fourcc-%s", g_strstrip (fourstr));
13421 caps = gst_caps_new_empty_simple (s);
13430 qtdemux_generic_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
13431 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
13437 _codec ("MPEG 1 video");
13438 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
13439 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13449 gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux,
13450 const gchar * system_id)
13454 if (!qtdemux->protection_system_ids)
13455 qtdemux->protection_system_ids =
13456 g_ptr_array_new_with_free_func ((GDestroyNotify) g_free);
13457 /* Check whether we already have an entry for this system ID. */
13458 for (i = 0; i < qtdemux->protection_system_ids->len; ++i) {
13459 const gchar *id = g_ptr_array_index (qtdemux->protection_system_ids, i);
13460 if (g_ascii_strcasecmp (system_id, id) == 0) {
13464 GST_DEBUG_OBJECT (qtdemux, "Adding cenc protection system ID %s", system_id);
13465 g_ptr_array_add (qtdemux->protection_system_ids, g_ascii_strdown (system_id,