2 * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
3 * Copyright (C) <2003> David A. Schleef <ds@schleef.org>
4 * Copyright (C) <2006> Wim Taymans <wim@fluendo.com>
5 * Copyright (C) <2007> Julien Moutte <julien@fluendo.com>
6 * Copyright (C) <2009> Tim-Philipp Müller <tim centricular net>
7 * Copyright (C) <2009> STEricsson <benjamin.gaignard@stericsson.com>
8 * Copyright (C) <2013> Sreerenj Balachandran <sreerenj.balachandran@intel.com>
9 * Copyright (C) <2013> Intel Corporation
10 * Copyright (C) <2014> Centricular Ltd
11 * Copyright (C) <2015> YouView TV Ltd.
13 * This library is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU Library General Public
15 * License as published by the Free Software Foundation; either
16 * version 2 of the License, or (at your option) any later version.
18 * This library is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * Library General Public License for more details.
23 * You should have received a copy of the GNU Library General Public
24 * License along with this library; if not, write to the
25 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
26 * Boston, MA 02110-1301, USA.
30 * SECTION:element-qtdemux
32 * Demuxes a .mov file into raw or compressed audio and/or video streams.
34 * This element supports both push and pull-based scheduling, depending on the
35 * capabilities of the upstream elements.
38 * <title>Example launch line</title>
40 * gst-launch-1.0 filesrc location=test.mov ! qtdemux name=demux demux.audio_0 ! queue ! decodebin ! audioconvert ! audioresample ! autoaudiosink demux.video_0 ! queue ! decodebin ! videoconvert ! videoscale ! autovideosink
41 * ]| Play (parse and decode) a .mov file and try to output it to
42 * an automatically detected soundcard and videosink. If the MOV file contains
43 * compressed audio or video data, this will only work if you have the
44 * right decoder elements/plugins installed.
52 #include "gst/gst-i18n-plugin.h"
54 #include <glib/gprintf.h>
55 #include <gst/tag/tag.h>
56 #include <gst/audio/audio.h>
57 #include <gst/video/video.h>
59 #include "qtatomparser.h"
60 #include "qtdemux_types.h"
61 #include "qtdemux_dump.h"
63 #include "descriptors.h"
64 #include "qtdemux_lang.h"
66 #include "qtpalette.h"
68 #include "gst/riff/riff-media.h"
69 #include "gst/riff/riff-read.h"
71 #include <gst/pbutils/pbutils.h>
78 #include <gst/math-compat.h>
84 /* max. size considered 'sane' for non-mdat atoms */
85 #define QTDEMUX_MAX_ATOM_SIZE (25*1024*1024)
87 /* if the sample index is larger than this, something is likely wrong */
88 #define QTDEMUX_MAX_SAMPLE_INDEX_SIZE (50*1024*1024)
90 /* For converting qt creation times to unix epoch times */
91 #define QTDEMUX_SECONDS_PER_DAY (60 * 60 * 24)
92 #define QTDEMUX_LEAP_YEARS_FROM_1904_TO_1970 17
93 #define QTDEMUX_SECONDS_FROM_1904_TO_1970 (((1970 - 1904) * (guint64) 365 + \
94 QTDEMUX_LEAP_YEARS_FROM_1904_TO_1970) * QTDEMUX_SECONDS_PER_DAY)
96 #define STREAM_IS_EOS(s) (s->time_position == GST_CLOCK_TIME_NONE)
98 GST_DEBUG_CATEGORY (qtdemux_debug);
100 typedef struct _QtDemuxSegment QtDemuxSegment;
101 typedef struct _QtDemuxSample QtDemuxSample;
103 typedef struct _QtDemuxCencSampleSetInfo QtDemuxCencSampleSetInfo;
105 struct _QtDemuxSample
108 gint32 pts_offset; /* Add this value to timestamp to get the pts */
110 guint64 timestamp; /* DTS In mov time */
111 guint32 duration; /* In mov time */
112 gboolean keyframe; /* TRUE when this packet is a keyframe */
115 /* Macros for converting to/from timescale */
116 #define QTSTREAMTIME_TO_GSTTIME(stream, value) (gst_util_uint64_scale((value), GST_SECOND, (stream)->timescale))
117 #define GSTTIME_TO_QTSTREAMTIME(stream, value) (gst_util_uint64_scale((value), (stream)->timescale, GST_SECOND))
119 #define QTTIME_TO_GSTTIME(qtdemux, value) (gst_util_uint64_scale((value), GST_SECOND, (qtdemux)->timescale))
120 #define GSTTIME_TO_QTTIME(qtdemux, value) (gst_util_uint64_scale((value), (qtdemux)->timescale, GST_SECOND))
122 /* timestamp is the DTS */
123 #define QTSAMPLE_DTS(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp))
124 /* timestamp + offset is the PTS */
125 #define QTSAMPLE_PTS(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp + (stream)->cslg_shift + (sample)->pts_offset))
126 /* timestamp + duration - dts is the duration */
127 #define QTSAMPLE_DUR_DTS(stream, sample, dts) (QTSTREAMTIME_TO_GSTTIME ((stream), (sample)->timestamp + (sample)->duration) - (dts))
129 #define QTSAMPLE_KEYFRAME(stream,sample) ((stream)->all_keyframe || (sample)->keyframe)
132 * Quicktime has tracks and segments. A track is a continuous piece of
133 * multimedia content. The track is not always played from start to finish but
134 * instead, pieces of the track are 'cut out' and played in sequence. This is
135 * what the segments do.
137 * Inside the track we have keyframes (K) and delta frames. The track has its
138 * own timing, which starts from 0 and extends to end. The position in the track
139 * is called the media_time.
141 * The segments now describe the pieces that should be played from this track
142 * and are basically tuples of media_time/duration/rate entries. We can have
143 * multiple segments and they are all played after one another. An example:
145 * segment 1: media_time: 1 second, duration: 1 second, rate 1
146 * segment 2: media_time: 3 second, duration: 2 second, rate 2
148 * To correctly play back this track, one must play: 1 second of media starting
149 * from media_time 1 followed by 2 seconds of media starting from media_time 3
152 * Each of the segments will be played at a specific time, the first segment at
153 * time 0, the second one after the duration of the first one, etc.. Note that
154 * the time in resulting playback is not identical to the media_time of the
157 * Visually, assuming the track has 4 second of media_time:
160 * .-----------------------------------------------------------.
161 * track: | K.....K.........K........K.......K.......K...........K... |
162 * '-----------------------------------------------------------'
164 * .------------^ ^ .----------^ ^
165 * / .-------------' / .------------------'
167 * .--------------. .--------------.
168 * | segment 1 | | segment 2 |
169 * '--------------' '--------------'
171 * The challenge here is to cut out the right pieces of the track for each of
172 * the playback segments. This fortunately can easily be done with the SEGMENT
173 * events of GStreamer.
175 * For playback of segment 1, we need to provide the decoder with the keyframe
176 * (a), in the above figure, but we must instruct it only to output the decoded
177 * data between second 1 and 2. We do this with a SEGMENT event for 1 to 2, time
178 * position set to the time of the segment: 0.
180 * We then proceed to push data from keyframe (a) to frame (b). The decoder
181 * decodes but clips all before media_time 1.
183 * After finishing a segment, we push out a new SEGMENT event with the clipping
184 * boundaries of the new data.
186 * This is a good usecase for the GStreamer accumulated SEGMENT events.
189 struct _QtDemuxSegment
191 /* global time and duration, all gst time */
193 GstClockTime stop_time;
194 GstClockTime duration;
195 /* media time of trak, all gst time */
196 GstClockTime media_start;
197 GstClockTime media_stop;
199 /* Media start time in trak timescale units */
200 guint32 trak_media_start;
203 #define QTSEGMENT_IS_EMPTY(s) ((s)->media_start == GST_CLOCK_TIME_NONE)
205 /* Used with fragmented MP4 files (mfra atom) */
210 } QtDemuxRandomAccessEntry;
212 struct _QtDemuxStream
222 gboolean new_caps; /* If TRUE, caps need to be generated (by
223 * calling _configure_stream()) This happens
224 * for MSS and fragmented streams */
226 gboolean new_stream; /* signals that a stream_start is required */
227 gboolean on_keyframe; /* if this stream last pushed buffer was a
228 * keyframe. This is important to identify
229 * where to stop pushing buffers after a
230 * segment stop time */
232 /* if the stream has a redirect URI in its headers, we store it here */
239 guint64 duration; /* in timescale units */
243 gchar lang_id[4]; /* ISO 639-2T language code */
247 QtDemuxSample *samples;
248 gboolean all_keyframe; /* TRUE when all samples are keyframes (no stss) */
249 guint32 first_duration; /* duration in timescale of first sample, used for figuring out
251 guint32 n_samples_moof; /* sample count in a moof */
252 guint64 duration_moof; /* duration in timescale of a moof, used for figure out
253 * the framerate of fragmented format stream */
255 guint32 offset_in_sample; /* Offset in the current sample, used for
256 * streams which have got exceedingly big
257 * sample size (such as 24s of raw audio).
258 * Only used when max_buffer_size is non-NULL */
259 guint32 max_buffer_size; /* Maximum allowed size for output buffers.
260 * Currently only set for raw audio streams*/
262 /* if we use chunks or samples */
274 /* Numerator/denominator framerate */
277 guint16 bits_per_sample;
278 guint16 color_table_id;
279 GstMemory *rgb8_palette;
284 guint samples_per_packet;
285 guint samples_per_frame;
286 guint bytes_per_packet;
287 guint bytes_per_sample;
288 guint bytes_per_frame;
292 gboolean use_allocator;
293 GstAllocator *allocator;
294 GstAllocationParams params;
296 /* when a discontinuity is pending */
299 /* list of buffers to push first */
302 /* if we need to clip this buffer. This is only needed for uncompressed
306 /* buffer needs some custom processing, e.g. subtitles */
307 gboolean need_process;
309 /* current position */
310 guint32 segment_index;
311 guint32 sample_index;
312 GstClockTime time_position; /* in gst time */
313 guint64 accumulated_base;
315 /* the Gst segment we are processing out, used for clipping */
318 /* quicktime segments */
320 QtDemuxSegment *segments;
321 gboolean dummy_segment;
326 GstTagList *pending_tags;
327 gboolean send_global_tags;
329 GstEvent *pending_event;
339 gboolean chunks_are_samples; /* TRUE means treat chunks as samples */
343 GstByteReader co_chunk;
345 guint32 current_chunk;
347 guint32 samples_per_chunk;
348 guint32 stco_sample_index;
350 guint32 sample_size; /* 0 means variable sizes are stored in stsz */
353 guint32 n_samples_per_chunk;
354 guint32 stsc_chunk_index;
355 guint32 stsc_sample_index;
356 guint64 chunk_offset;
359 guint32 stts_samples;
360 guint32 n_sample_times;
361 guint32 stts_sample_index;
363 guint32 stts_duration;
365 gboolean stss_present;
366 guint32 n_sample_syncs;
369 gboolean stps_present;
370 guint32 n_sample_partial_syncs;
372 QtDemuxRandomAccessEntry *ra_entries;
375 const QtDemuxRandomAccessEntry *pending_seek;
378 gboolean ctts_present;
379 guint32 n_composition_times;
381 guint32 ctts_sample_index;
389 gboolean parsed_trex;
390 guint32 def_sample_duration;
391 guint32 def_sample_size;
392 guint32 def_sample_flags;
396 /* stereoscopic video streams */
397 GstVideoMultiviewMode multiview_mode;
398 GstVideoMultiviewFlags multiview_flags;
400 /* protected streams */
402 guint32 protection_scheme_type;
403 guint32 protection_scheme_version;
404 gpointer protection_scheme_info; /* specific to the protection scheme */
405 GQueue protection_scheme_event_queue;
408 /* Contains properties and cryptographic info for a set of samples from a
409 * track protected using Common Encryption (cenc) */
410 struct _QtDemuxCencSampleSetInfo
412 GstStructure *default_properties;
414 /* @crypto_info holds one GstStructure per sample */
415 GPtrArray *crypto_info;
419 qt_demux_state_string (enum QtDemuxState state)
422 case QTDEMUX_STATE_INITIAL:
424 case QTDEMUX_STATE_HEADER:
426 case QTDEMUX_STATE_MOVIE:
428 case QTDEMUX_STATE_BUFFER_MDAT:
429 return "<BUFFER_MDAT>";
435 static GNode *qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc);
436 static GNode *qtdemux_tree_get_child_by_type_full (GNode * node,
437 guint32 fourcc, GstByteReader * parser);
438 static GNode *qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc);
439 static GNode *qtdemux_tree_get_sibling_by_type_full (GNode * node,
440 guint32 fourcc, GstByteReader * parser);
442 static GstFlowReturn qtdemux_add_fragmented_samples (GstQTDemux * qtdemux);
444 static GstStaticPadTemplate gst_qtdemux_sink_template =
445 GST_STATIC_PAD_TEMPLATE ("sink",
448 GST_STATIC_CAPS ("video/quicktime; video/mj2; audio/x-m4a; "
452 static GstStaticPadTemplate gst_qtdemux_videosrc_template =
453 GST_STATIC_PAD_TEMPLATE ("video_%u",
456 GST_STATIC_CAPS_ANY);
458 static GstStaticPadTemplate gst_qtdemux_audiosrc_template =
459 GST_STATIC_PAD_TEMPLATE ("audio_%u",
462 GST_STATIC_CAPS_ANY);
464 static GstStaticPadTemplate gst_qtdemux_subsrc_template =
465 GST_STATIC_PAD_TEMPLATE ("subtitle_%u",
468 GST_STATIC_CAPS_ANY);
470 #define gst_qtdemux_parent_class parent_class
471 G_DEFINE_TYPE (GstQTDemux, gst_qtdemux, GST_TYPE_ELEMENT);
473 static void gst_qtdemux_dispose (GObject * object);
476 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
477 GstClockTime media_time);
479 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
480 QtDemuxStream * str, gint64 media_offset);
483 static void gst_qtdemux_set_index (GstElement * element, GstIndex * index);
484 static GstIndex *gst_qtdemux_get_index (GstElement * element);
486 static GstStateChangeReturn gst_qtdemux_change_state (GstElement * element,
487 GstStateChange transition);
488 static gboolean qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent);
489 static gboolean qtdemux_sink_activate_mode (GstPad * sinkpad,
490 GstObject * parent, GstPadMode mode, gboolean active);
492 static void gst_qtdemux_loop (GstPad * pad);
493 static GstFlowReturn gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent,
495 static gboolean gst_qtdemux_handle_sink_event (GstPad * pad, GstObject * parent,
497 static gboolean gst_qtdemux_setcaps (GstQTDemux * qtdemux, GstCaps * caps);
498 static gboolean gst_qtdemux_configure_stream (GstQTDemux * qtdemux,
499 QtDemuxStream * stream);
500 static GstFlowReturn gst_qtdemux_process_adapter (GstQTDemux * demux,
503 static gboolean qtdemux_parse_moov (GstQTDemux * qtdemux,
504 const guint8 * buffer, guint length);
505 static gboolean qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node,
506 const guint8 * buffer, guint length);
507 static gboolean qtdemux_parse_tree (GstQTDemux * qtdemux);
508 static void qtdemux_parse_udta (GstQTDemux * qtdemux, GstTagList * taglist,
511 static void gst_qtdemux_handle_esds (GstQTDemux * qtdemux,
512 QtDemuxStream * stream, GNode * esds, GstTagList * list);
513 static GstCaps *qtdemux_video_caps (GstQTDemux * qtdemux,
514 QtDemuxStream * stream, guint32 fourcc, const guint8 * stsd_data,
515 gchar ** codec_name);
516 static GstCaps *qtdemux_audio_caps (GstQTDemux * qtdemux,
517 QtDemuxStream * stream, guint32 fourcc, const guint8 * data, int len,
518 gchar ** codec_name);
519 static GstCaps *qtdemux_sub_caps (GstQTDemux * qtdemux,
520 QtDemuxStream * stream, guint32 fourcc, const guint8 * data,
521 gchar ** codec_name);
522 static GstCaps *qtdemux_generic_caps (GstQTDemux * qtdemux,
523 QtDemuxStream * stream, guint32 fourcc, const guint8 * stsd_data,
524 gchar ** codec_name);
526 static gboolean qtdemux_parse_samples (GstQTDemux * qtdemux,
527 QtDemuxStream * stream, guint32 n);
528 static GstFlowReturn qtdemux_expose_streams (GstQTDemux * qtdemux);
529 static void gst_qtdemux_stream_free (GstQTDemux * qtdemux,
530 QtDemuxStream * stream);
531 static void gst_qtdemux_stream_clear (GstQTDemux * qtdemux,
532 QtDemuxStream * stream);
533 static void gst_qtdemux_remove_stream (GstQTDemux * qtdemux, int index);
534 static GstFlowReturn qtdemux_prepare_streams (GstQTDemux * qtdemux);
535 static void qtdemux_do_allocation (GstQTDemux * qtdemux,
536 QtDemuxStream * stream);
537 static gboolean gst_qtdemux_activate_segment (GstQTDemux * qtdemux,
538 QtDemuxStream * stream, guint32 seg_idx, GstClockTime offset);
539 static gboolean gst_qtdemux_stream_update_segment (GstQTDemux * qtdemux,
540 QtDemuxStream * stream, gint seg_idx, GstClockTime offset,
541 GstClockTime * _start, GstClockTime * _stop);
542 static void gst_qtdemux_send_gap_for_segment (GstQTDemux * demux,
543 QtDemuxStream * stream, gint segment_index, GstClockTime pos);
545 static gboolean qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux);
546 static void check_update_duration (GstQTDemux * qtdemux, GstClockTime duration);
548 static gchar *qtdemux_uuid_bytes_to_string (gconstpointer uuid_bytes);
550 static GstStructure *qtdemux_get_cenc_sample_properties (GstQTDemux * qtdemux,
551 QtDemuxStream * stream, guint sample_index);
552 static void gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux,
554 static void qtdemux_gst_structure_free (GstStructure * gststructure);
557 gst_qtdemux_class_init (GstQTDemuxClass * klass)
559 GObjectClass *gobject_class;
560 GstElementClass *gstelement_class;
562 gobject_class = (GObjectClass *) klass;
563 gstelement_class = (GstElementClass *) klass;
565 parent_class = g_type_class_peek_parent (klass);
567 gobject_class->dispose = gst_qtdemux_dispose;
569 gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_qtdemux_change_state);
571 gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_qtdemux_set_index);
572 gstelement_class->get_index = GST_DEBUG_FUNCPTR (gst_qtdemux_get_index);
575 gst_tag_register_musicbrainz_tags ();
577 gst_element_class_add_static_pad_template (gstelement_class,
578 &gst_qtdemux_sink_template);
579 gst_element_class_add_static_pad_template (gstelement_class,
580 &gst_qtdemux_videosrc_template);
581 gst_element_class_add_static_pad_template (gstelement_class,
582 &gst_qtdemux_audiosrc_template);
583 gst_element_class_add_static_pad_template (gstelement_class,
584 &gst_qtdemux_subsrc_template);
585 gst_element_class_set_static_metadata (gstelement_class, "QuickTime demuxer",
587 "Demultiplex a QuickTime file into audio and video streams",
588 "David Schleef <ds@schleef.org>, Wim Taymans <wim@fluendo.com>");
590 GST_DEBUG_CATEGORY_INIT (qtdemux_debug, "qtdemux", 0, "qtdemux plugin");
595 gst_qtdemux_init (GstQTDemux * qtdemux)
598 gst_pad_new_from_static_template (&gst_qtdemux_sink_template, "sink");
599 gst_pad_set_activate_function (qtdemux->sinkpad, qtdemux_sink_activate);
600 gst_pad_set_activatemode_function (qtdemux->sinkpad,
601 qtdemux_sink_activate_mode);
602 gst_pad_set_chain_function (qtdemux->sinkpad, gst_qtdemux_chain);
603 gst_pad_set_event_function (qtdemux->sinkpad, gst_qtdemux_handle_sink_event);
604 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), qtdemux->sinkpad);
606 qtdemux->state = QTDEMUX_STATE_INITIAL;
607 qtdemux->pullbased = FALSE;
608 qtdemux->posted_redirect = FALSE;
609 qtdemux->neededbytes = 16;
611 qtdemux->adapter = gst_adapter_new ();
613 qtdemux->first_mdat = -1;
614 qtdemux->got_moov = FALSE;
615 qtdemux->mdatoffset = -1;
616 qtdemux->mdatbuffer = NULL;
617 qtdemux->restoredata_buffer = NULL;
618 qtdemux->restoredata_offset = -1;
619 qtdemux->fragment_start = -1;
620 qtdemux->fragment_start_offset = -1;
621 qtdemux->media_caps = NULL;
622 qtdemux->exposed = FALSE;
623 qtdemux->mss_mode = FALSE;
624 qtdemux->pending_newsegment = NULL;
625 qtdemux->upstream_format_is_time = FALSE;
626 qtdemux->have_group_id = FALSE;
627 qtdemux->group_id = G_MAXUINT;
628 qtdemux->cenc_aux_info_offset = 0;
629 qtdemux->cenc_aux_info_sizes = NULL;
630 qtdemux->cenc_aux_sample_count = 0;
631 qtdemux->protection_system_ids = NULL;
632 g_queue_init (&qtdemux->protection_event_queue);
633 gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
634 qtdemux->flowcombiner = gst_flow_combiner_new ();
636 GST_OBJECT_FLAG_SET (qtdemux, GST_ELEMENT_FLAG_INDEXABLE);
640 gst_qtdemux_dispose (GObject * object)
642 GstQTDemux *qtdemux = GST_QTDEMUX (object);
644 if (qtdemux->adapter) {
645 g_object_unref (G_OBJECT (qtdemux->adapter));
646 qtdemux->adapter = NULL;
648 gst_flow_combiner_free (qtdemux->flowcombiner);
649 g_queue_foreach (&qtdemux->protection_event_queue, (GFunc) gst_event_unref,
651 g_queue_clear (&qtdemux->protection_event_queue);
653 g_free (qtdemux->cenc_aux_info_sizes);
654 qtdemux->cenc_aux_info_sizes = NULL;
656 G_OBJECT_CLASS (parent_class)->dispose (object);
660 gst_qtdemux_post_no_playable_stream_error (GstQTDemux * qtdemux)
662 if (qtdemux->posted_redirect) {
663 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
664 (_("This file contains no playable streams.")),
665 ("no known streams found, a redirect message has been posted"));
667 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
668 (_("This file contains no playable streams.")),
669 ("no known streams found"));
674 _gst_buffer_new_wrapped (gpointer mem, gsize size, GFreeFunc free_func)
676 return gst_buffer_new_wrapped_full (free_func ? 0 : GST_MEMORY_FLAG_READONLY,
677 mem, size, 0, size, mem, free_func);
681 gst_qtdemux_pull_atom (GstQTDemux * qtdemux, guint64 offset, guint64 size,
688 if (G_UNLIKELY (size == 0)) {
690 GstBuffer *tmp = NULL;
692 ret = gst_qtdemux_pull_atom (qtdemux, offset, sizeof (guint32), &tmp);
693 if (ret != GST_FLOW_OK)
696 gst_buffer_map (tmp, &map, GST_MAP_READ);
697 size = QT_UINT32 (map.data);
698 GST_DEBUG_OBJECT (qtdemux, "size 0x%08" G_GINT64_MODIFIER "x", size);
700 gst_buffer_unmap (tmp, &map);
701 gst_buffer_unref (tmp);
704 /* Sanity check: catch bogus sizes (fuzzed/broken files) */
705 if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
706 if (qtdemux->state != QTDEMUX_STATE_MOVIE && qtdemux->got_moov) {
707 /* we're pulling header but already got most interesting bits,
708 * so never mind the rest (e.g. tags) (that much) */
709 GST_WARNING_OBJECT (qtdemux, "atom has bogus size %" G_GUINT64_FORMAT,
713 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
714 (_("This file is invalid and cannot be played.")),
715 ("atom has bogus size %" G_GUINT64_FORMAT, size));
716 return GST_FLOW_ERROR;
720 flow = gst_pad_pull_range (qtdemux->sinkpad, offset, size, buf);
722 if (G_UNLIKELY (flow != GST_FLOW_OK))
725 bsize = gst_buffer_get_size (*buf);
726 /* Catch short reads - we don't want any partial atoms */
727 if (G_UNLIKELY (bsize < size)) {
728 GST_WARNING_OBJECT (qtdemux,
729 "short read: %" G_GSIZE_FORMAT " < %" G_GUINT64_FORMAT, bsize, size);
730 gst_buffer_unref (*buf);
740 gst_qtdemux_src_convert (GstQTDemux * qtdemux, GstPad * pad,
741 GstFormat src_format, gint64 src_value, GstFormat dest_format,
745 QtDemuxStream *stream = gst_pad_get_element_private (pad);
748 if (stream->subtype != FOURCC_vide) {
753 switch (src_format) {
754 case GST_FORMAT_TIME:
755 switch (dest_format) {
756 case GST_FORMAT_BYTES:{
757 index = gst_qtdemux_find_index_linear (qtdemux, stream, src_value);
763 *dest_value = stream->samples[index].offset;
765 GST_DEBUG_OBJECT (qtdemux, "Format Conversion Time->Offset :%"
766 GST_TIME_FORMAT "->%" G_GUINT64_FORMAT,
767 GST_TIME_ARGS (src_value), *dest_value);
775 case GST_FORMAT_BYTES:
776 switch (dest_format) {
777 case GST_FORMAT_TIME:{
779 gst_qtdemux_find_index_for_given_media_offset_linear (qtdemux,
788 QTSTREAMTIME_TO_GSTTIME (stream,
789 stream->samples[index].timestamp);
790 GST_DEBUG_OBJECT (qtdemux,
791 "Format Conversion Offset->Time :%" G_GUINT64_FORMAT "->%"
792 GST_TIME_FORMAT, src_value, GST_TIME_ARGS (*dest_value));
811 gst_qtdemux_get_duration (GstQTDemux * qtdemux, GstClockTime * duration)
813 gboolean res = FALSE;
815 *duration = GST_CLOCK_TIME_NONE;
817 if (qtdemux->duration != 0 &&
818 qtdemux->duration != G_MAXINT64 && qtdemux->timescale != 0) {
819 *duration = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
822 *duration = GST_CLOCK_TIME_NONE;
829 gst_qtdemux_handle_src_query (GstPad * pad, GstObject * parent,
832 gboolean res = FALSE;
833 GstQTDemux *qtdemux = GST_QTDEMUX (parent);
835 GST_LOG_OBJECT (pad, "%s query", GST_QUERY_TYPE_NAME (query));
837 switch (GST_QUERY_TYPE (query)) {
838 case GST_QUERY_POSITION:{
841 gst_query_parse_position (query, &fmt, NULL);
842 if (fmt == GST_FORMAT_TIME
843 && GST_CLOCK_TIME_IS_VALID (qtdemux->segment.position)) {
844 gst_query_set_position (query, GST_FORMAT_TIME,
845 qtdemux->segment.position);
850 case GST_QUERY_DURATION:{
853 gst_query_parse_duration (query, &fmt, NULL);
854 if (fmt == GST_FORMAT_TIME) {
855 /* First try to query upstream */
856 res = gst_pad_query_default (pad, parent, query);
858 GstClockTime duration;
859 if (gst_qtdemux_get_duration (qtdemux, &duration) && duration > 0) {
860 gst_query_set_duration (query, GST_FORMAT_TIME, duration);
867 case GST_QUERY_CONVERT:{
868 GstFormat src_fmt, dest_fmt;
869 gint64 src_value, dest_value = 0;
871 gst_query_parse_convert (query, &src_fmt, &src_value, &dest_fmt, NULL);
873 res = gst_qtdemux_src_convert (qtdemux, pad,
874 src_fmt, src_value, dest_fmt, &dest_value);
876 gst_query_set_convert (query, src_fmt, src_value, dest_fmt, dest_value);
881 case GST_QUERY_FORMATS:
882 gst_query_set_formats (query, 2, GST_FORMAT_TIME, GST_FORMAT_BYTES);
885 case GST_QUERY_SEEKING:{
889 /* try upstream first */
890 res = gst_pad_query_default (pad, parent, query);
893 gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
894 if (fmt == GST_FORMAT_TIME) {
895 GstClockTime duration;
897 gst_qtdemux_get_duration (qtdemux, &duration);
899 if (!qtdemux->pullbased) {
902 /* we might be able with help from upstream */
904 q = gst_query_new_seeking (GST_FORMAT_BYTES);
905 if (gst_pad_peer_query (qtdemux->sinkpad, q)) {
906 gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL);
907 GST_LOG_OBJECT (qtdemux, "upstream BYTE seekable %d", seekable);
911 gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0, duration);
917 case GST_QUERY_SEGMENT:
922 format = qtdemux->segment.format;
925 gst_segment_to_stream_time (&qtdemux->segment, format,
926 qtdemux->segment.start);
927 if ((stop = qtdemux->segment.stop) == -1)
928 stop = qtdemux->segment.duration;
930 stop = gst_segment_to_stream_time (&qtdemux->segment, format, stop);
932 gst_query_set_segment (query, qtdemux->segment.rate, format, start, stop);
937 res = gst_pad_query_default (pad, parent, query);
945 gst_qtdemux_push_tags (GstQTDemux * qtdemux, QtDemuxStream * stream)
947 if (G_LIKELY (stream->pad)) {
948 GST_DEBUG_OBJECT (qtdemux, "Checking pad %s:%s for tags",
949 GST_DEBUG_PAD_NAME (stream->pad));
951 if (G_UNLIKELY (stream->pending_tags)) {
952 GST_DEBUG_OBJECT (qtdemux, "Sending tags %" GST_PTR_FORMAT,
953 stream->pending_tags);
954 gst_pad_push_event (stream->pad,
955 gst_event_new_tag (stream->pending_tags));
956 stream->pending_tags = NULL;
959 if (G_UNLIKELY (stream->send_global_tags && qtdemux->tag_list)) {
960 GST_DEBUG_OBJECT (qtdemux, "Sending global tags %" GST_PTR_FORMAT,
962 gst_pad_push_event (stream->pad,
963 gst_event_new_tag (gst_tag_list_ref (qtdemux->tag_list)));
964 stream->send_global_tags = FALSE;
969 /* push event on all source pads; takes ownership of the event */
971 gst_qtdemux_push_event (GstQTDemux * qtdemux, GstEvent * event)
974 gboolean has_valid_stream = FALSE;
975 GstEventType etype = GST_EVENT_TYPE (event);
977 GST_DEBUG_OBJECT (qtdemux, "pushing %s event on all source pads",
978 GST_EVENT_TYPE_NAME (event));
980 for (n = 0; n < qtdemux->n_streams; n++) {
982 QtDemuxStream *stream = qtdemux->streams[n];
983 GST_DEBUG_OBJECT (qtdemux, "pushing on pad %i", n);
985 if ((pad = stream->pad)) {
986 has_valid_stream = TRUE;
988 if (etype == GST_EVENT_EOS) {
989 /* let's not send twice */
990 if (stream->sent_eos)
992 stream->sent_eos = TRUE;
995 gst_pad_push_event (pad, gst_event_ref (event));
999 gst_event_unref (event);
1001 /* if it is EOS and there are no pads, post an error */
1002 if (!has_valid_stream && etype == GST_EVENT_EOS) {
1003 gst_qtdemux_post_no_playable_stream_error (qtdemux);
1007 /* push a pending newsegment event, if any from the streaming thread */
1009 gst_qtdemux_push_pending_newsegment (GstQTDemux * qtdemux)
1011 if (qtdemux->pending_newsegment) {
1012 gst_qtdemux_push_event (qtdemux, qtdemux->pending_newsegment);
1013 qtdemux->pending_newsegment = NULL;
1023 find_func (QtDemuxSample * s1, gint64 * media_time, gpointer user_data)
1025 if ((gint64) s1->timestamp + s1->pts_offset > *media_time)
1027 if ((gint64) s1->timestamp + s1->pts_offset == *media_time)
1033 /* find the index of the sample that includes the data for @media_time using a
1034 * binary search. Only to be called in optimized cases of linear search below.
1036 * Returns the index of the sample.
1039 gst_qtdemux_find_index (GstQTDemux * qtdemux, QtDemuxStream * str,
1042 QtDemuxSample *result;
1045 /* convert media_time to mov format */
1047 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
1049 result = gst_util_array_binary_search (str->samples, str->stbl_index + 1,
1050 sizeof (QtDemuxSample), (GCompareDataFunc) find_func,
1051 GST_SEARCH_MODE_BEFORE, &media_time, NULL);
1053 if (G_LIKELY (result))
1054 index = result - str->samples;
1063 /* find the index of the sample that includes the data for @media_offset using a
1066 * Returns the index of the sample.
1069 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
1070 QtDemuxStream * str, gint64 media_offset)
1072 QtDemuxSample *result = str->samples;
1075 if (result == NULL || str->n_samples == 0)
1078 if (media_offset == result->offset)
1082 while (index < str->n_samples - 1) {
1083 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
1086 if (media_offset < result->offset)
1097 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
1102 /* find the index of the sample that includes the data for @media_time using a
1103 * linear search, and keeping in mind that not all samples may have been parsed
1104 * yet. If possible, it will delegate to binary search.
1106 * Returns the index of the sample.
1109 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
1110 GstClockTime media_time)
1114 QtDemuxSample *sample;
1116 /* convert media_time to mov format */
1118 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
1120 sample = str->samples;
1121 if (mov_time == sample->timestamp + sample->pts_offset)
1124 /* use faster search if requested time in already parsed range */
1125 sample = str->samples + str->stbl_index;
1126 if (str->stbl_index >= 0 &&
1127 mov_time <= (sample->timestamp + sample->pts_offset))
1128 return gst_qtdemux_find_index (qtdemux, str, media_time);
1130 while (index < str->n_samples - 1) {
1131 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
1134 sample = str->samples + index + 1;
1135 if (mov_time < (sample->timestamp + sample->pts_offset))
1145 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
1150 /* find the index of the keyframe needed to decode the sample at @index
1153 * Returns the index of the keyframe.
1156 gst_qtdemux_find_keyframe (GstQTDemux * qtdemux, QtDemuxStream * str,
1159 guint32 new_index = index;
1161 if (index >= str->n_samples) {
1162 new_index = str->n_samples;
1166 /* all keyframes, return index */
1167 if (str->all_keyframe) {
1172 /* else go back until we have a keyframe */
1174 if (str->samples[new_index].keyframe)
1184 GST_DEBUG_OBJECT (qtdemux, "searching for keyframe index before index %u "
1185 "gave %u", index, new_index);
1190 /* find the segment for @time_position for @stream
1192 * Returns the index of the segment containing @time_position.
1193 * Returns the last segment and sets the @eos variable to TRUE
1194 * if the time is beyond the end. @eos may be NULL
1197 gst_qtdemux_find_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
1198 GstClockTime time_position)
1203 GST_LOG_OBJECT (stream->pad, "finding segment for %" GST_TIME_FORMAT,
1204 GST_TIME_ARGS (time_position));
1207 for (i = 0; i < stream->n_segments; i++) {
1208 QtDemuxSegment *segment = &stream->segments[i];
1210 GST_LOG_OBJECT (stream->pad,
1211 "looking at segment %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT,
1212 GST_TIME_ARGS (segment->time), GST_TIME_ARGS (segment->stop_time));
1214 /* For the last segment we include stop_time in the last segment */
1215 if (i < stream->n_segments - 1) {
1216 if (segment->time <= time_position && time_position < segment->stop_time) {
1217 GST_LOG_OBJECT (stream->pad, "segment %d matches", i);
1222 /* Last segment always matches */
1230 /* move the stream @str to the sample position @index.
1232 * Updates @str->sample_index and marks discontinuity if needed.
1235 gst_qtdemux_move_stream (GstQTDemux * qtdemux, QtDemuxStream * str,
1238 /* no change needed */
1239 if (index == str->sample_index)
1242 GST_DEBUG_OBJECT (qtdemux, "moving to sample %u of %u", index,
1245 /* position changed, we have a discont */
1246 str->sample_index = index;
1247 str->offset_in_sample = 0;
1248 /* Each time we move in the stream we store the position where we are
1250 str->from_sample = index;
1251 str->discont = TRUE;
1255 gst_qtdemux_adjust_seek (GstQTDemux * qtdemux, gint64 desired_time,
1256 gboolean use_sparse, gint64 * key_time, gint64 * key_offset)
1259 gint64 min_byte_offset = -1;
1262 min_offset = desired_time;
1264 /* for each stream, find the index of the sample in the segment
1265 * and move back to the previous keyframe. */
1266 for (n = 0; n < qtdemux->n_streams; n++) {
1268 guint32 index, kindex;
1270 GstClockTime media_start;
1271 GstClockTime media_time;
1272 GstClockTime seg_time;
1273 QtDemuxSegment *seg;
1274 gboolean empty_segment = FALSE;
1276 str = qtdemux->streams[n];
1278 if (str->sparse && !use_sparse)
1281 seg_idx = gst_qtdemux_find_segment (qtdemux, str, desired_time);
1282 GST_DEBUG_OBJECT (qtdemux, "align segment %d", seg_idx);
1284 /* get segment and time in the segment */
1285 seg = &str->segments[seg_idx];
1286 seg_time = (desired_time - seg->time) * seg->rate;
1288 while (QTSEGMENT_IS_EMPTY (seg)) {
1290 empty_segment = TRUE;
1291 GST_DEBUG_OBJECT (str->pad, "Segment %d is empty, moving to next one",
1294 if (seg_idx == str->n_segments)
1296 seg = &str->segments[seg_idx];
1299 if (seg_idx == str->n_segments) {
1300 /* FIXME track shouldn't have the last segment as empty, but if it
1301 * happens we better handle it */
1305 /* get the media time in the segment */
1306 media_start = seg->media_start + seg_time;
1308 /* get the index of the sample with media time */
1309 index = gst_qtdemux_find_index_linear (qtdemux, str, media_start);
1310 GST_DEBUG_OBJECT (qtdemux, "sample for %" GST_TIME_FORMAT " at %u"
1311 " at offset %" G_GUINT64_FORMAT " (empty segment: %d)",
1312 GST_TIME_ARGS (media_start), index, str->samples[index].offset,
1315 if (!empty_segment) {
1316 /* find previous keyframe */
1317 kindex = gst_qtdemux_find_keyframe (qtdemux, str, index);
1319 /* if the keyframe is at a different position, we need to update the
1320 * requested seek time */
1321 if (index != kindex) {
1324 /* get timestamp of keyframe */
1325 media_time = QTSAMPLE_DTS (str, &str->samples[kindex]);
1326 GST_DEBUG_OBJECT (qtdemux,
1327 "keyframe at %u with time %" GST_TIME_FORMAT " at offset %"
1328 G_GUINT64_FORMAT, kindex, GST_TIME_ARGS (media_time),
1329 str->samples[kindex].offset);
1331 /* keyframes in the segment get a chance to change the
1332 * desired_offset. keyframes out of the segment are
1334 if (media_time >= seg->media_start) {
1335 GstClockTime seg_time;
1337 /* this keyframe is inside the segment, convert back to
1339 seg_time = (media_time - seg->media_start) + seg->time;
1340 if (seg_time < min_offset)
1341 min_offset = seg_time;
1346 if (min_byte_offset < 0 || str->samples[index].offset < min_byte_offset)
1347 min_byte_offset = str->samples[index].offset;
1351 *key_time = min_offset;
1353 *key_offset = min_byte_offset;
1357 gst_qtdemux_convert_seek (GstPad * pad, GstFormat * format,
1358 GstSeekType cur_type, gint64 * cur, GstSeekType stop_type, gint64 * stop)
1362 g_return_val_if_fail (format != NULL, FALSE);
1363 g_return_val_if_fail (cur != NULL, FALSE);
1364 g_return_val_if_fail (stop != NULL, FALSE);
1366 if (*format == GST_FORMAT_TIME)
1370 if (cur_type != GST_SEEK_TYPE_NONE)
1371 res = gst_pad_query_convert (pad, *format, *cur, GST_FORMAT_TIME, cur);
1372 if (res && stop_type != GST_SEEK_TYPE_NONE)
1373 res = gst_pad_query_convert (pad, *format, *stop, GST_FORMAT_TIME, stop);
1376 *format = GST_FORMAT_TIME;
1381 /* perform seek in push based mode:
1382 find BYTE position to move to based on time and delegate to upstream
1385 gst_qtdemux_do_push_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1390 GstSeekType cur_type, stop_type;
1391 gint64 cur, stop, key_cur;
1394 gint64 original_stop;
1397 GST_DEBUG_OBJECT (qtdemux, "doing push-based seek");
1399 gst_event_parse_seek (event, &rate, &format, &flags,
1400 &cur_type, &cur, &stop_type, &stop);
1401 seqnum = gst_event_get_seqnum (event);
1403 /* only forward streaming and seeking is possible */
1405 goto unsupported_seek;
1407 /* convert to TIME if needed and possible */
1408 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1412 /* Upstream seek in bytes will have undefined stop, but qtdemux stores
1413 * the original stop position to use when upstream pushes the new segment
1415 original_stop = stop;
1418 /* find reasonable corresponding BYTE position,
1419 * also try to mind about keyframes, since we can not go back a bit for them
1421 gst_qtdemux_adjust_seek (qtdemux, cur, FALSE, &key_cur, &byte_cur);
1426 GST_DEBUG_OBJECT (qtdemux, "Pushing BYTE seek rate %g, "
1427 "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, byte_cur,
1430 GST_OBJECT_LOCK (qtdemux);
1431 qtdemux->seek_offset = byte_cur;
1432 if (!(flags & GST_SEEK_FLAG_KEY_UNIT)) {
1433 qtdemux->push_seek_start = cur;
1435 qtdemux->push_seek_start = key_cur;
1438 if (stop_type == GST_SEEK_TYPE_NONE) {
1439 qtdemux->push_seek_stop = qtdemux->segment.stop;
1441 qtdemux->push_seek_stop = original_stop;
1443 GST_OBJECT_UNLOCK (qtdemux);
1445 /* BYTE seek event */
1446 event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type, byte_cur,
1448 gst_event_set_seqnum (event, seqnum);
1449 res = gst_pad_push_event (qtdemux->sinkpad, event);
1456 GST_DEBUG_OBJECT (qtdemux, "could not determine byte position to seek to, "
1462 GST_DEBUG_OBJECT (qtdemux, "unsupported seek, seek aborted.");
1467 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1472 /* perform the seek.
1474 * We set all segment_indexes in the streams to unknown and
1475 * adjust the time_position to the desired position. this is enough
1476 * to trigger a segment switch in the streaming thread to start
1477 * streaming from the desired position.
1479 * Keyframe seeking is a little more complicated when dealing with
1480 * segments. Ideally we want to move to the previous keyframe in
1481 * the segment but there might not be a keyframe in the segment. In
1482 * fact, none of the segments could contain a keyframe. We take a
1483 * practical approach: seek to the previous keyframe in the segment,
1484 * if there is none, seek to the beginning of the segment.
1486 * Called with STREAM_LOCK
1489 gst_qtdemux_perform_seek (GstQTDemux * qtdemux, GstSegment * segment,
1490 guint32 seqnum, GstSeekFlags flags)
1492 gint64 desired_offset;
1495 desired_offset = segment->position;
1497 GST_DEBUG_OBJECT (qtdemux, "seeking to %" GST_TIME_FORMAT,
1498 GST_TIME_ARGS (desired_offset));
1500 /* may not have enough fragmented info to do this adjustment,
1501 * and we can't scan (and probably should not) at this time with
1502 * possibly flushing upstream */
1503 if ((flags & GST_SEEK_FLAG_KEY_UNIT) && !qtdemux->fragmented) {
1506 gst_qtdemux_adjust_seek (qtdemux, desired_offset, TRUE, &min_offset, NULL);
1507 GST_DEBUG_OBJECT (qtdemux, "keyframe seek, align to %"
1508 GST_TIME_FORMAT, GST_TIME_ARGS (min_offset));
1509 desired_offset = min_offset;
1512 /* and set all streams to the final position */
1513 gst_flow_combiner_reset (qtdemux->flowcombiner);
1514 qtdemux->segment_seqnum = seqnum;
1515 for (n = 0; n < qtdemux->n_streams; n++) {
1516 QtDemuxStream *stream = qtdemux->streams[n];
1518 stream->time_position = desired_offset;
1519 stream->accumulated_base = 0;
1520 stream->sample_index = -1;
1521 stream->offset_in_sample = 0;
1522 stream->segment_index = -1;
1523 stream->sent_eos = FALSE;
1525 if (segment->flags & GST_SEEK_FLAG_FLUSH)
1526 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
1528 segment->position = desired_offset;
1529 segment->time = desired_offset;
1530 if (segment->rate >= 0) {
1531 segment->start = desired_offset;
1533 /* we stop at the end */
1534 if (segment->stop == -1)
1535 segment->stop = segment->duration;
1537 segment->stop = desired_offset;
1540 if (qtdemux->fragmented)
1541 qtdemux->fragmented_seek_pending = TRUE;
1546 /* do a seek in pull based mode */
1548 gst_qtdemux_do_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1553 GstSeekType cur_type, stop_type;
1557 GstSegment seeksegment;
1559 GstEvent *flush_event;
1562 GST_DEBUG_OBJECT (qtdemux, "doing seek with event");
1564 gst_event_parse_seek (event, &rate, &format, &flags,
1565 &cur_type, &cur, &stop_type, &stop);
1566 seqnum = gst_event_get_seqnum (event);
1568 /* we have to have a format as the segment format. Try to convert
1570 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1574 GST_DEBUG_OBJECT (qtdemux, "seek format %s", gst_format_get_name (format));
1576 GST_DEBUG_OBJECT (qtdemux, "doing seek without event");
1580 flush = flags & GST_SEEK_FLAG_FLUSH;
1582 /* stop streaming, either by flushing or by pausing the task */
1584 flush_event = gst_event_new_flush_start ();
1586 gst_event_set_seqnum (flush_event, seqnum);
1587 /* unlock upstream pull_range */
1588 gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event));
1589 /* make sure out loop function exits */
1590 gst_qtdemux_push_event (qtdemux, flush_event);
1592 /* non flushing seek, pause the task */
1593 gst_pad_pause_task (qtdemux->sinkpad);
1596 /* wait for streaming to finish */
1597 GST_PAD_STREAM_LOCK (qtdemux->sinkpad);
1599 /* copy segment, we need this because we still need the old
1600 * segment when we close the current segment. */
1601 memcpy (&seeksegment, &qtdemux->segment, sizeof (GstSegment));
1604 /* configure the segment with the seek variables */
1605 GST_DEBUG_OBJECT (qtdemux, "configuring seek");
1606 gst_segment_do_seek (&seeksegment, rate, format, flags,
1607 cur_type, cur, stop_type, stop, &update);
1610 /* now do the seek, this actually never returns FALSE */
1611 gst_qtdemux_perform_seek (qtdemux, &seeksegment, seqnum, flags);
1613 /* prepare for streaming again */
1615 flush_event = gst_event_new_flush_stop (TRUE);
1617 gst_event_set_seqnum (flush_event, seqnum);
1619 gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event));
1620 gst_qtdemux_push_event (qtdemux, flush_event);
1623 /* commit the new segment */
1624 memcpy (&qtdemux->segment, &seeksegment, sizeof (GstSegment));
1626 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
1627 GstMessage *msg = gst_message_new_segment_start (GST_OBJECT_CAST (qtdemux),
1628 qtdemux->segment.format, qtdemux->segment.position);
1630 gst_message_set_seqnum (msg, seqnum);
1631 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
1634 /* restart streaming, NEWSEGMENT will be sent from the streaming thread. */
1635 gst_pad_start_task (qtdemux->sinkpad, (GstTaskFunction) gst_qtdemux_loop,
1636 qtdemux->sinkpad, NULL);
1638 GST_PAD_STREAM_UNLOCK (qtdemux->sinkpad);
1645 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1651 qtdemux_ensure_index (GstQTDemux * qtdemux)
1655 GST_DEBUG_OBJECT (qtdemux, "collecting all metadata for all streams");
1657 /* Build complete index */
1658 for (i = 0; i < qtdemux->n_streams; i++) {
1659 QtDemuxStream *stream = qtdemux->streams[i];
1661 if (!qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1))
1669 GST_LOG_OBJECT (qtdemux,
1670 "Building complete index of stream %u for seeking failed!", i);
1676 gst_qtdemux_handle_src_event (GstPad * pad, GstObject * parent,
1679 gboolean res = TRUE;
1680 GstQTDemux *qtdemux = GST_QTDEMUX (parent);
1682 switch (GST_EVENT_TYPE (event)) {
1683 case GST_EVENT_SEEK:
1685 #ifndef GST_DISABLE_GST_DEBUG
1686 GstClockTime ts = gst_util_get_timestamp ();
1689 if (qtdemux->upstream_format_is_time && qtdemux->fragmented) {
1690 /* seek should be handled by upstream, we might need to re-download fragments */
1691 GST_DEBUG_OBJECT (qtdemux,
1692 "let upstream handle seek for fragmented playback");
1696 /* Build complete index for seeking;
1697 * if not a fragmented file at least */
1698 if (!qtdemux->fragmented)
1699 if (!qtdemux_ensure_index (qtdemux))
1701 #ifndef GST_DISABLE_GST_DEBUG
1702 ts = gst_util_get_timestamp () - ts;
1703 GST_INFO_OBJECT (qtdemux,
1704 "Time taken to parse index %" GST_TIME_FORMAT, GST_TIME_ARGS (ts));
1707 if (qtdemux->pullbased) {
1708 res = gst_qtdemux_do_seek (qtdemux, pad, event);
1709 } else if (gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (event))) {
1710 GST_DEBUG_OBJECT (qtdemux, "Upstream successfully seeked");
1712 } else if (qtdemux->state == QTDEMUX_STATE_MOVIE && qtdemux->n_streams
1713 && !qtdemux->fragmented) {
1714 res = gst_qtdemux_do_push_seek (qtdemux, pad, event);
1716 GST_DEBUG_OBJECT (qtdemux,
1717 "ignoring seek in push mode in current state");
1720 gst_event_unref (event);
1723 case GST_EVENT_NAVIGATION:
1725 gst_event_unref (event);
1729 res = gst_pad_event_default (pad, parent, event);
1739 GST_ERROR_OBJECT (qtdemux, "Index failed");
1740 gst_event_unref (event);
1746 /* stream/index return sample that is min/max w.r.t. byte position,
1747 * time is min/max w.r.t. time of samples,
1748 * the latter need not be time of the former sample */
1750 gst_qtdemux_find_sample (GstQTDemux * qtdemux, gint64 byte_pos, gboolean fw,
1751 gboolean set, QtDemuxStream ** _stream, gint * _index, gint64 * _time)
1754 gint64 time, min_time;
1755 QtDemuxStream *stream;
1761 for (n = 0; n < qtdemux->n_streams; ++n) {
1764 gboolean set_sample;
1766 str = qtdemux->streams[n];
1773 i = str->n_samples - 1;
1777 for (; (i >= 0) && (i < str->n_samples); i += inc) {
1778 if (str->samples[i].size == 0)
1781 if (fw && (str->samples[i].offset < byte_pos))
1784 if (!fw && (str->samples[i].offset + str->samples[i].size > byte_pos))
1787 /* move stream to first available sample */
1789 gst_qtdemux_move_stream (qtdemux, str, i);
1793 /* avoid index from sparse streams since they might be far away */
1795 /* determine min/max time */
1796 time = QTSAMPLE_PTS (str, &str->samples[i]);
1797 if (min_time == -1 || (!fw && time > min_time) ||
1798 (fw && time < min_time)) {
1802 /* determine stream with leading sample, to get its position */
1804 (fw && (str->samples[i].offset < stream->samples[index].offset)) ||
1805 (!fw && (str->samples[i].offset > stream->samples[index].offset))) {
1813 /* no sample for this stream, mark eos */
1815 gst_qtdemux_move_stream (qtdemux, str, str->n_samples);
1826 static QtDemuxStream *
1827 _create_stream (void)
1829 QtDemuxStream *stream;
1831 stream = g_new0 (QtDemuxStream, 1);
1832 /* new streams always need a discont */
1833 stream->discont = TRUE;
1834 /* we enable clipping for raw audio/video streams */
1835 stream->need_clip = FALSE;
1836 stream->need_process = FALSE;
1837 stream->segment_index = -1;
1838 stream->time_position = 0;
1839 stream->sample_index = -1;
1840 stream->offset_in_sample = 0;
1841 stream->new_stream = TRUE;
1842 stream->multiview_mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
1843 stream->multiview_flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
1844 stream->protected = FALSE;
1845 stream->protection_scheme_type = 0;
1846 stream->protection_scheme_version = 0;
1847 stream->protection_scheme_info = NULL;
1848 stream->n_samples_moof = 0;
1849 stream->duration_moof = 0;
1850 g_queue_init (&stream->protection_scheme_event_queue);
1855 gst_qtdemux_setcaps (GstQTDemux * demux, GstCaps * caps)
1857 GstStructure *structure;
1858 const gchar *variant;
1859 const GstCaps *mediacaps = NULL;
1861 GST_DEBUG_OBJECT (demux, "Sink set caps: %" GST_PTR_FORMAT, caps);
1863 structure = gst_caps_get_structure (caps, 0);
1864 variant = gst_structure_get_string (structure, "variant");
1866 if (variant && strcmp (variant, "mss-fragmented") == 0) {
1867 QtDemuxStream *stream;
1868 const GValue *value;
1870 demux->fragmented = TRUE;
1871 demux->mss_mode = TRUE;
1873 if (demux->n_streams > 1) {
1874 /* can't do this, we can only renegotiate for another mss format */
1878 value = gst_structure_get_value (structure, "media-caps");
1881 const GValue *timescale_v;
1883 /* TODO update when stream changes during playback */
1885 if (demux->n_streams == 0) {
1886 stream = _create_stream ();
1887 demux->streams[demux->n_streams] = stream;
1888 demux->n_streams = 1;
1890 stream = demux->streams[0];
1893 timescale_v = gst_structure_get_value (structure, "timescale");
1895 stream->timescale = g_value_get_uint64 (timescale_v);
1897 /* default mss timescale */
1898 stream->timescale = 10000000;
1900 demux->timescale = stream->timescale;
1902 mediacaps = gst_value_get_caps (value);
1903 if (!stream->caps || !gst_caps_is_equal_fixed (mediacaps, stream->caps)) {
1904 GST_DEBUG_OBJECT (demux, "We have a new caps %" GST_PTR_FORMAT,
1906 stream->new_caps = TRUE;
1908 gst_caps_replace (&stream->caps, (GstCaps *) mediacaps);
1909 structure = gst_caps_get_structure (mediacaps, 0);
1910 if (g_str_has_prefix (gst_structure_get_name (structure), "video")) {
1911 stream->subtype = FOURCC_vide;
1913 gst_structure_get_int (structure, "width", &stream->width);
1914 gst_structure_get_int (structure, "height", &stream->height);
1915 gst_structure_get_fraction (structure, "framerate", &stream->fps_n,
1917 } else if (g_str_has_prefix (gst_structure_get_name (structure), "audio")) {
1919 stream->subtype = FOURCC_soun;
1920 gst_structure_get_int (structure, "channels", &stream->n_channels);
1921 gst_structure_get_int (structure, "rate", &rate);
1922 stream->rate = rate;
1925 gst_caps_replace (&demux->media_caps, (GstCaps *) mediacaps);
1927 demux->mss_mode = FALSE;
1934 gst_qtdemux_reset (GstQTDemux * qtdemux, gboolean hard)
1938 GST_DEBUG_OBJECT (qtdemux, "Resetting demux");
1939 gst_pad_stop_task (qtdemux->sinkpad);
1941 if (hard || qtdemux->upstream_format_is_time) {
1942 qtdemux->state = QTDEMUX_STATE_INITIAL;
1943 qtdemux->neededbytes = 16;
1944 qtdemux->todrop = 0;
1945 qtdemux->pullbased = FALSE;
1946 qtdemux->posted_redirect = FALSE;
1947 qtdemux->first_mdat = -1;
1948 qtdemux->header_size = 0;
1949 qtdemux->mdatoffset = -1;
1950 qtdemux->restoredata_offset = -1;
1951 if (qtdemux->mdatbuffer)
1952 gst_buffer_unref (qtdemux->mdatbuffer);
1953 if (qtdemux->restoredata_buffer)
1954 gst_buffer_unref (qtdemux->restoredata_buffer);
1955 qtdemux->mdatbuffer = NULL;
1956 qtdemux->restoredata_buffer = NULL;
1957 qtdemux->mdatleft = 0;
1958 if (qtdemux->comp_brands)
1959 gst_buffer_unref (qtdemux->comp_brands);
1960 qtdemux->comp_brands = NULL;
1961 qtdemux->last_moov_offset = -1;
1962 if (qtdemux->moov_node)
1963 g_node_destroy (qtdemux->moov_node);
1964 qtdemux->moov_node = NULL;
1965 qtdemux->moov_node_compressed = NULL;
1966 if (qtdemux->tag_list)
1967 gst_mini_object_unref (GST_MINI_OBJECT_CAST (qtdemux->tag_list));
1968 qtdemux->tag_list = NULL;
1970 if (qtdemux->element_index)
1971 gst_object_unref (qtdemux->element_index);
1972 qtdemux->element_index = NULL;
1974 qtdemux->major_brand = 0;
1975 if (qtdemux->pending_newsegment)
1976 gst_event_unref (qtdemux->pending_newsegment);
1977 qtdemux->pending_newsegment = NULL;
1978 qtdemux->upstream_format_is_time = FALSE;
1979 qtdemux->upstream_seekable = FALSE;
1980 qtdemux->upstream_size = 0;
1982 qtdemux->fragment_start = -1;
1983 qtdemux->fragment_start_offset = -1;
1984 qtdemux->duration = 0;
1985 qtdemux->moof_offset = 0;
1986 qtdemux->chapters_track_id = 0;
1987 qtdemux->have_group_id = FALSE;
1988 qtdemux->group_id = G_MAXUINT;
1990 g_queue_foreach (&qtdemux->protection_event_queue, (GFunc) gst_event_unref,
1992 g_queue_clear (&qtdemux->protection_event_queue);
1994 qtdemux->offset = 0;
1995 gst_adapter_clear (qtdemux->adapter);
1996 gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
1997 qtdemux->segment_seqnum = 0;
2000 for (n = 0; n < qtdemux->n_streams; n++) {
2001 gst_qtdemux_stream_free (qtdemux, qtdemux->streams[n]);
2002 qtdemux->streams[n] = NULL;
2004 qtdemux->n_streams = 0;
2005 qtdemux->n_video_streams = 0;
2006 qtdemux->n_audio_streams = 0;
2007 qtdemux->n_sub_streams = 0;
2008 qtdemux->exposed = FALSE;
2009 qtdemux->fragmented = FALSE;
2010 qtdemux->mss_mode = FALSE;
2011 gst_caps_replace (&qtdemux->media_caps, NULL);
2012 qtdemux->timescale = 0;
2013 qtdemux->got_moov = FALSE;
2014 if (qtdemux->protection_system_ids) {
2015 g_ptr_array_free (qtdemux->protection_system_ids, TRUE);
2016 qtdemux->protection_system_ids = NULL;
2018 } else if (qtdemux->mss_mode) {
2019 gst_flow_combiner_reset (qtdemux->flowcombiner);
2020 for (n = 0; n < qtdemux->n_streams; n++)
2021 gst_qtdemux_stream_clear (qtdemux, qtdemux->streams[n]);
2023 gst_flow_combiner_reset (qtdemux->flowcombiner);
2024 for (n = 0; n < qtdemux->n_streams; n++) {
2025 qtdemux->streams[n]->sent_eos = FALSE;
2026 qtdemux->streams[n]->time_position = 0;
2027 qtdemux->streams[n]->accumulated_base = 0;
2029 if (!qtdemux->pending_newsegment) {
2030 qtdemux->pending_newsegment = gst_event_new_segment (&qtdemux->segment);
2031 if (qtdemux->segment_seqnum)
2032 gst_event_set_seqnum (qtdemux->pending_newsegment,
2033 qtdemux->segment_seqnum);
2039 /* Maps the @segment to the qt edts internal segments and pushes
2040 * the correspnding segment event.
2042 * If it ends up being at a empty segment, a gap will be pushed and the next
2043 * edts segment will be activated in sequence.
2045 * To be used in push-mode only */
2047 gst_qtdemux_map_and_push_segments (GstQTDemux * qtdemux, GstSegment * segment)
2051 for (n = 0; n < qtdemux->n_streams; n++) {
2052 QtDemuxStream *stream = qtdemux->streams[n];
2054 stream->time_position = segment->start;
2056 /* in push mode we should be guaranteed that we will have empty segments
2057 * at the beginning and then one segment after, other scenarios are not
2058 * supported and are discarded when parsing the edts */
2059 for (i = 0; i < stream->n_segments; i++) {
2060 if (stream->segments[i].stop_time > segment->start) {
2061 gst_qtdemux_activate_segment (qtdemux, stream, i,
2062 stream->time_position);
2063 if (QTSEGMENT_IS_EMPTY (&stream->segments[i])) {
2064 /* push the empty segment and move to the next one */
2065 gst_qtdemux_send_gap_for_segment (qtdemux, stream, i,
2066 stream->time_position);
2070 g_assert (i == stream->n_segments - 1);
2077 gst_qtdemux_handle_sink_event (GstPad * sinkpad, GstObject * parent,
2080 GstQTDemux *demux = GST_QTDEMUX (parent);
2081 gboolean res = TRUE;
2083 GST_LOG_OBJECT (demux, "handling %s event", GST_EVENT_TYPE_NAME (event));
2085 switch (GST_EVENT_TYPE (event)) {
2086 case GST_EVENT_SEGMENT:
2089 QtDemuxStream *stream;
2093 /* some debug output */
2094 gst_event_copy_segment (event, &segment);
2095 GST_DEBUG_OBJECT (demux, "received newsegment %" GST_SEGMENT_FORMAT,
2098 /* erase any previously set segment */
2099 gst_event_replace (&demux->pending_newsegment, NULL);
2101 if (segment.format == GST_FORMAT_TIME) {
2102 GST_DEBUG_OBJECT (demux, "new pending_newsegment");
2103 gst_event_replace (&demux->pending_newsegment, event);
2104 demux->upstream_format_is_time = TRUE;
2106 GST_DEBUG_OBJECT (demux, "Not storing upstream newsegment, "
2107 "not in time format");
2109 /* chain will send initial newsegment after pads have been added */
2110 if (demux->state != QTDEMUX_STATE_MOVIE || !demux->n_streams) {
2111 GST_DEBUG_OBJECT (demux, "still starting, eating event");
2116 /* check if this matches a time seek we received previously
2117 * FIXME for backwards compatibility reasons we use the
2118 * seek_offset here to compare. In the future we might want to
2119 * change this to use the seqnum as it uniquely should identify
2120 * the segment that corresponds to the seek. */
2121 GST_DEBUG_OBJECT (demux, "Stored seek offset: %" G_GINT64_FORMAT
2122 ", received segment offset %" G_GINT64_FORMAT,
2123 demux->seek_offset, segment.start);
2124 if (segment.format == GST_FORMAT_BYTES
2125 && demux->seek_offset == segment.start) {
2126 GST_OBJECT_LOCK (demux);
2127 offset = segment.start;
2129 segment.format = GST_FORMAT_TIME;
2130 segment.start = demux->push_seek_start;
2131 segment.stop = demux->push_seek_stop;
2132 GST_DEBUG_OBJECT (demux, "Replaced segment with stored seek "
2133 "segment %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT,
2134 GST_TIME_ARGS (segment.start), GST_TIME_ARGS (segment.stop));
2135 GST_OBJECT_UNLOCK (demux);
2138 /* we only expect a BYTE segment, e.g. following a seek */
2139 if (segment.format == GST_FORMAT_BYTES) {
2140 if (GST_CLOCK_TIME_IS_VALID (segment.start)) {
2141 offset = segment.start;
2143 gst_qtdemux_find_sample (demux, segment.start, TRUE, FALSE, NULL,
2144 NULL, (gint64 *) & segment.start);
2145 if ((gint64) segment.start < 0)
2148 if (GST_CLOCK_TIME_IS_VALID (segment.stop)) {
2149 gst_qtdemux_find_sample (demux, segment.stop, FALSE, FALSE, NULL,
2150 NULL, (gint64 *) & segment.stop);
2151 /* keyframe seeking should already arrange for start >= stop,
2152 * but make sure in other rare cases */
2153 segment.stop = MAX (segment.stop, segment.start);
2155 } else if (segment.format == GST_FORMAT_TIME) {
2156 /* push all data on the adapter before starting this
2158 gst_qtdemux_process_adapter (demux, TRUE);
2160 GST_DEBUG_OBJECT (demux, "unsupported segment format, ignoring");
2164 /* accept upstream's notion of segment and distribute along */
2165 segment.format = GST_FORMAT_TIME;
2166 segment.position = segment.time = segment.start;
2167 segment.duration = demux->segment.duration;
2168 segment.base = gst_segment_to_running_time (&demux->segment,
2169 GST_FORMAT_TIME, demux->segment.position);
2171 gst_segment_copy_into (&segment, &demux->segment);
2172 GST_DEBUG_OBJECT (demux, "Pushing newseg %" GST_SEGMENT_FORMAT, &segment);
2174 /* map segment to internal qt segments and push on each stream */
2175 if (demux->n_streams) {
2176 if (demux->fragmented) {
2177 GstEvent *segment_event = gst_event_new_segment (&segment);
2179 gst_event_replace (&demux->pending_newsegment, NULL);
2180 gst_event_set_seqnum (segment_event, demux->segment_seqnum);
2181 gst_qtdemux_push_event (demux, segment_event);
2183 gst_event_replace (&demux->pending_newsegment, NULL);
2184 gst_qtdemux_map_and_push_segments (demux, &segment);
2188 /* clear leftover in current segment, if any */
2189 gst_adapter_clear (demux->adapter);
2191 /* set up streaming thread */
2192 demux->offset = offset;
2193 if (demux->upstream_format_is_time) {
2194 GST_DEBUG_OBJECT (demux, "Upstream is driving in time format, "
2195 "set values to restart reading from a new atom");
2196 demux->neededbytes = 16;
2199 gst_qtdemux_find_sample (demux, offset, TRUE, TRUE, &stream, &idx,
2202 demux->todrop = stream->samples[idx].offset - offset;
2203 demux->neededbytes = demux->todrop + stream->samples[idx].size;
2205 /* set up for EOS */
2206 demux->neededbytes = -1;
2211 gst_event_unref (event);
2215 case GST_EVENT_FLUSH_START:
2217 if (gst_event_get_seqnum (event) == demux->offset_seek_seqnum) {
2218 gst_event_unref (event);
2223 case GST_EVENT_FLUSH_STOP:
2227 dur = demux->segment.duration;
2228 gst_qtdemux_reset (demux, FALSE);
2229 demux->segment.duration = dur;
2231 if (gst_event_get_seqnum (event) == demux->offset_seek_seqnum) {
2232 gst_event_unref (event);
2238 /* If we are in push mode, and get an EOS before we've seen any streams,
2239 * then error out - we have nowhere to send the EOS */
2240 if (!demux->pullbased) {
2242 gboolean has_valid_stream = FALSE;
2243 for (i = 0; i < demux->n_streams; i++) {
2244 if (demux->streams[i]->pad != NULL) {
2245 has_valid_stream = TRUE;
2249 if (!has_valid_stream)
2250 gst_qtdemux_post_no_playable_stream_error (demux);
2252 GST_DEBUG_OBJECT (demux, "Data still available after EOS: %u",
2253 (guint) gst_adapter_available (demux->adapter));
2254 if (gst_qtdemux_process_adapter (demux, TRUE) != GST_FLOW_OK) {
2260 case GST_EVENT_CAPS:{
2261 GstCaps *caps = NULL;
2263 gst_event_parse_caps (event, &caps);
2264 gst_qtdemux_setcaps (demux, caps);
2266 gst_event_unref (event);
2269 case GST_EVENT_PROTECTION:
2271 const gchar *system_id = NULL;
2273 gst_event_parse_protection (event, &system_id, NULL, NULL);
2274 GST_DEBUG_OBJECT (demux, "Received protection event for system ID %s",
2276 gst_qtdemux_append_protection_system_id (demux, system_id);
2277 /* save the event for later, for source pads that have not been created */
2278 g_queue_push_tail (&demux->protection_event_queue, gst_event_ref (event));
2279 /* send it to all pads that already exist */
2280 gst_qtdemux_push_event (demux, event);
2288 res = gst_pad_event_default (demux->sinkpad, parent, event) & res;
2296 gst_qtdemux_set_index (GstElement * element, GstIndex * index)
2298 GstQTDemux *demux = GST_QTDEMUX (element);
2300 GST_OBJECT_LOCK (demux);
2301 if (demux->element_index)
2302 gst_object_unref (demux->element_index);
2304 demux->element_index = gst_object_ref (index);
2306 demux->element_index = NULL;
2308 GST_OBJECT_UNLOCK (demux);
2309 /* object lock might be taken again */
2311 gst_index_get_writer_id (index, GST_OBJECT (element), &demux->index_id);
2312 GST_DEBUG_OBJECT (demux, "Set index %" GST_PTR_FORMAT "for writer id %d",
2313 demux->element_index, demux->index_id);
2317 gst_qtdemux_get_index (GstElement * element)
2319 GstIndex *result = NULL;
2320 GstQTDemux *demux = GST_QTDEMUX (element);
2322 GST_OBJECT_LOCK (demux);
2323 if (demux->element_index)
2324 result = gst_object_ref (demux->element_index);
2325 GST_OBJECT_UNLOCK (demux);
2327 GST_DEBUG_OBJECT (demux, "Returning index %" GST_PTR_FORMAT, result);
2334 gst_qtdemux_stbl_free (QtDemuxStream * stream)
2336 g_free ((gpointer) stream->stco.data);
2337 stream->stco.data = NULL;
2338 g_free ((gpointer) stream->stsz.data);
2339 stream->stsz.data = NULL;
2340 g_free ((gpointer) stream->stsc.data);
2341 stream->stsc.data = NULL;
2342 g_free ((gpointer) stream->stts.data);
2343 stream->stts.data = NULL;
2344 g_free ((gpointer) stream->stss.data);
2345 stream->stss.data = NULL;
2346 g_free ((gpointer) stream->stps.data);
2347 stream->stps.data = NULL;
2348 g_free ((gpointer) stream->ctts.data);
2349 stream->ctts.data = NULL;
2353 gst_qtdemux_stream_flush_segments_data (GstQTDemux * qtdemux,
2354 QtDemuxStream * stream)
2356 g_free (stream->segments);
2357 stream->segments = NULL;
2358 stream->segment_index = -1;
2359 stream->accumulated_base = 0;
2363 gst_qtdemux_stream_flush_samples_data (GstQTDemux * qtdemux,
2364 QtDemuxStream * stream)
2366 g_free (stream->samples);
2367 stream->samples = NULL;
2368 gst_qtdemux_stbl_free (stream);
2371 g_free (stream->ra_entries);
2372 stream->ra_entries = NULL;
2373 stream->n_ra_entries = 0;
2375 stream->sample_index = -1;
2376 stream->stbl_index = -1;
2377 stream->n_samples = 0;
2378 stream->time_position = 0;
2380 stream->n_samples_moof = 0;
2381 stream->duration_moof = 0;
2385 gst_qtdemux_stream_clear (GstQTDemux * qtdemux, QtDemuxStream * stream)
2387 if (stream->allocator)
2388 gst_object_unref (stream->allocator);
2389 while (stream->buffers) {
2390 gst_buffer_unref (GST_BUFFER_CAST (stream->buffers->data));
2391 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
2393 if (stream->rgb8_palette) {
2394 gst_memory_unref (stream->rgb8_palette);
2395 stream->rgb8_palette = NULL;
2398 if (stream->pending_tags)
2399 gst_tag_list_unref (stream->pending_tags);
2400 stream->pending_tags = NULL;
2401 g_free (stream->redirect_uri);
2402 stream->redirect_uri = NULL;
2403 stream->sent_eos = FALSE;
2404 stream->sparse = FALSE;
2405 stream->protected = FALSE;
2406 if (stream->protection_scheme_info) {
2407 if (stream->protection_scheme_type == FOURCC_cenc) {
2408 QtDemuxCencSampleSetInfo *info =
2409 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
2410 if (info->default_properties)
2411 gst_structure_free (info->default_properties);
2412 if (info->crypto_info)
2413 g_ptr_array_free (info->crypto_info, TRUE);
2415 g_free (stream->protection_scheme_info);
2416 stream->protection_scheme_info = NULL;
2418 stream->protection_scheme_type = 0;
2419 stream->protection_scheme_version = 0;
2420 g_queue_foreach (&stream->protection_scheme_event_queue,
2421 (GFunc) gst_event_unref, NULL);
2422 g_queue_clear (&stream->protection_scheme_event_queue);
2423 gst_qtdemux_stream_flush_segments_data (qtdemux, stream);
2424 gst_qtdemux_stream_flush_samples_data (qtdemux, stream);
2428 gst_qtdemux_stream_free (GstQTDemux * qtdemux, QtDemuxStream * stream)
2430 gst_qtdemux_stream_clear (qtdemux, stream);
2432 gst_caps_unref (stream->caps);
2433 stream->caps = NULL;
2435 gst_element_remove_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
2436 gst_flow_combiner_remove_pad (qtdemux->flowcombiner, stream->pad);
2442 gst_qtdemux_remove_stream (GstQTDemux * qtdemux, int i)
2444 g_assert (i >= 0 && i < qtdemux->n_streams && qtdemux->streams[i] != NULL);
2446 gst_qtdemux_stream_free (qtdemux, qtdemux->streams[i]);
2447 qtdemux->streams[i] = qtdemux->streams[qtdemux->n_streams - 1];
2448 qtdemux->streams[qtdemux->n_streams - 1] = NULL;
2449 qtdemux->n_streams--;
2452 static GstStateChangeReturn
2453 gst_qtdemux_change_state (GstElement * element, GstStateChange transition)
2455 GstQTDemux *qtdemux = GST_QTDEMUX (element);
2456 GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
2458 switch (transition) {
2459 case GST_STATE_CHANGE_PAUSED_TO_READY:
2465 result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
2467 switch (transition) {
2468 case GST_STATE_CHANGE_PAUSED_TO_READY:{
2469 gst_qtdemux_reset (qtdemux, TRUE);
2480 qtdemux_parse_ftyp (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2482 /* counts as header data */
2483 qtdemux->header_size += length;
2485 /* only consider at least a sufficiently complete ftyp atom */
2489 qtdemux->major_brand = QT_FOURCC (buffer + 8);
2490 GST_DEBUG_OBJECT (qtdemux, "major brand: %" GST_FOURCC_FORMAT,
2491 GST_FOURCC_ARGS (qtdemux->major_brand));
2492 if (qtdemux->comp_brands)
2493 gst_buffer_unref (qtdemux->comp_brands);
2494 buf = qtdemux->comp_brands = gst_buffer_new_and_alloc (length - 16);
2495 gst_buffer_fill (buf, 0, buffer + 16, length - 16);
2500 qtdemux_handle_xmp_taglist (GstQTDemux * qtdemux, GstTagList * taglist,
2501 GstTagList * xmptaglist)
2503 /* Strip out bogus fields */
2505 if (gst_tag_list_get_scope (taglist) == GST_TAG_SCOPE_GLOBAL) {
2506 gst_tag_list_remove_tag (xmptaglist, GST_TAG_VIDEO_CODEC);
2507 gst_tag_list_remove_tag (xmptaglist, GST_TAG_AUDIO_CODEC);
2509 gst_tag_list_remove_tag (xmptaglist, GST_TAG_CONTAINER_FORMAT);
2512 GST_DEBUG_OBJECT (qtdemux, "Found XMP tags %" GST_PTR_FORMAT, xmptaglist);
2514 /* prioritize native tags using _KEEP mode */
2515 gst_tag_list_insert (taglist, xmptaglist, GST_TAG_MERGE_KEEP);
2516 gst_tag_list_unref (xmptaglist);
2521 qtdemux_parse_piff (GstQTDemux * qtdemux, const guint8 * buffer, gint length,
2529 QtDemuxStream *stream;
2530 GstStructure *structure;
2531 QtDemuxCencSampleSetInfo *ss_info = NULL;
2532 const gchar *system_id;
2533 gboolean uses_sub_sample_encryption = FALSE;
2535 if (qtdemux->n_streams == 0)
2538 stream = qtdemux->streams[0];
2540 structure = gst_caps_get_structure (stream->caps, 0);
2541 if (!gst_structure_has_name (structure, "application/x-cenc")) {
2542 GST_WARNING_OBJECT (qtdemux,
2543 "Attempting PIFF box parsing on an unencrypted stream.");
2547 gst_structure_get (structure, GST_PROTECTION_SYSTEM_ID_CAPS_FIELD,
2548 G_TYPE_STRING, &system_id, NULL);
2549 gst_qtdemux_append_protection_system_id (qtdemux, system_id);
2551 stream->protected = TRUE;
2552 stream->protection_scheme_type = FOURCC_cenc;
2554 if (!stream->protection_scheme_info)
2555 stream->protection_scheme_info = g_new0 (QtDemuxCencSampleSetInfo, 1);
2557 ss_info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
2559 if (ss_info->default_properties)
2560 gst_structure_free (ss_info->default_properties);
2562 ss_info->default_properties =
2563 gst_structure_new ("application/x-cenc",
2564 "iv_size", G_TYPE_UINT, iv_size, "encrypted", G_TYPE_BOOLEAN, TRUE, NULL);
2566 if (ss_info->crypto_info) {
2567 GST_LOG_OBJECT (qtdemux, "unreffing existing crypto_info");
2568 g_ptr_array_free (ss_info->crypto_info, TRUE);
2569 ss_info->crypto_info = NULL;
2573 gst_byte_reader_init (&br, buffer + offset + 16, length - offset - 16);
2575 if (!gst_byte_reader_get_uint8 (&br, &version)) {
2576 GST_ERROR_OBJECT (qtdemux, "Error getting box's version field");
2580 if (!gst_byte_reader_get_uint24_be (&br, &flags)) {
2581 GST_ERROR_OBJECT (qtdemux, "Error getting box's flags field");
2585 if ((flags & 0x000001)) {
2586 guint32 algorithm_id = 0;
2589 gboolean is_encrypted = TRUE;
2591 if (!gst_byte_reader_get_uint24_le (&br, &algorithm_id)) {
2592 GST_ERROR_OBJECT (qtdemux, "Error getting box's algorithm ID field");
2597 if (algorithm_id == 0) {
2598 is_encrypted = FALSE;
2599 } else if (algorithm_id == 1) {
2600 /* FIXME: maybe store this in properties? */
2601 GST_DEBUG_OBJECT (qtdemux, "AES 128-bits CTR encrypted stream");
2602 } else if (algorithm_id == 2) {
2603 /* FIXME: maybe store this in properties? */
2604 GST_DEBUG_OBJECT (qtdemux, "AES 128-bits CBC encrypted stream");
2607 if (!gst_byte_reader_get_uint8 (&br, &iv_size))
2610 if (!gst_byte_reader_get_data (&br, 16, &kid))
2613 kid_buf = gst_buffer_new_allocate (NULL, 16, NULL);
2614 gst_buffer_fill (kid_buf, 0, kid, 16);
2615 if (ss_info->default_properties)
2616 gst_structure_free (ss_info->default_properties);
2617 ss_info->default_properties =
2618 gst_structure_new ("application/x-cenc",
2619 "iv_size", G_TYPE_UINT, iv_size,
2620 "encrypted", G_TYPE_BOOLEAN, is_encrypted,
2621 "kid", GST_TYPE_BUFFER, kid_buf, NULL);
2622 GST_DEBUG_OBJECT (qtdemux, "default sample properties: "
2623 "is_encrypted=%u, iv_size=%u", is_encrypted, iv_size);
2624 gst_buffer_unref (kid_buf);
2625 } else if ((flags & 0x000002)) {
2626 uses_sub_sample_encryption = TRUE;
2629 if (!gst_byte_reader_get_uint32_be (&br, &qtdemux->cenc_aux_sample_count)) {
2630 GST_ERROR_OBJECT (qtdemux, "Error getting box's sample count field");
2634 ss_info->crypto_info =
2635 g_ptr_array_new_full (qtdemux->cenc_aux_sample_count,
2636 (GDestroyNotify) qtdemux_gst_structure_free);
2638 for (i = 0; i < qtdemux->cenc_aux_sample_count; ++i) {
2639 GstStructure *properties;
2643 properties = qtdemux_get_cenc_sample_properties (qtdemux, stream, i);
2644 if (properties == NULL) {
2645 GST_ERROR_OBJECT (qtdemux, "failed to get properties for sample %u", i);
2649 if (!gst_byte_reader_dup_data (&br, iv_size, &data)) {
2650 GST_ERROR_OBJECT (qtdemux, "IV data not present for sample %u", i);
2651 gst_structure_free (properties);
2654 buf = gst_buffer_new_wrapped (data, iv_size);
2655 gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL);
2656 gst_buffer_unref (buf);
2658 if (uses_sub_sample_encryption) {
2659 guint16 n_subsamples;
2661 if (!gst_byte_reader_get_uint16_be (&br, &n_subsamples)
2662 || n_subsamples == 0) {
2663 GST_ERROR_OBJECT (qtdemux,
2664 "failed to get subsample count for sample %u", i);
2665 gst_structure_free (properties);
2668 GST_LOG_OBJECT (qtdemux, "subsample count: %u", n_subsamples);
2669 if (!gst_byte_reader_dup_data (&br, n_subsamples * 6, &data)) {
2670 GST_ERROR_OBJECT (qtdemux, "failed to get subsample data for sample %u",
2672 gst_structure_free (properties);
2675 buf = gst_buffer_new_wrapped (data, n_subsamples * 6);
2676 gst_structure_set (properties,
2677 "subsample_count", G_TYPE_UINT, n_subsamples,
2678 "subsamples", GST_TYPE_BUFFER, buf, NULL);
2679 gst_buffer_unref (buf);
2681 gst_structure_set (properties, "subsample_count", G_TYPE_UINT, 0, NULL);
2684 g_ptr_array_add (ss_info->crypto_info, properties);
2689 qtdemux_parse_uuid (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2691 static const guint8 xmp_uuid[] = { 0xBE, 0x7A, 0xCF, 0xCB,
2692 0x97, 0xA9, 0x42, 0xE8,
2693 0x9C, 0x71, 0x99, 0x94,
2694 0x91, 0xE3, 0xAF, 0xAC
2696 static const guint8 playready_uuid[] = {
2697 0xd0, 0x8a, 0x4f, 0x18, 0x10, 0xf3, 0x4a, 0x82,
2698 0xb6, 0xc8, 0x32, 0xd8, 0xab, 0xa1, 0x83, 0xd3
2701 static const guint8 piff_sample_encryption_uuid[] = {
2702 0xa2, 0x39, 0x4f, 0x52, 0x5a, 0x9b, 0x4f, 0x14,
2703 0xa2, 0x44, 0x6c, 0x42, 0x7c, 0x64, 0x8d, 0xf4
2708 /* counts as header data */
2709 qtdemux->header_size += length;
2711 offset = (QT_UINT32 (buffer) == 0) ? 16 : 8;
2713 if (length <= offset + 16) {
2714 GST_DEBUG_OBJECT (qtdemux, "uuid atom is too short, skipping");
2718 if (memcmp (buffer + offset, xmp_uuid, 16) == 0) {
2720 GstTagList *taglist;
2722 buf = _gst_buffer_new_wrapped ((guint8 *) buffer + offset + 16,
2723 length - offset - 16, NULL);
2724 taglist = gst_tag_list_from_xmp_buffer (buf);
2725 gst_buffer_unref (buf);
2727 qtdemux_handle_xmp_taglist (qtdemux, qtdemux->tag_list, taglist);
2729 } else if (memcmp (buffer + offset, playready_uuid, 16) == 0) {
2731 const gunichar2 *s_utf16;
2734 len = GST_READ_UINT16_LE (buffer + offset + 0x30);
2735 s_utf16 = (const gunichar2 *) (buffer + offset + 0x32);
2736 contents = g_utf16_to_utf8 (s_utf16, len / 2, NULL, NULL, NULL);
2737 GST_ERROR_OBJECT (qtdemux, "contents: %s", contents);
2741 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT,
2742 (_("Cannot play stream because it is encrypted with PlayReady DRM.")),
2744 } else if (memcmp (buffer + offset, piff_sample_encryption_uuid, 16) == 0) {
2745 qtdemux_parse_piff (qtdemux, buffer, length, offset);
2747 GST_DEBUG_OBJECT (qtdemux, "Ignoring unknown uuid: %08x-%08x-%08x-%08x",
2748 GST_READ_UINT32_LE (buffer + offset),
2749 GST_READ_UINT32_LE (buffer + offset + 4),
2750 GST_READ_UINT32_LE (buffer + offset + 8),
2751 GST_READ_UINT32_LE (buffer + offset + 12));
2756 qtdemux_parse_sidx (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2758 GstSidxParser sidx_parser;
2759 GstIsoffParserResult res;
2762 gst_isoff_qt_sidx_parser_init (&sidx_parser);
2765 gst_isoff_qt_sidx_parser_add_data (&sidx_parser, buffer, length,
2767 GST_DEBUG_OBJECT (qtdemux, "sidx parse result: %d", res);
2768 if (res == GST_ISOFF_QT_PARSER_DONE) {
2769 check_update_duration (qtdemux, sidx_parser.cumulative_pts);
2771 gst_isoff_qt_sidx_parser_clear (&sidx_parser);
2774 /* caller verifies at least 8 bytes in buf */
2776 extract_initial_length_and_fourcc (const guint8 * data, guint size,
2777 guint64 * plength, guint32 * pfourcc)
2782 length = QT_UINT32 (data);
2783 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
2784 fourcc = QT_FOURCC (data + 4);
2785 GST_DEBUG ("atom type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
2788 length = G_MAXUINT64;
2789 } else if (length == 1 && size >= 16) {
2790 /* this means we have an extended size, which is the 64 bit value of
2791 * the next 8 bytes */
2792 length = QT_UINT64 (data + 8);
2793 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
2803 qtdemux_parse_mehd (GstQTDemux * qtdemux, GstByteReader * br)
2805 guint32 version = 0;
2806 GstClockTime duration = 0;
2808 if (!gst_byte_reader_get_uint32_be (br, &version))
2813 if (!gst_byte_reader_get_uint64_be (br, &duration))
2818 if (!gst_byte_reader_get_uint32_be (br, &dur))
2823 GST_INFO_OBJECT (qtdemux, "mehd duration: %" G_GUINT64_FORMAT, duration);
2824 qtdemux->duration = duration;
2830 GST_DEBUG_OBJECT (qtdemux, "parsing mehd failed");
2836 qtdemux_parse_trex (GstQTDemux * qtdemux, QtDemuxStream * stream,
2837 guint32 * ds_duration, guint32 * ds_size, guint32 * ds_flags)
2839 if (!stream->parsed_trex && qtdemux->moov_node) {
2841 GstByteReader trex_data;
2843 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
2845 trex = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_trex,
2848 guint32 id = 0, dur = 0, size = 0, flags = 0, dummy = 0;
2850 /* skip version/flags */
2851 if (!gst_byte_reader_skip (&trex_data, 4))
2853 if (!gst_byte_reader_get_uint32_be (&trex_data, &id))
2855 if (id != stream->track_id)
2857 /* sample description index; ignore */
2858 if (!gst_byte_reader_get_uint32_be (&trex_data, &dummy))
2860 if (!gst_byte_reader_get_uint32_be (&trex_data, &dur))
2862 if (!gst_byte_reader_get_uint32_be (&trex_data, &size))
2864 if (!gst_byte_reader_get_uint32_be (&trex_data, &flags))
2867 GST_DEBUG_OBJECT (qtdemux, "fragment defaults for stream %d; "
2868 "duration %d, size %d, flags 0x%x", stream->track_id,
2871 stream->parsed_trex = TRUE;
2872 stream->def_sample_duration = dur;
2873 stream->def_sample_size = size;
2874 stream->def_sample_flags = flags;
2877 /* iterate all siblings */
2878 trex = qtdemux_tree_get_sibling_by_type_full (trex, FOURCC_trex,
2884 *ds_duration = stream->def_sample_duration;
2885 *ds_size = stream->def_sample_size;
2886 *ds_flags = stream->def_sample_flags;
2888 /* even then, above values are better than random ... */
2889 if (G_UNLIKELY (!stream->parsed_trex)) {
2890 GST_WARNING_OBJECT (qtdemux,
2891 "failed to find fragment defaults for stream %d", stream->track_id);
2898 /* This method should be called whenever a more accurate duration might
2899 * have been found. It will update all relevant variables if/where needed
2902 check_update_duration (GstQTDemux * qtdemux, GstClockTime duration)
2906 GstClockTime prevdur;
2908 movdur = GSTTIME_TO_QTTIME (qtdemux, duration);
2910 if (movdur > qtdemux->duration) {
2911 prevdur = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
2912 GST_DEBUG_OBJECT (qtdemux,
2913 "Updating total duration to %" GST_TIME_FORMAT " was %" GST_TIME_FORMAT,
2914 GST_TIME_ARGS (duration), GST_TIME_ARGS (prevdur));
2915 qtdemux->duration = movdur;
2916 GST_DEBUG_OBJECT (qtdemux,
2917 "qtdemux->segment.duration: %" GST_TIME_FORMAT " .stop: %"
2918 GST_TIME_FORMAT, GST_TIME_ARGS (qtdemux->segment.duration),
2919 GST_TIME_ARGS (qtdemux->segment.stop));
2920 if (qtdemux->segment.duration == prevdur) {
2921 /* If the current segment has duration/stop identical to previous duration
2922 * update them also (because they were set at that point in time with
2923 * the wrong duration */
2924 /* We convert the value *from* the timescale version to avoid rounding errors */
2925 GstClockTime fixeddur = QTTIME_TO_GSTTIME (qtdemux, movdur);
2926 GST_DEBUG_OBJECT (qtdemux, "Updated segment.duration and segment.stop");
2927 qtdemux->segment.duration = fixeddur;
2928 qtdemux->segment.stop = fixeddur;
2931 for (i = 0; i < qtdemux->n_streams; i++) {
2932 QtDemuxStream *stream = qtdemux->streams[i];
2934 movdur = GSTTIME_TO_QTSTREAMTIME (stream, duration);
2935 if (movdur > stream->duration) {
2936 GST_DEBUG_OBJECT (qtdemux,
2937 "Updating stream #%d duration to %" GST_TIME_FORMAT, i,
2938 GST_TIME_ARGS (duration));
2939 stream->duration = movdur;
2940 if (stream->dummy_segment) {
2941 /* Update all dummy values to new duration */
2942 stream->segments[0].stop_time = duration;
2943 stream->segments[0].duration = duration;
2944 stream->segments[0].media_stop = duration;
2946 /* let downstream know we possibly have a new stop time */
2947 if (stream->segment_index != -1) {
2950 if (qtdemux->segment.rate >= 0) {
2951 pos = stream->segment.start;
2953 pos = stream->segment.stop;
2956 gst_qtdemux_stream_update_segment (qtdemux, stream,
2957 stream->segment_index, pos, NULL, NULL);
2966 qtdemux_parse_trun (GstQTDemux * qtdemux, GstByteReader * trun,
2967 QtDemuxStream * stream, guint32 d_sample_duration, guint32 d_sample_size,
2968 guint32 d_sample_flags, gint64 moof_offset, gint64 moof_length,
2969 gint64 * base_offset, gint64 * running_offset, gint64 decode_ts)
2971 GstClockTime gst_ts = GST_CLOCK_TIME_NONE;
2973 gint32 data_offset = 0;
2974 guint32 flags = 0, first_flags = 0, samples_count = 0;
2977 guint entry_size, dur_offset, size_offset, flags_offset = 0, ct_offset = 0;
2978 QtDemuxSample *sample;
2979 gboolean ismv = FALSE;
2981 GST_LOG_OBJECT (qtdemux, "parsing trun stream %d; "
2982 "default dur %d, size %d, flags 0x%x, base offset %" G_GINT64_FORMAT ", "
2983 "decode ts %" G_GINT64_FORMAT, stream->track_id, d_sample_duration,
2984 d_sample_size, d_sample_flags, *base_offset, decode_ts);
2986 if (stream->pending_seek && moof_offset < stream->pending_seek->moof_offset) {
2987 GST_INFO_OBJECT (stream->pad, "skipping trun before seek target fragment");
2991 /* presence of stss or not can't really tell us much,
2992 * and flags and so on tend to be marginally reliable in these files */
2993 if (stream->subtype == FOURCC_soun) {
2994 GST_DEBUG_OBJECT (qtdemux,
2995 "sound track in fragmented file; marking all keyframes");
2996 stream->all_keyframe = TRUE;
2999 if (!gst_byte_reader_skip (trun, 1) ||
3000 !gst_byte_reader_get_uint24_be (trun, &flags))
3003 if (!gst_byte_reader_get_uint32_be (trun, &samples_count))
3006 if (flags & TR_DATA_OFFSET) {
3007 /* note this is really signed */
3008 if (!gst_byte_reader_get_int32_be (trun, &data_offset))
3010 GST_LOG_OBJECT (qtdemux, "trun data offset %d", data_offset);
3011 /* default base offset = first byte of moof */
3012 if (*base_offset == -1) {
3013 GST_LOG_OBJECT (qtdemux, "base_offset at moof");
3014 *base_offset = moof_offset;
3016 *running_offset = *base_offset + data_offset;
3018 /* if no offset at all, that would mean data starts at moof start,
3019 * which is a bit wrong and is ismv crappy way, so compensate
3020 * assuming data is in mdat following moof */
3021 if (*base_offset == -1) {
3022 *base_offset = moof_offset + moof_length + 8;
3023 GST_LOG_OBJECT (qtdemux, "base_offset assumed in mdat after moof");
3026 if (*running_offset == -1)
3027 *running_offset = *base_offset;
3030 GST_LOG_OBJECT (qtdemux, "running offset now %" G_GINT64_FORMAT,
3032 GST_LOG_OBJECT (qtdemux, "trun offset %d, flags 0x%x, entries %d",
3033 data_offset, flags, samples_count);
3035 if (flags & TR_FIRST_SAMPLE_FLAGS) {
3036 if (G_UNLIKELY (flags & TR_SAMPLE_FLAGS)) {
3037 GST_DEBUG_OBJECT (qtdemux,
3038 "invalid flags; SAMPLE and FIRST_SAMPLE present, discarding latter");
3039 flags ^= TR_FIRST_SAMPLE_FLAGS;
3041 if (!gst_byte_reader_get_uint32_be (trun, &first_flags))
3043 GST_LOG_OBJECT (qtdemux, "first flags: 0x%x", first_flags);
3047 /* FIXME ? spec says other bits should also be checked to determine
3048 * entry size (and prefix size for that matter) */
3050 dur_offset = size_offset = 0;
3051 if (flags & TR_SAMPLE_DURATION) {
3052 GST_LOG_OBJECT (qtdemux, "entry duration present");
3053 dur_offset = entry_size;
3056 if (flags & TR_SAMPLE_SIZE) {
3057 GST_LOG_OBJECT (qtdemux, "entry size present");
3058 size_offset = entry_size;
3061 if (flags & TR_SAMPLE_FLAGS) {
3062 GST_LOG_OBJECT (qtdemux, "entry flags present");
3063 flags_offset = entry_size;
3066 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
3067 GST_LOG_OBJECT (qtdemux, "entry ct offset present");
3068 ct_offset = entry_size;
3072 if (!qt_atom_parser_has_chunks (trun, samples_count, entry_size))
3074 data = (guint8 *) gst_byte_reader_peek_data_unchecked (trun);
3076 if (stream->n_samples + samples_count >=
3077 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample))
3080 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
3081 stream->n_samples + samples_count, (guint) sizeof (QtDemuxSample),
3082 (stream->n_samples + samples_count) *
3083 sizeof (QtDemuxSample) / (1024.0 * 1024.0));
3085 /* create a new array of samples if it's the first sample parsed */
3086 if (stream->n_samples == 0) {
3087 g_assert (stream->samples == NULL);
3088 stream->samples = g_try_new0 (QtDemuxSample, samples_count);
3089 /* or try to reallocate it with space enough to insert the new samples */
3091 stream->samples = g_try_renew (QtDemuxSample, stream->samples,
3092 stream->n_samples + samples_count);
3093 if (stream->samples == NULL)
3096 if (qtdemux->fragment_start != -1) {
3097 timestamp = GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->fragment_start);
3098 qtdemux->fragment_start = -1;
3100 if (stream->n_samples == 0) {
3101 if (decode_ts > 0) {
3102 timestamp = decode_ts;
3103 } else if (stream->pending_seek != NULL) {
3104 /* if we don't have a timestamp from a tfdt box, we'll use the one
3105 * from the mfra seek table */
3106 GST_INFO_OBJECT (stream->pad, "pending seek ts = %" GST_TIME_FORMAT,
3107 GST_TIME_ARGS (stream->pending_seek->ts));
3109 /* FIXME: this is not fully correct, the timestamp refers to the random
3110 * access sample refered to in the tfra entry, which may not necessarily
3111 * be the first sample in the tfrag/trun (but hopefully/usually is) */
3112 timestamp = GSTTIME_TO_QTSTREAMTIME (stream, stream->pending_seek->ts);
3117 gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
3118 GST_INFO_OBJECT (stream->pad, "first sample ts %" GST_TIME_FORMAT,
3119 GST_TIME_ARGS (gst_ts));
3121 /* subsequent fragments extend stream */
3123 stream->samples[stream->n_samples - 1].timestamp +
3124 stream->samples[stream->n_samples - 1].duration;
3126 gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
3127 GST_INFO_OBJECT (qtdemux, "first sample ts %" GST_TIME_FORMAT
3128 " (extends previous samples)", GST_TIME_ARGS (gst_ts));
3132 sample = stream->samples + stream->n_samples;
3133 for (i = 0; i < samples_count; i++) {
3134 guint32 dur, size, sflags, ct;
3136 /* first read sample data */
3137 if (flags & TR_SAMPLE_DURATION) {
3138 dur = QT_UINT32 (data + dur_offset);
3140 dur = d_sample_duration;
3142 if (flags & TR_SAMPLE_SIZE) {
3143 size = QT_UINT32 (data + size_offset);
3145 size = d_sample_size;
3147 if (flags & TR_FIRST_SAMPLE_FLAGS) {
3149 sflags = first_flags;
3151 sflags = d_sample_flags;
3153 } else if (flags & TR_SAMPLE_FLAGS) {
3154 sflags = QT_UINT32 (data + flags_offset);
3156 sflags = d_sample_flags;
3158 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
3159 ct = QT_UINT32 (data + ct_offset);
3165 /* fill the sample information */
3166 sample->offset = *running_offset;
3167 sample->pts_offset = ct;
3168 sample->size = size;
3169 sample->timestamp = timestamp;
3170 sample->duration = dur;
3171 /* sample-is-difference-sample */
3172 /* ismv seems to use 0x40 for keyframe, 0xc0 for non-keyframe,
3173 * now idea how it relates to bitfield other than massive LE/BE confusion */
3174 sample->keyframe = ismv ? ((sflags & 0xff) == 0x40) : !(sflags & 0x10000);
3175 *running_offset += size;
3177 stream->duration_moof += dur;
3181 /* Update total duration if needed */
3182 check_update_duration (qtdemux, QTSTREAMTIME_TO_GSTTIME (stream, timestamp));
3184 stream->n_samples += samples_count;
3185 stream->n_samples_moof += samples_count;
3187 if (stream->pending_seek != NULL)
3188 stream->pending_seek = NULL;
3194 GST_WARNING_OBJECT (qtdemux, "failed to parse trun");
3199 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
3205 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
3206 "be larger than %uMB (broken file?)", stream->n_samples,
3207 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
3212 /* find stream with @id */
3213 static inline QtDemuxStream *
3214 qtdemux_find_stream (GstQTDemux * qtdemux, guint32 id)
3216 QtDemuxStream *stream;
3220 if (G_UNLIKELY (!id)) {
3221 GST_DEBUG_OBJECT (qtdemux, "invalid track id 0");
3225 /* try to get it fast and simple */
3226 if (G_LIKELY (id <= qtdemux->n_streams)) {
3227 stream = qtdemux->streams[id - 1];
3228 if (G_LIKELY (stream->track_id == id))
3232 /* linear search otherwise */
3233 for (i = 0; i < qtdemux->n_streams; i++) {
3234 stream = qtdemux->streams[i];
3235 if (stream->track_id == id)
3238 if (qtdemux->mss_mode) {
3239 /* mss should have only 1 stream anyway */
3240 return qtdemux->streams[0];
3247 qtdemux_parse_mfhd (GstQTDemux * qtdemux, GstByteReader * mfhd,
3248 guint32 * fragment_number)
3250 if (!gst_byte_reader_skip (mfhd, 4))
3252 if (!gst_byte_reader_get_uint32_be (mfhd, fragment_number))
3257 GST_WARNING_OBJECT (qtdemux, "Failed to parse mfhd atom");
3263 qtdemux_parse_tfhd (GstQTDemux * qtdemux, GstByteReader * tfhd,
3264 QtDemuxStream ** stream, guint32 * default_sample_duration,
3265 guint32 * default_sample_size, guint32 * default_sample_flags,
3266 gint64 * base_offset)
3269 guint32 track_id = 0;
3271 if (!gst_byte_reader_skip (tfhd, 1) ||
3272 !gst_byte_reader_get_uint24_be (tfhd, &flags))
3275 if (!gst_byte_reader_get_uint32_be (tfhd, &track_id))
3278 *stream = qtdemux_find_stream (qtdemux, track_id);
3279 if (G_UNLIKELY (!*stream))
3280 goto unknown_stream;
3282 if (flags & TF_DEFAULT_BASE_IS_MOOF)
3283 *base_offset = qtdemux->moof_offset;
3285 if (flags & TF_BASE_DATA_OFFSET)
3286 if (!gst_byte_reader_get_uint64_be (tfhd, (guint64 *) base_offset))
3289 /* obtain stream defaults */
3290 qtdemux_parse_trex (qtdemux, *stream,
3291 default_sample_duration, default_sample_size, default_sample_flags);
3293 /* FIXME: Handle TF_SAMPLE_DESCRIPTION_INDEX properly */
3294 if (flags & TF_SAMPLE_DESCRIPTION_INDEX)
3295 if (!gst_byte_reader_skip (tfhd, 4))
3298 if (flags & TF_DEFAULT_SAMPLE_DURATION)
3299 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_duration))
3302 if (flags & TF_DEFAULT_SAMPLE_SIZE)
3303 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_size))
3306 if (flags & TF_DEFAULT_SAMPLE_FLAGS)
3307 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_flags))
3314 GST_WARNING_OBJECT (qtdemux, "invalid track fragment header");
3319 GST_DEBUG_OBJECT (qtdemux, "unknown stream in tfhd");
3325 qtdemux_parse_tfdt (GstQTDemux * qtdemux, GstByteReader * br,
3326 guint64 * decode_time)
3328 guint32 version = 0;
3330 if (!gst_byte_reader_get_uint32_be (br, &version))
3335 if (!gst_byte_reader_get_uint64_be (br, decode_time))
3338 guint32 dec_time = 0;
3339 if (!gst_byte_reader_get_uint32_be (br, &dec_time))
3341 *decode_time = dec_time;
3344 GST_INFO_OBJECT (qtdemux, "Track fragment decode time: %" G_GUINT64_FORMAT,
3351 GST_DEBUG_OBJECT (qtdemux, "parsing tfdt failed");
3356 /* Returns a pointer to a GstStructure containing the properties of
3357 * the stream sample identified by @sample_index. The caller must unref
3358 * the returned object after use. Returns NULL if unsuccessful. */
3359 static GstStructure *
3360 qtdemux_get_cenc_sample_properties (GstQTDemux * qtdemux,
3361 QtDemuxStream * stream, guint sample_index)
3363 QtDemuxCencSampleSetInfo *info = NULL;
3365 g_return_val_if_fail (stream != NULL, NULL);
3366 g_return_val_if_fail (stream->protected, NULL);
3367 g_return_val_if_fail (stream->protection_scheme_info != NULL, NULL);
3369 info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
3371 /* Currently, cenc properties for groups of samples are not supported, so
3372 * simply return a copy of the default sample properties */
3373 return gst_structure_copy (info->default_properties);
3376 /* Parses the sizes of sample auxiliary information contained within a stream,
3377 * as given in a saiz box. Returns array of sample_count guint8 size values,
3378 * or NULL on failure */
3380 qtdemux_parse_saiz (GstQTDemux * qtdemux, QtDemuxStream * stream,
3381 GstByteReader * br, guint32 * sample_count)
3385 guint8 default_info_size;
3387 g_return_val_if_fail (qtdemux != NULL, NULL);
3388 g_return_val_if_fail (stream != NULL, NULL);
3389 g_return_val_if_fail (br != NULL, NULL);
3390 g_return_val_if_fail (sample_count != NULL, NULL);
3392 if (!gst_byte_reader_get_uint32_be (br, &flags))
3396 /* aux_info_type and aux_info_type_parameter are ignored */
3397 if (!gst_byte_reader_skip (br, 8))
3401 if (!gst_byte_reader_get_uint8 (br, &default_info_size))
3403 GST_DEBUG_OBJECT (qtdemux, "default_info_size: %u", default_info_size);
3405 if (!gst_byte_reader_get_uint32_be (br, sample_count))
3407 GST_DEBUG_OBJECT (qtdemux, "sample_count: %u", *sample_count);
3410 if (default_info_size == 0) {
3411 if (!gst_byte_reader_dup_data (br, *sample_count, &info_sizes)) {
3415 info_sizes = g_new (guint8, *sample_count);
3416 memset (info_sizes, default_info_size, *sample_count);
3422 /* Parses the offset of sample auxiliary information contained within a stream,
3423 * as given in a saio box. Returns TRUE if successful; FALSE otherwise. */
3425 qtdemux_parse_saio (GstQTDemux * qtdemux, QtDemuxStream * stream,
3426 GstByteReader * br, guint32 * info_type, guint32 * info_type_parameter,
3431 guint32 aux_info_type = 0;
3432 guint32 aux_info_type_parameter = 0;
3433 guint32 entry_count;
3436 const guint8 *aux_info_type_data = NULL;
3438 g_return_val_if_fail (qtdemux != NULL, FALSE);
3439 g_return_val_if_fail (stream != NULL, FALSE);
3440 g_return_val_if_fail (br != NULL, FALSE);
3441 g_return_val_if_fail (offset != NULL, FALSE);
3443 if (!gst_byte_reader_get_uint8 (br, &version))
3446 if (!gst_byte_reader_get_uint24_be (br, &flags))
3451 if (!gst_byte_reader_get_data (br, 4, &aux_info_type_data))
3453 aux_info_type = QT_FOURCC (aux_info_type_data);
3455 if (!gst_byte_reader_get_uint32_be (br, &aux_info_type_parameter))
3457 } else if (stream->protected) {
3458 aux_info_type = stream->protection_scheme_type;
3460 aux_info_type = stream->fourcc;
3464 *info_type = aux_info_type;
3465 if (info_type_parameter)
3466 *info_type_parameter = aux_info_type_parameter;
3468 GST_DEBUG_OBJECT (qtdemux, "aux_info_type: '%" GST_FOURCC_FORMAT "', "
3469 "aux_info_type_parameter: %#06x",
3470 GST_FOURCC_ARGS (aux_info_type), aux_info_type_parameter);
3472 if (!gst_byte_reader_get_uint32_be (br, &entry_count))
3475 if (entry_count != 1) {
3476 GST_ERROR_OBJECT (qtdemux, "multiple offsets are not supported");
3481 if (!gst_byte_reader_get_uint32_be (br, &off_32))
3483 *offset = (guint64) off_32;
3485 if (!gst_byte_reader_get_uint64_be (br, &off_64))
3490 GST_DEBUG_OBJECT (qtdemux, "offset: %" G_GUINT64_FORMAT, *offset);
3495 qtdemux_gst_structure_free (GstStructure * gststructure)
3498 gst_structure_free (gststructure);
3502 /* Parses auxiliary information relating to samples protected using Common
3503 * Encryption (cenc); the format of this information is defined in
3504 * ISO/IEC 23001-7. Returns TRUE if successful; FALSE otherwise. */
3506 qtdemux_parse_cenc_aux_info (GstQTDemux * qtdemux, QtDemuxStream * stream,
3507 GstByteReader * br, guint8 * info_sizes, guint32 sample_count)
3509 QtDemuxCencSampleSetInfo *ss_info = NULL;
3513 g_return_val_if_fail (qtdemux != NULL, FALSE);
3514 g_return_val_if_fail (stream != NULL, FALSE);
3515 g_return_val_if_fail (br != NULL, FALSE);
3516 g_return_val_if_fail (stream->protected, FALSE);
3517 g_return_val_if_fail (stream->protection_scheme_info != NULL, FALSE);
3519 ss_info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
3521 if (ss_info->crypto_info) {
3522 GST_LOG_OBJECT (qtdemux, "unreffing existing crypto_info");
3523 g_ptr_array_free (ss_info->crypto_info, TRUE);
3526 ss_info->crypto_info =
3527 g_ptr_array_new_full (sample_count,
3528 (GDestroyNotify) qtdemux_gst_structure_free);
3530 for (i = 0; i < sample_count; ++i) {
3531 GstStructure *properties;
3532 guint16 n_subsamples = 0;
3537 properties = qtdemux_get_cenc_sample_properties (qtdemux, stream, i);
3538 if (properties == NULL) {
3539 GST_ERROR_OBJECT (qtdemux, "failed to get properties for sample %u", i);
3542 if (!gst_structure_get_uint (properties, "iv_size", &iv_size)) {
3543 GST_ERROR_OBJECT (qtdemux, "failed to get iv_size for sample %u", i);
3544 gst_structure_free (properties);
3547 if (!gst_byte_reader_dup_data (br, iv_size, &data)) {
3548 GST_ERROR_OBJECT (qtdemux, "failed to get IV for sample %u", i);
3549 gst_structure_free (properties);
3552 buf = gst_buffer_new_wrapped (data, iv_size);
3553 gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL);
3554 gst_buffer_unref (buf);
3555 size = info_sizes[i];
3556 if (size > iv_size) {
3557 if (!gst_byte_reader_get_uint16_be (br, &n_subsamples)
3558 || !(n_subsamples > 0)) {
3559 gst_structure_free (properties);
3560 GST_ERROR_OBJECT (qtdemux,
3561 "failed to get subsample count for sample %u", i);
3564 GST_LOG_OBJECT (qtdemux, "subsample count: %u", n_subsamples);
3565 if (!gst_byte_reader_dup_data (br, n_subsamples * 6, &data)) {
3566 GST_ERROR_OBJECT (qtdemux, "failed to get subsample data for sample %u",
3568 gst_structure_free (properties);
3571 buf = gst_buffer_new_wrapped (data, n_subsamples * 6);
3573 gst_structure_free (properties);
3576 gst_structure_set (properties,
3577 "subsample_count", G_TYPE_UINT, n_subsamples,
3578 "subsamples", GST_TYPE_BUFFER, buf, NULL);
3579 gst_buffer_unref (buf);
3581 gst_structure_set (properties, "subsample_count", G_TYPE_UINT, 0, NULL);
3583 g_ptr_array_add (ss_info->crypto_info, properties);
3588 /* Converts a UUID in raw byte form to a string representation, as defined in
3589 * RFC 4122. The caller takes ownership of the returned string and is
3590 * responsible for freeing it after use. */
3592 qtdemux_uuid_bytes_to_string (gconstpointer uuid_bytes)
3594 const guint8 *uuid = (const guint8 *) uuid_bytes;
3596 return g_strdup_printf ("%02x%02x%02x%02x-%02x%02x-%02x%02x-"
3597 "%02x%02x-%02x%02x%02x%02x%02x%02x",
3598 uuid[0], uuid[1], uuid[2], uuid[3],
3599 uuid[4], uuid[5], uuid[6], uuid[7],
3600 uuid[8], uuid[9], uuid[10], uuid[11],
3601 uuid[12], uuid[13], uuid[14], uuid[15]);
3604 /* Parses a Protection System Specific Header box (pssh), as defined in the
3605 * Common Encryption (cenc) standard (ISO/IEC 23001-7), which contains
3606 * information needed by a specific content protection system in order to
3607 * decrypt cenc-protected tracks. Returns TRUE if successful; FALSE
3610 qtdemux_parse_pssh (GstQTDemux * qtdemux, GNode * node)
3612 gchar *sysid_string;
3613 guint32 pssh_size = QT_UINT32 (node->data);
3614 GstBuffer *pssh = NULL;
3615 GstEvent *event = NULL;
3616 guint32 parent_box_type;
3619 if (G_UNLIKELY (pssh_size < 32U)) {
3620 GST_ERROR_OBJECT (qtdemux, "invalid box size");
3625 qtdemux_uuid_bytes_to_string ((const guint8 *) node->data + 12);
3627 gst_qtdemux_append_protection_system_id (qtdemux, sysid_string);
3629 pssh = gst_buffer_new_wrapped (g_memdup (node->data, pssh_size), pssh_size);
3630 GST_LOG_OBJECT (qtdemux, "cenc pssh size: %" G_GSIZE_FORMAT,
3631 gst_buffer_get_size (pssh));
3633 parent_box_type = QT_FOURCC ((const guint8 *) node->parent->data + 4);
3635 /* Push an event containing the pssh box onto the queues of all streams. */
3636 event = gst_event_new_protection (sysid_string, pssh,
3637 (parent_box_type == FOURCC_moov) ? "isobmff/moov" : "isobmff/moof");
3638 for (i = 0; i < qtdemux->n_streams; ++i) {
3639 g_queue_push_tail (&qtdemux->streams[i]->protection_scheme_event_queue,
3640 gst_event_ref (event));
3642 g_free (sysid_string);
3643 gst_event_unref (event);
3644 gst_buffer_unref (pssh);
3649 qtdemux_parse_moof (GstQTDemux * qtdemux, const guint8 * buffer, guint length,
3650 guint64 moof_offset, QtDemuxStream * stream)
3652 GNode *moof_node, *traf_node, *tfhd_node, *trun_node, *tfdt_node, *mfhd_node;
3654 GstByteReader mfhd_data, trun_data, tfhd_data, tfdt_data;
3655 GNode *saiz_node, *saio_node, *pssh_node;
3656 GstByteReader saiz_data, saio_data;
3657 guint32 ds_size = 0, ds_duration = 0, ds_flags = 0;
3658 gint64 base_offset, running_offset;
3661 /* NOTE @stream ignored */
3663 moof_node = g_node_new ((guint8 *) buffer);
3664 qtdemux_parse_node (qtdemux, moof_node, buffer, length);
3665 qtdemux_node_dump (qtdemux, moof_node);
3667 /* Get fragment number from mfhd and check it's valid */
3669 qtdemux_tree_get_child_by_type_full (moof_node, FOURCC_mfhd, &mfhd_data);
3670 if (mfhd_node == NULL)
3672 if (!qtdemux_parse_mfhd (qtdemux, &mfhd_data, &frag_num))
3674 GST_DEBUG_OBJECT (qtdemux, "Fragment #%d", frag_num);
3676 /* unknown base_offset to start with */
3677 base_offset = running_offset = -1;
3678 traf_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_traf);
3680 guint64 decode_time = 0;
3682 /* Fragment Header node */
3684 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfhd,
3688 if (!qtdemux_parse_tfhd (qtdemux, &tfhd_data, &stream, &ds_duration,
3689 &ds_size, &ds_flags, &base_offset))
3692 /* The following code assumes at most a single set of sample auxiliary
3693 * data in the fragment (consisting of a saiz box and a corresponding saio
3694 * box); in theory, however, there could be multiple sets of sample
3695 * auxiliary data in a fragment. */
3697 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saiz,
3700 guint32 info_type = 0;
3702 guint32 info_type_parameter = 0;
3704 g_free (qtdemux->cenc_aux_info_sizes);
3706 qtdemux->cenc_aux_info_sizes =
3707 qtdemux_parse_saiz (qtdemux, stream, &saiz_data,
3708 &qtdemux->cenc_aux_sample_count);
3709 if (qtdemux->cenc_aux_info_sizes == NULL) {
3710 GST_ERROR_OBJECT (qtdemux, "failed to parse saiz box");
3714 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saio,
3717 GST_ERROR_OBJECT (qtdemux, "saiz box without a corresponding saio box");
3718 g_free (qtdemux->cenc_aux_info_sizes);
3719 qtdemux->cenc_aux_info_sizes = NULL;
3723 if (G_UNLIKELY (!qtdemux_parse_saio (qtdemux, stream, &saio_data,
3724 &info_type, &info_type_parameter, &offset))) {
3725 GST_ERROR_OBJECT (qtdemux, "failed to parse saio box");
3726 g_free (qtdemux->cenc_aux_info_sizes);
3727 qtdemux->cenc_aux_info_sizes = NULL;
3730 if (base_offset > -1 && base_offset > qtdemux->moof_offset)
3731 offset += (guint64) (base_offset - qtdemux->moof_offset);
3732 if (info_type == FOURCC_cenc && info_type_parameter == 0U) {
3734 if (offset > length) {
3735 GST_DEBUG_OBJECT (qtdemux, "cenc auxiliary info stored out of moof");
3736 qtdemux->cenc_aux_info_offset = offset;
3738 gst_byte_reader_init (&br, buffer + offset, length - offset);
3739 if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
3740 qtdemux->cenc_aux_info_sizes,
3741 qtdemux->cenc_aux_sample_count)) {
3742 GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
3743 g_free (qtdemux->cenc_aux_info_sizes);
3744 qtdemux->cenc_aux_info_sizes = NULL;
3752 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfdt,
3755 /* We'll use decode_time to interpolate timestamps
3756 * in case the input timestamps are missing */
3757 qtdemux_parse_tfdt (qtdemux, &tfdt_data, &decode_time);
3759 GST_DEBUG_OBJECT (qtdemux, "decode time %" G_GINT64_FORMAT
3760 " (%" GST_TIME_FORMAT ")", decode_time,
3761 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, decode_time)));
3763 /* Discard the fragment buffer timestamp info to avoid using it.
3764 * Rely on tfdt instead as it is more accurate than the timestamp
3765 * that is fetched from a manifest/playlist and is usually
3767 qtdemux->fragment_start = -1;
3770 if (G_UNLIKELY (!stream)) {
3771 /* we lost track of offset, we'll need to regain it,
3772 * but can delay complaining until later or avoid doing so altogether */
3776 if (G_UNLIKELY (base_offset < -1))
3779 if (qtdemux->upstream_format_is_time)
3780 gst_qtdemux_stream_flush_samples_data (qtdemux, stream);
3782 /* initialise moof sample data */
3783 stream->n_samples_moof = 0;
3784 stream->duration_moof = 0;
3786 /* Track Run node */
3788 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_trun,
3791 qtdemux_parse_trun (qtdemux, &trun_data, stream,
3792 ds_duration, ds_size, ds_flags, moof_offset, length, &base_offset,
3793 &running_offset, decode_time);
3794 /* iterate all siblings */
3795 trun_node = qtdemux_tree_get_sibling_by_type_full (trun_node, FOURCC_trun,
3799 uuid_node = qtdemux_tree_get_child_by_type (traf_node, FOURCC_uuid);
3801 guint8 *uuid_buffer = (guint8 *) uuid_node->data;
3802 guint32 box_length = QT_UINT32 (uuid_buffer);
3804 qtdemux_parse_uuid (qtdemux, uuid_buffer, box_length);
3807 /* if no new base_offset provided for next traf,
3808 * base is end of current traf */
3809 base_offset = running_offset;
3810 running_offset = -1;
3812 if (stream->n_samples_moof && stream->duration_moof)
3813 stream->new_caps = TRUE;
3816 /* iterate all siblings */
3817 traf_node = qtdemux_tree_get_sibling_by_type (traf_node, FOURCC_traf);
3820 /* parse any protection system info */
3821 pssh_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_pssh);
3823 GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
3824 qtdemux_parse_pssh (qtdemux, pssh_node);
3825 pssh_node = qtdemux_tree_get_sibling_by_type (pssh_node, FOURCC_pssh);
3828 g_node_destroy (moof_node);
3833 GST_DEBUG_OBJECT (qtdemux, "missing tfhd box");
3838 GST_DEBUG_OBJECT (qtdemux, "Missing mfhd box");
3843 GST_DEBUG_OBJECT (qtdemux, "lost offset");
3848 g_node_destroy (moof_node);
3849 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
3850 (_("This file is corrupt and cannot be played.")), (NULL));
3856 /* might be used if some day we actually use mfra & co
3857 * for random access to fragments,
3858 * but that will require quite some modifications and much less relying
3859 * on a sample array */
3863 qtdemux_parse_tfra (GstQTDemux * qtdemux, GNode * tfra_node)
3865 QtDemuxStream *stream;
3866 guint32 ver_flags, track_id, len, num_entries, i;
3867 guint value_size, traf_size, trun_size, sample_size;
3868 guint64 time = 0, moof_offset = 0;
3870 GstBuffer *buf = NULL;
3875 gst_byte_reader_init (&tfra, tfra_node->data, QT_UINT32 (tfra_node->data));
3877 if (!gst_byte_reader_skip (&tfra, 8))
3880 if (!gst_byte_reader_get_uint32_be (&tfra, &ver_flags))
3883 if (!gst_byte_reader_get_uint32_be (&tfra, &track_id)
3884 || !gst_byte_reader_get_uint32_be (&tfra, &len)
3885 || !gst_byte_reader_get_uint32_be (&tfra, &num_entries))
3888 GST_DEBUG_OBJECT (qtdemux, "parsing tfra box for track id %u", track_id);
3890 stream = qtdemux_find_stream (qtdemux, track_id);
3892 goto unknown_trackid;
3894 value_size = ((ver_flags >> 24) == 1) ? sizeof (guint64) : sizeof (guint32);
3895 sample_size = (len & 3) + 1;
3896 trun_size = ((len & 12) >> 2) + 1;
3897 traf_size = ((len & 48) >> 4) + 1;
3899 GST_DEBUG_OBJECT (qtdemux, "%u entries, sizes: value %u, traf %u, trun %u, "
3900 "sample %u", num_entries, value_size, traf_size, trun_size, sample_size);
3902 if (num_entries == 0)
3905 if (!qt_atom_parser_has_chunks (&tfra, num_entries,
3906 value_size + value_size + traf_size + trun_size + sample_size))
3909 g_free (stream->ra_entries);
3910 stream->ra_entries = g_new (QtDemuxRandomAccessEntry, num_entries);
3911 stream->n_ra_entries = num_entries;
3913 for (i = 0; i < num_entries; i++) {
3914 qt_atom_parser_get_offset (&tfra, value_size, &time);
3915 qt_atom_parser_get_offset (&tfra, value_size, &moof_offset);
3916 qt_atom_parser_get_uint_with_size_unchecked (&tfra, traf_size);
3917 qt_atom_parser_get_uint_with_size_unchecked (&tfra, trun_size);
3918 qt_atom_parser_get_uint_with_size_unchecked (&tfra, sample_size);
3920 time = QTSTREAMTIME_TO_GSTTIME (stream, time);
3922 GST_LOG_OBJECT (qtdemux, "fragment time: %" GST_TIME_FORMAT ", "
3923 " moof_offset: %" G_GUINT64_FORMAT, GST_TIME_ARGS (time), moof_offset);
3925 stream->ra_entries[i].ts = time;
3926 stream->ra_entries[i].moof_offset = moof_offset;
3928 /* don't want to go through the entire file and read all moofs at startup */
3930 ret = gst_qtdemux_pull_atom (qtdemux, moof_offset, 0, &buf);
3931 if (ret != GST_FLOW_OK)
3933 qtdemux_parse_moof (qtdemux, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf),
3934 moof_offset, stream);
3935 gst_buffer_unref (buf);
3939 check_update_duration (qtdemux, time);
3946 GST_WARNING_OBJECT (qtdemux, "Couldn't find stream for track %u", track_id);
3951 GST_WARNING_OBJECT (qtdemux, "broken traf box, ignoring");
3956 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
3962 qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux)
3964 GstMapInfo mfro_map = GST_MAP_INFO_INIT;
3965 GstMapInfo mfra_map = GST_MAP_INFO_INIT;
3966 GstBuffer *mfro = NULL, *mfra = NULL;
3968 gboolean ret = FALSE;
3969 GNode *mfra_node, *tfra_node;
3970 guint64 mfra_offset = 0;
3971 guint32 fourcc, mfra_size;
3974 /* query upstream size in bytes */
3975 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &len))
3976 goto size_query_failed;
3978 /* mfro box should be at the very end of the file */
3979 flow = gst_qtdemux_pull_atom (qtdemux, len - 16, 16, &mfro);
3980 if (flow != GST_FLOW_OK)
3983 gst_buffer_map (mfro, &mfro_map, GST_MAP_READ);
3985 fourcc = QT_FOURCC (mfro_map.data + 4);
3986 if (fourcc != FOURCC_mfro)
3989 GST_INFO_OBJECT (qtdemux, "Found mfro box");
3990 if (mfro_map.size < 16)
3991 goto invalid_mfro_size;
3993 mfra_size = QT_UINT32 (mfro_map.data + 12);
3994 if (mfra_size >= len)
3995 goto invalid_mfra_size;
3997 mfra_offset = len - mfra_size;
3999 GST_INFO_OBJECT (qtdemux, "mfra offset: %" G_GUINT64_FORMAT ", size %u",
4000 mfra_offset, mfra_size);
4002 /* now get and parse mfra box */
4003 flow = gst_qtdemux_pull_atom (qtdemux, mfra_offset, mfra_size, &mfra);
4004 if (flow != GST_FLOW_OK)
4007 gst_buffer_map (mfra, &mfra_map, GST_MAP_READ);
4009 mfra_node = g_node_new ((guint8 *) mfra_map.data);
4010 qtdemux_parse_node (qtdemux, mfra_node, mfra_map.data, mfra_map.size);
4012 tfra_node = qtdemux_tree_get_child_by_type (mfra_node, FOURCC_tfra);
4015 qtdemux_parse_tfra (qtdemux, tfra_node);
4016 /* iterate all siblings */
4017 tfra_node = qtdemux_tree_get_sibling_by_type (tfra_node, FOURCC_tfra);
4019 g_node_destroy (mfra_node);
4021 GST_INFO_OBJECT (qtdemux, "parsed movie fragment random access box (mfra)");
4027 if (mfro_map.memory != NULL)
4028 gst_buffer_unmap (mfro, &mfro_map);
4029 gst_buffer_unref (mfro);
4032 if (mfra_map.memory != NULL)
4033 gst_buffer_unmap (mfra, &mfra_map);
4034 gst_buffer_unref (mfra);
4041 GST_WARNING_OBJECT (qtdemux, "could not query upstream size");
4046 GST_WARNING_OBJECT (qtdemux, "mfro size is too small");
4051 GST_WARNING_OBJECT (qtdemux, "mfra_size in mfro box is invalid");
4056 GST_WARNING_OBJECT (qtdemux, "bogus mfra offset or size, broken file");
4062 add_offset (guint64 offset, guint64 advance)
4064 /* Avoid 64-bit overflow by clamping */
4065 if (offset > G_MAXUINT64 - advance)
4067 return offset + advance;
4070 static GstFlowReturn
4071 gst_qtdemux_loop_state_header (GstQTDemux * qtdemux)
4075 GstBuffer *buf = NULL;
4076 GstFlowReturn ret = GST_FLOW_OK;
4077 guint64 cur_offset = qtdemux->offset;
4080 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, 16, &buf);
4081 if (G_UNLIKELY (ret != GST_FLOW_OK))
4083 gst_buffer_map (buf, &map, GST_MAP_READ);
4084 if (G_LIKELY (map.size >= 8))
4085 extract_initial_length_and_fourcc (map.data, map.size, &length, &fourcc);
4086 gst_buffer_unmap (buf, &map);
4087 gst_buffer_unref (buf);
4089 /* maybe we already got most we needed, so only consider this eof */
4090 if (G_UNLIKELY (length == 0)) {
4091 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
4092 (_("Invalid atom size.")),
4093 ("Header atom '%" GST_FOURCC_FORMAT "' has empty length",
4094 GST_FOURCC_ARGS (fourcc)));
4101 /* record for later parsing when needed */
4102 if (!qtdemux->moof_offset) {
4103 qtdemux->moof_offset = qtdemux->offset;
4105 if (qtdemux_pull_mfro_mfra (qtdemux)) {
4108 qtdemux->offset += length; /* skip moof and keep going */
4110 if (qtdemux->got_moov) {
4111 GST_INFO_OBJECT (qtdemux, "moof header, got moov, done with headers");
4122 GST_LOG_OBJECT (qtdemux,
4123 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
4124 GST_FOURCC_ARGS (fourcc), cur_offset);
4125 qtdemux->offset = add_offset (qtdemux->offset, length);
4130 GstBuffer *moov = NULL;
4132 if (qtdemux->got_moov) {
4133 GST_DEBUG_OBJECT (qtdemux, "Skipping moov atom as we have one already");
4134 qtdemux->offset = add_offset (qtdemux->offset, length);
4138 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, length, &moov);
4139 if (ret != GST_FLOW_OK)
4141 gst_buffer_map (moov, &map, GST_MAP_READ);
4143 if (length != map.size) {
4144 /* Some files have a 'moov' atom at the end of the file which contains
4145 * a terminal 'free' atom where the body of the atom is missing.
4146 * Check for, and permit, this special case.
4148 if (map.size >= 8) {
4149 guint8 *final_data = map.data + (map.size - 8);
4150 guint32 final_length = QT_UINT32 (final_data);
4151 guint32 final_fourcc = QT_FOURCC (final_data + 4);
4153 if (final_fourcc == FOURCC_free
4154 && map.size + final_length - 8 == length) {
4155 /* Ok, we've found that special case. Allocate a new buffer with
4156 * that free atom actually present. */
4157 GstBuffer *newmoov = gst_buffer_new_and_alloc (length);
4158 gst_buffer_fill (newmoov, 0, map.data, map.size);
4159 gst_buffer_memset (newmoov, map.size, 0, final_length - 8);
4160 gst_buffer_unmap (moov, &map);
4161 gst_buffer_unref (moov);
4163 gst_buffer_map (moov, &map, GST_MAP_READ);
4168 if (length != map.size) {
4169 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4170 (_("This file is incomplete and cannot be played.")),
4171 ("We got less than expected (received %" G_GSIZE_FORMAT
4172 ", wanted %u, offset %" G_GUINT64_FORMAT ")", map.size,
4173 (guint) length, cur_offset));
4174 gst_buffer_unmap (moov, &map);
4175 gst_buffer_unref (moov);
4176 ret = GST_FLOW_ERROR;
4179 qtdemux->offset += length;
4181 qtdemux_parse_moov (qtdemux, map.data, length);
4182 qtdemux_node_dump (qtdemux, qtdemux->moov_node);
4184 qtdemux_parse_tree (qtdemux);
4185 g_node_destroy (qtdemux->moov_node);
4186 gst_buffer_unmap (moov, &map);
4187 gst_buffer_unref (moov);
4188 qtdemux->moov_node = NULL;
4189 qtdemux->got_moov = TRUE;
4195 GstBuffer *ftyp = NULL;
4197 /* extract major brand; might come in handy for ISO vs QT issues */
4198 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &ftyp);
4199 if (ret != GST_FLOW_OK)
4201 qtdemux->offset += length;
4202 gst_buffer_map (ftyp, &map, GST_MAP_READ);
4203 qtdemux_parse_ftyp (qtdemux, map.data, map.size);
4204 gst_buffer_unmap (ftyp, &map);
4205 gst_buffer_unref (ftyp);
4210 GstBuffer *uuid = NULL;
4212 /* uuid are extension atoms */
4213 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &uuid);
4214 if (ret != GST_FLOW_OK)
4216 qtdemux->offset += length;
4217 gst_buffer_map (uuid, &map, GST_MAP_READ);
4218 qtdemux_parse_uuid (qtdemux, map.data, map.size);
4219 gst_buffer_unmap (uuid, &map);
4220 gst_buffer_unref (uuid);
4225 GstBuffer *sidx = NULL;
4226 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &sidx);
4227 if (ret != GST_FLOW_OK)
4229 qtdemux->offset += length;
4230 gst_buffer_map (sidx, &map, GST_MAP_READ);
4231 qtdemux_parse_sidx (qtdemux, map.data, map.size);
4232 gst_buffer_unmap (sidx, &map);
4233 gst_buffer_unref (sidx);
4238 GstBuffer *unknown = NULL;
4240 GST_LOG_OBJECT (qtdemux,
4241 "unknown %08x '%" GST_FOURCC_FORMAT "' of size %" G_GUINT64_FORMAT
4242 " at %" G_GUINT64_FORMAT, fourcc, GST_FOURCC_ARGS (fourcc), length,
4244 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &unknown);
4245 if (ret != GST_FLOW_OK)
4247 gst_buffer_map (unknown, &map, GST_MAP_READ);
4248 GST_MEMDUMP ("Unknown tag", map.data, map.size);
4249 gst_buffer_unmap (unknown, &map);
4250 gst_buffer_unref (unknown);
4251 qtdemux->offset += length;
4257 if (ret == GST_FLOW_EOS && (qtdemux->got_moov || qtdemux->media_caps)) {
4258 /* digested all data, show what we have */
4259 qtdemux_prepare_streams (qtdemux);
4260 ret = qtdemux_expose_streams (qtdemux);
4262 qtdemux->state = QTDEMUX_STATE_MOVIE;
4263 GST_DEBUG_OBJECT (qtdemux, "switching state to STATE_MOVIE (%d)",
4270 /* Seeks to the previous keyframe of the indexed stream and
4271 * aligns other streams with respect to the keyframe timestamp
4272 * of indexed stream. Only called in case of Reverse Playback
4274 static GstFlowReturn
4275 gst_qtdemux_seek_to_previous_keyframe (GstQTDemux * qtdemux)
4278 guint32 seg_idx = 0, k_index = 0;
4279 guint32 ref_seg_idx, ref_k_index;
4280 GstClockTime k_pos = 0, last_stop = 0;
4281 QtDemuxSegment *seg = NULL;
4282 QtDemuxStream *ref_str = NULL;
4283 guint64 seg_media_start_mov; /* segment media start time in mov format */
4286 /* Now we choose an arbitrary stream, get the previous keyframe timestamp
4287 * and finally align all the other streams on that timestamp with their
4288 * respective keyframes */
4289 for (n = 0; n < qtdemux->n_streams; n++) {
4290 QtDemuxStream *str = qtdemux->streams[n];
4292 /* No candidate yet, take the first stream */
4298 /* So that stream has a segment, we prefer video streams */
4299 if (str->subtype == FOURCC_vide) {
4305 if (G_UNLIKELY (!ref_str)) {
4306 GST_DEBUG_OBJECT (qtdemux, "couldn't find any stream");
4310 if (G_UNLIKELY (!ref_str->from_sample)) {
4311 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of the file");
4315 /* So that stream has been playing from from_sample to to_sample. We will
4316 * get the timestamp of the previous sample and search for a keyframe before
4317 * that. For audio streams we do an arbitrary jump in the past (10 samples) */
4318 if (ref_str->subtype == FOURCC_vide) {
4319 k_index = gst_qtdemux_find_keyframe (qtdemux, ref_str,
4320 ref_str->from_sample - 1);
4322 if (ref_str->from_sample >= 10)
4323 k_index = ref_str->from_sample - 10;
4329 ref_str->samples[k_index].timestamp +
4330 ref_str->samples[k_index].pts_offset;
4332 /* get current segment for that stream */
4333 seg = &ref_str->segments[ref_str->segment_index];
4334 /* Use segment start in original timescale for comparisons */
4335 seg_media_start_mov = seg->trak_media_start;
4337 GST_LOG_OBJECT (qtdemux, "keyframe index %u ts %" G_GUINT64_FORMAT
4338 " seg start %" G_GUINT64_FORMAT " %" GST_TIME_FORMAT "\n",
4339 k_index, target_ts, seg_media_start_mov,
4340 GST_TIME_ARGS (seg->media_start));
4342 /* Crawl back through segments to find the one containing this I frame */
4343 while (target_ts < seg_media_start_mov) {
4344 GST_DEBUG_OBJECT (qtdemux,
4345 "keyframe position (sample %u) is out of segment %u " " target %"
4346 G_GUINT64_FORMAT " seg start %" G_GUINT64_FORMAT, k_index,
4347 ref_str->segment_index, target_ts, seg_media_start_mov);
4349 if (G_UNLIKELY (!ref_str->segment_index)) {
4350 /* Reached first segment, let's consider it's EOS */
4353 ref_str->segment_index--;
4354 seg = &ref_str->segments[ref_str->segment_index];
4355 /* Use segment start in original timescale for comparisons */
4356 seg_media_start_mov = seg->trak_media_start;
4358 /* Calculate time position of the keyframe and where we should stop */
4360 QTSTREAMTIME_TO_GSTTIME (ref_str,
4361 target_ts - seg->trak_media_start) + seg->time;
4363 QTSTREAMTIME_TO_GSTTIME (ref_str,
4364 ref_str->samples[ref_str->from_sample].timestamp -
4365 seg->trak_media_start) + seg->time;
4367 GST_DEBUG_OBJECT (qtdemux, "preferred stream played from sample %u, "
4368 "now going to sample %u (pts %" GST_TIME_FORMAT ")", ref_str->from_sample,
4369 k_index, GST_TIME_ARGS (k_pos));
4371 /* Set last_stop with the keyframe timestamp we pushed of that stream */
4372 qtdemux->segment.position = last_stop;
4373 GST_DEBUG_OBJECT (qtdemux, "last_stop now is %" GST_TIME_FORMAT,
4374 GST_TIME_ARGS (last_stop));
4376 if (G_UNLIKELY (last_stop < qtdemux->segment.start)) {
4377 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of segment");
4381 ref_seg_idx = ref_str->segment_index;
4382 ref_k_index = k_index;
4384 /* Align them all on this */
4385 for (n = 0; n < qtdemux->n_streams; n++) {
4387 GstClockTime seg_time = 0;
4388 QtDemuxStream *str = qtdemux->streams[n];
4390 /* aligning reference stream again might lead to backing up to yet another
4391 * keyframe (due to timestamp rounding issues),
4392 * potentially putting more load on downstream; so let's try to avoid */
4393 if (str == ref_str) {
4394 seg_idx = ref_seg_idx;
4395 seg = &str->segments[seg_idx];
4396 k_index = ref_k_index;
4397 GST_DEBUG_OBJECT (qtdemux, "reference stream %d segment %d, "
4398 "sample at index %d", n, ref_str->segment_index, k_index);
4400 seg_idx = gst_qtdemux_find_segment (qtdemux, str, k_pos);
4401 GST_DEBUG_OBJECT (qtdemux,
4402 "stream %d align segment %d for keyframe pos %" GST_TIME_FORMAT, n,
4403 seg_idx, GST_TIME_ARGS (k_pos));
4405 /* get segment and time in the segment */
4406 seg = &str->segments[seg_idx];
4407 seg_time = k_pos - seg->time;
4409 /* get the media time in the segment.
4410 * No adjustment for empty "filler" segments */
4411 if (seg->media_start != GST_CLOCK_TIME_NONE)
4412 seg_time += seg->media_start;
4414 /* get the index of the sample with media time */
4415 index = gst_qtdemux_find_index_linear (qtdemux, str, seg_time);
4416 GST_DEBUG_OBJECT (qtdemux,
4417 "stream %d sample for %" GST_TIME_FORMAT " at %u", n,
4418 GST_TIME_ARGS (seg_time), index);
4420 /* find previous keyframe */
4421 k_index = gst_qtdemux_find_keyframe (qtdemux, str, index);
4424 /* Remember until where we want to go */
4425 str->to_sample = str->from_sample - 1;
4426 /* Define our time position */
4428 str->samples[k_index].timestamp + str->samples[k_index].pts_offset;
4429 str->time_position = QTSTREAMTIME_TO_GSTTIME (str, target_ts) + seg->time;
4430 if (seg->media_start != GST_CLOCK_TIME_NONE)
4431 str->time_position -= seg->media_start;
4433 /* Now seek back in time */
4434 gst_qtdemux_move_stream (qtdemux, str, k_index);
4435 GST_DEBUG_OBJECT (qtdemux, "stream %d keyframe at %u, time position %"
4436 GST_TIME_FORMAT " playing from sample %u to %u", n, k_index,
4437 GST_TIME_ARGS (str->time_position), str->from_sample, str->to_sample);
4443 return GST_FLOW_EOS;
4447 * Gets the current qt segment start, stop and position for the
4448 * given time offset. This is used in update_segment()
4451 gst_qtdemux_stream_segment_get_boundaries (GstQTDemux * qtdemux,
4452 QtDemuxStream * stream, GstClockTime offset,
4453 GstClockTime * _start, GstClockTime * _stop, GstClockTime * _time)
4455 GstClockTime seg_time;
4456 GstClockTime start, stop, time;
4457 QtDemuxSegment *segment;
4459 segment = &stream->segments[stream->segment_index];
4461 /* get time in this segment */
4462 seg_time = (offset - segment->time) * segment->rate;
4464 GST_LOG_OBJECT (stream->pad, "seg_time %" GST_TIME_FORMAT,
4465 GST_TIME_ARGS (seg_time));
4467 if (G_UNLIKELY (seg_time > segment->duration)) {
4468 GST_LOG_OBJECT (stream->pad,
4469 "seg_time > segment->duration %" GST_TIME_FORMAT,
4470 GST_TIME_ARGS (segment->duration));
4471 seg_time = segment->duration;
4474 /* qtdemux->segment.stop is in outside-time-realm, whereas
4475 * segment->media_stop is in track-time-realm.
4477 * In order to compare the two, we need to bring segment.stop
4478 * into the track-time-realm
4480 * FIXME - does this comment still hold? Don't see any conversion here */
4482 stop = qtdemux->segment.stop;
4483 if (stop == GST_CLOCK_TIME_NONE)
4484 stop = qtdemux->segment.duration;
4485 if (stop == GST_CLOCK_TIME_NONE)
4486 stop = segment->media_stop;
4489 MIN (segment->media_stop, stop - segment->time + segment->media_start);
4491 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
4492 start = segment->time + seg_time;
4494 stop = start - seg_time + segment->duration;
4495 } else if (qtdemux->segment.rate >= 0) {
4496 start = MIN (segment->media_start + seg_time, stop);
4499 if (segment->media_start >= qtdemux->segment.start) {
4500 time = segment->time;
4502 time = segment->time + (qtdemux->segment.start - segment->media_start);
4505 start = MAX (segment->media_start, qtdemux->segment.start);
4506 stop = MIN (segment->media_start + seg_time, stop);
4515 * Updates the qt segment used for the stream and pushes a new segment event
4516 * downstream on this stream's pad.
4519 gst_qtdemux_stream_update_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
4520 gint seg_idx, GstClockTime offset, GstClockTime * _start,
4521 GstClockTime * _stop)
4523 QtDemuxSegment *segment;
4524 GstClockTime start = 0, stop = GST_CLOCK_TIME_NONE, time = 0;
4528 /* update the current segment */
4529 stream->segment_index = seg_idx;
4531 /* get the segment */
4532 segment = &stream->segments[seg_idx];
4534 if (G_UNLIKELY (offset < segment->time)) {
4535 GST_WARNING_OBJECT (stream->pad, "offset < segment->time %" GST_TIME_FORMAT,
4536 GST_TIME_ARGS (segment->time));
4540 /* segment lies beyond total indicated duration */
4541 if (G_UNLIKELY (qtdemux->segment.duration != GST_CLOCK_TIME_NONE &&
4542 segment->time > qtdemux->segment.duration)) {
4543 GST_WARNING_OBJECT (stream->pad, "file duration %" GST_TIME_FORMAT
4544 " < segment->time %" GST_TIME_FORMAT,
4545 GST_TIME_ARGS (qtdemux->segment.duration),
4546 GST_TIME_ARGS (segment->time));
4550 gst_qtdemux_stream_segment_get_boundaries (qtdemux, stream, offset,
4551 &start, &stop, &time);
4553 GST_DEBUG_OBJECT (stream->pad, "new segment %d from %" GST_TIME_FORMAT
4554 " to %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT, seg_idx,
4555 GST_TIME_ARGS (start), GST_TIME_ARGS (stop), GST_TIME_ARGS (time));
4557 /* combine global rate with that of the segment */
4558 rate = segment->rate * qtdemux->segment.rate;
4560 /* Copy flags from main segment */
4561 stream->segment.flags = qtdemux->segment.flags;
4563 /* update the segment values used for clipping */
4564 stream->segment.offset = qtdemux->segment.offset;
4565 stream->segment.base = qtdemux->segment.base + stream->accumulated_base;
4566 stream->segment.applied_rate = qtdemux->segment.applied_rate;
4567 stream->segment.rate = rate;
4568 stream->segment.start = start + QTSTREAMTIME_TO_GSTTIME (stream,
4569 stream->cslg_shift);
4570 stream->segment.stop = stop + QTSTREAMTIME_TO_GSTTIME (stream,
4571 stream->cslg_shift);
4572 stream->segment.time = time;
4573 stream->segment.position = stream->segment.start;
4575 GST_DEBUG_OBJECT (stream->pad, "New segment: %" GST_SEGMENT_FORMAT,
4578 /* now prepare and send the segment */
4580 event = gst_event_new_segment (&stream->segment);
4581 if (qtdemux->segment_seqnum) {
4582 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
4584 gst_pad_push_event (stream->pad, event);
4585 /* assume we can send more data now */
4586 GST_PAD_LAST_FLOW_RETURN (stream->pad) = GST_FLOW_OK;
4587 /* clear to send tags on this pad now */
4588 gst_qtdemux_push_tags (qtdemux, stream);
4599 /* activate the given segment number @seg_idx of @stream at time @offset.
4600 * @offset is an absolute global position over all the segments.
4602 * This will push out a NEWSEGMENT event with the right values and
4603 * position the stream index to the first decodable sample before
4607 gst_qtdemux_activate_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
4608 guint32 seg_idx, GstClockTime offset)
4610 QtDemuxSegment *segment;
4611 guint32 index, kf_index;
4612 GstClockTime start = 0, stop = GST_CLOCK_TIME_NONE;
4614 GST_LOG_OBJECT (stream->pad, "activate segment %d, offset %" GST_TIME_FORMAT,
4615 seg_idx, GST_TIME_ARGS (offset));
4617 if (!gst_qtdemux_stream_update_segment (qtdemux, stream, seg_idx, offset,
4621 segment = &stream->segments[stream->segment_index];
4623 /* in the fragmented case, we pick a fragment that starts before our
4624 * desired position and rely on downstream to wait for a keyframe
4625 * (FIXME: doesn't seem to work so well with ismv and wmv, as no parser; the
4626 * tfra entries tells us which trun/sample the key unit is in, but we don't
4627 * make use of this additional information at the moment) */
4628 if (qtdemux->fragmented) {
4629 stream->to_sample = G_MAXUINT32;
4633 /* We don't need to look for a sample in push-based */
4634 if (!qtdemux->pullbased)
4637 /* and move to the keyframe before the indicated media time of the
4639 if (G_LIKELY (!QTSEGMENT_IS_EMPTY (segment))) {
4640 if (qtdemux->segment.rate >= 0) {
4641 index = gst_qtdemux_find_index_linear (qtdemux, stream, start);
4642 stream->to_sample = G_MAXUINT32;
4643 GST_DEBUG_OBJECT (stream->pad,
4644 "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
4645 GST_TIME_FORMAT, GST_TIME_ARGS (start), index,
4646 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
4648 index = gst_qtdemux_find_index_linear (qtdemux, stream, stop);
4649 stream->to_sample = index;
4650 GST_DEBUG_OBJECT (stream->pad,
4651 "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
4652 GST_TIME_FORMAT, GST_TIME_ARGS (stop), index,
4653 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
4656 GST_DEBUG_OBJECT (stream->pad, "No need to look for keyframe, "
4657 "this is an empty segment");
4661 /* gst_qtdemux_parse_sample () called from gst_qtdemux_find_index_linear ()
4662 * encountered an error and printed a message so we return appropriately */
4666 /* we're at the right spot */
4667 if (index == stream->sample_index) {
4668 GST_DEBUG_OBJECT (stream->pad, "we are at the right index");
4672 /* find keyframe of the target index */
4673 kf_index = gst_qtdemux_find_keyframe (qtdemux, stream, index);
4676 /* indent does stupid stuff with stream->samples[].timestamp */
4678 /* if we move forwards, we don't have to go back to the previous
4679 * keyframe since we already sent that. We can also just jump to
4680 * the keyframe right before the target index if there is one. */
4681 if (index > stream->sample_index) {
4682 /* moving forwards check if we move past a keyframe */
4683 if (kf_index > stream->sample_index) {
4684 GST_DEBUG_OBJECT (stream->pad,
4685 "moving forwards to keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" )", kf_index,
4686 GST_TIME_ARGS (QTSAMPLE_PTS(stream, &stream->samples[kf_index])),
4687 GST_TIME_ARGS (QTSAMPLE_DTS(stream, &stream->samples[kf_index])));
4688 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
4690 GST_DEBUG_OBJECT (stream->pad,
4691 "moving forwards, keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" ) already sent", kf_index,
4692 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[kf_index])),
4693 GST_TIME_ARGS (QTSAMPLE_DTS (stream, &stream->samples[kf_index])));
4696 GST_DEBUG_OBJECT (stream->pad,
4697 "moving backwards to keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" )", kf_index,
4698 GST_TIME_ARGS (QTSAMPLE_PTS(stream, &stream->samples[kf_index])),
4699 GST_TIME_ARGS (QTSAMPLE_DTS(stream, &stream->samples[kf_index])));
4700 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
4708 /* prepare to get the current sample of @stream, getting essential values.
4710 * This function will also prepare and send the segment when needed.
4712 * Return FALSE if the stream is EOS.
4717 gst_qtdemux_prepare_current_sample (GstQTDemux * qtdemux,
4718 QtDemuxStream * stream, gboolean * empty, guint64 * offset, guint * size,
4719 GstClockTime * dts, GstClockTime * pts, GstClockTime * duration,
4720 gboolean * keyframe)
4722 QtDemuxSample *sample;
4723 GstClockTime time_position;
4726 g_return_val_if_fail (stream != NULL, FALSE);
4728 time_position = stream->time_position;
4729 if (G_UNLIKELY (time_position == GST_CLOCK_TIME_NONE))
4732 seg_idx = stream->segment_index;
4733 if (G_UNLIKELY (seg_idx == -1)) {
4734 /* find segment corresponding to time_position if we are looking
4736 seg_idx = gst_qtdemux_find_segment (qtdemux, stream, time_position);
4739 /* different segment, activate it, sample_index will be set. */
4740 if (G_UNLIKELY (stream->segment_index != seg_idx))
4741 gst_qtdemux_activate_segment (qtdemux, stream, seg_idx, time_position);
4743 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (&stream->segments[stream->
4745 QtDemuxSegment *seg = &stream->segments[stream->segment_index];
4747 GST_LOG_OBJECT (qtdemux, "Empty segment activated,"
4748 " prepare empty sample");
4751 *pts = *dts = time_position;
4752 *duration = seg->duration - (time_position - seg->time);
4759 if (stream->sample_index == -1)
4760 stream->sample_index = 0;
4762 GST_LOG_OBJECT (qtdemux, "segment active, index = %u of %u",
4763 stream->sample_index, stream->n_samples);
4765 if (G_UNLIKELY (stream->sample_index >= stream->n_samples)) {
4766 if (!qtdemux->fragmented)
4769 GST_INFO_OBJECT (qtdemux, "out of samples, trying to add more");
4773 GST_OBJECT_LOCK (qtdemux);
4774 flow = qtdemux_add_fragmented_samples (qtdemux);
4775 GST_OBJECT_UNLOCK (qtdemux);
4777 if (flow != GST_FLOW_OK)
4780 while (stream->sample_index >= stream->n_samples);
4783 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
4784 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
4785 stream->sample_index);
4789 /* now get the info for the sample we're at */
4790 sample = &stream->samples[stream->sample_index];
4792 *dts = QTSAMPLE_DTS (stream, sample);
4793 *pts = QTSAMPLE_PTS (stream, sample);
4794 *offset = sample->offset;
4795 *size = sample->size;
4796 *duration = QTSAMPLE_DUR_DTS (stream, sample, *dts);
4797 *keyframe = QTSAMPLE_KEYFRAME (stream, sample);
4804 stream->time_position = GST_CLOCK_TIME_NONE;
4809 /* move to the next sample in @stream.
4811 * Moves to the next segment when needed.
4814 gst_qtdemux_advance_sample (GstQTDemux * qtdemux, QtDemuxStream * stream)
4816 QtDemuxSample *sample;
4817 QtDemuxSegment *segment;
4819 /* get current segment */
4820 segment = &stream->segments[stream->segment_index];
4822 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
4823 GST_DEBUG_OBJECT (qtdemux, "Empty segment, no samples to advance");
4827 if (G_UNLIKELY (stream->sample_index >= stream->to_sample)) {
4828 /* Mark the stream as EOS */
4829 GST_DEBUG_OBJECT (qtdemux,
4830 "reached max allowed sample %u, mark EOS", stream->to_sample);
4831 stream->time_position = GST_CLOCK_TIME_NONE;
4835 /* move to next sample */
4836 stream->sample_index++;
4837 stream->offset_in_sample = 0;
4839 /* reached the last sample, we need the next segment */
4840 if (G_UNLIKELY (stream->sample_index >= stream->n_samples))
4843 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
4844 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
4845 stream->sample_index);
4849 /* get next sample */
4850 sample = &stream->samples[stream->sample_index];
4852 /* see if we are past the segment */
4853 if (G_UNLIKELY (QTSAMPLE_DTS (stream, sample) >= segment->media_stop))
4856 if (QTSAMPLE_DTS (stream, sample) >= segment->media_start) {
4857 /* inside the segment, update time_position, looks very familiar to
4858 * GStreamer segments, doesn't it? */
4859 stream->time_position =
4860 QTSAMPLE_DTS (stream, sample) - segment->media_start + segment->time;
4862 /* not yet in segment, time does not yet increment. This means
4863 * that we are still prerolling keyframes to the decoder so it can
4864 * decode the first sample of the segment. */
4865 stream->time_position = segment->time;
4869 /* move to the next segment */
4872 GST_DEBUG_OBJECT (qtdemux, "segment %d ended ", stream->segment_index);
4874 if (stream->segment_index == stream->n_segments - 1) {
4875 /* are we at the end of the last segment, we're EOS */
4876 stream->time_position = GST_CLOCK_TIME_NONE;
4878 /* else we're only at the end of the current segment */
4879 stream->time_position = segment->stop_time;
4881 /* make sure we select a new segment */
4883 /* accumulate previous segments */
4884 if (GST_CLOCK_TIME_IS_VALID (stream->segment.stop))
4885 stream->accumulated_base +=
4886 (stream->segment.stop -
4887 stream->segment.start) / ABS (stream->segment.rate);
4889 stream->segment_index = -1;
4894 gst_qtdemux_sync_streams (GstQTDemux * demux)
4898 if (demux->n_streams <= 1)
4901 for (i = 0; i < demux->n_streams; i++) {
4902 QtDemuxStream *stream;
4903 GstClockTime end_time;
4905 stream = demux->streams[i];
4910 /* TODO advance time on subtitle streams here, if any some day */
4912 /* some clips/trailers may have unbalanced streams at the end,
4913 * so send EOS on shorter stream to prevent stalling others */
4915 /* do not mess with EOS if SEGMENT seeking */
4916 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT)
4919 if (demux->pullbased) {
4920 /* loop mode is sample time based */
4921 if (!STREAM_IS_EOS (stream))
4924 /* push mode is byte position based */
4925 if (stream->n_samples &&
4926 stream->samples[stream->n_samples - 1].offset >= demux->offset)
4930 if (stream->sent_eos)
4933 /* only act if some gap */
4934 end_time = stream->segments[stream->n_segments - 1].stop_time;
4935 GST_LOG_OBJECT (demux, "current position: %" GST_TIME_FORMAT
4936 ", stream end: %" GST_TIME_FORMAT,
4937 GST_TIME_ARGS (demux->segment.position), GST_TIME_ARGS (end_time));
4938 if (GST_CLOCK_TIME_IS_VALID (end_time)
4939 && (end_time + 2 * GST_SECOND < demux->segment.position)) {
4942 GST_DEBUG_OBJECT (demux, "sending EOS for stream %s",
4943 GST_PAD_NAME (stream->pad));
4944 stream->sent_eos = TRUE;
4945 event = gst_event_new_eos ();
4946 if (demux->segment_seqnum)
4947 gst_event_set_seqnum (event, demux->segment_seqnum);
4948 gst_pad_push_event (stream->pad, event);
4953 /* EOS and NOT_LINKED need to be combined. This means that we return:
4955 * GST_FLOW_NOT_LINKED: when all pads NOT_LINKED.
4956 * GST_FLOW_EOS: when all pads EOS or NOT_LINKED.
4958 static GstFlowReturn
4959 gst_qtdemux_combine_flows (GstQTDemux * demux, QtDemuxStream * stream,
4962 GST_LOG_OBJECT (demux, "flow return: %s", gst_flow_get_name (ret));
4965 ret = gst_flow_combiner_update_pad_flow (demux->flowcombiner, stream->pad,
4968 ret = gst_flow_combiner_update_flow (demux->flowcombiner, ret);
4970 GST_LOG_OBJECT (demux, "combined flow return: %s", gst_flow_get_name (ret));
4974 /* the input buffer metadata must be writable. Returns NULL when the buffer is
4975 * completely clipped
4977 * Should be used only with raw buffers */
4979 gst_qtdemux_clip_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
4982 guint64 start, stop, cstart, cstop, diff;
4983 GstClockTime pts, duration;
4985 gint num_rate, denom_rate;
4990 osize = size = gst_buffer_get_size (buf);
4993 /* depending on the type, setup the clip parameters */
4994 if (stream->subtype == FOURCC_soun) {
4995 frame_size = stream->bytes_per_frame;
4996 num_rate = GST_SECOND;
4997 denom_rate = (gint) stream->rate;
4999 } else if (stream->subtype == FOURCC_vide) {
5001 num_rate = stream->fps_n;
5002 denom_rate = stream->fps_d;
5007 if (frame_size <= 0)
5008 goto bad_frame_size;
5010 /* we can only clip if we have a valid pts */
5011 pts = GST_BUFFER_PTS (buf);
5012 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (pts)))
5015 duration = GST_BUFFER_DURATION (buf);
5017 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (duration))) {
5019 gst_util_uint64_scale_int (size / frame_size, num_rate, denom_rate);
5023 stop = start + duration;
5025 if (G_UNLIKELY (!gst_segment_clip (&stream->segment,
5026 GST_FORMAT_TIME, start, stop, &cstart, &cstop)))
5029 /* see if some clipping happened */
5030 diff = cstart - start;
5036 /* bring clipped time to samples and to bytes */
5037 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
5040 GST_DEBUG_OBJECT (qtdemux,
5041 "clipping start to %" GST_TIME_FORMAT " %"
5042 G_GUINT64_FORMAT " bytes", GST_TIME_ARGS (cstart), diff);
5048 diff = stop - cstop;
5053 /* bring clipped time to samples and then to bytes */
5054 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
5056 GST_DEBUG_OBJECT (qtdemux,
5057 "clipping stop to %" GST_TIME_FORMAT " %" G_GUINT64_FORMAT
5058 " bytes", GST_TIME_ARGS (cstop), diff);
5063 if (offset != 0 || size != osize)
5064 gst_buffer_resize (buf, offset, size);
5066 GST_BUFFER_DTS (buf) = GST_CLOCK_TIME_NONE;
5067 GST_BUFFER_PTS (buf) = pts;
5068 GST_BUFFER_DURATION (buf) = duration;
5072 /* dropped buffer */
5075 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
5080 GST_DEBUG_OBJECT (qtdemux, "bad frame size");
5085 GST_DEBUG_OBJECT (qtdemux, "no pts on buffer");
5090 GST_DEBUG_OBJECT (qtdemux, "clipped buffer");
5091 gst_buffer_unref (buf);
5096 /* the input buffer metadata must be writable,
5097 * but time/duration etc not yet set and need not be preserved */
5099 gst_qtdemux_process_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
5106 /* not many cases for now */
5107 if (G_UNLIKELY (stream->fourcc == FOURCC_mp4s)) {
5108 /* send a one time dvd clut event */
5109 if (stream->pending_event && stream->pad)
5110 gst_pad_push_event (stream->pad, stream->pending_event);
5111 stream->pending_event = NULL;
5114 if (G_UNLIKELY (stream->subtype != FOURCC_text
5115 && stream->subtype != FOURCC_sbtl &&
5116 stream->subtype != FOURCC_subp)) {
5120 gst_buffer_map (buf, &map, GST_MAP_READ);
5122 /* empty buffer is sent to terminate previous subtitle */
5123 if (map.size <= 2) {
5124 gst_buffer_unmap (buf, &map);
5125 gst_buffer_unref (buf);
5128 if (stream->subtype == FOURCC_subp) {
5129 /* That's all the processing needed for subpictures */
5130 gst_buffer_unmap (buf, &map);
5134 nsize = GST_READ_UINT16_BE (map.data);
5135 nsize = MIN (nsize, map.size - 2);
5137 GST_LOG_OBJECT (qtdemux, "3GPP timed text subtitle: %d/%" G_GSIZE_FORMAT "",
5140 /* takes care of UTF-8 validation or UTF-16 recognition,
5141 * no other encoding expected */
5142 str = gst_tag_freeform_string_to_utf8 ((gchar *) map.data + 2, nsize, NULL);
5143 gst_buffer_unmap (buf, &map);
5145 gst_buffer_unref (buf);
5146 buf = _gst_buffer_new_wrapped (str, strlen (str), g_free);
5148 /* this should not really happen unless the subtitle is corrupted */
5149 gst_buffer_unref (buf);
5153 /* FIXME ? convert optional subsequent style info to markup */
5158 /* Sets a buffer's attributes properly and pushes it downstream.
5159 * Also checks for additional actions and custom processing that may
5160 * need to be done first.
5162 static GstFlowReturn
5163 gst_qtdemux_decorate_and_push_buffer (GstQTDemux * qtdemux,
5164 QtDemuxStream * stream, GstBuffer * buf,
5165 GstClockTime dts, GstClockTime pts, GstClockTime duration,
5166 gboolean keyframe, GstClockTime position, guint64 byte_position)
5168 GstFlowReturn ret = GST_FLOW_OK;
5170 /* offset the timestamps according to the edit list */
5172 if (G_UNLIKELY (stream->fourcc == FOURCC_rtsp)) {
5176 gst_buffer_map (buf, &map, GST_MAP_READ);
5177 url = g_strndup ((gchar *) map.data, map.size);
5178 gst_buffer_unmap (buf, &map);
5179 if (url != NULL && strlen (url) != 0) {
5180 /* we have RTSP redirect now */
5181 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
5182 gst_message_new_element (GST_OBJECT_CAST (qtdemux),
5183 gst_structure_new ("redirect",
5184 "new-location", G_TYPE_STRING, url, NULL)));
5185 qtdemux->posted_redirect = TRUE;
5187 GST_WARNING_OBJECT (qtdemux, "Redirect URI of stream is empty, not "
5193 /* position reporting */
5194 if (qtdemux->segment.rate >= 0) {
5195 qtdemux->segment.position = position;
5196 gst_qtdemux_sync_streams (qtdemux);
5199 if (G_UNLIKELY (!stream->pad)) {
5200 GST_DEBUG_OBJECT (qtdemux, "No output pad for stream, ignoring");
5201 gst_buffer_unref (buf);
5205 /* send out pending buffers */
5206 while (stream->buffers) {
5207 GstBuffer *buffer = (GstBuffer *) stream->buffers->data;
5209 if (G_UNLIKELY (stream->discont)) {
5210 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
5211 GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
5212 stream->discont = FALSE;
5214 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
5217 gst_pad_push (stream->pad, buffer);
5219 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
5222 /* we're going to modify the metadata */
5223 buf = gst_buffer_make_writable (buf);
5225 if (G_UNLIKELY (stream->need_process))
5226 buf = gst_qtdemux_process_buffer (qtdemux, stream, buf);
5232 GST_BUFFER_DTS (buf) = dts;
5233 GST_BUFFER_PTS (buf) = pts;
5234 GST_BUFFER_DURATION (buf) = duration;
5235 GST_BUFFER_OFFSET (buf) = -1;
5236 GST_BUFFER_OFFSET_END (buf) = -1;
5238 if (G_UNLIKELY (stream->rgb8_palette))
5239 gst_buffer_append_memory (buf, gst_memory_ref (stream->rgb8_palette));
5241 if (G_UNLIKELY (stream->padding)) {
5242 gst_buffer_resize (buf, stream->padding, -1);
5245 if (G_UNLIKELY (qtdemux->element_index)) {
5246 GstClockTime stream_time;
5249 gst_segment_to_stream_time (&stream->segment, GST_FORMAT_TIME,
5251 if (GST_CLOCK_TIME_IS_VALID (stream_time)) {
5252 GST_LOG_OBJECT (qtdemux,
5253 "adding association %" GST_TIME_FORMAT "-> %"
5254 G_GUINT64_FORMAT, GST_TIME_ARGS (stream_time), byte_position);
5255 gst_index_add_association (qtdemux->element_index,
5257 keyframe ? GST_ASSOCIATION_FLAG_KEY_UNIT :
5258 GST_ASSOCIATION_FLAG_DELTA_UNIT, GST_FORMAT_TIME, stream_time,
5259 GST_FORMAT_BYTES, byte_position, NULL);
5264 if (stream->need_clip)
5265 buf = gst_qtdemux_clip_buffer (qtdemux, stream, buf);
5267 if (G_UNLIKELY (buf == NULL))
5270 if (G_UNLIKELY (stream->discont)) {
5271 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
5272 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
5273 stream->discont = FALSE;
5275 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
5279 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
5280 stream->on_keyframe = FALSE;
5282 stream->on_keyframe = TRUE;
5286 GST_LOG_OBJECT (qtdemux,
5287 "Pushing buffer with dts %" GST_TIME_FORMAT ", pts %" GST_TIME_FORMAT
5288 ", duration %" GST_TIME_FORMAT " on pad %s", GST_TIME_ARGS (dts),
5289 GST_TIME_ARGS (pts), GST_TIME_ARGS (duration),
5290 GST_PAD_NAME (stream->pad));
5292 if (stream->protected && stream->protection_scheme_type == FOURCC_cenc) {
5293 GstStructure *crypto_info;
5294 QtDemuxCencSampleSetInfo *info =
5295 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
5299 while ((event = g_queue_pop_head (&stream->protection_scheme_event_queue))) {
5300 gst_pad_push_event (stream->pad, event);
5303 if (qtdemux->cenc_aux_info_offset > 0 && info->crypto_info == NULL) {
5304 GST_DEBUG_OBJECT (qtdemux, "cenc metadata hasn't been parsed yet");
5305 gst_buffer_unref (buf);
5309 index = stream->sample_index - (stream->n_samples - info->crypto_info->len);
5310 if (G_LIKELY (index >= 0 && index < info->crypto_info->len)) {
5311 /* steal structure from array */
5312 crypto_info = g_ptr_array_index (info->crypto_info, index);
5313 g_ptr_array_index (info->crypto_info, index) = NULL;
5314 GST_LOG_OBJECT (qtdemux, "attaching cenc metadata [%u]", index);
5315 if (!crypto_info || !gst_buffer_add_protection_meta (buf, crypto_info))
5316 GST_ERROR_OBJECT (qtdemux, "failed to attach cenc metadata to buffer");
5320 ret = gst_pad_push (stream->pad, buf);
5322 if (GST_CLOCK_TIME_IS_VALID (pts) && GST_CLOCK_TIME_IS_VALID (duration)) {
5323 /* mark position in stream, we'll need this to know when to send GAP event */
5324 stream->segment.position = pts + duration;
5331 static const QtDemuxRandomAccessEntry *
5332 gst_qtdemux_stream_seek_fragment (GstQTDemux * qtdemux, QtDemuxStream * stream,
5333 GstClockTime pos, gboolean after)
5335 QtDemuxRandomAccessEntry *entries = stream->ra_entries;
5336 guint n_entries = stream->n_ra_entries;
5339 /* we assume the table is sorted */
5340 for (i = 0; i < n_entries; ++i) {
5341 if (entries[i].ts > pos)
5345 /* FIXME: maybe save first moof_offset somewhere instead, but for now it's
5346 * probably okay to assume that the index lists the very first fragment */
5353 return &entries[i - 1];
5357 gst_qtdemux_do_fragmented_seek (GstQTDemux * qtdemux)
5359 const QtDemuxRandomAccessEntry *best_entry = NULL;
5362 GST_OBJECT_LOCK (qtdemux);
5364 g_assert (qtdemux->n_streams > 0);
5366 for (i = 0; i < qtdemux->n_streams; i++) {
5367 const QtDemuxRandomAccessEntry *entry;
5368 QtDemuxStream *stream;
5369 gboolean is_audio_or_video;
5371 stream = qtdemux->streams[i];
5373 g_free (stream->samples);
5374 stream->samples = NULL;
5375 stream->n_samples = 0;
5376 stream->stbl_index = -1; /* no samples have yet been parsed */
5377 stream->sample_index = -1;
5379 if (stream->ra_entries == NULL)
5382 if (stream->subtype == FOURCC_vide || stream->subtype == FOURCC_soun)
5383 is_audio_or_video = TRUE;
5385 is_audio_or_video = FALSE;
5388 gst_qtdemux_stream_seek_fragment (qtdemux, stream,
5389 stream->time_position, !is_audio_or_video);
5391 GST_INFO_OBJECT (stream->pad, "%" GST_TIME_FORMAT " at offset "
5392 "%" G_GUINT64_FORMAT, GST_TIME_ARGS (entry->ts), entry->moof_offset);
5394 stream->pending_seek = entry;
5396 /* decide position to jump to just based on audio/video tracks, not subs */
5397 if (!is_audio_or_video)
5400 if (best_entry == NULL || entry->moof_offset < best_entry->moof_offset)
5404 if (best_entry == NULL) {
5405 GST_OBJECT_UNLOCK (qtdemux);
5409 GST_INFO_OBJECT (qtdemux, "seek to %" GST_TIME_FORMAT ", best fragment "
5410 "moof offset: %" G_GUINT64_FORMAT ", ts %" GST_TIME_FORMAT,
5411 GST_TIME_ARGS (qtdemux->streams[0]->time_position),
5412 best_entry->moof_offset, GST_TIME_ARGS (best_entry->ts));
5414 qtdemux->moof_offset = best_entry->moof_offset;
5416 qtdemux_add_fragmented_samples (qtdemux);
5418 GST_OBJECT_UNLOCK (qtdemux);
5422 static GstFlowReturn
5423 gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux)
5425 GstFlowReturn ret = GST_FLOW_OK;
5426 GstBuffer *buf = NULL;
5427 QtDemuxStream *stream;
5428 GstClockTime min_time;
5430 GstClockTime dts = GST_CLOCK_TIME_NONE;
5431 GstClockTime pts = GST_CLOCK_TIME_NONE;
5432 GstClockTime duration = 0;
5433 gboolean keyframe = FALSE;
5434 guint sample_size = 0;
5440 gst_qtdemux_push_pending_newsegment (qtdemux);
5442 if (qtdemux->fragmented_seek_pending) {
5443 GST_INFO_OBJECT (qtdemux, "pending fragmented seek");
5444 gst_qtdemux_do_fragmented_seek (qtdemux);
5445 GST_INFO_OBJECT (qtdemux, "fragmented seek done!");
5446 qtdemux->fragmented_seek_pending = FALSE;
5449 /* Figure out the next stream sample to output, min_time is expressed in
5450 * global time and runs over the edit list segments. */
5451 min_time = G_MAXUINT64;
5453 for (i = 0; i < qtdemux->n_streams; i++) {
5454 GstClockTime position;
5456 stream = qtdemux->streams[i];
5457 position = stream->time_position;
5459 /* position of -1 is EOS */
5460 if (position != GST_CLOCK_TIME_NONE && position < min_time) {
5461 min_time = position;
5466 if (G_UNLIKELY (index == -1)) {
5467 GST_DEBUG_OBJECT (qtdemux, "all streams are EOS");
5471 /* check for segment end */
5472 if (G_UNLIKELY (qtdemux->segment.stop != -1
5473 && ((qtdemux->segment.rate >= 0 && qtdemux->segment.stop <= min_time)
5474 || (qtdemux->segment.rate < 0
5475 && qtdemux->segment.start > min_time))
5476 && qtdemux->streams[index]->on_keyframe)) {
5477 GST_DEBUG_OBJECT (qtdemux, "we reached the end of our segment.");
5478 qtdemux->streams[index]->time_position = GST_CLOCK_TIME_NONE;
5482 /* gap events for subtitle streams */
5483 for (i = 0; i < qtdemux->n_streams; i++) {
5484 stream = qtdemux->streams[i];
5485 if (stream->pad && (stream->subtype == FOURCC_subp
5486 || stream->subtype == FOURCC_text
5487 || stream->subtype == FOURCC_sbtl)) {
5488 /* send one second gap events until the stream catches up */
5489 /* gaps can only be sent after segment is activated (segment.stop is no longer -1) */
5490 while (GST_CLOCK_TIME_IS_VALID (stream->segment.stop) &&
5491 GST_CLOCK_TIME_IS_VALID (stream->segment.position) &&
5492 stream->segment.position + GST_SECOND < min_time) {
5494 gst_event_new_gap (stream->segment.position, GST_SECOND);
5495 gst_pad_push_event (stream->pad, gap);
5496 stream->segment.position += GST_SECOND;
5501 stream = qtdemux->streams[index];
5502 if (stream->new_caps) {
5503 gst_qtdemux_configure_stream (qtdemux, stream);
5504 qtdemux_do_allocation (qtdemux, stream);
5507 /* fetch info for the current sample of this stream */
5508 if (G_UNLIKELY (!gst_qtdemux_prepare_current_sample (qtdemux, stream, &empty,
5509 &offset, &sample_size, &dts, &pts, &duration, &keyframe)))
5512 /* If we're doing a keyframe-only trickmode, only push keyframes on video streams */
5513 if (G_UNLIKELY (qtdemux->
5514 segment.flags & GST_SEGMENT_FLAG_TRICKMODE_KEY_UNITS)) {
5515 if (stream->subtype == FOURCC_vide && !keyframe) {
5516 GST_LOG_OBJECT (qtdemux, "Skipping non-keyframe on stream %d", index);
5521 GST_DEBUG_OBJECT (qtdemux,
5522 "pushing from stream %d, empty %d offset %" G_GUINT64_FORMAT
5523 ", size %d, dts=%" GST_TIME_FORMAT ", pts=%" GST_TIME_FORMAT
5524 ", duration %" GST_TIME_FORMAT, index, empty, offset, sample_size,
5525 GST_TIME_ARGS (dts), GST_TIME_ARGS (pts), GST_TIME_ARGS (duration));
5527 if (G_UNLIKELY (empty)) {
5528 /* empty segment, push a gap and move to the next one */
5529 gst_pad_push_event (stream->pad, gst_event_new_gap (pts, duration));
5530 stream->segment.position = pts + duration;
5534 /* hmm, empty sample, skip and move to next sample */
5535 if (G_UNLIKELY (sample_size <= 0))
5538 /* last pushed sample was out of boundary, goto next sample */
5539 if (G_UNLIKELY (GST_PAD_LAST_FLOW_RETURN (stream->pad) == GST_FLOW_EOS))
5542 if (stream->max_buffer_size == 0 || sample_size <= stream->max_buffer_size) {
5545 GST_DEBUG_OBJECT (qtdemux,
5546 "size %d larger than stream max_buffer_size %d, trimming",
5547 sample_size, stream->max_buffer_size);
5549 MIN (sample_size - stream->offset_in_sample, stream->max_buffer_size);
5552 if (qtdemux->cenc_aux_info_offset > 0) {
5555 GstBuffer *aux_info = NULL;
5557 /* pull the data stored before the sample */
5559 gst_qtdemux_pull_atom (qtdemux, qtdemux->offset,
5560 offset + stream->offset_in_sample - qtdemux->offset, &aux_info);
5561 if (G_UNLIKELY (ret != GST_FLOW_OK))
5563 gst_buffer_map (aux_info, &map, GST_MAP_READ);
5564 GST_DEBUG_OBJECT (qtdemux, "parsing cenc auxiliary info");
5565 gst_byte_reader_init (&br, map.data + 8, map.size);
5566 if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
5567 qtdemux->cenc_aux_info_sizes, qtdemux->cenc_aux_sample_count)) {
5568 GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
5569 gst_buffer_unmap (aux_info, &map);
5570 gst_buffer_unref (aux_info);
5571 ret = GST_FLOW_ERROR;
5574 gst_buffer_unmap (aux_info, &map);
5575 gst_buffer_unref (aux_info);
5578 GST_LOG_OBJECT (qtdemux, "reading %d bytes @ %" G_GUINT64_FORMAT, size,
5581 if (stream->use_allocator) {
5582 /* if we have a per-stream allocator, use it */
5583 buf = gst_buffer_new_allocate (stream->allocator, size, &stream->params);
5586 ret = gst_qtdemux_pull_atom (qtdemux, offset + stream->offset_in_sample,
5588 if (G_UNLIKELY (ret != GST_FLOW_OK))
5591 if (size != sample_size) {
5592 pts += gst_util_uint64_scale_int (GST_SECOND,
5593 stream->offset_in_sample / stream->bytes_per_frame, stream->timescale);
5594 dts += gst_util_uint64_scale_int (GST_SECOND,
5595 stream->offset_in_sample / stream->bytes_per_frame, stream->timescale);
5596 duration = gst_util_uint64_scale_int (GST_SECOND,
5597 size / stream->bytes_per_frame, stream->timescale);
5600 ret = gst_qtdemux_decorate_and_push_buffer (qtdemux, stream, buf,
5601 dts, pts, duration, keyframe, min_time, offset);
5603 if (size != sample_size) {
5604 QtDemuxSample *sample = &stream->samples[stream->sample_index];
5605 QtDemuxSegment *segment = &stream->segments[stream->segment_index];
5607 GstClockTime time_position = QTSTREAMTIME_TO_GSTTIME (stream,
5608 sample->timestamp + stream->offset_in_sample / stream->bytes_per_frame);
5609 if (time_position >= segment->media_start) {
5610 /* inside the segment, update time_position, looks very familiar to
5611 * GStreamer segments, doesn't it? */
5612 stream->time_position = (time_position - segment->media_start) +
5615 /* not yet in segment, time does not yet increment. This means
5616 * that we are still prerolling keyframes to the decoder so it can
5617 * decode the first sample of the segment. */
5618 stream->time_position = segment->time;
5623 ret = gst_qtdemux_combine_flows (qtdemux, stream, ret);
5624 /* ignore unlinked, we will not push on the pad anymore and we will EOS when
5625 * we have no more data for the pad to push */
5626 if (ret == GST_FLOW_EOS)
5629 stream->offset_in_sample += size;
5630 if (stream->offset_in_sample >= sample_size) {
5631 gst_qtdemux_advance_sample (qtdemux, stream);
5636 gst_qtdemux_advance_sample (qtdemux, stream);
5644 GST_DEBUG_OBJECT (qtdemux, "No samples left for any streams - EOS");
5650 GST_DEBUG_OBJECT (qtdemux, "No samples left for stream");
5651 /* EOS will be raised if all are EOS */
5658 gst_qtdemux_loop (GstPad * pad)
5660 GstQTDemux *qtdemux;
5664 qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
5666 cur_offset = qtdemux->offset;
5667 GST_LOG_OBJECT (qtdemux, "loop at position %" G_GUINT64_FORMAT ", state %s",
5668 cur_offset, qt_demux_state_string (qtdemux->state));
5670 switch (qtdemux->state) {
5671 case QTDEMUX_STATE_INITIAL:
5672 case QTDEMUX_STATE_HEADER:
5673 ret = gst_qtdemux_loop_state_header (qtdemux);
5675 case QTDEMUX_STATE_MOVIE:
5676 ret = gst_qtdemux_loop_state_movie (qtdemux);
5677 if (qtdemux->segment.rate < 0 && ret == GST_FLOW_EOS) {
5678 ret = gst_qtdemux_seek_to_previous_keyframe (qtdemux);
5686 /* if something went wrong, pause */
5687 if (ret != GST_FLOW_OK)
5691 gst_object_unref (qtdemux);
5697 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
5698 (NULL), ("streaming stopped, invalid state"));
5699 gst_pad_pause_task (pad);
5700 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
5705 const gchar *reason = gst_flow_get_name (ret);
5707 GST_LOG_OBJECT (qtdemux, "pausing task, reason %s", reason);
5709 gst_pad_pause_task (pad);
5711 /* fatal errors need special actions */
5713 if (ret == GST_FLOW_EOS) {
5714 if (qtdemux->n_streams == 0) {
5715 /* we have no streams, post an error */
5716 gst_qtdemux_post_no_playable_stream_error (qtdemux);
5718 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
5721 if ((stop = qtdemux->segment.stop) == -1)
5722 stop = qtdemux->segment.duration;
5724 if (qtdemux->segment.rate >= 0) {
5725 GstMessage *message;
5728 GST_LOG_OBJECT (qtdemux, "Sending segment done, at end of segment");
5729 message = gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
5730 GST_FORMAT_TIME, stop);
5731 event = gst_event_new_segment_done (GST_FORMAT_TIME, stop);
5732 if (qtdemux->segment_seqnum) {
5733 gst_message_set_seqnum (message, qtdemux->segment_seqnum);
5734 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
5736 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), message);
5737 gst_qtdemux_push_event (qtdemux, event);
5739 GstMessage *message;
5742 /* For Reverse Playback */
5743 GST_LOG_OBJECT (qtdemux, "Sending segment done, at start of segment");
5744 message = gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
5745 GST_FORMAT_TIME, qtdemux->segment.start);
5746 event = gst_event_new_segment_done (GST_FORMAT_TIME,
5747 qtdemux->segment.start);
5748 if (qtdemux->segment_seqnum) {
5749 gst_message_set_seqnum (message, qtdemux->segment_seqnum);
5750 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
5752 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), message);
5753 gst_qtdemux_push_event (qtdemux, event);
5758 GST_LOG_OBJECT (qtdemux, "Sending EOS at end of segment");
5759 event = gst_event_new_eos ();
5760 if (qtdemux->segment_seqnum)
5761 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
5762 gst_qtdemux_push_event (qtdemux, event);
5764 } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
5765 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
5766 (NULL), ("streaming stopped, reason %s", reason));
5767 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
5776 * Returns if there are samples to be played.
5779 has_next_entry (GstQTDemux * demux)
5781 QtDemuxStream *stream;
5784 GST_DEBUG_OBJECT (demux, "Checking if there are samples not played yet");
5786 for (i = 0; i < demux->n_streams; i++) {
5787 stream = demux->streams[i];
5789 if (stream->sample_index == -1) {
5790 stream->sample_index = 0;
5791 stream->offset_in_sample = 0;
5794 if (stream->sample_index >= stream->n_samples) {
5795 GST_LOG_OBJECT (demux, "stream %d samples exhausted", i);
5798 GST_DEBUG_OBJECT (demux, "Found a sample");
5802 GST_DEBUG_OBJECT (demux, "There wasn't any next sample");
5809 * Returns the size of the first entry at the current offset.
5810 * If -1, there are none (which means EOS or empty file).
5813 next_entry_size (GstQTDemux * demux)
5815 QtDemuxStream *stream;
5818 guint64 smalloffs = (guint64) - 1;
5819 QtDemuxSample *sample;
5821 GST_LOG_OBJECT (demux, "Finding entry at offset %" G_GUINT64_FORMAT,
5824 for (i = 0; i < demux->n_streams; i++) {
5825 stream = demux->streams[i];
5827 if (stream->sample_index == -1) {
5828 stream->sample_index = 0;
5829 stream->offset_in_sample = 0;
5832 if (stream->sample_index >= stream->n_samples) {
5833 GST_LOG_OBJECT (demux, "stream %d samples exhausted", i);
5837 if (!qtdemux_parse_samples (demux, stream, stream->sample_index)) {
5838 GST_LOG_OBJECT (demux, "Parsing of index %u from stbl atom failed!",
5839 stream->sample_index);
5843 sample = &stream->samples[stream->sample_index];
5845 GST_LOG_OBJECT (demux,
5846 "Checking Stream %d (sample_index:%d / offset:%" G_GUINT64_FORMAT
5847 " / size:%" G_GUINT32_FORMAT ")", i, stream->sample_index,
5848 sample->offset, sample->size);
5850 if (((smalloffs == -1)
5851 || (sample->offset < smalloffs)) && (sample->size)) {
5853 smalloffs = sample->offset;
5857 GST_LOG_OBJECT (demux,
5858 "stream %d offset %" G_GUINT64_FORMAT " demux->offset :%"
5859 G_GUINT64_FORMAT, smallidx, smalloffs, demux->offset);
5864 stream = demux->streams[smallidx];
5865 sample = &stream->samples[stream->sample_index];
5867 if (sample->offset >= demux->offset) {
5868 demux->todrop = sample->offset - demux->offset;
5869 return sample->size + demux->todrop;
5872 GST_DEBUG_OBJECT (demux,
5873 "There wasn't any entry at offset %" G_GUINT64_FORMAT, demux->offset);
5878 gst_qtdemux_post_progress (GstQTDemux * demux, gint num, gint denom)
5880 gint perc = (gint) ((gdouble) num * 100.0 / (gdouble) denom);
5882 gst_element_post_message (GST_ELEMENT_CAST (demux),
5883 gst_message_new_element (GST_OBJECT_CAST (demux),
5884 gst_structure_new ("progress", "percent", G_TYPE_INT, perc, NULL)));
5888 qtdemux_seek_offset (GstQTDemux * demux, guint64 offset)
5893 GST_DEBUG_OBJECT (demux, "Seeking to %" G_GUINT64_FORMAT, offset);
5896 gst_event_new_seek (1.0, GST_FORMAT_BYTES,
5897 GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset,
5898 GST_SEEK_TYPE_NONE, -1);
5900 /* store seqnum to drop flush events, they don't need to reach downstream */
5901 demux->offset_seek_seqnum = gst_event_get_seqnum (event);
5902 res = gst_pad_push_event (demux->sinkpad, event);
5903 demux->offset_seek_seqnum = 0;
5908 /* check for seekable upstream, above and beyond a mere query */
5910 gst_qtdemux_check_seekability (GstQTDemux * demux)
5913 gboolean seekable = FALSE;
5914 gint64 start = -1, stop = -1;
5916 if (demux->upstream_size)
5919 query = gst_query_new_seeking (GST_FORMAT_BYTES);
5920 if (!gst_pad_peer_query (demux->sinkpad, query)) {
5921 GST_DEBUG_OBJECT (demux, "seeking query failed");
5925 gst_query_parse_seeking (query, NULL, &seekable, &start, &stop);
5927 /* try harder to query upstream size if we didn't get it the first time */
5928 if (seekable && stop == -1) {
5929 GST_DEBUG_OBJECT (demux, "doing duration query to fix up unset stop");
5930 gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &stop);
5933 /* if upstream doesn't know the size, it's likely that it's not seekable in
5934 * practice even if it technically may be seekable */
5935 if (seekable && (start != 0 || stop <= start)) {
5936 GST_DEBUG_OBJECT (demux, "seekable but unknown start/stop -> disable");
5941 gst_query_unref (query);
5943 GST_DEBUG_OBJECT (demux, "seekable: %d (%" G_GUINT64_FORMAT " - %"
5944 G_GUINT64_FORMAT ")", seekable, start, stop);
5945 demux->upstream_seekable = seekable;
5946 demux->upstream_size = seekable ? stop : -1;
5950 gst_qtdemux_drop_data (GstQTDemux * demux, gint bytes)
5952 g_return_if_fail (bytes <= demux->todrop);
5954 GST_LOG_OBJECT (demux, "Dropping %d bytes", bytes);
5955 gst_adapter_flush (demux->adapter, bytes);
5956 demux->neededbytes -= bytes;
5957 demux->offset += bytes;
5958 demux->todrop -= bytes;
5962 gst_qtdemux_check_send_pending_segment (GstQTDemux * demux)
5964 if (G_UNLIKELY (demux->pending_newsegment)) {
5967 gst_qtdemux_push_pending_newsegment (demux);
5968 /* clear to send tags on all streams */
5969 for (i = 0; i < demux->n_streams; i++) {
5970 QtDemuxStream *stream;
5971 stream = demux->streams[i];
5972 gst_qtdemux_push_tags (demux, stream);
5973 if (stream->sparse) {
5974 GST_INFO_OBJECT (demux, "Sending gap event on stream %d", i);
5975 gst_pad_push_event (stream->pad,
5976 gst_event_new_gap (stream->segment.position, GST_CLOCK_TIME_NONE));
5983 gst_qtdemux_send_gap_for_segment (GstQTDemux * demux,
5984 QtDemuxStream * stream, gint segment_index, GstClockTime pos)
5986 GstClockTime ts, dur;
5991 stream->segments[segment_index].duration - (pos -
5992 stream->segments[segment_index].time);
5993 gap = gst_event_new_gap (ts, dur);
5994 stream->time_position += dur;
5996 GST_DEBUG_OBJECT (stream->pad, "Pushing gap for empty "
5997 "segment: %" GST_PTR_FORMAT, gap);
5998 gst_pad_push_event (stream->pad, gap);
6002 gst_qtdemux_stream_send_initial_gap_segments (GstQTDemux * demux,
6003 QtDemuxStream * stream)
6007 /* Push any initial gap segments before proceeding to the
6009 for (i = 0; i < stream->n_segments; i++) {
6010 gst_qtdemux_activate_segment (demux, stream, i, stream->time_position);
6012 if (QTSEGMENT_IS_EMPTY (&stream->segments[i])) {
6013 gst_qtdemux_send_gap_for_segment (demux, stream, i,
6014 stream->time_position);
6016 /* Only support empty segment at the beginning followed by
6017 * one non-empty segment, this was checked when parsing the
6018 * edts atom, arriving here is unexpected */
6019 g_assert (i + 1 == stream->n_segments);
6025 static GstFlowReturn
6026 gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent, GstBuffer * inbuf)
6030 demux = GST_QTDEMUX (parent);
6032 GST_DEBUG_OBJECT (demux,
6033 "Received buffer pts:%" GST_TIME_FORMAT " dts:%" GST_TIME_FORMAT
6034 " offset:%" G_GUINT64_FORMAT " size:%" G_GSIZE_FORMAT,
6035 GST_TIME_ARGS (GST_BUFFER_PTS (inbuf)),
6036 GST_TIME_ARGS (GST_BUFFER_DTS (inbuf)), GST_BUFFER_OFFSET (inbuf),
6037 gst_buffer_get_size (inbuf));
6039 if (GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_DISCONT)) {
6042 GST_DEBUG_OBJECT (demux, "Got DISCONT, marking all streams as DISCONT");
6044 for (i = 0; i < demux->n_streams; i++) {
6045 demux->streams[i]->discont = TRUE;
6048 /* Reverse fragmented playback, need to flush all we have before
6049 * consuming a new fragment.
6050 * The samples array have the timestamps calculated by accumulating the
6051 * durations but this won't work for reverse playback of fragments as
6052 * the timestamps of a subsequent fragment should be smaller than the
6053 * previously received one. */
6054 if (demux->fragmented && demux->segment.rate < 0) {
6055 gst_qtdemux_process_adapter (demux, TRUE);
6056 for (i = 0; i < demux->n_streams; i++)
6057 gst_qtdemux_stream_flush_samples_data (demux, demux->streams[i]);
6061 gst_adapter_push (demux->adapter, inbuf);
6063 GST_DEBUG_OBJECT (demux,
6064 "pushing in inbuf %p, neededbytes:%u, available:%" G_GSIZE_FORMAT, inbuf,
6065 demux->neededbytes, gst_adapter_available (demux->adapter));
6067 return gst_qtdemux_process_adapter (demux, FALSE);
6070 static GstFlowReturn
6071 gst_qtdemux_process_adapter (GstQTDemux * demux, gboolean force)
6073 GstFlowReturn ret = GST_FLOW_OK;
6075 /* we never really mean to buffer that much */
6076 if (demux->neededbytes == -1) {
6080 while (((gst_adapter_available (demux->adapter)) >= demux->neededbytes) &&
6081 (ret == GST_FLOW_OK || (ret == GST_FLOW_NOT_LINKED && force))) {
6083 GST_DEBUG_OBJECT (demux,
6084 "state:%s , demux->neededbytes:%d, demux->offset:%" G_GUINT64_FORMAT,
6085 qt_demux_state_string (demux->state), demux->neededbytes,
6088 switch (demux->state) {
6089 case QTDEMUX_STATE_INITIAL:{
6094 gst_qtdemux_check_seekability (demux);
6096 data = gst_adapter_map (demux->adapter, demux->neededbytes);
6098 /* get fourcc/length, set neededbytes */
6099 extract_initial_length_and_fourcc ((guint8 *) data, demux->neededbytes,
6101 gst_adapter_unmap (demux->adapter);
6103 GST_DEBUG_OBJECT (demux, "Peeking found [%" GST_FOURCC_FORMAT "] "
6104 "size: %" G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), size);
6106 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
6107 (_("This file is invalid and cannot be played.")),
6108 ("initial atom '%" GST_FOURCC_FORMAT "' has empty length",
6109 GST_FOURCC_ARGS (fourcc)));
6110 ret = GST_FLOW_ERROR;
6113 if (fourcc == FOURCC_mdat) {
6114 gint next_entry = next_entry_size (demux);
6115 if (demux->n_streams > 0 && (next_entry != -1 || !demux->fragmented)) {
6116 /* we have the headers, start playback */
6117 demux->state = QTDEMUX_STATE_MOVIE;
6118 demux->neededbytes = next_entry;
6119 demux->mdatleft = size;
6121 /* no headers yet, try to get them */
6124 guint64 old, target;
6127 old = demux->offset;
6128 target = old + size;
6130 /* try to jump over the atom with a seek */
6131 /* only bother if it seems worth doing so,
6132 * and avoids possible upstream/server problems */
6133 if (demux->upstream_seekable &&
6134 demux->upstream_size > 4 * (1 << 20)) {
6135 res = qtdemux_seek_offset (demux, target);
6137 GST_DEBUG_OBJECT (demux, "skipping seek");
6142 GST_DEBUG_OBJECT (demux, "seek success");
6143 /* remember the offset fo the first mdat so we can seek back to it
6144 * after we have the headers */
6145 if (fourcc == FOURCC_mdat && demux->first_mdat == -1) {
6146 demux->first_mdat = old;
6147 GST_DEBUG_OBJECT (demux, "first mdat at %" G_GUINT64_FORMAT,
6150 /* seek worked, continue reading */
6151 demux->offset = target;
6152 demux->neededbytes = 16;
6153 demux->state = QTDEMUX_STATE_INITIAL;
6155 /* seek failed, need to buffer */
6156 demux->offset = old;
6157 GST_DEBUG_OBJECT (demux, "seek failed/skipped");
6158 /* there may be multiple mdat (or alike) buffers */
6160 if (demux->mdatbuffer)
6161 bs = gst_buffer_get_size (demux->mdatbuffer);
6164 if (size + bs > 10 * (1 << 20))
6166 demux->state = QTDEMUX_STATE_BUFFER_MDAT;
6167 demux->neededbytes = size;
6168 if (!demux->mdatbuffer)
6169 demux->mdatoffset = demux->offset;
6172 } else if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
6173 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
6174 (_("This file is invalid and cannot be played.")),
6175 ("atom %" GST_FOURCC_FORMAT " has bogus size %" G_GUINT64_FORMAT,
6176 GST_FOURCC_ARGS (fourcc), size));
6177 ret = GST_FLOW_ERROR;
6180 /* this means we already started buffering and still no moov header,
6181 * let's continue buffering everything till we get moov */
6182 if (demux->mdatbuffer && !(fourcc == FOURCC_moov
6183 || fourcc == FOURCC_moof))
6185 demux->neededbytes = size;
6186 demux->state = QTDEMUX_STATE_HEADER;
6190 case QTDEMUX_STATE_HEADER:{
6194 GST_DEBUG_OBJECT (demux, "In header");
6196 data = gst_adapter_map (demux->adapter, demux->neededbytes);
6198 /* parse the header */
6199 extract_initial_length_and_fourcc (data, demux->neededbytes, NULL,
6201 if (fourcc == FOURCC_moov) {
6204 /* in usual fragmented setup we could try to scan for more
6205 * and end up at the the moov (after mdat) again */
6206 if (demux->got_moov && demux->n_streams > 0 &&
6208 || demux->last_moov_offset == demux->offset)) {
6209 GST_DEBUG_OBJECT (demux,
6210 "Skipping moov atom as we have (this) one already");
6212 GST_DEBUG_OBJECT (demux, "Parsing [moov]");
6214 if (demux->got_moov && demux->fragmented) {
6215 GST_DEBUG_OBJECT (demux,
6216 "Got a second moov, clean up data from old one");
6217 if (demux->moov_node)
6218 g_node_destroy (demux->moov_node);
6219 demux->moov_node = NULL;
6220 demux->moov_node_compressed = NULL;
6222 /* prepare newsegment to send when streaming actually starts */
6223 if (!demux->pending_newsegment) {
6224 demux->pending_newsegment =
6225 gst_event_new_segment (&demux->segment);
6226 if (demux->segment_seqnum)
6227 gst_event_set_seqnum (demux->pending_newsegment,
6228 demux->segment_seqnum);
6232 demux->last_moov_offset = demux->offset;
6234 qtdemux_parse_moov (demux, data, demux->neededbytes);
6235 qtdemux_node_dump (demux, demux->moov_node);
6236 qtdemux_parse_tree (demux);
6237 qtdemux_prepare_streams (demux);
6238 if (!demux->got_moov)
6239 qtdemux_expose_streams (demux);
6242 for (n = 0; n < demux->n_streams; n++) {
6243 QtDemuxStream *stream = demux->streams[n];
6245 gst_qtdemux_configure_stream (demux, stream);
6249 demux->got_moov = TRUE;
6250 gst_qtdemux_check_send_pending_segment (demux);
6252 /* fragmented streams headers shouldn't contain edts atoms */
6253 if (!demux->fragmented) {
6254 for (n = 0; n < demux->n_streams; n++) {
6255 gst_qtdemux_stream_send_initial_gap_segments (demux,
6260 g_node_destroy (demux->moov_node);
6261 demux->moov_node = NULL;
6262 GST_DEBUG_OBJECT (demux, "Finished parsing the header");
6264 } else if (fourcc == FOURCC_moof) {
6265 if ((demux->got_moov || demux->media_caps) && demux->fragmented) {
6267 GstClockTime prev_pts;
6268 guint64 prev_offset;
6270 GST_DEBUG_OBJECT (demux, "Parsing [moof]");
6273 * The timestamp of the moof buffer is relevant as some scenarios
6274 * won't have the initial timestamp in the atoms. Whenever a new
6275 * buffer has started, we get that buffer's PTS and use it as a base
6276 * timestamp for the trun entries.
6278 * To keep track of the current buffer timestamp and starting point
6279 * we use gst_adapter_prev_pts that gives us the PTS and the distance
6280 * from the beggining of the buffer, with the distance and demux->offset
6281 * we know if it is still the same buffer or not.
6283 prev_pts = gst_adapter_prev_pts (demux->adapter, &dist);
6284 prev_offset = demux->offset - dist;
6285 if (demux->fragment_start_offset == -1
6286 || prev_offset > demux->fragment_start_offset) {
6287 demux->fragment_start_offset = prev_offset;
6288 demux->fragment_start = prev_pts;
6289 GST_DEBUG_OBJECT (demux,
6290 "New fragment start found at: %" G_GUINT64_FORMAT " : %"
6291 GST_TIME_FORMAT, demux->fragment_start_offset,
6292 GST_TIME_ARGS (demux->fragment_start));
6295 demux->moof_offset = demux->offset;
6296 if (!qtdemux_parse_moof (demux, data, demux->neededbytes,
6297 demux->offset, NULL)) {
6298 gst_adapter_unmap (demux->adapter);
6299 ret = GST_FLOW_ERROR;
6302 /* in MSS we need to expose the pads after the first moof as we won't get a moov */
6303 if (demux->mss_mode && !demux->exposed) {
6304 if (!demux->pending_newsegment) {
6305 GST_DEBUG_OBJECT (demux, "new pending_newsegment");
6306 demux->pending_newsegment =
6307 gst_event_new_segment (&demux->segment);
6308 if (demux->segment_seqnum)
6309 gst_event_set_seqnum (demux->pending_newsegment,
6310 demux->segment_seqnum);
6312 qtdemux_expose_streams (demux);
6315 GST_DEBUG_OBJECT (demux, "Discarding [moof]");
6317 } else if (fourcc == FOURCC_ftyp) {
6318 GST_DEBUG_OBJECT (demux, "Parsing [ftyp]");
6319 qtdemux_parse_ftyp (demux, data, demux->neededbytes);
6320 } else if (fourcc == FOURCC_uuid) {
6321 GST_DEBUG_OBJECT (demux, "Parsing [uuid]");
6322 qtdemux_parse_uuid (demux, data, demux->neededbytes);
6323 } else if (fourcc == FOURCC_sidx) {
6324 GST_DEBUG_OBJECT (demux, "Parsing [sidx]");
6325 qtdemux_parse_sidx (demux, data, demux->neededbytes);
6327 GST_WARNING_OBJECT (demux,
6328 "Unknown fourcc while parsing header : %" GST_FOURCC_FORMAT,
6329 GST_FOURCC_ARGS (fourcc));
6330 /* Let's jump that one and go back to initial state */
6332 gst_adapter_unmap (demux->adapter);
6335 if (demux->mdatbuffer && demux->n_streams) {
6336 gsize remaining_data_size = 0;
6338 /* the mdat was before the header */
6339 GST_DEBUG_OBJECT (demux, "We have n_streams:%d and mdatbuffer:%p",
6340 demux->n_streams, demux->mdatbuffer);
6341 /* restore our adapter/offset view of things with upstream;
6342 * put preceding buffered data ahead of current moov data.
6343 * This should also handle evil mdat, moov, mdat cases and alike */
6344 gst_adapter_flush (demux->adapter, demux->neededbytes);
6346 /* Store any remaining data after the mdat for later usage */
6347 remaining_data_size = gst_adapter_available (demux->adapter);
6348 if (remaining_data_size > 0) {
6349 g_assert (demux->restoredata_buffer == NULL);
6350 demux->restoredata_buffer =
6351 gst_adapter_take_buffer (demux->adapter, remaining_data_size);
6352 demux->restoredata_offset = demux->offset + demux->neededbytes;
6353 GST_DEBUG_OBJECT (demux,
6354 "Stored %" G_GSIZE_FORMAT " post mdat bytes at offset %"
6355 G_GUINT64_FORMAT, remaining_data_size,
6356 demux->restoredata_offset);
6359 gst_adapter_push (demux->adapter, demux->mdatbuffer);
6360 demux->mdatbuffer = NULL;
6361 demux->offset = demux->mdatoffset;
6362 demux->neededbytes = next_entry_size (demux);
6363 demux->state = QTDEMUX_STATE_MOVIE;
6364 demux->mdatleft = gst_adapter_available (demux->adapter);
6366 GST_DEBUG_OBJECT (demux, "Carrying on normally");
6367 gst_adapter_flush (demux->adapter, demux->neededbytes);
6369 /* only go back to the mdat if there are samples to play */
6370 if (demux->got_moov && demux->first_mdat != -1
6371 && has_next_entry (demux)) {
6374 /* we need to seek back */
6375 res = qtdemux_seek_offset (demux, demux->first_mdat);
6377 demux->offset = demux->first_mdat;
6379 GST_DEBUG_OBJECT (demux, "Seek back failed");
6382 demux->offset += demux->neededbytes;
6384 demux->neededbytes = 16;
6385 demux->state = QTDEMUX_STATE_INITIAL;
6390 case QTDEMUX_STATE_BUFFER_MDAT:{
6394 GST_DEBUG_OBJECT (demux, "Got our buffer at offset %" G_GUINT64_FORMAT,
6396 buf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
6397 gst_buffer_extract (buf, 0, fourcc, 4);
6398 GST_DEBUG_OBJECT (demux, "mdatbuffer starts with %" GST_FOURCC_FORMAT,
6399 GST_FOURCC_ARGS (QT_FOURCC (fourcc)));
6400 if (demux->mdatbuffer)
6401 demux->mdatbuffer = gst_buffer_append (demux->mdatbuffer, buf);
6403 demux->mdatbuffer = buf;
6404 demux->offset += demux->neededbytes;
6405 demux->neededbytes = 16;
6406 demux->state = QTDEMUX_STATE_INITIAL;
6407 gst_qtdemux_post_progress (demux, 1, 1);
6411 case QTDEMUX_STATE_MOVIE:{
6412 QtDemuxStream *stream = NULL;
6413 QtDemuxSample *sample;
6415 GstClockTime dts, pts, duration;
6418 GST_DEBUG_OBJECT (demux,
6419 "BEGIN // in MOVIE for offset %" G_GUINT64_FORMAT, demux->offset);
6421 if (demux->fragmented) {
6422 GST_DEBUG_OBJECT (demux, "mdat remaining %" G_GUINT64_FORMAT,
6424 if (G_LIKELY (demux->todrop < demux->mdatleft)) {
6425 /* if needed data starts within this atom,
6426 * then it should not exceed this atom */
6427 if (G_UNLIKELY (demux->neededbytes > demux->mdatleft)) {
6428 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
6429 (_("This file is invalid and cannot be played.")),
6430 ("sample data crosses atom boundary"));
6431 ret = GST_FLOW_ERROR;
6434 demux->mdatleft -= demux->neededbytes;
6436 GST_DEBUG_OBJECT (demux, "data atom emptied; resuming atom scan");
6437 /* so we are dropping more than left in this atom */
6438 gst_qtdemux_drop_data (demux, demux->mdatleft);
6439 demux->mdatleft = 0;
6441 /* need to resume atom parsing so we do not miss any other pieces */
6442 demux->state = QTDEMUX_STATE_INITIAL;
6443 demux->neededbytes = 16;
6445 /* check if there was any stored post mdat data from previous buffers */
6446 if (demux->restoredata_buffer) {
6447 g_assert (gst_adapter_available (demux->adapter) == 0);
6449 gst_adapter_push (demux->adapter, demux->restoredata_buffer);
6450 demux->restoredata_buffer = NULL;
6451 demux->offset = demux->restoredata_offset;
6458 if (demux->todrop) {
6459 if (demux->cenc_aux_info_offset > 0) {
6463 GST_DEBUG_OBJECT (demux, "parsing cenc auxiliary info");
6464 data = gst_adapter_map (demux->adapter, demux->todrop);
6465 gst_byte_reader_init (&br, data + 8, demux->todrop);
6466 if (!qtdemux_parse_cenc_aux_info (demux, demux->streams[0], &br,
6467 demux->cenc_aux_info_sizes, demux->cenc_aux_sample_count)) {
6468 GST_ERROR_OBJECT (demux, "failed to parse cenc auxiliary info");
6469 ret = GST_FLOW_ERROR;
6470 gst_adapter_unmap (demux->adapter);
6471 g_free (demux->cenc_aux_info_sizes);
6472 demux->cenc_aux_info_sizes = NULL;
6475 demux->cenc_aux_info_offset = 0;
6476 g_free (demux->cenc_aux_info_sizes);
6477 demux->cenc_aux_info_sizes = NULL;
6478 gst_adapter_unmap (demux->adapter);
6480 gst_qtdemux_drop_data (demux, demux->todrop);
6484 /* initial newsegment sent here after having added pads,
6485 * possible others in sink_event */
6486 gst_qtdemux_check_send_pending_segment (demux);
6488 /* Figure out which stream this packet belongs to */
6489 for (i = 0; i < demux->n_streams; i++) {
6490 stream = demux->streams[i];
6491 if (stream->sample_index >= stream->n_samples)
6493 GST_LOG_OBJECT (demux,
6494 "Checking stream %d (sample_index:%d / offset:%" G_GUINT64_FORMAT
6495 " / size:%d)", i, stream->sample_index,
6496 stream->samples[stream->sample_index].offset,
6497 stream->samples[stream->sample_index].size);
6499 if (stream->samples[stream->sample_index].offset == demux->offset)
6503 if (G_UNLIKELY (stream == NULL || i == demux->n_streams))
6504 goto unknown_stream;
6506 if (stream->new_caps) {
6507 gst_qtdemux_configure_stream (demux, stream);
6510 /* Put data in a buffer, set timestamps, caps, ... */
6511 sample = &stream->samples[stream->sample_index];
6513 if (G_LIKELY (!(STREAM_IS_EOS (stream)))) {
6514 GST_DEBUG_OBJECT (demux, "stream : %" GST_FOURCC_FORMAT,
6515 GST_FOURCC_ARGS (stream->fourcc));
6517 dts = QTSAMPLE_DTS (stream, sample);
6518 pts = QTSAMPLE_PTS (stream, sample);
6519 duration = QTSAMPLE_DUR_DTS (stream, sample, dts);
6520 keyframe = QTSAMPLE_KEYFRAME (stream, sample);
6522 /* check for segment end */
6523 if (G_UNLIKELY (demux->segment.stop != -1
6524 && demux->segment.stop <= pts && stream->on_keyframe)) {
6525 GST_DEBUG_OBJECT (demux, "we reached the end of our segment.");
6526 stream->time_position = GST_CLOCK_TIME_NONE; /* this means EOS */
6528 /* skip this data, stream is EOS */
6529 gst_adapter_flush (demux->adapter, demux->neededbytes);
6531 /* check if all streams are eos */
6533 for (i = 0; i < demux->n_streams; i++) {
6534 if (!STREAM_IS_EOS (demux->streams[i])) {
6540 if (ret == GST_FLOW_EOS) {
6541 GST_DEBUG_OBJECT (demux, "All streams are EOS, signal upstream");
6548 gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
6550 /* FIXME: should either be an assert or a plain check */
6551 g_return_val_if_fail (outbuf != NULL, GST_FLOW_ERROR);
6553 ret = gst_qtdemux_decorate_and_push_buffer (demux, stream, outbuf,
6554 dts, pts, duration, keyframe, dts, demux->offset);
6558 ret = gst_qtdemux_combine_flows (demux, stream, ret);
6559 if (ret != GST_FLOW_OK && ret != GST_FLOW_NOT_LINKED)
6560 goto non_ok_unlinked_flow;
6562 /* skip this data, stream is EOS */
6563 gst_adapter_flush (demux->adapter, demux->neededbytes);
6566 stream->sample_index++;
6567 stream->offset_in_sample = 0;
6569 /* update current offset and figure out size of next buffer */
6570 GST_LOG_OBJECT (demux, "increasing offset %" G_GUINT64_FORMAT " by %u",
6571 demux->offset, demux->neededbytes);
6572 demux->offset += demux->neededbytes;
6573 GST_LOG_OBJECT (demux, "offset is now %" G_GUINT64_FORMAT,
6576 if ((demux->neededbytes = next_entry_size (demux)) == -1) {
6577 if (demux->fragmented) {
6578 GST_DEBUG_OBJECT (demux, "(temporarily) out of fragmented samples");
6579 /* there may be more to follow, only finish this atom */
6580 demux->todrop = demux->mdatleft;
6581 demux->neededbytes = demux->todrop;
6593 /* when buffering movie data, at least show user something is happening */
6594 if (ret == GST_FLOW_OK && demux->state == QTDEMUX_STATE_BUFFER_MDAT &&
6595 gst_adapter_available (demux->adapter) <= demux->neededbytes) {
6596 gst_qtdemux_post_progress (demux, gst_adapter_available (demux->adapter),
6597 demux->neededbytes);
6604 non_ok_unlinked_flow:
6606 GST_DEBUG_OBJECT (demux, "Stopping, combined return flow %s",
6607 gst_flow_get_name (ret));
6612 GST_ELEMENT_ERROR (demux, STREAM, FAILED, (NULL), ("unknown stream found"));
6613 ret = GST_FLOW_ERROR;
6618 GST_DEBUG_OBJECT (demux, "no next entry, EOS");
6624 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
6625 (NULL), ("qtdemuxer invalid state %d", demux->state));
6626 ret = GST_FLOW_ERROR;
6631 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
6632 (NULL), ("no 'moov' atom within the first 10 MB"));
6633 ret = GST_FLOW_ERROR;
6639 qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent)
6644 query = gst_query_new_scheduling ();
6646 if (!gst_pad_peer_query (sinkpad, query)) {
6647 gst_query_unref (query);
6651 pull_mode = gst_query_has_scheduling_mode_with_flags (query,
6652 GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
6653 gst_query_unref (query);
6658 GST_DEBUG_OBJECT (sinkpad, "activating pull");
6659 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
6663 GST_DEBUG_OBJECT (sinkpad, "activating push");
6664 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
6669 qtdemux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
6670 GstPadMode mode, gboolean active)
6673 GstQTDemux *demux = GST_QTDEMUX (parent);
6676 case GST_PAD_MODE_PUSH:
6677 demux->pullbased = FALSE;
6680 case GST_PAD_MODE_PULL:
6682 demux->pullbased = TRUE;
6683 res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_qtdemux_loop,
6686 res = gst_pad_stop_task (sinkpad);
6698 qtdemux_zalloc (void *opaque, unsigned int items, unsigned int size)
6700 return g_malloc (items * size);
6704 qtdemux_zfree (void *opaque, void *addr)
6710 qtdemux_inflate (void *z_buffer, guint z_length, guint length)
6716 z = g_new0 (z_stream, 1);
6717 z->zalloc = qtdemux_zalloc;
6718 z->zfree = qtdemux_zfree;
6721 z->next_in = z_buffer;
6722 z->avail_in = z_length;
6724 buffer = (guint8 *) g_malloc (length);
6725 ret = inflateInit (z);
6726 while (z->avail_in > 0) {
6727 if (z->avail_out == 0) {
6729 buffer = (guint8 *) g_realloc (buffer, length);
6730 z->next_out = buffer + z->total_out;
6731 z->avail_out = 1024;
6733 ret = inflate (z, Z_SYNC_FLUSH);
6737 if (ret != Z_STREAM_END) {
6738 g_warning ("inflate() returned %d", ret);
6744 #endif /* HAVE_ZLIB */
6747 qtdemux_parse_moov (GstQTDemux * qtdemux, const guint8 * buffer, guint length)
6751 qtdemux->moov_node = g_node_new ((guint8 *) buffer);
6753 /* counts as header data */
6754 qtdemux->header_size += length;
6756 GST_DEBUG_OBJECT (qtdemux, "parsing 'moov' atom");
6757 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buffer, length);
6759 cmov = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_cmov);
6765 dcom = qtdemux_tree_get_child_by_type (cmov, FOURCC_dcom);
6766 cmvd = qtdemux_tree_get_child_by_type (cmov, FOURCC_cmvd);
6767 if (dcom == NULL || cmvd == NULL)
6768 goto invalid_compression;
6770 method = QT_FOURCC ((guint8 *) dcom->data + 8);
6774 guint uncompressed_length;
6775 guint compressed_length;
6778 uncompressed_length = QT_UINT32 ((guint8 *) cmvd->data + 8);
6779 compressed_length = QT_UINT32 ((guint8 *) cmvd->data + 4) - 12;
6780 GST_LOG ("length = %u", uncompressed_length);
6783 (guint8 *) qtdemux_inflate ((guint8 *) cmvd->data + 12,
6784 compressed_length, uncompressed_length);
6786 qtdemux->moov_node_compressed = qtdemux->moov_node;
6787 qtdemux->moov_node = g_node_new (buf);
6789 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buf,
6790 uncompressed_length);
6793 #endif /* HAVE_ZLIB */
6795 GST_WARNING_OBJECT (qtdemux, "unknown or unhandled header compression "
6796 "type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (method));
6803 invalid_compression:
6805 GST_ERROR_OBJECT (qtdemux, "invalid compressed header");
6811 qtdemux_parse_container (GstQTDemux * qtdemux, GNode * node, const guint8 * buf,
6814 while (G_UNLIKELY (buf < end)) {
6818 if (G_UNLIKELY (buf + 4 > end)) {
6819 GST_LOG_OBJECT (qtdemux, "buffer overrun");
6822 len = QT_UINT32 (buf);
6823 if (G_UNLIKELY (len == 0)) {
6824 GST_LOG_OBJECT (qtdemux, "empty container");
6827 if (G_UNLIKELY (len < 8)) {
6828 GST_WARNING_OBJECT (qtdemux, "length too short (%d < 8)", len);
6831 if (G_UNLIKELY (len > (end - buf))) {
6832 GST_WARNING_OBJECT (qtdemux, "length too long (%d > %d)", len,
6833 (gint) (end - buf));
6837 child = g_node_new ((guint8 *) buf);
6838 g_node_append (node, child);
6839 GST_LOG_OBJECT (qtdemux, "adding new node of len %d", len);
6840 qtdemux_parse_node (qtdemux, child, buf, len);
6848 qtdemux_parse_theora_extension (GstQTDemux * qtdemux, QtDemuxStream * stream,
6851 int len = QT_UINT32 (xdxt->data);
6852 guint8 *buf = xdxt->data;
6853 guint8 *end = buf + len;
6856 /* skip size and type */
6864 size = QT_UINT32 (buf);
6865 type = QT_FOURCC (buf + 4);
6867 GST_LOG_OBJECT (qtdemux, "%p %p", buf, end);
6869 if (buf + size > end || size <= 0)
6875 GST_WARNING_OBJECT (qtdemux, "have cookie %" GST_FOURCC_FORMAT,
6876 GST_FOURCC_ARGS (type));
6880 buffer = gst_buffer_new_and_alloc (size);
6881 gst_buffer_fill (buffer, 0, buf, size);
6882 stream->buffers = g_slist_append (stream->buffers, buffer);
6883 GST_LOG_OBJECT (qtdemux, "parsing theora header");
6886 buffer = gst_buffer_new_and_alloc (size);
6887 gst_buffer_fill (buffer, 0, buf, size);
6888 stream->buffers = g_slist_append (stream->buffers, buffer);
6889 GST_LOG_OBJECT (qtdemux, "parsing theora comment");
6892 buffer = gst_buffer_new_and_alloc (size);
6893 gst_buffer_fill (buffer, 0, buf, size);
6894 stream->buffers = g_slist_append (stream->buffers, buffer);
6895 GST_LOG_OBJECT (qtdemux, "parsing theora codebook");
6898 GST_WARNING_OBJECT (qtdemux,
6899 "unknown theora cookie %" GST_FOURCC_FORMAT,
6900 GST_FOURCC_ARGS (type));
6909 qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node, const guint8 * buffer,
6913 guint32 node_length = 0;
6914 const QtNodeType *type;
6917 GST_LOG_OBJECT (qtdemux, "qtdemux_parse buffer %p length %u", buffer, length);
6919 if (G_UNLIKELY (length < 8))
6920 goto not_enough_data;
6922 node_length = QT_UINT32 (buffer);
6923 fourcc = QT_FOURCC (buffer + 4);
6925 /* ignore empty nodes */
6926 if (G_UNLIKELY (fourcc == 0 || node_length == 8))
6929 type = qtdemux_type_get (fourcc);
6931 end = buffer + length;
6933 GST_LOG_OBJECT (qtdemux,
6934 "parsing '%" GST_FOURCC_FORMAT "', length=%u, name '%s'",
6935 GST_FOURCC_ARGS (fourcc), node_length, type->name);
6937 if (node_length > length)
6938 goto broken_atom_size;
6940 if (type->flags & QT_FLAG_CONTAINER) {
6941 qtdemux_parse_container (qtdemux, node, buffer + 8, end);
6946 if (node_length < 20) {
6947 GST_LOG_OBJECT (qtdemux, "skipping small stsd box");
6950 GST_DEBUG_OBJECT (qtdemux,
6951 "parsing stsd (sample table, sample description) atom");
6952 /* Skip over 8 byte atom hdr + 1 byte version, 3 bytes flags, 4 byte num_entries */
6953 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
6963 /* also read alac (or whatever) in stead of mp4a in the following,
6964 * since a similar layout is used in other cases as well */
6965 if (fourcc == FOURCC_mp4a)
6970 /* There are two things we might encounter here: a true mp4a atom, and
6971 an mp4a entry in an stsd atom. The latter is what we're interested
6972 in, and it looks like an atom, but isn't really one. The true mp4a
6973 atom is short, so we detect it based on length here. */
6974 if (length < min_size) {
6975 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
6976 GST_FOURCC_ARGS (fourcc));
6980 /* 'version' here is the sound sample description version. Types 0 and
6981 1 are documented in the QTFF reference, but type 2 is not: it's
6982 described in Apple header files instead (struct SoundDescriptionV2
6984 version = QT_UINT16 (buffer + 16);
6986 GST_DEBUG_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT " version 0x%08x",
6987 GST_FOURCC_ARGS (fourcc), version);
6989 /* parse any esds descriptors */
7001 GST_WARNING_OBJECT (qtdemux,
7002 "unhandled %" GST_FOURCC_FORMAT " version 0x%08x",
7003 GST_FOURCC_ARGS (fourcc), version);
7008 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
7025 /* codec_data is contained inside these atoms, which all have
7026 * the same format. */
7028 GST_DEBUG_OBJECT (qtdemux, "parsing in %" GST_FOURCC_FORMAT,
7029 GST_FOURCC_ARGS (fourcc));
7030 version = QT_UINT32 (buffer + 16);
7031 GST_DEBUG_OBJECT (qtdemux, "version %08x", version);
7032 if (1 || version == 0x00000000) {
7033 buf = buffer + 0x32;
7035 /* FIXME Quicktime uses PASCAL string while
7036 * the iso format uses C strings. Check the file
7037 * type before attempting to parse the string here. */
7038 tlen = QT_UINT8 (buf);
7039 GST_DEBUG_OBJECT (qtdemux, "tlen = %d", tlen);
7041 GST_DEBUG_OBJECT (qtdemux, "string = %.*s", tlen, (char *) buf);
7042 /* the string has a reserved space of 32 bytes so skip
7043 * the remaining 31 */
7045 buf += 4; /* and 4 bytes reserved */
7047 GST_MEMDUMP_OBJECT (qtdemux, "mp4v", buf, end - buf);
7049 qtdemux_parse_container (qtdemux, node, buf, end);
7055 GST_MEMDUMP_OBJECT (qtdemux, "H264", buffer, end - buffer);
7056 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
7061 GST_MEMDUMP_OBJECT (qtdemux, "avc1", buffer, end - buffer);
7062 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
7067 GST_MEMDUMP_OBJECT (qtdemux, "avc3", buffer, end - buffer);
7068 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
7073 GST_MEMDUMP_OBJECT (qtdemux, "H265", buffer, end - buffer);
7074 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
7079 GST_MEMDUMP_OBJECT (qtdemux, "hvc1", buffer, end - buffer);
7080 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
7085 GST_MEMDUMP_OBJECT (qtdemux, "hev1", buffer, end - buffer);
7086 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
7091 qtdemux_parse_container (qtdemux, node, buffer + 86, end);
7096 GST_DEBUG_OBJECT (qtdemux, "parsing meta atom");
7097 qtdemux_parse_container (qtdemux, node, buffer + 12, end);
7102 GST_MEMDUMP_OBJECT (qtdemux, "mp4s", buffer, end - buffer);
7103 /* Skip 8 byte header, plus 8 byte version + flags + entry_count */
7104 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
7112 version = QT_UINT32 (buffer + 12);
7113 GST_DEBUG_OBJECT (qtdemux, "parsing XiTh atom version 0x%08x", version);
7120 GST_DEBUG_OBJECT (qtdemux, "unknown version 0x%08x", version);
7125 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
7130 qtdemux_parse_container (qtdemux, node, buffer + 0x34, end);
7135 qtdemux_parse_uuid (qtdemux, buffer, end - buffer);
7140 qtdemux_parse_container (qtdemux, node, buffer + 86, end);
7145 qtdemux_parse_container (qtdemux, node, buffer + 36, end);
7149 if (!strcmp (type->name, "unknown"))
7150 GST_MEMDUMP ("Unknown tag", buffer + 4, end - buffer - 4);
7154 GST_LOG_OBJECT (qtdemux, "parsed '%" GST_FOURCC_FORMAT "'",
7155 GST_FOURCC_ARGS (fourcc));
7161 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
7162 (_("This file is corrupt and cannot be played.")),
7163 ("Not enough data for an atom header, got only %u bytes", length));
7168 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
7169 (_("This file is corrupt and cannot be played.")),
7170 ("Atom '%" GST_FOURCC_FORMAT "' has size of %u bytes, but we have only "
7171 "%u bytes available.", GST_FOURCC_ARGS (fourcc), node_length,
7178 qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc)
7182 guint32 child_fourcc;
7184 for (child = g_node_first_child (node); child;
7185 child = g_node_next_sibling (child)) {
7186 buffer = (guint8 *) child->data;
7188 child_fourcc = QT_FOURCC (buffer + 4);
7190 if (G_UNLIKELY (child_fourcc == fourcc)) {
7198 qtdemux_tree_get_child_by_type_full (GNode * node, guint32 fourcc,
7199 GstByteReader * parser)
7203 guint32 child_fourcc, child_len;
7205 for (child = g_node_first_child (node); child;
7206 child = g_node_next_sibling (child)) {
7207 buffer = (guint8 *) child->data;
7209 child_len = QT_UINT32 (buffer);
7210 child_fourcc = QT_FOURCC (buffer + 4);
7212 if (G_UNLIKELY (child_fourcc == fourcc)) {
7213 if (G_UNLIKELY (child_len < (4 + 4)))
7215 /* FIXME: must verify if atom length < parent atom length */
7216 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
7224 qtdemux_tree_get_sibling_by_type_full (GNode * node, guint32 fourcc,
7225 GstByteReader * parser)
7229 guint32 child_fourcc, child_len;
7231 for (child = g_node_next_sibling (node); child;
7232 child = g_node_next_sibling (child)) {
7233 buffer = (guint8 *) child->data;
7235 child_fourcc = QT_FOURCC (buffer + 4);
7237 if (child_fourcc == fourcc) {
7239 child_len = QT_UINT32 (buffer);
7240 if (G_UNLIKELY (child_len < (4 + 4)))
7242 /* FIXME: must verify if atom length < parent atom length */
7243 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
7252 qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc)
7254 return qtdemux_tree_get_sibling_by_type_full (node, fourcc, NULL);
7258 qtdemux_do_allocation (GstQTDemux * qtdemux, QtDemuxStream * stream)
7260 /* FIXME: This can only reliably work if demuxers have a
7261 * separate streaming thread per srcpad. This should be
7262 * done in a demuxer base class, which integrates parts
7265 * https://bugzilla.gnome.org/show_bug.cgi?id=701856
7270 query = gst_query_new_allocation (stream->caps, FALSE);
7272 if (!gst_pad_peer_query (stream->pad, query)) {
7273 /* not a problem, just debug a little */
7274 GST_DEBUG_OBJECT (qtdemux, "peer ALLOCATION query failed");
7277 if (stream->allocator)
7278 gst_object_unref (stream->allocator);
7280 if (gst_query_get_n_allocation_params (query) > 0) {
7281 /* try the allocator */
7282 gst_query_parse_nth_allocation_param (query, 0, &stream->allocator,
7284 stream->use_allocator = TRUE;
7286 stream->allocator = NULL;
7287 gst_allocation_params_init (&stream->params);
7288 stream->use_allocator = FALSE;
7290 gst_query_unref (query);
7295 gst_qtdemux_configure_protected_caps (GstQTDemux * qtdemux,
7296 QtDemuxStream * stream)
7299 const gchar *selected_system;
7301 g_return_val_if_fail (qtdemux != NULL, FALSE);
7302 g_return_val_if_fail (stream != NULL, FALSE);
7303 g_return_val_if_fail (gst_caps_get_size (stream->caps) == 1, FALSE);
7305 if (stream->protection_scheme_type != FOURCC_cenc) {
7306 GST_ERROR_OBJECT (qtdemux, "unsupported protection scheme");
7309 if (qtdemux->protection_system_ids == NULL) {
7310 GST_ERROR_OBJECT (qtdemux, "stream is protected using cenc, but no "
7311 "cenc protection system information has been found");
7314 g_ptr_array_add (qtdemux->protection_system_ids, NULL);
7315 selected_system = gst_protection_select_system ((const gchar **)
7316 qtdemux->protection_system_ids->pdata);
7317 g_ptr_array_remove_index (qtdemux->protection_system_ids,
7318 qtdemux->protection_system_ids->len - 1);
7319 if (!selected_system) {
7320 GST_ERROR_OBJECT (qtdemux, "stream is protected, but no "
7321 "suitable decryptor element has been found");
7325 s = gst_caps_get_structure (stream->caps, 0);
7326 if (!gst_structure_has_name (s, "application/x-cenc")) {
7327 gst_structure_set (s,
7328 "original-media-type", G_TYPE_STRING, gst_structure_get_name (s),
7329 GST_PROTECTION_SYSTEM_ID_CAPS_FIELD, G_TYPE_STRING, selected_system,
7331 gst_structure_set_name (s, "application/x-cenc");
7337 gst_qtdemux_configure_stream (GstQTDemux * qtdemux, QtDemuxStream * stream)
7339 if (stream->subtype == FOURCC_vide) {
7340 /* fps is calculated base on the duration of the average framerate since
7341 * qt does not have a fixed framerate. */
7342 gboolean fps_available = TRUE;
7344 if ((stream->n_samples == 1) && (stream->first_duration == 0)) {
7349 if (stream->duration == 0 || stream->n_samples < 2) {
7350 stream->fps_n = stream->timescale;
7352 fps_available = FALSE;
7354 GstClockTime avg_duration;
7358 /* duration and n_samples can be updated for fragmented format
7359 * so, framerate of fragmented format is calculated using data in a moof */
7360 if (qtdemux->fragmented && stream->n_samples_moof > 0
7361 && stream->duration_moof > 0) {
7362 n_samples = stream->n_samples_moof;
7363 duration = stream->duration_moof;
7365 n_samples = stream->n_samples;
7366 duration = stream->duration;
7369 /* Calculate a framerate, ignoring the first sample which is sometimes truncated */
7370 /* stream->duration is guint64, timescale, n_samples are guint32 */
7372 gst_util_uint64_scale_round (duration -
7373 stream->first_duration, GST_SECOND,
7374 (guint64) (stream->timescale) * (n_samples - 1));
7376 GST_LOG_OBJECT (qtdemux,
7377 "Calculating avg sample duration based on stream (or moof) duration %"
7379 " minus first sample %u, leaving %d samples gives %"
7380 GST_TIME_FORMAT, duration, stream->first_duration,
7381 n_samples - 1, GST_TIME_ARGS (avg_duration));
7383 gst_video_guess_framerate (avg_duration, &stream->fps_n,
7386 GST_DEBUG_OBJECT (qtdemux,
7387 "Calculating framerate, timescale %u gave fps_n %d fps_d %d",
7388 stream->timescale, stream->fps_n, stream->fps_d);
7393 stream->caps = gst_caps_make_writable (stream->caps);
7395 gst_caps_set_simple (stream->caps,
7396 "width", G_TYPE_INT, stream->width,
7397 "height", G_TYPE_INT, stream->height, NULL);
7399 /* set framerate if calculated framerate is reliable */
7400 if (fps_available) {
7401 gst_caps_set_simple (stream->caps,
7402 "framerate", GST_TYPE_FRACTION, stream->fps_n, stream->fps_d, NULL);
7405 /* calculate pixel-aspect-ratio using display width and height */
7406 GST_DEBUG_OBJECT (qtdemux,
7407 "video size %dx%d, target display size %dx%d", stream->width,
7408 stream->height, stream->display_width, stream->display_height);
7409 /* qt file might have pasp atom */
7410 if (stream->par_w > 0 && stream->par_h > 0) {
7411 GST_DEBUG_OBJECT (qtdemux, "par %d:%d", stream->par_w, stream->par_h);
7412 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
7413 GST_TYPE_FRACTION, stream->par_w, stream->par_h, NULL);
7414 } else if (stream->display_width > 0 && stream->display_height > 0 &&
7415 stream->width > 0 && stream->height > 0) {
7418 /* calculate the pixel aspect ratio using the display and pixel w/h */
7419 n = stream->display_width * stream->height;
7420 d = stream->display_height * stream->width;
7423 GST_DEBUG_OBJECT (qtdemux, "setting PAR to %d/%d", n, d);
7426 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
7427 GST_TYPE_FRACTION, stream->par_w, stream->par_h, NULL);
7430 if (stream->multiview_mode != GST_VIDEO_MULTIVIEW_MODE_NONE) {
7431 guint par_w = 1, par_h = 1;
7433 if (stream->par_w > 0 && stream->par_h > 0) {
7434 par_w = stream->par_w;
7435 par_h = stream->par_h;
7438 if (gst_video_multiview_guess_half_aspect (stream->multiview_mode,
7439 stream->width, stream->height, par_w, par_h)) {
7440 stream->multiview_flags |= GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT;
7443 gst_caps_set_simple (stream->caps,
7444 "multiview-mode", G_TYPE_STRING,
7445 gst_video_multiview_mode_to_caps_string (stream->multiview_mode),
7446 "multiview-flags", GST_TYPE_VIDEO_MULTIVIEW_FLAGSET,
7447 stream->multiview_flags, GST_FLAG_SET_MASK_EXACT, NULL);
7452 else if (stream->subtype == FOURCC_soun) {
7454 stream->caps = gst_caps_make_writable (stream->caps);
7455 if (stream->rate > 0)
7456 gst_caps_set_simple (stream->caps,
7457 "rate", G_TYPE_INT, (int) stream->rate, NULL);
7458 if (stream->n_channels > 0)
7459 gst_caps_set_simple (stream->caps,
7460 "channels", G_TYPE_INT, stream->n_channels, NULL);
7461 if (stream->n_channels > 2) {
7462 /* FIXME: Need to parse the 'chan' atom to get channel layouts
7463 * correctly; this is just the minimum we can do - assume
7464 * we don't actually have any channel positions. */
7465 gst_caps_set_simple (stream->caps,
7466 "channel-mask", GST_TYPE_BITMASK, G_GUINT64_CONSTANT (0), NULL);
7472 GST_PAD_ELEMENT_PRIVATE (stream->pad) = stream;
7473 gst_pad_set_event_function (stream->pad, gst_qtdemux_handle_src_event);
7474 gst_pad_set_query_function (stream->pad, gst_qtdemux_handle_src_query);
7475 gst_pad_set_active (stream->pad, TRUE);
7477 gst_pad_use_fixed_caps (stream->pad);
7479 if (stream->protected) {
7480 if (!gst_qtdemux_configure_protected_caps (qtdemux, stream)) {
7481 GST_ERROR_OBJECT (qtdemux,
7482 "Failed to configure protected stream caps.");
7487 GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT, stream->caps);
7488 if (stream->new_stream) {
7491 GstStreamFlags stream_flags;
7494 gst_pad_get_sticky_event (qtdemux->sinkpad, GST_EVENT_STREAM_START,
7497 if (gst_event_parse_group_id (event, &qtdemux->group_id))
7498 qtdemux->have_group_id = TRUE;
7500 qtdemux->have_group_id = FALSE;
7501 gst_event_unref (event);
7502 } else if (!qtdemux->have_group_id) {
7503 qtdemux->have_group_id = TRUE;
7504 qtdemux->group_id = gst_util_group_id_next ();
7507 stream->new_stream = FALSE;
7509 gst_pad_create_stream_id_printf (stream->pad,
7510 GST_ELEMENT_CAST (qtdemux), "%03u", stream->track_id);
7511 event = gst_event_new_stream_start (stream_id);
7512 if (qtdemux->have_group_id)
7513 gst_event_set_group_id (event, qtdemux->group_id);
7514 stream_flags = GST_STREAM_FLAG_NONE;
7515 if (stream->disabled)
7516 stream_flags |= GST_STREAM_FLAG_UNSELECT;
7518 stream_flags |= GST_STREAM_FLAG_SPARSE;
7519 gst_event_set_stream_flags (event, stream_flags);
7520 gst_pad_push_event (stream->pad, event);
7523 gst_pad_set_caps (stream->pad, stream->caps);
7524 stream->new_caps = FALSE;
7530 gst_qtdemux_add_stream (GstQTDemux * qtdemux,
7531 QtDemuxStream * stream, GstTagList * list)
7533 gboolean ret = TRUE;
7534 /* consistent default for push based mode */
7535 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
7537 if (stream->subtype == FOURCC_vide) {
7538 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
7541 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
7544 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
7545 gst_object_unref (stream->pad);
7551 qtdemux->n_video_streams++;
7552 } else if (stream->subtype == FOURCC_soun) {
7553 gchar *name = g_strdup_printf ("audio_%u", qtdemux->n_audio_streams);
7556 gst_pad_new_from_static_template (&gst_qtdemux_audiosrc_template, name);
7558 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
7559 gst_object_unref (stream->pad);
7564 qtdemux->n_audio_streams++;
7565 } else if (stream->subtype == FOURCC_strm) {
7566 GST_DEBUG_OBJECT (qtdemux, "stream type, not creating pad");
7567 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
7568 || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt) {
7569 gchar *name = g_strdup_printf ("subtitle_%u", qtdemux->n_sub_streams);
7572 gst_pad_new_from_static_template (&gst_qtdemux_subsrc_template, name);
7574 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
7575 gst_object_unref (stream->pad);
7580 qtdemux->n_sub_streams++;
7581 } else if (stream->caps) {
7582 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
7585 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
7587 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
7588 gst_object_unref (stream->pad);
7593 qtdemux->n_video_streams++;
7595 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
7602 GST_DEBUG_OBJECT (qtdemux, "adding pad %s %p to qtdemux %p",
7603 GST_OBJECT_NAME (stream->pad), stream->pad, qtdemux);
7604 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
7605 gst_flow_combiner_add_pad (qtdemux->flowcombiner, stream->pad);
7607 if (stream->pending_tags)
7608 gst_tag_list_unref (stream->pending_tags);
7609 stream->pending_tags = list;
7611 /* global tags go on each pad anyway */
7612 stream->send_global_tags = TRUE;
7613 /* send upstream GST_EVENT_PROTECTION events that were received before
7614 this source pad was created */
7615 for (l = qtdemux->protection_event_queue.head; l != NULL; l = l->next)
7616 gst_pad_push_event (stream->pad, gst_event_ref (l->data));
7620 gst_tag_list_unref (list);
7624 /* find next atom with @fourcc starting at @offset */
7625 static GstFlowReturn
7626 qtdemux_find_atom (GstQTDemux * qtdemux, guint64 * offset,
7627 guint64 * length, guint32 fourcc)
7633 GST_LOG_OBJECT (qtdemux, "finding fourcc %" GST_FOURCC_FORMAT " at offset %"
7634 G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), *offset);
7640 ret = gst_pad_pull_range (qtdemux->sinkpad, *offset, 16, &buf);
7641 if (G_UNLIKELY (ret != GST_FLOW_OK))
7643 if (G_UNLIKELY (gst_buffer_get_size (buf) != 16)) {
7646 gst_buffer_unref (buf);
7649 gst_buffer_map (buf, &map, GST_MAP_READ);
7650 extract_initial_length_and_fourcc (map.data, 16, length, &lfourcc);
7651 gst_buffer_unmap (buf, &map);
7652 gst_buffer_unref (buf);
7654 if (G_UNLIKELY (*length == 0)) {
7655 GST_DEBUG_OBJECT (qtdemux, "invalid length 0");
7656 ret = GST_FLOW_ERROR;
7660 if (lfourcc == fourcc) {
7661 GST_DEBUG_OBJECT (qtdemux, "found fourcc at offset %" G_GUINT64_FORMAT,
7665 GST_LOG_OBJECT (qtdemux,
7666 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
7667 GST_FOURCC_ARGS (fourcc), *offset);
7676 /* might simply have had last one */
7677 GST_DEBUG_OBJECT (qtdemux, "fourcc not found");
7682 /* should only do something in pull mode */
7683 /* call with OBJECT lock */
7684 static GstFlowReturn
7685 qtdemux_add_fragmented_samples (GstQTDemux * qtdemux)
7687 guint64 length, offset;
7688 GstBuffer *buf = NULL;
7689 GstFlowReturn ret = GST_FLOW_OK;
7690 GstFlowReturn res = GST_FLOW_OK;
7693 offset = qtdemux->moof_offset;
7694 GST_DEBUG_OBJECT (qtdemux, "next moof at offset %" G_GUINT64_FORMAT, offset);
7697 GST_DEBUG_OBJECT (qtdemux, "no next moof");
7698 return GST_FLOW_EOS;
7701 /* best not do pull etc with lock held */
7702 GST_OBJECT_UNLOCK (qtdemux);
7704 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
7705 if (ret != GST_FLOW_OK)
7708 ret = gst_qtdemux_pull_atom (qtdemux, offset, length, &buf);
7709 if (G_UNLIKELY (ret != GST_FLOW_OK))
7711 gst_buffer_map (buf, &map, GST_MAP_READ);
7712 if (!qtdemux_parse_moof (qtdemux, map.data, map.size, offset, NULL)) {
7713 gst_buffer_unmap (buf, &map);
7714 gst_buffer_unref (buf);
7719 gst_buffer_unmap (buf, &map);
7720 gst_buffer_unref (buf);
7724 /* look for next moof */
7725 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
7726 if (G_UNLIKELY (ret != GST_FLOW_OK))
7730 GST_OBJECT_LOCK (qtdemux);
7732 qtdemux->moof_offset = offset;
7738 GST_DEBUG_OBJECT (qtdemux, "failed to parse moof");
7740 res = GST_FLOW_ERROR;
7745 /* maybe upstream temporarily flushing */
7746 if (ret != GST_FLOW_FLUSHING) {
7747 GST_DEBUG_OBJECT (qtdemux, "no next moof");
7750 GST_DEBUG_OBJECT (qtdemux, "upstream WRONG_STATE");
7751 /* resume at current position next time */
7758 /* initialise bytereaders for stbl sub-atoms */
7760 qtdemux_stbl_init (GstQTDemux * qtdemux, QtDemuxStream * stream, GNode * stbl)
7762 stream->stbl_index = -1; /* no samples have yet been parsed */
7763 stream->sample_index = -1;
7765 /* time-to-sample atom */
7766 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stts, &stream->stts))
7769 /* copy atom data into a new buffer for later use */
7770 stream->stts.data = g_memdup (stream->stts.data, stream->stts.size);
7772 /* skip version + flags */
7773 if (!gst_byte_reader_skip (&stream->stts, 1 + 3) ||
7774 !gst_byte_reader_get_uint32_be (&stream->stts, &stream->n_sample_times))
7776 GST_LOG_OBJECT (qtdemux, "%u timestamp blocks", stream->n_sample_times);
7778 /* make sure there's enough data */
7779 if (!qt_atom_parser_has_chunks (&stream->stts, stream->n_sample_times, 8)) {
7780 stream->n_sample_times = gst_byte_reader_get_remaining (&stream->stts) / 8;
7781 GST_LOG_OBJECT (qtdemux, "overriding to %u timestamp blocks",
7782 stream->n_sample_times);
7783 if (!stream->n_sample_times)
7787 /* sync sample atom */
7788 stream->stps_present = FALSE;
7789 if ((stream->stss_present =
7790 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stss,
7791 &stream->stss) ? TRUE : FALSE) == TRUE) {
7792 /* copy atom data into a new buffer for later use */
7793 stream->stss.data = g_memdup (stream->stss.data, stream->stss.size);
7795 /* skip version + flags */
7796 if (!gst_byte_reader_skip (&stream->stss, 1 + 3) ||
7797 !gst_byte_reader_get_uint32_be (&stream->stss, &stream->n_sample_syncs))
7800 if (stream->n_sample_syncs) {
7801 /* make sure there's enough data */
7802 if (!qt_atom_parser_has_chunks (&stream->stss, stream->n_sample_syncs, 4))
7806 /* partial sync sample atom */
7807 if ((stream->stps_present =
7808 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stps,
7809 &stream->stps) ? TRUE : FALSE) == TRUE) {
7810 /* copy atom data into a new buffer for later use */
7811 stream->stps.data = g_memdup (stream->stps.data, stream->stps.size);
7813 /* skip version + flags */
7814 if (!gst_byte_reader_skip (&stream->stps, 1 + 3) ||
7815 !gst_byte_reader_get_uint32_be (&stream->stps,
7816 &stream->n_sample_partial_syncs))
7819 /* if there are no entries, the stss table contains the real
7821 if (stream->n_sample_partial_syncs) {
7822 /* make sure there's enough data */
7823 if (!qt_atom_parser_has_chunks (&stream->stps,
7824 stream->n_sample_partial_syncs, 4))
7831 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsz, &stream->stsz))
7834 /* copy atom data into a new buffer for later use */
7835 stream->stsz.data = g_memdup (stream->stsz.data, stream->stsz.size);
7837 /* skip version + flags */
7838 if (!gst_byte_reader_skip (&stream->stsz, 1 + 3) ||
7839 !gst_byte_reader_get_uint32_be (&stream->stsz, &stream->sample_size))
7842 if (!gst_byte_reader_get_uint32_be (&stream->stsz, &stream->n_samples))
7845 if (!stream->n_samples)
7848 /* sample-to-chunk atom */
7849 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsc, &stream->stsc))
7852 /* copy atom data into a new buffer for later use */
7853 stream->stsc.data = g_memdup (stream->stsc.data, stream->stsc.size);
7855 /* skip version + flags */
7856 if (!gst_byte_reader_skip (&stream->stsc, 1 + 3) ||
7857 !gst_byte_reader_get_uint32_be (&stream->stsc,
7858 &stream->n_samples_per_chunk))
7861 GST_DEBUG_OBJECT (qtdemux, "n_samples_per_chunk %u",
7862 stream->n_samples_per_chunk);
7864 /* make sure there's enough data */
7865 if (!qt_atom_parser_has_chunks (&stream->stsc, stream->n_samples_per_chunk,
7871 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stco, &stream->stco))
7872 stream->co_size = sizeof (guint32);
7873 else if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_co64,
7875 stream->co_size = sizeof (guint64);
7879 /* copy atom data into a new buffer for later use */
7880 stream->stco.data = g_memdup (stream->stco.data, stream->stco.size);
7882 /* skip version + flags */
7883 if (!gst_byte_reader_skip (&stream->stco, 1 + 3))
7886 /* chunks_are_samples == TRUE means treat chunks as samples */
7887 stream->chunks_are_samples = stream->sample_size && !stream->sampled;
7888 if (stream->chunks_are_samples) {
7889 /* treat chunks as samples */
7890 if (!gst_byte_reader_get_uint32_be (&stream->stco, &stream->n_samples))
7893 /* skip number of entries */
7894 if (!gst_byte_reader_skip (&stream->stco, 4))
7897 /* make sure there are enough data in the stsz atom */
7898 if (!stream->sample_size) {
7899 /* different sizes for each sample */
7900 if (!qt_atom_parser_has_chunks (&stream->stsz, stream->n_samples, 4))
7905 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
7906 stream->n_samples, (guint) sizeof (QtDemuxSample),
7907 stream->n_samples * sizeof (QtDemuxSample) / (1024.0 * 1024.0));
7909 if (stream->n_samples >=
7910 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample)) {
7911 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
7912 "be larger than %uMB (broken file?)", stream->n_samples,
7913 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
7917 g_assert (stream->samples == NULL);
7918 stream->samples = g_try_new0 (QtDemuxSample, stream->n_samples);
7919 if (!stream->samples) {
7920 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
7925 /* composition time-to-sample */
7926 if ((stream->ctts_present =
7927 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_ctts,
7928 &stream->ctts) ? TRUE : FALSE) == TRUE) {
7929 GstByteReader cslg = GST_BYTE_READER_INIT (NULL, 0);
7931 /* copy atom data into a new buffer for later use */
7932 stream->ctts.data = g_memdup (stream->ctts.data, stream->ctts.size);
7934 /* skip version + flags */
7935 if (!gst_byte_reader_skip (&stream->ctts, 1 + 3)
7936 || !gst_byte_reader_get_uint32_be (&stream->ctts,
7937 &stream->n_composition_times))
7940 /* make sure there's enough data */
7941 if (!qt_atom_parser_has_chunks (&stream->ctts, stream->n_composition_times,
7945 /* This is optional, if missing we iterate the ctts */
7946 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_cslg, &cslg)) {
7947 if (!gst_byte_reader_skip (&cslg, 1 + 3)
7948 || !gst_byte_reader_get_uint32_be (&cslg, &stream->cslg_shift)) {
7949 g_free ((gpointer) cslg.data);
7953 gint32 cslg_least = 0;
7954 guint num_entries, pos;
7957 pos = gst_byte_reader_get_pos (&stream->ctts);
7958 num_entries = stream->n_composition_times;
7960 stream->cslg_shift = 0;
7962 for (i = 0; i < num_entries; i++) {
7965 gst_byte_reader_skip_unchecked (&stream->ctts, 4);
7966 offset = gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
7968 if (offset < cslg_least)
7969 cslg_least = offset;
7973 stream->cslg_shift = ABS (cslg_least);
7975 stream->cslg_shift = 0;
7977 /* reset the reader so we can generate sample table */
7978 gst_byte_reader_set_pos (&stream->ctts, pos);
7981 /* Ensure the cslg_shift value is consistent so we can use it
7982 * unconditionnally to produce TS and Segment */
7983 stream->cslg_shift = 0;
7990 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
7991 (_("This file is corrupt and cannot be played.")), (NULL));
7996 gst_qtdemux_stbl_free (stream);
7997 if (!qtdemux->fragmented) {
7998 /* not quite good */
7999 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
8002 /* may pick up samples elsewhere */
8008 /* collect samples from the next sample to be parsed up to sample @n for @stream
8009 * by reading the info from @stbl
8011 * This code can be executed from both the streaming thread and the seeking
8012 * thread so it takes the object lock to protect itself
8015 qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream, guint32 n)
8018 QtDemuxSample *samples, *first, *cur, *last;
8019 guint32 n_samples_per_chunk;
8022 GST_LOG_OBJECT (qtdemux, "parsing samples for stream fourcc %"
8023 GST_FOURCC_FORMAT ", pad %s", GST_FOURCC_ARGS (stream->fourcc),
8024 stream->pad ? GST_PAD_NAME (stream->pad) : "(NULL)");
8026 n_samples = stream->n_samples;
8029 goto out_of_samples;
8031 GST_OBJECT_LOCK (qtdemux);
8032 if (n <= stream->stbl_index)
8033 goto already_parsed;
8035 GST_DEBUG_OBJECT (qtdemux, "parsing up to sample %u", n);
8037 if (!stream->stsz.data) {
8038 /* so we already parsed and passed all the moov samples;
8039 * onto fragmented ones */
8040 g_assert (qtdemux->fragmented);
8044 /* pointer to the sample table */
8045 samples = stream->samples;
8047 /* starts from -1, moves to the next sample index to parse */
8048 stream->stbl_index++;
8050 /* keep track of the first and last sample to fill */
8051 first = &samples[stream->stbl_index];
8054 if (!stream->chunks_are_samples) {
8055 /* set the sample sizes */
8056 if (stream->sample_size == 0) {
8057 /* different sizes for each sample */
8058 for (cur = first; cur <= last; cur++) {
8059 cur->size = gst_byte_reader_get_uint32_be_unchecked (&stream->stsz);
8060 GST_LOG_OBJECT (qtdemux, "sample %d has size %u",
8061 (guint) (cur - samples), cur->size);
8064 /* samples have the same size */
8065 GST_LOG_OBJECT (qtdemux, "all samples have size %u", stream->sample_size);
8066 for (cur = first; cur <= last; cur++)
8067 cur->size = stream->sample_size;
8071 n_samples_per_chunk = stream->n_samples_per_chunk;
8074 for (i = stream->stsc_index; i < n_samples_per_chunk; i++) {
8077 if (stream->stsc_chunk_index >= stream->last_chunk
8078 || stream->stsc_chunk_index < stream->first_chunk) {
8079 stream->first_chunk =
8080 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
8081 stream->samples_per_chunk =
8082 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
8083 gst_byte_reader_skip_unchecked (&stream->stsc, 4);
8085 /* chunk numbers are counted from 1 it seems */
8086 if (G_UNLIKELY (stream->first_chunk == 0))
8089 --stream->first_chunk;
8091 /* the last chunk of each entry is calculated by taking the first chunk
8092 * of the next entry; except if there is no next, where we fake it with
8094 if (G_UNLIKELY (i == (stream->n_samples_per_chunk - 1))) {
8095 stream->last_chunk = G_MAXUINT32;
8097 stream->last_chunk =
8098 gst_byte_reader_peek_uint32_be_unchecked (&stream->stsc);
8099 if (G_UNLIKELY (stream->last_chunk == 0))
8102 --stream->last_chunk;
8105 GST_LOG_OBJECT (qtdemux,
8106 "entry %d has first_chunk %d, last_chunk %d, samples_per_chunk %d", i,
8107 stream->first_chunk, stream->last_chunk, stream->samples_per_chunk);
8109 if (G_UNLIKELY (stream->last_chunk < stream->first_chunk))
8112 if (stream->last_chunk != G_MAXUINT32) {
8113 if (!qt_atom_parser_peek_sub (&stream->stco,
8114 stream->first_chunk * stream->co_size,
8115 (stream->last_chunk - stream->first_chunk) * stream->co_size,
8120 stream->co_chunk = stream->stco;
8121 if (!gst_byte_reader_skip (&stream->co_chunk,
8122 stream->first_chunk * stream->co_size))
8126 stream->stsc_chunk_index = stream->first_chunk;
8129 last_chunk = stream->last_chunk;
8131 if (stream->chunks_are_samples) {
8132 cur = &samples[stream->stsc_chunk_index];
8134 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
8137 stream->stsc_chunk_index = j;
8142 qt_atom_parser_get_offset_unchecked (&stream->co_chunk,
8145 GST_LOG_OBJECT (qtdemux, "Created entry %d with offset "
8146 "%" G_GUINT64_FORMAT, j, cur->offset);
8148 if (stream->samples_per_frame * stream->bytes_per_frame) {
8150 (stream->samples_per_chunk * stream->n_channels) /
8151 stream->samples_per_frame * stream->bytes_per_frame;
8153 cur->size = stream->samples_per_chunk;
8156 GST_DEBUG_OBJECT (qtdemux,
8157 "keyframe sample %d: timestamp %" GST_TIME_FORMAT ", size %u",
8158 j, GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream,
8159 stream->stco_sample_index)), cur->size);
8161 cur->timestamp = stream->stco_sample_index;
8162 cur->duration = stream->samples_per_chunk;
8163 cur->keyframe = TRUE;
8166 stream->stco_sample_index += stream->samples_per_chunk;
8168 stream->stsc_chunk_index = j;
8170 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
8171 guint32 samples_per_chunk;
8172 guint64 chunk_offset;
8174 if (!stream->stsc_sample_index
8175 && !qt_atom_parser_get_offset (&stream->co_chunk, stream->co_size,
8176 &stream->chunk_offset))
8179 samples_per_chunk = stream->samples_per_chunk;
8180 chunk_offset = stream->chunk_offset;
8182 for (k = stream->stsc_sample_index; k < samples_per_chunk; k++) {
8183 GST_LOG_OBJECT (qtdemux, "creating entry %d with offset %"
8184 G_GUINT64_FORMAT " and size %d",
8185 (guint) (cur - samples), chunk_offset, cur->size);
8187 cur->offset = chunk_offset;
8188 chunk_offset += cur->size;
8191 if (G_UNLIKELY (cur > last)) {
8193 stream->stsc_sample_index = k + 1;
8194 stream->chunk_offset = chunk_offset;
8195 stream->stsc_chunk_index = j;
8199 stream->stsc_sample_index = 0;
8201 stream->stsc_chunk_index = j;
8203 stream->stsc_index++;
8206 if (stream->chunks_are_samples)
8210 guint32 n_sample_times;
8212 n_sample_times = stream->n_sample_times;
8215 for (i = stream->stts_index; i < n_sample_times; i++) {
8216 guint32 stts_samples;
8217 gint32 stts_duration;
8220 if (stream->stts_sample_index >= stream->stts_samples
8221 || !stream->stts_sample_index) {
8223 stream->stts_samples =
8224 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
8225 stream->stts_duration =
8226 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
8228 GST_LOG_OBJECT (qtdemux, "block %d, %u timestamps, duration %u",
8229 i, stream->stts_samples, stream->stts_duration);
8231 stream->stts_sample_index = 0;
8234 stts_samples = stream->stts_samples;
8235 stts_duration = stream->stts_duration;
8236 stts_time = stream->stts_time;
8238 for (j = stream->stts_sample_index; j < stts_samples; j++) {
8239 GST_DEBUG_OBJECT (qtdemux,
8240 "sample %d: index %d, timestamp %" GST_TIME_FORMAT,
8241 (guint) (cur - samples), j,
8242 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stts_time)));
8244 cur->timestamp = stts_time;
8245 cur->duration = stts_duration;
8247 /* avoid 32-bit wrap-around,
8248 * but still mind possible 'negative' duration */
8249 stts_time += (gint64) stts_duration;
8252 if (G_UNLIKELY (cur > last)) {
8254 stream->stts_time = stts_time;
8255 stream->stts_sample_index = j + 1;
8259 stream->stts_sample_index = 0;
8260 stream->stts_time = stts_time;
8261 stream->stts_index++;
8263 /* fill up empty timestamps with the last timestamp, this can happen when
8264 * the last samples do not decode and so we don't have timestamps for them.
8265 * We however look at the last timestamp to estimate the track length so we
8266 * need something in here. */
8267 for (; cur < last; cur++) {
8268 GST_DEBUG_OBJECT (qtdemux,
8269 "fill sample %d: timestamp %" GST_TIME_FORMAT,
8270 (guint) (cur - samples),
8271 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stream->stts_time)));
8272 cur->timestamp = stream->stts_time;
8278 /* sample sync, can be NULL */
8279 if (stream->stss_present == TRUE) {
8280 guint32 n_sample_syncs;
8282 n_sample_syncs = stream->n_sample_syncs;
8284 if (!n_sample_syncs) {
8285 GST_DEBUG_OBJECT (qtdemux, "all samples are keyframes");
8286 stream->all_keyframe = TRUE;
8288 for (i = stream->stss_index; i < n_sample_syncs; i++) {
8289 /* note that the first sample is index 1, not 0 */
8292 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stss);
8294 if (G_LIKELY (index > 0 && index <= n_samples)) {
8296 samples[index].keyframe = TRUE;
8297 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
8298 /* and exit if we have enough samples */
8299 if (G_UNLIKELY (index >= n)) {
8306 stream->stss_index = i;
8309 /* stps marks partial sync frames like open GOP I-Frames */
8310 if (stream->stps_present == TRUE) {
8311 guint32 n_sample_partial_syncs;
8313 n_sample_partial_syncs = stream->n_sample_partial_syncs;
8315 /* if there are no entries, the stss table contains the real
8317 if (n_sample_partial_syncs) {
8318 for (i = stream->stps_index; i < n_sample_partial_syncs; i++) {
8319 /* note that the first sample is index 1, not 0 */
8322 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stps);
8324 if (G_LIKELY (index > 0 && index <= n_samples)) {
8326 samples[index].keyframe = TRUE;
8327 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
8328 /* and exit if we have enough samples */
8329 if (G_UNLIKELY (index >= n)) {
8336 stream->stps_index = i;
8340 /* no stss, all samples are keyframes */
8341 stream->all_keyframe = TRUE;
8342 GST_DEBUG_OBJECT (qtdemux, "setting all keyframes");
8347 /* composition time to sample */
8348 if (stream->ctts_present == TRUE) {
8349 guint32 n_composition_times;
8351 gint32 ctts_soffset;
8353 /* Fill in the pts_offsets */
8355 n_composition_times = stream->n_composition_times;
8357 for (i = stream->ctts_index; i < n_composition_times; i++) {
8358 if (stream->ctts_sample_index >= stream->ctts_count
8359 || !stream->ctts_sample_index) {
8360 stream->ctts_count =
8361 gst_byte_reader_get_uint32_be_unchecked (&stream->ctts);
8362 stream->ctts_soffset =
8363 gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
8364 stream->ctts_sample_index = 0;
8367 ctts_count = stream->ctts_count;
8368 ctts_soffset = stream->ctts_soffset;
8370 for (j = stream->ctts_sample_index; j < ctts_count; j++) {
8371 cur->pts_offset = ctts_soffset;
8374 if (G_UNLIKELY (cur > last)) {
8376 stream->ctts_sample_index = j + 1;
8380 stream->ctts_sample_index = 0;
8381 stream->ctts_index++;
8385 stream->stbl_index = n;
8386 /* if index has been completely parsed, free data that is no-longer needed */
8387 if (n + 1 == stream->n_samples) {
8388 gst_qtdemux_stbl_free (stream);
8389 GST_DEBUG_OBJECT (qtdemux, "parsed all available samples;");
8390 if (qtdemux->pullbased) {
8391 GST_DEBUG_OBJECT (qtdemux, "checking for more samples");
8392 while (n + 1 == stream->n_samples)
8393 if (qtdemux_add_fragmented_samples (qtdemux) != GST_FLOW_OK)
8397 GST_OBJECT_UNLOCK (qtdemux);
8404 GST_LOG_OBJECT (qtdemux,
8405 "Tried to parse up to sample %u but this sample has already been parsed",
8407 /* if fragmented, there may be more */
8408 if (qtdemux->fragmented && n == stream->stbl_index)
8410 GST_OBJECT_UNLOCK (qtdemux);
8416 GST_LOG_OBJECT (qtdemux,
8417 "Tried to parse up to sample %u but there are only %u samples", n + 1,
8419 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8420 (_("This file is corrupt and cannot be played.")), (NULL));
8425 GST_OBJECT_UNLOCK (qtdemux);
8426 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8427 (_("This file is corrupt and cannot be played.")), (NULL));
8432 /* collect all segment info for @stream.
8435 qtdemux_parse_segments (GstQTDemux * qtdemux, QtDemuxStream * stream,
8439 /* accept edts if they contain gaps at start and there is only
8440 * one media segment */
8441 gboolean allow_pushbased_edts = TRUE;
8442 gint media_segments_count = 0;
8444 /* parse and prepare segment info from the edit list */
8445 GST_DEBUG_OBJECT (qtdemux, "looking for edit list container");
8446 stream->n_segments = 0;
8447 stream->segments = NULL;
8448 if ((edts = qtdemux_tree_get_child_by_type (trak, FOURCC_edts))) {
8451 gint i, count, entry_size;
8457 GST_DEBUG_OBJECT (qtdemux, "looking for edit list");
8458 if (!(elst = qtdemux_tree_get_child_by_type (edts, FOURCC_elst)))
8461 buffer = elst->data;
8463 version = QT_UINT8 (buffer + 8);
8464 entry_size = (version == 1) ? 20 : 12;
8466 n_segments = QT_UINT32 (buffer + 12);
8468 /* we might allocate a bit too much, at least allocate 1 segment */
8469 stream->segments = g_new (QtDemuxSegment, MAX (n_segments, 1));
8471 /* segments always start from 0 */
8475 for (i = 0; i < n_segments; i++) {
8478 gboolean time_valid = TRUE;
8479 QtDemuxSegment *segment;
8481 GstClockTime media_start = GST_CLOCK_TIME_NONE;
8484 media_time = QT_UINT64 (buffer + 24 + i * entry_size);
8485 duration = QT_UINT64 (buffer + 16 + i * entry_size);
8486 if (media_time == G_MAXUINT64)
8489 media_time = QT_UINT32 (buffer + 20 + i * entry_size);
8490 duration = QT_UINT32 (buffer + 16 + i * entry_size);
8491 if (media_time == G_MAXUINT32)
8496 media_start = QTSTREAMTIME_TO_GSTTIME (stream, media_time);
8498 segment = &stream->segments[count++];
8500 /* time and duration expressed in global timescale */
8501 segment->time = stime;
8502 /* add non scaled values so we don't cause roundoff errors */
8503 if (duration || media_start == GST_CLOCK_TIME_NONE) {
8505 stime = QTTIME_TO_GSTTIME (qtdemux, time);
8506 segment->duration = stime - segment->time;
8508 /* zero duration does not imply media_start == media_stop
8509 * but, only specify media_start.*/
8510 stime = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
8511 if (GST_CLOCK_TIME_IS_VALID (stime) && time_valid
8512 && stime >= media_start) {
8513 segment->duration = stime - media_start;
8515 segment->duration = GST_CLOCK_TIME_NONE;
8518 segment->stop_time = stime;
8520 segment->trak_media_start = media_time;
8521 /* media_time expressed in stream timescale */
8523 segment->media_start = media_start;
8524 segment->media_stop = segment->media_start + segment->duration;
8525 media_segments_count++;
8527 segment->media_start = GST_CLOCK_TIME_NONE;
8528 segment->media_stop = GST_CLOCK_TIME_NONE;
8531 QT_UINT32 (buffer + ((version == 1) ? 32 : 24) + i * entry_size);
8533 if (rate_int <= 1) {
8534 /* 0 is not allowed, some programs write 1 instead of the floating point
8536 GST_WARNING_OBJECT (qtdemux, "found suspicious rate %" G_GUINT32_FORMAT,
8540 segment->rate = rate_int / 65536.0;
8543 GST_DEBUG_OBJECT (qtdemux, "created segment %d time %" GST_TIME_FORMAT
8544 ", duration %" GST_TIME_FORMAT ", media_start %" GST_TIME_FORMAT
8545 " (%" G_GUINT64_FORMAT ") , media_stop %" GST_TIME_FORMAT
8546 " stop_time %" GST_TIME_FORMAT " rate %g, (%d) timescale %u",
8547 i, GST_TIME_ARGS (segment->time),
8548 GST_TIME_ARGS (segment->duration),
8549 GST_TIME_ARGS (segment->media_start), media_time,
8550 GST_TIME_ARGS (segment->media_stop),
8551 GST_TIME_ARGS (segment->stop_time), segment->rate, rate_int,
8553 if (segment->stop_time > qtdemux->segment.stop) {
8554 GST_WARNING_OBJECT (qtdemux, "Segment %d "
8555 " extends to %" GST_TIME_FORMAT
8556 " past the end of the file duration %" GST_TIME_FORMAT
8557 " it will be truncated", i, GST_TIME_ARGS (segment->stop_time),
8558 GST_TIME_ARGS (qtdemux->segment.stop));
8559 qtdemux->segment.stop = segment->stop_time;
8562 GST_DEBUG_OBJECT (qtdemux, "found %d segments", count);
8563 stream->n_segments = count;
8564 if (media_segments_count != 1)
8565 allow_pushbased_edts = FALSE;
8569 /* push based does not handle segments, so act accordingly here,
8570 * and warn if applicable */
8571 if (!qtdemux->pullbased && !allow_pushbased_edts) {
8572 GST_WARNING_OBJECT (qtdemux, "streaming; discarding edit list segments");
8573 /* remove and use default one below, we stream like it anyway */
8574 g_free (stream->segments);
8575 stream->segments = NULL;
8576 stream->n_segments = 0;
8579 /* no segments, create one to play the complete trak */
8580 if (stream->n_segments == 0) {
8581 GstClockTime stream_duration =
8582 QTSTREAMTIME_TO_GSTTIME (stream, stream->duration);
8584 if (stream->segments == NULL)
8585 stream->segments = g_new (QtDemuxSegment, 1);
8587 /* represent unknown our way */
8588 if (stream_duration == 0)
8589 stream_duration = GST_CLOCK_TIME_NONE;
8591 stream->segments[0].time = 0;
8592 stream->segments[0].stop_time = stream_duration;
8593 stream->segments[0].duration = stream_duration;
8594 stream->segments[0].media_start = 0;
8595 stream->segments[0].media_stop = stream_duration;
8596 stream->segments[0].rate = 1.0;
8597 stream->segments[0].trak_media_start = 0;
8599 GST_DEBUG_OBJECT (qtdemux, "created dummy segment %" GST_TIME_FORMAT,
8600 GST_TIME_ARGS (stream_duration));
8601 stream->n_segments = 1;
8602 stream->dummy_segment = TRUE;
8604 GST_DEBUG_OBJECT (qtdemux, "using %d segments", stream->n_segments);
8610 * Parses the stsd atom of a svq3 trak looking for
8611 * the SMI and gama atoms.
8614 qtdemux_parse_svq3_stsd_data (GstQTDemux * qtdemux, GNode * stsd,
8615 guint8 ** gamma, GstBuffer ** seqh)
8617 guint8 *_gamma = NULL;
8618 GstBuffer *_seqh = NULL;
8619 guint8 *stsd_data = stsd->data;
8620 guint32 length = QT_UINT32 (stsd_data);
8624 GST_WARNING_OBJECT (qtdemux, "stsd too short");
8630 version = QT_UINT16 (stsd_data);
8635 while (length > 8) {
8636 guint32 fourcc, size;
8638 size = QT_UINT32 (stsd_data);
8639 fourcc = QT_FOURCC (stsd_data + 4);
8640 data = stsd_data + 8;
8643 GST_WARNING_OBJECT (qtdemux, "Atom of size 0 found, aborting "
8644 "svq3 atom parsing");
8653 GST_WARNING_OBJECT (qtdemux, "Unexpected size %" G_GUINT32_FORMAT
8654 " for gama atom, expected 12", size);
8659 if (size > 16 && QT_FOURCC (data) == FOURCC_SEQH) {
8661 if (_seqh != NULL) {
8662 GST_WARNING_OBJECT (qtdemux, "Unexpected second SEQH SMI atom "
8663 " found, ignoring");
8665 seqh_size = QT_UINT32 (data + 4);
8666 if (seqh_size > 0) {
8667 _seqh = gst_buffer_new_and_alloc (seqh_size);
8668 gst_buffer_fill (_seqh, 0, data + 8, seqh_size);
8675 GST_WARNING_OBJECT (qtdemux, "Unhandled atom %" GST_FOURCC_FORMAT
8676 " in SVQ3 entry in stsd atom", GST_FOURCC_ARGS (fourcc));
8680 if (size <= length) {
8686 GST_WARNING_OBJECT (qtdemux, "SVQ3 entry too short in stsd atom");
8689 GST_WARNING_OBJECT (qtdemux, "Unexpected version for SVQ3 entry %"
8690 G_GUINT16_FORMAT, version);
8701 gst_buffer_unref (_seqh);
8706 qtdemux_get_rtsp_uri_from_hndl (GstQTDemux * qtdemux, GNode * minf)
8713 * Get 'dinf', to get its child 'dref', that might contain a 'hndl'
8714 * atom that might contain a 'data' atom with the rtsp uri.
8715 * This case was reported in bug #597497, some info about
8716 * the hndl atom can be found in TN1195
8718 dinf = qtdemux_tree_get_child_by_type (minf, FOURCC_dinf);
8719 GST_DEBUG_OBJECT (qtdemux, "Trying to obtain rtsp URI for stream trak");
8722 guint32 dref_num_entries = 0;
8723 if (qtdemux_tree_get_child_by_type_full (dinf, FOURCC_dref, &dref) &&
8724 gst_byte_reader_skip (&dref, 4) &&
8725 gst_byte_reader_get_uint32_be (&dref, &dref_num_entries)) {
8728 /* search dref entries for hndl atom */
8729 for (i = 0; i < dref_num_entries; i++) {
8730 guint32 size = 0, type;
8731 guint8 string_len = 0;
8732 if (gst_byte_reader_get_uint32_be (&dref, &size) &&
8733 qt_atom_parser_get_fourcc (&dref, &type)) {
8734 if (type == FOURCC_hndl) {
8735 GST_DEBUG_OBJECT (qtdemux, "Found hndl atom");
8737 /* skip data reference handle bytes and the
8738 * following pascal string and some extra 4
8739 * bytes I have no idea what are */
8740 if (!gst_byte_reader_skip (&dref, 4) ||
8741 !gst_byte_reader_get_uint8 (&dref, &string_len) ||
8742 !gst_byte_reader_skip (&dref, string_len + 4)) {
8743 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl atom");
8747 /* iterate over the atoms to find the data atom */
8748 while (gst_byte_reader_get_remaining (&dref) >= 8) {
8752 if (gst_byte_reader_get_uint32_be (&dref, &atom_size) &&
8753 qt_atom_parser_get_fourcc (&dref, &atom_type)) {
8754 if (atom_type == FOURCC_data) {
8755 const guint8 *uri_aux = NULL;
8757 /* found the data atom that might contain the rtsp uri */
8758 GST_DEBUG_OBJECT (qtdemux, "Found data atom inside "
8759 "hndl atom, interpreting it as an URI");
8760 if (gst_byte_reader_peek_data (&dref, atom_size - 8,
8762 if (g_strstr_len ((gchar *) uri_aux, 7, "rtsp://") != NULL)
8763 uri = g_strndup ((gchar *) uri_aux, atom_size - 8);
8765 GST_WARNING_OBJECT (qtdemux, "Data atom in hndl atom "
8766 "didn't contain a rtsp address");
8768 GST_WARNING_OBJECT (qtdemux, "Failed to get the data "
8773 /* skipping to the next entry */
8774 if (!gst_byte_reader_skip (&dref, atom_size - 8))
8777 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl child "
8784 /* skip to the next entry */
8785 if (!gst_byte_reader_skip (&dref, size - 8))
8788 GST_WARNING_OBJECT (qtdemux, "Error parsing dref atom");
8791 GST_DEBUG_OBJECT (qtdemux, "Finished parsing dref atom");
8797 #define AMR_NB_ALL_MODES 0x81ff
8798 #define AMR_WB_ALL_MODES 0x83ff
8800 qtdemux_parse_amr_bitrate (GstBuffer * buf, gboolean wb)
8802 /* The 'damr' atom is of the form:
8804 * | vendor | decoder_ver | mode_set | mode_change_period | frames/sample |
8805 * 32 b 8 b 16 b 8 b 8 b
8807 * The highest set bit of the first 7 (AMR-NB) or 8 (AMR-WB) bits of mode_set
8808 * represents the highest mode used in the stream (and thus the maximum
8809 * bitrate), with a couple of special cases as seen below.
8812 /* Map of frame type ID -> bitrate */
8813 static const guint nb_bitrates[] = {
8814 4750, 5150, 5900, 6700, 7400, 7950, 10200, 12200
8816 static const guint wb_bitrates[] = {
8817 6600, 8850, 12650, 14250, 15850, 18250, 19850, 23050, 23850
8823 gst_buffer_map (buf, &map, GST_MAP_READ);
8825 if (map.size != 0x11) {
8826 GST_DEBUG ("Atom should have size 0x11, not %" G_GSIZE_FORMAT, map.size);
8830 if (QT_FOURCC (map.data + 4) != FOURCC_damr) {
8831 GST_DEBUG ("Unknown atom in %" GST_FOURCC_FORMAT,
8832 GST_FOURCC_ARGS (QT_UINT32 (map.data + 4)));
8836 mode_set = QT_UINT16 (map.data + 13);
8838 if (mode_set == (wb ? AMR_WB_ALL_MODES : AMR_NB_ALL_MODES))
8839 max_mode = 7 + (wb ? 1 : 0);
8841 /* AMR-NB modes fo from 0-7, and AMR-WB modes go from 0-8 */
8842 max_mode = g_bit_nth_msf ((gulong) mode_set & (wb ? 0x1ff : 0xff), -1);
8844 if (max_mode == -1) {
8845 GST_DEBUG ("No mode indication was found (mode set) = %x",
8850 gst_buffer_unmap (buf, &map);
8851 return wb ? wb_bitrates[max_mode] : nb_bitrates[max_mode];
8854 gst_buffer_unmap (buf, &map);
8859 qtdemux_parse_transformation_matrix (GstQTDemux * qtdemux,
8860 GstByteReader * reader, guint32 * matrix, const gchar * atom)
8863 * 9 values of 32 bits (fixed point 16.16, except 2 5 and 8 that are 2.30)
8869 if (gst_byte_reader_get_remaining (reader) < 36)
8872 matrix[0] = gst_byte_reader_get_uint32_be_unchecked (reader);
8873 matrix[1] = gst_byte_reader_get_uint32_be_unchecked (reader);
8874 matrix[2] = gst_byte_reader_get_uint32_be_unchecked (reader);
8875 matrix[3] = gst_byte_reader_get_uint32_be_unchecked (reader);
8876 matrix[4] = gst_byte_reader_get_uint32_be_unchecked (reader);
8877 matrix[5] = gst_byte_reader_get_uint32_be_unchecked (reader);
8878 matrix[6] = gst_byte_reader_get_uint32_be_unchecked (reader);
8879 matrix[7] = gst_byte_reader_get_uint32_be_unchecked (reader);
8880 matrix[8] = gst_byte_reader_get_uint32_be_unchecked (reader);
8882 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix from atom %s", atom);
8883 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[0] >> 16,
8884 matrix[0] & 0xFFFF, matrix[1] >> 16, matrix[1] & 0xFF, matrix[2] >> 16,
8886 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[3] >> 16,
8887 matrix[3] & 0xFFFF, matrix[4] >> 16, matrix[4] & 0xFF, matrix[5] >> 16,
8889 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[6] >> 16,
8890 matrix[6] & 0xFFFF, matrix[7] >> 16, matrix[7] & 0xFF, matrix[8] >> 16,
8897 qtdemux_inspect_transformation_matrix (GstQTDemux * qtdemux,
8898 QtDemuxStream * stream, guint32 * matrix, GstTagList ** taglist)
8905 * This macro will only compare value abdegh, it expects cfi to have already
8908 #define QTCHECK_MATRIX(m,a,b,d,e) ((m)[0] == (a << 16) && (m)[1] == (b << 16) && \
8909 (m)[3] == (d << 16) && (m)[4] == (e << 16))
8911 /* only handle the cases where the last column has standard values */
8912 if (matrix[2] == 0 && matrix[5] == 0 && matrix[8] == 1 << 30) {
8913 const gchar *rotation_tag = NULL;
8915 /* no rotation needed */
8916 if (QTCHECK_MATRIX (matrix, 1, 0, 0, 1)) {
8918 } else if (QTCHECK_MATRIX (matrix, 0, 1, G_MAXUINT16, 0)) {
8919 rotation_tag = "rotate-90";
8920 } else if (QTCHECK_MATRIX (matrix, G_MAXUINT16, 0, 0, G_MAXUINT16)) {
8921 rotation_tag = "rotate-180";
8922 } else if (QTCHECK_MATRIX (matrix, 0, G_MAXUINT16, 1, 0)) {
8923 rotation_tag = "rotate-270";
8925 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
8928 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix rotation %s",
8930 if (rotation_tag != NULL) {
8931 if (*taglist == NULL)
8932 *taglist = gst_tag_list_new_empty ();
8933 gst_tag_list_add (*taglist, GST_TAG_MERGE_REPLACE,
8934 GST_TAG_IMAGE_ORIENTATION, rotation_tag, NULL);
8937 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
8941 /* Parses the boxes defined in ISO/IEC 14496-12 that enable support for
8942 * protected streams (sinf, frma, schm and schi); if the protection scheme is
8943 * Common Encryption (cenc), the function will also parse the tenc box (defined
8944 * in ISO/IEC 23001-7). @container points to the node that contains these boxes
8945 * (typically an enc[v|a|t|s] sample entry); the function will set
8946 * @original_fmt to the fourcc of the original unencrypted stream format.
8947 * Returns TRUE if successful; FALSE otherwise. */
8949 qtdemux_parse_protection_scheme_info (GstQTDemux * qtdemux,
8950 QtDemuxStream * stream, GNode * container, guint32 * original_fmt)
8957 g_return_val_if_fail (qtdemux != NULL, FALSE);
8958 g_return_val_if_fail (stream != NULL, FALSE);
8959 g_return_val_if_fail (container != NULL, FALSE);
8960 g_return_val_if_fail (original_fmt != NULL, FALSE);
8962 sinf = qtdemux_tree_get_child_by_type (container, FOURCC_sinf);
8963 if (G_UNLIKELY (!sinf)) {
8964 if (stream->protection_scheme_type == FOURCC_cenc) {
8965 GST_ERROR_OBJECT (qtdemux, "sinf box does not contain schi box, which is "
8966 "mandatory for Common Encryption");
8972 frma = qtdemux_tree_get_child_by_type (sinf, FOURCC_frma);
8973 if (G_UNLIKELY (!frma)) {
8974 GST_ERROR_OBJECT (qtdemux, "sinf box does not contain mandatory frma box");
8978 *original_fmt = QT_FOURCC ((const guint8 *) frma->data + 8);
8979 GST_DEBUG_OBJECT (qtdemux, "original stream format: '%" GST_FOURCC_FORMAT "'",
8980 GST_FOURCC_ARGS (*original_fmt));
8982 schm = qtdemux_tree_get_child_by_type (sinf, FOURCC_schm);
8984 GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schm box");
8987 stream->protection_scheme_type = QT_FOURCC ((const guint8 *) schm->data + 12);
8988 stream->protection_scheme_version =
8989 QT_UINT32 ((const guint8 *) schm->data + 16);
8991 GST_DEBUG_OBJECT (qtdemux,
8992 "protection_scheme_type: %" GST_FOURCC_FORMAT ", "
8993 "protection_scheme_version: %#010x",
8994 GST_FOURCC_ARGS (stream->protection_scheme_type),
8995 stream->protection_scheme_version);
8997 schi = qtdemux_tree_get_child_by_type (sinf, FOURCC_schi);
8999 GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schi box");
9002 if (stream->protection_scheme_type == FOURCC_cenc) {
9003 QtDemuxCencSampleSetInfo *info;
9005 const guint8 *tenc_data;
9006 guint32 isEncrypted;
9008 const guint8 *default_kid;
9011 if (G_UNLIKELY (!stream->protection_scheme_info))
9012 stream->protection_scheme_info =
9013 g_malloc0 (sizeof (QtDemuxCencSampleSetInfo));
9015 info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
9017 tenc = qtdemux_tree_get_child_by_type (schi, FOURCC_tenc);
9019 GST_ERROR_OBJECT (qtdemux, "schi box does not contain tenc box, "
9020 "which is mandatory for Common Encryption");
9023 tenc_data = (const guint8 *) tenc->data + 12;
9024 isEncrypted = QT_UINT24 (tenc_data);
9025 iv_size = QT_UINT8 (tenc_data + 3);
9026 default_kid = (tenc_data + 4);
9027 kid_buf = gst_buffer_new_allocate (NULL, 16, NULL);
9028 gst_buffer_fill (kid_buf, 0, default_kid, 16);
9029 if (info->default_properties)
9030 gst_structure_free (info->default_properties);
9031 info->default_properties =
9032 gst_structure_new ("application/x-cenc",
9033 "iv_size", G_TYPE_UINT, iv_size,
9034 "encrypted", G_TYPE_BOOLEAN, (isEncrypted == 1),
9035 "kid", GST_TYPE_BUFFER, kid_buf, NULL);
9036 GST_DEBUG_OBJECT (qtdemux, "default sample properties: "
9037 "is_encrypted=%u, iv_size=%u", isEncrypted, iv_size);
9038 gst_buffer_unref (kid_buf);
9044 * With each track we associate a new QtDemuxStream that contains all the info
9046 * traks that do not decode to something (like strm traks) will not have a pad.
9049 qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
9068 QtDemuxStream *stream = NULL;
9069 gboolean new_stream = FALSE;
9070 gchar *codec = NULL;
9071 const guint8 *stsd_data;
9072 guint16 lang_code; /* quicktime lang code or packed iso code */
9074 guint32 tkhd_flags = 0;
9075 guint8 tkhd_version = 0;
9077 guint value_size, stsd_len, len;
9081 GST_DEBUG_OBJECT (qtdemux, "parse_trak");
9083 if (!qtdemux_tree_get_child_by_type_full (trak, FOURCC_tkhd, &tkhd)
9084 || !gst_byte_reader_get_uint8 (&tkhd, &tkhd_version)
9085 || !gst_byte_reader_get_uint24_be (&tkhd, &tkhd_flags))
9088 /* pick between 64 or 32 bits */
9089 value_size = tkhd_version == 1 ? 8 : 4;
9090 if (!gst_byte_reader_skip (&tkhd, value_size * 2) ||
9091 !gst_byte_reader_get_uint32_be (&tkhd, &track_id))
9094 if (!qtdemux->got_moov) {
9095 if (qtdemux_find_stream (qtdemux, track_id))
9096 goto existing_stream;
9097 stream = _create_stream ();
9098 stream->track_id = track_id;
9101 stream = qtdemux_find_stream (qtdemux, track_id);
9103 GST_WARNING_OBJECT (qtdemux, "Stream not found, going to ignore it");
9107 /* flush samples data from this track from previous moov */
9108 gst_qtdemux_stream_flush_segments_data (qtdemux, stream);
9109 gst_qtdemux_stream_flush_samples_data (qtdemux, stream);
9111 /* need defaults for fragments */
9112 qtdemux_parse_trex (qtdemux, stream, &dummy, &dummy, &dummy);
9114 if (stream->pending_tags == NULL)
9115 stream->pending_tags = gst_tag_list_new_empty ();
9117 if ((tkhd_flags & 1) == 0)
9118 stream->disabled = TRUE;
9120 GST_LOG_OBJECT (qtdemux, "track[tkhd] version/flags/id: 0x%02x/%06x/%u",
9121 tkhd_version, tkhd_flags, stream->track_id);
9123 if (!(mdia = qtdemux_tree_get_child_by_type (trak, FOURCC_mdia)))
9126 if (!(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mdhd))) {
9127 /* be nice for some crooked mjp2 files that use mhdr for mdhd */
9128 if (qtdemux->major_brand != FOURCC_mjp2 ||
9129 !(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mhdr)))
9133 len = QT_UINT32 ((guint8 *) mdhd->data);
9134 version = QT_UINT32 ((guint8 *) mdhd->data + 8);
9135 GST_LOG_OBJECT (qtdemux, "track version/flags: %08x", version);
9136 if (version == 0x01000000) {
9139 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 28);
9140 stream->duration = QT_UINT64 ((guint8 *) mdhd->data + 32);
9141 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 36);
9145 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 20);
9146 stream->duration = QT_UINT32 ((guint8 *) mdhd->data + 24);
9147 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 28);
9150 if (lang_code < 0x400) {
9151 qtdemux_lang_map_qt_code_to_iso (stream->lang_id, lang_code);
9152 } else if (lang_code == 0x7fff) {
9153 stream->lang_id[0] = 0; /* unspecified */
9155 stream->lang_id[0] = 0x60 + ((lang_code >> 10) & 0x1F);
9156 stream->lang_id[1] = 0x60 + ((lang_code >> 5) & 0x1F);
9157 stream->lang_id[2] = 0x60 + (lang_code & 0x1F);
9158 stream->lang_id[3] = 0;
9161 GST_LOG_OBJECT (qtdemux, "track timescale: %" G_GUINT32_FORMAT,
9163 GST_LOG_OBJECT (qtdemux, "track duration: %" G_GUINT64_FORMAT,
9165 GST_LOG_OBJECT (qtdemux, "track language code/id: 0x%04x/%s",
9166 lang_code, stream->lang_id);
9168 if (G_UNLIKELY (stream->timescale == 0 || qtdemux->timescale == 0))
9171 if ((tref = qtdemux_tree_get_child_by_type (trak, FOURCC_tref))) {
9172 /* chapters track reference */
9173 GNode *chap = qtdemux_tree_get_child_by_type (tref, FOURCC_chap);
9175 gsize length = GST_READ_UINT32_BE (chap->data);
9176 if (qtdemux->chapters_track_id)
9177 GST_FIXME_OBJECT (qtdemux, "Multiple CHAP tracks");
9180 qtdemux->chapters_track_id =
9181 GST_READ_UINT32_BE ((gint8 *) chap->data + 8);
9186 /* fragmented files may have bogus duration in moov */
9187 if (!qtdemux->fragmented &&
9188 qtdemux->duration != G_MAXINT64 && stream->duration != G_MAXINT32) {
9189 guint64 tdur1, tdur2;
9191 /* don't overflow */
9192 tdur1 = stream->timescale * (guint64) qtdemux->duration;
9193 tdur2 = qtdemux->timescale * (guint64) stream->duration;
9196 * some of those trailers, nowadays, have prologue images that are
9197 * themselves video tracks as well. I haven't really found a way to
9198 * identify those yet, except for just looking at their duration. */
9199 if (tdur1 != 0 && (tdur2 * 10 / tdur1) < 2) {
9200 GST_WARNING_OBJECT (qtdemux,
9201 "Track shorter than 20%% (%" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT
9202 " vs. %" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT ") of the stream "
9203 "found, assuming preview image or something; skipping track",
9204 stream->duration, stream->timescale, qtdemux->duration,
9205 qtdemux->timescale);
9207 gst_qtdemux_stream_free (qtdemux, stream);
9212 if (!(hdlr = qtdemux_tree_get_child_by_type (mdia, FOURCC_hdlr)))
9215 GST_LOG_OBJECT (qtdemux, "track type: %" GST_FOURCC_FORMAT,
9216 GST_FOURCC_ARGS (QT_FOURCC ((guint8 *) hdlr->data + 12)));
9218 len = QT_UINT32 ((guint8 *) hdlr->data);
9220 stream->subtype = QT_FOURCC ((guint8 *) hdlr->data + 16);
9221 GST_LOG_OBJECT (qtdemux, "track subtype: %" GST_FOURCC_FORMAT,
9222 GST_FOURCC_ARGS (stream->subtype));
9224 if (!(minf = qtdemux_tree_get_child_by_type (mdia, FOURCC_minf)))
9227 if (!(stbl = qtdemux_tree_get_child_by_type (minf, FOURCC_stbl)))
9230 /*parse svmi header if existing */
9231 svmi = qtdemux_tree_get_child_by_type (stbl, FOURCC_svmi);
9233 len = QT_UINT32 ((guint8 *) svmi->data);
9234 version = QT_UINT32 ((guint8 *) svmi->data + 8);
9236 GstVideoMultiviewMode mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
9237 GstVideoMultiviewFlags flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
9238 guint8 frame_type, frame_layout;
9240 /* MPEG-A stereo video */
9241 if (qtdemux->major_brand == FOURCC_ss02)
9242 flags |= GST_VIDEO_MULTIVIEW_FLAGS_MIXED_MONO;
9244 frame_type = QT_UINT8 ((guint8 *) svmi->data + 12);
9245 frame_layout = QT_UINT8 ((guint8 *) svmi->data + 13) & 0x01;
9246 switch (frame_type) {
9248 mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
9251 mode = GST_VIDEO_MULTIVIEW_MODE_ROW_INTERLEAVED;
9254 mode = GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME;
9257 /* mode 3 is primary/secondary view sequence, ie
9258 * left/right views in separate tracks. See section 7.2
9259 * of ISO/IEC 23000-11:2009 */
9260 GST_FIXME_OBJECT (qtdemux,
9261 "Implement stereo video in separate streams");
9264 if ((frame_layout & 0x1) == 0)
9265 flags |= GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
9267 GST_LOG_OBJECT (qtdemux,
9268 "StereoVideo: composition type: %u, is_left_first: %u",
9269 frame_type, frame_layout);
9270 stream->multiview_mode = mode;
9271 stream->multiview_flags = flags;
9276 if (!(stsd = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsd)))
9278 stsd_data = (const guint8 *) stsd->data;
9280 /* stsd should at least have one entry */
9281 stsd_len = QT_UINT32 (stsd_data);
9282 if (stsd_len < 24) {
9283 /* .. but skip stream with empty stsd produced by some Vivotek cameras */
9284 if (stream->subtype == FOURCC_vivo) {
9286 gst_qtdemux_stream_free (qtdemux, stream);
9293 GST_LOG_OBJECT (qtdemux, "stsd len: %d", stsd_len);
9295 /* and that entry should fit within stsd */
9296 len = QT_UINT32 (stsd_data + 16);
9297 if (len > stsd_len + 16)
9300 stream->fourcc = fourcc = QT_FOURCC (stsd_data + 16 + 4);
9301 GST_LOG_OBJECT (qtdemux, "stsd type: %" GST_FOURCC_FORMAT,
9302 GST_FOURCC_ARGS (stream->fourcc));
9303 GST_LOG_OBJECT (qtdemux, "stsd type len: %d", len);
9305 if ((fourcc == FOURCC_drms) || (fourcc == FOURCC_drmi))
9306 goto error_encrypted;
9308 if (fourcc == FOURCC_encv || fourcc == FOURCC_enca) {
9309 GNode *enc = qtdemux_tree_get_child_by_type (stsd, fourcc);
9310 stream->protected = TRUE;
9311 if (!qtdemux_parse_protection_scheme_info (qtdemux, stream, enc, &fourcc))
9312 GST_ERROR_OBJECT (qtdemux, "Failed to parse protection scheme info");
9315 if (stream->subtype == FOURCC_vide) {
9316 guint32 w = 0, h = 0;
9318 gint depth, palette_size, palette_count;
9320 guint32 *palette_data = NULL;
9322 stream->sampled = TRUE;
9324 /* version 1 uses some 64-bit ints */
9325 if (!gst_byte_reader_skip (&tkhd, 20 + value_size))
9328 if (!qtdemux_parse_transformation_matrix (qtdemux, &tkhd, matrix, "tkhd"))
9331 if (!gst_byte_reader_get_uint32_be (&tkhd, &w)
9332 || !gst_byte_reader_get_uint32_be (&tkhd, &h))
9335 stream->display_width = w >> 16;
9336 stream->display_height = h >> 16;
9338 qtdemux_inspect_transformation_matrix (qtdemux, stream, matrix,
9339 &stream->pending_tags);
9345 stream->width = QT_UINT16 (stsd_data + offset + 32);
9346 stream->height = QT_UINT16 (stsd_data + offset + 34);
9347 stream->fps_n = 0; /* this is filled in later */
9348 stream->fps_d = 0; /* this is filled in later */
9349 stream->bits_per_sample = QT_UINT16 (stsd_data + offset + 82);
9350 stream->color_table_id = QT_UINT16 (stsd_data + offset + 84);
9352 /* if color_table_id is 0, ctab atom must follow; however some files
9353 * produced by TMPEGEnc have color_table_id = 0 and no ctab atom, so
9354 * if color table is not present we'll correct the value */
9355 if (stream->color_table_id == 0 &&
9356 (len < 90 || QT_FOURCC (stsd_data + offset + 86) != FOURCC_ctab)) {
9357 stream->color_table_id = -1;
9360 GST_LOG_OBJECT (qtdemux, "width %d, height %d, bps %d, color table id %d",
9361 stream->width, stream->height, stream->bits_per_sample,
9362 stream->color_table_id);
9364 depth = stream->bits_per_sample;
9366 /* more than 32 bits means grayscale */
9367 gray = (depth > 32);
9368 /* low 32 bits specify the depth */
9371 /* different number of palette entries is determined by depth. */
9373 if ((depth == 1) || (depth == 2) || (depth == 4) || (depth == 8))
9374 palette_count = (1 << depth);
9375 palette_size = palette_count * 4;
9377 if (stream->color_table_id) {
9378 switch (palette_count) {
9382 palette_data = g_memdup (ff_qt_default_palette_2, palette_size);
9385 palette_data = g_memdup (ff_qt_default_palette_4, palette_size);
9389 palette_data = g_memdup (ff_qt_grayscale_palette_16, palette_size);
9391 palette_data = g_memdup (ff_qt_default_palette_16, palette_size);
9395 palette_data = g_memdup (ff_qt_grayscale_palette_256, palette_size);
9397 palette_data = g_memdup (ff_qt_default_palette_256, palette_size);
9400 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
9401 (_("The video in this file might not play correctly.")),
9402 ("unsupported palette depth %d", depth));
9406 gint i, j, start, end;
9412 start = QT_UINT32 (stsd_data + offset + 86);
9413 palette_count = QT_UINT16 (stsd_data + offset + 90);
9414 end = QT_UINT16 (stsd_data + offset + 92);
9416 GST_LOG_OBJECT (qtdemux, "start %d, end %d, palette_count %d",
9417 start, end, palette_count);
9424 if (len < 94 + (end - start) * 8)
9427 /* palette is always the same size */
9428 palette_data = g_malloc0 (256 * 4);
9429 palette_size = 256 * 4;
9431 for (j = 0, i = start; i <= end; j++, i++) {
9434 a = QT_UINT16 (stsd_data + offset + 94 + (j * 8));
9435 r = QT_UINT16 (stsd_data + offset + 96 + (j * 8));
9436 g = QT_UINT16 (stsd_data + offset + 98 + (j * 8));
9437 b = QT_UINT16 (stsd_data + offset + 100 + (j * 8));
9439 palette_data[i] = ((a & 0xff00) << 16) | ((r & 0xff00) << 8) |
9440 (g & 0xff00) | (b >> 8);
9445 gst_caps_unref (stream->caps);
9448 qtdemux_video_caps (qtdemux, stream, fourcc, stsd_data, &codec);
9449 if (G_UNLIKELY (!stream->caps)) {
9450 g_free (palette_data);
9451 goto unknown_stream;
9455 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
9456 GST_TAG_VIDEO_CODEC, codec, NULL);
9465 if (stream->rgb8_palette)
9466 gst_memory_unref (stream->rgb8_palette);
9467 stream->rgb8_palette = gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY,
9468 palette_data, palette_size, 0, palette_size, palette_data, g_free);
9470 s = gst_caps_get_structure (stream->caps, 0);
9472 /* non-raw video has a palette_data property. raw video has the palette as
9473 * an extra plane that we append to the output buffers before we push
9475 if (!gst_structure_has_name (s, "video/x-raw")) {
9478 palette = gst_buffer_new ();
9479 gst_buffer_append_memory (palette, stream->rgb8_palette);
9480 stream->rgb8_palette = NULL;
9482 gst_caps_set_simple (stream->caps, "palette_data",
9483 GST_TYPE_BUFFER, palette, NULL);
9484 gst_buffer_unref (palette);
9486 } else if (palette_count != 0) {
9487 GST_ELEMENT_WARNING (qtdemux, STREAM, NOT_IMPLEMENTED,
9488 (NULL), ("Unsupported palette depth %d", depth));
9491 GST_LOG_OBJECT (qtdemux, "frame count: %u",
9492 QT_UINT16 (stsd_data + offset + 48));
9496 /* pick 'the' stsd child */
9497 if (!stream->protected)
9498 mp4v = qtdemux_tree_get_child_by_type (stsd, fourcc);
9500 mp4v = qtdemux_tree_get_child_by_type (stsd, FOURCC_encv);
9503 esds = qtdemux_tree_get_child_by_type (mp4v, FOURCC_esds);
9504 pasp = qtdemux_tree_get_child_by_type (mp4v, FOURCC_pasp);
9508 const guint8 *pasp_data = (const guint8 *) pasp->data;
9510 stream->par_w = QT_UINT32 (pasp_data + 8);
9511 stream->par_h = QT_UINT32 (pasp_data + 12);
9518 gst_qtdemux_handle_esds (qtdemux, stream, esds, stream->pending_tags);
9525 gint len = QT_UINT32 (stsd_data) - 0x66;
9526 const guint8 *avc_data = stsd_data + 0x66;
9529 while (len >= 0x8) {
9532 if (QT_UINT32 (avc_data) <= len)
9533 size = QT_UINT32 (avc_data) - 0x8;
9538 /* No real data, so break out */
9541 switch (QT_FOURCC (avc_data + 0x4)) {
9544 /* parse, if found */
9547 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
9549 /* First 4 bytes are the length of the atom, the next 4 bytes
9550 * are the fourcc, the next 1 byte is the version, and the
9551 * subsequent bytes are profile_tier_level structure like data. */
9552 gst_codec_utils_h264_caps_set_level_and_profile (stream->caps,
9553 avc_data + 8 + 1, size - 1);
9554 buf = gst_buffer_new_and_alloc (size);
9555 gst_buffer_fill (buf, 0, avc_data + 0x8, size);
9556 gst_caps_set_simple (stream->caps,
9557 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9558 gst_buffer_unref (buf);
9566 GST_DEBUG_OBJECT (qtdemux, "found strf codec_data in stsd");
9568 /* First 4 bytes are the length of the atom, the next 4 bytes
9569 * are the fourcc, next 40 bytes are BITMAPINFOHEADER,
9570 * next 1 byte is the version, and the
9571 * subsequent bytes are sequence parameter set like data. */
9573 size -= 40; /* we'll be skipping BITMAPINFOHEADER */
9575 gst_codec_utils_h264_caps_set_level_and_profile (stream->caps,
9576 avc_data + 8 + 40 + 1, size - 1);
9578 buf = gst_buffer_new_and_alloc (size);
9579 gst_buffer_fill (buf, 0, avc_data + 8 + 40, size);
9580 gst_caps_set_simple (stream->caps,
9581 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9582 gst_buffer_unref (buf);
9588 guint avg_bitrate, max_bitrate;
9590 /* bufferSizeDB, maxBitrate and avgBitrate - 4 bytes each */
9594 max_bitrate = QT_UINT32 (avc_data + 0xc);
9595 avg_bitrate = QT_UINT32 (avc_data + 0x10);
9597 if (!max_bitrate && !avg_bitrate)
9600 /* Some muxers seem to swap the average and maximum bitrates
9601 * (I'm looking at you, YouTube), so we swap for sanity. */
9602 if (max_bitrate > 0 && max_bitrate < avg_bitrate) {
9603 guint temp = avg_bitrate;
9605 avg_bitrate = max_bitrate;
9609 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
9610 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
9611 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
9613 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
9614 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
9615 GST_TAG_BITRATE, avg_bitrate, NULL);
9626 avc_data += size + 8;
9635 gint len = QT_UINT32 (stsd_data) - 0x66;
9636 const guint8 *hevc_data = stsd_data + 0x66;
9639 while (len >= 0x8) {
9642 if (QT_UINT32 (hevc_data) <= len)
9643 size = QT_UINT32 (hevc_data) - 0x8;
9648 /* No real data, so break out */
9651 switch (QT_FOURCC (hevc_data + 0x4)) {
9654 /* parse, if found */
9657 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
9659 /* First 4 bytes are the length of the atom, the next 4 bytes
9660 * are the fourcc, the next 1 byte is the version, and the
9661 * subsequent bytes are sequence parameter set like data. */
9662 gst_codec_utils_h265_caps_set_level_tier_and_profile
9663 (stream->caps, hevc_data + 8 + 1, size - 1);
9665 buf = gst_buffer_new_and_alloc (size);
9666 gst_buffer_fill (buf, 0, hevc_data + 0x8, size);
9667 gst_caps_set_simple (stream->caps,
9668 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9669 gst_buffer_unref (buf);
9676 hevc_data += size + 8;
9687 GST_DEBUG_OBJECT (qtdemux, "found %" GST_FOURCC_FORMAT,
9688 GST_FOURCC_ARGS (fourcc));
9690 /* codec data might be in glbl extension atom */
9692 qtdemux_tree_get_child_by_type (mp4v, FOURCC_glbl) : NULL;
9698 GST_DEBUG_OBJECT (qtdemux, "found glbl data in stsd");
9700 len = QT_UINT32 (data);
9703 buf = gst_buffer_new_and_alloc (len);
9704 gst_buffer_fill (buf, 0, data + 8, len);
9705 gst_caps_set_simple (stream->caps,
9706 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9707 gst_buffer_unref (buf);
9714 /* see annex I of the jpeg2000 spec */
9715 GNode *jp2h, *ihdr, *colr, *mjp2, *field, *prefix, *cmap, *cdef;
9717 const gchar *colorspace = NULL;
9719 guint32 ncomp_map = 0;
9720 gint32 *comp_map = NULL;
9721 guint32 nchan_def = 0;
9722 gint32 *chan_def = NULL;
9724 GST_DEBUG_OBJECT (qtdemux, "found mjp2");
9725 /* some required atoms */
9726 mjp2 = qtdemux_tree_get_child_by_type (stsd, FOURCC_mjp2);
9729 jp2h = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2h);
9733 /* number of components; redundant with info in codestream, but useful
9735 ihdr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_ihdr);
9736 if (!ihdr || QT_UINT32 (ihdr->data) != 22)
9738 ncomp = QT_UINT16 (((guint8 *) ihdr->data) + 16);
9740 colr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_colr);
9743 GST_DEBUG_OBJECT (qtdemux, "found colr");
9744 /* extract colour space info */
9745 if (QT_UINT8 ((guint8 *) colr->data + 8) == 1) {
9746 switch (QT_UINT32 ((guint8 *) colr->data + 11)) {
9748 colorspace = "sRGB";
9751 colorspace = "GRAY";
9754 colorspace = "sYUV";
9762 /* colr is required, and only values 16, 17, and 18 are specified,
9763 so error if we have no colorspace */
9766 /* extract component mapping */
9767 cmap = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cmap);
9769 guint32 cmap_len = 0;
9771 cmap_len = QT_UINT32 (cmap->data);
9772 if (cmap_len >= 8) {
9773 /* normal box, subtract off header */
9775 /* cmap: { u16 cmp; u8 mtyp; u8 pcol; }* */
9776 if (cmap_len % 4 == 0) {
9777 ncomp_map = (cmap_len / 4);
9778 comp_map = g_new0 (gint32, ncomp_map);
9779 for (i = 0; i < ncomp_map; i++) {
9782 cmp = QT_UINT16 (((guint8 *) cmap->data) + 8 + i * 4);
9783 mtyp = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 2);
9784 pcol = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 3);
9785 comp_map[i] = (mtyp << 24) | (pcol << 16) | cmp;
9790 /* extract channel definitions */
9791 cdef = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cdef);
9793 guint32 cdef_len = 0;
9795 cdef_len = QT_UINT32 (cdef->data);
9796 if (cdef_len >= 10) {
9797 /* normal box, subtract off header and len */
9799 /* cdef: u16 n; { u16 cn; u16 typ; u16 asoc; }* */
9800 if (cdef_len % 6 == 0) {
9801 nchan_def = (cdef_len / 6);
9802 chan_def = g_new0 (gint32, nchan_def);
9803 for (i = 0; i < nchan_def; i++)
9805 for (i = 0; i < nchan_def; i++) {
9806 guint16 cn, typ, asoc;
9807 cn = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6);
9808 typ = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 2);
9809 asoc = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 4);
9810 if (cn < nchan_def) {
9813 chan_def[cn] = asoc;
9816 chan_def[cn] = 0; /* alpha */
9819 chan_def[cn] = -typ;
9827 gst_caps_set_simple (stream->caps,
9828 "num-components", G_TYPE_INT, ncomp, NULL);
9829 gst_caps_set_simple (stream->caps,
9830 "colorspace", G_TYPE_STRING, colorspace, NULL);
9833 GValue arr = { 0, };
9834 GValue elt = { 0, };
9836 g_value_init (&arr, GST_TYPE_ARRAY);
9837 g_value_init (&elt, G_TYPE_INT);
9838 for (i = 0; i < ncomp_map; i++) {
9839 g_value_set_int (&elt, comp_map[i]);
9840 gst_value_array_append_value (&arr, &elt);
9842 gst_structure_set_value (gst_caps_get_structure (stream->caps, 0),
9843 "component-map", &arr);
9844 g_value_unset (&elt);
9845 g_value_unset (&arr);
9850 GValue arr = { 0, };
9851 GValue elt = { 0, };
9853 g_value_init (&arr, GST_TYPE_ARRAY);
9854 g_value_init (&elt, G_TYPE_INT);
9855 for (i = 0; i < nchan_def; i++) {
9856 g_value_set_int (&elt, chan_def[i]);
9857 gst_value_array_append_value (&arr, &elt);
9859 gst_structure_set_value (gst_caps_get_structure (stream->caps, 0),
9860 "channel-definitions", &arr);
9861 g_value_unset (&elt);
9862 g_value_unset (&arr);
9866 /* some optional atoms */
9867 field = qtdemux_tree_get_child_by_type (mjp2, FOURCC_fiel);
9868 prefix = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2x);
9870 /* indicate possible fields in caps */
9872 data = (guint8 *) field->data + 8;
9874 gst_caps_set_simple (stream->caps, "fields", G_TYPE_INT,
9875 (gint) * data, NULL);
9877 /* add codec_data if provided */
9882 GST_DEBUG_OBJECT (qtdemux, "found prefix data in stsd");
9883 data = prefix->data;
9884 len = QT_UINT32 (data);
9887 buf = gst_buffer_new_and_alloc (len);
9888 gst_buffer_fill (buf, 0, data + 8, len);
9889 gst_caps_set_simple (stream->caps,
9890 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9891 gst_buffer_unref (buf);
9900 GstBuffer *seqh = NULL;
9901 guint8 *gamma_data = NULL;
9902 gint len = QT_UINT32 (stsd_data);
9904 qtdemux_parse_svq3_stsd_data (qtdemux, stsd, &gamma_data, &seqh);
9906 gst_caps_set_simple (stream->caps, "applied-gamma", G_TYPE_DOUBLE,
9907 QT_FP32 (gamma_data), NULL);
9910 /* sorry for the bad name, but we don't know what this is, other
9911 * than its own fourcc */
9912 gst_caps_set_simple (stream->caps, "seqh", GST_TYPE_BUFFER, seqh,
9916 GST_DEBUG_OBJECT (qtdemux, "found codec_data in stsd");
9917 buf = gst_buffer_new_and_alloc (len);
9918 gst_buffer_fill (buf, 0, stsd_data, len);
9919 gst_caps_set_simple (stream->caps,
9920 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9921 gst_buffer_unref (buf);
9927 gst_caps_set_simple (stream->caps,
9928 "depth", G_TYPE_INT, QT_UINT16 (stsd_data + offset + 82), NULL);
9935 GST_DEBUG_OBJECT (qtdemux, "found XiTh");
9936 xith = qtdemux_tree_get_child_by_type (stsd, FOURCC_XiTh);
9940 xdxt = qtdemux_tree_get_child_by_type (xith, FOURCC_XdxT);
9944 GST_DEBUG_OBJECT (qtdemux, "found XdxT node");
9945 /* collect the headers and store them in a stream list so that we can
9946 * send them out first */
9947 qtdemux_parse_theora_extension (qtdemux, stream, xdxt);
9957 GST_DEBUG_OBJECT (qtdemux, "parse ovc1 header");
9958 ovc1 = qtdemux_tree_get_child_by_type (stsd, FOURCC_ovc1);
9961 ovc1_data = ovc1->data;
9962 ovc1_len = QT_UINT32 (ovc1_data);
9963 if (ovc1_len <= 198) {
9964 GST_WARNING_OBJECT (qtdemux, "Too small ovc1 header, skipping");
9967 buf = gst_buffer_new_and_alloc (ovc1_len - 198);
9968 gst_buffer_fill (buf, 0, ovc1_data + 198, ovc1_len - 198);
9969 gst_caps_set_simple (stream->caps,
9970 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9971 gst_buffer_unref (buf);
9976 gint len = QT_UINT32 (stsd_data) - 0x66;
9977 const guint8 *vc1_data = stsd_data + 0x66;
9983 if (QT_UINT32 (vc1_data) <= len)
9984 size = QT_UINT32 (vc1_data) - 8;
9989 /* No real data, so break out */
9992 switch (QT_FOURCC (vc1_data + 0x4)) {
9993 case GST_MAKE_FOURCC ('d', 'v', 'c', '1'):
9997 GST_DEBUG_OBJECT (qtdemux, "found dvc1 codec_data in stsd");
9998 buf = gst_buffer_new_and_alloc (size);
9999 gst_buffer_fill (buf, 0, vc1_data + 8, size);
10000 gst_caps_set_simple (stream->caps,
10001 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10002 gst_buffer_unref (buf);
10009 vc1_data += size + 8;
10018 GST_INFO_OBJECT (qtdemux,
10019 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
10020 GST_FOURCC_ARGS (fourcc), stream->caps);
10022 } else if (stream->subtype == FOURCC_soun) {
10023 int version, samplesize;
10024 guint16 compression_id;
10025 gboolean amrwb = FALSE;
10028 /* sample description entry (16) + sound sample description v0 (20) */
10032 version = QT_UINT32 (stsd_data + offset);
10033 stream->n_channels = QT_UINT16 (stsd_data + offset + 8);
10034 samplesize = QT_UINT16 (stsd_data + offset + 10);
10035 compression_id = QT_UINT16 (stsd_data + offset + 12);
10036 stream->rate = QT_FP32 (stsd_data + offset + 16);
10038 GST_LOG_OBJECT (qtdemux, "version/rev: %08x", version);
10039 GST_LOG_OBJECT (qtdemux, "vendor: %08x",
10040 QT_UINT32 (stsd_data + offset + 4));
10041 GST_LOG_OBJECT (qtdemux, "n_channels: %d", stream->n_channels);
10042 GST_LOG_OBJECT (qtdemux, "sample_size: %d", samplesize);
10043 GST_LOG_OBJECT (qtdemux, "compression_id: %d", compression_id);
10044 GST_LOG_OBJECT (qtdemux, "packet size: %d",
10045 QT_UINT16 (stsd_data + offset + 14));
10046 GST_LOG_OBJECT (qtdemux, "sample rate: %g", stream->rate);
10048 if (compression_id == 0xfffe)
10049 stream->sampled = TRUE;
10051 /* first assume uncompressed audio */
10052 stream->bytes_per_sample = samplesize / 8;
10053 stream->samples_per_frame = stream->n_channels;
10054 stream->bytes_per_frame = stream->n_channels * stream->bytes_per_sample;
10055 stream->samples_per_packet = stream->samples_per_frame;
10056 stream->bytes_per_packet = stream->bytes_per_sample;
10060 /* Yes, these have to be hard-coded */
10063 stream->samples_per_packet = 6;
10064 stream->bytes_per_packet = 1;
10065 stream->bytes_per_frame = 1 * stream->n_channels;
10066 stream->bytes_per_sample = 1;
10067 stream->samples_per_frame = 6 * stream->n_channels;
10072 stream->samples_per_packet = 3;
10073 stream->bytes_per_packet = 1;
10074 stream->bytes_per_frame = 1 * stream->n_channels;
10075 stream->bytes_per_sample = 1;
10076 stream->samples_per_frame = 3 * stream->n_channels;
10081 stream->samples_per_packet = 64;
10082 stream->bytes_per_packet = 34;
10083 stream->bytes_per_frame = 34 * stream->n_channels;
10084 stream->bytes_per_sample = 2;
10085 stream->samples_per_frame = 64 * stream->n_channels;
10091 stream->samples_per_packet = 1;
10092 stream->bytes_per_packet = 1;
10093 stream->bytes_per_frame = 1 * stream->n_channels;
10094 stream->bytes_per_sample = 1;
10095 stream->samples_per_frame = 1 * stream->n_channels;
10100 stream->samples_per_packet = 160;
10101 stream->bytes_per_packet = 33;
10102 stream->bytes_per_frame = 33 * stream->n_channels;
10103 stream->bytes_per_sample = 2;
10104 stream->samples_per_frame = 160 * stream->n_channels;
10111 if (version == 0x00010000) {
10112 /* sample description entry (16) + sound sample description v1 (20+16) */
10123 /* only parse extra decoding config for non-pcm audio */
10124 stream->samples_per_packet = QT_UINT32 (stsd_data + offset);
10125 stream->bytes_per_packet = QT_UINT32 (stsd_data + offset + 4);
10126 stream->bytes_per_frame = QT_UINT32 (stsd_data + offset + 8);
10127 stream->bytes_per_sample = QT_UINT32 (stsd_data + offset + 12);
10129 GST_LOG_OBJECT (qtdemux, "samples/packet: %d",
10130 stream->samples_per_packet);
10131 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
10132 stream->bytes_per_packet);
10133 GST_LOG_OBJECT (qtdemux, "bytes/frame: %d",
10134 stream->bytes_per_frame);
10135 GST_LOG_OBJECT (qtdemux, "bytes/sample: %d",
10136 stream->bytes_per_sample);
10138 if (!stream->sampled && stream->bytes_per_packet) {
10139 stream->samples_per_frame = (stream->bytes_per_frame /
10140 stream->bytes_per_packet) * stream->samples_per_packet;
10141 GST_LOG_OBJECT (qtdemux, "samples/frame: %d",
10142 stream->samples_per_frame);
10147 } else if (version == 0x00020000) {
10154 /* sample description entry (16) + sound sample description v2 (56) */
10158 qtfp.val = QT_UINT64 (stsd_data + offset + 4);
10159 stream->rate = qtfp.fp;
10160 stream->n_channels = QT_UINT32 (stsd_data + offset + 12);
10162 GST_LOG_OBJECT (qtdemux, "Sound sample description Version 2");
10163 GST_LOG_OBJECT (qtdemux, "sample rate: %g", stream->rate);
10164 GST_LOG_OBJECT (qtdemux, "n_channels: %d", stream->n_channels);
10165 GST_LOG_OBJECT (qtdemux, "bits/channel: %d",
10166 QT_UINT32 (stsd_data + offset + 20));
10167 GST_LOG_OBJECT (qtdemux, "format flags: %X",
10168 QT_UINT32 (stsd_data + offset + 24));
10169 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
10170 QT_UINT32 (stsd_data + offset + 28));
10171 GST_LOG_OBJECT (qtdemux, "LPCM frames/packet: %d",
10172 QT_UINT32 (stsd_data + offset + 32));
10173 } else if (version != 0x00000) {
10174 GST_WARNING_OBJECT (qtdemux, "unknown audio STSD version %08x", version);
10178 gst_caps_unref (stream->caps);
10180 stream->caps = qtdemux_audio_caps (qtdemux, stream, fourcc,
10181 stsd_data + 32, len - 16, &codec);
10189 in24 = qtdemux_tree_get_child_by_type (stsd, FOURCC_in24);
10191 enda = qtdemux_tree_get_child_by_type (in24, FOURCC_enda);
10193 wave = qtdemux_tree_get_child_by_type (in24, FOURCC_wave);
10195 enda = qtdemux_tree_get_child_by_type (wave, FOURCC_enda);
10198 int enda_value = QT_UINT16 ((guint8 *) enda->data + 8);
10199 gst_caps_set_simple (stream->caps,
10200 "format", G_TYPE_STRING, (enda_value) ? "S24LE" : "S24BE", NULL);
10207 const guint8 *owma_data;
10208 const gchar *codec_name = NULL;
10212 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
10213 /* FIXME this should also be gst_riff_strf_auds,
10214 * but the latter one is actually missing bits-per-sample :( */
10219 gint32 nSamplesPerSec;
10220 gint32 nAvgBytesPerSec;
10221 gint16 nBlockAlign;
10222 gint16 wBitsPerSample;
10225 WAVEFORMATEX *wfex;
10227 GST_DEBUG_OBJECT (qtdemux, "parse owma");
10228 owma = qtdemux_tree_get_child_by_type (stsd, FOURCC_owma);
10231 owma_data = owma->data;
10232 owma_len = QT_UINT32 (owma_data);
10233 if (owma_len <= 54) {
10234 GST_WARNING_OBJECT (qtdemux, "Too small owma header, skipping");
10237 wfex = (WAVEFORMATEX *) (owma_data + 36);
10238 buf = gst_buffer_new_and_alloc (owma_len - 54);
10239 gst_buffer_fill (buf, 0, owma_data + 54, owma_len - 54);
10240 if (wfex->wFormatTag == 0x0161) {
10241 codec_name = "Windows Media Audio";
10243 } else if (wfex->wFormatTag == 0x0162) {
10244 codec_name = "Windows Media Audio 9 Pro";
10246 } else if (wfex->wFormatTag == 0x0163) {
10247 codec_name = "Windows Media Audio 9 Lossless";
10248 /* is that correct? gstffmpegcodecmap.c is missing it, but
10249 * fluendo codec seems to support it */
10253 gst_caps_set_simple (stream->caps,
10254 "codec_data", GST_TYPE_BUFFER, buf,
10255 "wmaversion", G_TYPE_INT, version,
10256 "block_align", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->nBlockAlign),
10257 "bitrate", G_TYPE_INT, GST_READ_UINT32_LE (&wfex->nAvgBytesPerSec),
10258 "width", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->wBitsPerSample),
10259 "depth", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->wBitsPerSample),
10261 gst_buffer_unref (buf);
10265 codec = g_strdup (codec_name);
10271 gint len = QT_UINT32 (stsd_data) - offset;
10272 const guint8 *wfex_data = stsd_data + offset;
10273 const gchar *codec_name = NULL;
10275 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
10276 /* FIXME this should also be gst_riff_strf_auds,
10277 * but the latter one is actually missing bits-per-sample :( */
10282 gint32 nSamplesPerSec;
10283 gint32 nAvgBytesPerSec;
10284 gint16 nBlockAlign;
10285 gint16 wBitsPerSample;
10290 /* FIXME: unify with similar wavformatex parsing code above */
10291 GST_DEBUG_OBJECT (qtdemux, "parse wma, looking for wfex");
10297 if (QT_UINT32 (wfex_data) <= len)
10298 size = QT_UINT32 (wfex_data) - 8;
10303 /* No real data, so break out */
10306 switch (QT_FOURCC (wfex_data + 4)) {
10307 case GST_MAKE_FOURCC ('w', 'f', 'e', 'x'):
10309 GST_DEBUG_OBJECT (qtdemux, "found wfex in stsd");
10314 wfex.wFormatTag = GST_READ_UINT16_LE (wfex_data + 8 + 0);
10315 wfex.nChannels = GST_READ_UINT16_LE (wfex_data + 8 + 2);
10316 wfex.nSamplesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 4);
10317 wfex.nAvgBytesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 8);
10318 wfex.nBlockAlign = GST_READ_UINT16_LE (wfex_data + 8 + 12);
10319 wfex.wBitsPerSample = GST_READ_UINT16_LE (wfex_data + 8 + 14);
10320 wfex.cbSize = GST_READ_UINT16_LE (wfex_data + 8 + 16);
10322 GST_LOG_OBJECT (qtdemux, "Found wfex box in stsd:");
10323 GST_LOG_OBJECT (qtdemux, "FormatTag = 0x%04x, Channels = %u, "
10324 "SamplesPerSec = %u, AvgBytesPerSec = %u, BlockAlign = %u, "
10325 "BitsPerSample = %u, Size = %u", wfex.wFormatTag,
10326 wfex.nChannels, wfex.nSamplesPerSec, wfex.nAvgBytesPerSec,
10327 wfex.nBlockAlign, wfex.wBitsPerSample, wfex.cbSize);
10329 if (wfex.wFormatTag == 0x0161) {
10330 codec_name = "Windows Media Audio";
10332 } else if (wfex.wFormatTag == 0x0162) {
10333 codec_name = "Windows Media Audio 9 Pro";
10335 } else if (wfex.wFormatTag == 0x0163) {
10336 codec_name = "Windows Media Audio 9 Lossless";
10337 /* is that correct? gstffmpegcodecmap.c is missing it, but
10338 * fluendo codec seems to support it */
10342 gst_caps_set_simple (stream->caps,
10343 "wmaversion", G_TYPE_INT, version,
10344 "block_align", G_TYPE_INT, wfex.nBlockAlign,
10345 "bitrate", G_TYPE_INT, wfex.nAvgBytesPerSec,
10346 "width", G_TYPE_INT, wfex.wBitsPerSample,
10347 "depth", G_TYPE_INT, wfex.wBitsPerSample, NULL);
10349 if (size > wfex.cbSize) {
10352 buf = gst_buffer_new_and_alloc (size - wfex.cbSize);
10353 gst_buffer_fill (buf, 0, wfex_data + 8 + wfex.cbSize,
10354 size - wfex.cbSize);
10355 gst_caps_set_simple (stream->caps,
10356 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10357 gst_buffer_unref (buf);
10359 GST_WARNING_OBJECT (qtdemux, "no codec data");
10364 codec = g_strdup (codec_name);
10372 wfex_data += size + 8;
10379 const guint8 *opus_data;
10380 guint8 *channel_mapping = NULL;
10383 guint8 channel_mapping_family;
10384 guint8 stream_count;
10385 guint8 coupled_count;
10388 opus = qtdemux_tree_get_child_by_type (stsd, FOURCC_opus);
10389 opus_data = opus->data;
10391 channels = GST_READ_UINT8 (opus_data + 45);
10392 rate = GST_READ_UINT32_LE (opus_data + 48);
10393 channel_mapping_family = GST_READ_UINT8 (opus_data + 54);
10394 stream_count = GST_READ_UINT8 (opus_data + 55);
10395 coupled_count = GST_READ_UINT8 (opus_data + 56);
10397 if (channels > 0) {
10398 channel_mapping = g_malloc (channels * sizeof (guint8));
10399 for (i = 0; i < channels; i++)
10400 channel_mapping[i] = GST_READ_UINT8 (opus_data + i + 57);
10403 stream->caps = gst_codec_utils_opus_create_caps (rate, channels,
10404 channel_mapping_family, stream_count, coupled_count,
10416 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
10417 GST_TAG_AUDIO_CODEC, codec, NULL);
10421 /* some bitrate info may have ended up in caps */
10422 s = gst_caps_get_structure (stream->caps, 0);
10423 gst_structure_get_int (s, "bitrate", &bitrate);
10425 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
10426 GST_TAG_BITRATE, bitrate, NULL);
10429 if (stream->protected && fourcc == FOURCC_mp4a)
10430 mp4a = qtdemux_tree_get_child_by_type (stsd, FOURCC_enca);
10432 mp4a = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4a);
10437 wave = qtdemux_tree_get_child_by_type (mp4a, FOURCC_wave);
10439 esds = qtdemux_tree_get_child_by_type (wave, FOURCC_esds);
10441 esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
10445 /* If the fourcc's bottom 16 bits gives 'sm', then the top
10446 16 bits is a byte-swapped wave-style codec identifier,
10447 and we can find a WAVE header internally to a 'wave' atom here.
10448 This can more clearly be thought of as 'ms' as the top 16 bits, and a
10449 codec id as the bottom 16 bits - but byte-swapped to store in QT (which
10452 if ((fourcc & 0xffff) == (('s' << 8) | 'm')) {
10453 if (len < offset + 20) {
10454 GST_WARNING_OBJECT (qtdemux, "No wave atom in MS-style audio");
10456 guint32 datalen = QT_UINT32 (stsd_data + offset + 16);
10457 const guint8 *data = stsd_data + offset + 16;
10459 GNode *waveheadernode;
10461 wavenode = g_node_new ((guint8 *) data);
10462 if (qtdemux_parse_node (qtdemux, wavenode, data, datalen)) {
10463 const guint8 *waveheader;
10466 waveheadernode = qtdemux_tree_get_child_by_type (wavenode, fourcc);
10467 if (waveheadernode) {
10468 waveheader = (const guint8 *) waveheadernode->data;
10469 headerlen = QT_UINT32 (waveheader);
10471 if (headerlen > 8) {
10472 gst_riff_strf_auds *header = NULL;
10473 GstBuffer *headerbuf;
10479 headerbuf = gst_buffer_new_and_alloc (headerlen);
10480 gst_buffer_fill (headerbuf, 0, waveheader, headerlen);
10482 if (gst_riff_parse_strf_auds (GST_ELEMENT_CAST (qtdemux),
10483 headerbuf, &header, &extra)) {
10484 gst_caps_unref (stream->caps);
10485 /* FIXME: Need to do something with the channel reorder map */
10486 stream->caps = gst_riff_create_audio_caps (header->format, NULL,
10487 header, extra, NULL, NULL, NULL);
10490 gst_buffer_unref (extra);
10495 GST_DEBUG ("Didn't find waveheadernode for this codec");
10497 g_node_destroy (wavenode);
10500 gst_qtdemux_handle_esds (qtdemux, stream, esds, stream->pending_tags);
10504 /* FIXME: what is in the chunk? */
10507 gint len = QT_UINT32 (stsd_data);
10509 /* seems to be always = 116 = 0x74 */
10515 gint len = QT_UINT32 (stsd_data);
10518 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x4C);
10520 gst_buffer_fill (buf, 0, stsd_data + 0x4C, len - 0x4C);
10521 gst_caps_set_simple (stream->caps,
10522 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10523 gst_buffer_unref (buf);
10525 gst_caps_set_simple (stream->caps,
10526 "samplesize", G_TYPE_INT, samplesize, NULL);
10531 GNode *alac, *wave = NULL;
10533 /* apparently, m4a has this atom appended directly in the stsd entry,
10534 * while mov has it in a wave atom */
10535 alac = qtdemux_tree_get_child_by_type (stsd, FOURCC_alac);
10537 /* alac now refers to stsd entry atom */
10538 wave = qtdemux_tree_get_child_by_type (alac, FOURCC_wave);
10540 alac = qtdemux_tree_get_child_by_type (wave, FOURCC_alac);
10542 alac = qtdemux_tree_get_child_by_type (alac, FOURCC_alac);
10545 const guint8 *alac_data = alac->data;
10546 gint len = QT_UINT32 (alac->data);
10550 GST_DEBUG_OBJECT (qtdemux,
10551 "discarding alac atom with unexpected len %d", len);
10553 /* codec-data contains alac atom size and prefix,
10554 * ffmpeg likes it that way, not quite gst-ish though ...*/
10555 buf = gst_buffer_new_and_alloc (len);
10556 gst_buffer_fill (buf, 0, alac->data, len);
10557 gst_caps_set_simple (stream->caps,
10558 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10559 gst_buffer_unref (buf);
10561 stream->bytes_per_frame = QT_UINT32 (alac_data + 12);
10562 stream->n_channels = QT_UINT8 (alac_data + 21);
10563 stream->rate = QT_UINT32 (alac_data + 32);
10566 gst_caps_set_simple (stream->caps,
10567 "samplesize", G_TYPE_INT, samplesize, NULL);
10575 gint len = QT_UINT32 (stsd_data);
10578 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x34);
10581 gst_buffer_fill (buf, 0, stsd_data + 0x34, len - 0x34);
10583 /* If we have enough data, let's try to get the 'damr' atom. See
10584 * the 3GPP container spec (26.244) for more details. */
10585 if ((len - 0x34) > 8 &&
10586 (bitrate = qtdemux_parse_amr_bitrate (buf, amrwb))) {
10587 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
10588 GST_TAG_MAXIMUM_BITRATE, bitrate, NULL);
10591 gst_caps_set_simple (stream->caps,
10592 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10593 gst_buffer_unref (buf);
10599 /* mp4a atom withtout ESDS; Attempt to build codec data from atom */
10600 gint len = QT_UINT32 (stsd_data);
10603 guint16 sound_version = QT_UINT16 (stsd_data + 32);
10605 if (sound_version == 1) {
10606 guint16 channels = QT_UINT16 (stsd_data + 40);
10607 guint32 time_scale = QT_UINT32 (stsd_data + 46);
10608 guint8 codec_data[2];
10610 gint profile = 2; /* FIXME: Can this be determined somehow? There doesn't seem to be anything in mp4a atom that specifis compression */
10612 gint sample_rate_index =
10613 gst_codec_utils_aac_get_index_from_sample_rate (time_scale);
10615 /* build AAC codec data */
10616 codec_data[0] = profile << 3;
10617 codec_data[0] |= ((sample_rate_index >> 1) & 0x7);
10618 codec_data[1] = (sample_rate_index & 0x01) << 7;
10619 codec_data[1] |= (channels & 0xF) << 3;
10621 buf = gst_buffer_new_and_alloc (2);
10622 gst_buffer_fill (buf, 0, codec_data, 2);
10623 gst_caps_set_simple (stream->caps,
10624 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10625 gst_buffer_unref (buf);
10631 GST_INFO_OBJECT (qtdemux,
10632 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
10636 GST_INFO_OBJECT (qtdemux,
10637 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
10638 GST_FOURCC_ARGS (fourcc), stream->caps);
10640 } else if (stream->subtype == FOURCC_strm) {
10641 if (fourcc == FOURCC_rtsp) {
10642 stream->redirect_uri = qtdemux_get_rtsp_uri_from_hndl (qtdemux, minf);
10644 GST_INFO_OBJECT (qtdemux, "unhandled stream type %" GST_FOURCC_FORMAT,
10645 GST_FOURCC_ARGS (fourcc));
10646 goto unknown_stream;
10648 stream->sampled = TRUE;
10649 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
10650 || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt) {
10652 stream->sampled = TRUE;
10653 stream->sparse = TRUE;
10656 qtdemux_sub_caps (qtdemux, stream, fourcc, stsd_data, &codec);
10658 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
10659 GST_TAG_SUBTITLE_CODEC, codec, NULL);
10664 /* hunt for sort-of codec data */
10668 GNode *mp4s = NULL;
10669 GNode *esds = NULL;
10671 /* look for palette in a stsd->mp4s->esds sub-atom */
10672 mp4s = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4s);
10674 esds = qtdemux_tree_get_child_by_type (mp4s, FOURCC_esds);
10675 if (esds == NULL) {
10677 GST_LOG_OBJECT (qtdemux, "Skipping invalid stsd: no esds child");
10681 gst_qtdemux_handle_esds (qtdemux, stream, esds, stream->pending_tags);
10685 GST_INFO_OBJECT (qtdemux,
10686 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
10689 GST_INFO_OBJECT (qtdemux,
10690 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
10691 GST_FOURCC_ARGS (fourcc), stream->caps);
10693 /* everything in 1 sample */
10694 stream->sampled = TRUE;
10697 qtdemux_generic_caps (qtdemux, stream, fourcc, stsd_data, &codec);
10699 if (stream->caps == NULL)
10700 goto unknown_stream;
10703 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
10704 GST_TAG_SUBTITLE_CODEC, codec, NULL);
10710 /* promote to sampled format */
10711 if (stream->fourcc == FOURCC_samr) {
10712 /* force mono 8000 Hz for AMR */
10713 stream->sampled = TRUE;
10714 stream->n_channels = 1;
10715 stream->rate = 8000;
10716 } else if (stream->fourcc == FOURCC_sawb) {
10717 /* force mono 16000 Hz for AMR-WB */
10718 stream->sampled = TRUE;
10719 stream->n_channels = 1;
10720 stream->rate = 16000;
10721 } else if (stream->fourcc == FOURCC_mp4a) {
10722 stream->sampled = TRUE;
10725 /* collect sample information */
10726 if (!qtdemux_stbl_init (qtdemux, stream, stbl))
10727 goto samples_failed;
10729 if (qtdemux->fragmented) {
10732 /* need all moov samples as basis; probably not many if any at all */
10733 /* prevent moof parsing taking of at this time */
10734 offset = qtdemux->moof_offset;
10735 qtdemux->moof_offset = 0;
10736 if (stream->n_samples &&
10737 !qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
10738 qtdemux->moof_offset = offset;
10739 goto samples_failed;
10741 qtdemux->moof_offset = 0;
10742 /* movie duration more reliable in this case (e.g. mehd) */
10743 if (qtdemux->segment.duration &&
10744 GST_CLOCK_TIME_IS_VALID (qtdemux->segment.duration))
10746 GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->segment.duration);
10749 /* configure segments */
10750 if (!qtdemux_parse_segments (qtdemux, stream, trak))
10751 goto segments_failed;
10753 /* add some language tag, if useful */
10754 if (stream->lang_id[0] != '\0' && strcmp (stream->lang_id, "unk") &&
10755 strcmp (stream->lang_id, "und")) {
10756 const gchar *lang_code;
10758 /* convert ISO 639-2 code to ISO 639-1 */
10759 lang_code = gst_tag_get_language_code (stream->lang_id);
10760 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
10761 GST_TAG_LANGUAGE_CODE, (lang_code) ? lang_code : stream->lang_id, NULL);
10764 /* Check for UDTA tags */
10765 if ((udta = qtdemux_tree_get_child_by_type (trak, FOURCC_udta))) {
10766 qtdemux_parse_udta (qtdemux, stream->pending_tags, udta);
10769 /* now we are ready to add the stream */
10770 if (qtdemux->n_streams >= GST_QTDEMUX_MAX_STREAMS)
10771 goto too_many_streams;
10773 if (!qtdemux->got_moov) {
10774 qtdemux->streams[qtdemux->n_streams] = stream;
10775 qtdemux->n_streams++;
10776 GST_DEBUG_OBJECT (qtdemux, "n_streams is now %d", qtdemux->n_streams);
10784 GST_INFO_OBJECT (qtdemux, "skip disabled track");
10786 gst_qtdemux_stream_free (qtdemux, stream);
10791 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
10792 (_("This file is corrupt and cannot be played.")), (NULL));
10794 gst_qtdemux_stream_free (qtdemux, stream);
10799 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT, (NULL), (NULL));
10801 gst_qtdemux_stream_free (qtdemux, stream);
10807 /* we posted an error already */
10808 /* free stbl sub-atoms */
10809 gst_qtdemux_stbl_free (stream);
10811 gst_qtdemux_stream_free (qtdemux, stream);
10816 GST_INFO_OBJECT (qtdemux, "stream with track id %i already exists",
10819 gst_qtdemux_stream_free (qtdemux, stream);
10824 GST_INFO_OBJECT (qtdemux, "unknown subtype %" GST_FOURCC_FORMAT,
10825 GST_FOURCC_ARGS (stream->subtype));
10827 gst_qtdemux_stream_free (qtdemux, stream);
10832 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
10833 (_("This file contains too many streams. Only playing first %d"),
10834 GST_QTDEMUX_MAX_STREAMS), (NULL));
10839 /* If we can estimate the overall bitrate, and don't have information about the
10840 * stream bitrate for exactly one stream, this guesses the stream bitrate as
10841 * the overall bitrate minus the sum of the bitrates of all other streams. This
10842 * should be useful for the common case where we have one audio and one video
10843 * stream and can estimate the bitrate of one, but not the other. */
10845 gst_qtdemux_guess_bitrate (GstQTDemux * qtdemux)
10847 QtDemuxStream *stream = NULL;
10848 gint64 size, sys_bitrate, sum_bitrate = 0;
10849 GstClockTime duration;
10853 if (qtdemux->fragmented)
10856 GST_DEBUG_OBJECT (qtdemux, "Looking for streams with unknown bitrate");
10858 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &size)
10860 GST_DEBUG_OBJECT (qtdemux,
10861 "Size in bytes of the stream not known - bailing");
10865 /* Subtract the header size */
10866 GST_DEBUG_OBJECT (qtdemux, "Total size %" G_GINT64_FORMAT ", header size %u",
10867 size, qtdemux->header_size);
10869 if (size < qtdemux->header_size)
10872 size = size - qtdemux->header_size;
10874 if (!gst_qtdemux_get_duration (qtdemux, &duration)) {
10875 GST_DEBUG_OBJECT (qtdemux, "Stream duration not known - bailing");
10879 for (i = 0; i < qtdemux->n_streams; i++) {
10880 switch (qtdemux->streams[i]->subtype) {
10883 GST_DEBUG_OBJECT (qtdemux, "checking bitrate for %" GST_PTR_FORMAT,
10884 qtdemux->streams[i]->caps);
10885 /* retrieve bitrate, prefer avg then max */
10887 if (qtdemux->streams[i]->pending_tags) {
10888 gst_tag_list_get_uint (qtdemux->streams[i]->pending_tags,
10889 GST_TAG_MAXIMUM_BITRATE, &bitrate);
10890 GST_DEBUG_OBJECT (qtdemux, "max-bitrate: %u", bitrate);
10891 gst_tag_list_get_uint (qtdemux->streams[i]->pending_tags,
10892 GST_TAG_NOMINAL_BITRATE, &bitrate);
10893 GST_DEBUG_OBJECT (qtdemux, "nominal-bitrate: %u", bitrate);
10894 gst_tag_list_get_uint (qtdemux->streams[i]->pending_tags,
10895 GST_TAG_BITRATE, &bitrate);
10896 GST_DEBUG_OBJECT (qtdemux, "bitrate: %u", bitrate);
10899 sum_bitrate += bitrate;
10902 GST_DEBUG_OBJECT (qtdemux,
10903 ">1 stream with unknown bitrate - bailing");
10906 stream = qtdemux->streams[i];
10910 /* For other subtypes, we assume no significant impact on bitrate */
10916 GST_DEBUG_OBJECT (qtdemux, "All stream bitrates are known");
10920 sys_bitrate = gst_util_uint64_scale (size, GST_SECOND * 8, duration);
10922 if (sys_bitrate < sum_bitrate) {
10923 /* This can happen, since sum_bitrate might be derived from maximum
10924 * bitrates and not average bitrates */
10925 GST_DEBUG_OBJECT (qtdemux,
10926 "System bitrate less than sum bitrate - bailing");
10930 bitrate = sys_bitrate - sum_bitrate;
10931 GST_DEBUG_OBJECT (qtdemux, "System bitrate = %" G_GINT64_FORMAT
10932 ", Stream bitrate = %u", sys_bitrate, bitrate);
10934 if (!stream->pending_tags)
10935 stream->pending_tags = gst_tag_list_new_empty ();
10937 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
10938 GST_TAG_BITRATE, bitrate, NULL);
10941 static GstFlowReturn
10942 qtdemux_prepare_streams (GstQTDemux * qtdemux)
10945 GstFlowReturn ret = GST_FLOW_OK;
10947 GST_DEBUG_OBJECT (qtdemux, "prepare streams");
10949 for (i = 0; ret == GST_FLOW_OK && i < qtdemux->n_streams; i++) {
10950 QtDemuxStream *stream = qtdemux->streams[i];
10951 guint32 sample_num = 0;
10953 GST_DEBUG_OBJECT (qtdemux, "stream %d, id %d, fourcc %" GST_FOURCC_FORMAT,
10954 i, stream->track_id, GST_FOURCC_ARGS (stream->fourcc));
10956 if (qtdemux->fragmented) {
10957 /* need all moov samples first */
10958 GST_OBJECT_LOCK (qtdemux);
10959 while (stream->n_samples == 0)
10960 if ((ret = qtdemux_add_fragmented_samples (qtdemux)) != GST_FLOW_OK)
10962 GST_OBJECT_UNLOCK (qtdemux);
10964 /* discard any stray moof */
10965 qtdemux->moof_offset = 0;
10968 /* prepare braking */
10969 if (ret != GST_FLOW_ERROR)
10972 /* in pull mode, we should have parsed some sample info by now;
10973 * and quite some code will not handle no samples.
10974 * in push mode, we'll just have to deal with it */
10975 if (G_UNLIKELY (qtdemux->pullbased && !stream->n_samples)) {
10976 GST_DEBUG_OBJECT (qtdemux, "no samples for stream; discarding");
10977 gst_qtdemux_remove_stream (qtdemux, i);
10982 /* parse the initial sample for use in setting the frame rate cap */
10983 while (sample_num == 0 && sample_num < stream->n_samples) {
10984 if (!qtdemux_parse_samples (qtdemux, stream, sample_num))
10988 if (stream->n_samples > 0 && stream->stbl_index >= 0) {
10989 stream->first_duration = stream->samples[0].duration;
10990 GST_LOG_OBJECT (qtdemux, "stream %d first duration %u",
10991 stream->track_id, stream->first_duration);
10998 static GstFlowReturn
10999 qtdemux_expose_streams (GstQTDemux * qtdemux)
11002 GstFlowReturn ret = GST_FLOW_OK;
11003 GSList *oldpads = NULL;
11006 GST_DEBUG_OBJECT (qtdemux, "exposing streams");
11008 for (i = 0; ret == GST_FLOW_OK && i < qtdemux->n_streams; i++) {
11009 QtDemuxStream *stream = qtdemux->streams[i];
11010 GstPad *oldpad = stream->pad;
11013 GST_DEBUG_OBJECT (qtdemux, "stream %d, id %d, fourcc %" GST_FOURCC_FORMAT,
11014 i, stream->track_id, GST_FOURCC_ARGS (stream->fourcc));
11016 if ((stream->subtype == FOURCC_text || stream->subtype == FOURCC_sbtl) &&
11017 stream->track_id == qtdemux->chapters_track_id) {
11018 /* TODO - parse chapters track and expose it as GstToc; For now just ignore it
11019 so that it doesn't look like a subtitle track */
11020 gst_qtdemux_remove_stream (qtdemux, i);
11025 /* now we have all info and can expose */
11026 list = stream->pending_tags;
11027 stream->pending_tags = NULL;
11029 oldpads = g_slist_prepend (oldpads, oldpad);
11030 if (!gst_qtdemux_add_stream (qtdemux, stream, list))
11031 return GST_FLOW_ERROR;
11034 gst_qtdemux_guess_bitrate (qtdemux);
11036 gst_element_no_more_pads (GST_ELEMENT_CAST (qtdemux));
11038 for (iter = oldpads; iter; iter = g_slist_next (iter)) {
11039 GstPad *oldpad = iter->data;
11042 event = gst_event_new_eos ();
11043 if (qtdemux->segment_seqnum)
11044 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
11046 gst_pad_push_event (oldpad, event);
11047 gst_pad_set_active (oldpad, FALSE);
11048 gst_element_remove_pad (GST_ELEMENT (qtdemux), oldpad);
11049 gst_flow_combiner_remove_pad (qtdemux->flowcombiner, oldpad);
11050 gst_object_unref (oldpad);
11053 /* check if we should post a redirect in case there is a single trak
11054 * and it is a redirecting trak */
11055 if (qtdemux->n_streams == 1 && qtdemux->streams[0]->redirect_uri != NULL) {
11058 GST_INFO_OBJECT (qtdemux, "Issuing a redirect due to a single track with "
11059 "an external content");
11060 m = gst_message_new_element (GST_OBJECT_CAST (qtdemux),
11061 gst_structure_new ("redirect",
11062 "new-location", G_TYPE_STRING, qtdemux->streams[0]->redirect_uri,
11064 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), m);
11065 qtdemux->posted_redirect = TRUE;
11068 for (i = 0; i < qtdemux->n_streams; i++) {
11069 QtDemuxStream *stream = qtdemux->streams[i];
11071 qtdemux_do_allocation (qtdemux, stream);
11074 qtdemux->exposed = TRUE;
11078 /* check if major or compatible brand is 3GP */
11079 static inline gboolean
11080 qtdemux_is_brand_3gp (GstQTDemux * qtdemux, gboolean major)
11083 return ((qtdemux->major_brand & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
11085 } else if (qtdemux->comp_brands != NULL) {
11089 gboolean res = FALSE;
11091 gst_buffer_map (qtdemux->comp_brands, &map, GST_MAP_READ);
11094 while (size >= 4) {
11095 res = res || ((QT_FOURCC (data) & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
11100 gst_buffer_unmap (qtdemux->comp_brands, &map);
11107 /* check if tag is a spec'ed 3GP tag keyword storing a string */
11108 static inline gboolean
11109 qtdemux_is_string_tag_3gp (GstQTDemux * qtdemux, guint32 fourcc)
11111 return fourcc == FOURCC_cprt || fourcc == FOURCC_gnre || fourcc == FOURCC_titl
11112 || fourcc == FOURCC_dscp || fourcc == FOURCC_perf || fourcc == FOURCC_auth
11113 || fourcc == FOURCC_albm;
11117 qtdemux_tag_add_location (GstQTDemux * qtdemux, GstTagList * taglist,
11118 const char *tag, const char *dummy, GNode * node)
11120 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
11124 gdouble longitude, latitude, altitude;
11127 len = QT_UINT32 (node->data);
11134 /* TODO: language code skipped */
11136 name = gst_tag_freeform_string_to_utf8 (data + offset, -1, env_vars);
11139 /* do not alarm in trivial case, but bail out otherwise */
11140 if (*(data + offset) != 0) {
11141 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8, "
11145 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
11146 GST_TAG_GEO_LOCATION_NAME, name, NULL);
11147 offset += strlen (name);
11151 if (len < offset + 2 + 4 + 4 + 4)
11154 /* +1 +1 = skip null-terminator and location role byte */
11156 /* table in spec says unsigned, semantics say negative has meaning ... */
11157 longitude = QT_SFP32 (data + offset);
11160 latitude = QT_SFP32 (data + offset);
11163 altitude = QT_SFP32 (data + offset);
11165 /* one invalid means all are invalid */
11166 if (longitude >= -180.0 && longitude <= 180.0 &&
11167 latitude >= -90.0 && latitude <= 90.0) {
11168 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
11169 GST_TAG_GEO_LOCATION_LATITUDE, latitude,
11170 GST_TAG_GEO_LOCATION_LONGITUDE, longitude,
11171 GST_TAG_GEO_LOCATION_ELEVATION, altitude, NULL);
11174 /* TODO: no GST_TAG_, so astronomical body and additional notes skipped */
11181 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP location");
11188 qtdemux_tag_add_year (GstQTDemux * qtdemux, GstTagList * taglist,
11189 const char *tag, const char *dummy, GNode * node)
11195 len = QT_UINT32 (node->data);
11199 y = QT_UINT16 ((guint8 *) node->data + 12);
11201 GST_DEBUG_OBJECT (qtdemux, "year: %u is not a valid year", y);
11204 GST_DEBUG_OBJECT (qtdemux, "year: %u", y);
11206 date = g_date_new_dmy (1, 1, y);
11207 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, date, NULL);
11208 g_date_free (date);
11212 qtdemux_tag_add_classification (GstQTDemux * qtdemux, GstTagList * taglist,
11213 const char *tag, const char *dummy, GNode * node)
11216 char *tag_str = NULL;
11221 len = QT_UINT32 (node->data);
11226 entity = (guint8 *) node->data + offset;
11227 if (entity[0] == 0 || entity[1] == 0 || entity[2] == 0 || entity[3] == 0) {
11228 GST_DEBUG_OBJECT (qtdemux,
11229 "classification info: %c%c%c%c invalid classification entity",
11230 entity[0], entity[1], entity[2], entity[3]);
11235 table = QT_UINT16 ((guint8 *) node->data + offset);
11237 /* Language code skipped */
11241 /* Tag format: "XXXX://Y[YYYY]/classification info string"
11242 * XXXX: classification entity, fixed length 4 chars.
11243 * Y[YYYY]: classification table, max 5 chars.
11245 tag_str = g_strdup_printf ("----://%u/%s",
11246 table, (char *) node->data + offset);
11248 /* memcpy To be sure we're preserving byte order */
11249 memcpy (tag_str, entity, 4);
11250 GST_DEBUG_OBJECT (qtdemux, "classification info: %s", tag_str);
11252 gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND, tag, tag_str, NULL);
11261 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP classification");
11267 qtdemux_tag_add_str_full (GstQTDemux * qtdemux, GstTagList * taglist,
11268 const char *tag, const char *dummy, GNode * node)
11270 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
11276 gboolean ret = TRUE;
11277 const gchar *charset = NULL;
11279 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
11281 len = QT_UINT32 (data->data);
11282 type = QT_UINT32 ((guint8 *) data->data + 8);
11283 if (type == 0x00000001 && len > 16) {
11284 s = gst_tag_freeform_string_to_utf8 ((char *) data->data + 16, len - 16,
11287 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
11288 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, s, NULL);
11291 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
11295 len = QT_UINT32 (node->data);
11296 type = QT_UINT32 ((guint8 *) node->data + 4);
11297 if ((type >> 24) == 0xa9) {
11301 /* Type starts with the (C) symbol, so the next data is a list
11302 * of (string size(16), language code(16), string) */
11304 str_len = QT_UINT16 ((guint8 *) node->data + 8);
11305 lang_code = QT_UINT16 ((guint8 *) node->data + 10);
11307 /* the string + fourcc + size + 2 16bit fields,
11308 * means that there are more tags in this atom */
11309 if (len > str_len + 8 + 4) {
11310 /* TODO how to represent the same tag in different languages? */
11311 GST_WARNING_OBJECT (qtdemux, "Ignoring metadata entry with multiple "
11312 "text alternatives, reading only first one");
11316 len = str_len + 8 + 4; /* remove trailing strings that we don't use */
11317 GST_DEBUG_OBJECT (qtdemux, "found international text tag");
11319 if (lang_code < 0x800) { /* MAC encoded string */
11322 } else if (len > 14 && qtdemux_is_string_tag_3gp (qtdemux,
11323 QT_FOURCC ((guint8 *) node->data + 4))) {
11324 guint32 type = QT_UINT32 ((guint8 *) node->data + 8);
11326 /* we go for 3GP style encoding if major brands claims so,
11327 * or if no hope for data be ok UTF-8, and compatible 3GP brand present */
11328 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
11329 (qtdemux_is_brand_3gp (qtdemux, FALSE) &&
11330 ((type & 0x00FFFFFF) == 0x0) && (type >> 24 <= 0xF))) {
11332 /* 16-bit Language code is ignored here as well */
11333 GST_DEBUG_OBJECT (qtdemux, "found 3gpp text tag");
11340 GST_DEBUG_OBJECT (qtdemux, "found normal text tag");
11341 ret = FALSE; /* may have to fallback */
11344 GError *err = NULL;
11346 s = g_convert ((gchar *) node->data + offset, len - offset, "utf8",
11347 charset, NULL, NULL, &err);
11349 GST_DEBUG_OBJECT (qtdemux, "Failed to convert string from charset %s:"
11350 " %s(%d): %s", charset, g_quark_to_string (err->domain), err->code,
11352 g_error_free (err);
11355 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
11356 len - offset, env_vars);
11359 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
11360 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, s, NULL);
11364 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
11371 qtdemux_tag_add_str (GstQTDemux * qtdemux, GstTagList * taglist,
11372 const char *tag, const char *dummy, GNode * node)
11374 qtdemux_tag_add_str_full (qtdemux, taglist, tag, dummy, node);
11378 qtdemux_tag_add_keywords (GstQTDemux * qtdemux, GstTagList * taglist,
11379 const char *tag, const char *dummy, GNode * node)
11381 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
11383 char *s, *t, *k = NULL;
11388 /* first try normal string tag if major brand not 3GP */
11389 if (!qtdemux_is_brand_3gp (qtdemux, TRUE)) {
11390 if (!qtdemux_tag_add_str_full (qtdemux, taglist, tag, dummy, node)) {
11391 /* hm, that did not work, maybe 3gpp storage in non-3gpp major brand;
11392 * let's try it 3gpp way after minor safety check */
11394 if (QT_UINT32 (data) < 15 || !qtdemux_is_brand_3gp (qtdemux, FALSE))
11400 GST_DEBUG_OBJECT (qtdemux, "found 3gpp keyword tag");
11404 len = QT_UINT32 (data);
11408 count = QT_UINT8 (data + 14);
11410 for (; count; count--) {
11413 if (offset + 1 > len)
11415 slen = QT_UINT8 (data + offset);
11417 if (offset + slen > len)
11419 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
11422 GST_DEBUG_OBJECT (qtdemux, "adding keyword %s", GST_STR_NULL (s));
11424 t = g_strjoin (",", k, s, NULL);
11432 GST_DEBUG_OBJECT (qtdemux, "failed to convert keyword to UTF-8");
11439 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (k));
11440 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, k, NULL);
11449 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP keywords");
11455 qtdemux_tag_add_num (GstQTDemux * qtdemux, GstTagList * taglist,
11456 const char *tag1, const char *tag2, GNode * node)
11463 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
11465 len = QT_UINT32 (data->data);
11466 type = QT_UINT32 ((guint8 *) data->data + 8);
11467 if (type == 0x00000000 && len >= 22) {
11468 n1 = QT_UINT16 ((guint8 *) data->data + 18);
11469 n2 = QT_UINT16 ((guint8 *) data->data + 20);
11471 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag1, n1);
11472 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, n1, NULL);
11475 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag2, n2);
11476 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag2, n2, NULL);
11483 qtdemux_tag_add_tmpo (GstQTDemux * qtdemux, GstTagList * taglist,
11484 const char *tag1, const char *dummy, GNode * node)
11491 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
11493 len = QT_UINT32 (data->data);
11494 type = QT_UINT32 ((guint8 *) data->data + 8);
11495 GST_DEBUG_OBJECT (qtdemux, "have tempo tag, type=%d,len=%d", type, len);
11496 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
11497 if ((type == 0x00000015 || type == 0x0000000f) && len >= 18) {
11498 n1 = QT_UINT16 ((guint8 *) data->data + 16);
11500 /* do not add bpm=0 */
11501 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", n1);
11502 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, (gdouble) n1,
11510 qtdemux_tag_add_uint32 (GstQTDemux * qtdemux, GstTagList * taglist,
11511 const char *tag1, const char *dummy, GNode * node)
11518 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
11520 len = QT_UINT32 (data->data);
11521 type = QT_UINT32 ((guint8 *) data->data + 8);
11522 GST_DEBUG_OBJECT (qtdemux, "have %s tag, type=%d,len=%d", tag1, type, len);
11523 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
11524 if ((type == 0x00000015 || type == 0x0000000f) && len >= 20) {
11525 num = QT_UINT32 ((guint8 *) data->data + 16);
11527 /* do not add num=0 */
11528 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", num);
11529 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, num, NULL);
11536 qtdemux_tag_add_covr (GstQTDemux * qtdemux, GstTagList * taglist,
11537 const char *tag1, const char *dummy, GNode * node)
11544 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
11546 len = QT_UINT32 (data->data);
11547 type = QT_UINT32 ((guint8 *) data->data + 8);
11548 GST_DEBUG_OBJECT (qtdemux, "have covr tag, type=%d,len=%d", type, len);
11549 if ((type == 0x0000000d || type == 0x0000000e) && len > 16) {
11551 gst_tag_image_data_to_image_sample ((guint8 *) data->data + 16,
11552 len - 16, GST_TAG_IMAGE_TYPE_NONE))) {
11553 GST_DEBUG_OBJECT (qtdemux, "adding tag size %d", len - 16);
11554 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, sample, NULL);
11555 gst_sample_unref (sample);
11562 qtdemux_tag_add_date (GstQTDemux * qtdemux, GstTagList * taglist,
11563 const char *tag, const char *dummy, GNode * node)
11570 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
11572 len = QT_UINT32 (data->data);
11573 type = QT_UINT32 ((guint8 *) data->data + 8);
11574 if (type == 0x00000001 && len > 16) {
11575 guint y, m = 1, d = 1;
11578 s = g_strndup ((char *) data->data + 16, len - 16);
11579 GST_DEBUG_OBJECT (qtdemux, "adding date '%s'", s);
11580 ret = sscanf (s, "%u-%u-%u", &y, &m, &d);
11581 if (ret >= 1 && y > 1500 && y < 3000) {
11584 date = g_date_new_dmy (d, m, y);
11585 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, date, NULL);
11586 g_date_free (date);
11588 GST_DEBUG_OBJECT (qtdemux, "could not parse date string '%s'", s);
11596 qtdemux_tag_add_gnre (GstQTDemux * qtdemux, GstTagList * taglist,
11597 const char *tag, const char *dummy, GNode * node)
11601 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
11603 /* re-route to normal string tag if major brand says so
11604 * or no data atom and compatible brand suggests so */
11605 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
11606 (qtdemux_is_brand_3gp (qtdemux, FALSE) && !data)) {
11607 qtdemux_tag_add_str (qtdemux, taglist, tag, dummy, node);
11612 guint len, type, n;
11614 len = QT_UINT32 (data->data);
11615 type = QT_UINT32 ((guint8 *) data->data + 8);
11616 if (type == 0x00000000 && len >= 18) {
11617 n = QT_UINT16 ((guint8 *) data->data + 16);
11619 const gchar *genre;
11621 genre = gst_tag_id3_genre_get (n - 1);
11622 if (genre != NULL) {
11623 GST_DEBUG_OBJECT (qtdemux, "adding %d [%s]", n, genre);
11624 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, genre, NULL);
11632 qtdemux_add_double_tag_from_str (GstQTDemux * demux, GstTagList * taglist,
11633 const gchar * tag, guint8 * data, guint32 datasize)
11638 /* make a copy to have \0 at the end */
11639 datacopy = g_strndup ((gchar *) data, datasize);
11641 /* convert the str to double */
11642 if (sscanf (datacopy, "%lf", &value) == 1) {
11643 GST_DEBUG_OBJECT (demux, "adding tag: %s [%s]", tag, datacopy);
11644 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, value, NULL);
11646 GST_WARNING_OBJECT (demux, "Failed to parse double from string: %s",
11654 qtdemux_tag_add_revdns (GstQTDemux * demux, GstTagList * taglist,
11655 const char *tag, const char *tag_bis, GNode * node)
11664 const gchar *meanstr;
11665 const gchar *namestr;
11667 /* checking the whole ---- atom size for consistency */
11668 if (QT_UINT32 (node->data) <= 4 + 12 + 12 + 16) {
11669 GST_WARNING_OBJECT (demux, "Tag ---- atom is too small, ignoring");
11673 mean = qtdemux_tree_get_child_by_type (node, FOURCC_mean);
11675 GST_WARNING_OBJECT (demux, "No 'mean' atom found");
11679 meansize = QT_UINT32 (mean->data);
11680 if (meansize <= 12) {
11681 GST_WARNING_OBJECT (demux, "Small mean atom, ignoring the whole tag");
11684 meanstr = ((gchar *) mean->data) + 12;
11687 name = qtdemux_tree_get_child_by_type (node, FOURCC_name);
11689 GST_WARNING_OBJECT (demux, "'name' atom not found, ignoring tag");
11693 namesize = QT_UINT32 (name->data);
11694 if (namesize <= 12) {
11695 GST_WARNING_OBJECT (demux, "'name' atom is too small, ignoring tag");
11698 namestr = ((gchar *) name->data) + 12;
11706 * uint24 - data type
11710 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
11712 GST_WARNING_OBJECT (demux, "No data atom in this tag");
11715 datasize = QT_UINT32 (data->data);
11716 if (datasize <= 16) {
11717 GST_WARNING_OBJECT (demux, "Data atom too small");
11720 datatype = QT_UINT32 (((gchar *) data->data) + 8) & 0xFFFFFF;
11722 if ((strncmp (meanstr, "com.apple.iTunes", meansize) == 0) ||
11723 (strncmp (meanstr, "org.hydrogenaudio.replaygain", meansize) == 0)) {
11724 static const struct
11726 const gchar name[28];
11727 const gchar tag[28];
11730 "replaygain_track_gain", GST_TAG_TRACK_GAIN}, {
11731 "replaygain_track_peak", GST_TAG_TRACK_PEAK}, {
11732 "replaygain_album_gain", GST_TAG_ALBUM_GAIN}, {
11733 "replaygain_album_peak", GST_TAG_ALBUM_PEAK}, {
11734 "MusicBrainz Track Id", GST_TAG_MUSICBRAINZ_TRACKID}, {
11735 "MusicBrainz Artist Id", GST_TAG_MUSICBRAINZ_ARTISTID}, {
11736 "MusicBrainz Album Id", GST_TAG_MUSICBRAINZ_ALBUMID}, {
11737 "MusicBrainz Album Artist Id", GST_TAG_MUSICBRAINZ_ALBUMARTISTID}
11741 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
11742 if (!g_ascii_strncasecmp (tags[i].name, namestr, namesize)) {
11743 switch (gst_tag_get_type (tags[i].tag)) {
11744 case G_TYPE_DOUBLE:
11745 qtdemux_add_double_tag_from_str (demux, taglist, tags[i].tag,
11746 ((guint8 *) data->data) + 16, datasize - 16);
11748 case G_TYPE_STRING:
11749 qtdemux_tag_add_str (demux, taglist, tags[i].tag, NULL, node);
11758 if (i == G_N_ELEMENTS (tags))
11768 #ifndef GST_DISABLE_GST_DEBUG
11770 gchar *namestr_dbg;
11771 gchar *meanstr_dbg;
11773 meanstr_dbg = g_strndup (meanstr, meansize);
11774 namestr_dbg = g_strndup (namestr, namesize);
11776 GST_WARNING_OBJECT (demux, "This tag %s:%s type:%u is not mapped, "
11777 "file a bug at bugzilla.gnome.org", meanstr_dbg, namestr_dbg, datatype);
11779 g_free (namestr_dbg);
11780 g_free (meanstr_dbg);
11787 qtdemux_tag_add_id32 (GstQTDemux * demux, GstTagList * taglist, const char *tag,
11788 const char *tag_bis, GNode * node)
11793 GstTagList *id32_taglist = NULL;
11795 GST_LOG_OBJECT (demux, "parsing ID32");
11798 len = GST_READ_UINT32_BE (data);
11800 /* need at least full box and language tag */
11804 buf = gst_buffer_new_allocate (NULL, len - 14, NULL);
11805 gst_buffer_fill (buf, 0, data + 14, len - 14);
11807 id32_taglist = gst_tag_list_from_id3v2_tag (buf);
11808 if (id32_taglist) {
11809 GST_LOG_OBJECT (demux, "parsing ok");
11810 gst_tag_list_insert (taglist, id32_taglist, GST_TAG_MERGE_KEEP);
11811 gst_tag_list_unref (id32_taglist);
11813 GST_LOG_OBJECT (demux, "parsing failed");
11816 gst_buffer_unref (buf);
11819 typedef void (*GstQTDemuxAddTagFunc) (GstQTDemux * demux, GstTagList * taglist,
11820 const char *tag, const char *tag_bis, GNode * node);
11823 FOURCC_pcst -> if media is a podcast -> bool
11824 FOURCC_cpil -> if media is part of a compilation -> bool
11825 FOURCC_pgap -> if media is part of a gapless context -> bool
11826 FOURCC_tven -> the tv episode id e.g. S01E23 -> str
11829 static const struct
11832 const gchar *gst_tag;
11833 const gchar *gst_tag_bis;
11834 const GstQTDemuxAddTagFunc func;
11837 FOURCC__nam, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
11838 FOURCC_titl, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
11839 FOURCC__grp, GST_TAG_GROUPING, NULL, qtdemux_tag_add_str}, {
11840 FOURCC__wrt, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
11841 FOURCC__ART, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
11842 FOURCC_aART, GST_TAG_ALBUM_ARTIST, NULL, qtdemux_tag_add_str}, {
11843 FOURCC_perf, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
11844 FOURCC_auth, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
11845 FOURCC__alb, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
11846 FOURCC_albm, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
11847 FOURCC_cprt, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
11848 FOURCC__cpy, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
11849 FOURCC__cmt, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
11850 FOURCC__des, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
11851 FOURCC_desc, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
11852 FOURCC_dscp, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
11853 FOURCC__lyr, GST_TAG_LYRICS, NULL, qtdemux_tag_add_str}, {
11854 FOURCC__day, GST_TAG_DATE, NULL, qtdemux_tag_add_date}, {
11855 FOURCC_yrrc, GST_TAG_DATE, NULL, qtdemux_tag_add_year}, {
11856 FOURCC__too, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
11857 FOURCC__inf, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
11858 FOURCC_trkn, GST_TAG_TRACK_NUMBER, GST_TAG_TRACK_COUNT, qtdemux_tag_add_num}, {
11859 FOURCC_disk, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
11860 qtdemux_tag_add_num}, {
11861 FOURCC_disc, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
11862 qtdemux_tag_add_num}, {
11863 FOURCC__gen, GST_TAG_GENRE, NULL, qtdemux_tag_add_str}, {
11864 FOURCC_gnre, GST_TAG_GENRE, NULL, qtdemux_tag_add_gnre}, {
11865 FOURCC_tmpo, GST_TAG_BEATS_PER_MINUTE, NULL, qtdemux_tag_add_tmpo}, {
11866 FOURCC_covr, GST_TAG_PREVIEW_IMAGE, NULL, qtdemux_tag_add_covr}, {
11867 FOURCC_sonm, GST_TAG_TITLE_SORTNAME, NULL, qtdemux_tag_add_str}, {
11868 FOURCC_soal, GST_TAG_ALBUM_SORTNAME, NULL, qtdemux_tag_add_str}, {
11869 FOURCC_soar, GST_TAG_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
11870 FOURCC_soaa, GST_TAG_ALBUM_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
11871 FOURCC_soco, GST_TAG_COMPOSER_SORTNAME, NULL, qtdemux_tag_add_str}, {
11872 FOURCC_sosn, GST_TAG_SHOW_SORTNAME, NULL, qtdemux_tag_add_str}, {
11873 FOURCC_tvsh, GST_TAG_SHOW_NAME, NULL, qtdemux_tag_add_str}, {
11874 FOURCC_tvsn, GST_TAG_SHOW_SEASON_NUMBER, NULL, qtdemux_tag_add_uint32}, {
11875 FOURCC_tves, GST_TAG_SHOW_EPISODE_NUMBER, NULL, qtdemux_tag_add_uint32}, {
11876 FOURCC_kywd, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_keywords}, {
11877 FOURCC_keyw, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_str}, {
11878 FOURCC__enc, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
11879 FOURCC_loci, GST_TAG_GEO_LOCATION_NAME, NULL, qtdemux_tag_add_location}, {
11880 FOURCC_clsf, GST_QT_DEMUX_CLASSIFICATION_TAG, NULL,
11881 qtdemux_tag_add_classification}, {
11882 FOURCC__mak, GST_TAG_DEVICE_MANUFACTURER, NULL, qtdemux_tag_add_str}, {
11883 FOURCC__mod, GST_TAG_DEVICE_MODEL, NULL, qtdemux_tag_add_str}, {
11884 FOURCC__swr, GST_TAG_APPLICATION_NAME, NULL, qtdemux_tag_add_str}, {
11886 /* This is a special case, some tags are stored in this
11887 * 'reverse dns naming', according to:
11888 * http://atomicparsley.sourceforge.net/mpeg-4files.html and
11891 FOURCC_____, "", NULL, qtdemux_tag_add_revdns}, {
11892 /* see http://www.mp4ra.org/specs.html for ID32 in meta box */
11893 FOURCC_ID32, "", NULL, qtdemux_tag_add_id32}
11896 struct _GstQtDemuxTagList
11899 GstTagList *taglist;
11901 typedef struct _GstQtDemuxTagList GstQtDemuxTagList;
11904 qtdemux_tag_add_blob (GNode * node, GstQtDemuxTagList * qtdemuxtaglist)
11910 const gchar *style;
11915 GstQTDemux *demux = qtdemuxtaglist->demux;
11916 GstTagList *taglist = qtdemuxtaglist->taglist;
11919 len = QT_UINT32 (data);
11920 buf = gst_buffer_new_and_alloc (len);
11921 gst_buffer_fill (buf, 0, data, len);
11923 /* heuristic to determine style of tag */
11924 if (QT_FOURCC (data + 4) == FOURCC_____ ||
11925 (len > 8 + 12 && QT_FOURCC (data + 12) == FOURCC_data))
11927 else if (demux->major_brand == FOURCC_qt__)
11928 style = "quicktime";
11929 /* fall back to assuming iso/3gp tag style */
11933 /* santize the name for the caps. */
11934 for (i = 0; i < 4; i++) {
11935 guint8 d = data[4 + i];
11936 if (g_ascii_isalnum (d))
11937 ndata[i] = g_ascii_tolower (d);
11942 media_type = g_strdup_printf ("application/x-gst-qt-%c%c%c%c-tag",
11943 ndata[0], ndata[1], ndata[2], ndata[3]);
11944 GST_DEBUG_OBJECT (demux, "media type %s", media_type);
11946 s = gst_structure_new (media_type, "style", G_TYPE_STRING, style, NULL);
11947 sample = gst_sample_new (buf, NULL, NULL, s);
11948 gst_buffer_unref (buf);
11949 g_free (media_type);
11951 GST_DEBUG_OBJECT (demux, "adding private tag; size %d, info %" GST_PTR_FORMAT,
11954 gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND,
11955 GST_QT_DEMUX_PRIVATE_TAG, sample, NULL);
11957 gst_sample_unref (sample);
11961 qtdemux_parse_udta (GstQTDemux * qtdemux, GstTagList * taglist, GNode * udta)
11968 GstQtDemuxTagList demuxtaglist;
11970 demuxtaglist.demux = qtdemux;
11971 demuxtaglist.taglist = taglist;
11973 meta = qtdemux_tree_get_child_by_type (udta, FOURCC_meta);
11974 if (meta != NULL) {
11975 ilst = qtdemux_tree_get_child_by_type (meta, FOURCC_ilst);
11976 if (ilst == NULL) {
11977 GST_LOG_OBJECT (qtdemux, "no ilst");
11982 GST_LOG_OBJECT (qtdemux, "no meta so using udta itself");
11986 while (i < G_N_ELEMENTS (add_funcs)) {
11987 node = qtdemux_tree_get_child_by_type (ilst, add_funcs[i].fourcc);
11991 len = QT_UINT32 (node->data);
11993 GST_DEBUG_OBJECT (qtdemux, "too small tag atom %" GST_FOURCC_FORMAT,
11994 GST_FOURCC_ARGS (add_funcs[i].fourcc));
11996 add_funcs[i].func (qtdemux, taglist, add_funcs[i].gst_tag,
11997 add_funcs[i].gst_tag_bis, node);
11999 g_node_destroy (node);
12005 /* parsed nodes have been removed, pass along remainder as blob */
12006 g_node_children_foreach (ilst, G_TRAVERSE_ALL,
12007 (GNodeForeachFunc) qtdemux_tag_add_blob, &demuxtaglist);
12009 /* parse up XMP_ node if existing */
12010 xmp_ = qtdemux_tree_get_child_by_type (udta, FOURCC_XMP_);
12011 if (xmp_ != NULL) {
12013 GstTagList *xmptaglist;
12015 buf = _gst_buffer_new_wrapped (((guint8 *) xmp_->data) + 8,
12016 QT_UINT32 ((guint8 *) xmp_->data) - 8, NULL);
12017 xmptaglist = gst_tag_list_from_xmp_buffer (buf);
12018 gst_buffer_unref (buf);
12020 qtdemux_handle_xmp_taglist (qtdemux, taglist, xmptaglist);
12022 GST_DEBUG_OBJECT (qtdemux, "No XMP_ node found");
12028 GstStructure *structure; /* helper for sort function */
12030 guint min_req_bitrate;
12031 guint min_req_qt_version;
12035 qtdemux_redirects_sort_func (gconstpointer a, gconstpointer b)
12037 GstQtReference *ref_a = (GstQtReference *) a;
12038 GstQtReference *ref_b = (GstQtReference *) b;
12040 if (ref_b->min_req_qt_version != ref_a->min_req_qt_version)
12041 return ref_b->min_req_qt_version - ref_a->min_req_qt_version;
12043 /* known bitrates go before unknown; higher bitrates go first */
12044 return ref_b->min_req_bitrate - ref_a->min_req_bitrate;
12047 /* sort the redirects and post a message for the application.
12050 qtdemux_process_redirects (GstQTDemux * qtdemux, GList * references)
12052 GstQtReference *best;
12055 GValue list_val = { 0, };
12058 g_assert (references != NULL);
12060 references = g_list_sort (references, qtdemux_redirects_sort_func);
12062 best = (GstQtReference *) references->data;
12064 g_value_init (&list_val, GST_TYPE_LIST);
12066 for (l = references; l != NULL; l = l->next) {
12067 GstQtReference *ref = (GstQtReference *) l->data;
12068 GValue struct_val = { 0, };
12070 ref->structure = gst_structure_new ("redirect",
12071 "new-location", G_TYPE_STRING, ref->location, NULL);
12073 if (ref->min_req_bitrate > 0) {
12074 gst_structure_set (ref->structure, "minimum-bitrate", G_TYPE_INT,
12075 ref->min_req_bitrate, NULL);
12078 g_value_init (&struct_val, GST_TYPE_STRUCTURE);
12079 g_value_set_boxed (&struct_val, ref->structure);
12080 gst_value_list_append_value (&list_val, &struct_val);
12081 g_value_unset (&struct_val);
12082 /* don't free anything here yet, since we need best->structure below */
12085 g_assert (best != NULL);
12086 s = gst_structure_copy (best->structure);
12088 if (g_list_length (references) > 1) {
12089 gst_structure_set_value (s, "locations", &list_val);
12092 g_value_unset (&list_val);
12094 for (l = references; l != NULL; l = l->next) {
12095 GstQtReference *ref = (GstQtReference *) l->data;
12097 gst_structure_free (ref->structure);
12098 g_free (ref->location);
12101 g_list_free (references);
12103 GST_INFO_OBJECT (qtdemux, "posting redirect message: %" GST_PTR_FORMAT, s);
12104 msg = gst_message_new_element (GST_OBJECT_CAST (qtdemux), s);
12105 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
12106 qtdemux->posted_redirect = TRUE;
12109 /* look for redirect nodes, collect all redirect information and
12113 qtdemux_parse_redirects (GstQTDemux * qtdemux)
12115 GNode *rmra, *rmda, *rdrf;
12117 rmra = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_rmra);
12119 GList *redirects = NULL;
12121 rmda = qtdemux_tree_get_child_by_type (rmra, FOURCC_rmda);
12123 GstQtReference ref = { NULL, NULL, 0, 0 };
12124 GNode *rmdr, *rmvc;
12126 if ((rmdr = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmdr))) {
12127 ref.min_req_bitrate = QT_UINT32 ((guint8 *) rmdr->data + 12);
12128 GST_LOG_OBJECT (qtdemux, "data rate atom, required bitrate = %u",
12129 ref.min_req_bitrate);
12132 if ((rmvc = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmvc))) {
12133 guint32 package = QT_FOURCC ((guint8 *) rmvc->data + 12);
12134 guint version = QT_UINT32 ((guint8 *) rmvc->data + 16);
12136 #ifndef GST_DISABLE_GST_DEBUG
12137 guint bitmask = QT_UINT32 ((guint8 *) rmvc->data + 20);
12139 guint check_type = QT_UINT16 ((guint8 *) rmvc->data + 24);
12141 GST_LOG_OBJECT (qtdemux,
12142 "version check atom [%" GST_FOURCC_FORMAT "], version=0x%08x"
12143 ", mask=%08x, check_type=%u", GST_FOURCC_ARGS (package), version,
12144 bitmask, check_type);
12145 if (package == FOURCC_qtim && check_type == 0) {
12146 ref.min_req_qt_version = version;
12150 rdrf = qtdemux_tree_get_child_by_type (rmda, FOURCC_rdrf);
12156 ref_len = QT_UINT32 ((guint8 *) rdrf->data);
12157 if (ref_len > 20) {
12158 ref_type = QT_FOURCC ((guint8 *) rdrf->data + 12);
12159 ref_data = (guint8 *) rdrf->data + 20;
12160 if (ref_type == FOURCC_alis) {
12161 guint record_len, record_version, fn_len;
12163 if (ref_len > 70) {
12164 /* MacOSX alias record, google for alias-layout.txt */
12165 record_len = QT_UINT16 (ref_data + 4);
12166 record_version = QT_UINT16 (ref_data + 4 + 2);
12167 fn_len = QT_UINT8 (ref_data + 50);
12168 if (record_len > 50 && record_version == 2 && fn_len > 0) {
12169 ref.location = g_strndup ((gchar *) ref_data + 51, fn_len);
12172 GST_WARNING_OBJECT (qtdemux, "Invalid rdrf/alis size (%u < 70)",
12175 } else if (ref_type == FOURCC_url_) {
12176 ref.location = g_strndup ((gchar *) ref_data, ref_len - 8);
12178 GST_DEBUG_OBJECT (qtdemux,
12179 "unknown rdrf reference type %" GST_FOURCC_FORMAT,
12180 GST_FOURCC_ARGS (ref_type));
12182 if (ref.location != NULL) {
12183 GST_INFO_OBJECT (qtdemux, "New location: %s", ref.location);
12185 g_list_prepend (redirects, g_memdup (&ref, sizeof (ref)));
12187 GST_WARNING_OBJECT (qtdemux,
12188 "Failed to extract redirect location from rdrf atom");
12191 GST_WARNING_OBJECT (qtdemux, "Invalid rdrf size (%u < 20)", ref_len);
12195 /* look for others */
12196 rmda = qtdemux_tree_get_sibling_by_type (rmda, FOURCC_rmda);
12199 if (redirects != NULL) {
12200 qtdemux_process_redirects (qtdemux, redirects);
12206 static GstTagList *
12207 qtdemux_add_container_format (GstQTDemux * qtdemux, GstTagList * tags)
12211 if (tags == NULL) {
12212 tags = gst_tag_list_new_empty ();
12213 gst_tag_list_set_scope (tags, GST_TAG_SCOPE_GLOBAL);
12216 if (qtdemux->major_brand == FOURCC_mjp2)
12217 fmt = "Motion JPEG 2000";
12218 else if ((qtdemux->major_brand & 0xffff) == FOURCC_3g__)
12220 else if (qtdemux->major_brand == FOURCC_qt__)
12222 else if (qtdemux->fragmented)
12225 fmt = "ISO MP4/M4A";
12227 GST_LOG_OBJECT (qtdemux, "mapped %" GST_FOURCC_FORMAT " to '%s'",
12228 GST_FOURCC_ARGS (qtdemux->major_brand), fmt);
12230 gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_CONTAINER_FORMAT,
12236 /* we have read the complete moov node now.
12237 * This function parses all of the relevant info, creates the traks and
12238 * prepares all data structures for playback
12241 qtdemux_parse_tree (GstQTDemux * qtdemux)
12247 GstClockTime duration;
12249 guint64 creation_time;
12250 GstDateTime *datetime = NULL;
12253 /* make sure we have a usable taglist */
12254 if (!qtdemux->tag_list) {
12255 qtdemux->tag_list = gst_tag_list_new_empty ();
12256 gst_tag_list_set_scope (qtdemux->tag_list, GST_TAG_SCOPE_GLOBAL);
12258 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
12261 mvhd = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvhd);
12262 if (mvhd == NULL) {
12263 GST_LOG_OBJECT (qtdemux, "No mvhd node found, looking for redirects.");
12264 return qtdemux_parse_redirects (qtdemux);
12267 version = QT_UINT8 ((guint8 *) mvhd->data + 8);
12268 if (version == 1) {
12269 creation_time = QT_UINT64 ((guint8 *) mvhd->data + 12);
12270 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 28);
12271 qtdemux->duration = QT_UINT64 ((guint8 *) mvhd->data + 32);
12272 } else if (version == 0) {
12273 creation_time = QT_UINT32 ((guint8 *) mvhd->data + 12);
12274 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 20);
12275 qtdemux->duration = QT_UINT32 ((guint8 *) mvhd->data + 24);
12277 GST_WARNING_OBJECT (qtdemux, "Unhandled mvhd version %d", version);
12281 /* Moving qt creation time (secs since 1904) to unix time */
12282 if (creation_time != 0) {
12283 /* Try to use epoch first as it should be faster and more commonly found */
12284 if (creation_time >= QTDEMUX_SECONDS_FROM_1904_TO_1970) {
12287 creation_time -= QTDEMUX_SECONDS_FROM_1904_TO_1970;
12288 /* some data cleansing sanity */
12289 g_get_current_time (&now);
12290 if (now.tv_sec + 24 * 3600 < creation_time) {
12291 GST_DEBUG_OBJECT (qtdemux, "discarding bogus future creation time");
12293 datetime = gst_date_time_new_from_unix_epoch_utc (creation_time);
12296 GDateTime *base_dt = g_date_time_new_utc (1904, 1, 1, 0, 0, 0);
12297 GDateTime *dt, *dt_local;
12299 dt = g_date_time_add_seconds (base_dt, creation_time);
12300 dt_local = g_date_time_to_local (dt);
12301 datetime = gst_date_time_new_from_g_date_time (dt_local);
12303 g_date_time_unref (base_dt);
12304 g_date_time_unref (dt);
12308 /* Use KEEP as explicit tags should have a higher priority than mvhd tag */
12309 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_KEEP, GST_TAG_DATE_TIME,
12311 gst_date_time_unref (datetime);
12314 GST_INFO_OBJECT (qtdemux, "timescale: %u", qtdemux->timescale);
12315 GST_INFO_OBJECT (qtdemux, "duration: %" G_GUINT64_FORMAT, qtdemux->duration);
12317 /* check for fragmented file and get some (default) data */
12318 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
12321 GstByteReader mehd_data;
12323 /* let track parsing or anyone know weird stuff might happen ... */
12324 qtdemux->fragmented = TRUE;
12326 /* compensate for total duration */
12327 mehd = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_mehd, &mehd_data);
12329 qtdemux_parse_mehd (qtdemux, &mehd_data);
12332 /* set duration in the segment info */
12333 gst_qtdemux_get_duration (qtdemux, &duration);
12335 qtdemux->segment.duration = duration;
12336 /* also do not exceed duration; stop is set that way post seek anyway,
12337 * and segment activation falls back to duration,
12338 * whereas loop only checks stop, so let's align this here as well */
12339 qtdemux->segment.stop = duration;
12342 /* parse all traks */
12343 trak = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_trak);
12345 qtdemux_parse_trak (qtdemux, trak);
12346 /* iterate all siblings */
12347 trak = qtdemux_tree_get_sibling_by_type (trak, FOURCC_trak);
12350 if (!qtdemux->tag_list) {
12351 GST_DEBUG_OBJECT (qtdemux, "new tag list");
12352 qtdemux->tag_list = gst_tag_list_new_empty ();
12353 gst_tag_list_set_scope (qtdemux->tag_list, GST_TAG_SCOPE_GLOBAL);
12355 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
12359 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_udta);
12361 qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
12363 GST_LOG_OBJECT (qtdemux, "No udta node found.");
12366 /* maybe also some tags in meta box */
12367 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_meta);
12369 GST_DEBUG_OBJECT (qtdemux, "Parsing meta box for tags.");
12370 qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
12372 GST_LOG_OBJECT (qtdemux, "No meta node found.");
12375 /* parse any protection system info */
12376 pssh = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_pssh);
12378 GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
12379 qtdemux_parse_pssh (qtdemux, pssh);
12380 pssh = qtdemux_tree_get_sibling_by_type (pssh, FOURCC_pssh);
12383 qtdemux->tag_list = qtdemux_add_container_format (qtdemux, qtdemux->tag_list);
12388 /* taken from ffmpeg */
12390 read_descr_size (guint8 * ptr, guint8 * end, guint8 ** end_out)
12402 len = (len << 7) | (c & 0x7f);
12410 /* this can change the codec originally present in @list */
12412 gst_qtdemux_handle_esds (GstQTDemux * qtdemux, QtDemuxStream * stream,
12413 GNode * esds, GstTagList * list)
12415 int len = QT_UINT32 (esds->data);
12416 guint8 *ptr = esds->data;
12417 guint8 *end = ptr + len;
12419 guint8 *data_ptr = NULL;
12421 guint8 object_type_id = 0;
12422 const char *codec_name = NULL;
12423 GstCaps *caps = NULL;
12425 GST_MEMDUMP_OBJECT (qtdemux, "esds", ptr, len);
12427 GST_DEBUG_OBJECT (qtdemux, "version/flags = %08x", QT_UINT32 (ptr));
12429 while (ptr + 1 < end) {
12430 tag = QT_UINT8 (ptr);
12431 GST_DEBUG_OBJECT (qtdemux, "tag = %02x", tag);
12433 len = read_descr_size (ptr, end, &ptr);
12434 GST_DEBUG_OBJECT (qtdemux, "len = %d", len);
12436 /* Check the stated amount of data is available for reading */
12437 if (len < 0 || ptr + len > end)
12441 case ES_DESCRIPTOR_TAG:
12442 GST_DEBUG_OBJECT (qtdemux, "ID %04x", QT_UINT16 (ptr));
12443 GST_DEBUG_OBJECT (qtdemux, "priority %04x", QT_UINT8 (ptr + 2));
12446 case DECODER_CONFIG_DESC_TAG:{
12447 guint max_bitrate, avg_bitrate;
12449 object_type_id = QT_UINT8 (ptr);
12450 max_bitrate = QT_UINT32 (ptr + 5);
12451 avg_bitrate = QT_UINT32 (ptr + 9);
12452 GST_DEBUG_OBJECT (qtdemux, "object_type_id %02x", object_type_id);
12453 GST_DEBUG_OBJECT (qtdemux, "stream_type %02x", QT_UINT8 (ptr + 1));
12454 GST_DEBUG_OBJECT (qtdemux, "buffer_size_db %02x", QT_UINT24 (ptr + 2));
12455 GST_DEBUG_OBJECT (qtdemux, "max bitrate %u", max_bitrate);
12456 GST_DEBUG_OBJECT (qtdemux, "avg bitrate %u", avg_bitrate);
12457 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
12458 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
12459 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
12461 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
12462 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
12463 avg_bitrate, NULL);
12468 case DECODER_SPECIFIC_INFO_TAG:
12469 GST_MEMDUMP_OBJECT (qtdemux, "data", ptr, len);
12470 if (object_type_id == 0xe0 && len == 0x40) {
12476 GST_DEBUG_OBJECT (qtdemux,
12477 "Have VOBSUB palette. Creating palette event");
12478 /* move to decConfigDescr data and read palette */
12480 for (i = 0; i < 16; i++) {
12481 clut[i] = QT_UINT32 (data);
12485 s = gst_structure_new ("application/x-gst-dvd", "event",
12486 G_TYPE_STRING, "dvd-spu-clut-change",
12487 "clut00", G_TYPE_INT, clut[0], "clut01", G_TYPE_INT, clut[1],
12488 "clut02", G_TYPE_INT, clut[2], "clut03", G_TYPE_INT, clut[3],
12489 "clut04", G_TYPE_INT, clut[4], "clut05", G_TYPE_INT, clut[5],
12490 "clut06", G_TYPE_INT, clut[6], "clut07", G_TYPE_INT, clut[7],
12491 "clut08", G_TYPE_INT, clut[8], "clut09", G_TYPE_INT, clut[9],
12492 "clut10", G_TYPE_INT, clut[10], "clut11", G_TYPE_INT, clut[11],
12493 "clut12", G_TYPE_INT, clut[12], "clut13", G_TYPE_INT, clut[13],
12494 "clut14", G_TYPE_INT, clut[14], "clut15", G_TYPE_INT, clut[15],
12497 /* store event and trigger custom processing */
12498 stream->pending_event =
12499 gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s);
12501 /* Generic codec_data handler puts it on the caps */
12508 case SL_CONFIG_DESC_TAG:
12509 GST_DEBUG_OBJECT (qtdemux, "data %02x", QT_UINT8 (ptr));
12513 GST_DEBUG_OBJECT (qtdemux, "Unknown/unhandled descriptor tag %02x",
12515 GST_MEMDUMP_OBJECT (qtdemux, "descriptor data", ptr, len);
12521 /* object_type_id in the esds atom in mp4a and mp4v tells us which codec is
12522 * in use, and should also be used to override some other parameters for some
12524 switch (object_type_id) {
12525 case 0x20: /* MPEG-4 */
12526 /* 4 bytes for the visual_object_sequence_start_code and 1 byte for the
12527 * profile_and_level_indication */
12528 if (data_ptr != NULL && data_len >= 5 &&
12529 GST_READ_UINT32_BE (data_ptr) == 0x000001b0) {
12530 gst_codec_utils_mpeg4video_caps_set_level_and_profile (stream->caps,
12531 data_ptr + 4, data_len - 4);
12533 break; /* Nothing special needed here */
12534 case 0x21: /* H.264 */
12535 codec_name = "H.264 / AVC";
12536 caps = gst_caps_new_simple ("video/x-h264",
12537 "stream-format", G_TYPE_STRING, "avc",
12538 "alignment", G_TYPE_STRING, "au", NULL);
12540 case 0x40: /* AAC (any) */
12541 case 0x66: /* AAC Main */
12542 case 0x67: /* AAC LC */
12543 case 0x68: /* AAC SSR */
12544 /* Override channels and rate based on the codec_data, as it's often
12546 /* Only do so for basic setup without HE-AAC extension */
12547 if (data_ptr && data_len == 2) {
12548 guint channels, rate;
12550 channels = gst_codec_utils_aac_get_channels (data_ptr, data_len);
12552 stream->n_channels = channels;
12554 rate = gst_codec_utils_aac_get_sample_rate (data_ptr, data_len);
12556 stream->rate = rate;
12559 /* Set level and profile if possible */
12560 if (data_ptr != NULL && data_len >= 2) {
12561 gst_codec_utils_aac_caps_set_level_and_profile (stream->caps,
12562 data_ptr, data_len);
12565 case 0x60: /* MPEG-2, various profiles */
12571 codec_name = "MPEG-2 video";
12572 caps = gst_caps_new_simple ("video/mpeg",
12573 "mpegversion", G_TYPE_INT, 2,
12574 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
12576 case 0x69: /* MPEG-2 BC audio */
12577 case 0x6B: /* MPEG-1 audio */
12578 caps = gst_caps_new_simple ("audio/mpeg",
12579 "mpegversion", G_TYPE_INT, 1, "parsed", G_TYPE_BOOLEAN, TRUE, NULL);
12580 codec_name = "MPEG-1 audio";
12582 case 0x6A: /* MPEG-1 */
12583 codec_name = "MPEG-1 video";
12584 caps = gst_caps_new_simple ("video/mpeg",
12585 "mpegversion", G_TYPE_INT, 1,
12586 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
12588 case 0x6C: /* MJPEG */
12590 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
12592 codec_name = "Motion-JPEG";
12594 case 0x6D: /* PNG */
12596 gst_caps_new_simple ("image/png", "parsed", G_TYPE_BOOLEAN, TRUE,
12598 codec_name = "PNG still images";
12600 case 0x6E: /* JPEG2000 */
12601 codec_name = "JPEG-2000";
12602 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
12604 case 0xA4: /* Dirac */
12605 codec_name = "Dirac";
12606 caps = gst_caps_new_empty_simple ("video/x-dirac");
12608 case 0xA5: /* AC3 */
12609 codec_name = "AC-3 audio";
12610 caps = gst_caps_new_simple ("audio/x-ac3",
12611 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
12613 case 0xA9: /* AC3 */
12614 codec_name = "DTS audio";
12615 caps = gst_caps_new_simple ("audio/x-dts",
12616 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
12618 case 0xE1: /* QCELP */
12619 /* QCELP, the codec_data is a riff tag (little endian) with
12620 * 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). */
12621 caps = gst_caps_new_empty_simple ("audio/qcelp");
12622 codec_name = "QCELP";
12628 /* If we have a replacement caps, then change our caps for this stream */
12630 gst_caps_unref (stream->caps);
12631 stream->caps = caps;
12634 if (codec_name && list)
12635 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
12636 GST_TAG_AUDIO_CODEC, codec_name, NULL);
12638 /* Add the codec_data attribute to caps, if we have it */
12642 buffer = gst_buffer_new_and_alloc (data_len);
12643 gst_buffer_fill (buffer, 0, data_ptr, data_len);
12645 GST_DEBUG_OBJECT (qtdemux, "setting codec_data from esds");
12646 GST_MEMDUMP_OBJECT (qtdemux, "codec_data from esds", data_ptr, data_len);
12648 gst_caps_set_simple (stream->caps, "codec_data", GST_TYPE_BUFFER,
12650 gst_buffer_unref (buffer);
12655 #define _codec(name) \
12657 if (codec_name) { \
12658 *codec_name = g_strdup (name); \
12663 qtdemux_video_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
12664 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
12666 GstCaps *caps = NULL;
12667 GstVideoFormat format = GST_VIDEO_FORMAT_UNKNOWN;
12670 case GST_MAKE_FOURCC ('p', 'n', 'g', ' '):
12671 _codec ("PNG still images");
12672 caps = gst_caps_new_empty_simple ("image/png");
12675 _codec ("JPEG still images");
12677 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
12680 case GST_MAKE_FOURCC ('m', 'j', 'p', 'a'):
12681 case GST_MAKE_FOURCC ('A', 'V', 'D', 'J'):
12682 case GST_MAKE_FOURCC ('M', 'J', 'P', 'G'):
12683 case GST_MAKE_FOURCC ('d', 'm', 'b', '1'):
12684 _codec ("Motion-JPEG");
12686 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
12689 case GST_MAKE_FOURCC ('m', 'j', 'p', 'b'):
12690 _codec ("Motion-JPEG format B");
12691 caps = gst_caps_new_empty_simple ("video/x-mjpeg-b");
12694 _codec ("JPEG-2000");
12695 /* override to what it should be according to spec, avoid palette_data */
12696 stream->bits_per_sample = 24;
12697 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
12700 _codec ("Sorensen video v.3");
12701 caps = gst_caps_new_simple ("video/x-svq",
12702 "svqversion", G_TYPE_INT, 3, NULL);
12704 case GST_MAKE_FOURCC ('s', 'v', 'q', 'i'):
12705 case GST_MAKE_FOURCC ('S', 'V', 'Q', '1'):
12706 _codec ("Sorensen video v.1");
12707 caps = gst_caps_new_simple ("video/x-svq",
12708 "svqversion", G_TYPE_INT, 1, NULL);
12710 case GST_MAKE_FOURCC ('W', 'R', 'A', 'W'):
12711 caps = gst_caps_new_empty_simple ("video/x-raw");
12712 gst_caps_set_simple (caps, "format", G_TYPE_STRING, "RGB8P", NULL);
12713 _codec ("Windows Raw RGB");
12719 bps = QT_UINT16 (stsd_data + 98);
12722 format = GST_VIDEO_FORMAT_RGB15;
12725 format = GST_VIDEO_FORMAT_RGB16;
12728 format = GST_VIDEO_FORMAT_RGB;
12731 format = GST_VIDEO_FORMAT_ARGB;
12739 case GST_MAKE_FOURCC ('y', 'v', '1', '2'):
12740 format = GST_VIDEO_FORMAT_I420;
12742 case GST_MAKE_FOURCC ('y', 'u', 'v', '2'):
12743 case GST_MAKE_FOURCC ('Y', 'u', 'v', '2'):
12744 format = GST_VIDEO_FORMAT_I420;
12747 case GST_MAKE_FOURCC ('2', 'V', 'u', 'y'):
12748 format = GST_VIDEO_FORMAT_UYVY;
12750 case GST_MAKE_FOURCC ('v', '3', '0', '8'):
12751 format = GST_VIDEO_FORMAT_v308;
12753 case GST_MAKE_FOURCC ('v', '2', '1', '6'):
12754 format = GST_VIDEO_FORMAT_v216;
12757 format = GST_VIDEO_FORMAT_v210;
12759 case GST_MAKE_FOURCC ('r', '2', '1', '0'):
12760 format = GST_VIDEO_FORMAT_r210;
12762 /* Packed YUV 4:4:4 10 bit in 32 bits, complex
12763 case GST_MAKE_FOURCC ('v', '4', '1', '0'):
12764 format = GST_VIDEO_FORMAT_v410;
12767 /* Packed YUV 4:4:4:4 8 bit in 32 bits
12768 * but different order than AYUV
12769 case GST_MAKE_FOURCC ('v', '4', '0', '8'):
12770 format = GST_VIDEO_FORMAT_v408;
12773 case GST_MAKE_FOURCC ('m', 'p', 'e', 'g'):
12774 case GST_MAKE_FOURCC ('m', 'p', 'g', '1'):
12775 _codec ("MPEG-1 video");
12776 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
12777 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
12779 case GST_MAKE_FOURCC ('h', 'd', 'v', '1'): /* HDV 720p30 */
12780 case GST_MAKE_FOURCC ('h', 'd', 'v', '2'): /* HDV 1080i60 */
12781 case GST_MAKE_FOURCC ('h', 'd', 'v', '3'): /* HDV 1080i50 */
12782 case GST_MAKE_FOURCC ('h', 'd', 'v', '4'): /* HDV 720p24 */
12783 case GST_MAKE_FOURCC ('h', 'd', 'v', '5'): /* HDV 720p25 */
12784 case GST_MAKE_FOURCC ('h', 'd', 'v', '6'): /* HDV 1080p24 */
12785 case GST_MAKE_FOURCC ('h', 'd', 'v', '7'): /* HDV 1080p25 */
12786 case GST_MAKE_FOURCC ('h', 'd', 'v', '8'): /* HDV 1080p30 */
12787 case GST_MAKE_FOURCC ('h', 'd', 'v', '9'): /* HDV 720p60 */
12788 case GST_MAKE_FOURCC ('h', 'd', 'v', 'a'): /* HDV 720p50 */
12789 case GST_MAKE_FOURCC ('m', 'x', '5', 'n'): /* MPEG2 IMX NTSC 525/60 50mb/s produced by FCP */
12790 case GST_MAKE_FOURCC ('m', 'x', '5', 'p'): /* MPEG2 IMX PAL 625/60 50mb/s produced by FCP */
12791 case GST_MAKE_FOURCC ('m', 'x', '4', 'n'): /* MPEG2 IMX NTSC 525/60 40mb/s produced by FCP */
12792 case GST_MAKE_FOURCC ('m', 'x', '4', 'p'): /* MPEG2 IMX PAL 625/60 40mb/s produced by FCP */
12793 case GST_MAKE_FOURCC ('m', 'x', '3', 'n'): /* MPEG2 IMX NTSC 525/60 30mb/s produced by FCP */
12794 case GST_MAKE_FOURCC ('m', 'x', '3', 'p'): /* MPEG2 IMX PAL 625/50 30mb/s produced by FCP */
12795 case GST_MAKE_FOURCC ('x', 'd', 'v', '1'): /* XDCAM HD 720p30 35Mb/s */
12796 case GST_MAKE_FOURCC ('x', 'd', 'v', '2'): /* XDCAM HD 1080i60 35Mb/s */
12797 case GST_MAKE_FOURCC ('x', 'd', 'v', '3'): /* XDCAM HD 1080i50 35Mb/s */
12798 case GST_MAKE_FOURCC ('x', 'd', 'v', '4'): /* XDCAM HD 720p24 35Mb/s */
12799 case GST_MAKE_FOURCC ('x', 'd', 'v', '5'): /* XDCAM HD 720p25 35Mb/s */
12800 case GST_MAKE_FOURCC ('x', 'd', 'v', '6'): /* XDCAM HD 1080p24 35Mb/s */
12801 case GST_MAKE_FOURCC ('x', 'd', 'v', '7'): /* XDCAM HD 1080p25 35Mb/s */
12802 case GST_MAKE_FOURCC ('x', 'd', 'v', '8'): /* XDCAM HD 1080p30 35Mb/s */
12803 case GST_MAKE_FOURCC ('x', 'd', 'v', '9'): /* XDCAM HD 720p60 35Mb/s */
12804 case GST_MAKE_FOURCC ('x', 'd', 'v', 'a'): /* XDCAM HD 720p50 35Mb/s */
12805 case GST_MAKE_FOURCC ('x', 'd', 'v', 'b'): /* XDCAM EX 1080i60 50Mb/s CBR */
12806 case GST_MAKE_FOURCC ('x', 'd', 'v', 'c'): /* XDCAM EX 1080i50 50Mb/s CBR */
12807 case GST_MAKE_FOURCC ('x', 'd', 'v', 'd'): /* XDCAM HD 1080p24 50Mb/s CBR */
12808 case GST_MAKE_FOURCC ('x', 'd', 'v', 'e'): /* XDCAM HD 1080p25 50Mb/s CBR */
12809 case GST_MAKE_FOURCC ('x', 'd', 'v', 'f'): /* XDCAM HD 1080p30 50Mb/s CBR */
12810 case GST_MAKE_FOURCC ('x', 'd', '5', '1'): /* XDCAM HD422 720p30 50Mb/s CBR */
12811 case GST_MAKE_FOURCC ('x', 'd', '5', '4'): /* XDCAM HD422 720p24 50Mb/s CBR */
12812 case GST_MAKE_FOURCC ('x', 'd', '5', '5'): /* XDCAM HD422 720p25 50Mb/s CBR */
12813 case GST_MAKE_FOURCC ('x', 'd', '5', '9'): /* XDCAM HD422 720p60 50Mb/s CBR */
12814 case GST_MAKE_FOURCC ('x', 'd', '5', 'a'): /* XDCAM HD422 720p50 50Mb/s CBR */
12815 case GST_MAKE_FOURCC ('x', 'd', '5', 'b'): /* XDCAM HD422 1080i50 50Mb/s CBR */
12816 case GST_MAKE_FOURCC ('x', 'd', '5', 'c'): /* XDCAM HD422 1080i50 50Mb/s CBR */
12817 case GST_MAKE_FOURCC ('x', 'd', '5', 'd'): /* XDCAM HD422 1080p24 50Mb/s CBR */
12818 case GST_MAKE_FOURCC ('x', 'd', '5', 'e'): /* XDCAM HD422 1080p25 50Mb/s CBR */
12819 case GST_MAKE_FOURCC ('x', 'd', '5', 'f'): /* XDCAM HD422 1080p30 50Mb/s CBR */
12820 case GST_MAKE_FOURCC ('x', 'd', 'h', 'd'): /* XDCAM HD 540p */
12821 case GST_MAKE_FOURCC ('x', 'd', 'h', '2'): /* XDCAM HD422 540p */
12822 case GST_MAKE_FOURCC ('A', 'V', 'm', 'p'): /* AVID IMX PAL */
12823 case GST_MAKE_FOURCC ('m', 'p', 'g', '2'): /* AVID IMX PAL */
12824 case GST_MAKE_FOURCC ('m', 'p', '2', 'v'): /* AVID IMX PAL */
12825 _codec ("MPEG-2 video");
12826 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 2,
12827 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
12829 case GST_MAKE_FOURCC ('g', 'i', 'f', ' '):
12830 _codec ("GIF still images");
12831 caps = gst_caps_new_empty_simple ("image/gif");
12834 case GST_MAKE_FOURCC ('H', '2', '6', '3'):
12836 case GST_MAKE_FOURCC ('U', '2', '6', '3'):
12838 /* ffmpeg uses the height/width props, don't know why */
12839 caps = gst_caps_new_simple ("video/x-h263",
12840 "variant", G_TYPE_STRING, "itu", NULL);
12844 _codec ("MPEG-4 video");
12845 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
12846 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
12848 case GST_MAKE_FOURCC ('3', 'i', 'v', 'd'):
12849 case GST_MAKE_FOURCC ('3', 'I', 'V', 'D'):
12850 _codec ("Microsoft MPEG-4 4.3"); /* FIXME? */
12851 caps = gst_caps_new_simple ("video/x-msmpeg",
12852 "msmpegversion", G_TYPE_INT, 43, NULL);
12854 case GST_MAKE_FOURCC ('D', 'I', 'V', '3'):
12856 caps = gst_caps_new_simple ("video/x-divx",
12857 "divxversion", G_TYPE_INT, 3, NULL);
12859 case GST_MAKE_FOURCC ('D', 'I', 'V', 'X'):
12860 case GST_MAKE_FOURCC ('d', 'i', 'v', 'x'):
12862 caps = gst_caps_new_simple ("video/x-divx",
12863 "divxversion", G_TYPE_INT, 4, NULL);
12865 case GST_MAKE_FOURCC ('D', 'X', '5', '0'):
12867 caps = gst_caps_new_simple ("video/x-divx",
12868 "divxversion", G_TYPE_INT, 5, NULL);
12871 case GST_MAKE_FOURCC ('F', 'F', 'V', '1'):
12873 caps = gst_caps_new_simple ("video/x-ffv",
12874 "ffvversion", G_TYPE_INT, 1, NULL);
12877 case GST_MAKE_FOURCC ('3', 'I', 'V', '1'):
12878 case GST_MAKE_FOURCC ('3', 'I', 'V', '2'):
12879 case GST_MAKE_FOURCC ('X', 'V', 'I', 'D'):
12880 case GST_MAKE_FOURCC ('x', 'v', 'i', 'd'):
12882 case GST_MAKE_FOURCC ('U', 'M', 'P', '4'):
12883 caps = gst_caps_new_simple ("video/mpeg",
12884 "mpegversion", G_TYPE_INT, 4, NULL);
12888 case GST_MAKE_FOURCC ('c', 'v', 'i', 'd'):
12889 _codec ("Cinepak");
12890 caps = gst_caps_new_empty_simple ("video/x-cinepak");
12892 case GST_MAKE_FOURCC ('q', 'd', 'r', 'w'):
12893 _codec ("Apple QuickDraw");
12894 caps = gst_caps_new_empty_simple ("video/x-qdrw");
12896 case GST_MAKE_FOURCC ('r', 'p', 'z', 'a'):
12897 _codec ("Apple video");
12898 caps = gst_caps_new_empty_simple ("video/x-apple-video");
12902 _codec ("H.264 / AVC");
12903 caps = gst_caps_new_simple ("video/x-h264",
12904 "stream-format", G_TYPE_STRING, "avc",
12905 "alignment", G_TYPE_STRING, "au", NULL);
12908 _codec ("H.264 / AVC");
12909 caps = gst_caps_new_simple ("video/x-h264",
12910 "stream-format", G_TYPE_STRING, "avc3",
12911 "alignment", G_TYPE_STRING, "au", NULL);
12915 _codec ("H.265 / HEVC");
12916 caps = gst_caps_new_simple ("video/x-h265",
12917 "stream-format", G_TYPE_STRING, "hvc1",
12918 "alignment", G_TYPE_STRING, "au", NULL);
12921 _codec ("H.265 / HEVC");
12922 caps = gst_caps_new_simple ("video/x-h265",
12923 "stream-format", G_TYPE_STRING, "hev1",
12924 "alignment", G_TYPE_STRING, "au", NULL);
12927 _codec ("Run-length encoding");
12928 caps = gst_caps_new_simple ("video/x-rle",
12929 "layout", G_TYPE_STRING, "quicktime", NULL);
12932 _codec ("Run-length encoding");
12933 caps = gst_caps_new_simple ("video/x-rle",
12934 "layout", G_TYPE_STRING, "microsoft", NULL);
12936 case GST_MAKE_FOURCC ('I', 'V', '3', '2'):
12937 case GST_MAKE_FOURCC ('i', 'v', '3', '2'):
12938 _codec ("Indeo Video 3");
12939 caps = gst_caps_new_simple ("video/x-indeo",
12940 "indeoversion", G_TYPE_INT, 3, NULL);
12942 case GST_MAKE_FOURCC ('I', 'V', '4', '1'):
12943 case GST_MAKE_FOURCC ('i', 'v', '4', '1'):
12944 _codec ("Intel Video 4");
12945 caps = gst_caps_new_simple ("video/x-indeo",
12946 "indeoversion", G_TYPE_INT, 4, NULL);
12950 case GST_MAKE_FOURCC ('d', 'v', 's', 'd'):
12951 case GST_MAKE_FOURCC ('D', 'V', 'S', 'D'):
12952 case GST_MAKE_FOURCC ('d', 'v', 'c', 's'):
12953 case GST_MAKE_FOURCC ('D', 'V', 'C', 'S'):
12954 case GST_MAKE_FOURCC ('d', 'v', '2', '5'):
12955 case GST_MAKE_FOURCC ('d', 'v', 'p', 'p'):
12956 _codec ("DV Video");
12957 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 25,
12958 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
12960 case FOURCC_dv5n: /* DVCPRO50 NTSC */
12961 case FOURCC_dv5p: /* DVCPRO50 PAL */
12962 _codec ("DVCPro50 Video");
12963 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 50,
12964 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
12966 case GST_MAKE_FOURCC ('d', 'v', 'h', '5'): /* DVCPRO HD 50i produced by FCP */
12967 case GST_MAKE_FOURCC ('d', 'v', 'h', '6'): /* DVCPRO HD 60i produced by FCP */
12968 _codec ("DVCProHD Video");
12969 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 100,
12970 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
12972 case GST_MAKE_FOURCC ('s', 'm', 'c', ' '):
12973 _codec ("Apple Graphics (SMC)");
12974 caps = gst_caps_new_empty_simple ("video/x-smc");
12976 case GST_MAKE_FOURCC ('V', 'P', '3', '1'):
12978 caps = gst_caps_new_empty_simple ("video/x-vp3");
12980 case GST_MAKE_FOURCC ('V', 'P', '6', 'F'):
12981 _codec ("VP6 Flash");
12982 caps = gst_caps_new_empty_simple ("video/x-vp6-flash");
12986 caps = gst_caps_new_empty_simple ("video/x-theora");
12987 /* theora uses one byte of padding in the data stream because it does not
12988 * allow 0 sized packets while theora does */
12989 stream->padding = 1;
12993 caps = gst_caps_new_empty_simple ("video/x-dirac");
12995 case GST_MAKE_FOURCC ('t', 'i', 'f', 'f'):
12996 _codec ("TIFF still images");
12997 caps = gst_caps_new_empty_simple ("image/tiff");
12999 case GST_MAKE_FOURCC ('i', 'c', 'o', 'd'):
13000 _codec ("Apple Intermediate Codec");
13001 caps = gst_caps_from_string ("video/x-apple-intermediate-codec");
13003 case GST_MAKE_FOURCC ('A', 'V', 'd', 'n'):
13004 _codec ("AVID DNxHD");
13005 caps = gst_caps_from_string ("video/x-dnxhd");
13008 _codec ("On2 VP8");
13009 caps = gst_caps_from_string ("video/x-vp8");
13012 _codec ("Apple ProRes LT");
13014 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "lt",
13018 _codec ("Apple ProRes HQ");
13020 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "hq",
13024 _codec ("Apple ProRes");
13026 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
13030 _codec ("Apple ProRes Proxy");
13032 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
13036 _codec ("Apple ProRes 4444");
13038 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
13044 caps = gst_caps_new_simple ("video/x-wmv",
13045 "wmvversion", G_TYPE_INT, 3, "format", G_TYPE_STRING, "WVC1", NULL);
13047 case GST_MAKE_FOURCC ('k', 'p', 'c', 'd'):
13050 char *s, fourstr[5];
13052 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
13053 s = g_strdup_printf ("video/x-gst-fourcc-%s", g_strstrip (fourstr));
13054 caps = gst_caps_new_empty_simple (s);
13060 if (format != GST_VIDEO_FORMAT_UNKNOWN) {
13063 gst_video_info_init (&info);
13064 gst_video_info_set_format (&info, format, stream->width, stream->height);
13066 caps = gst_video_info_to_caps (&info);
13067 *codec_name = gst_pb_utils_get_codec_description (caps);
13069 /* enable clipping for raw video streams */
13070 stream->need_clip = TRUE;
13077 qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
13078 guint32 fourcc, const guint8 * data, int len, gchar ** codec_name)
13081 const GstStructure *s;
13084 GstAudioFormat format = 0;
13087 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
13089 depth = stream->bytes_per_packet * 8;
13092 case GST_MAKE_FOURCC ('N', 'O', 'N', 'E'):
13094 /* 8-bit audio is unsigned */
13096 format = GST_AUDIO_FORMAT_U8;
13097 /* otherwise it's signed and big-endian just like 'twos' */
13099 endian = G_BIG_ENDIAN;
13106 endian = G_LITTLE_ENDIAN;
13109 format = gst_audio_format_build_integer (TRUE, endian, depth, depth);
13111 str = g_strdup_printf ("Raw %d-bit PCM audio", depth);
13115 caps = gst_caps_new_simple ("audio/x-raw",
13116 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
13117 "layout", G_TYPE_STRING, "interleaved", NULL);
13120 case GST_MAKE_FOURCC ('f', 'l', '6', '4'):
13121 _codec ("Raw 64-bit floating-point audio");
13122 caps = gst_caps_new_simple ("audio/x-raw",
13123 "format", G_TYPE_STRING, "F64BE",
13124 "layout", G_TYPE_STRING, "interleaved", NULL);
13126 case GST_MAKE_FOURCC ('f', 'l', '3', '2'):
13127 _codec ("Raw 32-bit floating-point audio");
13128 caps = gst_caps_new_simple ("audio/x-raw",
13129 "format", G_TYPE_STRING, "F32BE",
13130 "layout", G_TYPE_STRING, "interleaved", NULL);
13133 _codec ("Raw 24-bit PCM audio");
13134 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
13136 caps = gst_caps_new_simple ("audio/x-raw",
13137 "format", G_TYPE_STRING, "S24BE",
13138 "layout", G_TYPE_STRING, "interleaved", NULL);
13140 case GST_MAKE_FOURCC ('i', 'n', '3', '2'):
13141 _codec ("Raw 32-bit PCM audio");
13142 caps = gst_caps_new_simple ("audio/x-raw",
13143 "format", G_TYPE_STRING, "S32BE",
13144 "layout", G_TYPE_STRING, "interleaved", NULL);
13147 _codec ("Mu-law audio");
13148 caps = gst_caps_new_empty_simple ("audio/x-mulaw");
13151 _codec ("A-law audio");
13152 caps = gst_caps_new_empty_simple ("audio/x-alaw");
13156 _codec ("Microsoft ADPCM");
13157 /* Microsoft ADPCM-ACM code 2 */
13158 caps = gst_caps_new_simple ("audio/x-adpcm",
13159 "layout", G_TYPE_STRING, "microsoft", NULL);
13163 _codec ("DVI/IMA ADPCM");
13164 caps = gst_caps_new_simple ("audio/x-adpcm",
13165 "layout", G_TYPE_STRING, "dvi", NULL);
13169 _codec ("DVI/Intel IMA ADPCM");
13170 /* FIXME DVI/Intel IMA ADPCM/ACM code 17 */
13171 caps = gst_caps_new_simple ("audio/x-adpcm",
13172 "layout", G_TYPE_STRING, "quicktime", NULL);
13176 /* MPEG layer 3, CBR only (pre QT4.1) */
13178 _codec ("MPEG-1 layer 3");
13179 /* MPEG layer 3, CBR & VBR (QT4.1 and later) */
13180 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 3,
13181 "mpegversion", G_TYPE_INT, 1, NULL);
13184 case GST_MAKE_FOURCC ('e', 'c', '-', '3'):
13185 _codec ("EAC-3 audio");
13186 caps = gst_caps_new_simple ("audio/x-eac3",
13187 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
13188 stream->sampled = TRUE;
13190 case GST_MAKE_FOURCC ('s', 'a', 'c', '3'): // Nero Recode
13192 _codec ("AC-3 audio");
13193 caps = gst_caps_new_simple ("audio/x-ac3",
13194 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
13195 stream->sampled = TRUE;
13197 case GST_MAKE_FOURCC ('d', 't', 's', 'c'):
13198 case GST_MAKE_FOURCC ('D', 'T', 'S', ' '):
13199 _codec ("DTS audio");
13200 caps = gst_caps_new_simple ("audio/x-dts",
13201 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
13202 stream->sampled = TRUE;
13204 case GST_MAKE_FOURCC ('d', 't', 's', 'h'): // DTS-HD
13205 case GST_MAKE_FOURCC ('d', 't', 's', 'l'): // DTS-HD Lossless
13206 _codec ("DTS-HD audio");
13207 caps = gst_caps_new_simple ("audio/x-dts",
13208 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
13209 stream->sampled = TRUE;
13213 caps = gst_caps_new_simple ("audio/x-mace",
13214 "maceversion", G_TYPE_INT, 3, NULL);
13218 caps = gst_caps_new_simple ("audio/x-mace",
13219 "maceversion", G_TYPE_INT, 6, NULL);
13221 case GST_MAKE_FOURCC ('O', 'g', 'g', 'V'):
13223 caps = gst_caps_new_empty_simple ("application/ogg");
13225 case GST_MAKE_FOURCC ('d', 'v', 'c', 'a'):
13226 _codec ("DV audio");
13227 caps = gst_caps_new_empty_simple ("audio/x-dv");
13230 _codec ("MPEG-4 AAC audio");
13231 caps = gst_caps_new_simple ("audio/mpeg",
13232 "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE,
13233 "stream-format", G_TYPE_STRING, "raw", NULL);
13235 case GST_MAKE_FOURCC ('Q', 'D', 'M', 'C'):
13236 _codec ("QDesign Music");
13237 caps = gst_caps_new_empty_simple ("audio/x-qdm");
13240 _codec ("QDesign Music v.2");
13241 /* FIXME: QDesign music version 2 (no constant) */
13242 if (FALSE && data) {
13243 caps = gst_caps_new_simple ("audio/x-qdm2",
13244 "framesize", G_TYPE_INT, QT_UINT32 (data + 52),
13245 "bitrate", G_TYPE_INT, QT_UINT32 (data + 40),
13246 "blocksize", G_TYPE_INT, QT_UINT32 (data + 44), NULL);
13248 caps = gst_caps_new_empty_simple ("audio/x-qdm2");
13252 _codec ("GSM audio");
13253 caps = gst_caps_new_empty_simple ("audio/x-gsm");
13256 _codec ("AMR audio");
13257 caps = gst_caps_new_empty_simple ("audio/AMR");
13260 _codec ("AMR-WB audio");
13261 caps = gst_caps_new_empty_simple ("audio/AMR-WB");
13264 _codec ("Quicktime IMA ADPCM");
13265 caps = gst_caps_new_simple ("audio/x-adpcm",
13266 "layout", G_TYPE_STRING, "quicktime", NULL);
13269 _codec ("Apple lossless audio");
13270 caps = gst_caps_new_empty_simple ("audio/x-alac");
13272 case GST_MAKE_FOURCC ('Q', 'c', 'l', 'p'):
13273 _codec ("QualComm PureVoice");
13274 caps = gst_caps_from_string ("audio/qcelp");
13279 caps = gst_caps_new_empty_simple ("audio/x-wma");
13283 caps = gst_caps_new_empty_simple ("audio/x-opus");
13285 case GST_MAKE_FOURCC ('l', 'p', 'c', 'm'):
13290 GstAudioFormat format;
13293 FLAG_IS_FLOAT = 0x1,
13294 FLAG_IS_BIG_ENDIAN = 0x2,
13295 FLAG_IS_SIGNED = 0x4,
13296 FLAG_IS_PACKED = 0x8,
13297 FLAG_IS_ALIGNED_HIGH = 0x10,
13298 FLAG_IS_NON_INTERLEAVED = 0x20
13300 _codec ("Raw LPCM audio");
13302 if (data && len >= 56) {
13303 depth = QT_UINT32 (data + 40);
13304 flags = QT_UINT32 (data + 44);
13305 width = QT_UINT32 (data + 48) * 8 / stream->n_channels;
13307 if ((flags & FLAG_IS_FLOAT) == 0) {
13312 format = gst_audio_format_build_integer ((flags & FLAG_IS_SIGNED) ?
13313 TRUE : FALSE, (flags & FLAG_IS_BIG_ENDIAN) ?
13314 G_BIG_ENDIAN : G_LITTLE_ENDIAN, width, depth);
13315 caps = gst_caps_new_simple ("audio/x-raw",
13316 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
13317 "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
13318 "non-interleaved" : "interleaved", NULL);
13323 if (flags & FLAG_IS_BIG_ENDIAN)
13324 format = GST_AUDIO_FORMAT_F64BE;
13326 format = GST_AUDIO_FORMAT_F64LE;
13328 if (flags & FLAG_IS_BIG_ENDIAN)
13329 format = GST_AUDIO_FORMAT_F32BE;
13331 format = GST_AUDIO_FORMAT_F32LE;
13333 caps = gst_caps_new_simple ("audio/x-raw",
13334 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
13335 "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
13336 "non-interleaved" : "interleaved", NULL);
13340 case GST_MAKE_FOURCC ('q', 't', 'v', 'r'):
13344 char *s, fourstr[5];
13346 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
13347 s = g_strdup_printf ("audio/x-gst-fourcc-%s", g_strstrip (fourstr));
13348 caps = gst_caps_new_empty_simple (s);
13355 GstCaps *templ_caps =
13356 gst_static_pad_template_get_caps (&gst_qtdemux_audiosrc_template);
13357 GstCaps *intersection = gst_caps_intersect (caps, templ_caps);
13358 gst_caps_unref (caps);
13359 gst_caps_unref (templ_caps);
13360 caps = intersection;
13363 /* enable clipping for raw audio streams */
13364 s = gst_caps_get_structure (caps, 0);
13365 name = gst_structure_get_name (s);
13366 if (g_str_has_prefix (name, "audio/x-raw")) {
13367 stream->need_clip = TRUE;
13368 stream->max_buffer_size = 4096 * stream->bytes_per_frame;
13369 GST_DEBUG ("setting max buffer size to %d", stream->max_buffer_size);
13375 qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
13376 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
13380 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
13384 _codec ("DVD subtitle");
13385 caps = gst_caps_new_empty_simple ("subpicture/x-dvd");
13386 stream->need_process = TRUE;
13389 _codec ("Quicktime timed text");
13392 _codec ("3GPP timed text");
13394 caps = gst_caps_new_simple ("text/x-raw", "format", G_TYPE_STRING,
13396 /* actual text piece needs to be extracted */
13397 stream->need_process = TRUE;
13400 _codec ("XML subtitles");
13401 caps = gst_caps_new_empty_simple ("application/ttml+xml");
13405 char *s, fourstr[5];
13407 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
13408 s = g_strdup_printf ("text/x-gst-fourcc-%s", g_strstrip (fourstr));
13409 caps = gst_caps_new_empty_simple (s);
13418 qtdemux_generic_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
13419 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
13425 _codec ("MPEG 1 video");
13426 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
13427 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13437 gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux,
13438 const gchar * system_id)
13442 if (!qtdemux->protection_system_ids)
13443 qtdemux->protection_system_ids =
13444 g_ptr_array_new_with_free_func ((GDestroyNotify) g_free);
13445 /* Check whether we already have an entry for this system ID. */
13446 for (i = 0; i < qtdemux->protection_system_ids->len; ++i) {
13447 const gchar *id = g_ptr_array_index (qtdemux->protection_system_ids, i);
13448 if (g_ascii_strcasecmp (system_id, id) == 0) {
13452 GST_DEBUG_OBJECT (qtdemux, "Adding cenc protection system ID %s", system_id);
13453 g_ptr_array_add (qtdemux->protection_system_ids, g_ascii_strdown (system_id,