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;
2980 gint64 initial_offset;
2982 GST_LOG_OBJECT (qtdemux, "parsing trun stream %d; "
2983 "default dur %d, size %d, flags 0x%x, base offset %" G_GINT64_FORMAT ", "
2984 "decode ts %" G_GINT64_FORMAT, stream->track_id, d_sample_duration,
2985 d_sample_size, d_sample_flags, *base_offset, decode_ts);
2987 if (stream->pending_seek && moof_offset < stream->pending_seek->moof_offset) {
2988 GST_INFO_OBJECT (stream->pad, "skipping trun before seek target fragment");
2992 /* presence of stss or not can't really tell us much,
2993 * and flags and so on tend to be marginally reliable in these files */
2994 if (stream->subtype == FOURCC_soun) {
2995 GST_DEBUG_OBJECT (qtdemux,
2996 "sound track in fragmented file; marking all keyframes");
2997 stream->all_keyframe = TRUE;
3000 if (!gst_byte_reader_skip (trun, 1) ||
3001 !gst_byte_reader_get_uint24_be (trun, &flags))
3004 if (!gst_byte_reader_get_uint32_be (trun, &samples_count))
3007 if (flags & TR_DATA_OFFSET) {
3008 /* note this is really signed */
3009 if (!gst_byte_reader_get_int32_be (trun, &data_offset))
3011 GST_LOG_OBJECT (qtdemux, "trun data offset %d", data_offset);
3012 /* default base offset = first byte of moof */
3013 if (*base_offset == -1) {
3014 GST_LOG_OBJECT (qtdemux, "base_offset at moof");
3015 *base_offset = moof_offset;
3017 *running_offset = *base_offset + data_offset;
3019 /* if no offset at all, that would mean data starts at moof start,
3020 * which is a bit wrong and is ismv crappy way, so compensate
3021 * assuming data is in mdat following moof */
3022 if (*base_offset == -1) {
3023 *base_offset = moof_offset + moof_length + 8;
3024 GST_LOG_OBJECT (qtdemux, "base_offset assumed in mdat after moof");
3027 if (*running_offset == -1)
3028 *running_offset = *base_offset;
3031 GST_LOG_OBJECT (qtdemux, "running offset now %" G_GINT64_FORMAT,
3033 GST_LOG_OBJECT (qtdemux, "trun offset %d, flags 0x%x, entries %d",
3034 data_offset, flags, samples_count);
3036 if (flags & TR_FIRST_SAMPLE_FLAGS) {
3037 if (G_UNLIKELY (flags & TR_SAMPLE_FLAGS)) {
3038 GST_DEBUG_OBJECT (qtdemux,
3039 "invalid flags; SAMPLE and FIRST_SAMPLE present, discarding latter");
3040 flags ^= TR_FIRST_SAMPLE_FLAGS;
3042 if (!gst_byte_reader_get_uint32_be (trun, &first_flags))
3044 GST_LOG_OBJECT (qtdemux, "first flags: 0x%x", first_flags);
3048 /* FIXME ? spec says other bits should also be checked to determine
3049 * entry size (and prefix size for that matter) */
3051 dur_offset = size_offset = 0;
3052 if (flags & TR_SAMPLE_DURATION) {
3053 GST_LOG_OBJECT (qtdemux, "entry duration present");
3054 dur_offset = entry_size;
3057 if (flags & TR_SAMPLE_SIZE) {
3058 GST_LOG_OBJECT (qtdemux, "entry size present");
3059 size_offset = entry_size;
3062 if (flags & TR_SAMPLE_FLAGS) {
3063 GST_LOG_OBJECT (qtdemux, "entry flags present");
3064 flags_offset = entry_size;
3067 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
3068 GST_LOG_OBJECT (qtdemux, "entry ct offset present");
3069 ct_offset = entry_size;
3073 if (!qt_atom_parser_has_chunks (trun, samples_count, entry_size))
3075 data = (guint8 *) gst_byte_reader_peek_data_unchecked (trun);
3077 if (stream->n_samples + samples_count >=
3078 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample))
3081 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
3082 stream->n_samples + samples_count, (guint) sizeof (QtDemuxSample),
3083 (stream->n_samples + samples_count) *
3084 sizeof (QtDemuxSample) / (1024.0 * 1024.0));
3086 /* create a new array of samples if it's the first sample parsed */
3087 if (stream->n_samples == 0) {
3088 g_assert (stream->samples == NULL);
3089 stream->samples = g_try_new0 (QtDemuxSample, samples_count);
3090 /* or try to reallocate it with space enough to insert the new samples */
3092 stream->samples = g_try_renew (QtDemuxSample, stream->samples,
3093 stream->n_samples + samples_count);
3094 if (stream->samples == NULL)
3097 if (qtdemux->fragment_start != -1) {
3098 timestamp = GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->fragment_start);
3099 qtdemux->fragment_start = -1;
3101 if (stream->n_samples == 0) {
3102 if (decode_ts > 0) {
3103 timestamp = decode_ts;
3104 } else if (stream->pending_seek != NULL) {
3105 /* if we don't have a timestamp from a tfdt box, we'll use the one
3106 * from the mfra seek table */
3107 GST_INFO_OBJECT (stream->pad, "pending seek ts = %" GST_TIME_FORMAT,
3108 GST_TIME_ARGS (stream->pending_seek->ts));
3110 /* FIXME: this is not fully correct, the timestamp refers to the random
3111 * access sample refered to in the tfra entry, which may not necessarily
3112 * be the first sample in the tfrag/trun (but hopefully/usually is) */
3113 timestamp = GSTTIME_TO_QTSTREAMTIME (stream, stream->pending_seek->ts);
3118 gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
3119 GST_INFO_OBJECT (stream->pad, "first sample ts %" GST_TIME_FORMAT,
3120 GST_TIME_ARGS (gst_ts));
3122 /* subsequent fragments extend stream */
3124 stream->samples[stream->n_samples - 1].timestamp +
3125 stream->samples[stream->n_samples - 1].duration;
3127 gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
3128 GST_INFO_OBJECT (qtdemux, "first sample ts %" GST_TIME_FORMAT
3129 " (extends previous samples)", GST_TIME_ARGS (gst_ts));
3133 initial_offset = *running_offset;
3135 sample = stream->samples + stream->n_samples;
3136 for (i = 0; i < samples_count; i++) {
3137 guint32 dur, size, sflags, ct;
3139 /* first read sample data */
3140 if (flags & TR_SAMPLE_DURATION) {
3141 dur = QT_UINT32 (data + dur_offset);
3143 dur = d_sample_duration;
3145 if (flags & TR_SAMPLE_SIZE) {
3146 size = QT_UINT32 (data + size_offset);
3148 size = d_sample_size;
3150 if (flags & TR_FIRST_SAMPLE_FLAGS) {
3152 sflags = first_flags;
3154 sflags = d_sample_flags;
3156 } else if (flags & TR_SAMPLE_FLAGS) {
3157 sflags = QT_UINT32 (data + flags_offset);
3159 sflags = d_sample_flags;
3161 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
3162 ct = QT_UINT32 (data + ct_offset);
3168 /* fill the sample information */
3169 sample->offset = *running_offset;
3170 sample->pts_offset = ct;
3171 sample->size = size;
3172 sample->timestamp = timestamp;
3173 sample->duration = dur;
3174 /* sample-is-difference-sample */
3175 /* ismv seems to use 0x40 for keyframe, 0xc0 for non-keyframe,
3176 * now idea how it relates to bitfield other than massive LE/BE confusion */
3177 sample->keyframe = ismv ? ((sflags & 0xff) == 0x40) : !(sflags & 0x10000);
3178 *running_offset += size;
3180 stream->duration_moof += dur;
3184 /* Update total duration if needed */
3185 check_update_duration (qtdemux, QTSTREAMTIME_TO_GSTTIME (stream, timestamp));
3187 /* Pre-emptively figure out size of mdat based on trun information.
3188 * If the [mdat] atom is effectivelly read, it will be replaced by the actual
3189 * size, else we will still be able to use this when dealing with gap'ed
3191 qtdemux->mdatleft = *running_offset - initial_offset;
3193 stream->n_samples += samples_count;
3194 stream->n_samples_moof += samples_count;
3196 if (stream->pending_seek != NULL)
3197 stream->pending_seek = NULL;
3203 GST_WARNING_OBJECT (qtdemux, "failed to parse trun");
3208 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
3214 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
3215 "be larger than %uMB (broken file?)", stream->n_samples,
3216 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
3221 /* find stream with @id */
3222 static inline QtDemuxStream *
3223 qtdemux_find_stream (GstQTDemux * qtdemux, guint32 id)
3225 QtDemuxStream *stream;
3229 if (G_UNLIKELY (!id)) {
3230 GST_DEBUG_OBJECT (qtdemux, "invalid track id 0");
3234 /* try to get it fast and simple */
3235 if (G_LIKELY (id <= qtdemux->n_streams)) {
3236 stream = qtdemux->streams[id - 1];
3237 if (G_LIKELY (stream->track_id == id))
3241 /* linear search otherwise */
3242 for (i = 0; i < qtdemux->n_streams; i++) {
3243 stream = qtdemux->streams[i];
3244 if (stream->track_id == id)
3247 if (qtdemux->mss_mode) {
3248 /* mss should have only 1 stream anyway */
3249 return qtdemux->streams[0];
3256 qtdemux_parse_mfhd (GstQTDemux * qtdemux, GstByteReader * mfhd,
3257 guint32 * fragment_number)
3259 if (!gst_byte_reader_skip (mfhd, 4))
3261 if (!gst_byte_reader_get_uint32_be (mfhd, fragment_number))
3266 GST_WARNING_OBJECT (qtdemux, "Failed to parse mfhd atom");
3272 qtdemux_parse_tfhd (GstQTDemux * qtdemux, GstByteReader * tfhd,
3273 QtDemuxStream ** stream, guint32 * default_sample_duration,
3274 guint32 * default_sample_size, guint32 * default_sample_flags,
3275 gint64 * base_offset)
3278 guint32 track_id = 0;
3280 if (!gst_byte_reader_skip (tfhd, 1) ||
3281 !gst_byte_reader_get_uint24_be (tfhd, &flags))
3284 if (!gst_byte_reader_get_uint32_be (tfhd, &track_id))
3287 *stream = qtdemux_find_stream (qtdemux, track_id);
3288 if (G_UNLIKELY (!*stream))
3289 goto unknown_stream;
3291 if (flags & TF_DEFAULT_BASE_IS_MOOF)
3292 *base_offset = qtdemux->moof_offset;
3294 if (flags & TF_BASE_DATA_OFFSET)
3295 if (!gst_byte_reader_get_uint64_be (tfhd, (guint64 *) base_offset))
3298 /* obtain stream defaults */
3299 qtdemux_parse_trex (qtdemux, *stream,
3300 default_sample_duration, default_sample_size, default_sample_flags);
3302 /* FIXME: Handle TF_SAMPLE_DESCRIPTION_INDEX properly */
3303 if (flags & TF_SAMPLE_DESCRIPTION_INDEX)
3304 if (!gst_byte_reader_skip (tfhd, 4))
3307 if (flags & TF_DEFAULT_SAMPLE_DURATION)
3308 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_duration))
3311 if (flags & TF_DEFAULT_SAMPLE_SIZE)
3312 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_size))
3315 if (flags & TF_DEFAULT_SAMPLE_FLAGS)
3316 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_flags))
3323 GST_WARNING_OBJECT (qtdemux, "invalid track fragment header");
3328 GST_DEBUG_OBJECT (qtdemux, "unknown stream in tfhd");
3334 qtdemux_parse_tfdt (GstQTDemux * qtdemux, GstByteReader * br,
3335 guint64 * decode_time)
3337 guint32 version = 0;
3339 if (!gst_byte_reader_get_uint32_be (br, &version))
3344 if (!gst_byte_reader_get_uint64_be (br, decode_time))
3347 guint32 dec_time = 0;
3348 if (!gst_byte_reader_get_uint32_be (br, &dec_time))
3350 *decode_time = dec_time;
3353 GST_INFO_OBJECT (qtdemux, "Track fragment decode time: %" G_GUINT64_FORMAT,
3360 GST_DEBUG_OBJECT (qtdemux, "parsing tfdt failed");
3365 /* Returns a pointer to a GstStructure containing the properties of
3366 * the stream sample identified by @sample_index. The caller must unref
3367 * the returned object after use. Returns NULL if unsuccessful. */
3368 static GstStructure *
3369 qtdemux_get_cenc_sample_properties (GstQTDemux * qtdemux,
3370 QtDemuxStream * stream, guint sample_index)
3372 QtDemuxCencSampleSetInfo *info = NULL;
3374 g_return_val_if_fail (stream != NULL, NULL);
3375 g_return_val_if_fail (stream->protected, NULL);
3376 g_return_val_if_fail (stream->protection_scheme_info != NULL, NULL);
3378 info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
3380 /* Currently, cenc properties for groups of samples are not supported, so
3381 * simply return a copy of the default sample properties */
3382 return gst_structure_copy (info->default_properties);
3385 /* Parses the sizes of sample auxiliary information contained within a stream,
3386 * as given in a saiz box. Returns array of sample_count guint8 size values,
3387 * or NULL on failure */
3389 qtdemux_parse_saiz (GstQTDemux * qtdemux, QtDemuxStream * stream,
3390 GstByteReader * br, guint32 * sample_count)
3394 guint8 default_info_size;
3396 g_return_val_if_fail (qtdemux != NULL, NULL);
3397 g_return_val_if_fail (stream != NULL, NULL);
3398 g_return_val_if_fail (br != NULL, NULL);
3399 g_return_val_if_fail (sample_count != NULL, NULL);
3401 if (!gst_byte_reader_get_uint32_be (br, &flags))
3405 /* aux_info_type and aux_info_type_parameter are ignored */
3406 if (!gst_byte_reader_skip (br, 8))
3410 if (!gst_byte_reader_get_uint8 (br, &default_info_size))
3412 GST_DEBUG_OBJECT (qtdemux, "default_info_size: %u", default_info_size);
3414 if (!gst_byte_reader_get_uint32_be (br, sample_count))
3416 GST_DEBUG_OBJECT (qtdemux, "sample_count: %u", *sample_count);
3419 if (default_info_size == 0) {
3420 if (!gst_byte_reader_dup_data (br, *sample_count, &info_sizes)) {
3424 info_sizes = g_new (guint8, *sample_count);
3425 memset (info_sizes, default_info_size, *sample_count);
3431 /* Parses the offset of sample auxiliary information contained within a stream,
3432 * as given in a saio box. Returns TRUE if successful; FALSE otherwise. */
3434 qtdemux_parse_saio (GstQTDemux * qtdemux, QtDemuxStream * stream,
3435 GstByteReader * br, guint32 * info_type, guint32 * info_type_parameter,
3440 guint32 aux_info_type = 0;
3441 guint32 aux_info_type_parameter = 0;
3442 guint32 entry_count;
3445 const guint8 *aux_info_type_data = NULL;
3447 g_return_val_if_fail (qtdemux != NULL, FALSE);
3448 g_return_val_if_fail (stream != NULL, FALSE);
3449 g_return_val_if_fail (br != NULL, FALSE);
3450 g_return_val_if_fail (offset != NULL, FALSE);
3452 if (!gst_byte_reader_get_uint8 (br, &version))
3455 if (!gst_byte_reader_get_uint24_be (br, &flags))
3460 if (!gst_byte_reader_get_data (br, 4, &aux_info_type_data))
3462 aux_info_type = QT_FOURCC (aux_info_type_data);
3464 if (!gst_byte_reader_get_uint32_be (br, &aux_info_type_parameter))
3466 } else if (stream->protected) {
3467 aux_info_type = stream->protection_scheme_type;
3469 aux_info_type = stream->fourcc;
3473 *info_type = aux_info_type;
3474 if (info_type_parameter)
3475 *info_type_parameter = aux_info_type_parameter;
3477 GST_DEBUG_OBJECT (qtdemux, "aux_info_type: '%" GST_FOURCC_FORMAT "', "
3478 "aux_info_type_parameter: %#06x",
3479 GST_FOURCC_ARGS (aux_info_type), aux_info_type_parameter);
3481 if (!gst_byte_reader_get_uint32_be (br, &entry_count))
3484 if (entry_count != 1) {
3485 GST_ERROR_OBJECT (qtdemux, "multiple offsets are not supported");
3490 if (!gst_byte_reader_get_uint32_be (br, &off_32))
3492 *offset = (guint64) off_32;
3494 if (!gst_byte_reader_get_uint64_be (br, &off_64))
3499 GST_DEBUG_OBJECT (qtdemux, "offset: %" G_GUINT64_FORMAT, *offset);
3504 qtdemux_gst_structure_free (GstStructure * gststructure)
3507 gst_structure_free (gststructure);
3511 /* Parses auxiliary information relating to samples protected using Common
3512 * Encryption (cenc); the format of this information is defined in
3513 * ISO/IEC 23001-7. Returns TRUE if successful; FALSE otherwise. */
3515 qtdemux_parse_cenc_aux_info (GstQTDemux * qtdemux, QtDemuxStream * stream,
3516 GstByteReader * br, guint8 * info_sizes, guint32 sample_count)
3518 QtDemuxCencSampleSetInfo *ss_info = NULL;
3522 g_return_val_if_fail (qtdemux != NULL, FALSE);
3523 g_return_val_if_fail (stream != NULL, FALSE);
3524 g_return_val_if_fail (br != NULL, FALSE);
3525 g_return_val_if_fail (stream->protected, FALSE);
3526 g_return_val_if_fail (stream->protection_scheme_info != NULL, FALSE);
3528 ss_info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
3530 if (ss_info->crypto_info) {
3531 GST_LOG_OBJECT (qtdemux, "unreffing existing crypto_info");
3532 g_ptr_array_free (ss_info->crypto_info, TRUE);
3535 ss_info->crypto_info =
3536 g_ptr_array_new_full (sample_count,
3537 (GDestroyNotify) qtdemux_gst_structure_free);
3539 for (i = 0; i < sample_count; ++i) {
3540 GstStructure *properties;
3541 guint16 n_subsamples = 0;
3546 properties = qtdemux_get_cenc_sample_properties (qtdemux, stream, i);
3547 if (properties == NULL) {
3548 GST_ERROR_OBJECT (qtdemux, "failed to get properties for sample %u", i);
3551 if (!gst_structure_get_uint (properties, "iv_size", &iv_size)) {
3552 GST_ERROR_OBJECT (qtdemux, "failed to get iv_size for sample %u", i);
3553 gst_structure_free (properties);
3556 if (!gst_byte_reader_dup_data (br, iv_size, &data)) {
3557 GST_ERROR_OBJECT (qtdemux, "failed to get IV for sample %u", i);
3558 gst_structure_free (properties);
3561 buf = gst_buffer_new_wrapped (data, iv_size);
3562 gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL);
3563 gst_buffer_unref (buf);
3564 size = info_sizes[i];
3565 if (size > iv_size) {
3566 if (!gst_byte_reader_get_uint16_be (br, &n_subsamples)
3567 || !(n_subsamples > 0)) {
3568 gst_structure_free (properties);
3569 GST_ERROR_OBJECT (qtdemux,
3570 "failed to get subsample count for sample %u", i);
3573 GST_LOG_OBJECT (qtdemux, "subsample count: %u", n_subsamples);
3574 if (!gst_byte_reader_dup_data (br, n_subsamples * 6, &data)) {
3575 GST_ERROR_OBJECT (qtdemux, "failed to get subsample data for sample %u",
3577 gst_structure_free (properties);
3580 buf = gst_buffer_new_wrapped (data, n_subsamples * 6);
3582 gst_structure_free (properties);
3585 gst_structure_set (properties,
3586 "subsample_count", G_TYPE_UINT, n_subsamples,
3587 "subsamples", GST_TYPE_BUFFER, buf, NULL);
3588 gst_buffer_unref (buf);
3590 gst_structure_set (properties, "subsample_count", G_TYPE_UINT, 0, NULL);
3592 g_ptr_array_add (ss_info->crypto_info, properties);
3597 /* Converts a UUID in raw byte form to a string representation, as defined in
3598 * RFC 4122. The caller takes ownership of the returned string and is
3599 * responsible for freeing it after use. */
3601 qtdemux_uuid_bytes_to_string (gconstpointer uuid_bytes)
3603 const guint8 *uuid = (const guint8 *) uuid_bytes;
3605 return g_strdup_printf ("%02x%02x%02x%02x-%02x%02x-%02x%02x-"
3606 "%02x%02x-%02x%02x%02x%02x%02x%02x",
3607 uuid[0], uuid[1], uuid[2], uuid[3],
3608 uuid[4], uuid[5], uuid[6], uuid[7],
3609 uuid[8], uuid[9], uuid[10], uuid[11],
3610 uuid[12], uuid[13], uuid[14], uuid[15]);
3613 /* Parses a Protection System Specific Header box (pssh), as defined in the
3614 * Common Encryption (cenc) standard (ISO/IEC 23001-7), which contains
3615 * information needed by a specific content protection system in order to
3616 * decrypt cenc-protected tracks. Returns TRUE if successful; FALSE
3619 qtdemux_parse_pssh (GstQTDemux * qtdemux, GNode * node)
3621 gchar *sysid_string;
3622 guint32 pssh_size = QT_UINT32 (node->data);
3623 GstBuffer *pssh = NULL;
3624 GstEvent *event = NULL;
3625 guint32 parent_box_type;
3628 if (G_UNLIKELY (pssh_size < 32U)) {
3629 GST_ERROR_OBJECT (qtdemux, "invalid box size");
3634 qtdemux_uuid_bytes_to_string ((const guint8 *) node->data + 12);
3636 gst_qtdemux_append_protection_system_id (qtdemux, sysid_string);
3638 pssh = gst_buffer_new_wrapped (g_memdup (node->data, pssh_size), pssh_size);
3639 GST_LOG_OBJECT (qtdemux, "cenc pssh size: %" G_GSIZE_FORMAT,
3640 gst_buffer_get_size (pssh));
3642 parent_box_type = QT_FOURCC ((const guint8 *) node->parent->data + 4);
3644 /* Push an event containing the pssh box onto the queues of all streams. */
3645 event = gst_event_new_protection (sysid_string, pssh,
3646 (parent_box_type == FOURCC_moov) ? "isobmff/moov" : "isobmff/moof");
3647 for (i = 0; i < qtdemux->n_streams; ++i) {
3648 g_queue_push_tail (&qtdemux->streams[i]->protection_scheme_event_queue,
3649 gst_event_ref (event));
3651 g_free (sysid_string);
3652 gst_event_unref (event);
3653 gst_buffer_unref (pssh);
3658 qtdemux_parse_moof (GstQTDemux * qtdemux, const guint8 * buffer, guint length,
3659 guint64 moof_offset, QtDemuxStream * stream)
3661 GNode *moof_node, *traf_node, *tfhd_node, *trun_node, *tfdt_node, *mfhd_node;
3663 GstByteReader mfhd_data, trun_data, tfhd_data, tfdt_data;
3664 GNode *saiz_node, *saio_node, *pssh_node;
3665 GstByteReader saiz_data, saio_data;
3666 guint32 ds_size = 0, ds_duration = 0, ds_flags = 0;
3667 gint64 base_offset, running_offset;
3670 /* NOTE @stream ignored */
3672 moof_node = g_node_new ((guint8 *) buffer);
3673 qtdemux_parse_node (qtdemux, moof_node, buffer, length);
3674 qtdemux_node_dump (qtdemux, moof_node);
3676 /* Get fragment number from mfhd and check it's valid */
3678 qtdemux_tree_get_child_by_type_full (moof_node, FOURCC_mfhd, &mfhd_data);
3679 if (mfhd_node == NULL)
3681 if (!qtdemux_parse_mfhd (qtdemux, &mfhd_data, &frag_num))
3683 GST_DEBUG_OBJECT (qtdemux, "Fragment #%d", frag_num);
3685 /* unknown base_offset to start with */
3686 base_offset = running_offset = -1;
3687 traf_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_traf);
3689 guint64 decode_time = 0;
3691 /* Fragment Header node */
3693 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfhd,
3697 if (!qtdemux_parse_tfhd (qtdemux, &tfhd_data, &stream, &ds_duration,
3698 &ds_size, &ds_flags, &base_offset))
3701 /* The following code assumes at most a single set of sample auxiliary
3702 * data in the fragment (consisting of a saiz box and a corresponding saio
3703 * box); in theory, however, there could be multiple sets of sample
3704 * auxiliary data in a fragment. */
3706 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saiz,
3709 guint32 info_type = 0;
3711 guint32 info_type_parameter = 0;
3713 g_free (qtdemux->cenc_aux_info_sizes);
3715 qtdemux->cenc_aux_info_sizes =
3716 qtdemux_parse_saiz (qtdemux, stream, &saiz_data,
3717 &qtdemux->cenc_aux_sample_count);
3718 if (qtdemux->cenc_aux_info_sizes == NULL) {
3719 GST_ERROR_OBJECT (qtdemux, "failed to parse saiz box");
3723 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saio,
3726 GST_ERROR_OBJECT (qtdemux, "saiz box without a corresponding saio box");
3727 g_free (qtdemux->cenc_aux_info_sizes);
3728 qtdemux->cenc_aux_info_sizes = NULL;
3732 if (G_UNLIKELY (!qtdemux_parse_saio (qtdemux, stream, &saio_data,
3733 &info_type, &info_type_parameter, &offset))) {
3734 GST_ERROR_OBJECT (qtdemux, "failed to parse saio box");
3735 g_free (qtdemux->cenc_aux_info_sizes);
3736 qtdemux->cenc_aux_info_sizes = NULL;
3739 if (base_offset > -1 && base_offset > qtdemux->moof_offset)
3740 offset += (guint64) (base_offset - qtdemux->moof_offset);
3741 if (info_type == FOURCC_cenc && info_type_parameter == 0U) {
3743 if (offset > length) {
3744 GST_DEBUG_OBJECT (qtdemux, "cenc auxiliary info stored out of moof");
3745 qtdemux->cenc_aux_info_offset = offset;
3747 gst_byte_reader_init (&br, buffer + offset, length - offset);
3748 if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
3749 qtdemux->cenc_aux_info_sizes,
3750 qtdemux->cenc_aux_sample_count)) {
3751 GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
3752 g_free (qtdemux->cenc_aux_info_sizes);
3753 qtdemux->cenc_aux_info_sizes = NULL;
3761 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfdt,
3764 /* We'll use decode_time to interpolate timestamps
3765 * in case the input timestamps are missing */
3766 qtdemux_parse_tfdt (qtdemux, &tfdt_data, &decode_time);
3768 GST_DEBUG_OBJECT (qtdemux, "decode time %" G_GINT64_FORMAT
3769 " (%" GST_TIME_FORMAT ")", decode_time,
3770 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, decode_time)));
3772 /* Discard the fragment buffer timestamp info to avoid using it.
3773 * Rely on tfdt instead as it is more accurate than the timestamp
3774 * that is fetched from a manifest/playlist and is usually
3776 qtdemux->fragment_start = -1;
3779 if (G_UNLIKELY (!stream)) {
3780 /* we lost track of offset, we'll need to regain it,
3781 * but can delay complaining until later or avoid doing so altogether */
3785 if (G_UNLIKELY (base_offset < -1))
3788 if (qtdemux->upstream_format_is_time)
3789 gst_qtdemux_stream_flush_samples_data (qtdemux, stream);
3791 /* initialise moof sample data */
3792 stream->n_samples_moof = 0;
3793 stream->duration_moof = 0;
3795 /* Track Run node */
3797 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_trun,
3800 qtdemux_parse_trun (qtdemux, &trun_data, stream,
3801 ds_duration, ds_size, ds_flags, moof_offset, length, &base_offset,
3802 &running_offset, decode_time);
3803 /* iterate all siblings */
3804 trun_node = qtdemux_tree_get_sibling_by_type_full (trun_node, FOURCC_trun,
3808 uuid_node = qtdemux_tree_get_child_by_type (traf_node, FOURCC_uuid);
3810 guint8 *uuid_buffer = (guint8 *) uuid_node->data;
3811 guint32 box_length = QT_UINT32 (uuid_buffer);
3813 qtdemux_parse_uuid (qtdemux, uuid_buffer, box_length);
3816 /* if no new base_offset provided for next traf,
3817 * base is end of current traf */
3818 base_offset = running_offset;
3819 running_offset = -1;
3821 if (stream->n_samples_moof && stream->duration_moof)
3822 stream->new_caps = TRUE;
3825 /* iterate all siblings */
3826 traf_node = qtdemux_tree_get_sibling_by_type (traf_node, FOURCC_traf);
3829 /* parse any protection system info */
3830 pssh_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_pssh);
3832 GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
3833 qtdemux_parse_pssh (qtdemux, pssh_node);
3834 pssh_node = qtdemux_tree_get_sibling_by_type (pssh_node, FOURCC_pssh);
3837 g_node_destroy (moof_node);
3842 GST_DEBUG_OBJECT (qtdemux, "missing tfhd box");
3847 GST_DEBUG_OBJECT (qtdemux, "Missing mfhd box");
3852 GST_DEBUG_OBJECT (qtdemux, "lost offset");
3857 g_node_destroy (moof_node);
3858 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
3859 (_("This file is corrupt and cannot be played.")), (NULL));
3865 /* might be used if some day we actually use mfra & co
3866 * for random access to fragments,
3867 * but that will require quite some modifications and much less relying
3868 * on a sample array */
3872 qtdemux_parse_tfra (GstQTDemux * qtdemux, GNode * tfra_node)
3874 QtDemuxStream *stream;
3875 guint32 ver_flags, track_id, len, num_entries, i;
3876 guint value_size, traf_size, trun_size, sample_size;
3877 guint64 time = 0, moof_offset = 0;
3879 GstBuffer *buf = NULL;
3884 gst_byte_reader_init (&tfra, tfra_node->data, QT_UINT32 (tfra_node->data));
3886 if (!gst_byte_reader_skip (&tfra, 8))
3889 if (!gst_byte_reader_get_uint32_be (&tfra, &ver_flags))
3892 if (!gst_byte_reader_get_uint32_be (&tfra, &track_id)
3893 || !gst_byte_reader_get_uint32_be (&tfra, &len)
3894 || !gst_byte_reader_get_uint32_be (&tfra, &num_entries))
3897 GST_DEBUG_OBJECT (qtdemux, "parsing tfra box for track id %u", track_id);
3899 stream = qtdemux_find_stream (qtdemux, track_id);
3901 goto unknown_trackid;
3903 value_size = ((ver_flags >> 24) == 1) ? sizeof (guint64) : sizeof (guint32);
3904 sample_size = (len & 3) + 1;
3905 trun_size = ((len & 12) >> 2) + 1;
3906 traf_size = ((len & 48) >> 4) + 1;
3908 GST_DEBUG_OBJECT (qtdemux, "%u entries, sizes: value %u, traf %u, trun %u, "
3909 "sample %u", num_entries, value_size, traf_size, trun_size, sample_size);
3911 if (num_entries == 0)
3914 if (!qt_atom_parser_has_chunks (&tfra, num_entries,
3915 value_size + value_size + traf_size + trun_size + sample_size))
3918 g_free (stream->ra_entries);
3919 stream->ra_entries = g_new (QtDemuxRandomAccessEntry, num_entries);
3920 stream->n_ra_entries = num_entries;
3922 for (i = 0; i < num_entries; i++) {
3923 qt_atom_parser_get_offset (&tfra, value_size, &time);
3924 qt_atom_parser_get_offset (&tfra, value_size, &moof_offset);
3925 qt_atom_parser_get_uint_with_size_unchecked (&tfra, traf_size);
3926 qt_atom_parser_get_uint_with_size_unchecked (&tfra, trun_size);
3927 qt_atom_parser_get_uint_with_size_unchecked (&tfra, sample_size);
3929 time = QTSTREAMTIME_TO_GSTTIME (stream, time);
3931 GST_LOG_OBJECT (qtdemux, "fragment time: %" GST_TIME_FORMAT ", "
3932 " moof_offset: %" G_GUINT64_FORMAT, GST_TIME_ARGS (time), moof_offset);
3934 stream->ra_entries[i].ts = time;
3935 stream->ra_entries[i].moof_offset = moof_offset;
3937 /* don't want to go through the entire file and read all moofs at startup */
3939 ret = gst_qtdemux_pull_atom (qtdemux, moof_offset, 0, &buf);
3940 if (ret != GST_FLOW_OK)
3942 qtdemux_parse_moof (qtdemux, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf),
3943 moof_offset, stream);
3944 gst_buffer_unref (buf);
3948 check_update_duration (qtdemux, time);
3955 GST_WARNING_OBJECT (qtdemux, "Couldn't find stream for track %u", track_id);
3960 GST_WARNING_OBJECT (qtdemux, "broken traf box, ignoring");
3965 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
3971 qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux)
3973 GstMapInfo mfro_map = GST_MAP_INFO_INIT;
3974 GstMapInfo mfra_map = GST_MAP_INFO_INIT;
3975 GstBuffer *mfro = NULL, *mfra = NULL;
3977 gboolean ret = FALSE;
3978 GNode *mfra_node, *tfra_node;
3979 guint64 mfra_offset = 0;
3980 guint32 fourcc, mfra_size;
3983 /* query upstream size in bytes */
3984 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &len))
3985 goto size_query_failed;
3987 /* mfro box should be at the very end of the file */
3988 flow = gst_qtdemux_pull_atom (qtdemux, len - 16, 16, &mfro);
3989 if (flow != GST_FLOW_OK)
3992 gst_buffer_map (mfro, &mfro_map, GST_MAP_READ);
3994 fourcc = QT_FOURCC (mfro_map.data + 4);
3995 if (fourcc != FOURCC_mfro)
3998 GST_INFO_OBJECT (qtdemux, "Found mfro box");
3999 if (mfro_map.size < 16)
4000 goto invalid_mfro_size;
4002 mfra_size = QT_UINT32 (mfro_map.data + 12);
4003 if (mfra_size >= len)
4004 goto invalid_mfra_size;
4006 mfra_offset = len - mfra_size;
4008 GST_INFO_OBJECT (qtdemux, "mfra offset: %" G_GUINT64_FORMAT ", size %u",
4009 mfra_offset, mfra_size);
4011 /* now get and parse mfra box */
4012 flow = gst_qtdemux_pull_atom (qtdemux, mfra_offset, mfra_size, &mfra);
4013 if (flow != GST_FLOW_OK)
4016 gst_buffer_map (mfra, &mfra_map, GST_MAP_READ);
4018 mfra_node = g_node_new ((guint8 *) mfra_map.data);
4019 qtdemux_parse_node (qtdemux, mfra_node, mfra_map.data, mfra_map.size);
4021 tfra_node = qtdemux_tree_get_child_by_type (mfra_node, FOURCC_tfra);
4024 qtdemux_parse_tfra (qtdemux, tfra_node);
4025 /* iterate all siblings */
4026 tfra_node = qtdemux_tree_get_sibling_by_type (tfra_node, FOURCC_tfra);
4028 g_node_destroy (mfra_node);
4030 GST_INFO_OBJECT (qtdemux, "parsed movie fragment random access box (mfra)");
4036 if (mfro_map.memory != NULL)
4037 gst_buffer_unmap (mfro, &mfro_map);
4038 gst_buffer_unref (mfro);
4041 if (mfra_map.memory != NULL)
4042 gst_buffer_unmap (mfra, &mfra_map);
4043 gst_buffer_unref (mfra);
4050 GST_WARNING_OBJECT (qtdemux, "could not query upstream size");
4055 GST_WARNING_OBJECT (qtdemux, "mfro size is too small");
4060 GST_WARNING_OBJECT (qtdemux, "mfra_size in mfro box is invalid");
4065 GST_WARNING_OBJECT (qtdemux, "bogus mfra offset or size, broken file");
4071 add_offset (guint64 offset, guint64 advance)
4073 /* Avoid 64-bit overflow by clamping */
4074 if (offset > G_MAXUINT64 - advance)
4076 return offset + advance;
4079 static GstFlowReturn
4080 gst_qtdemux_loop_state_header (GstQTDemux * qtdemux)
4084 GstBuffer *buf = NULL;
4085 GstFlowReturn ret = GST_FLOW_OK;
4086 guint64 cur_offset = qtdemux->offset;
4089 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, 16, &buf);
4090 if (G_UNLIKELY (ret != GST_FLOW_OK))
4092 gst_buffer_map (buf, &map, GST_MAP_READ);
4093 if (G_LIKELY (map.size >= 8))
4094 extract_initial_length_and_fourcc (map.data, map.size, &length, &fourcc);
4095 gst_buffer_unmap (buf, &map);
4096 gst_buffer_unref (buf);
4098 /* maybe we already got most we needed, so only consider this eof */
4099 if (G_UNLIKELY (length == 0)) {
4100 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
4101 (_("Invalid atom size.")),
4102 ("Header atom '%" GST_FOURCC_FORMAT "' has empty length",
4103 GST_FOURCC_ARGS (fourcc)));
4110 /* record for later parsing when needed */
4111 if (!qtdemux->moof_offset) {
4112 qtdemux->moof_offset = qtdemux->offset;
4114 if (qtdemux_pull_mfro_mfra (qtdemux)) {
4117 qtdemux->offset += length; /* skip moof and keep going */
4119 if (qtdemux->got_moov) {
4120 GST_INFO_OBJECT (qtdemux, "moof header, got moov, done with headers");
4131 GST_LOG_OBJECT (qtdemux,
4132 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
4133 GST_FOURCC_ARGS (fourcc), cur_offset);
4134 qtdemux->offset = add_offset (qtdemux->offset, length);
4139 GstBuffer *moov = NULL;
4141 if (qtdemux->got_moov) {
4142 GST_DEBUG_OBJECT (qtdemux, "Skipping moov atom as we have one already");
4143 qtdemux->offset = add_offset (qtdemux->offset, length);
4147 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, length, &moov);
4148 if (ret != GST_FLOW_OK)
4150 gst_buffer_map (moov, &map, GST_MAP_READ);
4152 if (length != map.size) {
4153 /* Some files have a 'moov' atom at the end of the file which contains
4154 * a terminal 'free' atom where the body of the atom is missing.
4155 * Check for, and permit, this special case.
4157 if (map.size >= 8) {
4158 guint8 *final_data = map.data + (map.size - 8);
4159 guint32 final_length = QT_UINT32 (final_data);
4160 guint32 final_fourcc = QT_FOURCC (final_data + 4);
4162 if (final_fourcc == FOURCC_free
4163 && map.size + final_length - 8 == length) {
4164 /* Ok, we've found that special case. Allocate a new buffer with
4165 * that free atom actually present. */
4166 GstBuffer *newmoov = gst_buffer_new_and_alloc (length);
4167 gst_buffer_fill (newmoov, 0, map.data, map.size);
4168 gst_buffer_memset (newmoov, map.size, 0, final_length - 8);
4169 gst_buffer_unmap (moov, &map);
4170 gst_buffer_unref (moov);
4172 gst_buffer_map (moov, &map, GST_MAP_READ);
4177 if (length != map.size) {
4178 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4179 (_("This file is incomplete and cannot be played.")),
4180 ("We got less than expected (received %" G_GSIZE_FORMAT
4181 ", wanted %u, offset %" G_GUINT64_FORMAT ")", map.size,
4182 (guint) length, cur_offset));
4183 gst_buffer_unmap (moov, &map);
4184 gst_buffer_unref (moov);
4185 ret = GST_FLOW_ERROR;
4188 qtdemux->offset += length;
4190 qtdemux_parse_moov (qtdemux, map.data, length);
4191 qtdemux_node_dump (qtdemux, qtdemux->moov_node);
4193 qtdemux_parse_tree (qtdemux);
4194 g_node_destroy (qtdemux->moov_node);
4195 gst_buffer_unmap (moov, &map);
4196 gst_buffer_unref (moov);
4197 qtdemux->moov_node = NULL;
4198 qtdemux->got_moov = TRUE;
4204 GstBuffer *ftyp = NULL;
4206 /* extract major brand; might come in handy for ISO vs QT issues */
4207 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &ftyp);
4208 if (ret != GST_FLOW_OK)
4210 qtdemux->offset += length;
4211 gst_buffer_map (ftyp, &map, GST_MAP_READ);
4212 qtdemux_parse_ftyp (qtdemux, map.data, map.size);
4213 gst_buffer_unmap (ftyp, &map);
4214 gst_buffer_unref (ftyp);
4219 GstBuffer *uuid = NULL;
4221 /* uuid are extension atoms */
4222 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &uuid);
4223 if (ret != GST_FLOW_OK)
4225 qtdemux->offset += length;
4226 gst_buffer_map (uuid, &map, GST_MAP_READ);
4227 qtdemux_parse_uuid (qtdemux, map.data, map.size);
4228 gst_buffer_unmap (uuid, &map);
4229 gst_buffer_unref (uuid);
4234 GstBuffer *sidx = NULL;
4235 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &sidx);
4236 if (ret != GST_FLOW_OK)
4238 qtdemux->offset += length;
4239 gst_buffer_map (sidx, &map, GST_MAP_READ);
4240 qtdemux_parse_sidx (qtdemux, map.data, map.size);
4241 gst_buffer_unmap (sidx, &map);
4242 gst_buffer_unref (sidx);
4247 GstBuffer *unknown = NULL;
4249 GST_LOG_OBJECT (qtdemux,
4250 "unknown %08x '%" GST_FOURCC_FORMAT "' of size %" G_GUINT64_FORMAT
4251 " at %" G_GUINT64_FORMAT, fourcc, GST_FOURCC_ARGS (fourcc), length,
4253 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &unknown);
4254 if (ret != GST_FLOW_OK)
4256 gst_buffer_map (unknown, &map, GST_MAP_READ);
4257 GST_MEMDUMP ("Unknown tag", map.data, map.size);
4258 gst_buffer_unmap (unknown, &map);
4259 gst_buffer_unref (unknown);
4260 qtdemux->offset += length;
4266 if (ret == GST_FLOW_EOS && (qtdemux->got_moov || qtdemux->media_caps)) {
4267 /* digested all data, show what we have */
4268 qtdemux_prepare_streams (qtdemux);
4269 ret = qtdemux_expose_streams (qtdemux);
4271 qtdemux->state = QTDEMUX_STATE_MOVIE;
4272 GST_DEBUG_OBJECT (qtdemux, "switching state to STATE_MOVIE (%d)",
4279 /* Seeks to the previous keyframe of the indexed stream and
4280 * aligns other streams with respect to the keyframe timestamp
4281 * of indexed stream. Only called in case of Reverse Playback
4283 static GstFlowReturn
4284 gst_qtdemux_seek_to_previous_keyframe (GstQTDemux * qtdemux)
4287 guint32 seg_idx = 0, k_index = 0;
4288 guint32 ref_seg_idx, ref_k_index;
4289 GstClockTime k_pos = 0, last_stop = 0;
4290 QtDemuxSegment *seg = NULL;
4291 QtDemuxStream *ref_str = NULL;
4292 guint64 seg_media_start_mov; /* segment media start time in mov format */
4295 /* Now we choose an arbitrary stream, get the previous keyframe timestamp
4296 * and finally align all the other streams on that timestamp with their
4297 * respective keyframes */
4298 for (n = 0; n < qtdemux->n_streams; n++) {
4299 QtDemuxStream *str = qtdemux->streams[n];
4301 /* No candidate yet, take the first stream */
4307 /* So that stream has a segment, we prefer video streams */
4308 if (str->subtype == FOURCC_vide) {
4314 if (G_UNLIKELY (!ref_str)) {
4315 GST_DEBUG_OBJECT (qtdemux, "couldn't find any stream");
4319 if (G_UNLIKELY (!ref_str->from_sample)) {
4320 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of the file");
4324 /* So that stream has been playing from from_sample to to_sample. We will
4325 * get the timestamp of the previous sample and search for a keyframe before
4326 * that. For audio streams we do an arbitrary jump in the past (10 samples) */
4327 if (ref_str->subtype == FOURCC_vide) {
4328 k_index = gst_qtdemux_find_keyframe (qtdemux, ref_str,
4329 ref_str->from_sample - 1);
4331 if (ref_str->from_sample >= 10)
4332 k_index = ref_str->from_sample - 10;
4338 ref_str->samples[k_index].timestamp +
4339 ref_str->samples[k_index].pts_offset;
4341 /* get current segment for that stream */
4342 seg = &ref_str->segments[ref_str->segment_index];
4343 /* Use segment start in original timescale for comparisons */
4344 seg_media_start_mov = seg->trak_media_start;
4346 GST_LOG_OBJECT (qtdemux, "keyframe index %u ts %" G_GUINT64_FORMAT
4347 " seg start %" G_GUINT64_FORMAT " %" GST_TIME_FORMAT "\n",
4348 k_index, target_ts, seg_media_start_mov,
4349 GST_TIME_ARGS (seg->media_start));
4351 /* Crawl back through segments to find the one containing this I frame */
4352 while (target_ts < seg_media_start_mov) {
4353 GST_DEBUG_OBJECT (qtdemux,
4354 "keyframe position (sample %u) is out of segment %u " " target %"
4355 G_GUINT64_FORMAT " seg start %" G_GUINT64_FORMAT, k_index,
4356 ref_str->segment_index, target_ts, seg_media_start_mov);
4358 if (G_UNLIKELY (!ref_str->segment_index)) {
4359 /* Reached first segment, let's consider it's EOS */
4362 ref_str->segment_index--;
4363 seg = &ref_str->segments[ref_str->segment_index];
4364 /* Use segment start in original timescale for comparisons */
4365 seg_media_start_mov = seg->trak_media_start;
4367 /* Calculate time position of the keyframe and where we should stop */
4369 QTSTREAMTIME_TO_GSTTIME (ref_str,
4370 target_ts - seg->trak_media_start) + seg->time;
4372 QTSTREAMTIME_TO_GSTTIME (ref_str,
4373 ref_str->samples[ref_str->from_sample].timestamp -
4374 seg->trak_media_start) + seg->time;
4376 GST_DEBUG_OBJECT (qtdemux, "preferred stream played from sample %u, "
4377 "now going to sample %u (pts %" GST_TIME_FORMAT ")", ref_str->from_sample,
4378 k_index, GST_TIME_ARGS (k_pos));
4380 /* Set last_stop with the keyframe timestamp we pushed of that stream */
4381 qtdemux->segment.position = last_stop;
4382 GST_DEBUG_OBJECT (qtdemux, "last_stop now is %" GST_TIME_FORMAT,
4383 GST_TIME_ARGS (last_stop));
4385 if (G_UNLIKELY (last_stop < qtdemux->segment.start)) {
4386 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of segment");
4390 ref_seg_idx = ref_str->segment_index;
4391 ref_k_index = k_index;
4393 /* Align them all on this */
4394 for (n = 0; n < qtdemux->n_streams; n++) {
4396 GstClockTime seg_time = 0;
4397 QtDemuxStream *str = qtdemux->streams[n];
4399 /* aligning reference stream again might lead to backing up to yet another
4400 * keyframe (due to timestamp rounding issues),
4401 * potentially putting more load on downstream; so let's try to avoid */
4402 if (str == ref_str) {
4403 seg_idx = ref_seg_idx;
4404 seg = &str->segments[seg_idx];
4405 k_index = ref_k_index;
4406 GST_DEBUG_OBJECT (qtdemux, "reference stream %d segment %d, "
4407 "sample at index %d", n, ref_str->segment_index, k_index);
4409 seg_idx = gst_qtdemux_find_segment (qtdemux, str, k_pos);
4410 GST_DEBUG_OBJECT (qtdemux,
4411 "stream %d align segment %d for keyframe pos %" GST_TIME_FORMAT, n,
4412 seg_idx, GST_TIME_ARGS (k_pos));
4414 /* get segment and time in the segment */
4415 seg = &str->segments[seg_idx];
4416 seg_time = k_pos - seg->time;
4418 /* get the media time in the segment.
4419 * No adjustment for empty "filler" segments */
4420 if (seg->media_start != GST_CLOCK_TIME_NONE)
4421 seg_time += seg->media_start;
4423 /* get the index of the sample with media time */
4424 index = gst_qtdemux_find_index_linear (qtdemux, str, seg_time);
4425 GST_DEBUG_OBJECT (qtdemux,
4426 "stream %d sample for %" GST_TIME_FORMAT " at %u", n,
4427 GST_TIME_ARGS (seg_time), index);
4429 /* find previous keyframe */
4430 k_index = gst_qtdemux_find_keyframe (qtdemux, str, index);
4433 /* Remember until where we want to go */
4434 str->to_sample = str->from_sample - 1;
4435 /* Define our time position */
4437 str->samples[k_index].timestamp + str->samples[k_index].pts_offset;
4438 str->time_position = QTSTREAMTIME_TO_GSTTIME (str, target_ts) + seg->time;
4439 if (seg->media_start != GST_CLOCK_TIME_NONE)
4440 str->time_position -= seg->media_start;
4442 /* Now seek back in time */
4443 gst_qtdemux_move_stream (qtdemux, str, k_index);
4444 GST_DEBUG_OBJECT (qtdemux, "stream %d keyframe at %u, time position %"
4445 GST_TIME_FORMAT " playing from sample %u to %u", n, k_index,
4446 GST_TIME_ARGS (str->time_position), str->from_sample, str->to_sample);
4452 return GST_FLOW_EOS;
4456 * Gets the current qt segment start, stop and position for the
4457 * given time offset. This is used in update_segment()
4460 gst_qtdemux_stream_segment_get_boundaries (GstQTDemux * qtdemux,
4461 QtDemuxStream * stream, GstClockTime offset,
4462 GstClockTime * _start, GstClockTime * _stop, GstClockTime * _time)
4464 GstClockTime seg_time;
4465 GstClockTime start, stop, time;
4466 QtDemuxSegment *segment;
4468 segment = &stream->segments[stream->segment_index];
4470 /* get time in this segment */
4471 seg_time = (offset - segment->time) * segment->rate;
4473 GST_LOG_OBJECT (stream->pad, "seg_time %" GST_TIME_FORMAT,
4474 GST_TIME_ARGS (seg_time));
4476 if (G_UNLIKELY (seg_time > segment->duration)) {
4477 GST_LOG_OBJECT (stream->pad,
4478 "seg_time > segment->duration %" GST_TIME_FORMAT,
4479 GST_TIME_ARGS (segment->duration));
4480 seg_time = segment->duration;
4483 /* qtdemux->segment.stop is in outside-time-realm, whereas
4484 * segment->media_stop is in track-time-realm.
4486 * In order to compare the two, we need to bring segment.stop
4487 * into the track-time-realm
4489 * FIXME - does this comment still hold? Don't see any conversion here */
4491 stop = qtdemux->segment.stop;
4492 if (stop == GST_CLOCK_TIME_NONE)
4493 stop = qtdemux->segment.duration;
4494 if (stop == GST_CLOCK_TIME_NONE)
4495 stop = segment->media_stop;
4498 MIN (segment->media_stop, stop - segment->time + segment->media_start);
4500 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
4501 start = segment->time + seg_time;
4503 stop = start - seg_time + segment->duration;
4504 } else if (qtdemux->segment.rate >= 0) {
4505 start = MIN (segment->media_start + seg_time, stop);
4508 if (segment->media_start >= qtdemux->segment.start) {
4509 time = segment->time;
4511 time = segment->time + (qtdemux->segment.start - segment->media_start);
4514 start = MAX (segment->media_start, qtdemux->segment.start);
4515 stop = MIN (segment->media_start + seg_time, stop);
4524 * Updates the qt segment used for the stream and pushes a new segment event
4525 * downstream on this stream's pad.
4528 gst_qtdemux_stream_update_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
4529 gint seg_idx, GstClockTime offset, GstClockTime * _start,
4530 GstClockTime * _stop)
4532 QtDemuxSegment *segment;
4533 GstClockTime start = 0, stop = GST_CLOCK_TIME_NONE, time = 0;
4537 /* update the current segment */
4538 stream->segment_index = seg_idx;
4540 /* get the segment */
4541 segment = &stream->segments[seg_idx];
4543 if (G_UNLIKELY (offset < segment->time)) {
4544 GST_WARNING_OBJECT (stream->pad, "offset < segment->time %" GST_TIME_FORMAT,
4545 GST_TIME_ARGS (segment->time));
4549 /* segment lies beyond total indicated duration */
4550 if (G_UNLIKELY (qtdemux->segment.duration != GST_CLOCK_TIME_NONE &&
4551 segment->time > qtdemux->segment.duration)) {
4552 GST_WARNING_OBJECT (stream->pad, "file duration %" GST_TIME_FORMAT
4553 " < segment->time %" GST_TIME_FORMAT,
4554 GST_TIME_ARGS (qtdemux->segment.duration),
4555 GST_TIME_ARGS (segment->time));
4559 gst_qtdemux_stream_segment_get_boundaries (qtdemux, stream, offset,
4560 &start, &stop, &time);
4562 GST_DEBUG_OBJECT (stream->pad, "new segment %d from %" GST_TIME_FORMAT
4563 " to %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT, seg_idx,
4564 GST_TIME_ARGS (start), GST_TIME_ARGS (stop), GST_TIME_ARGS (time));
4566 /* combine global rate with that of the segment */
4567 rate = segment->rate * qtdemux->segment.rate;
4569 /* Copy flags from main segment */
4570 stream->segment.flags = qtdemux->segment.flags;
4572 /* update the segment values used for clipping */
4573 stream->segment.offset = qtdemux->segment.offset;
4574 stream->segment.base = qtdemux->segment.base + stream->accumulated_base;
4575 stream->segment.applied_rate = qtdemux->segment.applied_rate;
4576 stream->segment.rate = rate;
4577 stream->segment.start = start + QTSTREAMTIME_TO_GSTTIME (stream,
4578 stream->cslg_shift);
4579 stream->segment.stop = stop + QTSTREAMTIME_TO_GSTTIME (stream,
4580 stream->cslg_shift);
4581 stream->segment.time = time;
4582 stream->segment.position = stream->segment.start;
4584 GST_DEBUG_OBJECT (stream->pad, "New segment: %" GST_SEGMENT_FORMAT,
4587 /* now prepare and send the segment */
4589 event = gst_event_new_segment (&stream->segment);
4590 if (qtdemux->segment_seqnum) {
4591 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
4593 gst_pad_push_event (stream->pad, event);
4594 /* assume we can send more data now */
4595 GST_PAD_LAST_FLOW_RETURN (stream->pad) = GST_FLOW_OK;
4596 /* clear to send tags on this pad now */
4597 gst_qtdemux_push_tags (qtdemux, stream);
4608 /* activate the given segment number @seg_idx of @stream at time @offset.
4609 * @offset is an absolute global position over all the segments.
4611 * This will push out a NEWSEGMENT event with the right values and
4612 * position the stream index to the first decodable sample before
4616 gst_qtdemux_activate_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
4617 guint32 seg_idx, GstClockTime offset)
4619 QtDemuxSegment *segment;
4620 guint32 index, kf_index;
4621 GstClockTime start = 0, stop = GST_CLOCK_TIME_NONE;
4623 GST_LOG_OBJECT (stream->pad, "activate segment %d, offset %" GST_TIME_FORMAT,
4624 seg_idx, GST_TIME_ARGS (offset));
4626 if (!gst_qtdemux_stream_update_segment (qtdemux, stream, seg_idx, offset,
4630 segment = &stream->segments[stream->segment_index];
4632 /* in the fragmented case, we pick a fragment that starts before our
4633 * desired position and rely on downstream to wait for a keyframe
4634 * (FIXME: doesn't seem to work so well with ismv and wmv, as no parser; the
4635 * tfra entries tells us which trun/sample the key unit is in, but we don't
4636 * make use of this additional information at the moment) */
4637 if (qtdemux->fragmented) {
4638 stream->to_sample = G_MAXUINT32;
4642 /* We don't need to look for a sample in push-based */
4643 if (!qtdemux->pullbased)
4646 /* and move to the keyframe before the indicated media time of the
4648 if (G_LIKELY (!QTSEGMENT_IS_EMPTY (segment))) {
4649 if (qtdemux->segment.rate >= 0) {
4650 index = gst_qtdemux_find_index_linear (qtdemux, stream, start);
4651 stream->to_sample = G_MAXUINT32;
4652 GST_DEBUG_OBJECT (stream->pad,
4653 "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
4654 GST_TIME_FORMAT, GST_TIME_ARGS (start), index,
4655 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
4657 index = gst_qtdemux_find_index_linear (qtdemux, stream, stop);
4658 stream->to_sample = index;
4659 GST_DEBUG_OBJECT (stream->pad,
4660 "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
4661 GST_TIME_FORMAT, GST_TIME_ARGS (stop), index,
4662 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
4665 GST_DEBUG_OBJECT (stream->pad, "No need to look for keyframe, "
4666 "this is an empty segment");
4670 /* gst_qtdemux_parse_sample () called from gst_qtdemux_find_index_linear ()
4671 * encountered an error and printed a message so we return appropriately */
4675 /* we're at the right spot */
4676 if (index == stream->sample_index) {
4677 GST_DEBUG_OBJECT (stream->pad, "we are at the right index");
4681 /* find keyframe of the target index */
4682 kf_index = gst_qtdemux_find_keyframe (qtdemux, stream, index);
4685 /* indent does stupid stuff with stream->samples[].timestamp */
4687 /* if we move forwards, we don't have to go back to the previous
4688 * keyframe since we already sent that. We can also just jump to
4689 * the keyframe right before the target index if there is one. */
4690 if (index > stream->sample_index) {
4691 /* moving forwards check if we move past a keyframe */
4692 if (kf_index > stream->sample_index) {
4693 GST_DEBUG_OBJECT (stream->pad,
4694 "moving forwards to keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" )", kf_index,
4695 GST_TIME_ARGS (QTSAMPLE_PTS(stream, &stream->samples[kf_index])),
4696 GST_TIME_ARGS (QTSAMPLE_DTS(stream, &stream->samples[kf_index])));
4697 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
4699 GST_DEBUG_OBJECT (stream->pad,
4700 "moving forwards, keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" ) already sent", kf_index,
4701 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[kf_index])),
4702 GST_TIME_ARGS (QTSAMPLE_DTS (stream, &stream->samples[kf_index])));
4705 GST_DEBUG_OBJECT (stream->pad,
4706 "moving backwards to keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" )", kf_index,
4707 GST_TIME_ARGS (QTSAMPLE_PTS(stream, &stream->samples[kf_index])),
4708 GST_TIME_ARGS (QTSAMPLE_DTS(stream, &stream->samples[kf_index])));
4709 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
4717 /* prepare to get the current sample of @stream, getting essential values.
4719 * This function will also prepare and send the segment when needed.
4721 * Return FALSE if the stream is EOS.
4726 gst_qtdemux_prepare_current_sample (GstQTDemux * qtdemux,
4727 QtDemuxStream * stream, gboolean * empty, guint64 * offset, guint * size,
4728 GstClockTime * dts, GstClockTime * pts, GstClockTime * duration,
4729 gboolean * keyframe)
4731 QtDemuxSample *sample;
4732 GstClockTime time_position;
4735 g_return_val_if_fail (stream != NULL, FALSE);
4737 time_position = stream->time_position;
4738 if (G_UNLIKELY (time_position == GST_CLOCK_TIME_NONE))
4741 seg_idx = stream->segment_index;
4742 if (G_UNLIKELY (seg_idx == -1)) {
4743 /* find segment corresponding to time_position if we are looking
4745 seg_idx = gst_qtdemux_find_segment (qtdemux, stream, time_position);
4748 /* different segment, activate it, sample_index will be set. */
4749 if (G_UNLIKELY (stream->segment_index != seg_idx))
4750 gst_qtdemux_activate_segment (qtdemux, stream, seg_idx, time_position);
4752 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (&stream->segments[stream->
4754 QtDemuxSegment *seg = &stream->segments[stream->segment_index];
4756 GST_LOG_OBJECT (qtdemux, "Empty segment activated,"
4757 " prepare empty sample");
4760 *pts = *dts = time_position;
4761 *duration = seg->duration - (time_position - seg->time);
4768 if (stream->sample_index == -1)
4769 stream->sample_index = 0;
4771 GST_LOG_OBJECT (qtdemux, "segment active, index = %u of %u",
4772 stream->sample_index, stream->n_samples);
4774 if (G_UNLIKELY (stream->sample_index >= stream->n_samples)) {
4775 if (!qtdemux->fragmented)
4778 GST_INFO_OBJECT (qtdemux, "out of samples, trying to add more");
4782 GST_OBJECT_LOCK (qtdemux);
4783 flow = qtdemux_add_fragmented_samples (qtdemux);
4784 GST_OBJECT_UNLOCK (qtdemux);
4786 if (flow != GST_FLOW_OK)
4789 while (stream->sample_index >= stream->n_samples);
4792 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
4793 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
4794 stream->sample_index);
4798 /* now get the info for the sample we're at */
4799 sample = &stream->samples[stream->sample_index];
4801 *dts = QTSAMPLE_DTS (stream, sample);
4802 *pts = QTSAMPLE_PTS (stream, sample);
4803 *offset = sample->offset;
4804 *size = sample->size;
4805 *duration = QTSAMPLE_DUR_DTS (stream, sample, *dts);
4806 *keyframe = QTSAMPLE_KEYFRAME (stream, sample);
4813 stream->time_position = GST_CLOCK_TIME_NONE;
4818 /* move to the next sample in @stream.
4820 * Moves to the next segment when needed.
4823 gst_qtdemux_advance_sample (GstQTDemux * qtdemux, QtDemuxStream * stream)
4825 QtDemuxSample *sample;
4826 QtDemuxSegment *segment;
4828 /* get current segment */
4829 segment = &stream->segments[stream->segment_index];
4831 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
4832 GST_DEBUG_OBJECT (qtdemux, "Empty segment, no samples to advance");
4836 if (G_UNLIKELY (stream->sample_index >= stream->to_sample)) {
4837 /* Mark the stream as EOS */
4838 GST_DEBUG_OBJECT (qtdemux,
4839 "reached max allowed sample %u, mark EOS", stream->to_sample);
4840 stream->time_position = GST_CLOCK_TIME_NONE;
4844 /* move to next sample */
4845 stream->sample_index++;
4846 stream->offset_in_sample = 0;
4848 /* reached the last sample, we need the next segment */
4849 if (G_UNLIKELY (stream->sample_index >= stream->n_samples))
4852 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
4853 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
4854 stream->sample_index);
4858 /* get next sample */
4859 sample = &stream->samples[stream->sample_index];
4861 /* see if we are past the segment */
4862 if (G_UNLIKELY (QTSAMPLE_DTS (stream, sample) >= segment->media_stop))
4865 if (QTSAMPLE_DTS (stream, sample) >= segment->media_start) {
4866 /* inside the segment, update time_position, looks very familiar to
4867 * GStreamer segments, doesn't it? */
4868 stream->time_position =
4869 QTSAMPLE_DTS (stream, sample) - segment->media_start + segment->time;
4871 /* not yet in segment, time does not yet increment. This means
4872 * that we are still prerolling keyframes to the decoder so it can
4873 * decode the first sample of the segment. */
4874 stream->time_position = segment->time;
4878 /* move to the next segment */
4881 GST_DEBUG_OBJECT (qtdemux, "segment %d ended ", stream->segment_index);
4883 if (stream->segment_index == stream->n_segments - 1) {
4884 /* are we at the end of the last segment, we're EOS */
4885 stream->time_position = GST_CLOCK_TIME_NONE;
4887 /* else we're only at the end of the current segment */
4888 stream->time_position = segment->stop_time;
4890 /* make sure we select a new segment */
4892 /* accumulate previous segments */
4893 if (GST_CLOCK_TIME_IS_VALID (stream->segment.stop))
4894 stream->accumulated_base +=
4895 (stream->segment.stop -
4896 stream->segment.start) / ABS (stream->segment.rate);
4898 stream->segment_index = -1;
4903 gst_qtdemux_sync_streams (GstQTDemux * demux)
4907 if (demux->n_streams <= 1)
4910 for (i = 0; i < demux->n_streams; i++) {
4911 QtDemuxStream *stream;
4912 GstClockTime end_time;
4914 stream = demux->streams[i];
4919 /* TODO advance time on subtitle streams here, if any some day */
4921 /* some clips/trailers may have unbalanced streams at the end,
4922 * so send EOS on shorter stream to prevent stalling others */
4924 /* do not mess with EOS if SEGMENT seeking */
4925 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT)
4928 if (demux->pullbased) {
4929 /* loop mode is sample time based */
4930 if (!STREAM_IS_EOS (stream))
4933 /* push mode is byte position based */
4934 if (stream->n_samples &&
4935 stream->samples[stream->n_samples - 1].offset >= demux->offset)
4939 if (stream->sent_eos)
4942 /* only act if some gap */
4943 end_time = stream->segments[stream->n_segments - 1].stop_time;
4944 GST_LOG_OBJECT (demux, "current position: %" GST_TIME_FORMAT
4945 ", stream end: %" GST_TIME_FORMAT,
4946 GST_TIME_ARGS (demux->segment.position), GST_TIME_ARGS (end_time));
4947 if (GST_CLOCK_TIME_IS_VALID (end_time)
4948 && (end_time + 2 * GST_SECOND < demux->segment.position)) {
4951 GST_DEBUG_OBJECT (demux, "sending EOS for stream %s",
4952 GST_PAD_NAME (stream->pad));
4953 stream->sent_eos = TRUE;
4954 event = gst_event_new_eos ();
4955 if (demux->segment_seqnum)
4956 gst_event_set_seqnum (event, demux->segment_seqnum);
4957 gst_pad_push_event (stream->pad, event);
4962 /* EOS and NOT_LINKED need to be combined. This means that we return:
4964 * GST_FLOW_NOT_LINKED: when all pads NOT_LINKED.
4965 * GST_FLOW_EOS: when all pads EOS or NOT_LINKED.
4967 static GstFlowReturn
4968 gst_qtdemux_combine_flows (GstQTDemux * demux, QtDemuxStream * stream,
4971 GST_LOG_OBJECT (demux, "flow return: %s", gst_flow_get_name (ret));
4974 ret = gst_flow_combiner_update_pad_flow (demux->flowcombiner, stream->pad,
4977 ret = gst_flow_combiner_update_flow (demux->flowcombiner, ret);
4979 GST_LOG_OBJECT (demux, "combined flow return: %s", gst_flow_get_name (ret));
4983 /* the input buffer metadata must be writable. Returns NULL when the buffer is
4984 * completely clipped
4986 * Should be used only with raw buffers */
4988 gst_qtdemux_clip_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
4991 guint64 start, stop, cstart, cstop, diff;
4992 GstClockTime pts, duration;
4994 gint num_rate, denom_rate;
4999 osize = size = gst_buffer_get_size (buf);
5002 /* depending on the type, setup the clip parameters */
5003 if (stream->subtype == FOURCC_soun) {
5004 frame_size = stream->bytes_per_frame;
5005 num_rate = GST_SECOND;
5006 denom_rate = (gint) stream->rate;
5008 } else if (stream->subtype == FOURCC_vide) {
5010 num_rate = stream->fps_n;
5011 denom_rate = stream->fps_d;
5016 if (frame_size <= 0)
5017 goto bad_frame_size;
5019 /* we can only clip if we have a valid pts */
5020 pts = GST_BUFFER_PTS (buf);
5021 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (pts)))
5024 duration = GST_BUFFER_DURATION (buf);
5026 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (duration))) {
5028 gst_util_uint64_scale_int (size / frame_size, num_rate, denom_rate);
5032 stop = start + duration;
5034 if (G_UNLIKELY (!gst_segment_clip (&stream->segment,
5035 GST_FORMAT_TIME, start, stop, &cstart, &cstop)))
5038 /* see if some clipping happened */
5039 diff = cstart - start;
5045 /* bring clipped time to samples and to bytes */
5046 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
5049 GST_DEBUG_OBJECT (qtdemux,
5050 "clipping start to %" GST_TIME_FORMAT " %"
5051 G_GUINT64_FORMAT " bytes", GST_TIME_ARGS (cstart), diff);
5057 diff = stop - cstop;
5062 /* bring clipped time to samples and then to bytes */
5063 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
5065 GST_DEBUG_OBJECT (qtdemux,
5066 "clipping stop to %" GST_TIME_FORMAT " %" G_GUINT64_FORMAT
5067 " bytes", GST_TIME_ARGS (cstop), diff);
5072 if (offset != 0 || size != osize)
5073 gst_buffer_resize (buf, offset, size);
5075 GST_BUFFER_DTS (buf) = GST_CLOCK_TIME_NONE;
5076 GST_BUFFER_PTS (buf) = pts;
5077 GST_BUFFER_DURATION (buf) = duration;
5081 /* dropped buffer */
5084 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
5089 GST_DEBUG_OBJECT (qtdemux, "bad frame size");
5094 GST_DEBUG_OBJECT (qtdemux, "no pts on buffer");
5099 GST_DEBUG_OBJECT (qtdemux, "clipped buffer");
5100 gst_buffer_unref (buf);
5105 /* the input buffer metadata must be writable,
5106 * but time/duration etc not yet set and need not be preserved */
5108 gst_qtdemux_process_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
5115 /* not many cases for now */
5116 if (G_UNLIKELY (stream->fourcc == FOURCC_mp4s)) {
5117 /* send a one time dvd clut event */
5118 if (stream->pending_event && stream->pad)
5119 gst_pad_push_event (stream->pad, stream->pending_event);
5120 stream->pending_event = NULL;
5123 if (G_UNLIKELY (stream->subtype != FOURCC_text
5124 && stream->subtype != FOURCC_sbtl &&
5125 stream->subtype != FOURCC_subp)) {
5129 gst_buffer_map (buf, &map, GST_MAP_READ);
5131 /* empty buffer is sent to terminate previous subtitle */
5132 if (map.size <= 2) {
5133 gst_buffer_unmap (buf, &map);
5134 gst_buffer_unref (buf);
5137 if (stream->subtype == FOURCC_subp) {
5138 /* That's all the processing needed for subpictures */
5139 gst_buffer_unmap (buf, &map);
5143 nsize = GST_READ_UINT16_BE (map.data);
5144 nsize = MIN (nsize, map.size - 2);
5146 GST_LOG_OBJECT (qtdemux, "3GPP timed text subtitle: %d/%" G_GSIZE_FORMAT "",
5149 /* takes care of UTF-8 validation or UTF-16 recognition,
5150 * no other encoding expected */
5151 str = gst_tag_freeform_string_to_utf8 ((gchar *) map.data + 2, nsize, NULL);
5152 gst_buffer_unmap (buf, &map);
5154 gst_buffer_unref (buf);
5155 buf = _gst_buffer_new_wrapped (str, strlen (str), g_free);
5157 /* this should not really happen unless the subtitle is corrupted */
5158 gst_buffer_unref (buf);
5162 /* FIXME ? convert optional subsequent style info to markup */
5167 /* Sets a buffer's attributes properly and pushes it downstream.
5168 * Also checks for additional actions and custom processing that may
5169 * need to be done first.
5171 static GstFlowReturn
5172 gst_qtdemux_decorate_and_push_buffer (GstQTDemux * qtdemux,
5173 QtDemuxStream * stream, GstBuffer * buf,
5174 GstClockTime dts, GstClockTime pts, GstClockTime duration,
5175 gboolean keyframe, GstClockTime position, guint64 byte_position)
5177 GstFlowReturn ret = GST_FLOW_OK;
5179 /* offset the timestamps according to the edit list */
5181 if (G_UNLIKELY (stream->fourcc == FOURCC_rtsp)) {
5185 gst_buffer_map (buf, &map, GST_MAP_READ);
5186 url = g_strndup ((gchar *) map.data, map.size);
5187 gst_buffer_unmap (buf, &map);
5188 if (url != NULL && strlen (url) != 0) {
5189 /* we have RTSP redirect now */
5190 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
5191 gst_message_new_element (GST_OBJECT_CAST (qtdemux),
5192 gst_structure_new ("redirect",
5193 "new-location", G_TYPE_STRING, url, NULL)));
5194 qtdemux->posted_redirect = TRUE;
5196 GST_WARNING_OBJECT (qtdemux, "Redirect URI of stream is empty, not "
5202 /* position reporting */
5203 if (qtdemux->segment.rate >= 0) {
5204 qtdemux->segment.position = position;
5205 gst_qtdemux_sync_streams (qtdemux);
5208 if (G_UNLIKELY (!stream->pad)) {
5209 GST_DEBUG_OBJECT (qtdemux, "No output pad for stream, ignoring");
5210 gst_buffer_unref (buf);
5214 /* send out pending buffers */
5215 while (stream->buffers) {
5216 GstBuffer *buffer = (GstBuffer *) stream->buffers->data;
5218 if (G_UNLIKELY (stream->discont)) {
5219 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
5220 GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
5221 stream->discont = FALSE;
5223 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
5226 gst_pad_push (stream->pad, buffer);
5228 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
5231 /* we're going to modify the metadata */
5232 buf = gst_buffer_make_writable (buf);
5234 if (G_UNLIKELY (stream->need_process))
5235 buf = gst_qtdemux_process_buffer (qtdemux, stream, buf);
5241 GST_BUFFER_DTS (buf) = dts;
5242 GST_BUFFER_PTS (buf) = pts;
5243 GST_BUFFER_DURATION (buf) = duration;
5244 GST_BUFFER_OFFSET (buf) = -1;
5245 GST_BUFFER_OFFSET_END (buf) = -1;
5247 if (G_UNLIKELY (stream->rgb8_palette))
5248 gst_buffer_append_memory (buf, gst_memory_ref (stream->rgb8_palette));
5250 if (G_UNLIKELY (stream->padding)) {
5251 gst_buffer_resize (buf, stream->padding, -1);
5254 if (G_UNLIKELY (qtdemux->element_index)) {
5255 GstClockTime stream_time;
5258 gst_segment_to_stream_time (&stream->segment, GST_FORMAT_TIME,
5260 if (GST_CLOCK_TIME_IS_VALID (stream_time)) {
5261 GST_LOG_OBJECT (qtdemux,
5262 "adding association %" GST_TIME_FORMAT "-> %"
5263 G_GUINT64_FORMAT, GST_TIME_ARGS (stream_time), byte_position);
5264 gst_index_add_association (qtdemux->element_index,
5266 keyframe ? GST_ASSOCIATION_FLAG_KEY_UNIT :
5267 GST_ASSOCIATION_FLAG_DELTA_UNIT, GST_FORMAT_TIME, stream_time,
5268 GST_FORMAT_BYTES, byte_position, NULL);
5273 if (stream->need_clip)
5274 buf = gst_qtdemux_clip_buffer (qtdemux, stream, buf);
5276 if (G_UNLIKELY (buf == NULL))
5279 if (G_UNLIKELY (stream->discont)) {
5280 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
5281 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
5282 stream->discont = FALSE;
5284 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
5288 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
5289 stream->on_keyframe = FALSE;
5291 stream->on_keyframe = TRUE;
5295 GST_LOG_OBJECT (qtdemux,
5296 "Pushing buffer with dts %" GST_TIME_FORMAT ", pts %" GST_TIME_FORMAT
5297 ", duration %" GST_TIME_FORMAT " on pad %s", GST_TIME_ARGS (dts),
5298 GST_TIME_ARGS (pts), GST_TIME_ARGS (duration),
5299 GST_PAD_NAME (stream->pad));
5301 if (stream->protected && stream->protection_scheme_type == FOURCC_cenc) {
5302 GstStructure *crypto_info;
5303 QtDemuxCencSampleSetInfo *info =
5304 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
5308 while ((event = g_queue_pop_head (&stream->protection_scheme_event_queue))) {
5309 gst_pad_push_event (stream->pad, event);
5312 if (qtdemux->cenc_aux_info_offset > 0 && info->crypto_info == NULL) {
5313 GST_DEBUG_OBJECT (qtdemux, "cenc metadata hasn't been parsed yet");
5314 gst_buffer_unref (buf);
5318 index = stream->sample_index - (stream->n_samples - info->crypto_info->len);
5319 if (G_LIKELY (index >= 0 && index < info->crypto_info->len)) {
5320 /* steal structure from array */
5321 crypto_info = g_ptr_array_index (info->crypto_info, index);
5322 g_ptr_array_index (info->crypto_info, index) = NULL;
5323 GST_LOG_OBJECT (qtdemux, "attaching cenc metadata [%u]", index);
5324 if (!crypto_info || !gst_buffer_add_protection_meta (buf, crypto_info))
5325 GST_ERROR_OBJECT (qtdemux, "failed to attach cenc metadata to buffer");
5329 ret = gst_pad_push (stream->pad, buf);
5331 if (GST_CLOCK_TIME_IS_VALID (pts) && GST_CLOCK_TIME_IS_VALID (duration)) {
5332 /* mark position in stream, we'll need this to know when to send GAP event */
5333 stream->segment.position = pts + duration;
5340 static const QtDemuxRandomAccessEntry *
5341 gst_qtdemux_stream_seek_fragment (GstQTDemux * qtdemux, QtDemuxStream * stream,
5342 GstClockTime pos, gboolean after)
5344 QtDemuxRandomAccessEntry *entries = stream->ra_entries;
5345 guint n_entries = stream->n_ra_entries;
5348 /* we assume the table is sorted */
5349 for (i = 0; i < n_entries; ++i) {
5350 if (entries[i].ts > pos)
5354 /* FIXME: maybe save first moof_offset somewhere instead, but for now it's
5355 * probably okay to assume that the index lists the very first fragment */
5362 return &entries[i - 1];
5366 gst_qtdemux_do_fragmented_seek (GstQTDemux * qtdemux)
5368 const QtDemuxRandomAccessEntry *best_entry = NULL;
5371 GST_OBJECT_LOCK (qtdemux);
5373 g_assert (qtdemux->n_streams > 0);
5375 for (i = 0; i < qtdemux->n_streams; i++) {
5376 const QtDemuxRandomAccessEntry *entry;
5377 QtDemuxStream *stream;
5378 gboolean is_audio_or_video;
5380 stream = qtdemux->streams[i];
5382 g_free (stream->samples);
5383 stream->samples = NULL;
5384 stream->n_samples = 0;
5385 stream->stbl_index = -1; /* no samples have yet been parsed */
5386 stream->sample_index = -1;
5388 if (stream->ra_entries == NULL)
5391 if (stream->subtype == FOURCC_vide || stream->subtype == FOURCC_soun)
5392 is_audio_or_video = TRUE;
5394 is_audio_or_video = FALSE;
5397 gst_qtdemux_stream_seek_fragment (qtdemux, stream,
5398 stream->time_position, !is_audio_or_video);
5400 GST_INFO_OBJECT (stream->pad, "%" GST_TIME_FORMAT " at offset "
5401 "%" G_GUINT64_FORMAT, GST_TIME_ARGS (entry->ts), entry->moof_offset);
5403 stream->pending_seek = entry;
5405 /* decide position to jump to just based on audio/video tracks, not subs */
5406 if (!is_audio_or_video)
5409 if (best_entry == NULL || entry->moof_offset < best_entry->moof_offset)
5413 if (best_entry == NULL) {
5414 GST_OBJECT_UNLOCK (qtdemux);
5418 GST_INFO_OBJECT (qtdemux, "seek to %" GST_TIME_FORMAT ", best fragment "
5419 "moof offset: %" G_GUINT64_FORMAT ", ts %" GST_TIME_FORMAT,
5420 GST_TIME_ARGS (qtdemux->streams[0]->time_position),
5421 best_entry->moof_offset, GST_TIME_ARGS (best_entry->ts));
5423 qtdemux->moof_offset = best_entry->moof_offset;
5425 qtdemux_add_fragmented_samples (qtdemux);
5427 GST_OBJECT_UNLOCK (qtdemux);
5431 static GstFlowReturn
5432 gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux)
5434 GstFlowReturn ret = GST_FLOW_OK;
5435 GstBuffer *buf = NULL;
5436 QtDemuxStream *stream;
5437 GstClockTime min_time;
5439 GstClockTime dts = GST_CLOCK_TIME_NONE;
5440 GstClockTime pts = GST_CLOCK_TIME_NONE;
5441 GstClockTime duration = 0;
5442 gboolean keyframe = FALSE;
5443 guint sample_size = 0;
5449 gst_qtdemux_push_pending_newsegment (qtdemux);
5451 if (qtdemux->fragmented_seek_pending) {
5452 GST_INFO_OBJECT (qtdemux, "pending fragmented seek");
5453 gst_qtdemux_do_fragmented_seek (qtdemux);
5454 GST_INFO_OBJECT (qtdemux, "fragmented seek done!");
5455 qtdemux->fragmented_seek_pending = FALSE;
5458 /* Figure out the next stream sample to output, min_time is expressed in
5459 * global time and runs over the edit list segments. */
5460 min_time = G_MAXUINT64;
5462 for (i = 0; i < qtdemux->n_streams; i++) {
5463 GstClockTime position;
5465 stream = qtdemux->streams[i];
5466 position = stream->time_position;
5468 /* position of -1 is EOS */
5469 if (position != GST_CLOCK_TIME_NONE && position < min_time) {
5470 min_time = position;
5475 if (G_UNLIKELY (index == -1)) {
5476 GST_DEBUG_OBJECT (qtdemux, "all streams are EOS");
5480 /* check for segment end */
5481 if (G_UNLIKELY (qtdemux->segment.stop != -1
5482 && ((qtdemux->segment.rate >= 0 && qtdemux->segment.stop <= min_time)
5483 || (qtdemux->segment.rate < 0
5484 && qtdemux->segment.start > min_time))
5485 && qtdemux->streams[index]->on_keyframe)) {
5486 GST_DEBUG_OBJECT (qtdemux, "we reached the end of our segment.");
5487 qtdemux->streams[index]->time_position = GST_CLOCK_TIME_NONE;
5491 /* gap events for subtitle streams */
5492 for (i = 0; i < qtdemux->n_streams; i++) {
5493 stream = qtdemux->streams[i];
5494 if (stream->pad && (stream->subtype == FOURCC_subp
5495 || stream->subtype == FOURCC_text
5496 || stream->subtype == FOURCC_sbtl)) {
5497 /* send one second gap events until the stream catches up */
5498 /* gaps can only be sent after segment is activated (segment.stop is no longer -1) */
5499 while (GST_CLOCK_TIME_IS_VALID (stream->segment.stop) &&
5500 GST_CLOCK_TIME_IS_VALID (stream->segment.position) &&
5501 stream->segment.position + GST_SECOND < min_time) {
5503 gst_event_new_gap (stream->segment.position, GST_SECOND);
5504 gst_pad_push_event (stream->pad, gap);
5505 stream->segment.position += GST_SECOND;
5510 stream = qtdemux->streams[index];
5511 if (stream->new_caps) {
5512 gst_qtdemux_configure_stream (qtdemux, stream);
5513 qtdemux_do_allocation (qtdemux, stream);
5516 /* fetch info for the current sample of this stream */
5517 if (G_UNLIKELY (!gst_qtdemux_prepare_current_sample (qtdemux, stream, &empty,
5518 &offset, &sample_size, &dts, &pts, &duration, &keyframe)))
5521 /* If we're doing a keyframe-only trickmode, only push keyframes on video streams */
5522 if (G_UNLIKELY (qtdemux->
5523 segment.flags & GST_SEGMENT_FLAG_TRICKMODE_KEY_UNITS)) {
5524 if (stream->subtype == FOURCC_vide && !keyframe) {
5525 GST_LOG_OBJECT (qtdemux, "Skipping non-keyframe on stream %d", index);
5530 GST_DEBUG_OBJECT (qtdemux,
5531 "pushing from stream %d, empty %d offset %" G_GUINT64_FORMAT
5532 ", size %d, dts=%" GST_TIME_FORMAT ", pts=%" GST_TIME_FORMAT
5533 ", duration %" GST_TIME_FORMAT, index, empty, offset, sample_size,
5534 GST_TIME_ARGS (dts), GST_TIME_ARGS (pts), GST_TIME_ARGS (duration));
5536 if (G_UNLIKELY (empty)) {
5537 /* empty segment, push a gap and move to the next one */
5538 gst_pad_push_event (stream->pad, gst_event_new_gap (pts, duration));
5539 stream->segment.position = pts + duration;
5543 /* hmm, empty sample, skip and move to next sample */
5544 if (G_UNLIKELY (sample_size <= 0))
5547 /* last pushed sample was out of boundary, goto next sample */
5548 if (G_UNLIKELY (GST_PAD_LAST_FLOW_RETURN (stream->pad) == GST_FLOW_EOS))
5551 if (stream->max_buffer_size == 0 || sample_size <= stream->max_buffer_size) {
5554 GST_DEBUG_OBJECT (qtdemux,
5555 "size %d larger than stream max_buffer_size %d, trimming",
5556 sample_size, stream->max_buffer_size);
5558 MIN (sample_size - stream->offset_in_sample, stream->max_buffer_size);
5561 if (qtdemux->cenc_aux_info_offset > 0) {
5564 GstBuffer *aux_info = NULL;
5566 /* pull the data stored before the sample */
5568 gst_qtdemux_pull_atom (qtdemux, qtdemux->offset,
5569 offset + stream->offset_in_sample - qtdemux->offset, &aux_info);
5570 if (G_UNLIKELY (ret != GST_FLOW_OK))
5572 gst_buffer_map (aux_info, &map, GST_MAP_READ);
5573 GST_DEBUG_OBJECT (qtdemux, "parsing cenc auxiliary info");
5574 gst_byte_reader_init (&br, map.data + 8, map.size);
5575 if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
5576 qtdemux->cenc_aux_info_sizes, qtdemux->cenc_aux_sample_count)) {
5577 GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
5578 gst_buffer_unmap (aux_info, &map);
5579 gst_buffer_unref (aux_info);
5580 ret = GST_FLOW_ERROR;
5583 gst_buffer_unmap (aux_info, &map);
5584 gst_buffer_unref (aux_info);
5587 GST_LOG_OBJECT (qtdemux, "reading %d bytes @ %" G_GUINT64_FORMAT, size,
5590 if (stream->use_allocator) {
5591 /* if we have a per-stream allocator, use it */
5592 buf = gst_buffer_new_allocate (stream->allocator, size, &stream->params);
5595 ret = gst_qtdemux_pull_atom (qtdemux, offset + stream->offset_in_sample,
5597 if (G_UNLIKELY (ret != GST_FLOW_OK))
5600 if (size != sample_size) {
5601 pts += gst_util_uint64_scale_int (GST_SECOND,
5602 stream->offset_in_sample / stream->bytes_per_frame, stream->timescale);
5603 dts += gst_util_uint64_scale_int (GST_SECOND,
5604 stream->offset_in_sample / stream->bytes_per_frame, stream->timescale);
5605 duration = gst_util_uint64_scale_int (GST_SECOND,
5606 size / stream->bytes_per_frame, stream->timescale);
5609 ret = gst_qtdemux_decorate_and_push_buffer (qtdemux, stream, buf,
5610 dts, pts, duration, keyframe, min_time, offset);
5612 if (size != sample_size) {
5613 QtDemuxSample *sample = &stream->samples[stream->sample_index];
5614 QtDemuxSegment *segment = &stream->segments[stream->segment_index];
5616 GstClockTime time_position = QTSTREAMTIME_TO_GSTTIME (stream,
5617 sample->timestamp + stream->offset_in_sample / stream->bytes_per_frame);
5618 if (time_position >= segment->media_start) {
5619 /* inside the segment, update time_position, looks very familiar to
5620 * GStreamer segments, doesn't it? */
5621 stream->time_position = (time_position - segment->media_start) +
5624 /* not yet in segment, time does not yet increment. This means
5625 * that we are still prerolling keyframes to the decoder so it can
5626 * decode the first sample of the segment. */
5627 stream->time_position = segment->time;
5632 ret = gst_qtdemux_combine_flows (qtdemux, stream, ret);
5633 /* ignore unlinked, we will not push on the pad anymore and we will EOS when
5634 * we have no more data for the pad to push */
5635 if (ret == GST_FLOW_EOS)
5638 stream->offset_in_sample += size;
5639 if (stream->offset_in_sample >= sample_size) {
5640 gst_qtdemux_advance_sample (qtdemux, stream);
5645 gst_qtdemux_advance_sample (qtdemux, stream);
5653 GST_DEBUG_OBJECT (qtdemux, "No samples left for any streams - EOS");
5659 GST_DEBUG_OBJECT (qtdemux, "No samples left for stream");
5660 /* EOS will be raised if all are EOS */
5667 gst_qtdemux_loop (GstPad * pad)
5669 GstQTDemux *qtdemux;
5673 qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
5675 cur_offset = qtdemux->offset;
5676 GST_LOG_OBJECT (qtdemux, "loop at position %" G_GUINT64_FORMAT ", state %s",
5677 cur_offset, qt_demux_state_string (qtdemux->state));
5679 switch (qtdemux->state) {
5680 case QTDEMUX_STATE_INITIAL:
5681 case QTDEMUX_STATE_HEADER:
5682 ret = gst_qtdemux_loop_state_header (qtdemux);
5684 case QTDEMUX_STATE_MOVIE:
5685 ret = gst_qtdemux_loop_state_movie (qtdemux);
5686 if (qtdemux->segment.rate < 0 && ret == GST_FLOW_EOS) {
5687 ret = gst_qtdemux_seek_to_previous_keyframe (qtdemux);
5695 /* if something went wrong, pause */
5696 if (ret != GST_FLOW_OK)
5700 gst_object_unref (qtdemux);
5706 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
5707 (NULL), ("streaming stopped, invalid state"));
5708 gst_pad_pause_task (pad);
5709 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
5714 const gchar *reason = gst_flow_get_name (ret);
5716 GST_LOG_OBJECT (qtdemux, "pausing task, reason %s", reason);
5718 gst_pad_pause_task (pad);
5720 /* fatal errors need special actions */
5722 if (ret == GST_FLOW_EOS) {
5723 if (qtdemux->n_streams == 0) {
5724 /* we have no streams, post an error */
5725 gst_qtdemux_post_no_playable_stream_error (qtdemux);
5727 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
5730 if ((stop = qtdemux->segment.stop) == -1)
5731 stop = qtdemux->segment.duration;
5733 if (qtdemux->segment.rate >= 0) {
5734 GstMessage *message;
5737 GST_LOG_OBJECT (qtdemux, "Sending segment done, at end of segment");
5738 message = gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
5739 GST_FORMAT_TIME, stop);
5740 event = gst_event_new_segment_done (GST_FORMAT_TIME, stop);
5741 if (qtdemux->segment_seqnum) {
5742 gst_message_set_seqnum (message, qtdemux->segment_seqnum);
5743 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
5745 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), message);
5746 gst_qtdemux_push_event (qtdemux, event);
5748 GstMessage *message;
5751 /* For Reverse Playback */
5752 GST_LOG_OBJECT (qtdemux, "Sending segment done, at start of segment");
5753 message = gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
5754 GST_FORMAT_TIME, qtdemux->segment.start);
5755 event = gst_event_new_segment_done (GST_FORMAT_TIME,
5756 qtdemux->segment.start);
5757 if (qtdemux->segment_seqnum) {
5758 gst_message_set_seqnum (message, qtdemux->segment_seqnum);
5759 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
5761 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), message);
5762 gst_qtdemux_push_event (qtdemux, event);
5767 GST_LOG_OBJECT (qtdemux, "Sending EOS at end of segment");
5768 event = gst_event_new_eos ();
5769 if (qtdemux->segment_seqnum)
5770 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
5771 gst_qtdemux_push_event (qtdemux, event);
5773 } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
5774 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
5775 (NULL), ("streaming stopped, reason %s", reason));
5776 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
5785 * Returns if there are samples to be played.
5788 has_next_entry (GstQTDemux * demux)
5790 QtDemuxStream *stream;
5793 GST_DEBUG_OBJECT (demux, "Checking if there are samples not played yet");
5795 for (i = 0; i < demux->n_streams; i++) {
5796 stream = demux->streams[i];
5798 if (stream->sample_index == -1) {
5799 stream->sample_index = 0;
5800 stream->offset_in_sample = 0;
5803 if (stream->sample_index >= stream->n_samples) {
5804 GST_LOG_OBJECT (demux, "stream %d samples exhausted", i);
5807 GST_DEBUG_OBJECT (demux, "Found a sample");
5811 GST_DEBUG_OBJECT (demux, "There wasn't any next sample");
5818 * Returns the size of the first entry at the current offset.
5819 * If -1, there are none (which means EOS or empty file).
5822 next_entry_size (GstQTDemux * demux)
5824 QtDemuxStream *stream;
5827 guint64 smalloffs = (guint64) - 1;
5828 QtDemuxSample *sample;
5830 GST_LOG_OBJECT (demux, "Finding entry at offset %" G_GUINT64_FORMAT,
5833 for (i = 0; i < demux->n_streams; i++) {
5834 stream = demux->streams[i];
5836 if (stream->sample_index == -1) {
5837 stream->sample_index = 0;
5838 stream->offset_in_sample = 0;
5841 if (stream->sample_index >= stream->n_samples) {
5842 GST_LOG_OBJECT (demux, "stream %d samples exhausted", i);
5846 if (!qtdemux_parse_samples (demux, stream, stream->sample_index)) {
5847 GST_LOG_OBJECT (demux, "Parsing of index %u from stbl atom failed!",
5848 stream->sample_index);
5852 sample = &stream->samples[stream->sample_index];
5854 GST_LOG_OBJECT (demux,
5855 "Checking Stream %d (sample_index:%d / offset:%" G_GUINT64_FORMAT
5856 " / size:%" G_GUINT32_FORMAT ")", i, stream->sample_index,
5857 sample->offset, sample->size);
5859 if (((smalloffs == -1)
5860 || (sample->offset < smalloffs)) && (sample->size)) {
5862 smalloffs = sample->offset;
5866 GST_LOG_OBJECT (demux,
5867 "stream %d offset %" G_GUINT64_FORMAT " demux->offset :%"
5868 G_GUINT64_FORMAT, smallidx, smalloffs, demux->offset);
5873 stream = demux->streams[smallidx];
5874 sample = &stream->samples[stream->sample_index];
5876 if (sample->offset >= demux->offset) {
5877 demux->todrop = sample->offset - demux->offset;
5878 return sample->size + demux->todrop;
5881 GST_DEBUG_OBJECT (demux,
5882 "There wasn't any entry at offset %" G_GUINT64_FORMAT, demux->offset);
5887 gst_qtdemux_post_progress (GstQTDemux * demux, gint num, gint denom)
5889 gint perc = (gint) ((gdouble) num * 100.0 / (gdouble) denom);
5891 gst_element_post_message (GST_ELEMENT_CAST (demux),
5892 gst_message_new_element (GST_OBJECT_CAST (demux),
5893 gst_structure_new ("progress", "percent", G_TYPE_INT, perc, NULL)));
5897 qtdemux_seek_offset (GstQTDemux * demux, guint64 offset)
5902 GST_DEBUG_OBJECT (demux, "Seeking to %" G_GUINT64_FORMAT, offset);
5905 gst_event_new_seek (1.0, GST_FORMAT_BYTES,
5906 GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset,
5907 GST_SEEK_TYPE_NONE, -1);
5909 /* store seqnum to drop flush events, they don't need to reach downstream */
5910 demux->offset_seek_seqnum = gst_event_get_seqnum (event);
5911 res = gst_pad_push_event (demux->sinkpad, event);
5912 demux->offset_seek_seqnum = 0;
5917 /* check for seekable upstream, above and beyond a mere query */
5919 gst_qtdemux_check_seekability (GstQTDemux * demux)
5922 gboolean seekable = FALSE;
5923 gint64 start = -1, stop = -1;
5925 if (demux->upstream_size)
5928 query = gst_query_new_seeking (GST_FORMAT_BYTES);
5929 if (!gst_pad_peer_query (demux->sinkpad, query)) {
5930 GST_DEBUG_OBJECT (demux, "seeking query failed");
5934 gst_query_parse_seeking (query, NULL, &seekable, &start, &stop);
5936 /* try harder to query upstream size if we didn't get it the first time */
5937 if (seekable && stop == -1) {
5938 GST_DEBUG_OBJECT (demux, "doing duration query to fix up unset stop");
5939 gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &stop);
5942 /* if upstream doesn't know the size, it's likely that it's not seekable in
5943 * practice even if it technically may be seekable */
5944 if (seekable && (start != 0 || stop <= start)) {
5945 GST_DEBUG_OBJECT (demux, "seekable but unknown start/stop -> disable");
5950 gst_query_unref (query);
5952 GST_DEBUG_OBJECT (demux, "seekable: %d (%" G_GUINT64_FORMAT " - %"
5953 G_GUINT64_FORMAT ")", seekable, start, stop);
5954 demux->upstream_seekable = seekable;
5955 demux->upstream_size = seekable ? stop : -1;
5959 gst_qtdemux_drop_data (GstQTDemux * demux, gint bytes)
5961 g_return_if_fail (bytes <= demux->todrop);
5963 GST_LOG_OBJECT (demux, "Dropping %d bytes", bytes);
5964 gst_adapter_flush (demux->adapter, bytes);
5965 demux->neededbytes -= bytes;
5966 demux->offset += bytes;
5967 demux->todrop -= bytes;
5971 gst_qtdemux_check_send_pending_segment (GstQTDemux * demux)
5973 if (G_UNLIKELY (demux->pending_newsegment)) {
5976 gst_qtdemux_push_pending_newsegment (demux);
5977 /* clear to send tags on all streams */
5978 for (i = 0; i < demux->n_streams; i++) {
5979 QtDemuxStream *stream;
5980 stream = demux->streams[i];
5981 gst_qtdemux_push_tags (demux, stream);
5982 if (stream->sparse) {
5983 GST_INFO_OBJECT (demux, "Sending gap event on stream %d", i);
5984 gst_pad_push_event (stream->pad,
5985 gst_event_new_gap (stream->segment.position, GST_CLOCK_TIME_NONE));
5992 gst_qtdemux_send_gap_for_segment (GstQTDemux * demux,
5993 QtDemuxStream * stream, gint segment_index, GstClockTime pos)
5995 GstClockTime ts, dur;
6000 stream->segments[segment_index].duration - (pos -
6001 stream->segments[segment_index].time);
6002 gap = gst_event_new_gap (ts, dur);
6003 stream->time_position += dur;
6005 GST_DEBUG_OBJECT (stream->pad, "Pushing gap for empty "
6006 "segment: %" GST_PTR_FORMAT, gap);
6007 gst_pad_push_event (stream->pad, gap);
6011 gst_qtdemux_stream_send_initial_gap_segments (GstQTDemux * demux,
6012 QtDemuxStream * stream)
6016 /* Push any initial gap segments before proceeding to the
6018 for (i = 0; i < stream->n_segments; i++) {
6019 gst_qtdemux_activate_segment (demux, stream, i, stream->time_position);
6021 if (QTSEGMENT_IS_EMPTY (&stream->segments[i])) {
6022 gst_qtdemux_send_gap_for_segment (demux, stream, i,
6023 stream->time_position);
6025 /* Only support empty segment at the beginning followed by
6026 * one non-empty segment, this was checked when parsing the
6027 * edts atom, arriving here is unexpected */
6028 g_assert (i + 1 == stream->n_segments);
6034 static GstFlowReturn
6035 gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent, GstBuffer * inbuf)
6039 demux = GST_QTDEMUX (parent);
6041 GST_DEBUG_OBJECT (demux,
6042 "Received buffer pts:%" GST_TIME_FORMAT " dts:%" GST_TIME_FORMAT
6043 " offset:%" G_GUINT64_FORMAT " size:%" G_GSIZE_FORMAT " demux offset:%"
6044 G_GUINT64_FORMAT, GST_TIME_ARGS (GST_BUFFER_PTS (inbuf)),
6045 GST_TIME_ARGS (GST_BUFFER_DTS (inbuf)), GST_BUFFER_OFFSET (inbuf),
6046 gst_buffer_get_size (inbuf), demux->offset);
6048 if (GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_DISCONT)) {
6049 gboolean is_gap_input = FALSE;
6052 GST_DEBUG_OBJECT (demux, "Got DISCONT, marking all streams as DISCONT");
6054 for (i = 0; i < demux->n_streams; i++) {
6055 demux->streams[i]->discont = TRUE;
6058 /* Check if we can land back on our feet in the case where upstream is
6059 * handling the seeking/pushing of samples with gaps in between (like
6060 * in the case of trick-mode DASH for example) */
6061 if (demux->upstream_format_is_time
6062 && GST_BUFFER_OFFSET (inbuf) != GST_BUFFER_OFFSET_NONE) {
6064 for (i = 0; i < demux->n_streams; i++) {
6066 GST_LOG_OBJECT (demux,
6067 "Stream #%d , checking if offset %" G_GUINT64_FORMAT
6068 " is a sample start", i, GST_BUFFER_OFFSET (inbuf));
6070 gst_qtdemux_find_index_for_given_media_offset_linear (demux,
6071 demux->streams[i], GST_BUFFER_OFFSET (inbuf));
6073 QtDemuxSample *sample = &demux->streams[i]->samples[res];
6074 GST_LOG_OBJECT (demux,
6075 "Checking if sample %d from stream %d is valid (offset:%"
6076 G_GUINT64_FORMAT " size:%" G_GUINT32_FORMAT ")", res, i,
6077 sample->offset, sample->size);
6078 if (sample->offset == GST_BUFFER_OFFSET (inbuf)) {
6079 GST_LOG_OBJECT (demux,
6080 "new buffer corresponds to a valid sample : %" G_GUINT32_FORMAT,
6082 is_gap_input = TRUE;
6083 /* We can go back to standard playback mode */
6084 demux->state = QTDEMUX_STATE_MOVIE;
6085 /* Remember which sample this stream is at */
6086 demux->streams[i]->sample_index = res;
6087 /* Finally update all push-based values to the expected values */
6088 demux->neededbytes = demux->streams[i]->samples[res].size;
6090 demux->offset = GST_BUFFER_OFFSET (inbuf);
6094 if (!is_gap_input) {
6095 /* Reset state if it's a real discont */
6096 demux->neededbytes = 16;
6097 demux->state = QTDEMUX_STATE_INITIAL;
6100 /* Reverse fragmented playback, need to flush all we have before
6101 * consuming a new fragment.
6102 * The samples array have the timestamps calculated by accumulating the
6103 * durations but this won't work for reverse playback of fragments as
6104 * the timestamps of a subsequent fragment should be smaller than the
6105 * previously received one. */
6106 if (!is_gap_input && demux->fragmented && demux->segment.rate < 0) {
6107 gst_qtdemux_process_adapter (demux, TRUE);
6108 for (i = 0; i < demux->n_streams; i++)
6109 gst_qtdemux_stream_flush_samples_data (demux, demux->streams[i]);
6113 gst_adapter_push (demux->adapter, inbuf);
6115 GST_DEBUG_OBJECT (demux,
6116 "pushing in inbuf %p, neededbytes:%u, available:%" G_GSIZE_FORMAT, inbuf,
6117 demux->neededbytes, gst_adapter_available (demux->adapter));
6119 return gst_qtdemux_process_adapter (demux, FALSE);
6122 static GstFlowReturn
6123 gst_qtdemux_process_adapter (GstQTDemux * demux, gboolean force)
6125 GstFlowReturn ret = GST_FLOW_OK;
6127 /* we never really mean to buffer that much */
6128 if (demux->neededbytes == -1) {
6132 while (((gst_adapter_available (demux->adapter)) >= demux->neededbytes) &&
6133 (ret == GST_FLOW_OK || (ret == GST_FLOW_NOT_LINKED && force))) {
6135 #ifndef GST_DISABLE_GST_DEBUG
6137 guint64 discont_offset, distance_from_discont;
6139 discont_offset = gst_adapter_offset_at_discont (demux->adapter);
6140 distance_from_discont =
6141 gst_adapter_distance_from_discont (demux->adapter);
6143 GST_DEBUG_OBJECT (demux,
6144 "state:%s , demux->neededbytes:%d, demux->offset:%" G_GUINT64_FORMAT
6145 " adapter offset :%" G_GUINT64_FORMAT " (+ %" G_GUINT64_FORMAT
6146 " bytes)", qt_demux_state_string (demux->state), demux->neededbytes,
6147 demux->offset, discont_offset, distance_from_discont);
6151 switch (demux->state) {
6152 case QTDEMUX_STATE_INITIAL:{
6157 gst_qtdemux_check_seekability (demux);
6159 data = gst_adapter_map (demux->adapter, demux->neededbytes);
6161 /* get fourcc/length, set neededbytes */
6162 extract_initial_length_and_fourcc ((guint8 *) data, demux->neededbytes,
6164 gst_adapter_unmap (demux->adapter);
6166 GST_DEBUG_OBJECT (demux, "Peeking found [%" GST_FOURCC_FORMAT "] "
6167 "size: %" G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), size);
6169 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
6170 (_("This file is invalid and cannot be played.")),
6171 ("initial atom '%" GST_FOURCC_FORMAT "' has empty length",
6172 GST_FOURCC_ARGS (fourcc)));
6173 ret = GST_FLOW_ERROR;
6176 if (fourcc == FOURCC_mdat) {
6177 gint next_entry = next_entry_size (demux);
6178 if (demux->n_streams > 0 && (next_entry != -1 || !demux->fragmented)) {
6179 /* we have the headers, start playback */
6180 demux->state = QTDEMUX_STATE_MOVIE;
6181 demux->neededbytes = next_entry;
6182 demux->mdatleft = size;
6184 /* no headers yet, try to get them */
6187 guint64 old, target;
6190 old = demux->offset;
6191 target = old + size;
6193 /* try to jump over the atom with a seek */
6194 /* only bother if it seems worth doing so,
6195 * and avoids possible upstream/server problems */
6196 if (demux->upstream_seekable &&
6197 demux->upstream_size > 4 * (1 << 20)) {
6198 res = qtdemux_seek_offset (demux, target);
6200 GST_DEBUG_OBJECT (demux, "skipping seek");
6205 GST_DEBUG_OBJECT (demux, "seek success");
6206 /* remember the offset fo the first mdat so we can seek back to it
6207 * after we have the headers */
6208 if (fourcc == FOURCC_mdat && demux->first_mdat == -1) {
6209 demux->first_mdat = old;
6210 GST_DEBUG_OBJECT (demux, "first mdat at %" G_GUINT64_FORMAT,
6213 /* seek worked, continue reading */
6214 demux->offset = target;
6215 demux->neededbytes = 16;
6216 demux->state = QTDEMUX_STATE_INITIAL;
6218 /* seek failed, need to buffer */
6219 demux->offset = old;
6220 GST_DEBUG_OBJECT (demux, "seek failed/skipped");
6221 /* there may be multiple mdat (or alike) buffers */
6223 if (demux->mdatbuffer)
6224 bs = gst_buffer_get_size (demux->mdatbuffer);
6227 if (size + bs > 10 * (1 << 20))
6229 demux->state = QTDEMUX_STATE_BUFFER_MDAT;
6230 demux->neededbytes = size;
6231 if (!demux->mdatbuffer)
6232 demux->mdatoffset = demux->offset;
6235 } else if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
6236 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
6237 (_("This file is invalid and cannot be played.")),
6238 ("atom %" GST_FOURCC_FORMAT " has bogus size %" G_GUINT64_FORMAT,
6239 GST_FOURCC_ARGS (fourcc), size));
6240 ret = GST_FLOW_ERROR;
6243 /* this means we already started buffering and still no moov header,
6244 * let's continue buffering everything till we get moov */
6245 if (demux->mdatbuffer && !(fourcc == FOURCC_moov
6246 || fourcc == FOURCC_moof))
6248 demux->neededbytes = size;
6249 demux->state = QTDEMUX_STATE_HEADER;
6253 case QTDEMUX_STATE_HEADER:{
6257 GST_DEBUG_OBJECT (demux, "In header");
6259 data = gst_adapter_map (demux->adapter, demux->neededbytes);
6261 /* parse the header */
6262 extract_initial_length_and_fourcc (data, demux->neededbytes, NULL,
6264 if (fourcc == FOURCC_moov) {
6267 /* in usual fragmented setup we could try to scan for more
6268 * and end up at the the moov (after mdat) again */
6269 if (demux->got_moov && demux->n_streams > 0 &&
6271 || demux->last_moov_offset == demux->offset)) {
6272 GST_DEBUG_OBJECT (demux,
6273 "Skipping moov atom as we have (this) one already");
6275 GST_DEBUG_OBJECT (demux, "Parsing [moov]");
6277 if (demux->got_moov && demux->fragmented) {
6278 GST_DEBUG_OBJECT (demux,
6279 "Got a second moov, clean up data from old one");
6280 if (demux->moov_node)
6281 g_node_destroy (demux->moov_node);
6282 demux->moov_node = NULL;
6283 demux->moov_node_compressed = NULL;
6285 /* prepare newsegment to send when streaming actually starts */
6286 if (!demux->pending_newsegment) {
6287 demux->pending_newsegment =
6288 gst_event_new_segment (&demux->segment);
6289 if (demux->segment_seqnum)
6290 gst_event_set_seqnum (demux->pending_newsegment,
6291 demux->segment_seqnum);
6295 demux->last_moov_offset = demux->offset;
6297 qtdemux_parse_moov (demux, data, demux->neededbytes);
6298 qtdemux_node_dump (demux, demux->moov_node);
6299 qtdemux_parse_tree (demux);
6300 qtdemux_prepare_streams (demux);
6301 if (!demux->got_moov)
6302 qtdemux_expose_streams (demux);
6305 for (n = 0; n < demux->n_streams; n++) {
6306 QtDemuxStream *stream = demux->streams[n];
6308 gst_qtdemux_configure_stream (demux, stream);
6312 demux->got_moov = TRUE;
6313 gst_qtdemux_check_send_pending_segment (demux);
6315 /* fragmented streams headers shouldn't contain edts atoms */
6316 if (!demux->fragmented) {
6317 for (n = 0; n < demux->n_streams; n++) {
6318 gst_qtdemux_stream_send_initial_gap_segments (demux,
6323 g_node_destroy (demux->moov_node);
6324 demux->moov_node = NULL;
6325 GST_DEBUG_OBJECT (demux, "Finished parsing the header");
6327 } else if (fourcc == FOURCC_moof) {
6328 if ((demux->got_moov || demux->media_caps) && demux->fragmented) {
6330 GstClockTime prev_pts;
6331 guint64 prev_offset;
6332 guint64 adapter_discont_offset, adapter_discont_dist;
6334 GST_DEBUG_OBJECT (demux, "Parsing [moof]");
6337 * The timestamp of the moof buffer is relevant as some scenarios
6338 * won't have the initial timestamp in the atoms. Whenever a new
6339 * buffer has started, we get that buffer's PTS and use it as a base
6340 * timestamp for the trun entries.
6342 * To keep track of the current buffer timestamp and starting point
6343 * we use gst_adapter_prev_pts that gives us the PTS and the distance
6344 * from the beggining of the buffer, with the distance and demux->offset
6345 * we know if it is still the same buffer or not.
6347 prev_pts = gst_adapter_prev_pts (demux->adapter, &dist);
6348 prev_offset = demux->offset - dist;
6349 if (demux->fragment_start_offset == -1
6350 || prev_offset > demux->fragment_start_offset) {
6351 demux->fragment_start_offset = prev_offset;
6352 demux->fragment_start = prev_pts;
6353 GST_DEBUG_OBJECT (demux,
6354 "New fragment start found at: %" G_GUINT64_FORMAT " : %"
6355 GST_TIME_FORMAT, demux->fragment_start_offset,
6356 GST_TIME_ARGS (demux->fragment_start));
6359 /* We can't use prev_offset() here because this would require
6360 * upstream to set consistent and correct offsets on all buffers
6361 * since the discont. Nothing ever did that in the past and we
6362 * would break backwards compatibility here then.
6363 * Instead take the offset we had at the last discont and count
6364 * the bytes from there. This works with old code as there would
6365 * be no discont between moov and moof, and also works with
6366 * adaptivedemux which correctly sets offset and will set the
6367 * DISCONT flag accordingly when needed.
6369 * We also only do this for upstream TIME segments as otherwise
6370 * there are potential backwards compatibility problems with
6371 * seeking in PUSH mode and upstream providing inconsistent
6373 adapter_discont_offset =
6374 gst_adapter_offset_at_discont (demux->adapter);
6375 adapter_discont_dist =
6376 gst_adapter_distance_from_discont (demux->adapter);
6378 GST_DEBUG_OBJECT (demux,
6379 "demux offset %" G_GUINT64_FORMAT " adapter offset %"
6380 G_GUINT64_FORMAT " (+ %" G_GUINT64_FORMAT " bytes)",
6381 demux->offset, adapter_discont_offset, adapter_discont_dist);
6383 if (demux->upstream_format_is_time) {
6384 demux->moof_offset = adapter_discont_offset;
6385 if (demux->moof_offset != GST_BUFFER_OFFSET_NONE)
6386 demux->moof_offset += adapter_discont_dist;
6387 if (demux->moof_offset == GST_BUFFER_OFFSET_NONE)
6388 demux->moof_offset = demux->offset;
6390 demux->moof_offset = demux->offset;
6393 if (!qtdemux_parse_moof (demux, data, demux->neededbytes,
6394 demux->moof_offset, NULL)) {
6395 gst_adapter_unmap (demux->adapter);
6396 ret = GST_FLOW_ERROR;
6399 /* in MSS we need to expose the pads after the first moof as we won't get a moov */
6400 if (demux->mss_mode && !demux->exposed) {
6401 if (!demux->pending_newsegment) {
6402 GST_DEBUG_OBJECT (demux, "new pending_newsegment");
6403 demux->pending_newsegment =
6404 gst_event_new_segment (&demux->segment);
6405 if (demux->segment_seqnum)
6406 gst_event_set_seqnum (demux->pending_newsegment,
6407 demux->segment_seqnum);
6409 qtdemux_expose_streams (demux);
6412 GST_DEBUG_OBJECT (demux, "Discarding [moof]");
6414 } else if (fourcc == FOURCC_ftyp) {
6415 GST_DEBUG_OBJECT (demux, "Parsing [ftyp]");
6416 qtdemux_parse_ftyp (demux, data, demux->neededbytes);
6417 } else if (fourcc == FOURCC_uuid) {
6418 GST_DEBUG_OBJECT (demux, "Parsing [uuid]");
6419 qtdemux_parse_uuid (demux, data, demux->neededbytes);
6420 } else if (fourcc == FOURCC_sidx) {
6421 GST_DEBUG_OBJECT (demux, "Parsing [sidx]");
6422 qtdemux_parse_sidx (demux, data, demux->neededbytes);
6424 GST_WARNING_OBJECT (demux,
6425 "Unknown fourcc while parsing header : %" GST_FOURCC_FORMAT,
6426 GST_FOURCC_ARGS (fourcc));
6427 /* Let's jump that one and go back to initial state */
6429 gst_adapter_unmap (demux->adapter);
6432 if (demux->mdatbuffer && demux->n_streams) {
6433 gsize remaining_data_size = 0;
6435 /* the mdat was before the header */
6436 GST_DEBUG_OBJECT (demux, "We have n_streams:%d and mdatbuffer:%p",
6437 demux->n_streams, demux->mdatbuffer);
6438 /* restore our adapter/offset view of things with upstream;
6439 * put preceding buffered data ahead of current moov data.
6440 * This should also handle evil mdat, moov, mdat cases and alike */
6441 gst_adapter_flush (demux->adapter, demux->neededbytes);
6443 /* Store any remaining data after the mdat for later usage */
6444 remaining_data_size = gst_adapter_available (demux->adapter);
6445 if (remaining_data_size > 0) {
6446 g_assert (demux->restoredata_buffer == NULL);
6447 demux->restoredata_buffer =
6448 gst_adapter_take_buffer (demux->adapter, remaining_data_size);
6449 demux->restoredata_offset = demux->offset + demux->neededbytes;
6450 GST_DEBUG_OBJECT (demux,
6451 "Stored %" G_GSIZE_FORMAT " post mdat bytes at offset %"
6452 G_GUINT64_FORMAT, remaining_data_size,
6453 demux->restoredata_offset);
6456 gst_adapter_push (demux->adapter, demux->mdatbuffer);
6457 demux->mdatbuffer = NULL;
6458 demux->offset = demux->mdatoffset;
6459 demux->neededbytes = next_entry_size (demux);
6460 demux->state = QTDEMUX_STATE_MOVIE;
6461 demux->mdatleft = gst_adapter_available (demux->adapter);
6463 GST_DEBUG_OBJECT (demux, "Carrying on normally");
6464 gst_adapter_flush (demux->adapter, demux->neededbytes);
6466 /* only go back to the mdat if there are samples to play */
6467 if (demux->got_moov && demux->first_mdat != -1
6468 && has_next_entry (demux)) {
6471 /* we need to seek back */
6472 res = qtdemux_seek_offset (demux, demux->first_mdat);
6474 demux->offset = demux->first_mdat;
6476 GST_DEBUG_OBJECT (demux, "Seek back failed");
6479 demux->offset += demux->neededbytes;
6481 demux->neededbytes = 16;
6482 demux->state = QTDEMUX_STATE_INITIAL;
6487 case QTDEMUX_STATE_BUFFER_MDAT:{
6491 GST_DEBUG_OBJECT (demux, "Got our buffer at offset %" G_GUINT64_FORMAT,
6493 buf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
6494 gst_buffer_extract (buf, 0, fourcc, 4);
6495 GST_DEBUG_OBJECT (demux, "mdatbuffer starts with %" GST_FOURCC_FORMAT,
6496 GST_FOURCC_ARGS (QT_FOURCC (fourcc)));
6497 if (demux->mdatbuffer)
6498 demux->mdatbuffer = gst_buffer_append (demux->mdatbuffer, buf);
6500 demux->mdatbuffer = buf;
6501 demux->offset += demux->neededbytes;
6502 demux->neededbytes = 16;
6503 demux->state = QTDEMUX_STATE_INITIAL;
6504 gst_qtdemux_post_progress (demux, 1, 1);
6508 case QTDEMUX_STATE_MOVIE:{
6509 QtDemuxStream *stream = NULL;
6510 QtDemuxSample *sample;
6512 GstClockTime dts, pts, duration;
6515 GST_DEBUG_OBJECT (demux,
6516 "BEGIN // in MOVIE for offset %" G_GUINT64_FORMAT, demux->offset);
6518 if (demux->fragmented) {
6519 GST_DEBUG_OBJECT (demux, "mdat remaining %" G_GUINT64_FORMAT,
6521 if (G_LIKELY (demux->todrop < demux->mdatleft)) {
6522 /* if needed data starts within this atom,
6523 * then it should not exceed this atom */
6524 if (G_UNLIKELY (demux->neededbytes > demux->mdatleft)) {
6525 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
6526 (_("This file is invalid and cannot be played.")),
6527 ("sample data crosses atom boundary"));
6528 ret = GST_FLOW_ERROR;
6531 demux->mdatleft -= demux->neededbytes;
6533 GST_DEBUG_OBJECT (demux, "data atom emptied; resuming atom scan");
6534 /* so we are dropping more than left in this atom */
6535 gst_qtdemux_drop_data (demux, demux->mdatleft);
6536 demux->mdatleft = 0;
6538 /* need to resume atom parsing so we do not miss any other pieces */
6539 demux->state = QTDEMUX_STATE_INITIAL;
6540 demux->neededbytes = 16;
6542 /* check if there was any stored post mdat data from previous buffers */
6543 if (demux->restoredata_buffer) {
6544 g_assert (gst_adapter_available (demux->adapter) == 0);
6546 gst_adapter_push (demux->adapter, demux->restoredata_buffer);
6547 demux->restoredata_buffer = NULL;
6548 demux->offset = demux->restoredata_offset;
6555 if (demux->todrop) {
6556 if (demux->cenc_aux_info_offset > 0) {
6560 GST_DEBUG_OBJECT (demux, "parsing cenc auxiliary info");
6561 data = gst_adapter_map (demux->adapter, demux->todrop);
6562 gst_byte_reader_init (&br, data + 8, demux->todrop);
6563 if (!qtdemux_parse_cenc_aux_info (demux, demux->streams[0], &br,
6564 demux->cenc_aux_info_sizes, demux->cenc_aux_sample_count)) {
6565 GST_ERROR_OBJECT (demux, "failed to parse cenc auxiliary info");
6566 ret = GST_FLOW_ERROR;
6567 gst_adapter_unmap (demux->adapter);
6568 g_free (demux->cenc_aux_info_sizes);
6569 demux->cenc_aux_info_sizes = NULL;
6572 demux->cenc_aux_info_offset = 0;
6573 g_free (demux->cenc_aux_info_sizes);
6574 demux->cenc_aux_info_sizes = NULL;
6575 gst_adapter_unmap (demux->adapter);
6577 gst_qtdemux_drop_data (demux, demux->todrop);
6581 /* initial newsegment sent here after having added pads,
6582 * possible others in sink_event */
6583 gst_qtdemux_check_send_pending_segment (demux);
6585 /* Figure out which stream this packet belongs to */
6586 for (i = 0; i < demux->n_streams; i++) {
6587 stream = demux->streams[i];
6588 if (stream->sample_index >= stream->n_samples)
6590 GST_LOG_OBJECT (demux,
6591 "Checking stream %d (sample_index:%d / offset:%" G_GUINT64_FORMAT
6592 " / size:%d)", i, stream->sample_index,
6593 stream->samples[stream->sample_index].offset,
6594 stream->samples[stream->sample_index].size);
6596 if (stream->samples[stream->sample_index].offset == demux->offset)
6600 if (G_UNLIKELY (stream == NULL || i == demux->n_streams))
6601 goto unknown_stream;
6603 if (stream->new_caps) {
6604 gst_qtdemux_configure_stream (demux, stream);
6607 /* Put data in a buffer, set timestamps, caps, ... */
6608 sample = &stream->samples[stream->sample_index];
6610 if (G_LIKELY (!(STREAM_IS_EOS (stream)))) {
6611 GST_DEBUG_OBJECT (demux, "stream : %" GST_FOURCC_FORMAT,
6612 GST_FOURCC_ARGS (stream->fourcc));
6614 dts = QTSAMPLE_DTS (stream, sample);
6615 pts = QTSAMPLE_PTS (stream, sample);
6616 duration = QTSAMPLE_DUR_DTS (stream, sample, dts);
6617 keyframe = QTSAMPLE_KEYFRAME (stream, sample);
6619 /* check for segment end */
6620 if (G_UNLIKELY (demux->segment.stop != -1
6621 && demux->segment.stop <= pts && stream->on_keyframe)) {
6622 GST_DEBUG_OBJECT (demux, "we reached the end of our segment.");
6623 stream->time_position = GST_CLOCK_TIME_NONE; /* this means EOS */
6625 /* skip this data, stream is EOS */
6626 gst_adapter_flush (demux->adapter, demux->neededbytes);
6628 /* check if all streams are eos */
6630 for (i = 0; i < demux->n_streams; i++) {
6631 if (!STREAM_IS_EOS (demux->streams[i])) {
6637 if (ret == GST_FLOW_EOS) {
6638 GST_DEBUG_OBJECT (demux, "All streams are EOS, signal upstream");
6645 gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
6647 /* FIXME: should either be an assert or a plain check */
6648 g_return_val_if_fail (outbuf != NULL, GST_FLOW_ERROR);
6650 ret = gst_qtdemux_decorate_and_push_buffer (demux, stream, outbuf,
6651 dts, pts, duration, keyframe, dts, demux->offset);
6655 ret = gst_qtdemux_combine_flows (demux, stream, ret);
6656 if (ret != GST_FLOW_OK && ret != GST_FLOW_NOT_LINKED)
6657 goto non_ok_unlinked_flow;
6659 /* skip this data, stream is EOS */
6660 gst_adapter_flush (demux->adapter, demux->neededbytes);
6663 stream->sample_index++;
6664 stream->offset_in_sample = 0;
6666 /* update current offset and figure out size of next buffer */
6667 GST_LOG_OBJECT (demux, "increasing offset %" G_GUINT64_FORMAT " by %u",
6668 demux->offset, demux->neededbytes);
6669 demux->offset += demux->neededbytes;
6670 GST_LOG_OBJECT (demux, "offset is now %" G_GUINT64_FORMAT,
6673 if ((demux->neededbytes = next_entry_size (demux)) == -1) {
6674 if (demux->fragmented) {
6675 GST_DEBUG_OBJECT (demux, "(temporarily) out of fragmented samples");
6676 /* there may be more to follow, only finish this atom */
6677 demux->todrop = demux->mdatleft;
6678 demux->neededbytes = demux->todrop;
6690 /* when buffering movie data, at least show user something is happening */
6691 if (ret == GST_FLOW_OK && demux->state == QTDEMUX_STATE_BUFFER_MDAT &&
6692 gst_adapter_available (demux->adapter) <= demux->neededbytes) {
6693 gst_qtdemux_post_progress (demux, gst_adapter_available (demux->adapter),
6694 demux->neededbytes);
6701 non_ok_unlinked_flow:
6703 GST_DEBUG_OBJECT (demux, "Stopping, combined return flow %s",
6704 gst_flow_get_name (ret));
6709 GST_ELEMENT_ERROR (demux, STREAM, FAILED, (NULL), ("unknown stream found"));
6710 ret = GST_FLOW_ERROR;
6715 GST_DEBUG_OBJECT (demux, "no next entry, EOS");
6721 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
6722 (NULL), ("qtdemuxer invalid state %d", demux->state));
6723 ret = GST_FLOW_ERROR;
6728 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
6729 (NULL), ("no 'moov' atom within the first 10 MB"));
6730 ret = GST_FLOW_ERROR;
6736 qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent)
6741 query = gst_query_new_scheduling ();
6743 if (!gst_pad_peer_query (sinkpad, query)) {
6744 gst_query_unref (query);
6748 pull_mode = gst_query_has_scheduling_mode_with_flags (query,
6749 GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
6750 gst_query_unref (query);
6755 GST_DEBUG_OBJECT (sinkpad, "activating pull");
6756 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
6760 GST_DEBUG_OBJECT (sinkpad, "activating push");
6761 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
6766 qtdemux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
6767 GstPadMode mode, gboolean active)
6770 GstQTDemux *demux = GST_QTDEMUX (parent);
6773 case GST_PAD_MODE_PUSH:
6774 demux->pullbased = FALSE;
6777 case GST_PAD_MODE_PULL:
6779 demux->pullbased = TRUE;
6780 res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_qtdemux_loop,
6783 res = gst_pad_stop_task (sinkpad);
6795 qtdemux_zalloc (void *opaque, unsigned int items, unsigned int size)
6797 return g_malloc (items * size);
6801 qtdemux_zfree (void *opaque, void *addr)
6807 qtdemux_inflate (void *z_buffer, guint z_length, guint length)
6813 z = g_new0 (z_stream, 1);
6814 z->zalloc = qtdemux_zalloc;
6815 z->zfree = qtdemux_zfree;
6818 z->next_in = z_buffer;
6819 z->avail_in = z_length;
6821 buffer = (guint8 *) g_malloc (length);
6822 ret = inflateInit (z);
6823 while (z->avail_in > 0) {
6824 if (z->avail_out == 0) {
6826 buffer = (guint8 *) g_realloc (buffer, length);
6827 z->next_out = buffer + z->total_out;
6828 z->avail_out = 1024;
6830 ret = inflate (z, Z_SYNC_FLUSH);
6834 if (ret != Z_STREAM_END) {
6835 g_warning ("inflate() returned %d", ret);
6841 #endif /* HAVE_ZLIB */
6844 qtdemux_parse_moov (GstQTDemux * qtdemux, const guint8 * buffer, guint length)
6848 qtdemux->moov_node = g_node_new ((guint8 *) buffer);
6850 /* counts as header data */
6851 qtdemux->header_size += length;
6853 GST_DEBUG_OBJECT (qtdemux, "parsing 'moov' atom");
6854 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buffer, length);
6856 cmov = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_cmov);
6862 dcom = qtdemux_tree_get_child_by_type (cmov, FOURCC_dcom);
6863 cmvd = qtdemux_tree_get_child_by_type (cmov, FOURCC_cmvd);
6864 if (dcom == NULL || cmvd == NULL)
6865 goto invalid_compression;
6867 method = QT_FOURCC ((guint8 *) dcom->data + 8);
6871 guint uncompressed_length;
6872 guint compressed_length;
6875 uncompressed_length = QT_UINT32 ((guint8 *) cmvd->data + 8);
6876 compressed_length = QT_UINT32 ((guint8 *) cmvd->data + 4) - 12;
6877 GST_LOG ("length = %u", uncompressed_length);
6880 (guint8 *) qtdemux_inflate ((guint8 *) cmvd->data + 12,
6881 compressed_length, uncompressed_length);
6883 qtdemux->moov_node_compressed = qtdemux->moov_node;
6884 qtdemux->moov_node = g_node_new (buf);
6886 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buf,
6887 uncompressed_length);
6890 #endif /* HAVE_ZLIB */
6892 GST_WARNING_OBJECT (qtdemux, "unknown or unhandled header compression "
6893 "type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (method));
6900 invalid_compression:
6902 GST_ERROR_OBJECT (qtdemux, "invalid compressed header");
6908 qtdemux_parse_container (GstQTDemux * qtdemux, GNode * node, const guint8 * buf,
6911 while (G_UNLIKELY (buf < end)) {
6915 if (G_UNLIKELY (buf + 4 > end)) {
6916 GST_LOG_OBJECT (qtdemux, "buffer overrun");
6919 len = QT_UINT32 (buf);
6920 if (G_UNLIKELY (len == 0)) {
6921 GST_LOG_OBJECT (qtdemux, "empty container");
6924 if (G_UNLIKELY (len < 8)) {
6925 GST_WARNING_OBJECT (qtdemux, "length too short (%d < 8)", len);
6928 if (G_UNLIKELY (len > (end - buf))) {
6929 GST_WARNING_OBJECT (qtdemux, "length too long (%d > %d)", len,
6930 (gint) (end - buf));
6934 child = g_node_new ((guint8 *) buf);
6935 g_node_append (node, child);
6936 GST_LOG_OBJECT (qtdemux, "adding new node of len %d", len);
6937 qtdemux_parse_node (qtdemux, child, buf, len);
6945 qtdemux_parse_theora_extension (GstQTDemux * qtdemux, QtDemuxStream * stream,
6948 int len = QT_UINT32 (xdxt->data);
6949 guint8 *buf = xdxt->data;
6950 guint8 *end = buf + len;
6953 /* skip size and type */
6961 size = QT_UINT32 (buf);
6962 type = QT_FOURCC (buf + 4);
6964 GST_LOG_OBJECT (qtdemux, "%p %p", buf, end);
6966 if (buf + size > end || size <= 0)
6972 GST_WARNING_OBJECT (qtdemux, "have cookie %" GST_FOURCC_FORMAT,
6973 GST_FOURCC_ARGS (type));
6977 buffer = gst_buffer_new_and_alloc (size);
6978 gst_buffer_fill (buffer, 0, buf, size);
6979 stream->buffers = g_slist_append (stream->buffers, buffer);
6980 GST_LOG_OBJECT (qtdemux, "parsing theora header");
6983 buffer = gst_buffer_new_and_alloc (size);
6984 gst_buffer_fill (buffer, 0, buf, size);
6985 stream->buffers = g_slist_append (stream->buffers, buffer);
6986 GST_LOG_OBJECT (qtdemux, "parsing theora comment");
6989 buffer = gst_buffer_new_and_alloc (size);
6990 gst_buffer_fill (buffer, 0, buf, size);
6991 stream->buffers = g_slist_append (stream->buffers, buffer);
6992 GST_LOG_OBJECT (qtdemux, "parsing theora codebook");
6995 GST_WARNING_OBJECT (qtdemux,
6996 "unknown theora cookie %" GST_FOURCC_FORMAT,
6997 GST_FOURCC_ARGS (type));
7006 qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node, const guint8 * buffer,
7010 guint32 node_length = 0;
7011 const QtNodeType *type;
7014 GST_LOG_OBJECT (qtdemux, "qtdemux_parse buffer %p length %u", buffer, length);
7016 if (G_UNLIKELY (length < 8))
7017 goto not_enough_data;
7019 node_length = QT_UINT32 (buffer);
7020 fourcc = QT_FOURCC (buffer + 4);
7022 /* ignore empty nodes */
7023 if (G_UNLIKELY (fourcc == 0 || node_length == 8))
7026 type = qtdemux_type_get (fourcc);
7028 end = buffer + length;
7030 GST_LOG_OBJECT (qtdemux,
7031 "parsing '%" GST_FOURCC_FORMAT "', length=%u, name '%s'",
7032 GST_FOURCC_ARGS (fourcc), node_length, type->name);
7034 if (node_length > length)
7035 goto broken_atom_size;
7037 if (type->flags & QT_FLAG_CONTAINER) {
7038 qtdemux_parse_container (qtdemux, node, buffer + 8, end);
7043 if (node_length < 20) {
7044 GST_LOG_OBJECT (qtdemux, "skipping small stsd box");
7047 GST_DEBUG_OBJECT (qtdemux,
7048 "parsing stsd (sample table, sample description) atom");
7049 /* Skip over 8 byte atom hdr + 1 byte version, 3 bytes flags, 4 byte num_entries */
7050 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
7060 /* also read alac (or whatever) in stead of mp4a in the following,
7061 * since a similar layout is used in other cases as well */
7062 if (fourcc == FOURCC_mp4a)
7067 /* There are two things we might encounter here: a true mp4a atom, and
7068 an mp4a entry in an stsd atom. The latter is what we're interested
7069 in, and it looks like an atom, but isn't really one. The true mp4a
7070 atom is short, so we detect it based on length here. */
7071 if (length < min_size) {
7072 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
7073 GST_FOURCC_ARGS (fourcc));
7077 /* 'version' here is the sound sample description version. Types 0 and
7078 1 are documented in the QTFF reference, but type 2 is not: it's
7079 described in Apple header files instead (struct SoundDescriptionV2
7081 version = QT_UINT16 (buffer + 16);
7083 GST_DEBUG_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT " version 0x%08x",
7084 GST_FOURCC_ARGS (fourcc), version);
7086 /* parse any esds descriptors */
7098 GST_WARNING_OBJECT (qtdemux,
7099 "unhandled %" GST_FOURCC_FORMAT " version 0x%08x",
7100 GST_FOURCC_ARGS (fourcc), version);
7105 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
7122 /* codec_data is contained inside these atoms, which all have
7123 * the same format. */
7125 GST_DEBUG_OBJECT (qtdemux, "parsing in %" GST_FOURCC_FORMAT,
7126 GST_FOURCC_ARGS (fourcc));
7127 version = QT_UINT32 (buffer + 16);
7128 GST_DEBUG_OBJECT (qtdemux, "version %08x", version);
7129 if (1 || version == 0x00000000) {
7130 buf = buffer + 0x32;
7132 /* FIXME Quicktime uses PASCAL string while
7133 * the iso format uses C strings. Check the file
7134 * type before attempting to parse the string here. */
7135 tlen = QT_UINT8 (buf);
7136 GST_DEBUG_OBJECT (qtdemux, "tlen = %d", tlen);
7138 GST_DEBUG_OBJECT (qtdemux, "string = %.*s", tlen, (char *) buf);
7139 /* the string has a reserved space of 32 bytes so skip
7140 * the remaining 31 */
7142 buf += 4; /* and 4 bytes reserved */
7144 GST_MEMDUMP_OBJECT (qtdemux, "mp4v", buf, end - buf);
7146 qtdemux_parse_container (qtdemux, node, buf, end);
7152 GST_MEMDUMP_OBJECT (qtdemux, "H264", buffer, end - buffer);
7153 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
7158 GST_MEMDUMP_OBJECT (qtdemux, "avc1", buffer, end - buffer);
7159 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
7164 GST_MEMDUMP_OBJECT (qtdemux, "avc3", buffer, end - buffer);
7165 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
7170 GST_MEMDUMP_OBJECT (qtdemux, "H265", buffer, end - buffer);
7171 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
7176 GST_MEMDUMP_OBJECT (qtdemux, "hvc1", buffer, end - buffer);
7177 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
7182 GST_MEMDUMP_OBJECT (qtdemux, "hev1", buffer, end - buffer);
7183 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
7188 qtdemux_parse_container (qtdemux, node, buffer + 86, end);
7193 GST_DEBUG_OBJECT (qtdemux, "parsing meta atom");
7194 qtdemux_parse_container (qtdemux, node, buffer + 12, end);
7199 GST_MEMDUMP_OBJECT (qtdemux, "mp4s", buffer, end - buffer);
7200 /* Skip 8 byte header, plus 8 byte version + flags + entry_count */
7201 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
7209 version = QT_UINT32 (buffer + 12);
7210 GST_DEBUG_OBJECT (qtdemux, "parsing XiTh atom version 0x%08x", version);
7217 GST_DEBUG_OBJECT (qtdemux, "unknown version 0x%08x", version);
7222 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
7227 qtdemux_parse_container (qtdemux, node, buffer + 0x34, end);
7232 qtdemux_parse_uuid (qtdemux, buffer, end - buffer);
7237 qtdemux_parse_container (qtdemux, node, buffer + 86, end);
7242 qtdemux_parse_container (qtdemux, node, buffer + 36, end);
7246 if (!strcmp (type->name, "unknown"))
7247 GST_MEMDUMP ("Unknown tag", buffer + 4, end - buffer - 4);
7251 GST_LOG_OBJECT (qtdemux, "parsed '%" GST_FOURCC_FORMAT "'",
7252 GST_FOURCC_ARGS (fourcc));
7258 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
7259 (_("This file is corrupt and cannot be played.")),
7260 ("Not enough data for an atom header, got only %u bytes", length));
7265 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
7266 (_("This file is corrupt and cannot be played.")),
7267 ("Atom '%" GST_FOURCC_FORMAT "' has size of %u bytes, but we have only "
7268 "%u bytes available.", GST_FOURCC_ARGS (fourcc), node_length,
7275 qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc)
7279 guint32 child_fourcc;
7281 for (child = g_node_first_child (node); child;
7282 child = g_node_next_sibling (child)) {
7283 buffer = (guint8 *) child->data;
7285 child_fourcc = QT_FOURCC (buffer + 4);
7287 if (G_UNLIKELY (child_fourcc == fourcc)) {
7295 qtdemux_tree_get_child_by_type_full (GNode * node, guint32 fourcc,
7296 GstByteReader * parser)
7300 guint32 child_fourcc, child_len;
7302 for (child = g_node_first_child (node); child;
7303 child = g_node_next_sibling (child)) {
7304 buffer = (guint8 *) child->data;
7306 child_len = QT_UINT32 (buffer);
7307 child_fourcc = QT_FOURCC (buffer + 4);
7309 if (G_UNLIKELY (child_fourcc == fourcc)) {
7310 if (G_UNLIKELY (child_len < (4 + 4)))
7312 /* FIXME: must verify if atom length < parent atom length */
7313 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
7321 qtdemux_tree_get_sibling_by_type_full (GNode * node, guint32 fourcc,
7322 GstByteReader * parser)
7326 guint32 child_fourcc, child_len;
7328 for (child = g_node_next_sibling (node); child;
7329 child = g_node_next_sibling (child)) {
7330 buffer = (guint8 *) child->data;
7332 child_fourcc = QT_FOURCC (buffer + 4);
7334 if (child_fourcc == fourcc) {
7336 child_len = QT_UINT32 (buffer);
7337 if (G_UNLIKELY (child_len < (4 + 4)))
7339 /* FIXME: must verify if atom length < parent atom length */
7340 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
7349 qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc)
7351 return qtdemux_tree_get_sibling_by_type_full (node, fourcc, NULL);
7355 qtdemux_do_allocation (GstQTDemux * qtdemux, QtDemuxStream * stream)
7357 /* FIXME: This can only reliably work if demuxers have a
7358 * separate streaming thread per srcpad. This should be
7359 * done in a demuxer base class, which integrates parts
7362 * https://bugzilla.gnome.org/show_bug.cgi?id=701856
7367 query = gst_query_new_allocation (stream->caps, FALSE);
7369 if (!gst_pad_peer_query (stream->pad, query)) {
7370 /* not a problem, just debug a little */
7371 GST_DEBUG_OBJECT (qtdemux, "peer ALLOCATION query failed");
7374 if (stream->allocator)
7375 gst_object_unref (stream->allocator);
7377 if (gst_query_get_n_allocation_params (query) > 0) {
7378 /* try the allocator */
7379 gst_query_parse_nth_allocation_param (query, 0, &stream->allocator,
7381 stream->use_allocator = TRUE;
7383 stream->allocator = NULL;
7384 gst_allocation_params_init (&stream->params);
7385 stream->use_allocator = FALSE;
7387 gst_query_unref (query);
7392 gst_qtdemux_configure_protected_caps (GstQTDemux * qtdemux,
7393 QtDemuxStream * stream)
7396 const gchar *selected_system;
7398 g_return_val_if_fail (qtdemux != NULL, FALSE);
7399 g_return_val_if_fail (stream != NULL, FALSE);
7400 g_return_val_if_fail (gst_caps_get_size (stream->caps) == 1, FALSE);
7402 if (stream->protection_scheme_type != FOURCC_cenc) {
7403 GST_ERROR_OBJECT (qtdemux, "unsupported protection scheme");
7406 if (qtdemux->protection_system_ids == NULL) {
7407 GST_ERROR_OBJECT (qtdemux, "stream is protected using cenc, but no "
7408 "cenc protection system information has been found");
7411 g_ptr_array_add (qtdemux->protection_system_ids, NULL);
7412 selected_system = gst_protection_select_system ((const gchar **)
7413 qtdemux->protection_system_ids->pdata);
7414 g_ptr_array_remove_index (qtdemux->protection_system_ids,
7415 qtdemux->protection_system_ids->len - 1);
7416 if (!selected_system) {
7417 GST_ERROR_OBJECT (qtdemux, "stream is protected, but no "
7418 "suitable decryptor element has been found");
7422 s = gst_caps_get_structure (stream->caps, 0);
7423 if (!gst_structure_has_name (s, "application/x-cenc")) {
7424 gst_structure_set (s,
7425 "original-media-type", G_TYPE_STRING, gst_structure_get_name (s),
7426 GST_PROTECTION_SYSTEM_ID_CAPS_FIELD, G_TYPE_STRING, selected_system,
7428 gst_structure_set_name (s, "application/x-cenc");
7434 gst_qtdemux_configure_stream (GstQTDemux * qtdemux, QtDemuxStream * stream)
7436 if (stream->subtype == FOURCC_vide) {
7437 /* fps is calculated base on the duration of the average framerate since
7438 * qt does not have a fixed framerate. */
7439 gboolean fps_available = TRUE;
7441 if ((stream->n_samples == 1) && (stream->first_duration == 0)) {
7446 if (stream->duration == 0 || stream->n_samples < 2) {
7447 stream->fps_n = stream->timescale;
7449 fps_available = FALSE;
7451 GstClockTime avg_duration;
7455 /* duration and n_samples can be updated for fragmented format
7456 * so, framerate of fragmented format is calculated using data in a moof */
7457 if (qtdemux->fragmented && stream->n_samples_moof > 0
7458 && stream->duration_moof > 0) {
7459 n_samples = stream->n_samples_moof;
7460 duration = stream->duration_moof;
7462 n_samples = stream->n_samples;
7463 duration = stream->duration;
7466 /* Calculate a framerate, ignoring the first sample which is sometimes truncated */
7467 /* stream->duration is guint64, timescale, n_samples are guint32 */
7469 gst_util_uint64_scale_round (duration -
7470 stream->first_duration, GST_SECOND,
7471 (guint64) (stream->timescale) * (n_samples - 1));
7473 GST_LOG_OBJECT (qtdemux,
7474 "Calculating avg sample duration based on stream (or moof) duration %"
7476 " minus first sample %u, leaving %d samples gives %"
7477 GST_TIME_FORMAT, duration, stream->first_duration,
7478 n_samples - 1, GST_TIME_ARGS (avg_duration));
7480 gst_video_guess_framerate (avg_duration, &stream->fps_n,
7483 GST_DEBUG_OBJECT (qtdemux,
7484 "Calculating framerate, timescale %u gave fps_n %d fps_d %d",
7485 stream->timescale, stream->fps_n, stream->fps_d);
7490 stream->caps = gst_caps_make_writable (stream->caps);
7492 gst_caps_set_simple (stream->caps,
7493 "width", G_TYPE_INT, stream->width,
7494 "height", G_TYPE_INT, stream->height, NULL);
7496 /* set framerate if calculated framerate is reliable */
7497 if (fps_available) {
7498 gst_caps_set_simple (stream->caps,
7499 "framerate", GST_TYPE_FRACTION, stream->fps_n, stream->fps_d, NULL);
7502 /* calculate pixel-aspect-ratio using display width and height */
7503 GST_DEBUG_OBJECT (qtdemux,
7504 "video size %dx%d, target display size %dx%d", stream->width,
7505 stream->height, stream->display_width, stream->display_height);
7506 /* qt file might have pasp atom */
7507 if (stream->par_w > 0 && stream->par_h > 0) {
7508 GST_DEBUG_OBJECT (qtdemux, "par %d:%d", stream->par_w, stream->par_h);
7509 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
7510 GST_TYPE_FRACTION, stream->par_w, stream->par_h, NULL);
7511 } else if (stream->display_width > 0 && stream->display_height > 0 &&
7512 stream->width > 0 && stream->height > 0) {
7515 /* calculate the pixel aspect ratio using the display and pixel w/h */
7516 n = stream->display_width * stream->height;
7517 d = stream->display_height * stream->width;
7520 GST_DEBUG_OBJECT (qtdemux, "setting PAR to %d/%d", n, d);
7523 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
7524 GST_TYPE_FRACTION, stream->par_w, stream->par_h, NULL);
7527 if (stream->multiview_mode != GST_VIDEO_MULTIVIEW_MODE_NONE) {
7528 guint par_w = 1, par_h = 1;
7530 if (stream->par_w > 0 && stream->par_h > 0) {
7531 par_w = stream->par_w;
7532 par_h = stream->par_h;
7535 if (gst_video_multiview_guess_half_aspect (stream->multiview_mode,
7536 stream->width, stream->height, par_w, par_h)) {
7537 stream->multiview_flags |= GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT;
7540 gst_caps_set_simple (stream->caps,
7541 "multiview-mode", G_TYPE_STRING,
7542 gst_video_multiview_mode_to_caps_string (stream->multiview_mode),
7543 "multiview-flags", GST_TYPE_VIDEO_MULTIVIEW_FLAGSET,
7544 stream->multiview_flags, GST_FLAG_SET_MASK_EXACT, NULL);
7549 else if (stream->subtype == FOURCC_soun) {
7551 stream->caps = gst_caps_make_writable (stream->caps);
7552 if (stream->rate > 0)
7553 gst_caps_set_simple (stream->caps,
7554 "rate", G_TYPE_INT, (int) stream->rate, NULL);
7555 if (stream->n_channels > 0)
7556 gst_caps_set_simple (stream->caps,
7557 "channels", G_TYPE_INT, stream->n_channels, NULL);
7558 if (stream->n_channels > 2) {
7559 /* FIXME: Need to parse the 'chan' atom to get channel layouts
7560 * correctly; this is just the minimum we can do - assume
7561 * we don't actually have any channel positions. */
7562 gst_caps_set_simple (stream->caps,
7563 "channel-mask", GST_TYPE_BITMASK, G_GUINT64_CONSTANT (0), NULL);
7569 GstCaps *prev_caps = NULL;
7571 GST_PAD_ELEMENT_PRIVATE (stream->pad) = stream;
7572 gst_pad_set_event_function (stream->pad, gst_qtdemux_handle_src_event);
7573 gst_pad_set_query_function (stream->pad, gst_qtdemux_handle_src_query);
7574 gst_pad_set_active (stream->pad, TRUE);
7576 gst_pad_use_fixed_caps (stream->pad);
7578 if (stream->protected) {
7579 if (!gst_qtdemux_configure_protected_caps (qtdemux, stream)) {
7580 GST_ERROR_OBJECT (qtdemux,
7581 "Failed to configure protected stream caps.");
7586 if (stream->new_stream) {
7589 GstStreamFlags stream_flags;
7592 gst_pad_get_sticky_event (qtdemux->sinkpad, GST_EVENT_STREAM_START,
7595 if (gst_event_parse_group_id (event, &qtdemux->group_id))
7596 qtdemux->have_group_id = TRUE;
7598 qtdemux->have_group_id = FALSE;
7599 gst_event_unref (event);
7600 } else if (!qtdemux->have_group_id) {
7601 qtdemux->have_group_id = TRUE;
7602 qtdemux->group_id = gst_util_group_id_next ();
7605 stream->new_stream = FALSE;
7607 gst_pad_create_stream_id_printf (stream->pad,
7608 GST_ELEMENT_CAST (qtdemux), "%03u", stream->track_id);
7609 event = gst_event_new_stream_start (stream_id);
7610 if (qtdemux->have_group_id)
7611 gst_event_set_group_id (event, qtdemux->group_id);
7612 stream_flags = GST_STREAM_FLAG_NONE;
7613 if (stream->disabled)
7614 stream_flags |= GST_STREAM_FLAG_UNSELECT;
7616 stream_flags |= GST_STREAM_FLAG_SPARSE;
7617 gst_event_set_stream_flags (event, stream_flags);
7618 gst_pad_push_event (stream->pad, event);
7622 prev_caps = gst_pad_get_current_caps (stream->pad);
7624 if (!prev_caps || !gst_caps_is_equal_fixed (prev_caps, stream->caps)) {
7625 GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT, stream->caps);
7626 gst_pad_set_caps (stream->pad, stream->caps);
7628 GST_DEBUG_OBJECT (qtdemux, "ignore duplicated caps");
7632 gst_caps_unref (prev_caps);
7633 stream->new_caps = FALSE;
7639 gst_qtdemux_add_stream (GstQTDemux * qtdemux,
7640 QtDemuxStream * stream, GstTagList * list)
7642 gboolean ret = TRUE;
7643 /* consistent default for push based mode */
7644 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
7646 if (stream->subtype == FOURCC_vide) {
7647 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
7650 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
7653 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
7654 gst_object_unref (stream->pad);
7660 qtdemux->n_video_streams++;
7661 } else if (stream->subtype == FOURCC_soun) {
7662 gchar *name = g_strdup_printf ("audio_%u", qtdemux->n_audio_streams);
7665 gst_pad_new_from_static_template (&gst_qtdemux_audiosrc_template, name);
7667 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
7668 gst_object_unref (stream->pad);
7673 qtdemux->n_audio_streams++;
7674 } else if (stream->subtype == FOURCC_strm) {
7675 GST_DEBUG_OBJECT (qtdemux, "stream type, not creating pad");
7676 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
7677 || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt) {
7678 gchar *name = g_strdup_printf ("subtitle_%u", qtdemux->n_sub_streams);
7681 gst_pad_new_from_static_template (&gst_qtdemux_subsrc_template, name);
7683 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
7684 gst_object_unref (stream->pad);
7689 qtdemux->n_sub_streams++;
7690 } else if (stream->caps) {
7691 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
7694 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
7696 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
7697 gst_object_unref (stream->pad);
7702 qtdemux->n_video_streams++;
7704 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
7711 GST_DEBUG_OBJECT (qtdemux, "adding pad %s %p to qtdemux %p",
7712 GST_OBJECT_NAME (stream->pad), stream->pad, qtdemux);
7713 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
7714 gst_flow_combiner_add_pad (qtdemux->flowcombiner, stream->pad);
7716 if (stream->pending_tags)
7717 gst_tag_list_unref (stream->pending_tags);
7718 stream->pending_tags = list;
7720 /* global tags go on each pad anyway */
7721 stream->send_global_tags = TRUE;
7722 /* send upstream GST_EVENT_PROTECTION events that were received before
7723 this source pad was created */
7724 for (l = qtdemux->protection_event_queue.head; l != NULL; l = l->next)
7725 gst_pad_push_event (stream->pad, gst_event_ref (l->data));
7729 gst_tag_list_unref (list);
7733 /* find next atom with @fourcc starting at @offset */
7734 static GstFlowReturn
7735 qtdemux_find_atom (GstQTDemux * qtdemux, guint64 * offset,
7736 guint64 * length, guint32 fourcc)
7742 GST_LOG_OBJECT (qtdemux, "finding fourcc %" GST_FOURCC_FORMAT " at offset %"
7743 G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), *offset);
7749 ret = gst_pad_pull_range (qtdemux->sinkpad, *offset, 16, &buf);
7750 if (G_UNLIKELY (ret != GST_FLOW_OK))
7752 if (G_UNLIKELY (gst_buffer_get_size (buf) != 16)) {
7755 gst_buffer_unref (buf);
7758 gst_buffer_map (buf, &map, GST_MAP_READ);
7759 extract_initial_length_and_fourcc (map.data, 16, length, &lfourcc);
7760 gst_buffer_unmap (buf, &map);
7761 gst_buffer_unref (buf);
7763 if (G_UNLIKELY (*length == 0)) {
7764 GST_DEBUG_OBJECT (qtdemux, "invalid length 0");
7765 ret = GST_FLOW_ERROR;
7769 if (lfourcc == fourcc) {
7770 GST_DEBUG_OBJECT (qtdemux, "found fourcc at offset %" G_GUINT64_FORMAT,
7774 GST_LOG_OBJECT (qtdemux,
7775 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
7776 GST_FOURCC_ARGS (fourcc), *offset);
7785 /* might simply have had last one */
7786 GST_DEBUG_OBJECT (qtdemux, "fourcc not found");
7791 /* should only do something in pull mode */
7792 /* call with OBJECT lock */
7793 static GstFlowReturn
7794 qtdemux_add_fragmented_samples (GstQTDemux * qtdemux)
7796 guint64 length, offset;
7797 GstBuffer *buf = NULL;
7798 GstFlowReturn ret = GST_FLOW_OK;
7799 GstFlowReturn res = GST_FLOW_OK;
7802 offset = qtdemux->moof_offset;
7803 GST_DEBUG_OBJECT (qtdemux, "next moof at offset %" G_GUINT64_FORMAT, offset);
7806 GST_DEBUG_OBJECT (qtdemux, "no next moof");
7807 return GST_FLOW_EOS;
7810 /* best not do pull etc with lock held */
7811 GST_OBJECT_UNLOCK (qtdemux);
7813 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
7814 if (ret != GST_FLOW_OK)
7817 ret = gst_qtdemux_pull_atom (qtdemux, offset, length, &buf);
7818 if (G_UNLIKELY (ret != GST_FLOW_OK))
7820 gst_buffer_map (buf, &map, GST_MAP_READ);
7821 if (!qtdemux_parse_moof (qtdemux, map.data, map.size, offset, NULL)) {
7822 gst_buffer_unmap (buf, &map);
7823 gst_buffer_unref (buf);
7828 gst_buffer_unmap (buf, &map);
7829 gst_buffer_unref (buf);
7833 /* look for next moof */
7834 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
7835 if (G_UNLIKELY (ret != GST_FLOW_OK))
7839 GST_OBJECT_LOCK (qtdemux);
7841 qtdemux->moof_offset = offset;
7847 GST_DEBUG_OBJECT (qtdemux, "failed to parse moof");
7849 res = GST_FLOW_ERROR;
7854 /* maybe upstream temporarily flushing */
7855 if (ret != GST_FLOW_FLUSHING) {
7856 GST_DEBUG_OBJECT (qtdemux, "no next moof");
7859 GST_DEBUG_OBJECT (qtdemux, "upstream WRONG_STATE");
7860 /* resume at current position next time */
7867 /* initialise bytereaders for stbl sub-atoms */
7869 qtdemux_stbl_init (GstQTDemux * qtdemux, QtDemuxStream * stream, GNode * stbl)
7871 stream->stbl_index = -1; /* no samples have yet been parsed */
7872 stream->sample_index = -1;
7874 /* time-to-sample atom */
7875 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stts, &stream->stts))
7878 /* copy atom data into a new buffer for later use */
7879 stream->stts.data = g_memdup (stream->stts.data, stream->stts.size);
7881 /* skip version + flags */
7882 if (!gst_byte_reader_skip (&stream->stts, 1 + 3) ||
7883 !gst_byte_reader_get_uint32_be (&stream->stts, &stream->n_sample_times))
7885 GST_LOG_OBJECT (qtdemux, "%u timestamp blocks", stream->n_sample_times);
7887 /* make sure there's enough data */
7888 if (!qt_atom_parser_has_chunks (&stream->stts, stream->n_sample_times, 8)) {
7889 stream->n_sample_times = gst_byte_reader_get_remaining (&stream->stts) / 8;
7890 GST_LOG_OBJECT (qtdemux, "overriding to %u timestamp blocks",
7891 stream->n_sample_times);
7892 if (!stream->n_sample_times)
7896 /* sync sample atom */
7897 stream->stps_present = FALSE;
7898 if ((stream->stss_present =
7899 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stss,
7900 &stream->stss) ? TRUE : FALSE) == TRUE) {
7901 /* copy atom data into a new buffer for later use */
7902 stream->stss.data = g_memdup (stream->stss.data, stream->stss.size);
7904 /* skip version + flags */
7905 if (!gst_byte_reader_skip (&stream->stss, 1 + 3) ||
7906 !gst_byte_reader_get_uint32_be (&stream->stss, &stream->n_sample_syncs))
7909 if (stream->n_sample_syncs) {
7910 /* make sure there's enough data */
7911 if (!qt_atom_parser_has_chunks (&stream->stss, stream->n_sample_syncs, 4))
7915 /* partial sync sample atom */
7916 if ((stream->stps_present =
7917 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stps,
7918 &stream->stps) ? TRUE : FALSE) == TRUE) {
7919 /* copy atom data into a new buffer for later use */
7920 stream->stps.data = g_memdup (stream->stps.data, stream->stps.size);
7922 /* skip version + flags */
7923 if (!gst_byte_reader_skip (&stream->stps, 1 + 3) ||
7924 !gst_byte_reader_get_uint32_be (&stream->stps,
7925 &stream->n_sample_partial_syncs))
7928 /* if there are no entries, the stss table contains the real
7930 if (stream->n_sample_partial_syncs) {
7931 /* make sure there's enough data */
7932 if (!qt_atom_parser_has_chunks (&stream->stps,
7933 stream->n_sample_partial_syncs, 4))
7940 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsz, &stream->stsz))
7943 /* copy atom data into a new buffer for later use */
7944 stream->stsz.data = g_memdup (stream->stsz.data, stream->stsz.size);
7946 /* skip version + flags */
7947 if (!gst_byte_reader_skip (&stream->stsz, 1 + 3) ||
7948 !gst_byte_reader_get_uint32_be (&stream->stsz, &stream->sample_size))
7951 if (!gst_byte_reader_get_uint32_be (&stream->stsz, &stream->n_samples))
7954 if (!stream->n_samples)
7957 /* sample-to-chunk atom */
7958 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsc, &stream->stsc))
7961 /* copy atom data into a new buffer for later use */
7962 stream->stsc.data = g_memdup (stream->stsc.data, stream->stsc.size);
7964 /* skip version + flags */
7965 if (!gst_byte_reader_skip (&stream->stsc, 1 + 3) ||
7966 !gst_byte_reader_get_uint32_be (&stream->stsc,
7967 &stream->n_samples_per_chunk))
7970 GST_DEBUG_OBJECT (qtdemux, "n_samples_per_chunk %u",
7971 stream->n_samples_per_chunk);
7973 /* make sure there's enough data */
7974 if (!qt_atom_parser_has_chunks (&stream->stsc, stream->n_samples_per_chunk,
7980 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stco, &stream->stco))
7981 stream->co_size = sizeof (guint32);
7982 else if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_co64,
7984 stream->co_size = sizeof (guint64);
7988 /* copy atom data into a new buffer for later use */
7989 stream->stco.data = g_memdup (stream->stco.data, stream->stco.size);
7991 /* skip version + flags */
7992 if (!gst_byte_reader_skip (&stream->stco, 1 + 3))
7995 /* chunks_are_samples == TRUE means treat chunks as samples */
7996 stream->chunks_are_samples = stream->sample_size && !stream->sampled;
7997 if (stream->chunks_are_samples) {
7998 /* treat chunks as samples */
7999 if (!gst_byte_reader_get_uint32_be (&stream->stco, &stream->n_samples))
8002 /* skip number of entries */
8003 if (!gst_byte_reader_skip (&stream->stco, 4))
8006 /* make sure there are enough data in the stsz atom */
8007 if (!stream->sample_size) {
8008 /* different sizes for each sample */
8009 if (!qt_atom_parser_has_chunks (&stream->stsz, stream->n_samples, 4))
8014 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
8015 stream->n_samples, (guint) sizeof (QtDemuxSample),
8016 stream->n_samples * sizeof (QtDemuxSample) / (1024.0 * 1024.0));
8018 if (stream->n_samples >=
8019 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample)) {
8020 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
8021 "be larger than %uMB (broken file?)", stream->n_samples,
8022 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
8026 g_assert (stream->samples == NULL);
8027 stream->samples = g_try_new0 (QtDemuxSample, stream->n_samples);
8028 if (!stream->samples) {
8029 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
8034 /* composition time-to-sample */
8035 if ((stream->ctts_present =
8036 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_ctts,
8037 &stream->ctts) ? TRUE : FALSE) == TRUE) {
8038 GstByteReader cslg = GST_BYTE_READER_INIT (NULL, 0);
8040 /* copy atom data into a new buffer for later use */
8041 stream->ctts.data = g_memdup (stream->ctts.data, stream->ctts.size);
8043 /* skip version + flags */
8044 if (!gst_byte_reader_skip (&stream->ctts, 1 + 3)
8045 || !gst_byte_reader_get_uint32_be (&stream->ctts,
8046 &stream->n_composition_times))
8049 /* make sure there's enough data */
8050 if (!qt_atom_parser_has_chunks (&stream->ctts, stream->n_composition_times,
8054 /* This is optional, if missing we iterate the ctts */
8055 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_cslg, &cslg)) {
8056 if (!gst_byte_reader_skip (&cslg, 1 + 3)
8057 || !gst_byte_reader_get_uint32_be (&cslg, &stream->cslg_shift)) {
8058 g_free ((gpointer) cslg.data);
8062 gint32 cslg_least = 0;
8063 guint num_entries, pos;
8066 pos = gst_byte_reader_get_pos (&stream->ctts);
8067 num_entries = stream->n_composition_times;
8069 stream->cslg_shift = 0;
8071 for (i = 0; i < num_entries; i++) {
8074 gst_byte_reader_skip_unchecked (&stream->ctts, 4);
8075 offset = gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
8077 if (offset < cslg_least)
8078 cslg_least = offset;
8082 stream->cslg_shift = ABS (cslg_least);
8084 stream->cslg_shift = 0;
8086 /* reset the reader so we can generate sample table */
8087 gst_byte_reader_set_pos (&stream->ctts, pos);
8090 /* Ensure the cslg_shift value is consistent so we can use it
8091 * unconditionnally to produce TS and Segment */
8092 stream->cslg_shift = 0;
8099 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8100 (_("This file is corrupt and cannot be played.")), (NULL));
8105 gst_qtdemux_stbl_free (stream);
8106 if (!qtdemux->fragmented) {
8107 /* not quite good */
8108 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
8111 /* may pick up samples elsewhere */
8117 /* collect samples from the next sample to be parsed up to sample @n for @stream
8118 * by reading the info from @stbl
8120 * This code can be executed from both the streaming thread and the seeking
8121 * thread so it takes the object lock to protect itself
8124 qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream, guint32 n)
8127 QtDemuxSample *samples, *first, *cur, *last;
8128 guint32 n_samples_per_chunk;
8131 GST_LOG_OBJECT (qtdemux, "parsing samples for stream fourcc %"
8132 GST_FOURCC_FORMAT ", pad %s", GST_FOURCC_ARGS (stream->fourcc),
8133 stream->pad ? GST_PAD_NAME (stream->pad) : "(NULL)");
8135 n_samples = stream->n_samples;
8138 goto out_of_samples;
8140 GST_OBJECT_LOCK (qtdemux);
8141 if (n <= stream->stbl_index)
8142 goto already_parsed;
8144 GST_DEBUG_OBJECT (qtdemux, "parsing up to sample %u", n);
8146 if (!stream->stsz.data) {
8147 /* so we already parsed and passed all the moov samples;
8148 * onto fragmented ones */
8149 g_assert (qtdemux->fragmented);
8153 /* pointer to the sample table */
8154 samples = stream->samples;
8156 /* starts from -1, moves to the next sample index to parse */
8157 stream->stbl_index++;
8159 /* keep track of the first and last sample to fill */
8160 first = &samples[stream->stbl_index];
8163 if (!stream->chunks_are_samples) {
8164 /* set the sample sizes */
8165 if (stream->sample_size == 0) {
8166 /* different sizes for each sample */
8167 for (cur = first; cur <= last; cur++) {
8168 cur->size = gst_byte_reader_get_uint32_be_unchecked (&stream->stsz);
8169 GST_LOG_OBJECT (qtdemux, "sample %d has size %u",
8170 (guint) (cur - samples), cur->size);
8173 /* samples have the same size */
8174 GST_LOG_OBJECT (qtdemux, "all samples have size %u", stream->sample_size);
8175 for (cur = first; cur <= last; cur++)
8176 cur->size = stream->sample_size;
8180 n_samples_per_chunk = stream->n_samples_per_chunk;
8183 for (i = stream->stsc_index; i < n_samples_per_chunk; i++) {
8186 if (stream->stsc_chunk_index >= stream->last_chunk
8187 || stream->stsc_chunk_index < stream->first_chunk) {
8188 stream->first_chunk =
8189 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
8190 stream->samples_per_chunk =
8191 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
8192 gst_byte_reader_skip_unchecked (&stream->stsc, 4);
8194 /* chunk numbers are counted from 1 it seems */
8195 if (G_UNLIKELY (stream->first_chunk == 0))
8198 --stream->first_chunk;
8200 /* the last chunk of each entry is calculated by taking the first chunk
8201 * of the next entry; except if there is no next, where we fake it with
8203 if (G_UNLIKELY (i == (stream->n_samples_per_chunk - 1))) {
8204 stream->last_chunk = G_MAXUINT32;
8206 stream->last_chunk =
8207 gst_byte_reader_peek_uint32_be_unchecked (&stream->stsc);
8208 if (G_UNLIKELY (stream->last_chunk == 0))
8211 --stream->last_chunk;
8214 GST_LOG_OBJECT (qtdemux,
8215 "entry %d has first_chunk %d, last_chunk %d, samples_per_chunk %d", i,
8216 stream->first_chunk, stream->last_chunk, stream->samples_per_chunk);
8218 if (G_UNLIKELY (stream->last_chunk < stream->first_chunk))
8221 if (stream->last_chunk != G_MAXUINT32) {
8222 if (!qt_atom_parser_peek_sub (&stream->stco,
8223 stream->first_chunk * stream->co_size,
8224 (stream->last_chunk - stream->first_chunk) * stream->co_size,
8229 stream->co_chunk = stream->stco;
8230 if (!gst_byte_reader_skip (&stream->co_chunk,
8231 stream->first_chunk * stream->co_size))
8235 stream->stsc_chunk_index = stream->first_chunk;
8238 last_chunk = stream->last_chunk;
8240 if (stream->chunks_are_samples) {
8241 cur = &samples[stream->stsc_chunk_index];
8243 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
8246 stream->stsc_chunk_index = j;
8251 qt_atom_parser_get_offset_unchecked (&stream->co_chunk,
8254 GST_LOG_OBJECT (qtdemux, "Created entry %d with offset "
8255 "%" G_GUINT64_FORMAT, j, cur->offset);
8257 if (stream->samples_per_frame * stream->bytes_per_frame) {
8259 (stream->samples_per_chunk * stream->n_channels) /
8260 stream->samples_per_frame * stream->bytes_per_frame;
8262 cur->size = stream->samples_per_chunk;
8265 GST_DEBUG_OBJECT (qtdemux,
8266 "keyframe sample %d: timestamp %" GST_TIME_FORMAT ", size %u",
8267 j, GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream,
8268 stream->stco_sample_index)), cur->size);
8270 cur->timestamp = stream->stco_sample_index;
8271 cur->duration = stream->samples_per_chunk;
8272 cur->keyframe = TRUE;
8275 stream->stco_sample_index += stream->samples_per_chunk;
8277 stream->stsc_chunk_index = j;
8279 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
8280 guint32 samples_per_chunk;
8281 guint64 chunk_offset;
8283 if (!stream->stsc_sample_index
8284 && !qt_atom_parser_get_offset (&stream->co_chunk, stream->co_size,
8285 &stream->chunk_offset))
8288 samples_per_chunk = stream->samples_per_chunk;
8289 chunk_offset = stream->chunk_offset;
8291 for (k = stream->stsc_sample_index; k < samples_per_chunk; k++) {
8292 GST_LOG_OBJECT (qtdemux, "creating entry %d with offset %"
8293 G_GUINT64_FORMAT " and size %d",
8294 (guint) (cur - samples), chunk_offset, cur->size);
8296 cur->offset = chunk_offset;
8297 chunk_offset += cur->size;
8300 if (G_UNLIKELY (cur > last)) {
8302 stream->stsc_sample_index = k + 1;
8303 stream->chunk_offset = chunk_offset;
8304 stream->stsc_chunk_index = j;
8308 stream->stsc_sample_index = 0;
8310 stream->stsc_chunk_index = j;
8312 stream->stsc_index++;
8315 if (stream->chunks_are_samples)
8319 guint32 n_sample_times;
8321 n_sample_times = stream->n_sample_times;
8324 for (i = stream->stts_index; i < n_sample_times; i++) {
8325 guint32 stts_samples;
8326 gint32 stts_duration;
8329 if (stream->stts_sample_index >= stream->stts_samples
8330 || !stream->stts_sample_index) {
8332 stream->stts_samples =
8333 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
8334 stream->stts_duration =
8335 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
8337 GST_LOG_OBJECT (qtdemux, "block %d, %u timestamps, duration %u",
8338 i, stream->stts_samples, stream->stts_duration);
8340 stream->stts_sample_index = 0;
8343 stts_samples = stream->stts_samples;
8344 stts_duration = stream->stts_duration;
8345 stts_time = stream->stts_time;
8347 for (j = stream->stts_sample_index; j < stts_samples; j++) {
8348 GST_DEBUG_OBJECT (qtdemux,
8349 "sample %d: index %d, timestamp %" GST_TIME_FORMAT,
8350 (guint) (cur - samples), j,
8351 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stts_time)));
8353 cur->timestamp = stts_time;
8354 cur->duration = stts_duration;
8356 /* avoid 32-bit wrap-around,
8357 * but still mind possible 'negative' duration */
8358 stts_time += (gint64) stts_duration;
8361 if (G_UNLIKELY (cur > last)) {
8363 stream->stts_time = stts_time;
8364 stream->stts_sample_index = j + 1;
8368 stream->stts_sample_index = 0;
8369 stream->stts_time = stts_time;
8370 stream->stts_index++;
8372 /* fill up empty timestamps with the last timestamp, this can happen when
8373 * the last samples do not decode and so we don't have timestamps for them.
8374 * We however look at the last timestamp to estimate the track length so we
8375 * need something in here. */
8376 for (; cur < last; cur++) {
8377 GST_DEBUG_OBJECT (qtdemux,
8378 "fill sample %d: timestamp %" GST_TIME_FORMAT,
8379 (guint) (cur - samples),
8380 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stream->stts_time)));
8381 cur->timestamp = stream->stts_time;
8387 /* sample sync, can be NULL */
8388 if (stream->stss_present == TRUE) {
8389 guint32 n_sample_syncs;
8391 n_sample_syncs = stream->n_sample_syncs;
8393 if (!n_sample_syncs) {
8394 GST_DEBUG_OBJECT (qtdemux, "all samples are keyframes");
8395 stream->all_keyframe = TRUE;
8397 for (i = stream->stss_index; i < n_sample_syncs; i++) {
8398 /* note that the first sample is index 1, not 0 */
8401 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stss);
8403 if (G_LIKELY (index > 0 && index <= n_samples)) {
8405 samples[index].keyframe = TRUE;
8406 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
8407 /* and exit if we have enough samples */
8408 if (G_UNLIKELY (index >= n)) {
8415 stream->stss_index = i;
8418 /* stps marks partial sync frames like open GOP I-Frames */
8419 if (stream->stps_present == TRUE) {
8420 guint32 n_sample_partial_syncs;
8422 n_sample_partial_syncs = stream->n_sample_partial_syncs;
8424 /* if there are no entries, the stss table contains the real
8426 if (n_sample_partial_syncs) {
8427 for (i = stream->stps_index; i < n_sample_partial_syncs; i++) {
8428 /* note that the first sample is index 1, not 0 */
8431 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stps);
8433 if (G_LIKELY (index > 0 && index <= n_samples)) {
8435 samples[index].keyframe = TRUE;
8436 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
8437 /* and exit if we have enough samples */
8438 if (G_UNLIKELY (index >= n)) {
8445 stream->stps_index = i;
8449 /* no stss, all samples are keyframes */
8450 stream->all_keyframe = TRUE;
8451 GST_DEBUG_OBJECT (qtdemux, "setting all keyframes");
8456 /* composition time to sample */
8457 if (stream->ctts_present == TRUE) {
8458 guint32 n_composition_times;
8460 gint32 ctts_soffset;
8462 /* Fill in the pts_offsets */
8464 n_composition_times = stream->n_composition_times;
8466 for (i = stream->ctts_index; i < n_composition_times; i++) {
8467 if (stream->ctts_sample_index >= stream->ctts_count
8468 || !stream->ctts_sample_index) {
8469 stream->ctts_count =
8470 gst_byte_reader_get_uint32_be_unchecked (&stream->ctts);
8471 stream->ctts_soffset =
8472 gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
8473 stream->ctts_sample_index = 0;
8476 ctts_count = stream->ctts_count;
8477 ctts_soffset = stream->ctts_soffset;
8479 for (j = stream->ctts_sample_index; j < ctts_count; j++) {
8480 cur->pts_offset = ctts_soffset;
8483 if (G_UNLIKELY (cur > last)) {
8485 stream->ctts_sample_index = j + 1;
8489 stream->ctts_sample_index = 0;
8490 stream->ctts_index++;
8494 stream->stbl_index = n;
8495 /* if index has been completely parsed, free data that is no-longer needed */
8496 if (n + 1 == stream->n_samples) {
8497 gst_qtdemux_stbl_free (stream);
8498 GST_DEBUG_OBJECT (qtdemux, "parsed all available samples;");
8499 if (qtdemux->pullbased) {
8500 GST_DEBUG_OBJECT (qtdemux, "checking for more samples");
8501 while (n + 1 == stream->n_samples)
8502 if (qtdemux_add_fragmented_samples (qtdemux) != GST_FLOW_OK)
8506 GST_OBJECT_UNLOCK (qtdemux);
8513 GST_LOG_OBJECT (qtdemux,
8514 "Tried to parse up to sample %u but this sample has already been parsed",
8516 /* if fragmented, there may be more */
8517 if (qtdemux->fragmented && n == stream->stbl_index)
8519 GST_OBJECT_UNLOCK (qtdemux);
8525 GST_LOG_OBJECT (qtdemux,
8526 "Tried to parse up to sample %u but there are only %u samples", n + 1,
8528 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8529 (_("This file is corrupt and cannot be played.")), (NULL));
8534 GST_OBJECT_UNLOCK (qtdemux);
8535 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8536 (_("This file is corrupt and cannot be played.")), (NULL));
8541 /* collect all segment info for @stream.
8544 qtdemux_parse_segments (GstQTDemux * qtdemux, QtDemuxStream * stream,
8548 /* accept edts if they contain gaps at start and there is only
8549 * one media segment */
8550 gboolean allow_pushbased_edts = TRUE;
8551 gint media_segments_count = 0;
8553 /* parse and prepare segment info from the edit list */
8554 GST_DEBUG_OBJECT (qtdemux, "looking for edit list container");
8555 stream->n_segments = 0;
8556 stream->segments = NULL;
8557 if ((edts = qtdemux_tree_get_child_by_type (trak, FOURCC_edts))) {
8560 gint i, count, entry_size;
8566 GST_DEBUG_OBJECT (qtdemux, "looking for edit list");
8567 if (!(elst = qtdemux_tree_get_child_by_type (edts, FOURCC_elst)))
8570 buffer = elst->data;
8572 version = QT_UINT8 (buffer + 8);
8573 entry_size = (version == 1) ? 20 : 12;
8575 n_segments = QT_UINT32 (buffer + 12);
8577 /* we might allocate a bit too much, at least allocate 1 segment */
8578 stream->segments = g_new (QtDemuxSegment, MAX (n_segments, 1));
8580 /* segments always start from 0 */
8584 for (i = 0; i < n_segments; i++) {
8587 gboolean time_valid = TRUE;
8588 QtDemuxSegment *segment;
8590 GstClockTime media_start = GST_CLOCK_TIME_NONE;
8593 media_time = QT_UINT64 (buffer + 24 + i * entry_size);
8594 duration = QT_UINT64 (buffer + 16 + i * entry_size);
8595 if (media_time == G_MAXUINT64)
8598 media_time = QT_UINT32 (buffer + 20 + i * entry_size);
8599 duration = QT_UINT32 (buffer + 16 + i * entry_size);
8600 if (media_time == G_MAXUINT32)
8605 media_start = QTSTREAMTIME_TO_GSTTIME (stream, media_time);
8607 segment = &stream->segments[count++];
8609 /* time and duration expressed in global timescale */
8610 segment->time = stime;
8611 /* add non scaled values so we don't cause roundoff errors */
8612 if (duration || media_start == GST_CLOCK_TIME_NONE) {
8614 stime = QTTIME_TO_GSTTIME (qtdemux, time);
8615 segment->duration = stime - segment->time;
8617 /* zero duration does not imply media_start == media_stop
8618 * but, only specify media_start.*/
8619 stime = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
8620 if (GST_CLOCK_TIME_IS_VALID (stime) && time_valid
8621 && stime >= media_start) {
8622 segment->duration = stime - media_start;
8624 segment->duration = GST_CLOCK_TIME_NONE;
8627 segment->stop_time = stime;
8629 segment->trak_media_start = media_time;
8630 /* media_time expressed in stream timescale */
8632 segment->media_start = media_start;
8633 segment->media_stop = segment->media_start + segment->duration;
8634 media_segments_count++;
8636 segment->media_start = GST_CLOCK_TIME_NONE;
8637 segment->media_stop = GST_CLOCK_TIME_NONE;
8640 QT_UINT32 (buffer + ((version == 1) ? 32 : 24) + i * entry_size);
8642 if (rate_int <= 1) {
8643 /* 0 is not allowed, some programs write 1 instead of the floating point
8645 GST_WARNING_OBJECT (qtdemux, "found suspicious rate %" G_GUINT32_FORMAT,
8649 segment->rate = rate_int / 65536.0;
8652 GST_DEBUG_OBJECT (qtdemux, "created segment %d time %" GST_TIME_FORMAT
8653 ", duration %" GST_TIME_FORMAT ", media_start %" GST_TIME_FORMAT
8654 " (%" G_GUINT64_FORMAT ") , media_stop %" GST_TIME_FORMAT
8655 " stop_time %" GST_TIME_FORMAT " rate %g, (%d) timescale %u",
8656 i, GST_TIME_ARGS (segment->time),
8657 GST_TIME_ARGS (segment->duration),
8658 GST_TIME_ARGS (segment->media_start), media_time,
8659 GST_TIME_ARGS (segment->media_stop),
8660 GST_TIME_ARGS (segment->stop_time), segment->rate, rate_int,
8662 if (segment->stop_time > qtdemux->segment.stop) {
8663 GST_WARNING_OBJECT (qtdemux, "Segment %d "
8664 " extends to %" GST_TIME_FORMAT
8665 " past the end of the file duration %" GST_TIME_FORMAT
8666 " it will be truncated", i, GST_TIME_ARGS (segment->stop_time),
8667 GST_TIME_ARGS (qtdemux->segment.stop));
8668 qtdemux->segment.stop = segment->stop_time;
8671 GST_DEBUG_OBJECT (qtdemux, "found %d segments", count);
8672 stream->n_segments = count;
8673 if (media_segments_count != 1)
8674 allow_pushbased_edts = FALSE;
8678 /* push based does not handle segments, so act accordingly here,
8679 * and warn if applicable */
8680 if (!qtdemux->pullbased && !allow_pushbased_edts) {
8681 GST_WARNING_OBJECT (qtdemux, "streaming; discarding edit list segments");
8682 /* remove and use default one below, we stream like it anyway */
8683 g_free (stream->segments);
8684 stream->segments = NULL;
8685 stream->n_segments = 0;
8688 /* no segments, create one to play the complete trak */
8689 if (stream->n_segments == 0) {
8690 GstClockTime stream_duration =
8691 QTSTREAMTIME_TO_GSTTIME (stream, stream->duration);
8693 if (stream->segments == NULL)
8694 stream->segments = g_new (QtDemuxSegment, 1);
8696 /* represent unknown our way */
8697 if (stream_duration == 0)
8698 stream_duration = GST_CLOCK_TIME_NONE;
8700 stream->segments[0].time = 0;
8701 stream->segments[0].stop_time = stream_duration;
8702 stream->segments[0].duration = stream_duration;
8703 stream->segments[0].media_start = 0;
8704 stream->segments[0].media_stop = stream_duration;
8705 stream->segments[0].rate = 1.0;
8706 stream->segments[0].trak_media_start = 0;
8708 GST_DEBUG_OBJECT (qtdemux, "created dummy segment %" GST_TIME_FORMAT,
8709 GST_TIME_ARGS (stream_duration));
8710 stream->n_segments = 1;
8711 stream->dummy_segment = TRUE;
8713 GST_DEBUG_OBJECT (qtdemux, "using %d segments", stream->n_segments);
8719 * Parses the stsd atom of a svq3 trak looking for
8720 * the SMI and gama atoms.
8723 qtdemux_parse_svq3_stsd_data (GstQTDemux * qtdemux, GNode * stsd,
8724 guint8 ** gamma, GstBuffer ** seqh)
8726 guint8 *_gamma = NULL;
8727 GstBuffer *_seqh = NULL;
8728 guint8 *stsd_data = stsd->data;
8729 guint32 length = QT_UINT32 (stsd_data);
8733 GST_WARNING_OBJECT (qtdemux, "stsd too short");
8739 version = QT_UINT16 (stsd_data);
8744 while (length > 8) {
8745 guint32 fourcc, size;
8747 size = QT_UINT32 (stsd_data);
8748 fourcc = QT_FOURCC (stsd_data + 4);
8749 data = stsd_data + 8;
8752 GST_WARNING_OBJECT (qtdemux, "Atom of size 0 found, aborting "
8753 "svq3 atom parsing");
8762 GST_WARNING_OBJECT (qtdemux, "Unexpected size %" G_GUINT32_FORMAT
8763 " for gama atom, expected 12", size);
8768 if (size > 16 && QT_FOURCC (data) == FOURCC_SEQH) {
8770 if (_seqh != NULL) {
8771 GST_WARNING_OBJECT (qtdemux, "Unexpected second SEQH SMI atom "
8772 " found, ignoring");
8774 seqh_size = QT_UINT32 (data + 4);
8775 if (seqh_size > 0) {
8776 _seqh = gst_buffer_new_and_alloc (seqh_size);
8777 gst_buffer_fill (_seqh, 0, data + 8, seqh_size);
8784 GST_WARNING_OBJECT (qtdemux, "Unhandled atom %" GST_FOURCC_FORMAT
8785 " in SVQ3 entry in stsd atom", GST_FOURCC_ARGS (fourcc));
8789 if (size <= length) {
8795 GST_WARNING_OBJECT (qtdemux, "SVQ3 entry too short in stsd atom");
8798 GST_WARNING_OBJECT (qtdemux, "Unexpected version for SVQ3 entry %"
8799 G_GUINT16_FORMAT, version);
8810 gst_buffer_unref (_seqh);
8815 qtdemux_get_rtsp_uri_from_hndl (GstQTDemux * qtdemux, GNode * minf)
8822 * Get 'dinf', to get its child 'dref', that might contain a 'hndl'
8823 * atom that might contain a 'data' atom with the rtsp uri.
8824 * This case was reported in bug #597497, some info about
8825 * the hndl atom can be found in TN1195
8827 dinf = qtdemux_tree_get_child_by_type (minf, FOURCC_dinf);
8828 GST_DEBUG_OBJECT (qtdemux, "Trying to obtain rtsp URI for stream trak");
8831 guint32 dref_num_entries = 0;
8832 if (qtdemux_tree_get_child_by_type_full (dinf, FOURCC_dref, &dref) &&
8833 gst_byte_reader_skip (&dref, 4) &&
8834 gst_byte_reader_get_uint32_be (&dref, &dref_num_entries)) {
8837 /* search dref entries for hndl atom */
8838 for (i = 0; i < dref_num_entries; i++) {
8839 guint32 size = 0, type;
8840 guint8 string_len = 0;
8841 if (gst_byte_reader_get_uint32_be (&dref, &size) &&
8842 qt_atom_parser_get_fourcc (&dref, &type)) {
8843 if (type == FOURCC_hndl) {
8844 GST_DEBUG_OBJECT (qtdemux, "Found hndl atom");
8846 /* skip data reference handle bytes and the
8847 * following pascal string and some extra 4
8848 * bytes I have no idea what are */
8849 if (!gst_byte_reader_skip (&dref, 4) ||
8850 !gst_byte_reader_get_uint8 (&dref, &string_len) ||
8851 !gst_byte_reader_skip (&dref, string_len + 4)) {
8852 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl atom");
8856 /* iterate over the atoms to find the data atom */
8857 while (gst_byte_reader_get_remaining (&dref) >= 8) {
8861 if (gst_byte_reader_get_uint32_be (&dref, &atom_size) &&
8862 qt_atom_parser_get_fourcc (&dref, &atom_type)) {
8863 if (atom_type == FOURCC_data) {
8864 const guint8 *uri_aux = NULL;
8866 /* found the data atom that might contain the rtsp uri */
8867 GST_DEBUG_OBJECT (qtdemux, "Found data atom inside "
8868 "hndl atom, interpreting it as an URI");
8869 if (gst_byte_reader_peek_data (&dref, atom_size - 8,
8871 if (g_strstr_len ((gchar *) uri_aux, 7, "rtsp://") != NULL)
8872 uri = g_strndup ((gchar *) uri_aux, atom_size - 8);
8874 GST_WARNING_OBJECT (qtdemux, "Data atom in hndl atom "
8875 "didn't contain a rtsp address");
8877 GST_WARNING_OBJECT (qtdemux, "Failed to get the data "
8882 /* skipping to the next entry */
8883 if (!gst_byte_reader_skip (&dref, atom_size - 8))
8886 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl child "
8893 /* skip to the next entry */
8894 if (!gst_byte_reader_skip (&dref, size - 8))
8897 GST_WARNING_OBJECT (qtdemux, "Error parsing dref atom");
8900 GST_DEBUG_OBJECT (qtdemux, "Finished parsing dref atom");
8906 #define AMR_NB_ALL_MODES 0x81ff
8907 #define AMR_WB_ALL_MODES 0x83ff
8909 qtdemux_parse_amr_bitrate (GstBuffer * buf, gboolean wb)
8911 /* The 'damr' atom is of the form:
8913 * | vendor | decoder_ver | mode_set | mode_change_period | frames/sample |
8914 * 32 b 8 b 16 b 8 b 8 b
8916 * The highest set bit of the first 7 (AMR-NB) or 8 (AMR-WB) bits of mode_set
8917 * represents the highest mode used in the stream (and thus the maximum
8918 * bitrate), with a couple of special cases as seen below.
8921 /* Map of frame type ID -> bitrate */
8922 static const guint nb_bitrates[] = {
8923 4750, 5150, 5900, 6700, 7400, 7950, 10200, 12200
8925 static const guint wb_bitrates[] = {
8926 6600, 8850, 12650, 14250, 15850, 18250, 19850, 23050, 23850
8932 gst_buffer_map (buf, &map, GST_MAP_READ);
8934 if (map.size != 0x11) {
8935 GST_DEBUG ("Atom should have size 0x11, not %" G_GSIZE_FORMAT, map.size);
8939 if (QT_FOURCC (map.data + 4) != FOURCC_damr) {
8940 GST_DEBUG ("Unknown atom in %" GST_FOURCC_FORMAT,
8941 GST_FOURCC_ARGS (QT_UINT32 (map.data + 4)));
8945 mode_set = QT_UINT16 (map.data + 13);
8947 if (mode_set == (wb ? AMR_WB_ALL_MODES : AMR_NB_ALL_MODES))
8948 max_mode = 7 + (wb ? 1 : 0);
8950 /* AMR-NB modes fo from 0-7, and AMR-WB modes go from 0-8 */
8951 max_mode = g_bit_nth_msf ((gulong) mode_set & (wb ? 0x1ff : 0xff), -1);
8953 if (max_mode == -1) {
8954 GST_DEBUG ("No mode indication was found (mode set) = %x",
8959 gst_buffer_unmap (buf, &map);
8960 return wb ? wb_bitrates[max_mode] : nb_bitrates[max_mode];
8963 gst_buffer_unmap (buf, &map);
8968 qtdemux_parse_transformation_matrix (GstQTDemux * qtdemux,
8969 GstByteReader * reader, guint32 * matrix, const gchar * atom)
8972 * 9 values of 32 bits (fixed point 16.16, except 2 5 and 8 that are 2.30)
8978 if (gst_byte_reader_get_remaining (reader) < 36)
8981 matrix[0] = gst_byte_reader_get_uint32_be_unchecked (reader);
8982 matrix[1] = gst_byte_reader_get_uint32_be_unchecked (reader);
8983 matrix[2] = gst_byte_reader_get_uint32_be_unchecked (reader);
8984 matrix[3] = gst_byte_reader_get_uint32_be_unchecked (reader);
8985 matrix[4] = gst_byte_reader_get_uint32_be_unchecked (reader);
8986 matrix[5] = gst_byte_reader_get_uint32_be_unchecked (reader);
8987 matrix[6] = gst_byte_reader_get_uint32_be_unchecked (reader);
8988 matrix[7] = gst_byte_reader_get_uint32_be_unchecked (reader);
8989 matrix[8] = gst_byte_reader_get_uint32_be_unchecked (reader);
8991 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix from atom %s", atom);
8992 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[0] >> 16,
8993 matrix[0] & 0xFFFF, matrix[1] >> 16, matrix[1] & 0xFF, matrix[2] >> 16,
8995 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[3] >> 16,
8996 matrix[3] & 0xFFFF, matrix[4] >> 16, matrix[4] & 0xFF, matrix[5] >> 16,
8998 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[6] >> 16,
8999 matrix[6] & 0xFFFF, matrix[7] >> 16, matrix[7] & 0xFF, matrix[8] >> 16,
9006 qtdemux_inspect_transformation_matrix (GstQTDemux * qtdemux,
9007 QtDemuxStream * stream, guint32 * matrix, GstTagList ** taglist)
9014 * This macro will only compare value abdegh, it expects cfi to have already
9017 #define QTCHECK_MATRIX(m,a,b,d,e) ((m)[0] == (a << 16) && (m)[1] == (b << 16) && \
9018 (m)[3] == (d << 16) && (m)[4] == (e << 16))
9020 /* only handle the cases where the last column has standard values */
9021 if (matrix[2] == 0 && matrix[5] == 0 && matrix[8] == 1 << 30) {
9022 const gchar *rotation_tag = NULL;
9024 /* no rotation needed */
9025 if (QTCHECK_MATRIX (matrix, 1, 0, 0, 1)) {
9027 } else if (QTCHECK_MATRIX (matrix, 0, 1, G_MAXUINT16, 0)) {
9028 rotation_tag = "rotate-90";
9029 } else if (QTCHECK_MATRIX (matrix, G_MAXUINT16, 0, 0, G_MAXUINT16)) {
9030 rotation_tag = "rotate-180";
9031 } else if (QTCHECK_MATRIX (matrix, 0, G_MAXUINT16, 1, 0)) {
9032 rotation_tag = "rotate-270";
9034 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
9037 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix rotation %s",
9039 if (rotation_tag != NULL) {
9040 if (*taglist == NULL)
9041 *taglist = gst_tag_list_new_empty ();
9042 gst_tag_list_add (*taglist, GST_TAG_MERGE_REPLACE,
9043 GST_TAG_IMAGE_ORIENTATION, rotation_tag, NULL);
9046 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
9050 /* Parses the boxes defined in ISO/IEC 14496-12 that enable support for
9051 * protected streams (sinf, frma, schm and schi); if the protection scheme is
9052 * Common Encryption (cenc), the function will also parse the tenc box (defined
9053 * in ISO/IEC 23001-7). @container points to the node that contains these boxes
9054 * (typically an enc[v|a|t|s] sample entry); the function will set
9055 * @original_fmt to the fourcc of the original unencrypted stream format.
9056 * Returns TRUE if successful; FALSE otherwise. */
9058 qtdemux_parse_protection_scheme_info (GstQTDemux * qtdemux,
9059 QtDemuxStream * stream, GNode * container, guint32 * original_fmt)
9066 g_return_val_if_fail (qtdemux != NULL, FALSE);
9067 g_return_val_if_fail (stream != NULL, FALSE);
9068 g_return_val_if_fail (container != NULL, FALSE);
9069 g_return_val_if_fail (original_fmt != NULL, FALSE);
9071 sinf = qtdemux_tree_get_child_by_type (container, FOURCC_sinf);
9072 if (G_UNLIKELY (!sinf)) {
9073 if (stream->protection_scheme_type == FOURCC_cenc) {
9074 GST_ERROR_OBJECT (qtdemux, "sinf box does not contain schi box, which is "
9075 "mandatory for Common Encryption");
9081 frma = qtdemux_tree_get_child_by_type (sinf, FOURCC_frma);
9082 if (G_UNLIKELY (!frma)) {
9083 GST_ERROR_OBJECT (qtdemux, "sinf box does not contain mandatory frma box");
9087 *original_fmt = QT_FOURCC ((const guint8 *) frma->data + 8);
9088 GST_DEBUG_OBJECT (qtdemux, "original stream format: '%" GST_FOURCC_FORMAT "'",
9089 GST_FOURCC_ARGS (*original_fmt));
9091 schm = qtdemux_tree_get_child_by_type (sinf, FOURCC_schm);
9093 GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schm box");
9096 stream->protection_scheme_type = QT_FOURCC ((const guint8 *) schm->data + 12);
9097 stream->protection_scheme_version =
9098 QT_UINT32 ((const guint8 *) schm->data + 16);
9100 GST_DEBUG_OBJECT (qtdemux,
9101 "protection_scheme_type: %" GST_FOURCC_FORMAT ", "
9102 "protection_scheme_version: %#010x",
9103 GST_FOURCC_ARGS (stream->protection_scheme_type),
9104 stream->protection_scheme_version);
9106 schi = qtdemux_tree_get_child_by_type (sinf, FOURCC_schi);
9108 GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schi box");
9111 if (stream->protection_scheme_type == FOURCC_cenc) {
9112 QtDemuxCencSampleSetInfo *info;
9114 const guint8 *tenc_data;
9115 guint32 isEncrypted;
9117 const guint8 *default_kid;
9120 if (G_UNLIKELY (!stream->protection_scheme_info))
9121 stream->protection_scheme_info =
9122 g_malloc0 (sizeof (QtDemuxCencSampleSetInfo));
9124 info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
9126 tenc = qtdemux_tree_get_child_by_type (schi, FOURCC_tenc);
9128 GST_ERROR_OBJECT (qtdemux, "schi box does not contain tenc box, "
9129 "which is mandatory for Common Encryption");
9132 tenc_data = (const guint8 *) tenc->data + 12;
9133 isEncrypted = QT_UINT24 (tenc_data);
9134 iv_size = QT_UINT8 (tenc_data + 3);
9135 default_kid = (tenc_data + 4);
9136 kid_buf = gst_buffer_new_allocate (NULL, 16, NULL);
9137 gst_buffer_fill (kid_buf, 0, default_kid, 16);
9138 if (info->default_properties)
9139 gst_structure_free (info->default_properties);
9140 info->default_properties =
9141 gst_structure_new ("application/x-cenc",
9142 "iv_size", G_TYPE_UINT, iv_size,
9143 "encrypted", G_TYPE_BOOLEAN, (isEncrypted == 1),
9144 "kid", GST_TYPE_BUFFER, kid_buf, NULL);
9145 GST_DEBUG_OBJECT (qtdemux, "default sample properties: "
9146 "is_encrypted=%u, iv_size=%u", isEncrypted, iv_size);
9147 gst_buffer_unref (kid_buf);
9153 * With each track we associate a new QtDemuxStream that contains all the info
9155 * traks that do not decode to something (like strm traks) will not have a pad.
9158 qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
9177 QtDemuxStream *stream = NULL;
9178 gboolean new_stream = FALSE;
9179 gchar *codec = NULL;
9180 const guint8 *stsd_data;
9181 guint16 lang_code; /* quicktime lang code or packed iso code */
9183 guint32 tkhd_flags = 0;
9184 guint8 tkhd_version = 0;
9186 guint value_size, stsd_len, len;
9190 GST_DEBUG_OBJECT (qtdemux, "parse_trak");
9192 if (!qtdemux_tree_get_child_by_type_full (trak, FOURCC_tkhd, &tkhd)
9193 || !gst_byte_reader_get_uint8 (&tkhd, &tkhd_version)
9194 || !gst_byte_reader_get_uint24_be (&tkhd, &tkhd_flags))
9197 /* pick between 64 or 32 bits */
9198 value_size = tkhd_version == 1 ? 8 : 4;
9199 if (!gst_byte_reader_skip (&tkhd, value_size * 2) ||
9200 !gst_byte_reader_get_uint32_be (&tkhd, &track_id))
9203 if (!qtdemux->got_moov) {
9204 if (qtdemux_find_stream (qtdemux, track_id))
9205 goto existing_stream;
9206 stream = _create_stream ();
9207 stream->track_id = track_id;
9210 stream = qtdemux_find_stream (qtdemux, track_id);
9212 GST_WARNING_OBJECT (qtdemux, "Stream not found, going to ignore it");
9216 /* flush samples data from this track from previous moov */
9217 gst_qtdemux_stream_flush_segments_data (qtdemux, stream);
9218 gst_qtdemux_stream_flush_samples_data (qtdemux, stream);
9220 /* need defaults for fragments */
9221 qtdemux_parse_trex (qtdemux, stream, &dummy, &dummy, &dummy);
9223 if (stream->pending_tags == NULL)
9224 stream->pending_tags = gst_tag_list_new_empty ();
9226 if ((tkhd_flags & 1) == 0)
9227 stream->disabled = TRUE;
9229 GST_LOG_OBJECT (qtdemux, "track[tkhd] version/flags/id: 0x%02x/%06x/%u",
9230 tkhd_version, tkhd_flags, stream->track_id);
9232 if (!(mdia = qtdemux_tree_get_child_by_type (trak, FOURCC_mdia)))
9235 if (!(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mdhd))) {
9236 /* be nice for some crooked mjp2 files that use mhdr for mdhd */
9237 if (qtdemux->major_brand != FOURCC_mjp2 ||
9238 !(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mhdr)))
9242 len = QT_UINT32 ((guint8 *) mdhd->data);
9243 version = QT_UINT32 ((guint8 *) mdhd->data + 8);
9244 GST_LOG_OBJECT (qtdemux, "track version/flags: %08x", version);
9245 if (version == 0x01000000) {
9248 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 28);
9249 stream->duration = QT_UINT64 ((guint8 *) mdhd->data + 32);
9250 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 36);
9254 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 20);
9255 stream->duration = QT_UINT32 ((guint8 *) mdhd->data + 24);
9256 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 28);
9259 if (lang_code < 0x400) {
9260 qtdemux_lang_map_qt_code_to_iso (stream->lang_id, lang_code);
9261 } else if (lang_code == 0x7fff) {
9262 stream->lang_id[0] = 0; /* unspecified */
9264 stream->lang_id[0] = 0x60 + ((lang_code >> 10) & 0x1F);
9265 stream->lang_id[1] = 0x60 + ((lang_code >> 5) & 0x1F);
9266 stream->lang_id[2] = 0x60 + (lang_code & 0x1F);
9267 stream->lang_id[3] = 0;
9270 GST_LOG_OBJECT (qtdemux, "track timescale: %" G_GUINT32_FORMAT,
9272 GST_LOG_OBJECT (qtdemux, "track duration: %" G_GUINT64_FORMAT,
9274 GST_LOG_OBJECT (qtdemux, "track language code/id: 0x%04x/%s",
9275 lang_code, stream->lang_id);
9277 if (G_UNLIKELY (stream->timescale == 0 || qtdemux->timescale == 0))
9280 if ((tref = qtdemux_tree_get_child_by_type (trak, FOURCC_tref))) {
9281 /* chapters track reference */
9282 GNode *chap = qtdemux_tree_get_child_by_type (tref, FOURCC_chap);
9284 gsize length = GST_READ_UINT32_BE (chap->data);
9285 if (qtdemux->chapters_track_id)
9286 GST_FIXME_OBJECT (qtdemux, "Multiple CHAP tracks");
9289 qtdemux->chapters_track_id =
9290 GST_READ_UINT32_BE ((gint8 *) chap->data + 8);
9295 /* fragmented files may have bogus duration in moov */
9296 if (!qtdemux->fragmented &&
9297 qtdemux->duration != G_MAXINT64 && stream->duration != G_MAXINT32) {
9298 guint64 tdur1, tdur2;
9300 /* don't overflow */
9301 tdur1 = stream->timescale * (guint64) qtdemux->duration;
9302 tdur2 = qtdemux->timescale * (guint64) stream->duration;
9305 * some of those trailers, nowadays, have prologue images that are
9306 * themselves video tracks as well. I haven't really found a way to
9307 * identify those yet, except for just looking at their duration. */
9308 if (tdur1 != 0 && (tdur2 * 10 / tdur1) < 2) {
9309 GST_WARNING_OBJECT (qtdemux,
9310 "Track shorter than 20%% (%" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT
9311 " vs. %" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT ") of the stream "
9312 "found, assuming preview image or something; skipping track",
9313 stream->duration, stream->timescale, qtdemux->duration,
9314 qtdemux->timescale);
9316 gst_qtdemux_stream_free (qtdemux, stream);
9321 if (!(hdlr = qtdemux_tree_get_child_by_type (mdia, FOURCC_hdlr)))
9324 GST_LOG_OBJECT (qtdemux, "track type: %" GST_FOURCC_FORMAT,
9325 GST_FOURCC_ARGS (QT_FOURCC ((guint8 *) hdlr->data + 12)));
9327 len = QT_UINT32 ((guint8 *) hdlr->data);
9329 stream->subtype = QT_FOURCC ((guint8 *) hdlr->data + 16);
9330 GST_LOG_OBJECT (qtdemux, "track subtype: %" GST_FOURCC_FORMAT,
9331 GST_FOURCC_ARGS (stream->subtype));
9333 if (!(minf = qtdemux_tree_get_child_by_type (mdia, FOURCC_minf)))
9336 if (!(stbl = qtdemux_tree_get_child_by_type (minf, FOURCC_stbl)))
9339 /*parse svmi header if existing */
9340 svmi = qtdemux_tree_get_child_by_type (stbl, FOURCC_svmi);
9342 len = QT_UINT32 ((guint8 *) svmi->data);
9343 version = QT_UINT32 ((guint8 *) svmi->data + 8);
9345 GstVideoMultiviewMode mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
9346 GstVideoMultiviewFlags flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
9347 guint8 frame_type, frame_layout;
9349 /* MPEG-A stereo video */
9350 if (qtdemux->major_brand == FOURCC_ss02)
9351 flags |= GST_VIDEO_MULTIVIEW_FLAGS_MIXED_MONO;
9353 frame_type = QT_UINT8 ((guint8 *) svmi->data + 12);
9354 frame_layout = QT_UINT8 ((guint8 *) svmi->data + 13) & 0x01;
9355 switch (frame_type) {
9357 mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
9360 mode = GST_VIDEO_MULTIVIEW_MODE_ROW_INTERLEAVED;
9363 mode = GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME;
9366 /* mode 3 is primary/secondary view sequence, ie
9367 * left/right views in separate tracks. See section 7.2
9368 * of ISO/IEC 23000-11:2009 */
9369 GST_FIXME_OBJECT (qtdemux,
9370 "Implement stereo video in separate streams");
9373 if ((frame_layout & 0x1) == 0)
9374 flags |= GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
9376 GST_LOG_OBJECT (qtdemux,
9377 "StereoVideo: composition type: %u, is_left_first: %u",
9378 frame_type, frame_layout);
9379 stream->multiview_mode = mode;
9380 stream->multiview_flags = flags;
9385 if (!(stsd = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsd)))
9387 stsd_data = (const guint8 *) stsd->data;
9389 /* stsd should at least have one entry */
9390 stsd_len = QT_UINT32 (stsd_data);
9391 if (stsd_len < 24) {
9392 /* .. but skip stream with empty stsd produced by some Vivotek cameras */
9393 if (stream->subtype == FOURCC_vivo) {
9395 gst_qtdemux_stream_free (qtdemux, stream);
9402 GST_LOG_OBJECT (qtdemux, "stsd len: %d", stsd_len);
9404 /* and that entry should fit within stsd */
9405 len = QT_UINT32 (stsd_data + 16);
9406 if (len > stsd_len + 16)
9409 stream->fourcc = fourcc = QT_FOURCC (stsd_data + 16 + 4);
9410 GST_LOG_OBJECT (qtdemux, "stsd type: %" GST_FOURCC_FORMAT,
9411 GST_FOURCC_ARGS (stream->fourcc));
9412 GST_LOG_OBJECT (qtdemux, "stsd type len: %d", len);
9414 if ((fourcc == FOURCC_drms) || (fourcc == FOURCC_drmi))
9415 goto error_encrypted;
9417 if (fourcc == FOURCC_encv || fourcc == FOURCC_enca) {
9418 GNode *enc = qtdemux_tree_get_child_by_type (stsd, fourcc);
9419 stream->protected = TRUE;
9420 if (!qtdemux_parse_protection_scheme_info (qtdemux, stream, enc, &fourcc))
9421 GST_ERROR_OBJECT (qtdemux, "Failed to parse protection scheme info");
9424 if (stream->subtype == FOURCC_vide) {
9425 guint32 w = 0, h = 0;
9427 gint depth, palette_size, palette_count;
9429 guint32 *palette_data = NULL;
9431 stream->sampled = TRUE;
9433 /* version 1 uses some 64-bit ints */
9434 if (!gst_byte_reader_skip (&tkhd, 20 + value_size))
9437 if (!qtdemux_parse_transformation_matrix (qtdemux, &tkhd, matrix, "tkhd"))
9440 if (!gst_byte_reader_get_uint32_be (&tkhd, &w)
9441 || !gst_byte_reader_get_uint32_be (&tkhd, &h))
9444 stream->display_width = w >> 16;
9445 stream->display_height = h >> 16;
9447 qtdemux_inspect_transformation_matrix (qtdemux, stream, matrix,
9448 &stream->pending_tags);
9454 stream->width = QT_UINT16 (stsd_data + offset + 32);
9455 stream->height = QT_UINT16 (stsd_data + offset + 34);
9456 stream->fps_n = 0; /* this is filled in later */
9457 stream->fps_d = 0; /* this is filled in later */
9458 stream->bits_per_sample = QT_UINT16 (stsd_data + offset + 82);
9459 stream->color_table_id = QT_UINT16 (stsd_data + offset + 84);
9461 /* if color_table_id is 0, ctab atom must follow; however some files
9462 * produced by TMPEGEnc have color_table_id = 0 and no ctab atom, so
9463 * if color table is not present we'll correct the value */
9464 if (stream->color_table_id == 0 &&
9465 (len < 90 || QT_FOURCC (stsd_data + offset + 86) != FOURCC_ctab)) {
9466 stream->color_table_id = -1;
9469 GST_LOG_OBJECT (qtdemux, "width %d, height %d, bps %d, color table id %d",
9470 stream->width, stream->height, stream->bits_per_sample,
9471 stream->color_table_id);
9473 depth = stream->bits_per_sample;
9475 /* more than 32 bits means grayscale */
9476 gray = (depth > 32);
9477 /* low 32 bits specify the depth */
9480 /* different number of palette entries is determined by depth. */
9482 if ((depth == 1) || (depth == 2) || (depth == 4) || (depth == 8))
9483 palette_count = (1 << depth);
9484 palette_size = palette_count * 4;
9486 if (stream->color_table_id) {
9487 switch (palette_count) {
9491 palette_data = g_memdup (ff_qt_default_palette_2, palette_size);
9494 palette_data = g_memdup (ff_qt_default_palette_4, palette_size);
9498 palette_data = g_memdup (ff_qt_grayscale_palette_16, palette_size);
9500 palette_data = g_memdup (ff_qt_default_palette_16, palette_size);
9504 palette_data = g_memdup (ff_qt_grayscale_palette_256, palette_size);
9506 palette_data = g_memdup (ff_qt_default_palette_256, palette_size);
9509 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
9510 (_("The video in this file might not play correctly.")),
9511 ("unsupported palette depth %d", depth));
9515 gint i, j, start, end;
9521 start = QT_UINT32 (stsd_data + offset + 86);
9522 palette_count = QT_UINT16 (stsd_data + offset + 90);
9523 end = QT_UINT16 (stsd_data + offset + 92);
9525 GST_LOG_OBJECT (qtdemux, "start %d, end %d, palette_count %d",
9526 start, end, palette_count);
9533 if (len < 94 + (end - start) * 8)
9536 /* palette is always the same size */
9537 palette_data = g_malloc0 (256 * 4);
9538 palette_size = 256 * 4;
9540 for (j = 0, i = start; i <= end; j++, i++) {
9543 a = QT_UINT16 (stsd_data + offset + 94 + (j * 8));
9544 r = QT_UINT16 (stsd_data + offset + 96 + (j * 8));
9545 g = QT_UINT16 (stsd_data + offset + 98 + (j * 8));
9546 b = QT_UINT16 (stsd_data + offset + 100 + (j * 8));
9548 palette_data[i] = ((a & 0xff00) << 16) | ((r & 0xff00) << 8) |
9549 (g & 0xff00) | (b >> 8);
9554 gst_caps_unref (stream->caps);
9557 qtdemux_video_caps (qtdemux, stream, fourcc, stsd_data, &codec);
9558 if (G_UNLIKELY (!stream->caps)) {
9559 g_free (palette_data);
9560 goto unknown_stream;
9564 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
9565 GST_TAG_VIDEO_CODEC, codec, NULL);
9574 if (stream->rgb8_palette)
9575 gst_memory_unref (stream->rgb8_palette);
9576 stream->rgb8_palette = gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY,
9577 palette_data, palette_size, 0, palette_size, palette_data, g_free);
9579 s = gst_caps_get_structure (stream->caps, 0);
9581 /* non-raw video has a palette_data property. raw video has the palette as
9582 * an extra plane that we append to the output buffers before we push
9584 if (!gst_structure_has_name (s, "video/x-raw")) {
9587 palette = gst_buffer_new ();
9588 gst_buffer_append_memory (palette, stream->rgb8_palette);
9589 stream->rgb8_palette = NULL;
9591 gst_caps_set_simple (stream->caps, "palette_data",
9592 GST_TYPE_BUFFER, palette, NULL);
9593 gst_buffer_unref (palette);
9595 } else if (palette_count != 0) {
9596 GST_ELEMENT_WARNING (qtdemux, STREAM, NOT_IMPLEMENTED,
9597 (NULL), ("Unsupported palette depth %d", depth));
9600 GST_LOG_OBJECT (qtdemux, "frame count: %u",
9601 QT_UINT16 (stsd_data + offset + 48));
9605 /* pick 'the' stsd child */
9606 if (!stream->protected)
9607 mp4v = qtdemux_tree_get_child_by_type (stsd, fourcc);
9609 mp4v = qtdemux_tree_get_child_by_type (stsd, FOURCC_encv);
9612 esds = qtdemux_tree_get_child_by_type (mp4v, FOURCC_esds);
9613 pasp = qtdemux_tree_get_child_by_type (mp4v, FOURCC_pasp);
9617 const guint8 *pasp_data = (const guint8 *) pasp->data;
9619 stream->par_w = QT_UINT32 (pasp_data + 8);
9620 stream->par_h = QT_UINT32 (pasp_data + 12);
9627 gst_qtdemux_handle_esds (qtdemux, stream, esds, stream->pending_tags);
9634 gint len = QT_UINT32 (stsd_data) - 0x66;
9635 const guint8 *avc_data = stsd_data + 0x66;
9638 while (len >= 0x8) {
9641 if (QT_UINT32 (avc_data) <= len)
9642 size = QT_UINT32 (avc_data) - 0x8;
9647 /* No real data, so break out */
9650 switch (QT_FOURCC (avc_data + 0x4)) {
9653 /* parse, if found */
9656 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
9658 /* First 4 bytes are the length of the atom, the next 4 bytes
9659 * are the fourcc, the next 1 byte is the version, and the
9660 * subsequent bytes are profile_tier_level structure like data. */
9661 gst_codec_utils_h264_caps_set_level_and_profile (stream->caps,
9662 avc_data + 8 + 1, size - 1);
9663 buf = gst_buffer_new_and_alloc (size);
9664 gst_buffer_fill (buf, 0, avc_data + 0x8, size);
9665 gst_caps_set_simple (stream->caps,
9666 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9667 gst_buffer_unref (buf);
9675 GST_DEBUG_OBJECT (qtdemux, "found strf codec_data in stsd");
9677 /* First 4 bytes are the length of the atom, the next 4 bytes
9678 * are the fourcc, next 40 bytes are BITMAPINFOHEADER,
9679 * next 1 byte is the version, and the
9680 * subsequent bytes are sequence parameter set like data. */
9682 size -= 40; /* we'll be skipping BITMAPINFOHEADER */
9684 gst_codec_utils_h264_caps_set_level_and_profile (stream->caps,
9685 avc_data + 8 + 40 + 1, size - 1);
9687 buf = gst_buffer_new_and_alloc (size);
9688 gst_buffer_fill (buf, 0, avc_data + 8 + 40, size);
9689 gst_caps_set_simple (stream->caps,
9690 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9691 gst_buffer_unref (buf);
9697 guint avg_bitrate, max_bitrate;
9699 /* bufferSizeDB, maxBitrate and avgBitrate - 4 bytes each */
9703 max_bitrate = QT_UINT32 (avc_data + 0xc);
9704 avg_bitrate = QT_UINT32 (avc_data + 0x10);
9706 if (!max_bitrate && !avg_bitrate)
9709 /* Some muxers seem to swap the average and maximum bitrates
9710 * (I'm looking at you, YouTube), so we swap for sanity. */
9711 if (max_bitrate > 0 && max_bitrate < avg_bitrate) {
9712 guint temp = avg_bitrate;
9714 avg_bitrate = max_bitrate;
9718 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
9719 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
9720 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
9722 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
9723 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
9724 GST_TAG_BITRATE, avg_bitrate, NULL);
9735 avc_data += size + 8;
9744 gint len = QT_UINT32 (stsd_data) - 0x66;
9745 const guint8 *hevc_data = stsd_data + 0x66;
9748 while (len >= 0x8) {
9751 if (QT_UINT32 (hevc_data) <= len)
9752 size = QT_UINT32 (hevc_data) - 0x8;
9757 /* No real data, so break out */
9760 switch (QT_FOURCC (hevc_data + 0x4)) {
9763 /* parse, if found */
9766 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
9768 /* First 4 bytes are the length of the atom, the next 4 bytes
9769 * are the fourcc, the next 1 byte is the version, and the
9770 * subsequent bytes are sequence parameter set like data. */
9771 gst_codec_utils_h265_caps_set_level_tier_and_profile
9772 (stream->caps, hevc_data + 8 + 1, size - 1);
9774 buf = gst_buffer_new_and_alloc (size);
9775 gst_buffer_fill (buf, 0, hevc_data + 0x8, size);
9776 gst_caps_set_simple (stream->caps,
9777 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9778 gst_buffer_unref (buf);
9785 hevc_data += size + 8;
9796 GST_DEBUG_OBJECT (qtdemux, "found %" GST_FOURCC_FORMAT,
9797 GST_FOURCC_ARGS (fourcc));
9799 /* codec data might be in glbl extension atom */
9801 qtdemux_tree_get_child_by_type (mp4v, FOURCC_glbl) : NULL;
9807 GST_DEBUG_OBJECT (qtdemux, "found glbl data in stsd");
9809 len = QT_UINT32 (data);
9812 buf = gst_buffer_new_and_alloc (len);
9813 gst_buffer_fill (buf, 0, data + 8, len);
9814 gst_caps_set_simple (stream->caps,
9815 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9816 gst_buffer_unref (buf);
9823 /* see annex I of the jpeg2000 spec */
9824 GNode *jp2h, *ihdr, *colr, *mjp2, *field, *prefix, *cmap, *cdef;
9826 const gchar *colorspace = NULL;
9828 guint32 ncomp_map = 0;
9829 gint32 *comp_map = NULL;
9830 guint32 nchan_def = 0;
9831 gint32 *chan_def = NULL;
9833 GST_DEBUG_OBJECT (qtdemux, "found mjp2");
9834 /* some required atoms */
9835 mjp2 = qtdemux_tree_get_child_by_type (stsd, FOURCC_mjp2);
9838 jp2h = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2h);
9842 /* number of components; redundant with info in codestream, but useful
9844 ihdr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_ihdr);
9845 if (!ihdr || QT_UINT32 (ihdr->data) != 22)
9847 ncomp = QT_UINT16 (((guint8 *) ihdr->data) + 16);
9849 colr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_colr);
9852 GST_DEBUG_OBJECT (qtdemux, "found colr");
9853 /* extract colour space info */
9854 if (QT_UINT8 ((guint8 *) colr->data + 8) == 1) {
9855 switch (QT_UINT32 ((guint8 *) colr->data + 11)) {
9857 colorspace = "sRGB";
9860 colorspace = "GRAY";
9863 colorspace = "sYUV";
9871 /* colr is required, and only values 16, 17, and 18 are specified,
9872 so error if we have no colorspace */
9875 /* extract component mapping */
9876 cmap = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cmap);
9878 guint32 cmap_len = 0;
9880 cmap_len = QT_UINT32 (cmap->data);
9881 if (cmap_len >= 8) {
9882 /* normal box, subtract off header */
9884 /* cmap: { u16 cmp; u8 mtyp; u8 pcol; }* */
9885 if (cmap_len % 4 == 0) {
9886 ncomp_map = (cmap_len / 4);
9887 comp_map = g_new0 (gint32, ncomp_map);
9888 for (i = 0; i < ncomp_map; i++) {
9891 cmp = QT_UINT16 (((guint8 *) cmap->data) + 8 + i * 4);
9892 mtyp = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 2);
9893 pcol = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 3);
9894 comp_map[i] = (mtyp << 24) | (pcol << 16) | cmp;
9899 /* extract channel definitions */
9900 cdef = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cdef);
9902 guint32 cdef_len = 0;
9904 cdef_len = QT_UINT32 (cdef->data);
9905 if (cdef_len >= 10) {
9906 /* normal box, subtract off header and len */
9908 /* cdef: u16 n; { u16 cn; u16 typ; u16 asoc; }* */
9909 if (cdef_len % 6 == 0) {
9910 nchan_def = (cdef_len / 6);
9911 chan_def = g_new0 (gint32, nchan_def);
9912 for (i = 0; i < nchan_def; i++)
9914 for (i = 0; i < nchan_def; i++) {
9915 guint16 cn, typ, asoc;
9916 cn = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6);
9917 typ = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 2);
9918 asoc = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 4);
9919 if (cn < nchan_def) {
9922 chan_def[cn] = asoc;
9925 chan_def[cn] = 0; /* alpha */
9928 chan_def[cn] = -typ;
9936 gst_caps_set_simple (stream->caps,
9937 "num-components", G_TYPE_INT, ncomp, NULL);
9938 gst_caps_set_simple (stream->caps,
9939 "colorspace", G_TYPE_STRING, colorspace, NULL);
9942 GValue arr = { 0, };
9943 GValue elt = { 0, };
9945 g_value_init (&arr, GST_TYPE_ARRAY);
9946 g_value_init (&elt, G_TYPE_INT);
9947 for (i = 0; i < ncomp_map; i++) {
9948 g_value_set_int (&elt, comp_map[i]);
9949 gst_value_array_append_value (&arr, &elt);
9951 gst_structure_set_value (gst_caps_get_structure (stream->caps, 0),
9952 "component-map", &arr);
9953 g_value_unset (&elt);
9954 g_value_unset (&arr);
9959 GValue arr = { 0, };
9960 GValue elt = { 0, };
9962 g_value_init (&arr, GST_TYPE_ARRAY);
9963 g_value_init (&elt, G_TYPE_INT);
9964 for (i = 0; i < nchan_def; i++) {
9965 g_value_set_int (&elt, chan_def[i]);
9966 gst_value_array_append_value (&arr, &elt);
9968 gst_structure_set_value (gst_caps_get_structure (stream->caps, 0),
9969 "channel-definitions", &arr);
9970 g_value_unset (&elt);
9971 g_value_unset (&arr);
9975 /* some optional atoms */
9976 field = qtdemux_tree_get_child_by_type (mjp2, FOURCC_fiel);
9977 prefix = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2x);
9979 /* indicate possible fields in caps */
9981 data = (guint8 *) field->data + 8;
9983 gst_caps_set_simple (stream->caps, "fields", G_TYPE_INT,
9984 (gint) * data, NULL);
9986 /* add codec_data if provided */
9991 GST_DEBUG_OBJECT (qtdemux, "found prefix data in stsd");
9992 data = prefix->data;
9993 len = QT_UINT32 (data);
9996 buf = gst_buffer_new_and_alloc (len);
9997 gst_buffer_fill (buf, 0, data + 8, len);
9998 gst_caps_set_simple (stream->caps,
9999 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10000 gst_buffer_unref (buf);
10009 GstBuffer *seqh = NULL;
10010 guint8 *gamma_data = NULL;
10011 gint len = QT_UINT32 (stsd_data);
10013 qtdemux_parse_svq3_stsd_data (qtdemux, stsd, &gamma_data, &seqh);
10015 gst_caps_set_simple (stream->caps, "applied-gamma", G_TYPE_DOUBLE,
10016 QT_FP32 (gamma_data), NULL);
10019 /* sorry for the bad name, but we don't know what this is, other
10020 * than its own fourcc */
10021 gst_caps_set_simple (stream->caps, "seqh", GST_TYPE_BUFFER, seqh,
10025 GST_DEBUG_OBJECT (qtdemux, "found codec_data in stsd");
10026 buf = gst_buffer_new_and_alloc (len);
10027 gst_buffer_fill (buf, 0, stsd_data, len);
10028 gst_caps_set_simple (stream->caps,
10029 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10030 gst_buffer_unref (buf);
10036 gst_caps_set_simple (stream->caps,
10037 "depth", G_TYPE_INT, QT_UINT16 (stsd_data + offset + 82), NULL);
10042 GNode *xith, *xdxt;
10044 GST_DEBUG_OBJECT (qtdemux, "found XiTh");
10045 xith = qtdemux_tree_get_child_by_type (stsd, FOURCC_XiTh);
10049 xdxt = qtdemux_tree_get_child_by_type (xith, FOURCC_XdxT);
10053 GST_DEBUG_OBJECT (qtdemux, "found XdxT node");
10054 /* collect the headers and store them in a stream list so that we can
10055 * send them out first */
10056 qtdemux_parse_theora_extension (qtdemux, stream, xdxt);
10066 GST_DEBUG_OBJECT (qtdemux, "parse ovc1 header");
10067 ovc1 = qtdemux_tree_get_child_by_type (stsd, FOURCC_ovc1);
10070 ovc1_data = ovc1->data;
10071 ovc1_len = QT_UINT32 (ovc1_data);
10072 if (ovc1_len <= 198) {
10073 GST_WARNING_OBJECT (qtdemux, "Too small ovc1 header, skipping");
10076 buf = gst_buffer_new_and_alloc (ovc1_len - 198);
10077 gst_buffer_fill (buf, 0, ovc1_data + 198, ovc1_len - 198);
10078 gst_caps_set_simple (stream->caps,
10079 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10080 gst_buffer_unref (buf);
10085 gint len = QT_UINT32 (stsd_data) - 0x66;
10086 const guint8 *vc1_data = stsd_data + 0x66;
10092 if (QT_UINT32 (vc1_data) <= len)
10093 size = QT_UINT32 (vc1_data) - 8;
10098 /* No real data, so break out */
10101 switch (QT_FOURCC (vc1_data + 0x4)) {
10102 case GST_MAKE_FOURCC ('d', 'v', 'c', '1'):
10106 GST_DEBUG_OBJECT (qtdemux, "found dvc1 codec_data in stsd");
10107 buf = gst_buffer_new_and_alloc (size);
10108 gst_buffer_fill (buf, 0, vc1_data + 8, size);
10109 gst_caps_set_simple (stream->caps,
10110 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10111 gst_buffer_unref (buf);
10118 vc1_data += size + 8;
10127 GST_INFO_OBJECT (qtdemux,
10128 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
10129 GST_FOURCC_ARGS (fourcc), stream->caps);
10131 } else if (stream->subtype == FOURCC_soun) {
10132 int version, samplesize;
10133 guint16 compression_id;
10134 gboolean amrwb = FALSE;
10137 /* sample description entry (16) + sound sample description v0 (20) */
10141 version = QT_UINT32 (stsd_data + offset);
10142 stream->n_channels = QT_UINT16 (stsd_data + offset + 8);
10143 samplesize = QT_UINT16 (stsd_data + offset + 10);
10144 compression_id = QT_UINT16 (stsd_data + offset + 12);
10145 stream->rate = QT_FP32 (stsd_data + offset + 16);
10147 GST_LOG_OBJECT (qtdemux, "version/rev: %08x", version);
10148 GST_LOG_OBJECT (qtdemux, "vendor: %08x",
10149 QT_UINT32 (stsd_data + offset + 4));
10150 GST_LOG_OBJECT (qtdemux, "n_channels: %d", stream->n_channels);
10151 GST_LOG_OBJECT (qtdemux, "sample_size: %d", samplesize);
10152 GST_LOG_OBJECT (qtdemux, "compression_id: %d", compression_id);
10153 GST_LOG_OBJECT (qtdemux, "packet size: %d",
10154 QT_UINT16 (stsd_data + offset + 14));
10155 GST_LOG_OBJECT (qtdemux, "sample rate: %g", stream->rate);
10157 if (compression_id == 0xfffe)
10158 stream->sampled = TRUE;
10160 /* first assume uncompressed audio */
10161 stream->bytes_per_sample = samplesize / 8;
10162 stream->samples_per_frame = stream->n_channels;
10163 stream->bytes_per_frame = stream->n_channels * stream->bytes_per_sample;
10164 stream->samples_per_packet = stream->samples_per_frame;
10165 stream->bytes_per_packet = stream->bytes_per_sample;
10169 /* Yes, these have to be hard-coded */
10172 stream->samples_per_packet = 6;
10173 stream->bytes_per_packet = 1;
10174 stream->bytes_per_frame = 1 * stream->n_channels;
10175 stream->bytes_per_sample = 1;
10176 stream->samples_per_frame = 6 * stream->n_channels;
10181 stream->samples_per_packet = 3;
10182 stream->bytes_per_packet = 1;
10183 stream->bytes_per_frame = 1 * stream->n_channels;
10184 stream->bytes_per_sample = 1;
10185 stream->samples_per_frame = 3 * stream->n_channels;
10190 stream->samples_per_packet = 64;
10191 stream->bytes_per_packet = 34;
10192 stream->bytes_per_frame = 34 * stream->n_channels;
10193 stream->bytes_per_sample = 2;
10194 stream->samples_per_frame = 64 * stream->n_channels;
10200 stream->samples_per_packet = 1;
10201 stream->bytes_per_packet = 1;
10202 stream->bytes_per_frame = 1 * stream->n_channels;
10203 stream->bytes_per_sample = 1;
10204 stream->samples_per_frame = 1 * stream->n_channels;
10209 stream->samples_per_packet = 160;
10210 stream->bytes_per_packet = 33;
10211 stream->bytes_per_frame = 33 * stream->n_channels;
10212 stream->bytes_per_sample = 2;
10213 stream->samples_per_frame = 160 * stream->n_channels;
10220 if (version == 0x00010000) {
10221 /* sample description entry (16) + sound sample description v1 (20+16) */
10232 /* only parse extra decoding config for non-pcm audio */
10233 stream->samples_per_packet = QT_UINT32 (stsd_data + offset);
10234 stream->bytes_per_packet = QT_UINT32 (stsd_data + offset + 4);
10235 stream->bytes_per_frame = QT_UINT32 (stsd_data + offset + 8);
10236 stream->bytes_per_sample = QT_UINT32 (stsd_data + offset + 12);
10238 GST_LOG_OBJECT (qtdemux, "samples/packet: %d",
10239 stream->samples_per_packet);
10240 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
10241 stream->bytes_per_packet);
10242 GST_LOG_OBJECT (qtdemux, "bytes/frame: %d",
10243 stream->bytes_per_frame);
10244 GST_LOG_OBJECT (qtdemux, "bytes/sample: %d",
10245 stream->bytes_per_sample);
10247 if (!stream->sampled && stream->bytes_per_packet) {
10248 stream->samples_per_frame = (stream->bytes_per_frame /
10249 stream->bytes_per_packet) * stream->samples_per_packet;
10250 GST_LOG_OBJECT (qtdemux, "samples/frame: %d",
10251 stream->samples_per_frame);
10256 } else if (version == 0x00020000) {
10263 /* sample description entry (16) + sound sample description v2 (56) */
10267 qtfp.val = QT_UINT64 (stsd_data + offset + 4);
10268 stream->rate = qtfp.fp;
10269 stream->n_channels = QT_UINT32 (stsd_data + offset + 12);
10271 GST_LOG_OBJECT (qtdemux, "Sound sample description Version 2");
10272 GST_LOG_OBJECT (qtdemux, "sample rate: %g", stream->rate);
10273 GST_LOG_OBJECT (qtdemux, "n_channels: %d", stream->n_channels);
10274 GST_LOG_OBJECT (qtdemux, "bits/channel: %d",
10275 QT_UINT32 (stsd_data + offset + 20));
10276 GST_LOG_OBJECT (qtdemux, "format flags: %X",
10277 QT_UINT32 (stsd_data + offset + 24));
10278 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
10279 QT_UINT32 (stsd_data + offset + 28));
10280 GST_LOG_OBJECT (qtdemux, "LPCM frames/packet: %d",
10281 QT_UINT32 (stsd_data + offset + 32));
10282 } else if (version != 0x00000) {
10283 GST_WARNING_OBJECT (qtdemux, "unknown audio STSD version %08x", version);
10287 gst_caps_unref (stream->caps);
10289 stream->caps = qtdemux_audio_caps (qtdemux, stream, fourcc,
10290 stsd_data + 32, len - 16, &codec);
10298 in24 = qtdemux_tree_get_child_by_type (stsd, FOURCC_in24);
10300 enda = qtdemux_tree_get_child_by_type (in24, FOURCC_enda);
10302 wave = qtdemux_tree_get_child_by_type (in24, FOURCC_wave);
10304 enda = qtdemux_tree_get_child_by_type (wave, FOURCC_enda);
10307 int enda_value = QT_UINT16 ((guint8 *) enda->data + 8);
10308 gst_caps_set_simple (stream->caps,
10309 "format", G_TYPE_STRING, (enda_value) ? "S24LE" : "S24BE", NULL);
10316 const guint8 *owma_data;
10317 const gchar *codec_name = NULL;
10321 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
10322 /* FIXME this should also be gst_riff_strf_auds,
10323 * but the latter one is actually missing bits-per-sample :( */
10328 gint32 nSamplesPerSec;
10329 gint32 nAvgBytesPerSec;
10330 gint16 nBlockAlign;
10331 gint16 wBitsPerSample;
10334 WAVEFORMATEX *wfex;
10336 GST_DEBUG_OBJECT (qtdemux, "parse owma");
10337 owma = qtdemux_tree_get_child_by_type (stsd, FOURCC_owma);
10340 owma_data = owma->data;
10341 owma_len = QT_UINT32 (owma_data);
10342 if (owma_len <= 54) {
10343 GST_WARNING_OBJECT (qtdemux, "Too small owma header, skipping");
10346 wfex = (WAVEFORMATEX *) (owma_data + 36);
10347 buf = gst_buffer_new_and_alloc (owma_len - 54);
10348 gst_buffer_fill (buf, 0, owma_data + 54, owma_len - 54);
10349 if (wfex->wFormatTag == 0x0161) {
10350 codec_name = "Windows Media Audio";
10352 } else if (wfex->wFormatTag == 0x0162) {
10353 codec_name = "Windows Media Audio 9 Pro";
10355 } else if (wfex->wFormatTag == 0x0163) {
10356 codec_name = "Windows Media Audio 9 Lossless";
10357 /* is that correct? gstffmpegcodecmap.c is missing it, but
10358 * fluendo codec seems to support it */
10362 gst_caps_set_simple (stream->caps,
10363 "codec_data", GST_TYPE_BUFFER, buf,
10364 "wmaversion", G_TYPE_INT, version,
10365 "block_align", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->nBlockAlign),
10366 "bitrate", G_TYPE_INT, GST_READ_UINT32_LE (&wfex->nAvgBytesPerSec),
10367 "width", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->wBitsPerSample),
10368 "depth", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->wBitsPerSample),
10370 gst_buffer_unref (buf);
10374 codec = g_strdup (codec_name);
10380 gint len = QT_UINT32 (stsd_data) - offset;
10381 const guint8 *wfex_data = stsd_data + offset;
10382 const gchar *codec_name = NULL;
10384 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
10385 /* FIXME this should also be gst_riff_strf_auds,
10386 * but the latter one is actually missing bits-per-sample :( */
10391 gint32 nSamplesPerSec;
10392 gint32 nAvgBytesPerSec;
10393 gint16 nBlockAlign;
10394 gint16 wBitsPerSample;
10399 /* FIXME: unify with similar wavformatex parsing code above */
10400 GST_DEBUG_OBJECT (qtdemux, "parse wma, looking for wfex");
10406 if (QT_UINT32 (wfex_data) <= len)
10407 size = QT_UINT32 (wfex_data) - 8;
10412 /* No real data, so break out */
10415 switch (QT_FOURCC (wfex_data + 4)) {
10416 case GST_MAKE_FOURCC ('w', 'f', 'e', 'x'):
10418 GST_DEBUG_OBJECT (qtdemux, "found wfex in stsd");
10423 wfex.wFormatTag = GST_READ_UINT16_LE (wfex_data + 8 + 0);
10424 wfex.nChannels = GST_READ_UINT16_LE (wfex_data + 8 + 2);
10425 wfex.nSamplesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 4);
10426 wfex.nAvgBytesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 8);
10427 wfex.nBlockAlign = GST_READ_UINT16_LE (wfex_data + 8 + 12);
10428 wfex.wBitsPerSample = GST_READ_UINT16_LE (wfex_data + 8 + 14);
10429 wfex.cbSize = GST_READ_UINT16_LE (wfex_data + 8 + 16);
10431 GST_LOG_OBJECT (qtdemux, "Found wfex box in stsd:");
10432 GST_LOG_OBJECT (qtdemux, "FormatTag = 0x%04x, Channels = %u, "
10433 "SamplesPerSec = %u, AvgBytesPerSec = %u, BlockAlign = %u, "
10434 "BitsPerSample = %u, Size = %u", wfex.wFormatTag,
10435 wfex.nChannels, wfex.nSamplesPerSec, wfex.nAvgBytesPerSec,
10436 wfex.nBlockAlign, wfex.wBitsPerSample, wfex.cbSize);
10438 if (wfex.wFormatTag == 0x0161) {
10439 codec_name = "Windows Media Audio";
10441 } else if (wfex.wFormatTag == 0x0162) {
10442 codec_name = "Windows Media Audio 9 Pro";
10444 } else if (wfex.wFormatTag == 0x0163) {
10445 codec_name = "Windows Media Audio 9 Lossless";
10446 /* is that correct? gstffmpegcodecmap.c is missing it, but
10447 * fluendo codec seems to support it */
10451 gst_caps_set_simple (stream->caps,
10452 "wmaversion", G_TYPE_INT, version,
10453 "block_align", G_TYPE_INT, wfex.nBlockAlign,
10454 "bitrate", G_TYPE_INT, wfex.nAvgBytesPerSec,
10455 "width", G_TYPE_INT, wfex.wBitsPerSample,
10456 "depth", G_TYPE_INT, wfex.wBitsPerSample, NULL);
10458 if (size > wfex.cbSize) {
10461 buf = gst_buffer_new_and_alloc (size - wfex.cbSize);
10462 gst_buffer_fill (buf, 0, wfex_data + 8 + wfex.cbSize,
10463 size - wfex.cbSize);
10464 gst_caps_set_simple (stream->caps,
10465 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10466 gst_buffer_unref (buf);
10468 GST_WARNING_OBJECT (qtdemux, "no codec data");
10473 codec = g_strdup (codec_name);
10481 wfex_data += size + 8;
10488 const guint8 *opus_data;
10489 guint8 *channel_mapping = NULL;
10492 guint8 channel_mapping_family;
10493 guint8 stream_count;
10494 guint8 coupled_count;
10497 opus = qtdemux_tree_get_child_by_type (stsd, FOURCC_opus);
10498 opus_data = opus->data;
10500 channels = GST_READ_UINT8 (opus_data + 45);
10501 rate = GST_READ_UINT32_LE (opus_data + 48);
10502 channel_mapping_family = GST_READ_UINT8 (opus_data + 54);
10503 stream_count = GST_READ_UINT8 (opus_data + 55);
10504 coupled_count = GST_READ_UINT8 (opus_data + 56);
10506 if (channels > 0) {
10507 channel_mapping = g_malloc (channels * sizeof (guint8));
10508 for (i = 0; i < channels; i++)
10509 channel_mapping[i] = GST_READ_UINT8 (opus_data + i + 57);
10512 stream->caps = gst_codec_utils_opus_create_caps (rate, channels,
10513 channel_mapping_family, stream_count, coupled_count,
10525 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
10526 GST_TAG_AUDIO_CODEC, codec, NULL);
10530 /* some bitrate info may have ended up in caps */
10531 s = gst_caps_get_structure (stream->caps, 0);
10532 gst_structure_get_int (s, "bitrate", &bitrate);
10534 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
10535 GST_TAG_BITRATE, bitrate, NULL);
10538 if (stream->protected && fourcc == FOURCC_mp4a)
10539 mp4a = qtdemux_tree_get_child_by_type (stsd, FOURCC_enca);
10541 mp4a = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4a);
10546 wave = qtdemux_tree_get_child_by_type (mp4a, FOURCC_wave);
10548 esds = qtdemux_tree_get_child_by_type (wave, FOURCC_esds);
10550 esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
10554 /* If the fourcc's bottom 16 bits gives 'sm', then the top
10555 16 bits is a byte-swapped wave-style codec identifier,
10556 and we can find a WAVE header internally to a 'wave' atom here.
10557 This can more clearly be thought of as 'ms' as the top 16 bits, and a
10558 codec id as the bottom 16 bits - but byte-swapped to store in QT (which
10561 if ((fourcc & 0xffff) == (('s' << 8) | 'm')) {
10562 if (len < offset + 20) {
10563 GST_WARNING_OBJECT (qtdemux, "No wave atom in MS-style audio");
10565 guint32 datalen = QT_UINT32 (stsd_data + offset + 16);
10566 const guint8 *data = stsd_data + offset + 16;
10568 GNode *waveheadernode;
10570 wavenode = g_node_new ((guint8 *) data);
10571 if (qtdemux_parse_node (qtdemux, wavenode, data, datalen)) {
10572 const guint8 *waveheader;
10575 waveheadernode = qtdemux_tree_get_child_by_type (wavenode, fourcc);
10576 if (waveheadernode) {
10577 waveheader = (const guint8 *) waveheadernode->data;
10578 headerlen = QT_UINT32 (waveheader);
10580 if (headerlen > 8) {
10581 gst_riff_strf_auds *header = NULL;
10582 GstBuffer *headerbuf;
10588 headerbuf = gst_buffer_new_and_alloc (headerlen);
10589 gst_buffer_fill (headerbuf, 0, waveheader, headerlen);
10591 if (gst_riff_parse_strf_auds (GST_ELEMENT_CAST (qtdemux),
10592 headerbuf, &header, &extra)) {
10593 gst_caps_unref (stream->caps);
10594 /* FIXME: Need to do something with the channel reorder map */
10595 stream->caps = gst_riff_create_audio_caps (header->format, NULL,
10596 header, extra, NULL, NULL, NULL);
10599 gst_buffer_unref (extra);
10604 GST_DEBUG ("Didn't find waveheadernode for this codec");
10606 g_node_destroy (wavenode);
10609 gst_qtdemux_handle_esds (qtdemux, stream, esds, stream->pending_tags);
10613 /* FIXME: what is in the chunk? */
10616 gint len = QT_UINT32 (stsd_data);
10618 /* seems to be always = 116 = 0x74 */
10624 gint len = QT_UINT32 (stsd_data);
10627 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x4C);
10629 gst_buffer_fill (buf, 0, stsd_data + 0x4C, len - 0x4C);
10630 gst_caps_set_simple (stream->caps,
10631 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10632 gst_buffer_unref (buf);
10634 gst_caps_set_simple (stream->caps,
10635 "samplesize", G_TYPE_INT, samplesize, NULL);
10640 GNode *alac, *wave = NULL;
10642 /* apparently, m4a has this atom appended directly in the stsd entry,
10643 * while mov has it in a wave atom */
10644 alac = qtdemux_tree_get_child_by_type (stsd, FOURCC_alac);
10646 /* alac now refers to stsd entry atom */
10647 wave = qtdemux_tree_get_child_by_type (alac, FOURCC_wave);
10649 alac = qtdemux_tree_get_child_by_type (wave, FOURCC_alac);
10651 alac = qtdemux_tree_get_child_by_type (alac, FOURCC_alac);
10654 const guint8 *alac_data = alac->data;
10655 gint len = QT_UINT32 (alac->data);
10659 GST_DEBUG_OBJECT (qtdemux,
10660 "discarding alac atom with unexpected len %d", len);
10662 /* codec-data contains alac atom size and prefix,
10663 * ffmpeg likes it that way, not quite gst-ish though ...*/
10664 buf = gst_buffer_new_and_alloc (len);
10665 gst_buffer_fill (buf, 0, alac->data, len);
10666 gst_caps_set_simple (stream->caps,
10667 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10668 gst_buffer_unref (buf);
10670 stream->bytes_per_frame = QT_UINT32 (alac_data + 12);
10671 stream->n_channels = QT_UINT8 (alac_data + 21);
10672 stream->rate = QT_UINT32 (alac_data + 32);
10675 gst_caps_set_simple (stream->caps,
10676 "samplesize", G_TYPE_INT, samplesize, NULL);
10684 gint len = QT_UINT32 (stsd_data);
10687 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x34);
10690 gst_buffer_fill (buf, 0, stsd_data + 0x34, len - 0x34);
10692 /* If we have enough data, let's try to get the 'damr' atom. See
10693 * the 3GPP container spec (26.244) for more details. */
10694 if ((len - 0x34) > 8 &&
10695 (bitrate = qtdemux_parse_amr_bitrate (buf, amrwb))) {
10696 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
10697 GST_TAG_MAXIMUM_BITRATE, bitrate, NULL);
10700 gst_caps_set_simple (stream->caps,
10701 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10702 gst_buffer_unref (buf);
10708 /* mp4a atom withtout ESDS; Attempt to build codec data from atom */
10709 gint len = QT_UINT32 (stsd_data);
10712 guint16 sound_version = QT_UINT16 (stsd_data + 32);
10714 if (sound_version == 1) {
10715 guint16 channels = QT_UINT16 (stsd_data + 40);
10716 guint32 time_scale = QT_UINT32 (stsd_data + 46);
10717 guint8 codec_data[2];
10719 gint profile = 2; /* FIXME: Can this be determined somehow? There doesn't seem to be anything in mp4a atom that specifis compression */
10721 gint sample_rate_index =
10722 gst_codec_utils_aac_get_index_from_sample_rate (time_scale);
10724 /* build AAC codec data */
10725 codec_data[0] = profile << 3;
10726 codec_data[0] |= ((sample_rate_index >> 1) & 0x7);
10727 codec_data[1] = (sample_rate_index & 0x01) << 7;
10728 codec_data[1] |= (channels & 0xF) << 3;
10730 buf = gst_buffer_new_and_alloc (2);
10731 gst_buffer_fill (buf, 0, codec_data, 2);
10732 gst_caps_set_simple (stream->caps,
10733 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10734 gst_buffer_unref (buf);
10740 GST_INFO_OBJECT (qtdemux,
10741 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
10745 GST_INFO_OBJECT (qtdemux,
10746 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
10747 GST_FOURCC_ARGS (fourcc), stream->caps);
10749 } else if (stream->subtype == FOURCC_strm) {
10750 if (fourcc == FOURCC_rtsp) {
10751 stream->redirect_uri = qtdemux_get_rtsp_uri_from_hndl (qtdemux, minf);
10753 GST_INFO_OBJECT (qtdemux, "unhandled stream type %" GST_FOURCC_FORMAT,
10754 GST_FOURCC_ARGS (fourcc));
10755 goto unknown_stream;
10757 stream->sampled = TRUE;
10758 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
10759 || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt) {
10761 stream->sampled = TRUE;
10762 stream->sparse = TRUE;
10765 qtdemux_sub_caps (qtdemux, stream, fourcc, stsd_data, &codec);
10767 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
10768 GST_TAG_SUBTITLE_CODEC, codec, NULL);
10773 /* hunt for sort-of codec data */
10777 GNode *mp4s = NULL;
10778 GNode *esds = NULL;
10780 /* look for palette in a stsd->mp4s->esds sub-atom */
10781 mp4s = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4s);
10783 esds = qtdemux_tree_get_child_by_type (mp4s, FOURCC_esds);
10784 if (esds == NULL) {
10786 GST_LOG_OBJECT (qtdemux, "Skipping invalid stsd: no esds child");
10790 gst_qtdemux_handle_esds (qtdemux, stream, esds, stream->pending_tags);
10794 GST_INFO_OBJECT (qtdemux,
10795 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
10798 GST_INFO_OBJECT (qtdemux,
10799 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
10800 GST_FOURCC_ARGS (fourcc), stream->caps);
10802 /* everything in 1 sample */
10803 stream->sampled = TRUE;
10806 qtdemux_generic_caps (qtdemux, stream, fourcc, stsd_data, &codec);
10808 if (stream->caps == NULL)
10809 goto unknown_stream;
10812 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
10813 GST_TAG_SUBTITLE_CODEC, codec, NULL);
10819 /* promote to sampled format */
10820 if (stream->fourcc == FOURCC_samr) {
10821 /* force mono 8000 Hz for AMR */
10822 stream->sampled = TRUE;
10823 stream->n_channels = 1;
10824 stream->rate = 8000;
10825 } else if (stream->fourcc == FOURCC_sawb) {
10826 /* force mono 16000 Hz for AMR-WB */
10827 stream->sampled = TRUE;
10828 stream->n_channels = 1;
10829 stream->rate = 16000;
10830 } else if (stream->fourcc == FOURCC_mp4a) {
10831 stream->sampled = TRUE;
10834 /* collect sample information */
10835 if (!qtdemux_stbl_init (qtdemux, stream, stbl))
10836 goto samples_failed;
10838 if (qtdemux->fragmented) {
10841 /* need all moov samples as basis; probably not many if any at all */
10842 /* prevent moof parsing taking of at this time */
10843 offset = qtdemux->moof_offset;
10844 qtdemux->moof_offset = 0;
10845 if (stream->n_samples &&
10846 !qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
10847 qtdemux->moof_offset = offset;
10848 goto samples_failed;
10850 qtdemux->moof_offset = 0;
10851 /* movie duration more reliable in this case (e.g. mehd) */
10852 if (qtdemux->segment.duration &&
10853 GST_CLOCK_TIME_IS_VALID (qtdemux->segment.duration))
10855 GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->segment.duration);
10858 /* configure segments */
10859 if (!qtdemux_parse_segments (qtdemux, stream, trak))
10860 goto segments_failed;
10862 /* add some language tag, if useful */
10863 if (stream->lang_id[0] != '\0' && strcmp (stream->lang_id, "unk") &&
10864 strcmp (stream->lang_id, "und")) {
10865 const gchar *lang_code;
10867 /* convert ISO 639-2 code to ISO 639-1 */
10868 lang_code = gst_tag_get_language_code (stream->lang_id);
10869 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
10870 GST_TAG_LANGUAGE_CODE, (lang_code) ? lang_code : stream->lang_id, NULL);
10873 /* Check for UDTA tags */
10874 if ((udta = qtdemux_tree_get_child_by_type (trak, FOURCC_udta))) {
10875 qtdemux_parse_udta (qtdemux, stream->pending_tags, udta);
10878 /* now we are ready to add the stream */
10879 if (qtdemux->n_streams >= GST_QTDEMUX_MAX_STREAMS)
10880 goto too_many_streams;
10882 if (!qtdemux->got_moov) {
10883 qtdemux->streams[qtdemux->n_streams] = stream;
10884 qtdemux->n_streams++;
10885 GST_DEBUG_OBJECT (qtdemux, "n_streams is now %d", qtdemux->n_streams);
10893 GST_INFO_OBJECT (qtdemux, "skip disabled track");
10895 gst_qtdemux_stream_free (qtdemux, stream);
10900 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
10901 (_("This file is corrupt and cannot be played.")), (NULL));
10903 gst_qtdemux_stream_free (qtdemux, stream);
10908 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT, (NULL), (NULL));
10910 gst_qtdemux_stream_free (qtdemux, stream);
10916 /* we posted an error already */
10917 /* free stbl sub-atoms */
10918 gst_qtdemux_stbl_free (stream);
10920 gst_qtdemux_stream_free (qtdemux, stream);
10925 GST_INFO_OBJECT (qtdemux, "stream with track id %i already exists",
10928 gst_qtdemux_stream_free (qtdemux, stream);
10933 GST_INFO_OBJECT (qtdemux, "unknown subtype %" GST_FOURCC_FORMAT,
10934 GST_FOURCC_ARGS (stream->subtype));
10936 gst_qtdemux_stream_free (qtdemux, stream);
10941 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
10942 (_("This file contains too many streams. Only playing first %d"),
10943 GST_QTDEMUX_MAX_STREAMS), (NULL));
10948 /* If we can estimate the overall bitrate, and don't have information about the
10949 * stream bitrate for exactly one stream, this guesses the stream bitrate as
10950 * the overall bitrate minus the sum of the bitrates of all other streams. This
10951 * should be useful for the common case where we have one audio and one video
10952 * stream and can estimate the bitrate of one, but not the other. */
10954 gst_qtdemux_guess_bitrate (GstQTDemux * qtdemux)
10956 QtDemuxStream *stream = NULL;
10957 gint64 size, sys_bitrate, sum_bitrate = 0;
10958 GstClockTime duration;
10962 if (qtdemux->fragmented)
10965 GST_DEBUG_OBJECT (qtdemux, "Looking for streams with unknown bitrate");
10967 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &size)
10969 GST_DEBUG_OBJECT (qtdemux,
10970 "Size in bytes of the stream not known - bailing");
10974 /* Subtract the header size */
10975 GST_DEBUG_OBJECT (qtdemux, "Total size %" G_GINT64_FORMAT ", header size %u",
10976 size, qtdemux->header_size);
10978 if (size < qtdemux->header_size)
10981 size = size - qtdemux->header_size;
10983 if (!gst_qtdemux_get_duration (qtdemux, &duration)) {
10984 GST_DEBUG_OBJECT (qtdemux, "Stream duration not known - bailing");
10988 for (i = 0; i < qtdemux->n_streams; i++) {
10989 switch (qtdemux->streams[i]->subtype) {
10992 GST_DEBUG_OBJECT (qtdemux, "checking bitrate for %" GST_PTR_FORMAT,
10993 qtdemux->streams[i]->caps);
10994 /* retrieve bitrate, prefer avg then max */
10996 if (qtdemux->streams[i]->pending_tags) {
10997 gst_tag_list_get_uint (qtdemux->streams[i]->pending_tags,
10998 GST_TAG_MAXIMUM_BITRATE, &bitrate);
10999 GST_DEBUG_OBJECT (qtdemux, "max-bitrate: %u", bitrate);
11000 gst_tag_list_get_uint (qtdemux->streams[i]->pending_tags,
11001 GST_TAG_NOMINAL_BITRATE, &bitrate);
11002 GST_DEBUG_OBJECT (qtdemux, "nominal-bitrate: %u", bitrate);
11003 gst_tag_list_get_uint (qtdemux->streams[i]->pending_tags,
11004 GST_TAG_BITRATE, &bitrate);
11005 GST_DEBUG_OBJECT (qtdemux, "bitrate: %u", bitrate);
11008 sum_bitrate += bitrate;
11011 GST_DEBUG_OBJECT (qtdemux,
11012 ">1 stream with unknown bitrate - bailing");
11015 stream = qtdemux->streams[i];
11019 /* For other subtypes, we assume no significant impact on bitrate */
11025 GST_DEBUG_OBJECT (qtdemux, "All stream bitrates are known");
11029 sys_bitrate = gst_util_uint64_scale (size, GST_SECOND * 8, duration);
11031 if (sys_bitrate < sum_bitrate) {
11032 /* This can happen, since sum_bitrate might be derived from maximum
11033 * bitrates and not average bitrates */
11034 GST_DEBUG_OBJECT (qtdemux,
11035 "System bitrate less than sum bitrate - bailing");
11039 bitrate = sys_bitrate - sum_bitrate;
11040 GST_DEBUG_OBJECT (qtdemux, "System bitrate = %" G_GINT64_FORMAT
11041 ", Stream bitrate = %u", sys_bitrate, bitrate);
11043 if (!stream->pending_tags)
11044 stream->pending_tags = gst_tag_list_new_empty ();
11046 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
11047 GST_TAG_BITRATE, bitrate, NULL);
11050 static GstFlowReturn
11051 qtdemux_prepare_streams (GstQTDemux * qtdemux)
11054 GstFlowReturn ret = GST_FLOW_OK;
11056 GST_DEBUG_OBJECT (qtdemux, "prepare streams");
11058 for (i = 0; ret == GST_FLOW_OK && i < qtdemux->n_streams; i++) {
11059 QtDemuxStream *stream = qtdemux->streams[i];
11060 guint32 sample_num = 0;
11062 GST_DEBUG_OBJECT (qtdemux, "stream %d, id %d, fourcc %" GST_FOURCC_FORMAT,
11063 i, stream->track_id, GST_FOURCC_ARGS (stream->fourcc));
11065 if (qtdemux->fragmented) {
11066 /* need all moov samples first */
11067 GST_OBJECT_LOCK (qtdemux);
11068 while (stream->n_samples == 0)
11069 if ((ret = qtdemux_add_fragmented_samples (qtdemux)) != GST_FLOW_OK)
11071 GST_OBJECT_UNLOCK (qtdemux);
11073 /* discard any stray moof */
11074 qtdemux->moof_offset = 0;
11077 /* prepare braking */
11078 if (ret != GST_FLOW_ERROR)
11081 /* in pull mode, we should have parsed some sample info by now;
11082 * and quite some code will not handle no samples.
11083 * in push mode, we'll just have to deal with it */
11084 if (G_UNLIKELY (qtdemux->pullbased && !stream->n_samples)) {
11085 GST_DEBUG_OBJECT (qtdemux, "no samples for stream; discarding");
11086 gst_qtdemux_remove_stream (qtdemux, i);
11091 /* parse the initial sample for use in setting the frame rate cap */
11092 while (sample_num == 0 && sample_num < stream->n_samples) {
11093 if (!qtdemux_parse_samples (qtdemux, stream, sample_num))
11097 if (stream->n_samples > 0 && stream->stbl_index >= 0) {
11098 stream->first_duration = stream->samples[0].duration;
11099 GST_LOG_OBJECT (qtdemux, "stream %d first duration %u",
11100 stream->track_id, stream->first_duration);
11107 static GstFlowReturn
11108 qtdemux_expose_streams (GstQTDemux * qtdemux)
11111 GstFlowReturn ret = GST_FLOW_OK;
11112 GSList *oldpads = NULL;
11115 GST_DEBUG_OBJECT (qtdemux, "exposing streams");
11117 for (i = 0; ret == GST_FLOW_OK && i < qtdemux->n_streams; i++) {
11118 QtDemuxStream *stream = qtdemux->streams[i];
11119 GstPad *oldpad = stream->pad;
11122 GST_DEBUG_OBJECT (qtdemux, "stream %d, id %d, fourcc %" GST_FOURCC_FORMAT,
11123 i, stream->track_id, GST_FOURCC_ARGS (stream->fourcc));
11125 if ((stream->subtype == FOURCC_text || stream->subtype == FOURCC_sbtl) &&
11126 stream->track_id == qtdemux->chapters_track_id) {
11127 /* TODO - parse chapters track and expose it as GstToc; For now just ignore it
11128 so that it doesn't look like a subtitle track */
11129 gst_qtdemux_remove_stream (qtdemux, i);
11134 /* now we have all info and can expose */
11135 list = stream->pending_tags;
11136 stream->pending_tags = NULL;
11138 oldpads = g_slist_prepend (oldpads, oldpad);
11139 if (!gst_qtdemux_add_stream (qtdemux, stream, list))
11140 return GST_FLOW_ERROR;
11143 gst_qtdemux_guess_bitrate (qtdemux);
11145 gst_element_no_more_pads (GST_ELEMENT_CAST (qtdemux));
11147 for (iter = oldpads; iter; iter = g_slist_next (iter)) {
11148 GstPad *oldpad = iter->data;
11151 event = gst_event_new_eos ();
11152 if (qtdemux->segment_seqnum)
11153 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
11155 gst_pad_push_event (oldpad, event);
11156 gst_pad_set_active (oldpad, FALSE);
11157 gst_element_remove_pad (GST_ELEMENT (qtdemux), oldpad);
11158 gst_flow_combiner_remove_pad (qtdemux->flowcombiner, oldpad);
11159 gst_object_unref (oldpad);
11162 /* check if we should post a redirect in case there is a single trak
11163 * and it is a redirecting trak */
11164 if (qtdemux->n_streams == 1 && qtdemux->streams[0]->redirect_uri != NULL) {
11167 GST_INFO_OBJECT (qtdemux, "Issuing a redirect due to a single track with "
11168 "an external content");
11169 m = gst_message_new_element (GST_OBJECT_CAST (qtdemux),
11170 gst_structure_new ("redirect",
11171 "new-location", G_TYPE_STRING, qtdemux->streams[0]->redirect_uri,
11173 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), m);
11174 qtdemux->posted_redirect = TRUE;
11177 for (i = 0; i < qtdemux->n_streams; i++) {
11178 QtDemuxStream *stream = qtdemux->streams[i];
11180 qtdemux_do_allocation (qtdemux, stream);
11183 qtdemux->exposed = TRUE;
11187 /* check if major or compatible brand is 3GP */
11188 static inline gboolean
11189 qtdemux_is_brand_3gp (GstQTDemux * qtdemux, gboolean major)
11192 return ((qtdemux->major_brand & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
11194 } else if (qtdemux->comp_brands != NULL) {
11198 gboolean res = FALSE;
11200 gst_buffer_map (qtdemux->comp_brands, &map, GST_MAP_READ);
11203 while (size >= 4) {
11204 res = res || ((QT_FOURCC (data) & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
11209 gst_buffer_unmap (qtdemux->comp_brands, &map);
11216 /* check if tag is a spec'ed 3GP tag keyword storing a string */
11217 static inline gboolean
11218 qtdemux_is_string_tag_3gp (GstQTDemux * qtdemux, guint32 fourcc)
11220 return fourcc == FOURCC_cprt || fourcc == FOURCC_gnre || fourcc == FOURCC_titl
11221 || fourcc == FOURCC_dscp || fourcc == FOURCC_perf || fourcc == FOURCC_auth
11222 || fourcc == FOURCC_albm;
11226 qtdemux_tag_add_location (GstQTDemux * qtdemux, GstTagList * taglist,
11227 const char *tag, const char *dummy, GNode * node)
11229 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
11233 gdouble longitude, latitude, altitude;
11236 len = QT_UINT32 (node->data);
11243 /* TODO: language code skipped */
11245 name = gst_tag_freeform_string_to_utf8 (data + offset, -1, env_vars);
11248 /* do not alarm in trivial case, but bail out otherwise */
11249 if (*(data + offset) != 0) {
11250 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8, "
11254 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
11255 GST_TAG_GEO_LOCATION_NAME, name, NULL);
11256 offset += strlen (name);
11260 if (len < offset + 2 + 4 + 4 + 4)
11263 /* +1 +1 = skip null-terminator and location role byte */
11265 /* table in spec says unsigned, semantics say negative has meaning ... */
11266 longitude = QT_SFP32 (data + offset);
11269 latitude = QT_SFP32 (data + offset);
11272 altitude = QT_SFP32 (data + offset);
11274 /* one invalid means all are invalid */
11275 if (longitude >= -180.0 && longitude <= 180.0 &&
11276 latitude >= -90.0 && latitude <= 90.0) {
11277 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
11278 GST_TAG_GEO_LOCATION_LATITUDE, latitude,
11279 GST_TAG_GEO_LOCATION_LONGITUDE, longitude,
11280 GST_TAG_GEO_LOCATION_ELEVATION, altitude, NULL);
11283 /* TODO: no GST_TAG_, so astronomical body and additional notes skipped */
11290 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP location");
11297 qtdemux_tag_add_year (GstQTDemux * qtdemux, GstTagList * taglist,
11298 const char *tag, const char *dummy, GNode * node)
11304 len = QT_UINT32 (node->data);
11308 y = QT_UINT16 ((guint8 *) node->data + 12);
11310 GST_DEBUG_OBJECT (qtdemux, "year: %u is not a valid year", y);
11313 GST_DEBUG_OBJECT (qtdemux, "year: %u", y);
11315 date = g_date_new_dmy (1, 1, y);
11316 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, date, NULL);
11317 g_date_free (date);
11321 qtdemux_tag_add_classification (GstQTDemux * qtdemux, GstTagList * taglist,
11322 const char *tag, const char *dummy, GNode * node)
11325 char *tag_str = NULL;
11330 len = QT_UINT32 (node->data);
11335 entity = (guint8 *) node->data + offset;
11336 if (entity[0] == 0 || entity[1] == 0 || entity[2] == 0 || entity[3] == 0) {
11337 GST_DEBUG_OBJECT (qtdemux,
11338 "classification info: %c%c%c%c invalid classification entity",
11339 entity[0], entity[1], entity[2], entity[3]);
11344 table = QT_UINT16 ((guint8 *) node->data + offset);
11346 /* Language code skipped */
11350 /* Tag format: "XXXX://Y[YYYY]/classification info string"
11351 * XXXX: classification entity, fixed length 4 chars.
11352 * Y[YYYY]: classification table, max 5 chars.
11354 tag_str = g_strdup_printf ("----://%u/%s",
11355 table, (char *) node->data + offset);
11357 /* memcpy To be sure we're preserving byte order */
11358 memcpy (tag_str, entity, 4);
11359 GST_DEBUG_OBJECT (qtdemux, "classification info: %s", tag_str);
11361 gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND, tag, tag_str, NULL);
11370 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP classification");
11376 qtdemux_tag_add_str_full (GstQTDemux * qtdemux, GstTagList * taglist,
11377 const char *tag, const char *dummy, GNode * node)
11379 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
11385 gboolean ret = TRUE;
11386 const gchar *charset = NULL;
11388 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
11390 len = QT_UINT32 (data->data);
11391 type = QT_UINT32 ((guint8 *) data->data + 8);
11392 if (type == 0x00000001 && len > 16) {
11393 s = gst_tag_freeform_string_to_utf8 ((char *) data->data + 16, len - 16,
11396 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
11397 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, s, NULL);
11400 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
11404 len = QT_UINT32 (node->data);
11405 type = QT_UINT32 ((guint8 *) node->data + 4);
11406 if ((type >> 24) == 0xa9) {
11410 /* Type starts with the (C) symbol, so the next data is a list
11411 * of (string size(16), language code(16), string) */
11413 str_len = QT_UINT16 ((guint8 *) node->data + 8);
11414 lang_code = QT_UINT16 ((guint8 *) node->data + 10);
11416 /* the string + fourcc + size + 2 16bit fields,
11417 * means that there are more tags in this atom */
11418 if (len > str_len + 8 + 4) {
11419 /* TODO how to represent the same tag in different languages? */
11420 GST_WARNING_OBJECT (qtdemux, "Ignoring metadata entry with multiple "
11421 "text alternatives, reading only first one");
11425 len = str_len + 8 + 4; /* remove trailing strings that we don't use */
11426 GST_DEBUG_OBJECT (qtdemux, "found international text tag");
11428 if (lang_code < 0x800) { /* MAC encoded string */
11431 } else if (len > 14 && qtdemux_is_string_tag_3gp (qtdemux,
11432 QT_FOURCC ((guint8 *) node->data + 4))) {
11433 guint32 type = QT_UINT32 ((guint8 *) node->data + 8);
11435 /* we go for 3GP style encoding if major brands claims so,
11436 * or if no hope for data be ok UTF-8, and compatible 3GP brand present */
11437 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
11438 (qtdemux_is_brand_3gp (qtdemux, FALSE) &&
11439 ((type & 0x00FFFFFF) == 0x0) && (type >> 24 <= 0xF))) {
11441 /* 16-bit Language code is ignored here as well */
11442 GST_DEBUG_OBJECT (qtdemux, "found 3gpp text tag");
11449 GST_DEBUG_OBJECT (qtdemux, "found normal text tag");
11450 ret = FALSE; /* may have to fallback */
11453 GError *err = NULL;
11455 s = g_convert ((gchar *) node->data + offset, len - offset, "utf8",
11456 charset, NULL, NULL, &err);
11458 GST_DEBUG_OBJECT (qtdemux, "Failed to convert string from charset %s:"
11459 " %s(%d): %s", charset, g_quark_to_string (err->domain), err->code,
11461 g_error_free (err);
11464 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
11465 len - offset, env_vars);
11468 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
11469 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, s, NULL);
11473 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
11480 qtdemux_tag_add_str (GstQTDemux * qtdemux, GstTagList * taglist,
11481 const char *tag, const char *dummy, GNode * node)
11483 qtdemux_tag_add_str_full (qtdemux, taglist, tag, dummy, node);
11487 qtdemux_tag_add_keywords (GstQTDemux * qtdemux, GstTagList * taglist,
11488 const char *tag, const char *dummy, GNode * node)
11490 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
11492 char *s, *t, *k = NULL;
11497 /* first try normal string tag if major brand not 3GP */
11498 if (!qtdemux_is_brand_3gp (qtdemux, TRUE)) {
11499 if (!qtdemux_tag_add_str_full (qtdemux, taglist, tag, dummy, node)) {
11500 /* hm, that did not work, maybe 3gpp storage in non-3gpp major brand;
11501 * let's try it 3gpp way after minor safety check */
11503 if (QT_UINT32 (data) < 15 || !qtdemux_is_brand_3gp (qtdemux, FALSE))
11509 GST_DEBUG_OBJECT (qtdemux, "found 3gpp keyword tag");
11513 len = QT_UINT32 (data);
11517 count = QT_UINT8 (data + 14);
11519 for (; count; count--) {
11522 if (offset + 1 > len)
11524 slen = QT_UINT8 (data + offset);
11526 if (offset + slen > len)
11528 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
11531 GST_DEBUG_OBJECT (qtdemux, "adding keyword %s", GST_STR_NULL (s));
11533 t = g_strjoin (",", k, s, NULL);
11541 GST_DEBUG_OBJECT (qtdemux, "failed to convert keyword to UTF-8");
11548 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (k));
11549 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, k, NULL);
11558 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP keywords");
11564 qtdemux_tag_add_num (GstQTDemux * qtdemux, GstTagList * taglist,
11565 const char *tag1, const char *tag2, GNode * node)
11572 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
11574 len = QT_UINT32 (data->data);
11575 type = QT_UINT32 ((guint8 *) data->data + 8);
11576 if (type == 0x00000000 && len >= 22) {
11577 n1 = QT_UINT16 ((guint8 *) data->data + 18);
11578 n2 = QT_UINT16 ((guint8 *) data->data + 20);
11580 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag1, n1);
11581 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, n1, NULL);
11584 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag2, n2);
11585 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag2, n2, NULL);
11592 qtdemux_tag_add_tmpo (GstQTDemux * qtdemux, GstTagList * taglist,
11593 const char *tag1, const char *dummy, GNode * node)
11600 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
11602 len = QT_UINT32 (data->data);
11603 type = QT_UINT32 ((guint8 *) data->data + 8);
11604 GST_DEBUG_OBJECT (qtdemux, "have tempo tag, type=%d,len=%d", type, len);
11605 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
11606 if ((type == 0x00000015 || type == 0x0000000f) && len >= 18) {
11607 n1 = QT_UINT16 ((guint8 *) data->data + 16);
11609 /* do not add bpm=0 */
11610 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", n1);
11611 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, (gdouble) n1,
11619 qtdemux_tag_add_uint32 (GstQTDemux * qtdemux, GstTagList * taglist,
11620 const char *tag1, const char *dummy, GNode * node)
11627 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
11629 len = QT_UINT32 (data->data);
11630 type = QT_UINT32 ((guint8 *) data->data + 8);
11631 GST_DEBUG_OBJECT (qtdemux, "have %s tag, type=%d,len=%d", tag1, type, len);
11632 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
11633 if ((type == 0x00000015 || type == 0x0000000f) && len >= 20) {
11634 num = QT_UINT32 ((guint8 *) data->data + 16);
11636 /* do not add num=0 */
11637 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", num);
11638 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, num, NULL);
11645 qtdemux_tag_add_covr (GstQTDemux * qtdemux, GstTagList * taglist,
11646 const char *tag1, const char *dummy, GNode * node)
11653 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
11655 len = QT_UINT32 (data->data);
11656 type = QT_UINT32 ((guint8 *) data->data + 8);
11657 GST_DEBUG_OBJECT (qtdemux, "have covr tag, type=%d,len=%d", type, len);
11658 if ((type == 0x0000000d || type == 0x0000000e) && len > 16) {
11660 gst_tag_image_data_to_image_sample ((guint8 *) data->data + 16,
11661 len - 16, GST_TAG_IMAGE_TYPE_NONE))) {
11662 GST_DEBUG_OBJECT (qtdemux, "adding tag size %d", len - 16);
11663 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, sample, NULL);
11664 gst_sample_unref (sample);
11671 qtdemux_tag_add_date (GstQTDemux * qtdemux, GstTagList * taglist,
11672 const char *tag, const char *dummy, GNode * node)
11679 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
11681 len = QT_UINT32 (data->data);
11682 type = QT_UINT32 ((guint8 *) data->data + 8);
11683 if (type == 0x00000001 && len > 16) {
11684 guint y, m = 1, d = 1;
11687 s = g_strndup ((char *) data->data + 16, len - 16);
11688 GST_DEBUG_OBJECT (qtdemux, "adding date '%s'", s);
11689 ret = sscanf (s, "%u-%u-%u", &y, &m, &d);
11690 if (ret >= 1 && y > 1500 && y < 3000) {
11693 date = g_date_new_dmy (d, m, y);
11694 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, date, NULL);
11695 g_date_free (date);
11697 GST_DEBUG_OBJECT (qtdemux, "could not parse date string '%s'", s);
11705 qtdemux_tag_add_gnre (GstQTDemux * qtdemux, GstTagList * taglist,
11706 const char *tag, const char *dummy, GNode * node)
11710 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
11712 /* re-route to normal string tag if major brand says so
11713 * or no data atom and compatible brand suggests so */
11714 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
11715 (qtdemux_is_brand_3gp (qtdemux, FALSE) && !data)) {
11716 qtdemux_tag_add_str (qtdemux, taglist, tag, dummy, node);
11721 guint len, type, n;
11723 len = QT_UINT32 (data->data);
11724 type = QT_UINT32 ((guint8 *) data->data + 8);
11725 if (type == 0x00000000 && len >= 18) {
11726 n = QT_UINT16 ((guint8 *) data->data + 16);
11728 const gchar *genre;
11730 genre = gst_tag_id3_genre_get (n - 1);
11731 if (genre != NULL) {
11732 GST_DEBUG_OBJECT (qtdemux, "adding %d [%s]", n, genre);
11733 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, genre, NULL);
11741 qtdemux_add_double_tag_from_str (GstQTDemux * demux, GstTagList * taglist,
11742 const gchar * tag, guint8 * data, guint32 datasize)
11747 /* make a copy to have \0 at the end */
11748 datacopy = g_strndup ((gchar *) data, datasize);
11750 /* convert the str to double */
11751 if (sscanf (datacopy, "%lf", &value) == 1) {
11752 GST_DEBUG_OBJECT (demux, "adding tag: %s [%s]", tag, datacopy);
11753 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, value, NULL);
11755 GST_WARNING_OBJECT (demux, "Failed to parse double from string: %s",
11763 qtdemux_tag_add_revdns (GstQTDemux * demux, GstTagList * taglist,
11764 const char *tag, const char *tag_bis, GNode * node)
11773 const gchar *meanstr;
11774 const gchar *namestr;
11776 /* checking the whole ---- atom size for consistency */
11777 if (QT_UINT32 (node->data) <= 4 + 12 + 12 + 16) {
11778 GST_WARNING_OBJECT (demux, "Tag ---- atom is too small, ignoring");
11782 mean = qtdemux_tree_get_child_by_type (node, FOURCC_mean);
11784 GST_WARNING_OBJECT (demux, "No 'mean' atom found");
11788 meansize = QT_UINT32 (mean->data);
11789 if (meansize <= 12) {
11790 GST_WARNING_OBJECT (demux, "Small mean atom, ignoring the whole tag");
11793 meanstr = ((gchar *) mean->data) + 12;
11796 name = qtdemux_tree_get_child_by_type (node, FOURCC_name);
11798 GST_WARNING_OBJECT (demux, "'name' atom not found, ignoring tag");
11802 namesize = QT_UINT32 (name->data);
11803 if (namesize <= 12) {
11804 GST_WARNING_OBJECT (demux, "'name' atom is too small, ignoring tag");
11807 namestr = ((gchar *) name->data) + 12;
11815 * uint24 - data type
11819 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
11821 GST_WARNING_OBJECT (demux, "No data atom in this tag");
11824 datasize = QT_UINT32 (data->data);
11825 if (datasize <= 16) {
11826 GST_WARNING_OBJECT (demux, "Data atom too small");
11829 datatype = QT_UINT32 (((gchar *) data->data) + 8) & 0xFFFFFF;
11831 if ((strncmp (meanstr, "com.apple.iTunes", meansize) == 0) ||
11832 (strncmp (meanstr, "org.hydrogenaudio.replaygain", meansize) == 0)) {
11833 static const struct
11835 const gchar name[28];
11836 const gchar tag[28];
11839 "replaygain_track_gain", GST_TAG_TRACK_GAIN}, {
11840 "replaygain_track_peak", GST_TAG_TRACK_PEAK}, {
11841 "replaygain_album_gain", GST_TAG_ALBUM_GAIN}, {
11842 "replaygain_album_peak", GST_TAG_ALBUM_PEAK}, {
11843 "MusicBrainz Track Id", GST_TAG_MUSICBRAINZ_TRACKID}, {
11844 "MusicBrainz Artist Id", GST_TAG_MUSICBRAINZ_ARTISTID}, {
11845 "MusicBrainz Album Id", GST_TAG_MUSICBRAINZ_ALBUMID}, {
11846 "MusicBrainz Album Artist Id", GST_TAG_MUSICBRAINZ_ALBUMARTISTID}
11850 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
11851 if (!g_ascii_strncasecmp (tags[i].name, namestr, namesize)) {
11852 switch (gst_tag_get_type (tags[i].tag)) {
11853 case G_TYPE_DOUBLE:
11854 qtdemux_add_double_tag_from_str (demux, taglist, tags[i].tag,
11855 ((guint8 *) data->data) + 16, datasize - 16);
11857 case G_TYPE_STRING:
11858 qtdemux_tag_add_str (demux, taglist, tags[i].tag, NULL, node);
11867 if (i == G_N_ELEMENTS (tags))
11877 #ifndef GST_DISABLE_GST_DEBUG
11879 gchar *namestr_dbg;
11880 gchar *meanstr_dbg;
11882 meanstr_dbg = g_strndup (meanstr, meansize);
11883 namestr_dbg = g_strndup (namestr, namesize);
11885 GST_WARNING_OBJECT (demux, "This tag %s:%s type:%u is not mapped, "
11886 "file a bug at bugzilla.gnome.org", meanstr_dbg, namestr_dbg, datatype);
11888 g_free (namestr_dbg);
11889 g_free (meanstr_dbg);
11896 qtdemux_tag_add_id32 (GstQTDemux * demux, GstTagList * taglist, const char *tag,
11897 const char *tag_bis, GNode * node)
11902 GstTagList *id32_taglist = NULL;
11904 GST_LOG_OBJECT (demux, "parsing ID32");
11907 len = GST_READ_UINT32_BE (data);
11909 /* need at least full box and language tag */
11913 buf = gst_buffer_new_allocate (NULL, len - 14, NULL);
11914 gst_buffer_fill (buf, 0, data + 14, len - 14);
11916 id32_taglist = gst_tag_list_from_id3v2_tag (buf);
11917 if (id32_taglist) {
11918 GST_LOG_OBJECT (demux, "parsing ok");
11919 gst_tag_list_insert (taglist, id32_taglist, GST_TAG_MERGE_KEEP);
11920 gst_tag_list_unref (id32_taglist);
11922 GST_LOG_OBJECT (demux, "parsing failed");
11925 gst_buffer_unref (buf);
11928 typedef void (*GstQTDemuxAddTagFunc) (GstQTDemux * demux, GstTagList * taglist,
11929 const char *tag, const char *tag_bis, GNode * node);
11932 FOURCC_pcst -> if media is a podcast -> bool
11933 FOURCC_cpil -> if media is part of a compilation -> bool
11934 FOURCC_pgap -> if media is part of a gapless context -> bool
11935 FOURCC_tven -> the tv episode id e.g. S01E23 -> str
11938 static const struct
11941 const gchar *gst_tag;
11942 const gchar *gst_tag_bis;
11943 const GstQTDemuxAddTagFunc func;
11946 FOURCC__nam, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
11947 FOURCC_titl, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
11948 FOURCC__grp, GST_TAG_GROUPING, NULL, qtdemux_tag_add_str}, {
11949 FOURCC__wrt, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
11950 FOURCC__ART, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
11951 FOURCC_aART, GST_TAG_ALBUM_ARTIST, NULL, qtdemux_tag_add_str}, {
11952 FOURCC_perf, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
11953 FOURCC_auth, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
11954 FOURCC__alb, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
11955 FOURCC_albm, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
11956 FOURCC_cprt, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
11957 FOURCC__cpy, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
11958 FOURCC__cmt, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
11959 FOURCC__des, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
11960 FOURCC_desc, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
11961 FOURCC_dscp, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
11962 FOURCC__lyr, GST_TAG_LYRICS, NULL, qtdemux_tag_add_str}, {
11963 FOURCC__day, GST_TAG_DATE, NULL, qtdemux_tag_add_date}, {
11964 FOURCC_yrrc, GST_TAG_DATE, NULL, qtdemux_tag_add_year}, {
11965 FOURCC__too, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
11966 FOURCC__inf, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
11967 FOURCC_trkn, GST_TAG_TRACK_NUMBER, GST_TAG_TRACK_COUNT, qtdemux_tag_add_num}, {
11968 FOURCC_disk, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
11969 qtdemux_tag_add_num}, {
11970 FOURCC_disc, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
11971 qtdemux_tag_add_num}, {
11972 FOURCC__gen, GST_TAG_GENRE, NULL, qtdemux_tag_add_str}, {
11973 FOURCC_gnre, GST_TAG_GENRE, NULL, qtdemux_tag_add_gnre}, {
11974 FOURCC_tmpo, GST_TAG_BEATS_PER_MINUTE, NULL, qtdemux_tag_add_tmpo}, {
11975 FOURCC_covr, GST_TAG_PREVIEW_IMAGE, NULL, qtdemux_tag_add_covr}, {
11976 FOURCC_sonm, GST_TAG_TITLE_SORTNAME, NULL, qtdemux_tag_add_str}, {
11977 FOURCC_soal, GST_TAG_ALBUM_SORTNAME, NULL, qtdemux_tag_add_str}, {
11978 FOURCC_soar, GST_TAG_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
11979 FOURCC_soaa, GST_TAG_ALBUM_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
11980 FOURCC_soco, GST_TAG_COMPOSER_SORTNAME, NULL, qtdemux_tag_add_str}, {
11981 FOURCC_sosn, GST_TAG_SHOW_SORTNAME, NULL, qtdemux_tag_add_str}, {
11982 FOURCC_tvsh, GST_TAG_SHOW_NAME, NULL, qtdemux_tag_add_str}, {
11983 FOURCC_tvsn, GST_TAG_SHOW_SEASON_NUMBER, NULL, qtdemux_tag_add_uint32}, {
11984 FOURCC_tves, GST_TAG_SHOW_EPISODE_NUMBER, NULL, qtdemux_tag_add_uint32}, {
11985 FOURCC_kywd, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_keywords}, {
11986 FOURCC_keyw, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_str}, {
11987 FOURCC__enc, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
11988 FOURCC_loci, GST_TAG_GEO_LOCATION_NAME, NULL, qtdemux_tag_add_location}, {
11989 FOURCC_clsf, GST_QT_DEMUX_CLASSIFICATION_TAG, NULL,
11990 qtdemux_tag_add_classification}, {
11991 FOURCC__mak, GST_TAG_DEVICE_MANUFACTURER, NULL, qtdemux_tag_add_str}, {
11992 FOURCC__mod, GST_TAG_DEVICE_MODEL, NULL, qtdemux_tag_add_str}, {
11993 FOURCC__swr, GST_TAG_APPLICATION_NAME, NULL, qtdemux_tag_add_str}, {
11995 /* This is a special case, some tags are stored in this
11996 * 'reverse dns naming', according to:
11997 * http://atomicparsley.sourceforge.net/mpeg-4files.html and
12000 FOURCC_____, "", NULL, qtdemux_tag_add_revdns}, {
12001 /* see http://www.mp4ra.org/specs.html for ID32 in meta box */
12002 FOURCC_ID32, "", NULL, qtdemux_tag_add_id32}
12005 struct _GstQtDemuxTagList
12008 GstTagList *taglist;
12010 typedef struct _GstQtDemuxTagList GstQtDemuxTagList;
12013 qtdemux_tag_add_blob (GNode * node, GstQtDemuxTagList * qtdemuxtaglist)
12019 const gchar *style;
12024 GstQTDemux *demux = qtdemuxtaglist->demux;
12025 GstTagList *taglist = qtdemuxtaglist->taglist;
12028 len = QT_UINT32 (data);
12029 buf = gst_buffer_new_and_alloc (len);
12030 gst_buffer_fill (buf, 0, data, len);
12032 /* heuristic to determine style of tag */
12033 if (QT_FOURCC (data + 4) == FOURCC_____ ||
12034 (len > 8 + 12 && QT_FOURCC (data + 12) == FOURCC_data))
12036 else if (demux->major_brand == FOURCC_qt__)
12037 style = "quicktime";
12038 /* fall back to assuming iso/3gp tag style */
12042 /* santize the name for the caps. */
12043 for (i = 0; i < 4; i++) {
12044 guint8 d = data[4 + i];
12045 if (g_ascii_isalnum (d))
12046 ndata[i] = g_ascii_tolower (d);
12051 media_type = g_strdup_printf ("application/x-gst-qt-%c%c%c%c-tag",
12052 ndata[0], ndata[1], ndata[2], ndata[3]);
12053 GST_DEBUG_OBJECT (demux, "media type %s", media_type);
12055 s = gst_structure_new (media_type, "style", G_TYPE_STRING, style, NULL);
12056 sample = gst_sample_new (buf, NULL, NULL, s);
12057 gst_buffer_unref (buf);
12058 g_free (media_type);
12060 GST_DEBUG_OBJECT (demux, "adding private tag; size %d, info %" GST_PTR_FORMAT,
12063 gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND,
12064 GST_QT_DEMUX_PRIVATE_TAG, sample, NULL);
12066 gst_sample_unref (sample);
12070 qtdemux_parse_udta (GstQTDemux * qtdemux, GstTagList * taglist, GNode * udta)
12077 GstQtDemuxTagList demuxtaglist;
12079 demuxtaglist.demux = qtdemux;
12080 demuxtaglist.taglist = taglist;
12082 meta = qtdemux_tree_get_child_by_type (udta, FOURCC_meta);
12083 if (meta != NULL) {
12084 ilst = qtdemux_tree_get_child_by_type (meta, FOURCC_ilst);
12085 if (ilst == NULL) {
12086 GST_LOG_OBJECT (qtdemux, "no ilst");
12091 GST_LOG_OBJECT (qtdemux, "no meta so using udta itself");
12095 while (i < G_N_ELEMENTS (add_funcs)) {
12096 node = qtdemux_tree_get_child_by_type (ilst, add_funcs[i].fourcc);
12100 len = QT_UINT32 (node->data);
12102 GST_DEBUG_OBJECT (qtdemux, "too small tag atom %" GST_FOURCC_FORMAT,
12103 GST_FOURCC_ARGS (add_funcs[i].fourcc));
12105 add_funcs[i].func (qtdemux, taglist, add_funcs[i].gst_tag,
12106 add_funcs[i].gst_tag_bis, node);
12108 g_node_destroy (node);
12114 /* parsed nodes have been removed, pass along remainder as blob */
12115 g_node_children_foreach (ilst, G_TRAVERSE_ALL,
12116 (GNodeForeachFunc) qtdemux_tag_add_blob, &demuxtaglist);
12118 /* parse up XMP_ node if existing */
12119 xmp_ = qtdemux_tree_get_child_by_type (udta, FOURCC_XMP_);
12120 if (xmp_ != NULL) {
12122 GstTagList *xmptaglist;
12124 buf = _gst_buffer_new_wrapped (((guint8 *) xmp_->data) + 8,
12125 QT_UINT32 ((guint8 *) xmp_->data) - 8, NULL);
12126 xmptaglist = gst_tag_list_from_xmp_buffer (buf);
12127 gst_buffer_unref (buf);
12129 qtdemux_handle_xmp_taglist (qtdemux, taglist, xmptaglist);
12131 GST_DEBUG_OBJECT (qtdemux, "No XMP_ node found");
12137 GstStructure *structure; /* helper for sort function */
12139 guint min_req_bitrate;
12140 guint min_req_qt_version;
12144 qtdemux_redirects_sort_func (gconstpointer a, gconstpointer b)
12146 GstQtReference *ref_a = (GstQtReference *) a;
12147 GstQtReference *ref_b = (GstQtReference *) b;
12149 if (ref_b->min_req_qt_version != ref_a->min_req_qt_version)
12150 return ref_b->min_req_qt_version - ref_a->min_req_qt_version;
12152 /* known bitrates go before unknown; higher bitrates go first */
12153 return ref_b->min_req_bitrate - ref_a->min_req_bitrate;
12156 /* sort the redirects and post a message for the application.
12159 qtdemux_process_redirects (GstQTDemux * qtdemux, GList * references)
12161 GstQtReference *best;
12164 GValue list_val = { 0, };
12167 g_assert (references != NULL);
12169 references = g_list_sort (references, qtdemux_redirects_sort_func);
12171 best = (GstQtReference *) references->data;
12173 g_value_init (&list_val, GST_TYPE_LIST);
12175 for (l = references; l != NULL; l = l->next) {
12176 GstQtReference *ref = (GstQtReference *) l->data;
12177 GValue struct_val = { 0, };
12179 ref->structure = gst_structure_new ("redirect",
12180 "new-location", G_TYPE_STRING, ref->location, NULL);
12182 if (ref->min_req_bitrate > 0) {
12183 gst_structure_set (ref->structure, "minimum-bitrate", G_TYPE_INT,
12184 ref->min_req_bitrate, NULL);
12187 g_value_init (&struct_val, GST_TYPE_STRUCTURE);
12188 g_value_set_boxed (&struct_val, ref->structure);
12189 gst_value_list_append_value (&list_val, &struct_val);
12190 g_value_unset (&struct_val);
12191 /* don't free anything here yet, since we need best->structure below */
12194 g_assert (best != NULL);
12195 s = gst_structure_copy (best->structure);
12197 if (g_list_length (references) > 1) {
12198 gst_structure_set_value (s, "locations", &list_val);
12201 g_value_unset (&list_val);
12203 for (l = references; l != NULL; l = l->next) {
12204 GstQtReference *ref = (GstQtReference *) l->data;
12206 gst_structure_free (ref->structure);
12207 g_free (ref->location);
12210 g_list_free (references);
12212 GST_INFO_OBJECT (qtdemux, "posting redirect message: %" GST_PTR_FORMAT, s);
12213 msg = gst_message_new_element (GST_OBJECT_CAST (qtdemux), s);
12214 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
12215 qtdemux->posted_redirect = TRUE;
12218 /* look for redirect nodes, collect all redirect information and
12222 qtdemux_parse_redirects (GstQTDemux * qtdemux)
12224 GNode *rmra, *rmda, *rdrf;
12226 rmra = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_rmra);
12228 GList *redirects = NULL;
12230 rmda = qtdemux_tree_get_child_by_type (rmra, FOURCC_rmda);
12232 GstQtReference ref = { NULL, NULL, 0, 0 };
12233 GNode *rmdr, *rmvc;
12235 if ((rmdr = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmdr))) {
12236 ref.min_req_bitrate = QT_UINT32 ((guint8 *) rmdr->data + 12);
12237 GST_LOG_OBJECT (qtdemux, "data rate atom, required bitrate = %u",
12238 ref.min_req_bitrate);
12241 if ((rmvc = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmvc))) {
12242 guint32 package = QT_FOURCC ((guint8 *) rmvc->data + 12);
12243 guint version = QT_UINT32 ((guint8 *) rmvc->data + 16);
12245 #ifndef GST_DISABLE_GST_DEBUG
12246 guint bitmask = QT_UINT32 ((guint8 *) rmvc->data + 20);
12248 guint check_type = QT_UINT16 ((guint8 *) rmvc->data + 24);
12250 GST_LOG_OBJECT (qtdemux,
12251 "version check atom [%" GST_FOURCC_FORMAT "], version=0x%08x"
12252 ", mask=%08x, check_type=%u", GST_FOURCC_ARGS (package), version,
12253 bitmask, check_type);
12254 if (package == FOURCC_qtim && check_type == 0) {
12255 ref.min_req_qt_version = version;
12259 rdrf = qtdemux_tree_get_child_by_type (rmda, FOURCC_rdrf);
12265 ref_len = QT_UINT32 ((guint8 *) rdrf->data);
12266 if (ref_len > 20) {
12267 ref_type = QT_FOURCC ((guint8 *) rdrf->data + 12);
12268 ref_data = (guint8 *) rdrf->data + 20;
12269 if (ref_type == FOURCC_alis) {
12270 guint record_len, record_version, fn_len;
12272 if (ref_len > 70) {
12273 /* MacOSX alias record, google for alias-layout.txt */
12274 record_len = QT_UINT16 (ref_data + 4);
12275 record_version = QT_UINT16 (ref_data + 4 + 2);
12276 fn_len = QT_UINT8 (ref_data + 50);
12277 if (record_len > 50 && record_version == 2 && fn_len > 0) {
12278 ref.location = g_strndup ((gchar *) ref_data + 51, fn_len);
12281 GST_WARNING_OBJECT (qtdemux, "Invalid rdrf/alis size (%u < 70)",
12284 } else if (ref_type == FOURCC_url_) {
12285 ref.location = g_strndup ((gchar *) ref_data, ref_len - 8);
12287 GST_DEBUG_OBJECT (qtdemux,
12288 "unknown rdrf reference type %" GST_FOURCC_FORMAT,
12289 GST_FOURCC_ARGS (ref_type));
12291 if (ref.location != NULL) {
12292 GST_INFO_OBJECT (qtdemux, "New location: %s", ref.location);
12294 g_list_prepend (redirects, g_memdup (&ref, sizeof (ref)));
12296 GST_WARNING_OBJECT (qtdemux,
12297 "Failed to extract redirect location from rdrf atom");
12300 GST_WARNING_OBJECT (qtdemux, "Invalid rdrf size (%u < 20)", ref_len);
12304 /* look for others */
12305 rmda = qtdemux_tree_get_sibling_by_type (rmda, FOURCC_rmda);
12308 if (redirects != NULL) {
12309 qtdemux_process_redirects (qtdemux, redirects);
12315 static GstTagList *
12316 qtdemux_add_container_format (GstQTDemux * qtdemux, GstTagList * tags)
12320 if (tags == NULL) {
12321 tags = gst_tag_list_new_empty ();
12322 gst_tag_list_set_scope (tags, GST_TAG_SCOPE_GLOBAL);
12325 if (qtdemux->major_brand == FOURCC_mjp2)
12326 fmt = "Motion JPEG 2000";
12327 else if ((qtdemux->major_brand & 0xffff) == FOURCC_3g__)
12329 else if (qtdemux->major_brand == FOURCC_qt__)
12331 else if (qtdemux->fragmented)
12334 fmt = "ISO MP4/M4A";
12336 GST_LOG_OBJECT (qtdemux, "mapped %" GST_FOURCC_FORMAT " to '%s'",
12337 GST_FOURCC_ARGS (qtdemux->major_brand), fmt);
12339 gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_CONTAINER_FORMAT,
12345 /* we have read the complete moov node now.
12346 * This function parses all of the relevant info, creates the traks and
12347 * prepares all data structures for playback
12350 qtdemux_parse_tree (GstQTDemux * qtdemux)
12356 GstClockTime duration;
12358 guint64 creation_time;
12359 GstDateTime *datetime = NULL;
12362 /* make sure we have a usable taglist */
12363 if (!qtdemux->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);
12370 mvhd = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvhd);
12371 if (mvhd == NULL) {
12372 GST_LOG_OBJECT (qtdemux, "No mvhd node found, looking for redirects.");
12373 return qtdemux_parse_redirects (qtdemux);
12376 version = QT_UINT8 ((guint8 *) mvhd->data + 8);
12377 if (version == 1) {
12378 creation_time = QT_UINT64 ((guint8 *) mvhd->data + 12);
12379 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 28);
12380 qtdemux->duration = QT_UINT64 ((guint8 *) mvhd->data + 32);
12381 } else if (version == 0) {
12382 creation_time = QT_UINT32 ((guint8 *) mvhd->data + 12);
12383 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 20);
12384 qtdemux->duration = QT_UINT32 ((guint8 *) mvhd->data + 24);
12386 GST_WARNING_OBJECT (qtdemux, "Unhandled mvhd version %d", version);
12390 /* Moving qt creation time (secs since 1904) to unix time */
12391 if (creation_time != 0) {
12392 /* Try to use epoch first as it should be faster and more commonly found */
12393 if (creation_time >= QTDEMUX_SECONDS_FROM_1904_TO_1970) {
12396 creation_time -= QTDEMUX_SECONDS_FROM_1904_TO_1970;
12397 /* some data cleansing sanity */
12398 g_get_current_time (&now);
12399 if (now.tv_sec + 24 * 3600 < creation_time) {
12400 GST_DEBUG_OBJECT (qtdemux, "discarding bogus future creation time");
12402 datetime = gst_date_time_new_from_unix_epoch_utc (creation_time);
12405 GDateTime *base_dt = g_date_time_new_utc (1904, 1, 1, 0, 0, 0);
12406 GDateTime *dt, *dt_local;
12408 dt = g_date_time_add_seconds (base_dt, creation_time);
12409 dt_local = g_date_time_to_local (dt);
12410 datetime = gst_date_time_new_from_g_date_time (dt_local);
12412 g_date_time_unref (base_dt);
12413 g_date_time_unref (dt);
12417 /* Use KEEP as explicit tags should have a higher priority than mvhd tag */
12418 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_KEEP, GST_TAG_DATE_TIME,
12420 gst_date_time_unref (datetime);
12423 GST_INFO_OBJECT (qtdemux, "timescale: %u", qtdemux->timescale);
12424 GST_INFO_OBJECT (qtdemux, "duration: %" G_GUINT64_FORMAT, qtdemux->duration);
12426 /* check for fragmented file and get some (default) data */
12427 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
12430 GstByteReader mehd_data;
12432 /* let track parsing or anyone know weird stuff might happen ... */
12433 qtdemux->fragmented = TRUE;
12435 /* compensate for total duration */
12436 mehd = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_mehd, &mehd_data);
12438 qtdemux_parse_mehd (qtdemux, &mehd_data);
12441 /* set duration in the segment info */
12442 gst_qtdemux_get_duration (qtdemux, &duration);
12444 qtdemux->segment.duration = duration;
12445 /* also do not exceed duration; stop is set that way post seek anyway,
12446 * and segment activation falls back to duration,
12447 * whereas loop only checks stop, so let's align this here as well */
12448 qtdemux->segment.stop = duration;
12451 /* parse all traks */
12452 trak = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_trak);
12454 qtdemux_parse_trak (qtdemux, trak);
12455 /* iterate all siblings */
12456 trak = qtdemux_tree_get_sibling_by_type (trak, FOURCC_trak);
12459 if (!qtdemux->tag_list) {
12460 GST_DEBUG_OBJECT (qtdemux, "new tag list");
12461 qtdemux->tag_list = gst_tag_list_new_empty ();
12462 gst_tag_list_set_scope (qtdemux->tag_list, GST_TAG_SCOPE_GLOBAL);
12464 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
12468 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_udta);
12470 qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
12472 GST_LOG_OBJECT (qtdemux, "No udta node found.");
12475 /* maybe also some tags in meta box */
12476 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_meta);
12478 GST_DEBUG_OBJECT (qtdemux, "Parsing meta box for tags.");
12479 qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
12481 GST_LOG_OBJECT (qtdemux, "No meta node found.");
12484 /* parse any protection system info */
12485 pssh = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_pssh);
12487 GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
12488 qtdemux_parse_pssh (qtdemux, pssh);
12489 pssh = qtdemux_tree_get_sibling_by_type (pssh, FOURCC_pssh);
12492 qtdemux->tag_list = qtdemux_add_container_format (qtdemux, qtdemux->tag_list);
12497 /* taken from ffmpeg */
12499 read_descr_size (guint8 * ptr, guint8 * end, guint8 ** end_out)
12511 len = (len << 7) | (c & 0x7f);
12519 /* this can change the codec originally present in @list */
12521 gst_qtdemux_handle_esds (GstQTDemux * qtdemux, QtDemuxStream * stream,
12522 GNode * esds, GstTagList * list)
12524 int len = QT_UINT32 (esds->data);
12525 guint8 *ptr = esds->data;
12526 guint8 *end = ptr + len;
12528 guint8 *data_ptr = NULL;
12530 guint8 object_type_id = 0;
12531 const char *codec_name = NULL;
12532 GstCaps *caps = NULL;
12534 GST_MEMDUMP_OBJECT (qtdemux, "esds", ptr, len);
12536 GST_DEBUG_OBJECT (qtdemux, "version/flags = %08x", QT_UINT32 (ptr));
12538 while (ptr + 1 < end) {
12539 tag = QT_UINT8 (ptr);
12540 GST_DEBUG_OBJECT (qtdemux, "tag = %02x", tag);
12542 len = read_descr_size (ptr, end, &ptr);
12543 GST_DEBUG_OBJECT (qtdemux, "len = %d", len);
12545 /* Check the stated amount of data is available for reading */
12546 if (len < 0 || ptr + len > end)
12550 case ES_DESCRIPTOR_TAG:
12551 GST_DEBUG_OBJECT (qtdemux, "ID %04x", QT_UINT16 (ptr));
12552 GST_DEBUG_OBJECT (qtdemux, "priority %04x", QT_UINT8 (ptr + 2));
12555 case DECODER_CONFIG_DESC_TAG:{
12556 guint max_bitrate, avg_bitrate;
12558 object_type_id = QT_UINT8 (ptr);
12559 max_bitrate = QT_UINT32 (ptr + 5);
12560 avg_bitrate = QT_UINT32 (ptr + 9);
12561 GST_DEBUG_OBJECT (qtdemux, "object_type_id %02x", object_type_id);
12562 GST_DEBUG_OBJECT (qtdemux, "stream_type %02x", QT_UINT8 (ptr + 1));
12563 GST_DEBUG_OBJECT (qtdemux, "buffer_size_db %02x", QT_UINT24 (ptr + 2));
12564 GST_DEBUG_OBJECT (qtdemux, "max bitrate %u", max_bitrate);
12565 GST_DEBUG_OBJECT (qtdemux, "avg bitrate %u", avg_bitrate);
12566 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
12567 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
12568 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
12570 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
12571 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
12572 avg_bitrate, NULL);
12577 case DECODER_SPECIFIC_INFO_TAG:
12578 GST_MEMDUMP_OBJECT (qtdemux, "data", ptr, len);
12579 if (object_type_id == 0xe0 && len == 0x40) {
12585 GST_DEBUG_OBJECT (qtdemux,
12586 "Have VOBSUB palette. Creating palette event");
12587 /* move to decConfigDescr data and read palette */
12589 for (i = 0; i < 16; i++) {
12590 clut[i] = QT_UINT32 (data);
12594 s = gst_structure_new ("application/x-gst-dvd", "event",
12595 G_TYPE_STRING, "dvd-spu-clut-change",
12596 "clut00", G_TYPE_INT, clut[0], "clut01", G_TYPE_INT, clut[1],
12597 "clut02", G_TYPE_INT, clut[2], "clut03", G_TYPE_INT, clut[3],
12598 "clut04", G_TYPE_INT, clut[4], "clut05", G_TYPE_INT, clut[5],
12599 "clut06", G_TYPE_INT, clut[6], "clut07", G_TYPE_INT, clut[7],
12600 "clut08", G_TYPE_INT, clut[8], "clut09", G_TYPE_INT, clut[9],
12601 "clut10", G_TYPE_INT, clut[10], "clut11", G_TYPE_INT, clut[11],
12602 "clut12", G_TYPE_INT, clut[12], "clut13", G_TYPE_INT, clut[13],
12603 "clut14", G_TYPE_INT, clut[14], "clut15", G_TYPE_INT, clut[15],
12606 /* store event and trigger custom processing */
12607 stream->pending_event =
12608 gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s);
12610 /* Generic codec_data handler puts it on the caps */
12617 case SL_CONFIG_DESC_TAG:
12618 GST_DEBUG_OBJECT (qtdemux, "data %02x", QT_UINT8 (ptr));
12622 GST_DEBUG_OBJECT (qtdemux, "Unknown/unhandled descriptor tag %02x",
12624 GST_MEMDUMP_OBJECT (qtdemux, "descriptor data", ptr, len);
12630 /* object_type_id in the esds atom in mp4a and mp4v tells us which codec is
12631 * in use, and should also be used to override some other parameters for some
12633 switch (object_type_id) {
12634 case 0x20: /* MPEG-4 */
12635 /* 4 bytes for the visual_object_sequence_start_code and 1 byte for the
12636 * profile_and_level_indication */
12637 if (data_ptr != NULL && data_len >= 5 &&
12638 GST_READ_UINT32_BE (data_ptr) == 0x000001b0) {
12639 gst_codec_utils_mpeg4video_caps_set_level_and_profile (stream->caps,
12640 data_ptr + 4, data_len - 4);
12642 break; /* Nothing special needed here */
12643 case 0x21: /* H.264 */
12644 codec_name = "H.264 / AVC";
12645 caps = gst_caps_new_simple ("video/x-h264",
12646 "stream-format", G_TYPE_STRING, "avc",
12647 "alignment", G_TYPE_STRING, "au", NULL);
12649 case 0x40: /* AAC (any) */
12650 case 0x66: /* AAC Main */
12651 case 0x67: /* AAC LC */
12652 case 0x68: /* AAC SSR */
12653 /* Override channels and rate based on the codec_data, as it's often
12655 /* Only do so for basic setup without HE-AAC extension */
12656 if (data_ptr && data_len == 2) {
12657 guint channels, rate;
12659 channels = gst_codec_utils_aac_get_channels (data_ptr, data_len);
12661 stream->n_channels = channels;
12663 rate = gst_codec_utils_aac_get_sample_rate (data_ptr, data_len);
12665 stream->rate = rate;
12668 /* Set level and profile if possible */
12669 if (data_ptr != NULL && data_len >= 2) {
12670 gst_codec_utils_aac_caps_set_level_and_profile (stream->caps,
12671 data_ptr, data_len);
12673 const gchar *profile_str = NULL;
12676 guint8 *codec_data;
12677 gint rate_idx, profile;
12679 /* No codec_data, let's invent something.
12680 * FIXME: This is wrong for SBR! */
12682 GST_WARNING_OBJECT (qtdemux, "No codec_data for AAC available");
12684 buffer = gst_buffer_new_and_alloc (2);
12685 gst_buffer_map (buffer, &map, GST_MAP_WRITE);
12686 codec_data = map.data;
12689 gst_codec_utils_aac_get_index_from_sample_rate (stream->rate);
12691 switch (object_type_id) {
12693 profile_str = "main";
12697 profile_str = "lc";
12701 profile_str = "ssr";
12709 codec_data[0] = ((profile + 1) << 3) | ((rate_idx & 0xE) >> 1);
12710 codec_data[1] = ((rate_idx & 0x1) << 7) | (stream->n_channels << 3);
12712 gst_buffer_unmap (buffer, &map);
12713 gst_caps_set_simple (stream->caps, "codec_data", GST_TYPE_BUFFER,
12715 gst_buffer_unref (buffer);
12718 gst_caps_set_simple (stream->caps, "profile", G_TYPE_STRING,
12719 profile_str, NULL);
12723 case 0x60: /* MPEG-2, various profiles */
12729 codec_name = "MPEG-2 video";
12730 caps = gst_caps_new_simple ("video/mpeg",
12731 "mpegversion", G_TYPE_INT, 2,
12732 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
12734 case 0x69: /* MPEG-2 BC audio */
12735 case 0x6B: /* MPEG-1 audio */
12736 caps = gst_caps_new_simple ("audio/mpeg",
12737 "mpegversion", G_TYPE_INT, 1, "parsed", G_TYPE_BOOLEAN, TRUE, NULL);
12738 codec_name = "MPEG-1 audio";
12740 case 0x6A: /* MPEG-1 */
12741 codec_name = "MPEG-1 video";
12742 caps = gst_caps_new_simple ("video/mpeg",
12743 "mpegversion", G_TYPE_INT, 1,
12744 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
12746 case 0x6C: /* MJPEG */
12748 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
12750 codec_name = "Motion-JPEG";
12752 case 0x6D: /* PNG */
12754 gst_caps_new_simple ("image/png", "parsed", G_TYPE_BOOLEAN, TRUE,
12756 codec_name = "PNG still images";
12758 case 0x6E: /* JPEG2000 */
12759 codec_name = "JPEG-2000";
12760 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
12762 case 0xA4: /* Dirac */
12763 codec_name = "Dirac";
12764 caps = gst_caps_new_empty_simple ("video/x-dirac");
12766 case 0xA5: /* AC3 */
12767 codec_name = "AC-3 audio";
12768 caps = gst_caps_new_simple ("audio/x-ac3",
12769 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
12771 case 0xA9: /* AC3 */
12772 codec_name = "DTS audio";
12773 caps = gst_caps_new_simple ("audio/x-dts",
12774 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
12776 case 0xE1: /* QCELP */
12777 /* QCELP, the codec_data is a riff tag (little endian) with
12778 * 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). */
12779 caps = gst_caps_new_empty_simple ("audio/qcelp");
12780 codec_name = "QCELP";
12786 /* If we have a replacement caps, then change our caps for this stream */
12788 gst_caps_unref (stream->caps);
12789 stream->caps = caps;
12792 if (codec_name && list)
12793 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
12794 GST_TAG_AUDIO_CODEC, codec_name, NULL);
12796 /* Add the codec_data attribute to caps, if we have it */
12800 buffer = gst_buffer_new_and_alloc (data_len);
12801 gst_buffer_fill (buffer, 0, data_ptr, data_len);
12803 GST_DEBUG_OBJECT (qtdemux, "setting codec_data from esds");
12804 GST_MEMDUMP_OBJECT (qtdemux, "codec_data from esds", data_ptr, data_len);
12806 gst_caps_set_simple (stream->caps, "codec_data", GST_TYPE_BUFFER,
12808 gst_buffer_unref (buffer);
12813 #define _codec(name) \
12815 if (codec_name) { \
12816 *codec_name = g_strdup (name); \
12821 qtdemux_video_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
12822 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
12824 GstCaps *caps = NULL;
12825 GstVideoFormat format = GST_VIDEO_FORMAT_UNKNOWN;
12828 case GST_MAKE_FOURCC ('p', 'n', 'g', ' '):
12829 _codec ("PNG still images");
12830 caps = gst_caps_new_empty_simple ("image/png");
12833 _codec ("JPEG still images");
12835 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
12838 case GST_MAKE_FOURCC ('m', 'j', 'p', 'a'):
12839 case GST_MAKE_FOURCC ('A', 'V', 'D', 'J'):
12840 case GST_MAKE_FOURCC ('M', 'J', 'P', 'G'):
12841 case GST_MAKE_FOURCC ('d', 'm', 'b', '1'):
12842 _codec ("Motion-JPEG");
12844 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
12847 case GST_MAKE_FOURCC ('m', 'j', 'p', 'b'):
12848 _codec ("Motion-JPEG format B");
12849 caps = gst_caps_new_empty_simple ("video/x-mjpeg-b");
12852 _codec ("JPEG-2000");
12853 /* override to what it should be according to spec, avoid palette_data */
12854 stream->bits_per_sample = 24;
12855 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
12858 _codec ("Sorensen video v.3");
12859 caps = gst_caps_new_simple ("video/x-svq",
12860 "svqversion", G_TYPE_INT, 3, NULL);
12862 case GST_MAKE_FOURCC ('s', 'v', 'q', 'i'):
12863 case GST_MAKE_FOURCC ('S', 'V', 'Q', '1'):
12864 _codec ("Sorensen video v.1");
12865 caps = gst_caps_new_simple ("video/x-svq",
12866 "svqversion", G_TYPE_INT, 1, NULL);
12868 case GST_MAKE_FOURCC ('W', 'R', 'A', 'W'):
12869 caps = gst_caps_new_empty_simple ("video/x-raw");
12870 gst_caps_set_simple (caps, "format", G_TYPE_STRING, "RGB8P", NULL);
12871 _codec ("Windows Raw RGB");
12877 bps = QT_UINT16 (stsd_data + 98);
12880 format = GST_VIDEO_FORMAT_RGB15;
12883 format = GST_VIDEO_FORMAT_RGB16;
12886 format = GST_VIDEO_FORMAT_RGB;
12889 format = GST_VIDEO_FORMAT_ARGB;
12897 case GST_MAKE_FOURCC ('y', 'v', '1', '2'):
12898 format = GST_VIDEO_FORMAT_I420;
12900 case GST_MAKE_FOURCC ('y', 'u', 'v', '2'):
12901 case GST_MAKE_FOURCC ('Y', 'u', 'v', '2'):
12902 format = GST_VIDEO_FORMAT_I420;
12905 case GST_MAKE_FOURCC ('2', 'V', 'u', 'y'):
12906 format = GST_VIDEO_FORMAT_UYVY;
12908 case GST_MAKE_FOURCC ('v', '3', '0', '8'):
12909 format = GST_VIDEO_FORMAT_v308;
12911 case GST_MAKE_FOURCC ('v', '2', '1', '6'):
12912 format = GST_VIDEO_FORMAT_v216;
12915 format = GST_VIDEO_FORMAT_v210;
12917 case GST_MAKE_FOURCC ('r', '2', '1', '0'):
12918 format = GST_VIDEO_FORMAT_r210;
12920 /* Packed YUV 4:4:4 10 bit in 32 bits, complex
12921 case GST_MAKE_FOURCC ('v', '4', '1', '0'):
12922 format = GST_VIDEO_FORMAT_v410;
12925 /* Packed YUV 4:4:4:4 8 bit in 32 bits
12926 * but different order than AYUV
12927 case GST_MAKE_FOURCC ('v', '4', '0', '8'):
12928 format = GST_VIDEO_FORMAT_v408;
12931 case GST_MAKE_FOURCC ('m', 'p', 'e', 'g'):
12932 case GST_MAKE_FOURCC ('m', 'p', 'g', '1'):
12933 _codec ("MPEG-1 video");
12934 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
12935 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
12937 case GST_MAKE_FOURCC ('h', 'd', 'v', '1'): /* HDV 720p30 */
12938 case GST_MAKE_FOURCC ('h', 'd', 'v', '2'): /* HDV 1080i60 */
12939 case GST_MAKE_FOURCC ('h', 'd', 'v', '3'): /* HDV 1080i50 */
12940 case GST_MAKE_FOURCC ('h', 'd', 'v', '4'): /* HDV 720p24 */
12941 case GST_MAKE_FOURCC ('h', 'd', 'v', '5'): /* HDV 720p25 */
12942 case GST_MAKE_FOURCC ('h', 'd', 'v', '6'): /* HDV 1080p24 */
12943 case GST_MAKE_FOURCC ('h', 'd', 'v', '7'): /* HDV 1080p25 */
12944 case GST_MAKE_FOURCC ('h', 'd', 'v', '8'): /* HDV 1080p30 */
12945 case GST_MAKE_FOURCC ('h', 'd', 'v', '9'): /* HDV 720p60 */
12946 case GST_MAKE_FOURCC ('h', 'd', 'v', 'a'): /* HDV 720p50 */
12947 case GST_MAKE_FOURCC ('m', 'x', '5', 'n'): /* MPEG2 IMX NTSC 525/60 50mb/s produced by FCP */
12948 case GST_MAKE_FOURCC ('m', 'x', '5', 'p'): /* MPEG2 IMX PAL 625/60 50mb/s produced by FCP */
12949 case GST_MAKE_FOURCC ('m', 'x', '4', 'n'): /* MPEG2 IMX NTSC 525/60 40mb/s produced by FCP */
12950 case GST_MAKE_FOURCC ('m', 'x', '4', 'p'): /* MPEG2 IMX PAL 625/60 40mb/s produced by FCP */
12951 case GST_MAKE_FOURCC ('m', 'x', '3', 'n'): /* MPEG2 IMX NTSC 525/60 30mb/s produced by FCP */
12952 case GST_MAKE_FOURCC ('m', 'x', '3', 'p'): /* MPEG2 IMX PAL 625/50 30mb/s produced by FCP */
12953 case GST_MAKE_FOURCC ('x', 'd', 'v', '1'): /* XDCAM HD 720p30 35Mb/s */
12954 case GST_MAKE_FOURCC ('x', 'd', 'v', '2'): /* XDCAM HD 1080i60 35Mb/s */
12955 case GST_MAKE_FOURCC ('x', 'd', 'v', '3'): /* XDCAM HD 1080i50 35Mb/s */
12956 case GST_MAKE_FOURCC ('x', 'd', 'v', '4'): /* XDCAM HD 720p24 35Mb/s */
12957 case GST_MAKE_FOURCC ('x', 'd', 'v', '5'): /* XDCAM HD 720p25 35Mb/s */
12958 case GST_MAKE_FOURCC ('x', 'd', 'v', '6'): /* XDCAM HD 1080p24 35Mb/s */
12959 case GST_MAKE_FOURCC ('x', 'd', 'v', '7'): /* XDCAM HD 1080p25 35Mb/s */
12960 case GST_MAKE_FOURCC ('x', 'd', 'v', '8'): /* XDCAM HD 1080p30 35Mb/s */
12961 case GST_MAKE_FOURCC ('x', 'd', 'v', '9'): /* XDCAM HD 720p60 35Mb/s */
12962 case GST_MAKE_FOURCC ('x', 'd', 'v', 'a'): /* XDCAM HD 720p50 35Mb/s */
12963 case GST_MAKE_FOURCC ('x', 'd', 'v', 'b'): /* XDCAM EX 1080i60 50Mb/s CBR */
12964 case GST_MAKE_FOURCC ('x', 'd', 'v', 'c'): /* XDCAM EX 1080i50 50Mb/s CBR */
12965 case GST_MAKE_FOURCC ('x', 'd', 'v', 'd'): /* XDCAM HD 1080p24 50Mb/s CBR */
12966 case GST_MAKE_FOURCC ('x', 'd', 'v', 'e'): /* XDCAM HD 1080p25 50Mb/s CBR */
12967 case GST_MAKE_FOURCC ('x', 'd', 'v', 'f'): /* XDCAM HD 1080p30 50Mb/s CBR */
12968 case GST_MAKE_FOURCC ('x', 'd', '5', '1'): /* XDCAM HD422 720p30 50Mb/s CBR */
12969 case GST_MAKE_FOURCC ('x', 'd', '5', '4'): /* XDCAM HD422 720p24 50Mb/s CBR */
12970 case GST_MAKE_FOURCC ('x', 'd', '5', '5'): /* XDCAM HD422 720p25 50Mb/s CBR */
12971 case GST_MAKE_FOURCC ('x', 'd', '5', '9'): /* XDCAM HD422 720p60 50Mb/s CBR */
12972 case GST_MAKE_FOURCC ('x', 'd', '5', 'a'): /* XDCAM HD422 720p50 50Mb/s CBR */
12973 case GST_MAKE_FOURCC ('x', 'd', '5', 'b'): /* XDCAM HD422 1080i50 50Mb/s CBR */
12974 case GST_MAKE_FOURCC ('x', 'd', '5', 'c'): /* XDCAM HD422 1080i50 50Mb/s CBR */
12975 case GST_MAKE_FOURCC ('x', 'd', '5', 'd'): /* XDCAM HD422 1080p24 50Mb/s CBR */
12976 case GST_MAKE_FOURCC ('x', 'd', '5', 'e'): /* XDCAM HD422 1080p25 50Mb/s CBR */
12977 case GST_MAKE_FOURCC ('x', 'd', '5', 'f'): /* XDCAM HD422 1080p30 50Mb/s CBR */
12978 case GST_MAKE_FOURCC ('x', 'd', 'h', 'd'): /* XDCAM HD 540p */
12979 case GST_MAKE_FOURCC ('x', 'd', 'h', '2'): /* XDCAM HD422 540p */
12980 case GST_MAKE_FOURCC ('A', 'V', 'm', 'p'): /* AVID IMX PAL */
12981 case GST_MAKE_FOURCC ('m', 'p', 'g', '2'): /* AVID IMX PAL */
12982 case GST_MAKE_FOURCC ('m', 'p', '2', 'v'): /* AVID IMX PAL */
12983 _codec ("MPEG-2 video");
12984 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 2,
12985 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
12987 case GST_MAKE_FOURCC ('g', 'i', 'f', ' '):
12988 _codec ("GIF still images");
12989 caps = gst_caps_new_empty_simple ("image/gif");
12992 case GST_MAKE_FOURCC ('H', '2', '6', '3'):
12994 case GST_MAKE_FOURCC ('U', '2', '6', '3'):
12996 /* ffmpeg uses the height/width props, don't know why */
12997 caps = gst_caps_new_simple ("video/x-h263",
12998 "variant", G_TYPE_STRING, "itu", NULL);
13002 _codec ("MPEG-4 video");
13003 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
13004 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13006 case GST_MAKE_FOURCC ('3', 'i', 'v', 'd'):
13007 case GST_MAKE_FOURCC ('3', 'I', 'V', 'D'):
13008 _codec ("Microsoft MPEG-4 4.3"); /* FIXME? */
13009 caps = gst_caps_new_simple ("video/x-msmpeg",
13010 "msmpegversion", G_TYPE_INT, 43, NULL);
13012 case GST_MAKE_FOURCC ('D', 'I', 'V', '3'):
13014 caps = gst_caps_new_simple ("video/x-divx",
13015 "divxversion", G_TYPE_INT, 3, NULL);
13017 case GST_MAKE_FOURCC ('D', 'I', 'V', 'X'):
13018 case GST_MAKE_FOURCC ('d', 'i', 'v', 'x'):
13020 caps = gst_caps_new_simple ("video/x-divx",
13021 "divxversion", G_TYPE_INT, 4, NULL);
13023 case GST_MAKE_FOURCC ('D', 'X', '5', '0'):
13025 caps = gst_caps_new_simple ("video/x-divx",
13026 "divxversion", G_TYPE_INT, 5, NULL);
13029 case GST_MAKE_FOURCC ('F', 'F', 'V', '1'):
13031 caps = gst_caps_new_simple ("video/x-ffv",
13032 "ffvversion", G_TYPE_INT, 1, NULL);
13035 case GST_MAKE_FOURCC ('3', 'I', 'V', '1'):
13036 case GST_MAKE_FOURCC ('3', 'I', 'V', '2'):
13037 case GST_MAKE_FOURCC ('X', 'V', 'I', 'D'):
13038 case GST_MAKE_FOURCC ('x', 'v', 'i', 'd'):
13040 case GST_MAKE_FOURCC ('U', 'M', 'P', '4'):
13041 caps = gst_caps_new_simple ("video/mpeg",
13042 "mpegversion", G_TYPE_INT, 4, NULL);
13046 case GST_MAKE_FOURCC ('c', 'v', 'i', 'd'):
13047 _codec ("Cinepak");
13048 caps = gst_caps_new_empty_simple ("video/x-cinepak");
13050 case GST_MAKE_FOURCC ('q', 'd', 'r', 'w'):
13051 _codec ("Apple QuickDraw");
13052 caps = gst_caps_new_empty_simple ("video/x-qdrw");
13054 case GST_MAKE_FOURCC ('r', 'p', 'z', 'a'):
13055 _codec ("Apple video");
13056 caps = gst_caps_new_empty_simple ("video/x-apple-video");
13060 _codec ("H.264 / AVC");
13061 caps = gst_caps_new_simple ("video/x-h264",
13062 "stream-format", G_TYPE_STRING, "avc",
13063 "alignment", G_TYPE_STRING, "au", NULL);
13066 _codec ("H.264 / AVC");
13067 caps = gst_caps_new_simple ("video/x-h264",
13068 "stream-format", G_TYPE_STRING, "avc3",
13069 "alignment", G_TYPE_STRING, "au", NULL);
13073 _codec ("H.265 / HEVC");
13074 caps = gst_caps_new_simple ("video/x-h265",
13075 "stream-format", G_TYPE_STRING, "hvc1",
13076 "alignment", G_TYPE_STRING, "au", NULL);
13079 _codec ("H.265 / HEVC");
13080 caps = gst_caps_new_simple ("video/x-h265",
13081 "stream-format", G_TYPE_STRING, "hev1",
13082 "alignment", G_TYPE_STRING, "au", NULL);
13085 _codec ("Run-length encoding");
13086 caps = gst_caps_new_simple ("video/x-rle",
13087 "layout", G_TYPE_STRING, "quicktime", NULL);
13090 _codec ("Run-length encoding");
13091 caps = gst_caps_new_simple ("video/x-rle",
13092 "layout", G_TYPE_STRING, "microsoft", NULL);
13094 case GST_MAKE_FOURCC ('I', 'V', '3', '2'):
13095 case GST_MAKE_FOURCC ('i', 'v', '3', '2'):
13096 _codec ("Indeo Video 3");
13097 caps = gst_caps_new_simple ("video/x-indeo",
13098 "indeoversion", G_TYPE_INT, 3, NULL);
13100 case GST_MAKE_FOURCC ('I', 'V', '4', '1'):
13101 case GST_MAKE_FOURCC ('i', 'v', '4', '1'):
13102 _codec ("Intel Video 4");
13103 caps = gst_caps_new_simple ("video/x-indeo",
13104 "indeoversion", G_TYPE_INT, 4, NULL);
13108 case GST_MAKE_FOURCC ('d', 'v', 's', 'd'):
13109 case GST_MAKE_FOURCC ('D', 'V', 'S', 'D'):
13110 case GST_MAKE_FOURCC ('d', 'v', 'c', 's'):
13111 case GST_MAKE_FOURCC ('D', 'V', 'C', 'S'):
13112 case GST_MAKE_FOURCC ('d', 'v', '2', '5'):
13113 case GST_MAKE_FOURCC ('d', 'v', 'p', 'p'):
13114 _codec ("DV Video");
13115 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 25,
13116 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13118 case FOURCC_dv5n: /* DVCPRO50 NTSC */
13119 case FOURCC_dv5p: /* DVCPRO50 PAL */
13120 _codec ("DVCPro50 Video");
13121 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 50,
13122 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13124 case GST_MAKE_FOURCC ('d', 'v', 'h', '5'): /* DVCPRO HD 50i produced by FCP */
13125 case GST_MAKE_FOURCC ('d', 'v', 'h', '6'): /* DVCPRO HD 60i produced by FCP */
13126 _codec ("DVCProHD Video");
13127 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 100,
13128 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13130 case GST_MAKE_FOURCC ('s', 'm', 'c', ' '):
13131 _codec ("Apple Graphics (SMC)");
13132 caps = gst_caps_new_empty_simple ("video/x-smc");
13134 case GST_MAKE_FOURCC ('V', 'P', '3', '1'):
13136 caps = gst_caps_new_empty_simple ("video/x-vp3");
13138 case GST_MAKE_FOURCC ('V', 'P', '6', 'F'):
13139 _codec ("VP6 Flash");
13140 caps = gst_caps_new_empty_simple ("video/x-vp6-flash");
13144 caps = gst_caps_new_empty_simple ("video/x-theora");
13145 /* theora uses one byte of padding in the data stream because it does not
13146 * allow 0 sized packets while theora does */
13147 stream->padding = 1;
13151 caps = gst_caps_new_empty_simple ("video/x-dirac");
13153 case GST_MAKE_FOURCC ('t', 'i', 'f', 'f'):
13154 _codec ("TIFF still images");
13155 caps = gst_caps_new_empty_simple ("image/tiff");
13157 case GST_MAKE_FOURCC ('i', 'c', 'o', 'd'):
13158 _codec ("Apple Intermediate Codec");
13159 caps = gst_caps_from_string ("video/x-apple-intermediate-codec");
13161 case GST_MAKE_FOURCC ('A', 'V', 'd', 'n'):
13162 _codec ("AVID DNxHD");
13163 caps = gst_caps_from_string ("video/x-dnxhd");
13166 _codec ("On2 VP8");
13167 caps = gst_caps_from_string ("video/x-vp8");
13170 _codec ("Apple ProRes LT");
13172 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "lt",
13176 _codec ("Apple ProRes HQ");
13178 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "hq",
13182 _codec ("Apple ProRes");
13184 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
13188 _codec ("Apple ProRes Proxy");
13190 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
13194 _codec ("Apple ProRes 4444");
13196 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
13202 caps = gst_caps_new_simple ("video/x-wmv",
13203 "wmvversion", G_TYPE_INT, 3, "format", G_TYPE_STRING, "WVC1", NULL);
13205 case GST_MAKE_FOURCC ('k', 'p', 'c', 'd'):
13208 char *s, fourstr[5];
13210 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
13211 s = g_strdup_printf ("video/x-gst-fourcc-%s", g_strstrip (fourstr));
13212 caps = gst_caps_new_empty_simple (s);
13218 if (format != GST_VIDEO_FORMAT_UNKNOWN) {
13221 gst_video_info_init (&info);
13222 gst_video_info_set_format (&info, format, stream->width, stream->height);
13224 caps = gst_video_info_to_caps (&info);
13225 *codec_name = gst_pb_utils_get_codec_description (caps);
13227 /* enable clipping for raw video streams */
13228 stream->need_clip = TRUE;
13235 qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
13236 guint32 fourcc, const guint8 * data, int len, gchar ** codec_name)
13239 const GstStructure *s;
13242 GstAudioFormat format = 0;
13245 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
13247 depth = stream->bytes_per_packet * 8;
13250 case GST_MAKE_FOURCC ('N', 'O', 'N', 'E'):
13252 /* 8-bit audio is unsigned */
13254 format = GST_AUDIO_FORMAT_U8;
13255 /* otherwise it's signed and big-endian just like 'twos' */
13257 endian = G_BIG_ENDIAN;
13264 endian = G_LITTLE_ENDIAN;
13267 format = gst_audio_format_build_integer (TRUE, endian, depth, depth);
13269 str = g_strdup_printf ("Raw %d-bit PCM audio", depth);
13273 caps = gst_caps_new_simple ("audio/x-raw",
13274 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
13275 "layout", G_TYPE_STRING, "interleaved", NULL);
13278 case GST_MAKE_FOURCC ('f', 'l', '6', '4'):
13279 _codec ("Raw 64-bit floating-point audio");
13280 caps = gst_caps_new_simple ("audio/x-raw",
13281 "format", G_TYPE_STRING, "F64BE",
13282 "layout", G_TYPE_STRING, "interleaved", NULL);
13284 case GST_MAKE_FOURCC ('f', 'l', '3', '2'):
13285 _codec ("Raw 32-bit floating-point audio");
13286 caps = gst_caps_new_simple ("audio/x-raw",
13287 "format", G_TYPE_STRING, "F32BE",
13288 "layout", G_TYPE_STRING, "interleaved", NULL);
13291 _codec ("Raw 24-bit PCM audio");
13292 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
13294 caps = gst_caps_new_simple ("audio/x-raw",
13295 "format", G_TYPE_STRING, "S24BE",
13296 "layout", G_TYPE_STRING, "interleaved", NULL);
13298 case GST_MAKE_FOURCC ('i', 'n', '3', '2'):
13299 _codec ("Raw 32-bit PCM audio");
13300 caps = gst_caps_new_simple ("audio/x-raw",
13301 "format", G_TYPE_STRING, "S32BE",
13302 "layout", G_TYPE_STRING, "interleaved", NULL);
13305 _codec ("Mu-law audio");
13306 caps = gst_caps_new_empty_simple ("audio/x-mulaw");
13309 _codec ("A-law audio");
13310 caps = gst_caps_new_empty_simple ("audio/x-alaw");
13314 _codec ("Microsoft ADPCM");
13315 /* Microsoft ADPCM-ACM code 2 */
13316 caps = gst_caps_new_simple ("audio/x-adpcm",
13317 "layout", G_TYPE_STRING, "microsoft", NULL);
13321 _codec ("DVI/IMA ADPCM");
13322 caps = gst_caps_new_simple ("audio/x-adpcm",
13323 "layout", G_TYPE_STRING, "dvi", NULL);
13327 _codec ("DVI/Intel IMA ADPCM");
13328 /* FIXME DVI/Intel IMA ADPCM/ACM code 17 */
13329 caps = gst_caps_new_simple ("audio/x-adpcm",
13330 "layout", G_TYPE_STRING, "quicktime", NULL);
13334 /* MPEG layer 3, CBR only (pre QT4.1) */
13336 _codec ("MPEG-1 layer 3");
13337 /* MPEG layer 3, CBR & VBR (QT4.1 and later) */
13338 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 3,
13339 "mpegversion", G_TYPE_INT, 1, NULL);
13342 case GST_MAKE_FOURCC ('e', 'c', '-', '3'):
13343 _codec ("EAC-3 audio");
13344 caps = gst_caps_new_simple ("audio/x-eac3",
13345 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
13346 stream->sampled = TRUE;
13348 case GST_MAKE_FOURCC ('s', 'a', 'c', '3'): // Nero Recode
13350 _codec ("AC-3 audio");
13351 caps = gst_caps_new_simple ("audio/x-ac3",
13352 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
13353 stream->sampled = TRUE;
13355 case GST_MAKE_FOURCC ('d', 't', 's', 'c'):
13356 case GST_MAKE_FOURCC ('D', 'T', 'S', ' '):
13357 _codec ("DTS audio");
13358 caps = gst_caps_new_simple ("audio/x-dts",
13359 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
13360 stream->sampled = TRUE;
13362 case GST_MAKE_FOURCC ('d', 't', 's', 'h'): // DTS-HD
13363 case GST_MAKE_FOURCC ('d', 't', 's', 'l'): // DTS-HD Lossless
13364 _codec ("DTS-HD audio");
13365 caps = gst_caps_new_simple ("audio/x-dts",
13366 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
13367 stream->sampled = TRUE;
13371 caps = gst_caps_new_simple ("audio/x-mace",
13372 "maceversion", G_TYPE_INT, 3, NULL);
13376 caps = gst_caps_new_simple ("audio/x-mace",
13377 "maceversion", G_TYPE_INT, 6, NULL);
13379 case GST_MAKE_FOURCC ('O', 'g', 'g', 'V'):
13381 caps = gst_caps_new_empty_simple ("application/ogg");
13383 case GST_MAKE_FOURCC ('d', 'v', 'c', 'a'):
13384 _codec ("DV audio");
13385 caps = gst_caps_new_empty_simple ("audio/x-dv");
13388 _codec ("MPEG-4 AAC audio");
13389 caps = gst_caps_new_simple ("audio/mpeg",
13390 "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE,
13391 "stream-format", G_TYPE_STRING, "raw", NULL);
13393 case GST_MAKE_FOURCC ('Q', 'D', 'M', 'C'):
13394 _codec ("QDesign Music");
13395 caps = gst_caps_new_empty_simple ("audio/x-qdm");
13398 _codec ("QDesign Music v.2");
13399 /* FIXME: QDesign music version 2 (no constant) */
13400 if (FALSE && data) {
13401 caps = gst_caps_new_simple ("audio/x-qdm2",
13402 "framesize", G_TYPE_INT, QT_UINT32 (data + 52),
13403 "bitrate", G_TYPE_INT, QT_UINT32 (data + 40),
13404 "blocksize", G_TYPE_INT, QT_UINT32 (data + 44), NULL);
13406 caps = gst_caps_new_empty_simple ("audio/x-qdm2");
13410 _codec ("GSM audio");
13411 caps = gst_caps_new_empty_simple ("audio/x-gsm");
13414 _codec ("AMR audio");
13415 caps = gst_caps_new_empty_simple ("audio/AMR");
13418 _codec ("AMR-WB audio");
13419 caps = gst_caps_new_empty_simple ("audio/AMR-WB");
13422 _codec ("Quicktime IMA ADPCM");
13423 caps = gst_caps_new_simple ("audio/x-adpcm",
13424 "layout", G_TYPE_STRING, "quicktime", NULL);
13427 _codec ("Apple lossless audio");
13428 caps = gst_caps_new_empty_simple ("audio/x-alac");
13430 case GST_MAKE_FOURCC ('Q', 'c', 'l', 'p'):
13431 _codec ("QualComm PureVoice");
13432 caps = gst_caps_from_string ("audio/qcelp");
13437 caps = gst_caps_new_empty_simple ("audio/x-wma");
13441 caps = gst_caps_new_empty_simple ("audio/x-opus");
13443 case GST_MAKE_FOURCC ('l', 'p', 'c', 'm'):
13448 GstAudioFormat format;
13451 FLAG_IS_FLOAT = 0x1,
13452 FLAG_IS_BIG_ENDIAN = 0x2,
13453 FLAG_IS_SIGNED = 0x4,
13454 FLAG_IS_PACKED = 0x8,
13455 FLAG_IS_ALIGNED_HIGH = 0x10,
13456 FLAG_IS_NON_INTERLEAVED = 0x20
13458 _codec ("Raw LPCM audio");
13460 if (data && len >= 56) {
13461 depth = QT_UINT32 (data + 40);
13462 flags = QT_UINT32 (data + 44);
13463 width = QT_UINT32 (data + 48) * 8 / stream->n_channels;
13465 if ((flags & FLAG_IS_FLOAT) == 0) {
13470 format = gst_audio_format_build_integer ((flags & FLAG_IS_SIGNED) ?
13471 TRUE : FALSE, (flags & FLAG_IS_BIG_ENDIAN) ?
13472 G_BIG_ENDIAN : G_LITTLE_ENDIAN, width, depth);
13473 caps = gst_caps_new_simple ("audio/x-raw",
13474 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
13475 "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
13476 "non-interleaved" : "interleaved", NULL);
13481 if (flags & FLAG_IS_BIG_ENDIAN)
13482 format = GST_AUDIO_FORMAT_F64BE;
13484 format = GST_AUDIO_FORMAT_F64LE;
13486 if (flags & FLAG_IS_BIG_ENDIAN)
13487 format = GST_AUDIO_FORMAT_F32BE;
13489 format = GST_AUDIO_FORMAT_F32LE;
13491 caps = gst_caps_new_simple ("audio/x-raw",
13492 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
13493 "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
13494 "non-interleaved" : "interleaved", NULL);
13498 case GST_MAKE_FOURCC ('q', 't', 'v', 'r'):
13502 char *s, fourstr[5];
13504 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
13505 s = g_strdup_printf ("audio/x-gst-fourcc-%s", g_strstrip (fourstr));
13506 caps = gst_caps_new_empty_simple (s);
13513 GstCaps *templ_caps =
13514 gst_static_pad_template_get_caps (&gst_qtdemux_audiosrc_template);
13515 GstCaps *intersection = gst_caps_intersect (caps, templ_caps);
13516 gst_caps_unref (caps);
13517 gst_caps_unref (templ_caps);
13518 caps = intersection;
13521 /* enable clipping for raw audio streams */
13522 s = gst_caps_get_structure (caps, 0);
13523 name = gst_structure_get_name (s);
13524 if (g_str_has_prefix (name, "audio/x-raw")) {
13525 stream->need_clip = TRUE;
13526 stream->max_buffer_size = 4096 * stream->bytes_per_frame;
13527 GST_DEBUG ("setting max buffer size to %d", stream->max_buffer_size);
13533 qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
13534 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
13538 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
13542 _codec ("DVD subtitle");
13543 caps = gst_caps_new_empty_simple ("subpicture/x-dvd");
13544 stream->need_process = TRUE;
13547 _codec ("Quicktime timed text");
13550 _codec ("3GPP timed text");
13552 caps = gst_caps_new_simple ("text/x-raw", "format", G_TYPE_STRING,
13554 /* actual text piece needs to be extracted */
13555 stream->need_process = TRUE;
13558 _codec ("XML subtitles");
13559 caps = gst_caps_new_empty_simple ("application/ttml+xml");
13563 char *s, fourstr[5];
13565 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
13566 s = g_strdup_printf ("text/x-gst-fourcc-%s", g_strstrip (fourstr));
13567 caps = gst_caps_new_empty_simple (s);
13576 qtdemux_generic_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
13577 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
13583 _codec ("MPEG 1 video");
13584 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
13585 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13595 gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux,
13596 const gchar * system_id)
13600 if (!qtdemux->protection_system_ids)
13601 qtdemux->protection_system_ids =
13602 g_ptr_array_new_with_free_func ((GDestroyNotify) g_free);
13603 /* Check whether we already have an entry for this system ID. */
13604 for (i = 0; i < qtdemux->protection_system_ids->len; ++i) {
13605 const gchar *id = g_ptr_array_index (qtdemux->protection_system_ids, i);
13606 if (g_ascii_strcasecmp (system_id, id) == 0) {
13610 GST_DEBUG_OBJECT (qtdemux, "Adding cenc protection system ID %s", system_id);
13611 g_ptr_array_add (qtdemux->protection_system_ids, g_ascii_strdown (system_id,