2 * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
3 * Copyright (C) <2003> David A. Schleef <ds@schleef.org>
4 * Copyright (C) <2006> Wim Taymans <wim@fluendo.com>
5 * Copyright (C) <2007> Julien Moutte <julien@fluendo.com>
6 * Copyright (C) <2009> Tim-Philipp Müller <tim centricular net>
7 * Copyright (C) <2009> STEricsson <benjamin.gaignard@stericsson.com>
8 * Copyright (C) <2013> Sreerenj Balachandran <sreerenj.balachandran@intel.com>
9 * Copyright (C) <2013> Intel Corporation
10 * Copyright (C) <2014> Centricular Ltd
11 * Copyright (C) <2015> YouView TV Ltd.
12 * Copyright (C) <2016> British Broadcasting Corporation
14 * This library is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU Library General Public
16 * License as published by the Free Software Foundation; either
17 * version 2 of the License, or (at your option) any later version.
19 * This library is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * Library General Public License for more details.
24 * You should have received a copy of the GNU Library General Public
25 * License along with this library; if not, write to the
26 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
27 * Boston, MA 02110-1301, USA.
31 * SECTION:element-qtdemux
33 * Demuxes a .mov file into raw or compressed audio and/or video streams.
35 * This element supports both push and pull-based scheduling, depending on the
36 * capabilities of the upstream elements.
39 * <title>Example launch line</title>
41 * gst-launch-1.0 filesrc location=test.mov ! qtdemux name=demux demux.audio_0 ! queue ! decodebin ! audioconvert ! audioresample ! autoaudiosink demux.video_0 ! queue ! decodebin ! videoconvert ! videoscale ! autovideosink
42 * ]| Play (parse and decode) a .mov file and try to output it to
43 * an automatically detected soundcard and videosink. If the MOV file contains
44 * compressed audio or video data, this will only work if you have the
45 * right decoder elements/plugins installed.
53 #include "gst/gst-i18n-plugin.h"
55 #include <glib/gprintf.h>
56 #include <gst/tag/tag.h>
57 #include <gst/audio/audio.h>
58 #include <gst/video/video.h>
60 #include "qtatomparser.h"
61 #include "qtdemux_types.h"
62 #include "qtdemux_dump.h"
64 #include "descriptors.h"
65 #include "qtdemux_lang.h"
67 #include "qtpalette.h"
69 #include "gst/riff/riff-media.h"
70 #include "gst/riff/riff-read.h"
72 #include <gst/pbutils/pbutils.h>
79 #include <gst/math-compat.h>
85 /* max. size considered 'sane' for non-mdat atoms */
86 #define QTDEMUX_MAX_ATOM_SIZE (25*1024*1024)
88 /* if the sample index is larger than this, something is likely wrong */
89 #define QTDEMUX_MAX_SAMPLE_INDEX_SIZE (50*1024*1024)
91 /* For converting qt creation times to unix epoch times */
92 #define QTDEMUX_SECONDS_PER_DAY (60 * 60 * 24)
93 #define QTDEMUX_LEAP_YEARS_FROM_1904_TO_1970 17
94 #define QTDEMUX_SECONDS_FROM_1904_TO_1970 (((1970 - 1904) * (guint64) 365 + \
95 QTDEMUX_LEAP_YEARS_FROM_1904_TO_1970) * QTDEMUX_SECONDS_PER_DAY)
97 #define STREAM_IS_EOS(s) (s->time_position == GST_CLOCK_TIME_NONE)
99 #define ABSDIFF(x, y) ( (x) > (y) ? ((x) - (y)) : ((y) - (x)) )
101 GST_DEBUG_CATEGORY (qtdemux_debug);
103 typedef struct _QtDemuxSegment QtDemuxSegment;
104 typedef struct _QtDemuxSample QtDemuxSample;
106 typedef struct _QtDemuxCencSampleSetInfo QtDemuxCencSampleSetInfo;
108 struct _QtDemuxSample
111 gint32 pts_offset; /* Add this value to timestamp to get the pts */
113 guint64 timestamp; /* DTS In mov time */
114 guint32 duration; /* In mov time */
115 gboolean keyframe; /* TRUE when this packet is a keyframe */
118 /* Macros for converting to/from timescale */
119 #define QTSTREAMTIME_TO_GSTTIME(stream, value) (gst_util_uint64_scale((value), GST_SECOND, (stream)->timescale))
120 #define GSTTIME_TO_QTSTREAMTIME(stream, value) (gst_util_uint64_scale((value), (stream)->timescale, GST_SECOND))
122 #define QTTIME_TO_GSTTIME(qtdemux, value) (gst_util_uint64_scale((value), GST_SECOND, (qtdemux)->timescale))
123 #define GSTTIME_TO_QTTIME(qtdemux, value) (gst_util_uint64_scale((value), (qtdemux)->timescale, GST_SECOND))
125 /* timestamp is the DTS */
126 #define QTSAMPLE_DTS(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp))
127 /* timestamp + offset is the PTS */
128 #define QTSAMPLE_PTS(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp + (stream)->cslg_shift + (sample)->pts_offset))
129 /* timestamp + duration - dts is the duration */
130 #define QTSAMPLE_DUR_DTS(stream, sample, dts) (QTSTREAMTIME_TO_GSTTIME ((stream), (sample)->timestamp + (sample)->duration) - (dts))
132 #define QTSAMPLE_KEYFRAME(stream,sample) ((stream)->all_keyframe || (sample)->keyframe)
135 * Quicktime has tracks and segments. A track is a continuous piece of
136 * multimedia content. The track is not always played from start to finish but
137 * instead, pieces of the track are 'cut out' and played in sequence. This is
138 * what the segments do.
140 * Inside the track we have keyframes (K) and delta frames. The track has its
141 * own timing, which starts from 0 and extends to end. The position in the track
142 * is called the media_time.
144 * The segments now describe the pieces that should be played from this track
145 * and are basically tuples of media_time/duration/rate entries. We can have
146 * multiple segments and they are all played after one another. An example:
148 * segment 1: media_time: 1 second, duration: 1 second, rate 1
149 * segment 2: media_time: 3 second, duration: 2 second, rate 2
151 * To correctly play back this track, one must play: 1 second of media starting
152 * from media_time 1 followed by 2 seconds of media starting from media_time 3
155 * Each of the segments will be played at a specific time, the first segment at
156 * time 0, the second one after the duration of the first one, etc.. Note that
157 * the time in resulting playback is not identical to the media_time of the
160 * Visually, assuming the track has 4 second of media_time:
163 * .-----------------------------------------------------------.
164 * track: | K.....K.........K........K.......K.......K...........K... |
165 * '-----------------------------------------------------------'
167 * .------------^ ^ .----------^ ^
168 * / .-------------' / .------------------'
170 * .--------------. .--------------.
171 * | segment 1 | | segment 2 |
172 * '--------------' '--------------'
174 * The challenge here is to cut out the right pieces of the track for each of
175 * the playback segments. This fortunately can easily be done with the SEGMENT
176 * events of GStreamer.
178 * For playback of segment 1, we need to provide the decoder with the keyframe
179 * (a), in the above figure, but we must instruct it only to output the decoded
180 * data between second 1 and 2. We do this with a SEGMENT event for 1 to 2, time
181 * position set to the time of the segment: 0.
183 * We then proceed to push data from keyframe (a) to frame (b). The decoder
184 * decodes but clips all before media_time 1.
186 * After finishing a segment, we push out a new SEGMENT event with the clipping
187 * boundaries of the new data.
189 * This is a good usecase for the GStreamer accumulated SEGMENT events.
192 struct _QtDemuxSegment
194 /* global time and duration, all gst time */
196 GstClockTime stop_time;
197 GstClockTime duration;
198 /* media time of trak, all gst time */
199 GstClockTime media_start;
200 GstClockTime media_stop;
202 /* Media start time in trak timescale units */
203 guint32 trak_media_start;
206 #define QTSEGMENT_IS_EMPTY(s) ((s)->media_start == GST_CLOCK_TIME_NONE)
208 /* Used with fragmented MP4 files (mfra atom) */
213 } QtDemuxRandomAccessEntry;
215 struct _QtDemuxStream
225 gboolean new_caps; /* If TRUE, caps need to be generated (by
226 * calling _configure_stream()) This happens
227 * for MSS and fragmented streams */
229 gboolean new_stream; /* signals that a stream_start is required */
230 gboolean on_keyframe; /* if this stream last pushed buffer was a
231 * keyframe. This is important to identify
232 * where to stop pushing buffers after a
233 * segment stop time */
235 /* if the stream has a redirect URI in its headers, we store it here */
242 guint64 duration; /* in timescale units */
246 gchar lang_id[4]; /* ISO 639-2T language code */
250 QtDemuxSample *samples;
251 gboolean all_keyframe; /* TRUE when all samples are keyframes (no stss) */
252 guint32 first_duration; /* duration in timescale of first sample, used for figuring out
254 guint32 n_samples_moof; /* sample count in a moof */
255 guint64 duration_moof; /* duration in timescale of a moof, used for figure out
256 * the framerate of fragmented format stream */
257 guint64 duration_last_moof;
259 guint32 offset_in_sample; /* Offset in the current sample, used for
260 * streams which have got exceedingly big
261 * sample size (such as 24s of raw audio).
262 * Only used when max_buffer_size is non-NULL */
263 guint32 max_buffer_size; /* Maximum allowed size for output buffers.
264 * Currently only set for raw audio streams*/
266 /* if we use chunks or samples */
278 /* Numerator/denominator framerate */
281 GstVideoColorimetry colorimetry;
282 guint16 bits_per_sample;
283 guint16 color_table_id;
284 GstMemory *rgb8_palette;
289 guint samples_per_packet;
290 guint samples_per_frame;
291 guint bytes_per_packet;
292 guint bytes_per_sample;
293 guint bytes_per_frame;
297 gboolean use_allocator;
298 GstAllocator *allocator;
299 GstAllocationParams params;
303 /* when a discontinuity is pending */
306 /* list of buffers to push first */
309 /* if we need to clip this buffer. This is only needed for uncompressed
313 /* buffer needs some custom processing, e.g. subtitles */
314 gboolean need_process;
316 /* current position */
317 guint32 segment_index;
318 guint32 sample_index;
319 GstClockTime time_position; /* in gst time */
320 guint64 accumulated_base;
322 /* the Gst segment we are processing out, used for clipping */
325 /* quicktime segments */
327 QtDemuxSegment *segments;
328 gboolean dummy_segment;
333 GstTagList *pending_tags;
334 gboolean send_global_tags;
336 GstEvent *pending_event;
346 gboolean chunks_are_samples; /* TRUE means treat chunks as samples */
350 GstByteReader co_chunk;
352 guint32 current_chunk;
354 guint32 samples_per_chunk;
355 guint32 stco_sample_index;
357 guint32 sample_size; /* 0 means variable sizes are stored in stsz */
360 guint32 n_samples_per_chunk;
361 guint32 stsc_chunk_index;
362 guint32 stsc_sample_index;
363 guint64 chunk_offset;
366 guint32 stts_samples;
367 guint32 n_sample_times;
368 guint32 stts_sample_index;
370 guint32 stts_duration;
372 gboolean stss_present;
373 guint32 n_sample_syncs;
376 gboolean stps_present;
377 guint32 n_sample_partial_syncs;
379 QtDemuxRandomAccessEntry *ra_entries;
382 const QtDemuxRandomAccessEntry *pending_seek;
385 gboolean ctts_present;
386 guint32 n_composition_times;
388 guint32 ctts_sample_index;
396 gboolean parsed_trex;
397 guint32 def_sample_duration;
398 guint32 def_sample_size;
399 guint32 def_sample_flags;
403 /* stereoscopic video streams */
404 GstVideoMultiviewMode multiview_mode;
405 GstVideoMultiviewFlags multiview_flags;
407 /* protected streams */
409 guint32 protection_scheme_type;
410 guint32 protection_scheme_version;
411 gpointer protection_scheme_info; /* specific to the protection scheme */
412 GQueue protection_scheme_event_queue;
415 /* Contains properties and cryptographic info for a set of samples from a
416 * track protected using Common Encryption (cenc) */
417 struct _QtDemuxCencSampleSetInfo
419 GstStructure *default_properties;
421 /* @crypto_info holds one GstStructure per sample */
422 GPtrArray *crypto_info;
426 qt_demux_state_string (enum QtDemuxState state)
429 case QTDEMUX_STATE_INITIAL:
431 case QTDEMUX_STATE_HEADER:
433 case QTDEMUX_STATE_MOVIE:
435 case QTDEMUX_STATE_BUFFER_MDAT:
436 return "<BUFFER_MDAT>";
442 static GNode *qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc);
443 static GNode *qtdemux_tree_get_child_by_type_full (GNode * node,
444 guint32 fourcc, GstByteReader * parser);
445 static GNode *qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc);
446 static GNode *qtdemux_tree_get_sibling_by_type_full (GNode * node,
447 guint32 fourcc, GstByteReader * parser);
449 static GstFlowReturn qtdemux_add_fragmented_samples (GstQTDemux * qtdemux);
451 static GstStaticPadTemplate gst_qtdemux_sink_template =
452 GST_STATIC_PAD_TEMPLATE ("sink",
455 GST_STATIC_CAPS ("video/quicktime; video/mj2; audio/x-m4a; "
459 static GstStaticPadTemplate gst_qtdemux_videosrc_template =
460 GST_STATIC_PAD_TEMPLATE ("video_%u",
463 GST_STATIC_CAPS_ANY);
465 static GstStaticPadTemplate gst_qtdemux_audiosrc_template =
466 GST_STATIC_PAD_TEMPLATE ("audio_%u",
469 GST_STATIC_CAPS_ANY);
471 static GstStaticPadTemplate gst_qtdemux_subsrc_template =
472 GST_STATIC_PAD_TEMPLATE ("subtitle_%u",
475 GST_STATIC_CAPS_ANY);
477 #define gst_qtdemux_parent_class parent_class
478 G_DEFINE_TYPE (GstQTDemux, gst_qtdemux, GST_TYPE_ELEMENT);
480 static void gst_qtdemux_dispose (GObject * object);
483 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
484 GstClockTime media_time);
486 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
487 QtDemuxStream * str, gint64 media_offset);
490 static void gst_qtdemux_set_index (GstElement * element, GstIndex * index);
491 static GstIndex *gst_qtdemux_get_index (GstElement * element);
493 static GstStateChangeReturn gst_qtdemux_change_state (GstElement * element,
494 GstStateChange transition);
495 static gboolean qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent);
496 static gboolean qtdemux_sink_activate_mode (GstPad * sinkpad,
497 GstObject * parent, GstPadMode mode, gboolean active);
499 static void gst_qtdemux_loop (GstPad * pad);
500 static GstFlowReturn gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent,
502 static gboolean gst_qtdemux_handle_sink_event (GstPad * pad, GstObject * parent,
504 static gboolean gst_qtdemux_setcaps (GstQTDemux * qtdemux, GstCaps * caps);
505 static gboolean gst_qtdemux_configure_stream (GstQTDemux * qtdemux,
506 QtDemuxStream * stream);
507 static GstFlowReturn gst_qtdemux_process_adapter (GstQTDemux * demux,
510 static gboolean qtdemux_parse_moov (GstQTDemux * qtdemux,
511 const guint8 * buffer, guint length);
512 static gboolean qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node,
513 const guint8 * buffer, guint length);
514 static gboolean qtdemux_parse_tree (GstQTDemux * qtdemux);
515 static void qtdemux_parse_udta (GstQTDemux * qtdemux, GstTagList * taglist,
518 static void gst_qtdemux_handle_esds (GstQTDemux * qtdemux,
519 QtDemuxStream * stream, GNode * esds, GstTagList * list);
520 static GstCaps *qtdemux_video_caps (GstQTDemux * qtdemux,
521 QtDemuxStream * stream, guint32 fourcc, const guint8 * stsd_data,
522 gchar ** codec_name);
523 static GstCaps *qtdemux_audio_caps (GstQTDemux * qtdemux,
524 QtDemuxStream * stream, guint32 fourcc, const guint8 * data, int len,
525 gchar ** codec_name);
526 static GstCaps *qtdemux_sub_caps (GstQTDemux * qtdemux,
527 QtDemuxStream * stream, guint32 fourcc, const guint8 * data,
528 gchar ** codec_name);
529 static GstCaps *qtdemux_generic_caps (GstQTDemux * qtdemux,
530 QtDemuxStream * stream, guint32 fourcc, const guint8 * stsd_data,
531 gchar ** codec_name);
533 static gboolean qtdemux_parse_samples (GstQTDemux * qtdemux,
534 QtDemuxStream * stream, guint32 n);
535 static GstFlowReturn qtdemux_expose_streams (GstQTDemux * qtdemux);
536 static void gst_qtdemux_stream_free (GstQTDemux * qtdemux,
537 QtDemuxStream * stream);
538 static void gst_qtdemux_stream_clear (GstQTDemux * qtdemux,
539 QtDemuxStream * stream);
540 static void gst_qtdemux_remove_stream (GstQTDemux * qtdemux, int index);
541 static GstFlowReturn qtdemux_prepare_streams (GstQTDemux * qtdemux);
542 static void qtdemux_do_allocation (GstQTDemux * qtdemux,
543 QtDemuxStream * stream);
544 static gboolean gst_qtdemux_activate_segment (GstQTDemux * qtdemux,
545 QtDemuxStream * stream, guint32 seg_idx, GstClockTime offset);
546 static gboolean gst_qtdemux_stream_update_segment (GstQTDemux * qtdemux,
547 QtDemuxStream * stream, gint seg_idx, GstClockTime offset,
548 GstClockTime * _start, GstClockTime * _stop);
549 static void gst_qtdemux_send_gap_for_segment (GstQTDemux * demux,
550 QtDemuxStream * stream, gint segment_index, GstClockTime pos);
552 static gboolean qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux);
553 static void check_update_duration (GstQTDemux * qtdemux, GstClockTime duration);
555 static gchar *qtdemux_uuid_bytes_to_string (gconstpointer uuid_bytes);
557 static GstStructure *qtdemux_get_cenc_sample_properties (GstQTDemux * qtdemux,
558 QtDemuxStream * stream, guint sample_index);
559 static void gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux,
561 static void qtdemux_gst_structure_free (GstStructure * gststructure);
564 gst_qtdemux_class_init (GstQTDemuxClass * klass)
566 GObjectClass *gobject_class;
567 GstElementClass *gstelement_class;
569 gobject_class = (GObjectClass *) klass;
570 gstelement_class = (GstElementClass *) klass;
572 parent_class = g_type_class_peek_parent (klass);
574 gobject_class->dispose = gst_qtdemux_dispose;
576 gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_qtdemux_change_state);
578 gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_qtdemux_set_index);
579 gstelement_class->get_index = GST_DEBUG_FUNCPTR (gst_qtdemux_get_index);
582 gst_tag_register_musicbrainz_tags ();
584 gst_element_class_add_static_pad_template (gstelement_class,
585 &gst_qtdemux_sink_template);
586 gst_element_class_add_static_pad_template (gstelement_class,
587 &gst_qtdemux_videosrc_template);
588 gst_element_class_add_static_pad_template (gstelement_class,
589 &gst_qtdemux_audiosrc_template);
590 gst_element_class_add_static_pad_template (gstelement_class,
591 &gst_qtdemux_subsrc_template);
592 gst_element_class_set_static_metadata (gstelement_class, "QuickTime demuxer",
594 "Demultiplex a QuickTime file into audio and video streams",
595 "David Schleef <ds@schleef.org>, Wim Taymans <wim@fluendo.com>");
597 GST_DEBUG_CATEGORY_INIT (qtdemux_debug, "qtdemux", 0, "qtdemux plugin");
602 gst_qtdemux_init (GstQTDemux * qtdemux)
605 gst_pad_new_from_static_template (&gst_qtdemux_sink_template, "sink");
606 gst_pad_set_activate_function (qtdemux->sinkpad, qtdemux_sink_activate);
607 gst_pad_set_activatemode_function (qtdemux->sinkpad,
608 qtdemux_sink_activate_mode);
609 gst_pad_set_chain_function (qtdemux->sinkpad, gst_qtdemux_chain);
610 gst_pad_set_event_function (qtdemux->sinkpad, gst_qtdemux_handle_sink_event);
611 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), qtdemux->sinkpad);
613 qtdemux->state = QTDEMUX_STATE_INITIAL;
614 qtdemux->pullbased = FALSE;
615 qtdemux->posted_redirect = FALSE;
616 qtdemux->neededbytes = 16;
618 qtdemux->adapter = gst_adapter_new ();
620 qtdemux->first_mdat = -1;
621 qtdemux->got_moov = FALSE;
622 qtdemux->mdatoffset = -1;
623 qtdemux->mdatbuffer = NULL;
624 qtdemux->restoredata_buffer = NULL;
625 qtdemux->restoredata_offset = -1;
626 qtdemux->fragment_start = -1;
627 qtdemux->fragment_start_offset = -1;
628 qtdemux->media_caps = NULL;
629 qtdemux->exposed = FALSE;
630 qtdemux->mss_mode = FALSE;
631 qtdemux->pending_newsegment = NULL;
632 qtdemux->upstream_format_is_time = FALSE;
633 qtdemux->have_group_id = FALSE;
634 qtdemux->group_id = G_MAXUINT;
635 qtdemux->cenc_aux_info_offset = 0;
636 qtdemux->cenc_aux_info_sizes = NULL;
637 qtdemux->cenc_aux_sample_count = 0;
638 qtdemux->protection_system_ids = NULL;
639 g_queue_init (&qtdemux->protection_event_queue);
640 gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
641 qtdemux->flowcombiner = gst_flow_combiner_new ();
643 GST_OBJECT_FLAG_SET (qtdemux, GST_ELEMENT_FLAG_INDEXABLE);
647 gst_qtdemux_dispose (GObject * object)
649 GstQTDemux *qtdemux = GST_QTDEMUX (object);
651 if (qtdemux->adapter) {
652 g_object_unref (G_OBJECT (qtdemux->adapter));
653 qtdemux->adapter = NULL;
655 gst_flow_combiner_free (qtdemux->flowcombiner);
656 g_queue_foreach (&qtdemux->protection_event_queue, (GFunc) gst_event_unref,
658 g_queue_clear (&qtdemux->protection_event_queue);
660 g_free (qtdemux->cenc_aux_info_sizes);
661 qtdemux->cenc_aux_info_sizes = NULL;
663 G_OBJECT_CLASS (parent_class)->dispose (object);
667 gst_qtdemux_post_no_playable_stream_error (GstQTDemux * qtdemux)
669 if (qtdemux->posted_redirect) {
670 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
671 (_("This file contains no playable streams.")),
672 ("no known streams found, a redirect message has been posted"));
674 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
675 (_("This file contains no playable streams.")),
676 ("no known streams found"));
681 _gst_buffer_new_wrapped (gpointer mem, gsize size, GFreeFunc free_func)
683 return gst_buffer_new_wrapped_full (free_func ? 0 : GST_MEMORY_FLAG_READONLY,
684 mem, size, 0, size, mem, free_func);
688 gst_qtdemux_pull_atom (GstQTDemux * qtdemux, guint64 offset, guint64 size,
695 if (G_UNLIKELY (size == 0)) {
697 GstBuffer *tmp = NULL;
699 ret = gst_qtdemux_pull_atom (qtdemux, offset, sizeof (guint32), &tmp);
700 if (ret != GST_FLOW_OK)
703 gst_buffer_map (tmp, &map, GST_MAP_READ);
704 size = QT_UINT32 (map.data);
705 GST_DEBUG_OBJECT (qtdemux, "size 0x%08" G_GINT64_MODIFIER "x", size);
707 gst_buffer_unmap (tmp, &map);
708 gst_buffer_unref (tmp);
711 /* Sanity check: catch bogus sizes (fuzzed/broken files) */
712 if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
713 if (qtdemux->state != QTDEMUX_STATE_MOVIE && qtdemux->got_moov) {
714 /* we're pulling header but already got most interesting bits,
715 * so never mind the rest (e.g. tags) (that much) */
716 GST_WARNING_OBJECT (qtdemux, "atom has bogus size %" G_GUINT64_FORMAT,
720 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
721 (_("This file is invalid and cannot be played.")),
722 ("atom has bogus size %" G_GUINT64_FORMAT, size));
723 return GST_FLOW_ERROR;
727 flow = gst_pad_pull_range (qtdemux->sinkpad, offset, size, buf);
729 if (G_UNLIKELY (flow != GST_FLOW_OK))
732 bsize = gst_buffer_get_size (*buf);
733 /* Catch short reads - we don't want any partial atoms */
734 if (G_UNLIKELY (bsize < size)) {
735 GST_WARNING_OBJECT (qtdemux,
736 "short read: %" G_GSIZE_FORMAT " < %" G_GUINT64_FORMAT, bsize, size);
737 gst_buffer_unref (*buf);
747 gst_qtdemux_src_convert (GstQTDemux * qtdemux, GstPad * pad,
748 GstFormat src_format, gint64 src_value, GstFormat dest_format,
752 QtDemuxStream *stream = gst_pad_get_element_private (pad);
755 if (stream->subtype != FOURCC_vide) {
760 switch (src_format) {
761 case GST_FORMAT_TIME:
762 switch (dest_format) {
763 case GST_FORMAT_BYTES:{
764 index = gst_qtdemux_find_index_linear (qtdemux, stream, src_value);
770 *dest_value = stream->samples[index].offset;
772 GST_DEBUG_OBJECT (qtdemux, "Format Conversion Time->Offset :%"
773 GST_TIME_FORMAT "->%" G_GUINT64_FORMAT,
774 GST_TIME_ARGS (src_value), *dest_value);
782 case GST_FORMAT_BYTES:
783 switch (dest_format) {
784 case GST_FORMAT_TIME:{
786 gst_qtdemux_find_index_for_given_media_offset_linear (qtdemux,
795 QTSTREAMTIME_TO_GSTTIME (stream,
796 stream->samples[index].timestamp);
797 GST_DEBUG_OBJECT (qtdemux,
798 "Format Conversion Offset->Time :%" G_GUINT64_FORMAT "->%"
799 GST_TIME_FORMAT, src_value, GST_TIME_ARGS (*dest_value));
818 gst_qtdemux_get_duration (GstQTDemux * qtdemux, GstClockTime * duration)
820 gboolean res = FALSE;
822 *duration = GST_CLOCK_TIME_NONE;
824 if (qtdemux->duration != 0 &&
825 qtdemux->duration != G_MAXINT64 && qtdemux->timescale != 0) {
826 *duration = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
829 *duration = GST_CLOCK_TIME_NONE;
836 gst_qtdemux_handle_src_query (GstPad * pad, GstObject * parent,
839 gboolean res = FALSE;
840 GstQTDemux *qtdemux = GST_QTDEMUX (parent);
842 GST_LOG_OBJECT (pad, "%s query", GST_QUERY_TYPE_NAME (query));
844 switch (GST_QUERY_TYPE (query)) {
845 case GST_QUERY_POSITION:{
848 gst_query_parse_position (query, &fmt, NULL);
849 if (fmt == GST_FORMAT_TIME
850 && GST_CLOCK_TIME_IS_VALID (qtdemux->segment.position)) {
851 gst_query_set_position (query, GST_FORMAT_TIME,
852 qtdemux->segment.position);
857 case GST_QUERY_DURATION:{
860 gst_query_parse_duration (query, &fmt, NULL);
861 if (fmt == GST_FORMAT_TIME) {
862 /* First try to query upstream */
863 res = gst_pad_query_default (pad, parent, query);
865 GstClockTime duration;
866 if (gst_qtdemux_get_duration (qtdemux, &duration) && duration > 0) {
867 gst_query_set_duration (query, GST_FORMAT_TIME, duration);
874 case GST_QUERY_CONVERT:{
875 GstFormat src_fmt, dest_fmt;
876 gint64 src_value, dest_value = 0;
878 gst_query_parse_convert (query, &src_fmt, &src_value, &dest_fmt, NULL);
880 res = gst_qtdemux_src_convert (qtdemux, pad,
881 src_fmt, src_value, dest_fmt, &dest_value);
883 gst_query_set_convert (query, src_fmt, src_value, dest_fmt, dest_value);
888 case GST_QUERY_FORMATS:
889 gst_query_set_formats (query, 2, GST_FORMAT_TIME, GST_FORMAT_BYTES);
892 case GST_QUERY_SEEKING:{
896 /* try upstream first */
897 res = gst_pad_query_default (pad, parent, query);
900 gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
901 if (fmt == GST_FORMAT_TIME) {
902 GstClockTime duration;
904 gst_qtdemux_get_duration (qtdemux, &duration);
906 if (!qtdemux->pullbased) {
909 /* we might be able with help from upstream */
911 q = gst_query_new_seeking (GST_FORMAT_BYTES);
912 if (gst_pad_peer_query (qtdemux->sinkpad, q)) {
913 gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL);
914 GST_LOG_OBJECT (qtdemux, "upstream BYTE seekable %d", seekable);
918 gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0, duration);
924 case GST_QUERY_SEGMENT:
929 format = qtdemux->segment.format;
932 gst_segment_to_stream_time (&qtdemux->segment, format,
933 qtdemux->segment.start);
934 if ((stop = qtdemux->segment.stop) == -1)
935 stop = qtdemux->segment.duration;
937 stop = gst_segment_to_stream_time (&qtdemux->segment, format, stop);
939 gst_query_set_segment (query, qtdemux->segment.rate, format, start, stop);
944 res = gst_pad_query_default (pad, parent, query);
952 gst_qtdemux_push_tags (GstQTDemux * qtdemux, QtDemuxStream * stream)
954 if (G_LIKELY (stream->pad)) {
955 GST_DEBUG_OBJECT (qtdemux, "Checking pad %s:%s for tags",
956 GST_DEBUG_PAD_NAME (stream->pad));
958 if (G_UNLIKELY (stream->pending_tags)) {
959 GST_DEBUG_OBJECT (qtdemux, "Sending tags %" GST_PTR_FORMAT,
960 stream->pending_tags);
961 gst_pad_push_event (stream->pad,
962 gst_event_new_tag (stream->pending_tags));
963 stream->pending_tags = NULL;
966 if (G_UNLIKELY (stream->send_global_tags && qtdemux->tag_list)) {
967 GST_DEBUG_OBJECT (qtdemux, "Sending global tags %" GST_PTR_FORMAT,
969 gst_pad_push_event (stream->pad,
970 gst_event_new_tag (gst_tag_list_ref (qtdemux->tag_list)));
971 stream->send_global_tags = FALSE;
976 /* push event on all source pads; takes ownership of the event */
978 gst_qtdemux_push_event (GstQTDemux * qtdemux, GstEvent * event)
981 gboolean has_valid_stream = FALSE;
982 GstEventType etype = GST_EVENT_TYPE (event);
984 GST_DEBUG_OBJECT (qtdemux, "pushing %s event on all source pads",
985 GST_EVENT_TYPE_NAME (event));
987 for (n = 0; n < qtdemux->n_streams; n++) {
989 QtDemuxStream *stream = qtdemux->streams[n];
990 GST_DEBUG_OBJECT (qtdemux, "pushing on pad %i", n);
992 if ((pad = stream->pad)) {
993 has_valid_stream = TRUE;
995 if (etype == GST_EVENT_EOS) {
996 /* let's not send twice */
997 if (stream->sent_eos)
999 stream->sent_eos = TRUE;
1002 gst_pad_push_event (pad, gst_event_ref (event));
1006 gst_event_unref (event);
1008 /* if it is EOS and there are no pads, post an error */
1009 if (!has_valid_stream && etype == GST_EVENT_EOS) {
1010 gst_qtdemux_post_no_playable_stream_error (qtdemux);
1014 /* push a pending newsegment event, if any from the streaming thread */
1016 gst_qtdemux_push_pending_newsegment (GstQTDemux * qtdemux)
1018 if (qtdemux->pending_newsegment) {
1019 gst_qtdemux_push_event (qtdemux, qtdemux->pending_newsegment);
1020 qtdemux->pending_newsegment = NULL;
1030 find_func (QtDemuxSample * s1, gint64 * media_time, gpointer user_data)
1032 if ((gint64) s1->timestamp + s1->pts_offset > *media_time)
1034 if ((gint64) s1->timestamp + s1->pts_offset == *media_time)
1040 /* find the index of the sample that includes the data for @media_time using a
1041 * binary search. Only to be called in optimized cases of linear search below.
1043 * Returns the index of the sample.
1046 gst_qtdemux_find_index (GstQTDemux * qtdemux, QtDemuxStream * str,
1049 QtDemuxSample *result;
1052 /* convert media_time to mov format */
1054 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
1056 result = gst_util_array_binary_search (str->samples, str->stbl_index + 1,
1057 sizeof (QtDemuxSample), (GCompareDataFunc) find_func,
1058 GST_SEARCH_MODE_BEFORE, &media_time, NULL);
1060 if (G_LIKELY (result))
1061 index = result - str->samples;
1070 /* find the index of the sample that includes the data for @media_offset using a
1073 * Returns the index of the sample.
1076 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
1077 QtDemuxStream * str, gint64 media_offset)
1079 QtDemuxSample *result = str->samples;
1082 if (result == NULL || str->n_samples == 0)
1085 if (media_offset == result->offset)
1089 while (index < str->n_samples - 1) {
1090 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
1093 if (media_offset < result->offset)
1104 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
1109 /* find the index of the sample that includes the data for @media_time using a
1110 * linear search, and keeping in mind that not all samples may have been parsed
1111 * yet. If possible, it will delegate to binary search.
1113 * Returns the index of the sample.
1116 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
1117 GstClockTime media_time)
1121 QtDemuxSample *sample;
1123 /* convert media_time to mov format */
1125 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
1127 sample = str->samples;
1128 if (mov_time == sample->timestamp + sample->pts_offset)
1131 /* use faster search if requested time in already parsed range */
1132 sample = str->samples + str->stbl_index;
1133 if (str->stbl_index >= 0 &&
1134 mov_time <= (sample->timestamp + sample->pts_offset))
1135 return gst_qtdemux_find_index (qtdemux, str, media_time);
1137 while (index < str->n_samples - 1) {
1138 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
1141 sample = str->samples + index + 1;
1142 if (mov_time < (sample->timestamp + sample->pts_offset))
1152 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
1157 /* find the index of the keyframe needed to decode the sample at @index
1160 * Returns the index of the keyframe.
1163 gst_qtdemux_find_keyframe (GstQTDemux * qtdemux, QtDemuxStream * str,
1166 guint32 new_index = index;
1168 if (index >= str->n_samples) {
1169 new_index = str->n_samples;
1173 /* all keyframes, return index */
1174 if (str->all_keyframe) {
1179 /* else go back until we have a keyframe */
1181 if (str->samples[new_index].keyframe)
1191 GST_DEBUG_OBJECT (qtdemux, "searching for keyframe index before index %u "
1192 "gave %u", index, new_index);
1197 /* find the segment for @time_position for @stream
1199 * Returns the index of the segment containing @time_position.
1200 * Returns the last segment and sets the @eos variable to TRUE
1201 * if the time is beyond the end. @eos may be NULL
1204 gst_qtdemux_find_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
1205 GstClockTime time_position)
1210 GST_LOG_OBJECT (stream->pad, "finding segment for %" GST_TIME_FORMAT,
1211 GST_TIME_ARGS (time_position));
1214 for (i = 0; i < stream->n_segments; i++) {
1215 QtDemuxSegment *segment = &stream->segments[i];
1217 GST_LOG_OBJECT (stream->pad,
1218 "looking at segment %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT,
1219 GST_TIME_ARGS (segment->time), GST_TIME_ARGS (segment->stop_time));
1221 /* For the last segment we include stop_time in the last segment */
1222 if (i < stream->n_segments - 1) {
1223 if (segment->time <= time_position && time_position < segment->stop_time) {
1224 GST_LOG_OBJECT (stream->pad, "segment %d matches", i);
1229 /* Last segment always matches */
1237 /* move the stream @str to the sample position @index.
1239 * Updates @str->sample_index and marks discontinuity if needed.
1242 gst_qtdemux_move_stream (GstQTDemux * qtdemux, QtDemuxStream * str,
1245 /* no change needed */
1246 if (index == str->sample_index)
1249 GST_DEBUG_OBJECT (qtdemux, "moving to sample %u of %u", index,
1252 /* position changed, we have a discont */
1253 str->sample_index = index;
1254 str->offset_in_sample = 0;
1255 /* Each time we move in the stream we store the position where we are
1257 str->from_sample = index;
1258 str->discont = TRUE;
1262 gst_qtdemux_adjust_seek (GstQTDemux * qtdemux, gint64 desired_time,
1263 gboolean use_sparse, gint64 * key_time, gint64 * key_offset)
1266 gint64 min_byte_offset = -1;
1269 min_offset = desired_time;
1271 /* for each stream, find the index of the sample in the segment
1272 * and move back to the previous keyframe. */
1273 for (n = 0; n < qtdemux->n_streams; n++) {
1275 guint32 index, kindex;
1277 GstClockTime media_start;
1278 GstClockTime media_time;
1279 GstClockTime seg_time;
1280 QtDemuxSegment *seg;
1281 gboolean empty_segment = FALSE;
1283 str = qtdemux->streams[n];
1285 if (str->sparse && !use_sparse)
1288 seg_idx = gst_qtdemux_find_segment (qtdemux, str, desired_time);
1289 GST_DEBUG_OBJECT (qtdemux, "align segment %d", seg_idx);
1291 /* get segment and time in the segment */
1292 seg = &str->segments[seg_idx];
1293 seg_time = (desired_time - seg->time) * seg->rate;
1295 while (QTSEGMENT_IS_EMPTY (seg)) {
1297 empty_segment = TRUE;
1298 GST_DEBUG_OBJECT (str->pad, "Segment %d is empty, moving to next one",
1301 if (seg_idx == str->n_segments)
1303 seg = &str->segments[seg_idx];
1306 if (seg_idx == str->n_segments) {
1307 /* FIXME track shouldn't have the last segment as empty, but if it
1308 * happens we better handle it */
1312 /* get the media time in the segment */
1313 media_start = seg->media_start + seg_time;
1315 /* get the index of the sample with media time */
1316 index = gst_qtdemux_find_index_linear (qtdemux, str, media_start);
1317 GST_DEBUG_OBJECT (qtdemux, "sample for %" GST_TIME_FORMAT " at %u"
1318 " at offset %" G_GUINT64_FORMAT " (empty segment: %d)",
1319 GST_TIME_ARGS (media_start), index, str->samples[index].offset,
1322 if (!empty_segment) {
1323 /* find previous keyframe */
1324 kindex = gst_qtdemux_find_keyframe (qtdemux, str, index);
1326 /* if the keyframe is at a different position, we need to update the
1327 * requested seek time */
1328 if (index != kindex) {
1331 /* get timestamp of keyframe */
1332 media_time = QTSAMPLE_DTS (str, &str->samples[kindex]);
1333 GST_DEBUG_OBJECT (qtdemux,
1334 "keyframe at %u with time %" GST_TIME_FORMAT " at offset %"
1335 G_GUINT64_FORMAT, kindex, GST_TIME_ARGS (media_time),
1336 str->samples[kindex].offset);
1338 /* keyframes in the segment get a chance to change the
1339 * desired_offset. keyframes out of the segment are
1341 if (media_time >= seg->media_start) {
1342 GstClockTime seg_time;
1344 /* this keyframe is inside the segment, convert back to
1346 seg_time = (media_time - seg->media_start) + seg->time;
1347 if (seg_time < min_offset)
1348 min_offset = seg_time;
1353 if (min_byte_offset < 0 || str->samples[index].offset < min_byte_offset)
1354 min_byte_offset = str->samples[index].offset;
1358 *key_time = min_offset;
1360 *key_offset = min_byte_offset;
1364 gst_qtdemux_convert_seek (GstPad * pad, GstFormat * format,
1365 GstSeekType cur_type, gint64 * cur, GstSeekType stop_type, gint64 * stop)
1369 g_return_val_if_fail (format != NULL, FALSE);
1370 g_return_val_if_fail (cur != NULL, FALSE);
1371 g_return_val_if_fail (stop != NULL, FALSE);
1373 if (*format == GST_FORMAT_TIME)
1377 if (cur_type != GST_SEEK_TYPE_NONE)
1378 res = gst_pad_query_convert (pad, *format, *cur, GST_FORMAT_TIME, cur);
1379 if (res && stop_type != GST_SEEK_TYPE_NONE)
1380 res = gst_pad_query_convert (pad, *format, *stop, GST_FORMAT_TIME, stop);
1383 *format = GST_FORMAT_TIME;
1388 /* perform seek in push based mode:
1389 find BYTE position to move to based on time and delegate to upstream
1392 gst_qtdemux_do_push_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1397 GstSeekType cur_type, stop_type;
1398 gint64 cur, stop, key_cur;
1401 gint64 original_stop;
1404 GST_DEBUG_OBJECT (qtdemux, "doing push-based seek");
1406 gst_event_parse_seek (event, &rate, &format, &flags,
1407 &cur_type, &cur, &stop_type, &stop);
1408 seqnum = gst_event_get_seqnum (event);
1410 /* only forward streaming and seeking is possible */
1412 goto unsupported_seek;
1414 /* convert to TIME if needed and possible */
1415 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1419 /* Upstream seek in bytes will have undefined stop, but qtdemux stores
1420 * the original stop position to use when upstream pushes the new segment
1422 original_stop = stop;
1425 /* find reasonable corresponding BYTE position,
1426 * also try to mind about keyframes, since we can not go back a bit for them
1428 gst_qtdemux_adjust_seek (qtdemux, cur, FALSE, &key_cur, &byte_cur);
1433 GST_DEBUG_OBJECT (qtdemux, "Pushing BYTE seek rate %g, "
1434 "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, byte_cur,
1437 GST_OBJECT_LOCK (qtdemux);
1438 qtdemux->seek_offset = byte_cur;
1439 if (!(flags & GST_SEEK_FLAG_KEY_UNIT)) {
1440 qtdemux->push_seek_start = cur;
1442 qtdemux->push_seek_start = key_cur;
1445 if (stop_type == GST_SEEK_TYPE_NONE) {
1446 qtdemux->push_seek_stop = qtdemux->segment.stop;
1448 qtdemux->push_seek_stop = original_stop;
1450 GST_OBJECT_UNLOCK (qtdemux);
1452 /* BYTE seek event */
1453 event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type, byte_cur,
1455 gst_event_set_seqnum (event, seqnum);
1456 res = gst_pad_push_event (qtdemux->sinkpad, event);
1463 GST_DEBUG_OBJECT (qtdemux, "could not determine byte position to seek to, "
1469 GST_DEBUG_OBJECT (qtdemux, "unsupported seek, seek aborted.");
1474 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1479 /* perform the seek.
1481 * We set all segment_indexes in the streams to unknown and
1482 * adjust the time_position to the desired position. this is enough
1483 * to trigger a segment switch in the streaming thread to start
1484 * streaming from the desired position.
1486 * Keyframe seeking is a little more complicated when dealing with
1487 * segments. Ideally we want to move to the previous keyframe in
1488 * the segment but there might not be a keyframe in the segment. In
1489 * fact, none of the segments could contain a keyframe. We take a
1490 * practical approach: seek to the previous keyframe in the segment,
1491 * if there is none, seek to the beginning of the segment.
1493 * Called with STREAM_LOCK
1496 gst_qtdemux_perform_seek (GstQTDemux * qtdemux, GstSegment * segment,
1497 guint32 seqnum, GstSeekFlags flags)
1499 gint64 desired_offset;
1502 desired_offset = segment->position;
1504 GST_DEBUG_OBJECT (qtdemux, "seeking to %" GST_TIME_FORMAT,
1505 GST_TIME_ARGS (desired_offset));
1507 /* may not have enough fragmented info to do this adjustment,
1508 * and we can't scan (and probably should not) at this time with
1509 * possibly flushing upstream */
1510 if ((flags & GST_SEEK_FLAG_KEY_UNIT) && !qtdemux->fragmented) {
1513 gst_qtdemux_adjust_seek (qtdemux, desired_offset, TRUE, &min_offset, NULL);
1514 GST_DEBUG_OBJECT (qtdemux, "keyframe seek, align to %"
1515 GST_TIME_FORMAT, GST_TIME_ARGS (min_offset));
1516 desired_offset = min_offset;
1519 /* and set all streams to the final position */
1520 gst_flow_combiner_reset (qtdemux->flowcombiner);
1521 qtdemux->segment_seqnum = seqnum;
1522 for (n = 0; n < qtdemux->n_streams; n++) {
1523 QtDemuxStream *stream = qtdemux->streams[n];
1525 stream->time_position = desired_offset;
1526 stream->accumulated_base = 0;
1527 stream->sample_index = -1;
1528 stream->offset_in_sample = 0;
1529 stream->segment_index = -1;
1530 stream->sent_eos = FALSE;
1532 if (segment->flags & GST_SEEK_FLAG_FLUSH)
1533 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
1535 segment->position = desired_offset;
1536 segment->time = desired_offset;
1537 if (segment->rate >= 0) {
1538 segment->start = desired_offset;
1540 /* we stop at the end */
1541 if (segment->stop == -1)
1542 segment->stop = segment->duration;
1544 segment->stop = desired_offset;
1547 if (qtdemux->fragmented)
1548 qtdemux->fragmented_seek_pending = TRUE;
1553 /* do a seek in pull based mode */
1555 gst_qtdemux_do_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1560 GstSeekType cur_type, stop_type;
1564 GstSegment seeksegment;
1566 GstEvent *flush_event;
1569 GST_DEBUG_OBJECT (qtdemux, "doing seek with event");
1571 gst_event_parse_seek (event, &rate, &format, &flags,
1572 &cur_type, &cur, &stop_type, &stop);
1573 seqnum = gst_event_get_seqnum (event);
1575 /* we have to have a format as the segment format. Try to convert
1577 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1581 GST_DEBUG_OBJECT (qtdemux, "seek format %s", gst_format_get_name (format));
1583 GST_DEBUG_OBJECT (qtdemux, "doing seek without event");
1587 flush = flags & GST_SEEK_FLAG_FLUSH;
1589 /* stop streaming, either by flushing or by pausing the task */
1591 flush_event = gst_event_new_flush_start ();
1593 gst_event_set_seqnum (flush_event, seqnum);
1594 /* unlock upstream pull_range */
1595 gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event));
1596 /* make sure out loop function exits */
1597 gst_qtdemux_push_event (qtdemux, flush_event);
1599 /* non flushing seek, pause the task */
1600 gst_pad_pause_task (qtdemux->sinkpad);
1603 /* wait for streaming to finish */
1604 GST_PAD_STREAM_LOCK (qtdemux->sinkpad);
1606 /* copy segment, we need this because we still need the old
1607 * segment when we close the current segment. */
1608 memcpy (&seeksegment, &qtdemux->segment, sizeof (GstSegment));
1611 /* configure the segment with the seek variables */
1612 GST_DEBUG_OBJECT (qtdemux, "configuring seek");
1613 gst_segment_do_seek (&seeksegment, rate, format, flags,
1614 cur_type, cur, stop_type, stop, &update);
1617 /* now do the seek, this actually never returns FALSE */
1618 gst_qtdemux_perform_seek (qtdemux, &seeksegment, seqnum, flags);
1620 /* prepare for streaming again */
1622 flush_event = gst_event_new_flush_stop (TRUE);
1624 gst_event_set_seqnum (flush_event, seqnum);
1626 gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event));
1627 gst_qtdemux_push_event (qtdemux, flush_event);
1630 /* commit the new segment */
1631 memcpy (&qtdemux->segment, &seeksegment, sizeof (GstSegment));
1633 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
1634 GstMessage *msg = gst_message_new_segment_start (GST_OBJECT_CAST (qtdemux),
1635 qtdemux->segment.format, qtdemux->segment.position);
1637 gst_message_set_seqnum (msg, seqnum);
1638 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
1641 /* restart streaming, NEWSEGMENT will be sent from the streaming thread. */
1642 gst_pad_start_task (qtdemux->sinkpad, (GstTaskFunction) gst_qtdemux_loop,
1643 qtdemux->sinkpad, NULL);
1645 GST_PAD_STREAM_UNLOCK (qtdemux->sinkpad);
1652 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1658 qtdemux_ensure_index (GstQTDemux * qtdemux)
1662 GST_DEBUG_OBJECT (qtdemux, "collecting all metadata for all streams");
1664 /* Build complete index */
1665 for (i = 0; i < qtdemux->n_streams; i++) {
1666 QtDemuxStream *stream = qtdemux->streams[i];
1668 if (!qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1))
1676 GST_LOG_OBJECT (qtdemux,
1677 "Building complete index of stream %u for seeking failed!", i);
1683 gst_qtdemux_handle_src_event (GstPad * pad, GstObject * parent,
1686 gboolean res = TRUE;
1687 GstQTDemux *qtdemux = GST_QTDEMUX (parent);
1689 switch (GST_EVENT_TYPE (event)) {
1690 case GST_EVENT_SEEK:
1692 #ifndef GST_DISABLE_GST_DEBUG
1693 GstClockTime ts = gst_util_get_timestamp ();
1696 if (qtdemux->upstream_format_is_time && qtdemux->fragmented) {
1697 /* seek should be handled by upstream, we might need to re-download fragments */
1698 GST_DEBUG_OBJECT (qtdemux,
1699 "let upstream handle seek for fragmented playback");
1703 /* Build complete index for seeking;
1704 * if not a fragmented file at least */
1705 if (!qtdemux->fragmented)
1706 if (!qtdemux_ensure_index (qtdemux))
1708 #ifndef GST_DISABLE_GST_DEBUG
1709 ts = gst_util_get_timestamp () - ts;
1710 GST_INFO_OBJECT (qtdemux,
1711 "Time taken to parse index %" GST_TIME_FORMAT, GST_TIME_ARGS (ts));
1714 if (qtdemux->pullbased) {
1715 res = gst_qtdemux_do_seek (qtdemux, pad, event);
1716 } else if (gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (event))) {
1717 GST_DEBUG_OBJECT (qtdemux, "Upstream successfully seeked");
1719 } else if (qtdemux->state == QTDEMUX_STATE_MOVIE && qtdemux->n_streams
1720 && !qtdemux->fragmented) {
1721 res = gst_qtdemux_do_push_seek (qtdemux, pad, event);
1723 GST_DEBUG_OBJECT (qtdemux,
1724 "ignoring seek in push mode in current state");
1727 gst_event_unref (event);
1731 res = gst_pad_event_default (pad, parent, event);
1741 GST_ERROR_OBJECT (qtdemux, "Index failed");
1742 gst_event_unref (event);
1748 /* stream/index return sample that is min/max w.r.t. byte position,
1749 * time is min/max w.r.t. time of samples,
1750 * the latter need not be time of the former sample */
1752 gst_qtdemux_find_sample (GstQTDemux * qtdemux, gint64 byte_pos, gboolean fw,
1753 gboolean set, QtDemuxStream ** _stream, gint * _index, gint64 * _time)
1756 gint64 time, min_time;
1757 QtDemuxStream *stream;
1763 for (n = 0; n < qtdemux->n_streams; ++n) {
1766 gboolean set_sample;
1768 str = qtdemux->streams[n];
1775 i = str->n_samples - 1;
1779 for (; (i >= 0) && (i < str->n_samples); i += inc) {
1780 if (str->samples[i].size == 0)
1783 if (fw && (str->samples[i].offset < byte_pos))
1786 if (!fw && (str->samples[i].offset + str->samples[i].size > byte_pos))
1789 /* move stream to first available sample */
1791 gst_qtdemux_move_stream (qtdemux, str, i);
1795 /* avoid index from sparse streams since they might be far away */
1797 /* determine min/max time */
1798 time = QTSAMPLE_PTS (str, &str->samples[i]);
1799 if (min_time == -1 || (!fw && time > min_time) ||
1800 (fw && time < min_time)) {
1804 /* determine stream with leading sample, to get its position */
1806 (fw && (str->samples[i].offset < stream->samples[index].offset)) ||
1807 (!fw && (str->samples[i].offset > stream->samples[index].offset))) {
1815 /* no sample for this stream, mark eos */
1817 gst_qtdemux_move_stream (qtdemux, str, str->n_samples);
1828 static QtDemuxStream *
1829 _create_stream (void)
1831 QtDemuxStream *stream;
1833 stream = g_new0 (QtDemuxStream, 1);
1834 /* new streams always need a discont */
1835 stream->discont = TRUE;
1836 /* we enable clipping for raw audio/video streams */
1837 stream->need_clip = FALSE;
1838 stream->need_process = FALSE;
1839 stream->segment_index = -1;
1840 stream->time_position = 0;
1841 stream->sample_index = -1;
1842 stream->offset_in_sample = 0;
1843 stream->new_stream = TRUE;
1844 stream->multiview_mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
1845 stream->multiview_flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
1846 stream->protected = FALSE;
1847 stream->protection_scheme_type = 0;
1848 stream->protection_scheme_version = 0;
1849 stream->protection_scheme_info = NULL;
1850 stream->n_samples_moof = 0;
1851 stream->duration_moof = 0;
1852 stream->duration_last_moof = 0;
1853 stream->alignment = 1;
1854 g_queue_init (&stream->protection_scheme_event_queue);
1859 gst_qtdemux_setcaps (GstQTDemux * demux, GstCaps * caps)
1861 GstStructure *structure;
1862 const gchar *variant;
1863 const GstCaps *mediacaps = NULL;
1865 GST_DEBUG_OBJECT (demux, "Sink set caps: %" GST_PTR_FORMAT, caps);
1867 structure = gst_caps_get_structure (caps, 0);
1868 variant = gst_structure_get_string (structure, "variant");
1870 if (variant && strcmp (variant, "mss-fragmented") == 0) {
1871 QtDemuxStream *stream;
1872 const GValue *value;
1874 demux->fragmented = TRUE;
1875 demux->mss_mode = TRUE;
1877 if (demux->n_streams > 1) {
1878 /* can't do this, we can only renegotiate for another mss format */
1882 value = gst_structure_get_value (structure, "media-caps");
1885 const GValue *timescale_v;
1887 /* TODO update when stream changes during playback */
1889 if (demux->n_streams == 0) {
1890 stream = _create_stream ();
1891 demux->streams[demux->n_streams] = stream;
1892 demux->n_streams = 1;
1894 stream = demux->streams[0];
1897 timescale_v = gst_structure_get_value (structure, "timescale");
1899 stream->timescale = g_value_get_uint64 (timescale_v);
1901 /* default mss timescale */
1902 stream->timescale = 10000000;
1904 demux->timescale = stream->timescale;
1906 mediacaps = gst_value_get_caps (value);
1907 if (!stream->caps || !gst_caps_is_equal_fixed (mediacaps, stream->caps)) {
1908 GST_DEBUG_OBJECT (demux, "We have a new caps %" GST_PTR_FORMAT,
1910 stream->new_caps = TRUE;
1912 gst_caps_replace (&stream->caps, (GstCaps *) mediacaps);
1913 structure = gst_caps_get_structure (mediacaps, 0);
1914 if (g_str_has_prefix (gst_structure_get_name (structure), "video")) {
1915 stream->subtype = FOURCC_vide;
1917 gst_structure_get_int (structure, "width", &stream->width);
1918 gst_structure_get_int (structure, "height", &stream->height);
1919 gst_structure_get_fraction (structure, "framerate", &stream->fps_n,
1921 } else if (g_str_has_prefix (gst_structure_get_name (structure), "audio")) {
1923 stream->subtype = FOURCC_soun;
1924 gst_structure_get_int (structure, "channels", &stream->n_channels);
1925 gst_structure_get_int (structure, "rate", &rate);
1926 stream->rate = rate;
1929 gst_caps_replace (&demux->media_caps, (GstCaps *) mediacaps);
1931 demux->mss_mode = FALSE;
1938 gst_qtdemux_reset (GstQTDemux * qtdemux, gboolean hard)
1942 GST_DEBUG_OBJECT (qtdemux, "Resetting demux");
1943 gst_pad_stop_task (qtdemux->sinkpad);
1945 if (hard || qtdemux->upstream_format_is_time) {
1946 qtdemux->state = QTDEMUX_STATE_INITIAL;
1947 qtdemux->neededbytes = 16;
1948 qtdemux->todrop = 0;
1949 qtdemux->pullbased = FALSE;
1950 qtdemux->posted_redirect = FALSE;
1951 qtdemux->first_mdat = -1;
1952 qtdemux->header_size = 0;
1953 qtdemux->mdatoffset = -1;
1954 qtdemux->restoredata_offset = -1;
1955 if (qtdemux->mdatbuffer)
1956 gst_buffer_unref (qtdemux->mdatbuffer);
1957 if (qtdemux->restoredata_buffer)
1958 gst_buffer_unref (qtdemux->restoredata_buffer);
1959 qtdemux->mdatbuffer = NULL;
1960 qtdemux->restoredata_buffer = NULL;
1961 qtdemux->mdatleft = 0;
1962 if (qtdemux->comp_brands)
1963 gst_buffer_unref (qtdemux->comp_brands);
1964 qtdemux->comp_brands = NULL;
1965 qtdemux->last_moov_offset = -1;
1966 if (qtdemux->moov_node)
1967 g_node_destroy (qtdemux->moov_node);
1968 qtdemux->moov_node = NULL;
1969 qtdemux->moov_node_compressed = NULL;
1970 if (qtdemux->tag_list)
1971 gst_mini_object_unref (GST_MINI_OBJECT_CAST (qtdemux->tag_list));
1972 qtdemux->tag_list = NULL;
1974 if (qtdemux->element_index)
1975 gst_object_unref (qtdemux->element_index);
1976 qtdemux->element_index = NULL;
1978 qtdemux->major_brand = 0;
1979 if (qtdemux->pending_newsegment)
1980 gst_event_unref (qtdemux->pending_newsegment);
1981 qtdemux->pending_newsegment = NULL;
1982 qtdemux->upstream_format_is_time = FALSE;
1983 qtdemux->upstream_seekable = FALSE;
1984 qtdemux->upstream_size = 0;
1986 qtdemux->fragment_start = -1;
1987 qtdemux->fragment_start_offset = -1;
1988 qtdemux->duration = 0;
1989 qtdemux->moof_offset = 0;
1990 qtdemux->chapters_track_id = 0;
1991 qtdemux->have_group_id = FALSE;
1992 qtdemux->group_id = G_MAXUINT;
1994 g_queue_foreach (&qtdemux->protection_event_queue, (GFunc) gst_event_unref,
1996 g_queue_clear (&qtdemux->protection_event_queue);
1998 qtdemux->offset = 0;
1999 gst_adapter_clear (qtdemux->adapter);
2000 gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
2001 qtdemux->segment_seqnum = 0;
2004 for (n = 0; n < qtdemux->n_streams; n++) {
2005 gst_qtdemux_stream_free (qtdemux, qtdemux->streams[n]);
2006 qtdemux->streams[n] = NULL;
2008 qtdemux->n_streams = 0;
2009 qtdemux->n_video_streams = 0;
2010 qtdemux->n_audio_streams = 0;
2011 qtdemux->n_sub_streams = 0;
2012 qtdemux->exposed = FALSE;
2013 qtdemux->fragmented = FALSE;
2014 qtdemux->mss_mode = FALSE;
2015 gst_caps_replace (&qtdemux->media_caps, NULL);
2016 qtdemux->timescale = 0;
2017 qtdemux->got_moov = FALSE;
2018 if (qtdemux->protection_system_ids) {
2019 g_ptr_array_free (qtdemux->protection_system_ids, TRUE);
2020 qtdemux->protection_system_ids = NULL;
2022 } else if (qtdemux->mss_mode) {
2023 gst_flow_combiner_reset (qtdemux->flowcombiner);
2024 for (n = 0; n < qtdemux->n_streams; n++)
2025 gst_qtdemux_stream_clear (qtdemux, qtdemux->streams[n]);
2027 gst_flow_combiner_reset (qtdemux->flowcombiner);
2028 for (n = 0; n < qtdemux->n_streams; n++) {
2029 qtdemux->streams[n]->sent_eos = FALSE;
2030 qtdemux->streams[n]->time_position = 0;
2031 qtdemux->streams[n]->accumulated_base = 0;
2033 if (!qtdemux->pending_newsegment) {
2034 qtdemux->pending_newsegment = gst_event_new_segment (&qtdemux->segment);
2035 if (qtdemux->segment_seqnum)
2036 gst_event_set_seqnum (qtdemux->pending_newsegment,
2037 qtdemux->segment_seqnum);
2043 /* Maps the @segment to the qt edts internal segments and pushes
2044 * the correspnding segment event.
2046 * If it ends up being at a empty segment, a gap will be pushed and the next
2047 * edts segment will be activated in sequence.
2049 * To be used in push-mode only */
2051 gst_qtdemux_map_and_push_segments (GstQTDemux * qtdemux, GstSegment * segment)
2055 for (n = 0; n < qtdemux->n_streams; n++) {
2056 QtDemuxStream *stream = qtdemux->streams[n];
2058 stream->time_position = segment->start;
2060 /* in push mode we should be guaranteed that we will have empty segments
2061 * at the beginning and then one segment after, other scenarios are not
2062 * supported and are discarded when parsing the edts */
2063 for (i = 0; i < stream->n_segments; i++) {
2064 if (stream->segments[i].stop_time > segment->start) {
2065 gst_qtdemux_activate_segment (qtdemux, stream, i,
2066 stream->time_position);
2067 if (QTSEGMENT_IS_EMPTY (&stream->segments[i])) {
2068 /* push the empty segment and move to the next one */
2069 gst_qtdemux_send_gap_for_segment (qtdemux, stream, i,
2070 stream->time_position);
2074 g_assert (i == stream->n_segments - 1);
2081 gst_qtdemux_handle_sink_event (GstPad * sinkpad, GstObject * parent,
2084 GstQTDemux *demux = GST_QTDEMUX (parent);
2085 gboolean res = TRUE;
2087 GST_LOG_OBJECT (demux, "handling %s event", GST_EVENT_TYPE_NAME (event));
2089 switch (GST_EVENT_TYPE (event)) {
2090 case GST_EVENT_SEGMENT:
2093 QtDemuxStream *stream;
2097 /* some debug output */
2098 gst_event_copy_segment (event, &segment);
2099 GST_DEBUG_OBJECT (demux, "received newsegment %" GST_SEGMENT_FORMAT,
2102 /* erase any previously set segment */
2103 gst_event_replace (&demux->pending_newsegment, NULL);
2105 if (segment.format == GST_FORMAT_TIME) {
2106 GST_DEBUG_OBJECT (demux, "new pending_newsegment");
2107 gst_event_replace (&demux->pending_newsegment, event);
2108 demux->upstream_format_is_time = TRUE;
2110 GST_DEBUG_OBJECT (demux, "Not storing upstream newsegment, "
2111 "not in time format");
2113 /* chain will send initial newsegment after pads have been added */
2114 if (demux->state != QTDEMUX_STATE_MOVIE || !demux->n_streams) {
2115 GST_DEBUG_OBJECT (demux, "still starting, eating event");
2120 /* check if this matches a time seek we received previously
2121 * FIXME for backwards compatibility reasons we use the
2122 * seek_offset here to compare. In the future we might want to
2123 * change this to use the seqnum as it uniquely should identify
2124 * the segment that corresponds to the seek. */
2125 GST_DEBUG_OBJECT (demux, "Stored seek offset: %" G_GINT64_FORMAT
2126 ", received segment offset %" G_GINT64_FORMAT,
2127 demux->seek_offset, segment.start);
2128 if (segment.format == GST_FORMAT_BYTES
2129 && demux->seek_offset == segment.start) {
2130 GST_OBJECT_LOCK (demux);
2131 offset = segment.start;
2133 segment.format = GST_FORMAT_TIME;
2134 segment.start = demux->push_seek_start;
2135 segment.stop = demux->push_seek_stop;
2136 GST_DEBUG_OBJECT (demux, "Replaced segment with stored seek "
2137 "segment %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT,
2138 GST_TIME_ARGS (segment.start), GST_TIME_ARGS (segment.stop));
2139 GST_OBJECT_UNLOCK (demux);
2142 /* we only expect a BYTE segment, e.g. following a seek */
2143 if (segment.format == GST_FORMAT_BYTES) {
2144 if (GST_CLOCK_TIME_IS_VALID (segment.start)) {
2145 offset = segment.start;
2147 gst_qtdemux_find_sample (demux, segment.start, TRUE, FALSE, NULL,
2148 NULL, (gint64 *) & segment.start);
2149 if ((gint64) segment.start < 0)
2152 if (GST_CLOCK_TIME_IS_VALID (segment.stop)) {
2153 gst_qtdemux_find_sample (demux, segment.stop, FALSE, FALSE, NULL,
2154 NULL, (gint64 *) & segment.stop);
2155 /* keyframe seeking should already arrange for start >= stop,
2156 * but make sure in other rare cases */
2157 segment.stop = MAX (segment.stop, segment.start);
2159 } else if (segment.format == GST_FORMAT_TIME) {
2160 /* push all data on the adapter before starting this
2162 gst_qtdemux_process_adapter (demux, TRUE);
2164 GST_DEBUG_OBJECT (demux, "unsupported segment format, ignoring");
2168 /* We shouldn't modify upstream driven TIME FORMAT segment */
2169 if (!demux->upstream_format_is_time) {
2170 /* accept upstream's notion of segment and distribute along */
2171 segment.format = GST_FORMAT_TIME;
2172 segment.position = segment.time = segment.start;
2173 segment.duration = demux->segment.duration;
2174 segment.base = gst_segment_to_running_time (&demux->segment,
2175 GST_FORMAT_TIME, demux->segment.position);
2178 gst_segment_copy_into (&segment, &demux->segment);
2179 GST_DEBUG_OBJECT (demux, "Pushing newseg %" GST_SEGMENT_FORMAT, &segment);
2181 /* map segment to internal qt segments and push on each stream */
2182 if (demux->n_streams) {
2183 if (demux->fragmented) {
2184 GstEvent *segment_event = gst_event_new_segment (&segment);
2186 gst_event_replace (&demux->pending_newsegment, NULL);
2187 gst_event_set_seqnum (segment_event, demux->segment_seqnum);
2188 gst_qtdemux_push_event (demux, segment_event);
2190 gst_event_replace (&demux->pending_newsegment, NULL);
2191 gst_qtdemux_map_and_push_segments (demux, &segment);
2195 /* clear leftover in current segment, if any */
2196 gst_adapter_clear (demux->adapter);
2198 /* set up streaming thread */
2199 demux->offset = offset;
2200 if (demux->upstream_format_is_time) {
2201 GST_DEBUG_OBJECT (demux, "Upstream is driving in time format, "
2202 "set values to restart reading from a new atom");
2203 demux->neededbytes = 16;
2206 gst_qtdemux_find_sample (demux, offset, TRUE, TRUE, &stream, &idx,
2209 demux->todrop = stream->samples[idx].offset - offset;
2210 demux->neededbytes = demux->todrop + stream->samples[idx].size;
2212 /* set up for EOS */
2213 demux->neededbytes = -1;
2218 gst_event_unref (event);
2222 case GST_EVENT_FLUSH_START:
2224 if (gst_event_get_seqnum (event) == demux->offset_seek_seqnum) {
2225 gst_event_unref (event);
2230 case GST_EVENT_FLUSH_STOP:
2234 dur = demux->segment.duration;
2235 gst_qtdemux_reset (demux, FALSE);
2236 demux->segment.duration = dur;
2238 if (gst_event_get_seqnum (event) == demux->offset_seek_seqnum) {
2239 gst_event_unref (event);
2245 /* If we are in push mode, and get an EOS before we've seen any streams,
2246 * then error out - we have nowhere to send the EOS */
2247 if (!demux->pullbased) {
2249 gboolean has_valid_stream = FALSE;
2250 for (i = 0; i < demux->n_streams; i++) {
2251 if (demux->streams[i]->pad != NULL) {
2252 has_valid_stream = TRUE;
2256 if (!has_valid_stream)
2257 gst_qtdemux_post_no_playable_stream_error (demux);
2259 GST_DEBUG_OBJECT (demux, "Data still available after EOS: %u",
2260 (guint) gst_adapter_available (demux->adapter));
2261 if (gst_qtdemux_process_adapter (demux, TRUE) != GST_FLOW_OK) {
2267 case GST_EVENT_CAPS:{
2268 GstCaps *caps = NULL;
2270 gst_event_parse_caps (event, &caps);
2271 gst_qtdemux_setcaps (demux, caps);
2273 gst_event_unref (event);
2276 case GST_EVENT_PROTECTION:
2278 const gchar *system_id = NULL;
2280 gst_event_parse_protection (event, &system_id, NULL, NULL);
2281 GST_DEBUG_OBJECT (demux, "Received protection event for system ID %s",
2283 gst_qtdemux_append_protection_system_id (demux, system_id);
2284 /* save the event for later, for source pads that have not been created */
2285 g_queue_push_tail (&demux->protection_event_queue, gst_event_ref (event));
2286 /* send it to all pads that already exist */
2287 gst_qtdemux_push_event (demux, event);
2295 res = gst_pad_event_default (demux->sinkpad, parent, event) & res;
2303 gst_qtdemux_set_index (GstElement * element, GstIndex * index)
2305 GstQTDemux *demux = GST_QTDEMUX (element);
2307 GST_OBJECT_LOCK (demux);
2308 if (demux->element_index)
2309 gst_object_unref (demux->element_index);
2311 demux->element_index = gst_object_ref (index);
2313 demux->element_index = NULL;
2315 GST_OBJECT_UNLOCK (demux);
2316 /* object lock might be taken again */
2318 gst_index_get_writer_id (index, GST_OBJECT (element), &demux->index_id);
2319 GST_DEBUG_OBJECT (demux, "Set index %" GST_PTR_FORMAT "for writer id %d",
2320 demux->element_index, demux->index_id);
2324 gst_qtdemux_get_index (GstElement * element)
2326 GstIndex *result = NULL;
2327 GstQTDemux *demux = GST_QTDEMUX (element);
2329 GST_OBJECT_LOCK (demux);
2330 if (demux->element_index)
2331 result = gst_object_ref (demux->element_index);
2332 GST_OBJECT_UNLOCK (demux);
2334 GST_DEBUG_OBJECT (demux, "Returning index %" GST_PTR_FORMAT, result);
2341 gst_qtdemux_stbl_free (QtDemuxStream * stream)
2343 g_free ((gpointer) stream->stco.data);
2344 stream->stco.data = NULL;
2345 g_free ((gpointer) stream->stsz.data);
2346 stream->stsz.data = NULL;
2347 g_free ((gpointer) stream->stsc.data);
2348 stream->stsc.data = NULL;
2349 g_free ((gpointer) stream->stts.data);
2350 stream->stts.data = NULL;
2351 g_free ((gpointer) stream->stss.data);
2352 stream->stss.data = NULL;
2353 g_free ((gpointer) stream->stps.data);
2354 stream->stps.data = NULL;
2355 g_free ((gpointer) stream->ctts.data);
2356 stream->ctts.data = NULL;
2360 gst_qtdemux_stream_flush_segments_data (GstQTDemux * qtdemux,
2361 QtDemuxStream * stream)
2363 g_free (stream->segments);
2364 stream->segments = NULL;
2365 stream->segment_index = -1;
2366 stream->accumulated_base = 0;
2370 gst_qtdemux_stream_flush_samples_data (GstQTDemux * qtdemux,
2371 QtDemuxStream * stream)
2373 g_free (stream->samples);
2374 stream->samples = NULL;
2375 gst_qtdemux_stbl_free (stream);
2378 g_free (stream->ra_entries);
2379 stream->ra_entries = NULL;
2380 stream->n_ra_entries = 0;
2382 stream->sample_index = -1;
2383 stream->stbl_index = -1;
2384 stream->n_samples = 0;
2385 stream->time_position = 0;
2387 stream->n_samples_moof = 0;
2388 stream->duration_moof = 0;
2389 stream->duration_last_moof = 0;
2393 gst_qtdemux_stream_clear (GstQTDemux * qtdemux, QtDemuxStream * stream)
2395 if (stream->allocator)
2396 gst_object_unref (stream->allocator);
2397 while (stream->buffers) {
2398 gst_buffer_unref (GST_BUFFER_CAST (stream->buffers->data));
2399 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
2401 if (stream->rgb8_palette) {
2402 gst_memory_unref (stream->rgb8_palette);
2403 stream->rgb8_palette = NULL;
2406 if (stream->pending_tags)
2407 gst_tag_list_unref (stream->pending_tags);
2408 stream->pending_tags = NULL;
2409 g_free (stream->redirect_uri);
2410 stream->redirect_uri = NULL;
2411 stream->sent_eos = FALSE;
2412 stream->sparse = FALSE;
2413 stream->protected = FALSE;
2414 if (stream->protection_scheme_info) {
2415 if (stream->protection_scheme_type == FOURCC_cenc) {
2416 QtDemuxCencSampleSetInfo *info =
2417 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
2418 if (info->default_properties)
2419 gst_structure_free (info->default_properties);
2420 if (info->crypto_info)
2421 g_ptr_array_free (info->crypto_info, TRUE);
2423 g_free (stream->protection_scheme_info);
2424 stream->protection_scheme_info = NULL;
2426 stream->protection_scheme_type = 0;
2427 stream->protection_scheme_version = 0;
2428 g_queue_foreach (&stream->protection_scheme_event_queue,
2429 (GFunc) gst_event_unref, NULL);
2430 g_queue_clear (&stream->protection_scheme_event_queue);
2431 gst_qtdemux_stream_flush_segments_data (qtdemux, stream);
2432 gst_qtdemux_stream_flush_samples_data (qtdemux, stream);
2436 gst_qtdemux_stream_free (GstQTDemux * qtdemux, QtDemuxStream * stream)
2438 gst_qtdemux_stream_clear (qtdemux, stream);
2440 gst_caps_unref (stream->caps);
2441 stream->caps = NULL;
2443 gst_element_remove_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
2444 gst_flow_combiner_remove_pad (qtdemux->flowcombiner, stream->pad);
2450 gst_qtdemux_remove_stream (GstQTDemux * qtdemux, int i)
2452 g_assert (i >= 0 && i < qtdemux->n_streams && qtdemux->streams[i] != NULL);
2454 gst_qtdemux_stream_free (qtdemux, qtdemux->streams[i]);
2455 qtdemux->streams[i] = qtdemux->streams[qtdemux->n_streams - 1];
2456 qtdemux->streams[qtdemux->n_streams - 1] = NULL;
2457 qtdemux->n_streams--;
2460 static GstStateChangeReturn
2461 gst_qtdemux_change_state (GstElement * element, GstStateChange transition)
2463 GstQTDemux *qtdemux = GST_QTDEMUX (element);
2464 GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
2466 switch (transition) {
2467 case GST_STATE_CHANGE_PAUSED_TO_READY:
2473 result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
2475 switch (transition) {
2476 case GST_STATE_CHANGE_PAUSED_TO_READY:{
2477 gst_qtdemux_reset (qtdemux, TRUE);
2488 qtdemux_parse_ftyp (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2490 /* counts as header data */
2491 qtdemux->header_size += length;
2493 /* only consider at least a sufficiently complete ftyp atom */
2497 qtdemux->major_brand = QT_FOURCC (buffer + 8);
2498 GST_DEBUG_OBJECT (qtdemux, "major brand: %" GST_FOURCC_FORMAT,
2499 GST_FOURCC_ARGS (qtdemux->major_brand));
2500 if (qtdemux->comp_brands)
2501 gst_buffer_unref (qtdemux->comp_brands);
2502 buf = qtdemux->comp_brands = gst_buffer_new_and_alloc (length - 16);
2503 gst_buffer_fill (buf, 0, buffer + 16, length - 16);
2508 qtdemux_handle_xmp_taglist (GstQTDemux * qtdemux, GstTagList * taglist,
2509 GstTagList * xmptaglist)
2511 /* Strip out bogus fields */
2513 if (gst_tag_list_get_scope (taglist) == GST_TAG_SCOPE_GLOBAL) {
2514 gst_tag_list_remove_tag (xmptaglist, GST_TAG_VIDEO_CODEC);
2515 gst_tag_list_remove_tag (xmptaglist, GST_TAG_AUDIO_CODEC);
2517 gst_tag_list_remove_tag (xmptaglist, GST_TAG_CONTAINER_FORMAT);
2520 GST_DEBUG_OBJECT (qtdemux, "Found XMP tags %" GST_PTR_FORMAT, xmptaglist);
2522 /* prioritize native tags using _KEEP mode */
2523 gst_tag_list_insert (taglist, xmptaglist, GST_TAG_MERGE_KEEP);
2524 gst_tag_list_unref (xmptaglist);
2529 qtdemux_parse_piff (GstQTDemux * qtdemux, const guint8 * buffer, gint length,
2537 QtDemuxStream *stream;
2538 GstStructure *structure;
2539 QtDemuxCencSampleSetInfo *ss_info = NULL;
2540 const gchar *system_id;
2541 gboolean uses_sub_sample_encryption = FALSE;
2543 if (qtdemux->n_streams == 0)
2546 stream = qtdemux->streams[0];
2548 structure = gst_caps_get_structure (stream->caps, 0);
2549 if (!gst_structure_has_name (structure, "application/x-cenc")) {
2550 GST_WARNING_OBJECT (qtdemux,
2551 "Attempting PIFF box parsing on an unencrypted stream.");
2555 gst_structure_get (structure, GST_PROTECTION_SYSTEM_ID_CAPS_FIELD,
2556 G_TYPE_STRING, &system_id, NULL);
2557 gst_qtdemux_append_protection_system_id (qtdemux, system_id);
2559 stream->protected = TRUE;
2560 stream->protection_scheme_type = FOURCC_cenc;
2562 if (!stream->protection_scheme_info)
2563 stream->protection_scheme_info = g_new0 (QtDemuxCencSampleSetInfo, 1);
2565 ss_info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
2567 if (ss_info->default_properties)
2568 gst_structure_free (ss_info->default_properties);
2570 ss_info->default_properties =
2571 gst_structure_new ("application/x-cenc",
2572 "iv_size", G_TYPE_UINT, iv_size, "encrypted", G_TYPE_BOOLEAN, TRUE, NULL);
2574 if (ss_info->crypto_info) {
2575 GST_LOG_OBJECT (qtdemux, "unreffing existing crypto_info");
2576 g_ptr_array_free (ss_info->crypto_info, TRUE);
2577 ss_info->crypto_info = NULL;
2581 gst_byte_reader_init (&br, buffer + offset + 16, length - offset - 16);
2583 if (!gst_byte_reader_get_uint8 (&br, &version)) {
2584 GST_ERROR_OBJECT (qtdemux, "Error getting box's version field");
2588 if (!gst_byte_reader_get_uint24_be (&br, &flags)) {
2589 GST_ERROR_OBJECT (qtdemux, "Error getting box's flags field");
2593 if ((flags & 0x000001)) {
2594 guint32 algorithm_id = 0;
2597 gboolean is_encrypted = TRUE;
2599 if (!gst_byte_reader_get_uint24_le (&br, &algorithm_id)) {
2600 GST_ERROR_OBJECT (qtdemux, "Error getting box's algorithm ID field");
2605 if (algorithm_id == 0) {
2606 is_encrypted = FALSE;
2607 } else if (algorithm_id == 1) {
2608 /* FIXME: maybe store this in properties? */
2609 GST_DEBUG_OBJECT (qtdemux, "AES 128-bits CTR encrypted stream");
2610 } else if (algorithm_id == 2) {
2611 /* FIXME: maybe store this in properties? */
2612 GST_DEBUG_OBJECT (qtdemux, "AES 128-bits CBC encrypted stream");
2615 if (!gst_byte_reader_get_uint8 (&br, &iv_size))
2618 if (!gst_byte_reader_get_data (&br, 16, &kid))
2621 kid_buf = gst_buffer_new_allocate (NULL, 16, NULL);
2622 gst_buffer_fill (kid_buf, 0, kid, 16);
2623 if (ss_info->default_properties)
2624 gst_structure_free (ss_info->default_properties);
2625 ss_info->default_properties =
2626 gst_structure_new ("application/x-cenc",
2627 "iv_size", G_TYPE_UINT, iv_size,
2628 "encrypted", G_TYPE_BOOLEAN, is_encrypted,
2629 "kid", GST_TYPE_BUFFER, kid_buf, NULL);
2630 GST_DEBUG_OBJECT (qtdemux, "default sample properties: "
2631 "is_encrypted=%u, iv_size=%u", is_encrypted, iv_size);
2632 gst_buffer_unref (kid_buf);
2633 } else if ((flags & 0x000002)) {
2634 uses_sub_sample_encryption = TRUE;
2637 if (!gst_byte_reader_get_uint32_be (&br, &qtdemux->cenc_aux_sample_count)) {
2638 GST_ERROR_OBJECT (qtdemux, "Error getting box's sample count field");
2642 ss_info->crypto_info =
2643 g_ptr_array_new_full (qtdemux->cenc_aux_sample_count,
2644 (GDestroyNotify) qtdemux_gst_structure_free);
2646 for (i = 0; i < qtdemux->cenc_aux_sample_count; ++i) {
2647 GstStructure *properties;
2651 properties = qtdemux_get_cenc_sample_properties (qtdemux, stream, i);
2652 if (properties == NULL) {
2653 GST_ERROR_OBJECT (qtdemux, "failed to get properties for sample %u", i);
2657 if (!gst_byte_reader_dup_data (&br, iv_size, &data)) {
2658 GST_ERROR_OBJECT (qtdemux, "IV data not present for sample %u", i);
2659 gst_structure_free (properties);
2662 buf = gst_buffer_new_wrapped (data, iv_size);
2663 gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL);
2664 gst_buffer_unref (buf);
2666 if (uses_sub_sample_encryption) {
2667 guint16 n_subsamples;
2669 if (!gst_byte_reader_get_uint16_be (&br, &n_subsamples)
2670 || n_subsamples == 0) {
2671 GST_ERROR_OBJECT (qtdemux,
2672 "failed to get subsample count for sample %u", i);
2673 gst_structure_free (properties);
2676 GST_LOG_OBJECT (qtdemux, "subsample count: %u", n_subsamples);
2677 if (!gst_byte_reader_dup_data (&br, n_subsamples * 6, &data)) {
2678 GST_ERROR_OBJECT (qtdemux, "failed to get subsample data for sample %u",
2680 gst_structure_free (properties);
2683 buf = gst_buffer_new_wrapped (data, n_subsamples * 6);
2684 gst_structure_set (properties,
2685 "subsample_count", G_TYPE_UINT, n_subsamples,
2686 "subsamples", GST_TYPE_BUFFER, buf, NULL);
2687 gst_buffer_unref (buf);
2689 gst_structure_set (properties, "subsample_count", G_TYPE_UINT, 0, NULL);
2692 g_ptr_array_add (ss_info->crypto_info, properties);
2697 qtdemux_parse_uuid (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2699 static const guint8 xmp_uuid[] = { 0xBE, 0x7A, 0xCF, 0xCB,
2700 0x97, 0xA9, 0x42, 0xE8,
2701 0x9C, 0x71, 0x99, 0x94,
2702 0x91, 0xE3, 0xAF, 0xAC
2704 static const guint8 playready_uuid[] = {
2705 0xd0, 0x8a, 0x4f, 0x18, 0x10, 0xf3, 0x4a, 0x82,
2706 0xb6, 0xc8, 0x32, 0xd8, 0xab, 0xa1, 0x83, 0xd3
2709 static const guint8 piff_sample_encryption_uuid[] = {
2710 0xa2, 0x39, 0x4f, 0x52, 0x5a, 0x9b, 0x4f, 0x14,
2711 0xa2, 0x44, 0x6c, 0x42, 0x7c, 0x64, 0x8d, 0xf4
2716 /* counts as header data */
2717 qtdemux->header_size += length;
2719 offset = (QT_UINT32 (buffer) == 0) ? 16 : 8;
2721 if (length <= offset + 16) {
2722 GST_DEBUG_OBJECT (qtdemux, "uuid atom is too short, skipping");
2726 if (memcmp (buffer + offset, xmp_uuid, 16) == 0) {
2728 GstTagList *taglist;
2730 buf = _gst_buffer_new_wrapped ((guint8 *) buffer + offset + 16,
2731 length - offset - 16, NULL);
2732 taglist = gst_tag_list_from_xmp_buffer (buf);
2733 gst_buffer_unref (buf);
2735 qtdemux_handle_xmp_taglist (qtdemux, qtdemux->tag_list, taglist);
2737 } else if (memcmp (buffer + offset, playready_uuid, 16) == 0) {
2739 const gunichar2 *s_utf16;
2742 len = GST_READ_UINT16_LE (buffer + offset + 0x30);
2743 s_utf16 = (const gunichar2 *) (buffer + offset + 0x32);
2744 contents = g_utf16_to_utf8 (s_utf16, len / 2, NULL, NULL, NULL);
2745 GST_ERROR_OBJECT (qtdemux, "contents: %s", contents);
2749 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT,
2750 (_("Cannot play stream because it is encrypted with PlayReady DRM.")),
2752 } else if (memcmp (buffer + offset, piff_sample_encryption_uuid, 16) == 0) {
2753 qtdemux_parse_piff (qtdemux, buffer, length, offset);
2755 GST_DEBUG_OBJECT (qtdemux, "Ignoring unknown uuid: %08x-%08x-%08x-%08x",
2756 GST_READ_UINT32_LE (buffer + offset),
2757 GST_READ_UINT32_LE (buffer + offset + 4),
2758 GST_READ_UINT32_LE (buffer + offset + 8),
2759 GST_READ_UINT32_LE (buffer + offset + 12));
2764 qtdemux_parse_sidx (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2766 GstSidxParser sidx_parser;
2767 GstIsoffParserResult res;
2770 gst_isoff_qt_sidx_parser_init (&sidx_parser);
2773 gst_isoff_qt_sidx_parser_add_data (&sidx_parser, buffer, length,
2775 GST_DEBUG_OBJECT (qtdemux, "sidx parse result: %d", res);
2776 if (res == GST_ISOFF_QT_PARSER_DONE) {
2777 check_update_duration (qtdemux, sidx_parser.cumulative_pts);
2779 gst_isoff_qt_sidx_parser_clear (&sidx_parser);
2782 /* caller verifies at least 8 bytes in buf */
2784 extract_initial_length_and_fourcc (const guint8 * data, guint size,
2785 guint64 * plength, guint32 * pfourcc)
2790 length = QT_UINT32 (data);
2791 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
2792 fourcc = QT_FOURCC (data + 4);
2793 GST_DEBUG ("atom type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
2796 length = G_MAXUINT64;
2797 } else if (length == 1 && size >= 16) {
2798 /* this means we have an extended size, which is the 64 bit value of
2799 * the next 8 bytes */
2800 length = QT_UINT64 (data + 8);
2801 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
2811 qtdemux_parse_mehd (GstQTDemux * qtdemux, GstByteReader * br)
2813 guint32 version = 0;
2814 GstClockTime duration = 0;
2816 if (!gst_byte_reader_get_uint32_be (br, &version))
2821 if (!gst_byte_reader_get_uint64_be (br, &duration))
2826 if (!gst_byte_reader_get_uint32_be (br, &dur))
2831 GST_INFO_OBJECT (qtdemux, "mehd duration: %" G_GUINT64_FORMAT, duration);
2832 qtdemux->duration = duration;
2838 GST_DEBUG_OBJECT (qtdemux, "parsing mehd failed");
2844 qtdemux_parse_trex (GstQTDemux * qtdemux, QtDemuxStream * stream,
2845 guint32 * ds_duration, guint32 * ds_size, guint32 * ds_flags)
2847 if (!stream->parsed_trex && qtdemux->moov_node) {
2849 GstByteReader trex_data;
2851 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
2853 trex = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_trex,
2856 guint32 id = 0, dur = 0, size = 0, flags = 0, dummy = 0;
2858 /* skip version/flags */
2859 if (!gst_byte_reader_skip (&trex_data, 4))
2861 if (!gst_byte_reader_get_uint32_be (&trex_data, &id))
2863 if (id != stream->track_id)
2865 /* sample description index; ignore */
2866 if (!gst_byte_reader_get_uint32_be (&trex_data, &dummy))
2868 if (!gst_byte_reader_get_uint32_be (&trex_data, &dur))
2870 if (!gst_byte_reader_get_uint32_be (&trex_data, &size))
2872 if (!gst_byte_reader_get_uint32_be (&trex_data, &flags))
2875 GST_DEBUG_OBJECT (qtdemux, "fragment defaults for stream %d; "
2876 "duration %d, size %d, flags 0x%x", stream->track_id,
2879 stream->parsed_trex = TRUE;
2880 stream->def_sample_duration = dur;
2881 stream->def_sample_size = size;
2882 stream->def_sample_flags = flags;
2885 /* iterate all siblings */
2886 trex = qtdemux_tree_get_sibling_by_type_full (trex, FOURCC_trex,
2892 *ds_duration = stream->def_sample_duration;
2893 *ds_size = stream->def_sample_size;
2894 *ds_flags = stream->def_sample_flags;
2896 /* even then, above values are better than random ... */
2897 if (G_UNLIKELY (!stream->parsed_trex)) {
2898 GST_WARNING_OBJECT (qtdemux,
2899 "failed to find fragment defaults for stream %d", stream->track_id);
2906 /* This method should be called whenever a more accurate duration might
2907 * have been found. It will update all relevant variables if/where needed
2910 check_update_duration (GstQTDemux * qtdemux, GstClockTime duration)
2914 GstClockTime prevdur;
2916 movdur = GSTTIME_TO_QTTIME (qtdemux, duration);
2918 if (movdur > qtdemux->duration) {
2919 prevdur = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
2920 GST_DEBUG_OBJECT (qtdemux,
2921 "Updating total duration to %" GST_TIME_FORMAT " was %" GST_TIME_FORMAT,
2922 GST_TIME_ARGS (duration), GST_TIME_ARGS (prevdur));
2923 qtdemux->duration = movdur;
2924 GST_DEBUG_OBJECT (qtdemux,
2925 "qtdemux->segment.duration: %" GST_TIME_FORMAT " .stop: %"
2926 GST_TIME_FORMAT, GST_TIME_ARGS (qtdemux->segment.duration),
2927 GST_TIME_ARGS (qtdemux->segment.stop));
2928 if (qtdemux->segment.duration == prevdur) {
2929 /* If the current segment has duration/stop identical to previous duration
2930 * update them also (because they were set at that point in time with
2931 * the wrong duration */
2932 /* We convert the value *from* the timescale version to avoid rounding errors */
2933 GstClockTime fixeddur = QTTIME_TO_GSTTIME (qtdemux, movdur);
2934 GST_DEBUG_OBJECT (qtdemux, "Updated segment.duration and segment.stop");
2935 qtdemux->segment.duration = fixeddur;
2936 qtdemux->segment.stop = fixeddur;
2939 for (i = 0; i < qtdemux->n_streams; i++) {
2940 QtDemuxStream *stream = qtdemux->streams[i];
2942 movdur = GSTTIME_TO_QTSTREAMTIME (stream, duration);
2943 if (movdur > stream->duration) {
2944 GST_DEBUG_OBJECT (qtdemux,
2945 "Updating stream #%d duration to %" GST_TIME_FORMAT, i,
2946 GST_TIME_ARGS (duration));
2947 stream->duration = movdur;
2948 if (stream->dummy_segment) {
2949 /* Update all dummy values to new duration */
2950 stream->segments[0].stop_time = duration;
2951 stream->segments[0].duration = duration;
2952 stream->segments[0].media_stop = duration;
2954 /* let downstream know we possibly have a new stop time */
2955 if (stream->segment_index != -1) {
2958 if (qtdemux->segment.rate >= 0) {
2959 pos = stream->segment.start;
2961 pos = stream->segment.stop;
2964 gst_qtdemux_stream_update_segment (qtdemux, stream,
2965 stream->segment_index, pos, NULL, NULL);
2974 qtdemux_parse_trun (GstQTDemux * qtdemux, GstByteReader * trun,
2975 QtDemuxStream * stream, guint32 d_sample_duration, guint32 d_sample_size,
2976 guint32 d_sample_flags, gint64 moof_offset, gint64 moof_length,
2977 gint64 * base_offset, gint64 * running_offset, gint64 decode_ts)
2979 GstClockTime gst_ts = GST_CLOCK_TIME_NONE;
2981 gint32 data_offset = 0;
2982 guint32 flags = 0, first_flags = 0, samples_count = 0;
2985 guint entry_size, dur_offset, size_offset, flags_offset = 0, ct_offset = 0;
2986 QtDemuxSample *sample;
2987 gboolean ismv = FALSE;
2988 gint64 initial_offset;
2990 GST_LOG_OBJECT (qtdemux, "parsing trun stream %d; "
2991 "default dur %d, size %d, flags 0x%x, base offset %" G_GINT64_FORMAT ", "
2992 "decode ts %" G_GINT64_FORMAT, stream->track_id, d_sample_duration,
2993 d_sample_size, d_sample_flags, *base_offset, decode_ts);
2995 if (stream->pending_seek && moof_offset < stream->pending_seek->moof_offset) {
2996 GST_INFO_OBJECT (stream->pad, "skipping trun before seek target fragment");
3000 /* presence of stss or not can't really tell us much,
3001 * and flags and so on tend to be marginally reliable in these files */
3002 if (stream->subtype == FOURCC_soun) {
3003 GST_DEBUG_OBJECT (qtdemux,
3004 "sound track in fragmented file; marking all keyframes");
3005 stream->all_keyframe = TRUE;
3008 if (!gst_byte_reader_skip (trun, 1) ||
3009 !gst_byte_reader_get_uint24_be (trun, &flags))
3012 if (!gst_byte_reader_get_uint32_be (trun, &samples_count))
3015 if (flags & TR_DATA_OFFSET) {
3016 /* note this is really signed */
3017 if (!gst_byte_reader_get_int32_be (trun, &data_offset))
3019 GST_LOG_OBJECT (qtdemux, "trun data offset %d", data_offset);
3020 /* default base offset = first byte of moof */
3021 if (*base_offset == -1) {
3022 GST_LOG_OBJECT (qtdemux, "base_offset at moof");
3023 *base_offset = moof_offset;
3025 *running_offset = *base_offset + data_offset;
3027 /* if no offset at all, that would mean data starts at moof start,
3028 * which is a bit wrong and is ismv crappy way, so compensate
3029 * assuming data is in mdat following moof */
3030 if (*base_offset == -1) {
3031 *base_offset = moof_offset + moof_length + 8;
3032 GST_LOG_OBJECT (qtdemux, "base_offset assumed in mdat after moof");
3035 if (*running_offset == -1)
3036 *running_offset = *base_offset;
3039 GST_LOG_OBJECT (qtdemux, "running offset now %" G_GINT64_FORMAT,
3041 GST_LOG_OBJECT (qtdemux, "trun offset %d, flags 0x%x, entries %d",
3042 data_offset, flags, samples_count);
3044 if (flags & TR_FIRST_SAMPLE_FLAGS) {
3045 if (G_UNLIKELY (flags & TR_SAMPLE_FLAGS)) {
3046 GST_DEBUG_OBJECT (qtdemux,
3047 "invalid flags; SAMPLE and FIRST_SAMPLE present, discarding latter");
3048 flags ^= TR_FIRST_SAMPLE_FLAGS;
3050 if (!gst_byte_reader_get_uint32_be (trun, &first_flags))
3052 GST_LOG_OBJECT (qtdemux, "first flags: 0x%x", first_flags);
3056 /* FIXME ? spec says other bits should also be checked to determine
3057 * entry size (and prefix size for that matter) */
3059 dur_offset = size_offset = 0;
3060 if (flags & TR_SAMPLE_DURATION) {
3061 GST_LOG_OBJECT (qtdemux, "entry duration present");
3062 dur_offset = entry_size;
3065 if (flags & TR_SAMPLE_SIZE) {
3066 GST_LOG_OBJECT (qtdemux, "entry size present");
3067 size_offset = entry_size;
3070 if (flags & TR_SAMPLE_FLAGS) {
3071 GST_LOG_OBJECT (qtdemux, "entry flags present");
3072 flags_offset = entry_size;
3075 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
3076 GST_LOG_OBJECT (qtdemux, "entry ct offset present");
3077 ct_offset = entry_size;
3081 if (!qt_atom_parser_has_chunks (trun, samples_count, entry_size))
3083 data = (guint8 *) gst_byte_reader_peek_data_unchecked (trun);
3085 if (stream->n_samples + samples_count >=
3086 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample))
3089 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
3090 stream->n_samples + samples_count, (guint) sizeof (QtDemuxSample),
3091 (stream->n_samples + samples_count) *
3092 sizeof (QtDemuxSample) / (1024.0 * 1024.0));
3094 /* create a new array of samples if it's the first sample parsed */
3095 if (stream->n_samples == 0) {
3096 g_assert (stream->samples == NULL);
3097 stream->samples = g_try_new0 (QtDemuxSample, samples_count);
3098 /* or try to reallocate it with space enough to insert the new samples */
3100 stream->samples = g_try_renew (QtDemuxSample, stream->samples,
3101 stream->n_samples + samples_count);
3102 if (stream->samples == NULL)
3105 if (qtdemux->fragment_start != -1) {
3106 timestamp = GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->fragment_start);
3107 qtdemux->fragment_start = -1;
3109 if (stream->n_samples == 0) {
3110 if (decode_ts > 0) {
3111 timestamp = decode_ts;
3112 } else if (stream->pending_seek != NULL) {
3113 /* if we don't have a timestamp from a tfdt box, we'll use the one
3114 * from the mfra seek table */
3115 GST_INFO_OBJECT (stream->pad, "pending seek ts = %" GST_TIME_FORMAT,
3116 GST_TIME_ARGS (stream->pending_seek->ts));
3118 /* FIXME: this is not fully correct, the timestamp refers to the random
3119 * access sample refered to in the tfra entry, which may not necessarily
3120 * be the first sample in the tfrag/trun (but hopefully/usually is) */
3121 timestamp = GSTTIME_TO_QTSTREAMTIME (stream, stream->pending_seek->ts);
3126 gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
3127 GST_INFO_OBJECT (stream->pad, "first sample ts %" GST_TIME_FORMAT,
3128 GST_TIME_ARGS (gst_ts));
3130 /* subsequent fragments extend stream */
3132 stream->samples[stream->n_samples - 1].timestamp +
3133 stream->samples[stream->n_samples - 1].duration;
3135 /* If this is a GST_FORMAT_BYTES stream and there's a significant
3136 * difference (1 sec.) between decode_ts and timestamp, prefer the
3138 if (!qtdemux->upstream_format_is_time
3139 && ABSDIFF (decode_ts, timestamp) >
3140 MAX (stream->duration_last_moof / 2,
3141 GSTTIME_TO_QTSTREAMTIME (stream, GST_SECOND))) {
3142 GST_INFO_OBJECT (qtdemux,
3143 "decode_ts (%" GST_TIME_FORMAT ") and timestamp (%" GST_TIME_FORMAT
3144 ") are significantly different (more than %" GST_TIME_FORMAT
3145 "), using decode_ts",
3146 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, decode_ts)),
3147 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, timestamp)),
3148 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream,
3149 MAX (stream->duration_last_moof / 2,
3150 GSTTIME_TO_QTSTREAMTIME (stream, GST_SECOND)))));
3151 timestamp = decode_ts;
3154 gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
3155 GST_INFO_OBJECT (qtdemux, "first sample ts %" GST_TIME_FORMAT
3156 " (extends previous samples)", GST_TIME_ARGS (gst_ts));
3160 initial_offset = *running_offset;
3162 sample = stream->samples + stream->n_samples;
3163 for (i = 0; i < samples_count; i++) {
3164 guint32 dur, size, sflags, ct;
3166 /* first read sample data */
3167 if (flags & TR_SAMPLE_DURATION) {
3168 dur = QT_UINT32 (data + dur_offset);
3170 dur = d_sample_duration;
3172 if (flags & TR_SAMPLE_SIZE) {
3173 size = QT_UINT32 (data + size_offset);
3175 size = d_sample_size;
3177 if (flags & TR_FIRST_SAMPLE_FLAGS) {
3179 sflags = first_flags;
3181 sflags = d_sample_flags;
3183 } else if (flags & TR_SAMPLE_FLAGS) {
3184 sflags = QT_UINT32 (data + flags_offset);
3186 sflags = d_sample_flags;
3188 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
3189 ct = QT_UINT32 (data + ct_offset);
3195 /* fill the sample information */
3196 sample->offset = *running_offset;
3197 sample->pts_offset = ct;
3198 sample->size = size;
3199 sample->timestamp = timestamp;
3200 sample->duration = dur;
3201 /* sample-is-difference-sample */
3202 /* ismv seems to use 0x40 for keyframe, 0xc0 for non-keyframe,
3203 * now idea how it relates to bitfield other than massive LE/BE confusion */
3204 sample->keyframe = ismv ? ((sflags & 0xff) == 0x40) : !(sflags & 0x10000);
3205 *running_offset += size;
3207 stream->duration_moof += dur;
3211 /* Update total duration if needed */
3212 check_update_duration (qtdemux, QTSTREAMTIME_TO_GSTTIME (stream, timestamp));
3214 /* Pre-emptively figure out size of mdat based on trun information.
3215 * If the [mdat] atom is effectivelly read, it will be replaced by the actual
3216 * size, else we will still be able to use this when dealing with gap'ed
3218 qtdemux->mdatleft = *running_offset - initial_offset;
3220 stream->n_samples += samples_count;
3221 stream->n_samples_moof += samples_count;
3223 if (stream->pending_seek != NULL)
3224 stream->pending_seek = NULL;
3230 GST_WARNING_OBJECT (qtdemux, "failed to parse trun");
3235 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
3241 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
3242 "be larger than %uMB (broken file?)", stream->n_samples,
3243 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
3248 /* find stream with @id */
3249 static inline QtDemuxStream *
3250 qtdemux_find_stream (GstQTDemux * qtdemux, guint32 id)
3252 QtDemuxStream *stream;
3256 if (G_UNLIKELY (!id)) {
3257 GST_DEBUG_OBJECT (qtdemux, "invalid track id 0");
3261 /* try to get it fast and simple */
3262 if (G_LIKELY (id <= qtdemux->n_streams)) {
3263 stream = qtdemux->streams[id - 1];
3264 if (G_LIKELY (stream->track_id == id))
3268 /* linear search otherwise */
3269 for (i = 0; i < qtdemux->n_streams; i++) {
3270 stream = qtdemux->streams[i];
3271 if (stream->track_id == id)
3274 if (qtdemux->mss_mode) {
3275 /* mss should have only 1 stream anyway */
3276 return qtdemux->streams[0];
3283 qtdemux_parse_mfhd (GstQTDemux * qtdemux, GstByteReader * mfhd,
3284 guint32 * fragment_number)
3286 if (!gst_byte_reader_skip (mfhd, 4))
3288 if (!gst_byte_reader_get_uint32_be (mfhd, fragment_number))
3293 GST_WARNING_OBJECT (qtdemux, "Failed to parse mfhd atom");
3299 qtdemux_parse_tfhd (GstQTDemux * qtdemux, GstByteReader * tfhd,
3300 QtDemuxStream ** stream, guint32 * default_sample_duration,
3301 guint32 * default_sample_size, guint32 * default_sample_flags,
3302 gint64 * base_offset)
3305 guint32 track_id = 0;
3307 if (!gst_byte_reader_skip (tfhd, 1) ||
3308 !gst_byte_reader_get_uint24_be (tfhd, &flags))
3311 if (!gst_byte_reader_get_uint32_be (tfhd, &track_id))
3314 *stream = qtdemux_find_stream (qtdemux, track_id);
3315 if (G_UNLIKELY (!*stream))
3316 goto unknown_stream;
3318 if (flags & TF_DEFAULT_BASE_IS_MOOF)
3319 *base_offset = qtdemux->moof_offset;
3321 if (flags & TF_BASE_DATA_OFFSET)
3322 if (!gst_byte_reader_get_uint64_be (tfhd, (guint64 *) base_offset))
3325 /* obtain stream defaults */
3326 qtdemux_parse_trex (qtdemux, *stream,
3327 default_sample_duration, default_sample_size, default_sample_flags);
3329 /* FIXME: Handle TF_SAMPLE_DESCRIPTION_INDEX properly */
3330 if (flags & TF_SAMPLE_DESCRIPTION_INDEX)
3331 if (!gst_byte_reader_skip (tfhd, 4))
3334 if (flags & TF_DEFAULT_SAMPLE_DURATION)
3335 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_duration))
3338 if (flags & TF_DEFAULT_SAMPLE_SIZE)
3339 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_size))
3342 if (flags & TF_DEFAULT_SAMPLE_FLAGS)
3343 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_flags))
3350 GST_WARNING_OBJECT (qtdemux, "invalid track fragment header");
3355 GST_DEBUG_OBJECT (qtdemux, "unknown stream in tfhd");
3361 qtdemux_parse_tfdt (GstQTDemux * qtdemux, GstByteReader * br,
3362 guint64 * decode_time)
3364 guint32 version = 0;
3366 if (!gst_byte_reader_get_uint32_be (br, &version))
3371 if (!gst_byte_reader_get_uint64_be (br, decode_time))
3374 guint32 dec_time = 0;
3375 if (!gst_byte_reader_get_uint32_be (br, &dec_time))
3377 *decode_time = dec_time;
3380 GST_INFO_OBJECT (qtdemux, "Track fragment decode time: %" G_GUINT64_FORMAT,
3387 GST_DEBUG_OBJECT (qtdemux, "parsing tfdt failed");
3392 /* Returns a pointer to a GstStructure containing the properties of
3393 * the stream sample identified by @sample_index. The caller must unref
3394 * the returned object after use. Returns NULL if unsuccessful. */
3395 static GstStructure *
3396 qtdemux_get_cenc_sample_properties (GstQTDemux * qtdemux,
3397 QtDemuxStream * stream, guint sample_index)
3399 QtDemuxCencSampleSetInfo *info = NULL;
3401 g_return_val_if_fail (stream != NULL, NULL);
3402 g_return_val_if_fail (stream->protected, NULL);
3403 g_return_val_if_fail (stream->protection_scheme_info != NULL, NULL);
3405 info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
3407 /* Currently, cenc properties for groups of samples are not supported, so
3408 * simply return a copy of the default sample properties */
3409 return gst_structure_copy (info->default_properties);
3412 /* Parses the sizes of sample auxiliary information contained within a stream,
3413 * as given in a saiz box. Returns array of sample_count guint8 size values,
3414 * or NULL on failure */
3416 qtdemux_parse_saiz (GstQTDemux * qtdemux, QtDemuxStream * stream,
3417 GstByteReader * br, guint32 * sample_count)
3421 guint8 default_info_size;
3423 g_return_val_if_fail (qtdemux != NULL, NULL);
3424 g_return_val_if_fail (stream != NULL, NULL);
3425 g_return_val_if_fail (br != NULL, NULL);
3426 g_return_val_if_fail (sample_count != NULL, NULL);
3428 if (!gst_byte_reader_get_uint32_be (br, &flags))
3432 /* aux_info_type and aux_info_type_parameter are ignored */
3433 if (!gst_byte_reader_skip (br, 8))
3437 if (!gst_byte_reader_get_uint8 (br, &default_info_size))
3439 GST_DEBUG_OBJECT (qtdemux, "default_info_size: %u", default_info_size);
3441 if (!gst_byte_reader_get_uint32_be (br, sample_count))
3443 GST_DEBUG_OBJECT (qtdemux, "sample_count: %u", *sample_count);
3446 if (default_info_size == 0) {
3447 if (!gst_byte_reader_dup_data (br, *sample_count, &info_sizes)) {
3451 info_sizes = g_new (guint8, *sample_count);
3452 memset (info_sizes, default_info_size, *sample_count);
3458 /* Parses the offset of sample auxiliary information contained within a stream,
3459 * as given in a saio box. Returns TRUE if successful; FALSE otherwise. */
3461 qtdemux_parse_saio (GstQTDemux * qtdemux, QtDemuxStream * stream,
3462 GstByteReader * br, guint32 * info_type, guint32 * info_type_parameter,
3467 guint32 aux_info_type = 0;
3468 guint32 aux_info_type_parameter = 0;
3469 guint32 entry_count;
3472 const guint8 *aux_info_type_data = NULL;
3474 g_return_val_if_fail (qtdemux != NULL, FALSE);
3475 g_return_val_if_fail (stream != NULL, FALSE);
3476 g_return_val_if_fail (br != NULL, FALSE);
3477 g_return_val_if_fail (offset != NULL, FALSE);
3479 if (!gst_byte_reader_get_uint8 (br, &version))
3482 if (!gst_byte_reader_get_uint24_be (br, &flags))
3487 if (!gst_byte_reader_get_data (br, 4, &aux_info_type_data))
3489 aux_info_type = QT_FOURCC (aux_info_type_data);
3491 if (!gst_byte_reader_get_uint32_be (br, &aux_info_type_parameter))
3493 } else if (stream->protected) {
3494 aux_info_type = stream->protection_scheme_type;
3496 aux_info_type = stream->fourcc;
3500 *info_type = aux_info_type;
3501 if (info_type_parameter)
3502 *info_type_parameter = aux_info_type_parameter;
3504 GST_DEBUG_OBJECT (qtdemux, "aux_info_type: '%" GST_FOURCC_FORMAT "', "
3505 "aux_info_type_parameter: %#06x",
3506 GST_FOURCC_ARGS (aux_info_type), aux_info_type_parameter);
3508 if (!gst_byte_reader_get_uint32_be (br, &entry_count))
3511 if (entry_count != 1) {
3512 GST_ERROR_OBJECT (qtdemux, "multiple offsets are not supported");
3517 if (!gst_byte_reader_get_uint32_be (br, &off_32))
3519 *offset = (guint64) off_32;
3521 if (!gst_byte_reader_get_uint64_be (br, &off_64))
3526 GST_DEBUG_OBJECT (qtdemux, "offset: %" G_GUINT64_FORMAT, *offset);
3531 qtdemux_gst_structure_free (GstStructure * gststructure)
3534 gst_structure_free (gststructure);
3538 /* Parses auxiliary information relating to samples protected using Common
3539 * Encryption (cenc); the format of this information is defined in
3540 * ISO/IEC 23001-7. Returns TRUE if successful; FALSE otherwise. */
3542 qtdemux_parse_cenc_aux_info (GstQTDemux * qtdemux, QtDemuxStream * stream,
3543 GstByteReader * br, guint8 * info_sizes, guint32 sample_count)
3545 QtDemuxCencSampleSetInfo *ss_info = NULL;
3549 g_return_val_if_fail (qtdemux != NULL, FALSE);
3550 g_return_val_if_fail (stream != NULL, FALSE);
3551 g_return_val_if_fail (br != NULL, FALSE);
3552 g_return_val_if_fail (stream->protected, FALSE);
3553 g_return_val_if_fail (stream->protection_scheme_info != NULL, FALSE);
3555 ss_info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
3557 if (ss_info->crypto_info) {
3558 GST_LOG_OBJECT (qtdemux, "unreffing existing crypto_info");
3559 g_ptr_array_free (ss_info->crypto_info, TRUE);
3562 ss_info->crypto_info =
3563 g_ptr_array_new_full (sample_count,
3564 (GDestroyNotify) qtdemux_gst_structure_free);
3566 for (i = 0; i < sample_count; ++i) {
3567 GstStructure *properties;
3568 guint16 n_subsamples = 0;
3573 properties = qtdemux_get_cenc_sample_properties (qtdemux, stream, i);
3574 if (properties == NULL) {
3575 GST_ERROR_OBJECT (qtdemux, "failed to get properties for sample %u", i);
3578 if (!gst_structure_get_uint (properties, "iv_size", &iv_size)) {
3579 GST_ERROR_OBJECT (qtdemux, "failed to get iv_size for sample %u", i);
3580 gst_structure_free (properties);
3583 if (!gst_byte_reader_dup_data (br, iv_size, &data)) {
3584 GST_ERROR_OBJECT (qtdemux, "failed to get IV for sample %u", i);
3585 gst_structure_free (properties);
3588 buf = gst_buffer_new_wrapped (data, iv_size);
3589 gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL);
3590 gst_buffer_unref (buf);
3591 size = info_sizes[i];
3592 if (size > iv_size) {
3593 if (!gst_byte_reader_get_uint16_be (br, &n_subsamples)
3594 || !(n_subsamples > 0)) {
3595 gst_structure_free (properties);
3596 GST_ERROR_OBJECT (qtdemux,
3597 "failed to get subsample count for sample %u", i);
3600 GST_LOG_OBJECT (qtdemux, "subsample count: %u", n_subsamples);
3601 if (!gst_byte_reader_dup_data (br, n_subsamples * 6, &data)) {
3602 GST_ERROR_OBJECT (qtdemux, "failed to get subsample data for sample %u",
3604 gst_structure_free (properties);
3607 buf = gst_buffer_new_wrapped (data, n_subsamples * 6);
3609 gst_structure_free (properties);
3612 gst_structure_set (properties,
3613 "subsample_count", G_TYPE_UINT, n_subsamples,
3614 "subsamples", GST_TYPE_BUFFER, buf, NULL);
3615 gst_buffer_unref (buf);
3617 gst_structure_set (properties, "subsample_count", G_TYPE_UINT, 0, NULL);
3619 g_ptr_array_add (ss_info->crypto_info, properties);
3624 /* Converts a UUID in raw byte form to a string representation, as defined in
3625 * RFC 4122. The caller takes ownership of the returned string and is
3626 * responsible for freeing it after use. */
3628 qtdemux_uuid_bytes_to_string (gconstpointer uuid_bytes)
3630 const guint8 *uuid = (const guint8 *) uuid_bytes;
3632 return g_strdup_printf ("%02x%02x%02x%02x-%02x%02x-%02x%02x-"
3633 "%02x%02x-%02x%02x%02x%02x%02x%02x",
3634 uuid[0], uuid[1], uuid[2], uuid[3],
3635 uuid[4], uuid[5], uuid[6], uuid[7],
3636 uuid[8], uuid[9], uuid[10], uuid[11],
3637 uuid[12], uuid[13], uuid[14], uuid[15]);
3640 /* Parses a Protection System Specific Header box (pssh), as defined in the
3641 * Common Encryption (cenc) standard (ISO/IEC 23001-7), which contains
3642 * information needed by a specific content protection system in order to
3643 * decrypt cenc-protected tracks. Returns TRUE if successful; FALSE
3646 qtdemux_parse_pssh (GstQTDemux * qtdemux, GNode * node)
3648 gchar *sysid_string;
3649 guint32 pssh_size = QT_UINT32 (node->data);
3650 GstBuffer *pssh = NULL;
3651 GstEvent *event = NULL;
3652 guint32 parent_box_type;
3655 if (G_UNLIKELY (pssh_size < 32U)) {
3656 GST_ERROR_OBJECT (qtdemux, "invalid box size");
3661 qtdemux_uuid_bytes_to_string ((const guint8 *) node->data + 12);
3663 gst_qtdemux_append_protection_system_id (qtdemux, sysid_string);
3665 pssh = gst_buffer_new_wrapped (g_memdup (node->data, pssh_size), pssh_size);
3666 GST_LOG_OBJECT (qtdemux, "cenc pssh size: %" G_GSIZE_FORMAT,
3667 gst_buffer_get_size (pssh));
3669 parent_box_type = QT_FOURCC ((const guint8 *) node->parent->data + 4);
3671 /* Push an event containing the pssh box onto the queues of all streams. */
3672 event = gst_event_new_protection (sysid_string, pssh,
3673 (parent_box_type == FOURCC_moov) ? "isobmff/moov" : "isobmff/moof");
3674 for (i = 0; i < qtdemux->n_streams; ++i) {
3675 g_queue_push_tail (&qtdemux->streams[i]->protection_scheme_event_queue,
3676 gst_event_ref (event));
3678 g_free (sysid_string);
3679 gst_event_unref (event);
3680 gst_buffer_unref (pssh);
3685 qtdemux_parse_moof (GstQTDemux * qtdemux, const guint8 * buffer, guint length,
3686 guint64 moof_offset, QtDemuxStream * stream)
3688 GNode *moof_node, *traf_node, *tfhd_node, *trun_node, *tfdt_node, *mfhd_node;
3690 GstByteReader mfhd_data, trun_data, tfhd_data, tfdt_data;
3691 GNode *saiz_node, *saio_node, *pssh_node;
3692 GstByteReader saiz_data, saio_data;
3693 guint32 ds_size = 0, ds_duration = 0, ds_flags = 0;
3694 gint64 base_offset, running_offset;
3697 /* NOTE @stream ignored */
3699 moof_node = g_node_new ((guint8 *) buffer);
3700 qtdemux_parse_node (qtdemux, moof_node, buffer, length);
3701 qtdemux_node_dump (qtdemux, moof_node);
3703 /* Get fragment number from mfhd and check it's valid */
3705 qtdemux_tree_get_child_by_type_full (moof_node, FOURCC_mfhd, &mfhd_data);
3706 if (mfhd_node == NULL)
3708 if (!qtdemux_parse_mfhd (qtdemux, &mfhd_data, &frag_num))
3710 GST_DEBUG_OBJECT (qtdemux, "Fragment #%d", frag_num);
3712 /* unknown base_offset to start with */
3713 base_offset = running_offset = -1;
3714 traf_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_traf);
3716 guint64 decode_time = 0;
3718 /* Fragment Header node */
3720 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfhd,
3724 if (!qtdemux_parse_tfhd (qtdemux, &tfhd_data, &stream, &ds_duration,
3725 &ds_size, &ds_flags, &base_offset))
3728 /* The following code assumes at most a single set of sample auxiliary
3729 * data in the fragment (consisting of a saiz box and a corresponding saio
3730 * box); in theory, however, there could be multiple sets of sample
3731 * auxiliary data in a fragment. */
3733 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saiz,
3736 guint32 info_type = 0;
3738 guint32 info_type_parameter = 0;
3740 g_free (qtdemux->cenc_aux_info_sizes);
3742 qtdemux->cenc_aux_info_sizes =
3743 qtdemux_parse_saiz (qtdemux, stream, &saiz_data,
3744 &qtdemux->cenc_aux_sample_count);
3745 if (qtdemux->cenc_aux_info_sizes == NULL) {
3746 GST_ERROR_OBJECT (qtdemux, "failed to parse saiz box");
3750 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saio,
3753 GST_ERROR_OBJECT (qtdemux, "saiz box without a corresponding saio box");
3754 g_free (qtdemux->cenc_aux_info_sizes);
3755 qtdemux->cenc_aux_info_sizes = NULL;
3759 if (G_UNLIKELY (!qtdemux_parse_saio (qtdemux, stream, &saio_data,
3760 &info_type, &info_type_parameter, &offset))) {
3761 GST_ERROR_OBJECT (qtdemux, "failed to parse saio box");
3762 g_free (qtdemux->cenc_aux_info_sizes);
3763 qtdemux->cenc_aux_info_sizes = NULL;
3766 if (base_offset > -1 && base_offset > qtdemux->moof_offset)
3767 offset += (guint64) (base_offset - qtdemux->moof_offset);
3768 if (info_type == FOURCC_cenc && info_type_parameter == 0U) {
3770 if (offset > length) {
3771 GST_DEBUG_OBJECT (qtdemux, "cenc auxiliary info stored out of moof");
3772 qtdemux->cenc_aux_info_offset = offset;
3774 gst_byte_reader_init (&br, buffer + offset, length - offset);
3775 if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
3776 qtdemux->cenc_aux_info_sizes,
3777 qtdemux->cenc_aux_sample_count)) {
3778 GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
3779 g_free (qtdemux->cenc_aux_info_sizes);
3780 qtdemux->cenc_aux_info_sizes = NULL;
3788 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfdt,
3791 /* We'll use decode_time to interpolate timestamps
3792 * in case the input timestamps are missing */
3793 qtdemux_parse_tfdt (qtdemux, &tfdt_data, &decode_time);
3795 GST_DEBUG_OBJECT (qtdemux, "decode time %" G_GINT64_FORMAT
3796 " (%" GST_TIME_FORMAT ")", decode_time,
3797 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, decode_time)));
3799 /* Discard the fragment buffer timestamp info to avoid using it.
3800 * Rely on tfdt instead as it is more accurate than the timestamp
3801 * that is fetched from a manifest/playlist and is usually
3803 qtdemux->fragment_start = -1;
3806 if (G_UNLIKELY (!stream)) {
3807 /* we lost track of offset, we'll need to regain it,
3808 * but can delay complaining until later or avoid doing so altogether */
3812 if (G_UNLIKELY (base_offset < -1))
3815 if (qtdemux->upstream_format_is_time)
3816 gst_qtdemux_stream_flush_samples_data (qtdemux, stream);
3818 /* initialise moof sample data */
3819 stream->n_samples_moof = 0;
3820 stream->duration_last_moof = stream->duration_moof;
3821 stream->duration_moof = 0;
3823 /* Track Run node */
3825 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_trun,
3828 qtdemux_parse_trun (qtdemux, &trun_data, stream,
3829 ds_duration, ds_size, ds_flags, moof_offset, length, &base_offset,
3830 &running_offset, decode_time);
3831 /* iterate all siblings */
3832 trun_node = qtdemux_tree_get_sibling_by_type_full (trun_node, FOURCC_trun,
3836 uuid_node = qtdemux_tree_get_child_by_type (traf_node, FOURCC_uuid);
3838 guint8 *uuid_buffer = (guint8 *) uuid_node->data;
3839 guint32 box_length = QT_UINT32 (uuid_buffer);
3841 qtdemux_parse_uuid (qtdemux, uuid_buffer, box_length);
3844 /* if no new base_offset provided for next traf,
3845 * base is end of current traf */
3846 base_offset = running_offset;
3847 running_offset = -1;
3849 if (stream->n_samples_moof && stream->duration_moof)
3850 stream->new_caps = TRUE;
3853 /* iterate all siblings */
3854 traf_node = qtdemux_tree_get_sibling_by_type (traf_node, FOURCC_traf);
3857 /* parse any protection system info */
3858 pssh_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_pssh);
3860 GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
3861 qtdemux_parse_pssh (qtdemux, pssh_node);
3862 pssh_node = qtdemux_tree_get_sibling_by_type (pssh_node, FOURCC_pssh);
3865 g_node_destroy (moof_node);
3870 GST_DEBUG_OBJECT (qtdemux, "missing tfhd box");
3875 GST_DEBUG_OBJECT (qtdemux, "Missing mfhd box");
3880 GST_DEBUG_OBJECT (qtdemux, "lost offset");
3885 g_node_destroy (moof_node);
3886 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
3887 (_("This file is corrupt and cannot be played.")), (NULL));
3893 /* might be used if some day we actually use mfra & co
3894 * for random access to fragments,
3895 * but that will require quite some modifications and much less relying
3896 * on a sample array */
3900 qtdemux_parse_tfra (GstQTDemux * qtdemux, GNode * tfra_node)
3902 QtDemuxStream *stream;
3903 guint32 ver_flags, track_id, len, num_entries, i;
3904 guint value_size, traf_size, trun_size, sample_size;
3905 guint64 time = 0, moof_offset = 0;
3907 GstBuffer *buf = NULL;
3912 gst_byte_reader_init (&tfra, tfra_node->data, QT_UINT32 (tfra_node->data));
3914 if (!gst_byte_reader_skip (&tfra, 8))
3917 if (!gst_byte_reader_get_uint32_be (&tfra, &ver_flags))
3920 if (!gst_byte_reader_get_uint32_be (&tfra, &track_id)
3921 || !gst_byte_reader_get_uint32_be (&tfra, &len)
3922 || !gst_byte_reader_get_uint32_be (&tfra, &num_entries))
3925 GST_DEBUG_OBJECT (qtdemux, "parsing tfra box for track id %u", track_id);
3927 stream = qtdemux_find_stream (qtdemux, track_id);
3929 goto unknown_trackid;
3931 value_size = ((ver_flags >> 24) == 1) ? sizeof (guint64) : sizeof (guint32);
3932 sample_size = (len & 3) + 1;
3933 trun_size = ((len & 12) >> 2) + 1;
3934 traf_size = ((len & 48) >> 4) + 1;
3936 GST_DEBUG_OBJECT (qtdemux, "%u entries, sizes: value %u, traf %u, trun %u, "
3937 "sample %u", num_entries, value_size, traf_size, trun_size, sample_size);
3939 if (num_entries == 0)
3942 if (!qt_atom_parser_has_chunks (&tfra, num_entries,
3943 value_size + value_size + traf_size + trun_size + sample_size))
3946 g_free (stream->ra_entries);
3947 stream->ra_entries = g_new (QtDemuxRandomAccessEntry, num_entries);
3948 stream->n_ra_entries = num_entries;
3950 for (i = 0; i < num_entries; i++) {
3951 qt_atom_parser_get_offset (&tfra, value_size, &time);
3952 qt_atom_parser_get_offset (&tfra, value_size, &moof_offset);
3953 qt_atom_parser_get_uint_with_size_unchecked (&tfra, traf_size);
3954 qt_atom_parser_get_uint_with_size_unchecked (&tfra, trun_size);
3955 qt_atom_parser_get_uint_with_size_unchecked (&tfra, sample_size);
3957 time = QTSTREAMTIME_TO_GSTTIME (stream, time);
3959 GST_LOG_OBJECT (qtdemux, "fragment time: %" GST_TIME_FORMAT ", "
3960 " moof_offset: %" G_GUINT64_FORMAT, GST_TIME_ARGS (time), moof_offset);
3962 stream->ra_entries[i].ts = time;
3963 stream->ra_entries[i].moof_offset = moof_offset;
3965 /* don't want to go through the entire file and read all moofs at startup */
3967 ret = gst_qtdemux_pull_atom (qtdemux, moof_offset, 0, &buf);
3968 if (ret != GST_FLOW_OK)
3970 qtdemux_parse_moof (qtdemux, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf),
3971 moof_offset, stream);
3972 gst_buffer_unref (buf);
3976 check_update_duration (qtdemux, time);
3983 GST_WARNING_OBJECT (qtdemux, "Couldn't find stream for track %u", track_id);
3988 GST_WARNING_OBJECT (qtdemux, "broken traf box, ignoring");
3993 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
3999 qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux)
4001 GstMapInfo mfro_map = GST_MAP_INFO_INIT;
4002 GstMapInfo mfra_map = GST_MAP_INFO_INIT;
4003 GstBuffer *mfro = NULL, *mfra = NULL;
4005 gboolean ret = FALSE;
4006 GNode *mfra_node, *tfra_node;
4007 guint64 mfra_offset = 0;
4008 guint32 fourcc, mfra_size;
4011 /* query upstream size in bytes */
4012 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &len))
4013 goto size_query_failed;
4015 /* mfro box should be at the very end of the file */
4016 flow = gst_qtdemux_pull_atom (qtdemux, len - 16, 16, &mfro);
4017 if (flow != GST_FLOW_OK)
4020 gst_buffer_map (mfro, &mfro_map, GST_MAP_READ);
4022 fourcc = QT_FOURCC (mfro_map.data + 4);
4023 if (fourcc != FOURCC_mfro)
4026 GST_INFO_OBJECT (qtdemux, "Found mfro box");
4027 if (mfro_map.size < 16)
4028 goto invalid_mfro_size;
4030 mfra_size = QT_UINT32 (mfro_map.data + 12);
4031 if (mfra_size >= len)
4032 goto invalid_mfra_size;
4034 mfra_offset = len - mfra_size;
4036 GST_INFO_OBJECT (qtdemux, "mfra offset: %" G_GUINT64_FORMAT ", size %u",
4037 mfra_offset, mfra_size);
4039 /* now get and parse mfra box */
4040 flow = gst_qtdemux_pull_atom (qtdemux, mfra_offset, mfra_size, &mfra);
4041 if (flow != GST_FLOW_OK)
4044 gst_buffer_map (mfra, &mfra_map, GST_MAP_READ);
4046 mfra_node = g_node_new ((guint8 *) mfra_map.data);
4047 qtdemux_parse_node (qtdemux, mfra_node, mfra_map.data, mfra_map.size);
4049 tfra_node = qtdemux_tree_get_child_by_type (mfra_node, FOURCC_tfra);
4052 qtdemux_parse_tfra (qtdemux, tfra_node);
4053 /* iterate all siblings */
4054 tfra_node = qtdemux_tree_get_sibling_by_type (tfra_node, FOURCC_tfra);
4056 g_node_destroy (mfra_node);
4058 GST_INFO_OBJECT (qtdemux, "parsed movie fragment random access box (mfra)");
4064 if (mfro_map.memory != NULL)
4065 gst_buffer_unmap (mfro, &mfro_map);
4066 gst_buffer_unref (mfro);
4069 if (mfra_map.memory != NULL)
4070 gst_buffer_unmap (mfra, &mfra_map);
4071 gst_buffer_unref (mfra);
4078 GST_WARNING_OBJECT (qtdemux, "could not query upstream size");
4083 GST_WARNING_OBJECT (qtdemux, "mfro size is too small");
4088 GST_WARNING_OBJECT (qtdemux, "mfra_size in mfro box is invalid");
4093 GST_WARNING_OBJECT (qtdemux, "bogus mfra offset or size, broken file");
4099 add_offset (guint64 offset, guint64 advance)
4101 /* Avoid 64-bit overflow by clamping */
4102 if (offset > G_MAXUINT64 - advance)
4104 return offset + advance;
4107 static GstFlowReturn
4108 gst_qtdemux_loop_state_header (GstQTDemux * qtdemux)
4112 GstBuffer *buf = NULL;
4113 GstFlowReturn ret = GST_FLOW_OK;
4114 guint64 cur_offset = qtdemux->offset;
4117 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, 16, &buf);
4118 if (G_UNLIKELY (ret != GST_FLOW_OK))
4120 gst_buffer_map (buf, &map, GST_MAP_READ);
4121 if (G_LIKELY (map.size >= 8))
4122 extract_initial_length_and_fourcc (map.data, map.size, &length, &fourcc);
4123 gst_buffer_unmap (buf, &map);
4124 gst_buffer_unref (buf);
4126 /* maybe we already got most we needed, so only consider this eof */
4127 if (G_UNLIKELY (length == 0)) {
4128 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
4129 (_("Invalid atom size.")),
4130 ("Header atom '%" GST_FOURCC_FORMAT "' has empty length",
4131 GST_FOURCC_ARGS (fourcc)));
4138 /* record for later parsing when needed */
4139 if (!qtdemux->moof_offset) {
4140 qtdemux->moof_offset = qtdemux->offset;
4142 if (qtdemux_pull_mfro_mfra (qtdemux)) {
4145 qtdemux->offset += length; /* skip moof and keep going */
4147 if (qtdemux->got_moov) {
4148 GST_INFO_OBJECT (qtdemux, "moof header, got moov, done with headers");
4159 GST_LOG_OBJECT (qtdemux,
4160 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
4161 GST_FOURCC_ARGS (fourcc), cur_offset);
4162 qtdemux->offset = add_offset (qtdemux->offset, length);
4167 GstBuffer *moov = NULL;
4169 if (qtdemux->got_moov) {
4170 GST_DEBUG_OBJECT (qtdemux, "Skipping moov atom as we have one already");
4171 qtdemux->offset = add_offset (qtdemux->offset, length);
4175 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, length, &moov);
4176 if (ret != GST_FLOW_OK)
4178 gst_buffer_map (moov, &map, GST_MAP_READ);
4180 if (length != map.size) {
4181 /* Some files have a 'moov' atom at the end of the file which contains
4182 * a terminal 'free' atom where the body of the atom is missing.
4183 * Check for, and permit, this special case.
4185 if (map.size >= 8) {
4186 guint8 *final_data = map.data + (map.size - 8);
4187 guint32 final_length = QT_UINT32 (final_data);
4188 guint32 final_fourcc = QT_FOURCC (final_data + 4);
4190 if (final_fourcc == FOURCC_free
4191 && map.size + final_length - 8 == length) {
4192 /* Ok, we've found that special case. Allocate a new buffer with
4193 * that free atom actually present. */
4194 GstBuffer *newmoov = gst_buffer_new_and_alloc (length);
4195 gst_buffer_fill (newmoov, 0, map.data, map.size);
4196 gst_buffer_memset (newmoov, map.size, 0, final_length - 8);
4197 gst_buffer_unmap (moov, &map);
4198 gst_buffer_unref (moov);
4200 gst_buffer_map (moov, &map, GST_MAP_READ);
4205 if (length != map.size) {
4206 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4207 (_("This file is incomplete and cannot be played.")),
4208 ("We got less than expected (received %" G_GSIZE_FORMAT
4209 ", wanted %u, offset %" G_GUINT64_FORMAT ")", map.size,
4210 (guint) length, cur_offset));
4211 gst_buffer_unmap (moov, &map);
4212 gst_buffer_unref (moov);
4213 ret = GST_FLOW_ERROR;
4216 qtdemux->offset += length;
4218 qtdemux_parse_moov (qtdemux, map.data, length);
4219 qtdemux_node_dump (qtdemux, qtdemux->moov_node);
4221 qtdemux_parse_tree (qtdemux);
4222 g_node_destroy (qtdemux->moov_node);
4223 gst_buffer_unmap (moov, &map);
4224 gst_buffer_unref (moov);
4225 qtdemux->moov_node = NULL;
4226 qtdemux->got_moov = TRUE;
4232 GstBuffer *ftyp = NULL;
4234 /* extract major brand; might come in handy for ISO vs QT issues */
4235 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &ftyp);
4236 if (ret != GST_FLOW_OK)
4238 qtdemux->offset += length;
4239 gst_buffer_map (ftyp, &map, GST_MAP_READ);
4240 qtdemux_parse_ftyp (qtdemux, map.data, map.size);
4241 gst_buffer_unmap (ftyp, &map);
4242 gst_buffer_unref (ftyp);
4247 GstBuffer *uuid = NULL;
4249 /* uuid are extension atoms */
4250 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &uuid);
4251 if (ret != GST_FLOW_OK)
4253 qtdemux->offset += length;
4254 gst_buffer_map (uuid, &map, GST_MAP_READ);
4255 qtdemux_parse_uuid (qtdemux, map.data, map.size);
4256 gst_buffer_unmap (uuid, &map);
4257 gst_buffer_unref (uuid);
4262 GstBuffer *sidx = NULL;
4263 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &sidx);
4264 if (ret != GST_FLOW_OK)
4266 qtdemux->offset += length;
4267 gst_buffer_map (sidx, &map, GST_MAP_READ);
4268 qtdemux_parse_sidx (qtdemux, map.data, map.size);
4269 gst_buffer_unmap (sidx, &map);
4270 gst_buffer_unref (sidx);
4275 GstBuffer *unknown = NULL;
4277 GST_LOG_OBJECT (qtdemux,
4278 "unknown %08x '%" GST_FOURCC_FORMAT "' of size %" G_GUINT64_FORMAT
4279 " at %" G_GUINT64_FORMAT, fourcc, GST_FOURCC_ARGS (fourcc), length,
4281 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &unknown);
4282 if (ret != GST_FLOW_OK)
4284 gst_buffer_map (unknown, &map, GST_MAP_READ);
4285 GST_MEMDUMP ("Unknown tag", map.data, map.size);
4286 gst_buffer_unmap (unknown, &map);
4287 gst_buffer_unref (unknown);
4288 qtdemux->offset += length;
4294 if (ret == GST_FLOW_EOS && (qtdemux->got_moov || qtdemux->media_caps)) {
4295 /* digested all data, show what we have */
4296 qtdemux_prepare_streams (qtdemux);
4297 ret = qtdemux_expose_streams (qtdemux);
4299 qtdemux->state = QTDEMUX_STATE_MOVIE;
4300 GST_DEBUG_OBJECT (qtdemux, "switching state to STATE_MOVIE (%d)",
4307 /* Seeks to the previous keyframe of the indexed stream and
4308 * aligns other streams with respect to the keyframe timestamp
4309 * of indexed stream. Only called in case of Reverse Playback
4311 static GstFlowReturn
4312 gst_qtdemux_seek_to_previous_keyframe (GstQTDemux * qtdemux)
4315 guint32 seg_idx = 0, k_index = 0;
4316 guint32 ref_seg_idx, ref_k_index;
4317 GstClockTime k_pos = 0, last_stop = 0;
4318 QtDemuxSegment *seg = NULL;
4319 QtDemuxStream *ref_str = NULL;
4320 guint64 seg_media_start_mov; /* segment media start time in mov format */
4323 /* Now we choose an arbitrary stream, get the previous keyframe timestamp
4324 * and finally align all the other streams on that timestamp with their
4325 * respective keyframes */
4326 for (n = 0; n < qtdemux->n_streams; n++) {
4327 QtDemuxStream *str = qtdemux->streams[n];
4329 /* No candidate yet, take the first stream */
4335 /* So that stream has a segment, we prefer video streams */
4336 if (str->subtype == FOURCC_vide) {
4342 if (G_UNLIKELY (!ref_str)) {
4343 GST_DEBUG_OBJECT (qtdemux, "couldn't find any stream");
4347 if (G_UNLIKELY (!ref_str->from_sample)) {
4348 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of the file");
4352 /* So that stream has been playing from from_sample to to_sample. We will
4353 * get the timestamp of the previous sample and search for a keyframe before
4354 * that. For audio streams we do an arbitrary jump in the past (10 samples) */
4355 if (ref_str->subtype == FOURCC_vide) {
4356 k_index = gst_qtdemux_find_keyframe (qtdemux, ref_str,
4357 ref_str->from_sample - 1);
4359 if (ref_str->from_sample >= 10)
4360 k_index = ref_str->from_sample - 10;
4366 ref_str->samples[k_index].timestamp +
4367 ref_str->samples[k_index].pts_offset;
4369 /* get current segment for that stream */
4370 seg = &ref_str->segments[ref_str->segment_index];
4371 /* Use segment start in original timescale for comparisons */
4372 seg_media_start_mov = seg->trak_media_start;
4374 GST_LOG_OBJECT (qtdemux, "keyframe index %u ts %" G_GUINT64_FORMAT
4375 " seg start %" G_GUINT64_FORMAT " %" GST_TIME_FORMAT "\n",
4376 k_index, target_ts, seg_media_start_mov,
4377 GST_TIME_ARGS (seg->media_start));
4379 /* Crawl back through segments to find the one containing this I frame */
4380 while (target_ts < seg_media_start_mov) {
4381 GST_DEBUG_OBJECT (qtdemux,
4382 "keyframe position (sample %u) is out of segment %u " " target %"
4383 G_GUINT64_FORMAT " seg start %" G_GUINT64_FORMAT, k_index,
4384 ref_str->segment_index, target_ts, seg_media_start_mov);
4386 if (G_UNLIKELY (!ref_str->segment_index)) {
4387 /* Reached first segment, let's consider it's EOS */
4390 ref_str->segment_index--;
4391 seg = &ref_str->segments[ref_str->segment_index];
4392 /* Use segment start in original timescale for comparisons */
4393 seg_media_start_mov = seg->trak_media_start;
4395 /* Calculate time position of the keyframe and where we should stop */
4397 QTSTREAMTIME_TO_GSTTIME (ref_str,
4398 target_ts - seg->trak_media_start) + seg->time;
4400 QTSTREAMTIME_TO_GSTTIME (ref_str,
4401 ref_str->samples[ref_str->from_sample].timestamp -
4402 seg->trak_media_start) + seg->time;
4404 GST_DEBUG_OBJECT (qtdemux, "preferred stream played from sample %u, "
4405 "now going to sample %u (pts %" GST_TIME_FORMAT ")", ref_str->from_sample,
4406 k_index, GST_TIME_ARGS (k_pos));
4408 /* Set last_stop with the keyframe timestamp we pushed of that stream */
4409 qtdemux->segment.position = last_stop;
4410 GST_DEBUG_OBJECT (qtdemux, "last_stop now is %" GST_TIME_FORMAT,
4411 GST_TIME_ARGS (last_stop));
4413 if (G_UNLIKELY (last_stop < qtdemux->segment.start)) {
4414 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of segment");
4418 ref_seg_idx = ref_str->segment_index;
4419 ref_k_index = k_index;
4421 /* Align them all on this */
4422 for (n = 0; n < qtdemux->n_streams; n++) {
4424 GstClockTime seg_time = 0;
4425 QtDemuxStream *str = qtdemux->streams[n];
4427 /* aligning reference stream again might lead to backing up to yet another
4428 * keyframe (due to timestamp rounding issues),
4429 * potentially putting more load on downstream; so let's try to avoid */
4430 if (str == ref_str) {
4431 seg_idx = ref_seg_idx;
4432 seg = &str->segments[seg_idx];
4433 k_index = ref_k_index;
4434 GST_DEBUG_OBJECT (qtdemux, "reference stream %d segment %d, "
4435 "sample at index %d", n, ref_str->segment_index, k_index);
4437 seg_idx = gst_qtdemux_find_segment (qtdemux, str, k_pos);
4438 GST_DEBUG_OBJECT (qtdemux,
4439 "stream %d align segment %d for keyframe pos %" GST_TIME_FORMAT, n,
4440 seg_idx, GST_TIME_ARGS (k_pos));
4442 /* get segment and time in the segment */
4443 seg = &str->segments[seg_idx];
4444 seg_time = k_pos - seg->time;
4446 /* get the media time in the segment.
4447 * No adjustment for empty "filler" segments */
4448 if (seg->media_start != GST_CLOCK_TIME_NONE)
4449 seg_time += seg->media_start;
4451 /* get the index of the sample with media time */
4452 index = gst_qtdemux_find_index_linear (qtdemux, str, seg_time);
4453 GST_DEBUG_OBJECT (qtdemux,
4454 "stream %d sample for %" GST_TIME_FORMAT " at %u", n,
4455 GST_TIME_ARGS (seg_time), index);
4457 /* find previous keyframe */
4458 k_index = gst_qtdemux_find_keyframe (qtdemux, str, index);
4461 /* Remember until where we want to go */
4462 str->to_sample = str->from_sample - 1;
4463 /* Define our time position */
4465 str->samples[k_index].timestamp + str->samples[k_index].pts_offset;
4466 str->time_position = QTSTREAMTIME_TO_GSTTIME (str, target_ts) + seg->time;
4467 if (seg->media_start != GST_CLOCK_TIME_NONE)
4468 str->time_position -= seg->media_start;
4470 /* Now seek back in time */
4471 gst_qtdemux_move_stream (qtdemux, str, k_index);
4472 GST_DEBUG_OBJECT (qtdemux, "stream %d keyframe at %u, time position %"
4473 GST_TIME_FORMAT " playing from sample %u to %u", n, k_index,
4474 GST_TIME_ARGS (str->time_position), str->from_sample, str->to_sample);
4480 return GST_FLOW_EOS;
4484 * Gets the current qt segment start, stop and position for the
4485 * given time offset. This is used in update_segment()
4488 gst_qtdemux_stream_segment_get_boundaries (GstQTDemux * qtdemux,
4489 QtDemuxStream * stream, GstClockTime offset,
4490 GstClockTime * _start, GstClockTime * _stop, GstClockTime * _time)
4492 GstClockTime seg_time;
4493 GstClockTime start, stop, time;
4494 QtDemuxSegment *segment;
4496 segment = &stream->segments[stream->segment_index];
4498 /* get time in this segment */
4499 seg_time = (offset - segment->time) * segment->rate;
4501 GST_LOG_OBJECT (stream->pad, "seg_time %" GST_TIME_FORMAT,
4502 GST_TIME_ARGS (seg_time));
4504 if (G_UNLIKELY (seg_time > segment->duration)) {
4505 GST_LOG_OBJECT (stream->pad,
4506 "seg_time > segment->duration %" GST_TIME_FORMAT,
4507 GST_TIME_ARGS (segment->duration));
4508 seg_time = segment->duration;
4511 /* qtdemux->segment.stop is in outside-time-realm, whereas
4512 * segment->media_stop is in track-time-realm.
4514 * In order to compare the two, we need to bring segment.stop
4515 * into the track-time-realm
4517 * FIXME - does this comment still hold? Don't see any conversion here */
4519 stop = qtdemux->segment.stop;
4520 if (stop == GST_CLOCK_TIME_NONE)
4521 stop = qtdemux->segment.duration;
4522 if (stop == GST_CLOCK_TIME_NONE)
4523 stop = segment->media_stop;
4526 MIN (segment->media_stop, stop - segment->time + segment->media_start);
4528 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
4529 start = segment->time + seg_time;
4531 stop = start - seg_time + segment->duration;
4532 } else if (qtdemux->segment.rate >= 0) {
4533 start = MIN (segment->media_start + seg_time, stop);
4536 if (segment->media_start >= qtdemux->segment.start) {
4537 time = segment->time;
4539 time = segment->time + (qtdemux->segment.start - segment->media_start);
4542 start = MAX (segment->media_start, qtdemux->segment.start);
4543 stop = MIN (segment->media_start + seg_time, stop);
4552 * Updates the qt segment used for the stream and pushes a new segment event
4553 * downstream on this stream's pad.
4556 gst_qtdemux_stream_update_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
4557 gint seg_idx, GstClockTime offset, GstClockTime * _start,
4558 GstClockTime * _stop)
4560 QtDemuxSegment *segment;
4561 GstClockTime start = 0, stop = GST_CLOCK_TIME_NONE, time = 0;
4565 /* update the current segment */
4566 stream->segment_index = seg_idx;
4568 /* get the segment */
4569 segment = &stream->segments[seg_idx];
4571 if (G_UNLIKELY (offset < segment->time)) {
4572 GST_WARNING_OBJECT (stream->pad, "offset < segment->time %" GST_TIME_FORMAT,
4573 GST_TIME_ARGS (segment->time));
4577 /* segment lies beyond total indicated duration */
4578 if (G_UNLIKELY (qtdemux->segment.duration != GST_CLOCK_TIME_NONE &&
4579 segment->time > qtdemux->segment.duration)) {
4580 GST_WARNING_OBJECT (stream->pad, "file duration %" GST_TIME_FORMAT
4581 " < segment->time %" GST_TIME_FORMAT,
4582 GST_TIME_ARGS (qtdemux->segment.duration),
4583 GST_TIME_ARGS (segment->time));
4587 gst_qtdemux_stream_segment_get_boundaries (qtdemux, stream, offset,
4588 &start, &stop, &time);
4590 GST_DEBUG_OBJECT (stream->pad, "new segment %d from %" GST_TIME_FORMAT
4591 " to %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT, seg_idx,
4592 GST_TIME_ARGS (start), GST_TIME_ARGS (stop), GST_TIME_ARGS (time));
4594 /* combine global rate with that of the segment */
4595 rate = segment->rate * qtdemux->segment.rate;
4597 /* Copy flags from main segment */
4598 stream->segment.flags = qtdemux->segment.flags;
4600 /* update the segment values used for clipping */
4601 stream->segment.offset = qtdemux->segment.offset;
4602 stream->segment.base = qtdemux->segment.base + stream->accumulated_base;
4603 stream->segment.applied_rate = qtdemux->segment.applied_rate;
4604 stream->segment.rate = rate;
4605 stream->segment.start = start + QTSTREAMTIME_TO_GSTTIME (stream,
4606 stream->cslg_shift);
4607 stream->segment.stop = stop + QTSTREAMTIME_TO_GSTTIME (stream,
4608 stream->cslg_shift);
4609 stream->segment.time = time;
4610 stream->segment.position = stream->segment.start;
4612 GST_DEBUG_OBJECT (stream->pad, "New segment: %" GST_SEGMENT_FORMAT,
4615 /* now prepare and send the segment */
4617 event = gst_event_new_segment (&stream->segment);
4618 if (qtdemux->segment_seqnum) {
4619 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
4621 gst_pad_push_event (stream->pad, event);
4622 /* assume we can send more data now */
4623 GST_PAD_LAST_FLOW_RETURN (stream->pad) = GST_FLOW_OK;
4624 /* clear to send tags on this pad now */
4625 gst_qtdemux_push_tags (qtdemux, stream);
4636 /* activate the given segment number @seg_idx of @stream at time @offset.
4637 * @offset is an absolute global position over all the segments.
4639 * This will push out a NEWSEGMENT event with the right values and
4640 * position the stream index to the first decodable sample before
4644 gst_qtdemux_activate_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
4645 guint32 seg_idx, GstClockTime offset)
4647 QtDemuxSegment *segment;
4648 guint32 index, kf_index;
4649 GstClockTime start = 0, stop = GST_CLOCK_TIME_NONE;
4651 GST_LOG_OBJECT (stream->pad, "activate segment %d, offset %" GST_TIME_FORMAT,
4652 seg_idx, GST_TIME_ARGS (offset));
4654 if (!gst_qtdemux_stream_update_segment (qtdemux, stream, seg_idx, offset,
4658 segment = &stream->segments[stream->segment_index];
4660 /* in the fragmented case, we pick a fragment that starts before our
4661 * desired position and rely on downstream to wait for a keyframe
4662 * (FIXME: doesn't seem to work so well with ismv and wmv, as no parser; the
4663 * tfra entries tells us which trun/sample the key unit is in, but we don't
4664 * make use of this additional information at the moment) */
4665 if (qtdemux->fragmented) {
4666 stream->to_sample = G_MAXUINT32;
4670 /* We don't need to look for a sample in push-based */
4671 if (!qtdemux->pullbased)
4674 /* and move to the keyframe before the indicated media time of the
4676 if (G_LIKELY (!QTSEGMENT_IS_EMPTY (segment))) {
4677 if (qtdemux->segment.rate >= 0) {
4678 index = gst_qtdemux_find_index_linear (qtdemux, stream, start);
4679 stream->to_sample = G_MAXUINT32;
4680 GST_DEBUG_OBJECT (stream->pad,
4681 "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
4682 GST_TIME_FORMAT, GST_TIME_ARGS (start), index,
4683 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
4685 index = gst_qtdemux_find_index_linear (qtdemux, stream, stop);
4686 stream->to_sample = index;
4687 GST_DEBUG_OBJECT (stream->pad,
4688 "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
4689 GST_TIME_FORMAT, GST_TIME_ARGS (stop), index,
4690 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
4693 GST_DEBUG_OBJECT (stream->pad, "No need to look for keyframe, "
4694 "this is an empty segment");
4698 /* gst_qtdemux_parse_sample () called from gst_qtdemux_find_index_linear ()
4699 * encountered an error and printed a message so we return appropriately */
4703 /* we're at the right spot */
4704 if (index == stream->sample_index) {
4705 GST_DEBUG_OBJECT (stream->pad, "we are at the right index");
4709 /* find keyframe of the target index */
4710 kf_index = gst_qtdemux_find_keyframe (qtdemux, stream, index);
4713 /* indent does stupid stuff with stream->samples[].timestamp */
4715 /* if we move forwards, we don't have to go back to the previous
4716 * keyframe since we already sent that. We can also just jump to
4717 * the keyframe right before the target index if there is one. */
4718 if (index > stream->sample_index) {
4719 /* moving forwards check if we move past a keyframe */
4720 if (kf_index > stream->sample_index) {
4721 GST_DEBUG_OBJECT (stream->pad,
4722 "moving forwards to keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" )", kf_index,
4723 GST_TIME_ARGS (QTSAMPLE_PTS(stream, &stream->samples[kf_index])),
4724 GST_TIME_ARGS (QTSAMPLE_DTS(stream, &stream->samples[kf_index])));
4725 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
4727 GST_DEBUG_OBJECT (stream->pad,
4728 "moving forwards, keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" ) already sent", kf_index,
4729 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[kf_index])),
4730 GST_TIME_ARGS (QTSAMPLE_DTS (stream, &stream->samples[kf_index])));
4733 GST_DEBUG_OBJECT (stream->pad,
4734 "moving backwards to keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" )", kf_index,
4735 GST_TIME_ARGS (QTSAMPLE_PTS(stream, &stream->samples[kf_index])),
4736 GST_TIME_ARGS (QTSAMPLE_DTS(stream, &stream->samples[kf_index])));
4737 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
4745 /* prepare to get the current sample of @stream, getting essential values.
4747 * This function will also prepare and send the segment when needed.
4749 * Return FALSE if the stream is EOS.
4754 gst_qtdemux_prepare_current_sample (GstQTDemux * qtdemux,
4755 QtDemuxStream * stream, gboolean * empty, guint64 * offset, guint * size,
4756 GstClockTime * dts, GstClockTime * pts, GstClockTime * duration,
4757 gboolean * keyframe)
4759 QtDemuxSample *sample;
4760 GstClockTime time_position;
4763 g_return_val_if_fail (stream != NULL, FALSE);
4765 time_position = stream->time_position;
4766 if (G_UNLIKELY (time_position == GST_CLOCK_TIME_NONE))
4769 seg_idx = stream->segment_index;
4770 if (G_UNLIKELY (seg_idx == -1)) {
4771 /* find segment corresponding to time_position if we are looking
4773 seg_idx = gst_qtdemux_find_segment (qtdemux, stream, time_position);
4776 /* different segment, activate it, sample_index will be set. */
4777 if (G_UNLIKELY (stream->segment_index != seg_idx))
4778 gst_qtdemux_activate_segment (qtdemux, stream, seg_idx, time_position);
4780 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (&stream->segments[stream->
4782 QtDemuxSegment *seg = &stream->segments[stream->segment_index];
4784 GST_LOG_OBJECT (qtdemux, "Empty segment activated,"
4785 " prepare empty sample");
4788 *pts = *dts = time_position;
4789 *duration = seg->duration - (time_position - seg->time);
4796 if (stream->sample_index == -1)
4797 stream->sample_index = 0;
4799 GST_LOG_OBJECT (qtdemux, "segment active, index = %u of %u",
4800 stream->sample_index, stream->n_samples);
4802 if (G_UNLIKELY (stream->sample_index >= stream->n_samples)) {
4803 if (!qtdemux->fragmented)
4806 GST_INFO_OBJECT (qtdemux, "out of samples, trying to add more");
4810 GST_OBJECT_LOCK (qtdemux);
4811 flow = qtdemux_add_fragmented_samples (qtdemux);
4812 GST_OBJECT_UNLOCK (qtdemux);
4814 if (flow != GST_FLOW_OK)
4817 while (stream->sample_index >= stream->n_samples);
4820 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
4821 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
4822 stream->sample_index);
4826 /* now get the info for the sample we're at */
4827 sample = &stream->samples[stream->sample_index];
4829 *dts = QTSAMPLE_DTS (stream, sample);
4830 *pts = QTSAMPLE_PTS (stream, sample);
4831 *offset = sample->offset;
4832 *size = sample->size;
4833 *duration = QTSAMPLE_DUR_DTS (stream, sample, *dts);
4834 *keyframe = QTSAMPLE_KEYFRAME (stream, sample);
4841 stream->time_position = GST_CLOCK_TIME_NONE;
4846 /* move to the next sample in @stream.
4848 * Moves to the next segment when needed.
4851 gst_qtdemux_advance_sample (GstQTDemux * qtdemux, QtDemuxStream * stream)
4853 QtDemuxSample *sample;
4854 QtDemuxSegment *segment;
4856 /* get current segment */
4857 segment = &stream->segments[stream->segment_index];
4859 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
4860 GST_DEBUG_OBJECT (qtdemux, "Empty segment, no samples to advance");
4864 if (G_UNLIKELY (stream->sample_index >= stream->to_sample)) {
4865 /* Mark the stream as EOS */
4866 GST_DEBUG_OBJECT (qtdemux,
4867 "reached max allowed sample %u, mark EOS", stream->to_sample);
4868 stream->time_position = GST_CLOCK_TIME_NONE;
4872 /* move to next sample */
4873 stream->sample_index++;
4874 stream->offset_in_sample = 0;
4876 /* reached the last sample, we need the next segment */
4877 if (G_UNLIKELY (stream->sample_index >= stream->n_samples))
4880 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
4881 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
4882 stream->sample_index);
4886 /* get next sample */
4887 sample = &stream->samples[stream->sample_index];
4889 /* see if we are past the segment */
4890 if (G_UNLIKELY (QTSAMPLE_DTS (stream, sample) >= segment->media_stop))
4893 if (QTSAMPLE_DTS (stream, sample) >= segment->media_start) {
4894 /* inside the segment, update time_position, looks very familiar to
4895 * GStreamer segments, doesn't it? */
4896 stream->time_position =
4897 QTSAMPLE_DTS (stream, sample) - segment->media_start + segment->time;
4899 /* not yet in segment, time does not yet increment. This means
4900 * that we are still prerolling keyframes to the decoder so it can
4901 * decode the first sample of the segment. */
4902 stream->time_position = segment->time;
4906 /* move to the next segment */
4909 GST_DEBUG_OBJECT (qtdemux, "segment %d ended ", stream->segment_index);
4911 if (stream->segment_index == stream->n_segments - 1) {
4912 /* are we at the end of the last segment, we're EOS */
4913 stream->time_position = GST_CLOCK_TIME_NONE;
4915 /* else we're only at the end of the current segment */
4916 stream->time_position = segment->stop_time;
4918 /* make sure we select a new segment */
4920 /* accumulate previous segments */
4921 if (GST_CLOCK_TIME_IS_VALID (stream->segment.stop))
4922 stream->accumulated_base +=
4923 (stream->segment.stop -
4924 stream->segment.start) / ABS (stream->segment.rate);
4926 stream->segment_index = -1;
4931 gst_qtdemux_sync_streams (GstQTDemux * demux)
4935 if (demux->n_streams <= 1)
4938 for (i = 0; i < demux->n_streams; i++) {
4939 QtDemuxStream *stream;
4940 GstClockTime end_time;
4942 stream = demux->streams[i];
4947 /* TODO advance time on subtitle streams here, if any some day */
4949 /* some clips/trailers may have unbalanced streams at the end,
4950 * so send EOS on shorter stream to prevent stalling others */
4952 /* do not mess with EOS if SEGMENT seeking */
4953 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT)
4956 if (demux->pullbased) {
4957 /* loop mode is sample time based */
4958 if (!STREAM_IS_EOS (stream))
4961 /* push mode is byte position based */
4962 if (stream->n_samples &&
4963 stream->samples[stream->n_samples - 1].offset >= demux->offset)
4967 if (stream->sent_eos)
4970 /* only act if some gap */
4971 end_time = stream->segments[stream->n_segments - 1].stop_time;
4972 GST_LOG_OBJECT (demux, "current position: %" GST_TIME_FORMAT
4973 ", stream end: %" GST_TIME_FORMAT,
4974 GST_TIME_ARGS (demux->segment.position), GST_TIME_ARGS (end_time));
4975 if (GST_CLOCK_TIME_IS_VALID (end_time)
4976 && (end_time + 2 * GST_SECOND < demux->segment.position)) {
4979 GST_DEBUG_OBJECT (demux, "sending EOS for stream %s",
4980 GST_PAD_NAME (stream->pad));
4981 stream->sent_eos = TRUE;
4982 event = gst_event_new_eos ();
4983 if (demux->segment_seqnum)
4984 gst_event_set_seqnum (event, demux->segment_seqnum);
4985 gst_pad_push_event (stream->pad, event);
4990 /* EOS and NOT_LINKED need to be combined. This means that we return:
4992 * GST_FLOW_NOT_LINKED: when all pads NOT_LINKED.
4993 * GST_FLOW_EOS: when all pads EOS or NOT_LINKED.
4995 static GstFlowReturn
4996 gst_qtdemux_combine_flows (GstQTDemux * demux, QtDemuxStream * stream,
4999 GST_LOG_OBJECT (demux, "flow return: %s", gst_flow_get_name (ret));
5002 ret = gst_flow_combiner_update_pad_flow (demux->flowcombiner, stream->pad,
5005 ret = gst_flow_combiner_update_flow (demux->flowcombiner, ret);
5007 GST_LOG_OBJECT (demux, "combined flow return: %s", gst_flow_get_name (ret));
5011 /* the input buffer metadata must be writable. Returns NULL when the buffer is
5012 * completely clipped
5014 * Should be used only with raw buffers */
5016 gst_qtdemux_clip_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
5019 guint64 start, stop, cstart, cstop, diff;
5020 GstClockTime pts, duration;
5022 gint num_rate, denom_rate;
5027 osize = size = gst_buffer_get_size (buf);
5030 /* depending on the type, setup the clip parameters */
5031 if (stream->subtype == FOURCC_soun) {
5032 frame_size = stream->bytes_per_frame;
5033 num_rate = GST_SECOND;
5034 denom_rate = (gint) stream->rate;
5036 } else if (stream->subtype == FOURCC_vide) {
5038 num_rate = stream->fps_n;
5039 denom_rate = stream->fps_d;
5044 if (frame_size <= 0)
5045 goto bad_frame_size;
5047 /* we can only clip if we have a valid pts */
5048 pts = GST_BUFFER_PTS (buf);
5049 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (pts)))
5052 duration = GST_BUFFER_DURATION (buf);
5054 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (duration))) {
5056 gst_util_uint64_scale_int (size / frame_size, num_rate, denom_rate);
5060 stop = start + duration;
5062 if (G_UNLIKELY (!gst_segment_clip (&stream->segment,
5063 GST_FORMAT_TIME, start, stop, &cstart, &cstop)))
5066 /* see if some clipping happened */
5067 diff = cstart - start;
5073 /* bring clipped time to samples and to bytes */
5074 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
5077 GST_DEBUG_OBJECT (qtdemux,
5078 "clipping start to %" GST_TIME_FORMAT " %"
5079 G_GUINT64_FORMAT " bytes", GST_TIME_ARGS (cstart), diff);
5085 diff = stop - cstop;
5090 /* bring clipped time to samples and then to bytes */
5091 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
5093 GST_DEBUG_OBJECT (qtdemux,
5094 "clipping stop to %" GST_TIME_FORMAT " %" G_GUINT64_FORMAT
5095 " bytes", GST_TIME_ARGS (cstop), diff);
5100 if (offset != 0 || size != osize)
5101 gst_buffer_resize (buf, offset, size);
5103 GST_BUFFER_DTS (buf) = GST_CLOCK_TIME_NONE;
5104 GST_BUFFER_PTS (buf) = pts;
5105 GST_BUFFER_DURATION (buf) = duration;
5109 /* dropped buffer */
5112 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
5117 GST_DEBUG_OBJECT (qtdemux, "bad frame size");
5122 GST_DEBUG_OBJECT (qtdemux, "no pts on buffer");
5127 GST_DEBUG_OBJECT (qtdemux, "clipped buffer");
5128 gst_buffer_unref (buf);
5134 gst_qtdemux_align_buffer (GstQTDemux * demux,
5135 GstBuffer * buffer, gsize alignment)
5139 gst_buffer_map (buffer, &map, GST_MAP_READ);
5141 if (map.size < sizeof (guintptr)) {
5142 gst_buffer_unmap (buffer, &map);
5146 if (((guintptr) map.data) & (alignment - 1)) {
5147 GstBuffer *new_buffer;
5148 GstAllocationParams params = { 0, alignment - 1, 0, 0, };
5150 new_buffer = gst_buffer_new_allocate (NULL,
5151 gst_buffer_get_size (buffer), ¶ms);
5153 /* Copy data "by hand", so ensure alignment is kept: */
5154 gst_buffer_fill (new_buffer, 0, map.data, map.size);
5156 gst_buffer_copy_into (new_buffer, buffer, GST_BUFFER_COPY_METADATA, 0, -1);
5157 GST_DEBUG_OBJECT (demux,
5158 "We want output aligned on %" G_GSIZE_FORMAT ", reallocated",
5161 gst_buffer_unmap (buffer, &map);
5162 gst_buffer_unref (buffer);
5167 gst_buffer_unmap (buffer, &map);
5171 /* the input buffer metadata must be writable,
5172 * but time/duration etc not yet set and need not be preserved */
5174 gst_qtdemux_process_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
5181 /* not many cases for now */
5182 if (G_UNLIKELY (stream->fourcc == FOURCC_mp4s)) {
5183 /* send a one time dvd clut event */
5184 if (stream->pending_event && stream->pad)
5185 gst_pad_push_event (stream->pad, stream->pending_event);
5186 stream->pending_event = NULL;
5189 if (G_UNLIKELY (stream->subtype != FOURCC_text
5190 && stream->subtype != FOURCC_sbtl &&
5191 stream->subtype != FOURCC_subp)) {
5195 gst_buffer_map (buf, &map, GST_MAP_READ);
5197 /* empty buffer is sent to terminate previous subtitle */
5198 if (map.size <= 2) {
5199 gst_buffer_unmap (buf, &map);
5200 gst_buffer_unref (buf);
5203 if (stream->subtype == FOURCC_subp) {
5204 /* That's all the processing needed for subpictures */
5205 gst_buffer_unmap (buf, &map);
5209 nsize = GST_READ_UINT16_BE (map.data);
5210 nsize = MIN (nsize, map.size - 2);
5212 GST_LOG_OBJECT (qtdemux, "3GPP timed text subtitle: %d/%" G_GSIZE_FORMAT "",
5215 /* takes care of UTF-8 validation or UTF-16 recognition,
5216 * no other encoding expected */
5217 str = gst_tag_freeform_string_to_utf8 ((gchar *) map.data + 2, nsize, NULL);
5218 gst_buffer_unmap (buf, &map);
5220 gst_buffer_unref (buf);
5221 buf = _gst_buffer_new_wrapped (str, strlen (str), g_free);
5223 /* this should not really happen unless the subtitle is corrupted */
5224 gst_buffer_unref (buf);
5228 /* FIXME ? convert optional subsequent style info to markup */
5233 /* Sets a buffer's attributes properly and pushes it downstream.
5234 * Also checks for additional actions and custom processing that may
5235 * need to be done first.
5237 static GstFlowReturn
5238 gst_qtdemux_decorate_and_push_buffer (GstQTDemux * qtdemux,
5239 QtDemuxStream * stream, GstBuffer * buf,
5240 GstClockTime dts, GstClockTime pts, GstClockTime duration,
5241 gboolean keyframe, GstClockTime position, guint64 byte_position)
5243 GstFlowReturn ret = GST_FLOW_OK;
5245 /* offset the timestamps according to the edit list */
5247 if (G_UNLIKELY (stream->fourcc == FOURCC_rtsp)) {
5251 gst_buffer_map (buf, &map, GST_MAP_READ);
5252 url = g_strndup ((gchar *) map.data, map.size);
5253 gst_buffer_unmap (buf, &map);
5254 if (url != NULL && strlen (url) != 0) {
5255 /* we have RTSP redirect now */
5256 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
5257 gst_message_new_element (GST_OBJECT_CAST (qtdemux),
5258 gst_structure_new ("redirect",
5259 "new-location", G_TYPE_STRING, url, NULL)));
5260 qtdemux->posted_redirect = TRUE;
5262 GST_WARNING_OBJECT (qtdemux, "Redirect URI of stream is empty, not "
5268 /* position reporting */
5269 if (qtdemux->segment.rate >= 0) {
5270 qtdemux->segment.position = position;
5271 gst_qtdemux_sync_streams (qtdemux);
5274 if (G_UNLIKELY (!stream->pad)) {
5275 GST_DEBUG_OBJECT (qtdemux, "No output pad for stream, ignoring");
5276 gst_buffer_unref (buf);
5280 /* send out pending buffers */
5281 while (stream->buffers) {
5282 GstBuffer *buffer = (GstBuffer *) stream->buffers->data;
5284 if (G_UNLIKELY (stream->discont)) {
5285 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
5286 GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
5287 stream->discont = FALSE;
5289 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
5292 if (stream->alignment > 1)
5293 buffer = gst_qtdemux_align_buffer (qtdemux, buffer, stream->alignment);
5294 gst_pad_push (stream->pad, buffer);
5296 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
5299 /* we're going to modify the metadata */
5300 buf = gst_buffer_make_writable (buf);
5302 if (G_UNLIKELY (stream->need_process))
5303 buf = gst_qtdemux_process_buffer (qtdemux, stream, buf);
5309 GST_BUFFER_DTS (buf) = dts;
5310 GST_BUFFER_PTS (buf) = pts;
5311 GST_BUFFER_DURATION (buf) = duration;
5312 GST_BUFFER_OFFSET (buf) = -1;
5313 GST_BUFFER_OFFSET_END (buf) = -1;
5315 if (G_UNLIKELY (stream->rgb8_palette))
5316 gst_buffer_append_memory (buf, gst_memory_ref (stream->rgb8_palette));
5318 if (G_UNLIKELY (stream->padding)) {
5319 gst_buffer_resize (buf, stream->padding, -1);
5322 if (G_UNLIKELY (qtdemux->element_index)) {
5323 GstClockTime stream_time;
5326 gst_segment_to_stream_time (&stream->segment, GST_FORMAT_TIME,
5328 if (GST_CLOCK_TIME_IS_VALID (stream_time)) {
5329 GST_LOG_OBJECT (qtdemux,
5330 "adding association %" GST_TIME_FORMAT "-> %"
5331 G_GUINT64_FORMAT, GST_TIME_ARGS (stream_time), byte_position);
5332 gst_index_add_association (qtdemux->element_index,
5334 keyframe ? GST_ASSOCIATION_FLAG_KEY_UNIT :
5335 GST_ASSOCIATION_FLAG_DELTA_UNIT, GST_FORMAT_TIME, stream_time,
5336 GST_FORMAT_BYTES, byte_position, NULL);
5341 if (stream->need_clip)
5342 buf = gst_qtdemux_clip_buffer (qtdemux, stream, buf);
5344 if (G_UNLIKELY (buf == NULL))
5347 if (G_UNLIKELY (stream->discont)) {
5348 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
5349 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
5350 stream->discont = FALSE;
5352 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
5356 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
5357 stream->on_keyframe = FALSE;
5359 stream->on_keyframe = TRUE;
5363 GST_LOG_OBJECT (qtdemux,
5364 "Pushing buffer with dts %" GST_TIME_FORMAT ", pts %" GST_TIME_FORMAT
5365 ", duration %" GST_TIME_FORMAT " on pad %s", GST_TIME_ARGS (dts),
5366 GST_TIME_ARGS (pts), GST_TIME_ARGS (duration),
5367 GST_PAD_NAME (stream->pad));
5369 if (stream->protected && stream->protection_scheme_type == FOURCC_cenc) {
5370 GstStructure *crypto_info;
5371 QtDemuxCencSampleSetInfo *info =
5372 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
5376 while ((event = g_queue_pop_head (&stream->protection_scheme_event_queue))) {
5377 gst_pad_push_event (stream->pad, event);
5380 if (info->crypto_info == NULL) {
5381 GST_DEBUG_OBJECT (qtdemux, "cenc metadata hasn't been parsed yet");
5382 gst_buffer_unref (buf);
5386 index = stream->sample_index - (stream->n_samples - info->crypto_info->len);
5387 if (G_LIKELY (index >= 0 && index < info->crypto_info->len)) {
5388 /* steal structure from array */
5389 crypto_info = g_ptr_array_index (info->crypto_info, index);
5390 g_ptr_array_index (info->crypto_info, index) = NULL;
5391 GST_LOG_OBJECT (qtdemux, "attaching cenc metadata [%u]", index);
5392 if (!crypto_info || !gst_buffer_add_protection_meta (buf, crypto_info))
5393 GST_ERROR_OBJECT (qtdemux, "failed to attach cenc metadata to buffer");
5397 if (stream->alignment > 1)
5398 buf = gst_qtdemux_align_buffer (qtdemux, buf, stream->alignment);
5400 ret = gst_pad_push (stream->pad, buf);
5402 if (GST_CLOCK_TIME_IS_VALID (pts) && GST_CLOCK_TIME_IS_VALID (duration)) {
5403 /* mark position in stream, we'll need this to know when to send GAP event */
5404 stream->segment.position = pts + duration;
5411 static const QtDemuxRandomAccessEntry *
5412 gst_qtdemux_stream_seek_fragment (GstQTDemux * qtdemux, QtDemuxStream * stream,
5413 GstClockTime pos, gboolean after)
5415 QtDemuxRandomAccessEntry *entries = stream->ra_entries;
5416 guint n_entries = stream->n_ra_entries;
5419 /* we assume the table is sorted */
5420 for (i = 0; i < n_entries; ++i) {
5421 if (entries[i].ts > pos)
5425 /* FIXME: maybe save first moof_offset somewhere instead, but for now it's
5426 * probably okay to assume that the index lists the very first fragment */
5433 return &entries[i - 1];
5437 gst_qtdemux_do_fragmented_seek (GstQTDemux * qtdemux)
5439 const QtDemuxRandomAccessEntry *best_entry = NULL;
5442 GST_OBJECT_LOCK (qtdemux);
5444 g_assert (qtdemux->n_streams > 0);
5446 for (i = 0; i < qtdemux->n_streams; i++) {
5447 const QtDemuxRandomAccessEntry *entry;
5448 QtDemuxStream *stream;
5449 gboolean is_audio_or_video;
5451 stream = qtdemux->streams[i];
5453 g_free (stream->samples);
5454 stream->samples = NULL;
5455 stream->n_samples = 0;
5456 stream->stbl_index = -1; /* no samples have yet been parsed */
5457 stream->sample_index = -1;
5459 if (stream->ra_entries == NULL)
5462 if (stream->subtype == FOURCC_vide || stream->subtype == FOURCC_soun)
5463 is_audio_or_video = TRUE;
5465 is_audio_or_video = FALSE;
5468 gst_qtdemux_stream_seek_fragment (qtdemux, stream,
5469 stream->time_position, !is_audio_or_video);
5471 GST_INFO_OBJECT (stream->pad, "%" GST_TIME_FORMAT " at offset "
5472 "%" G_GUINT64_FORMAT, GST_TIME_ARGS (entry->ts), entry->moof_offset);
5474 stream->pending_seek = entry;
5476 /* decide position to jump to just based on audio/video tracks, not subs */
5477 if (!is_audio_or_video)
5480 if (best_entry == NULL || entry->moof_offset < best_entry->moof_offset)
5484 if (best_entry == NULL) {
5485 GST_OBJECT_UNLOCK (qtdemux);
5489 GST_INFO_OBJECT (qtdemux, "seek to %" GST_TIME_FORMAT ", best fragment "
5490 "moof offset: %" G_GUINT64_FORMAT ", ts %" GST_TIME_FORMAT,
5491 GST_TIME_ARGS (qtdemux->streams[0]->time_position),
5492 best_entry->moof_offset, GST_TIME_ARGS (best_entry->ts));
5494 qtdemux->moof_offset = best_entry->moof_offset;
5496 qtdemux_add_fragmented_samples (qtdemux);
5498 GST_OBJECT_UNLOCK (qtdemux);
5502 static GstFlowReturn
5503 gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux)
5505 GstFlowReturn ret = GST_FLOW_OK;
5506 GstBuffer *buf = NULL;
5507 QtDemuxStream *stream;
5508 GstClockTime min_time;
5510 GstClockTime dts = GST_CLOCK_TIME_NONE;
5511 GstClockTime pts = GST_CLOCK_TIME_NONE;
5512 GstClockTime duration = 0;
5513 gboolean keyframe = FALSE;
5514 guint sample_size = 0;
5520 gst_qtdemux_push_pending_newsegment (qtdemux);
5522 if (qtdemux->fragmented_seek_pending) {
5523 GST_INFO_OBJECT (qtdemux, "pending fragmented seek");
5524 gst_qtdemux_do_fragmented_seek (qtdemux);
5525 GST_INFO_OBJECT (qtdemux, "fragmented seek done!");
5526 qtdemux->fragmented_seek_pending = FALSE;
5529 /* Figure out the next stream sample to output, min_time is expressed in
5530 * global time and runs over the edit list segments. */
5531 min_time = G_MAXUINT64;
5533 for (i = 0; i < qtdemux->n_streams; i++) {
5534 GstClockTime position;
5536 stream = qtdemux->streams[i];
5537 position = stream->time_position;
5539 /* position of -1 is EOS */
5540 if (position != GST_CLOCK_TIME_NONE && position < min_time) {
5541 min_time = position;
5546 if (G_UNLIKELY (index == -1)) {
5547 GST_DEBUG_OBJECT (qtdemux, "all streams are EOS");
5551 /* check for segment end */
5552 if (G_UNLIKELY (qtdemux->segment.stop != -1
5553 && ((qtdemux->segment.rate >= 0 && qtdemux->segment.stop <= min_time)
5554 || (qtdemux->segment.rate < 0
5555 && qtdemux->segment.start > min_time))
5556 && qtdemux->streams[index]->on_keyframe)) {
5557 GST_DEBUG_OBJECT (qtdemux, "we reached the end of our segment.");
5558 qtdemux->streams[index]->time_position = GST_CLOCK_TIME_NONE;
5562 /* gap events for subtitle streams */
5563 for (i = 0; i < qtdemux->n_streams; i++) {
5564 stream = qtdemux->streams[i];
5565 if (stream->pad && (stream->subtype == FOURCC_subp
5566 || stream->subtype == FOURCC_text
5567 || stream->subtype == FOURCC_sbtl)) {
5568 /* send one second gap events until the stream catches up */
5569 /* gaps can only be sent after segment is activated (segment.stop is no longer -1) */
5570 while (GST_CLOCK_TIME_IS_VALID (stream->segment.stop) &&
5571 GST_CLOCK_TIME_IS_VALID (stream->segment.position) &&
5572 stream->segment.position + GST_SECOND < min_time) {
5574 gst_event_new_gap (stream->segment.position, GST_SECOND);
5575 gst_pad_push_event (stream->pad, gap);
5576 stream->segment.position += GST_SECOND;
5581 stream = qtdemux->streams[index];
5582 if (stream->new_caps) {
5583 gst_qtdemux_configure_stream (qtdemux, stream);
5584 qtdemux_do_allocation (qtdemux, stream);
5587 /* fetch info for the current sample of this stream */
5588 if (G_UNLIKELY (!gst_qtdemux_prepare_current_sample (qtdemux, stream, &empty,
5589 &offset, &sample_size, &dts, &pts, &duration, &keyframe)))
5592 /* If we're doing a keyframe-only trickmode, only push keyframes on video streams */
5593 if (G_UNLIKELY (qtdemux->
5594 segment.flags & GST_SEGMENT_FLAG_TRICKMODE_KEY_UNITS)) {
5595 if (stream->subtype == FOURCC_vide && !keyframe) {
5596 GST_LOG_OBJECT (qtdemux, "Skipping non-keyframe on stream %d", index);
5601 GST_DEBUG_OBJECT (qtdemux,
5602 "pushing from stream %d, empty %d offset %" G_GUINT64_FORMAT
5603 ", size %d, dts=%" GST_TIME_FORMAT ", pts=%" GST_TIME_FORMAT
5604 ", duration %" GST_TIME_FORMAT, index, empty, offset, sample_size,
5605 GST_TIME_ARGS (dts), GST_TIME_ARGS (pts), GST_TIME_ARGS (duration));
5607 if (G_UNLIKELY (empty)) {
5608 /* empty segment, push a gap and move to the next one */
5609 gst_pad_push_event (stream->pad, gst_event_new_gap (pts, duration));
5610 stream->segment.position = pts + duration;
5614 /* hmm, empty sample, skip and move to next sample */
5615 if (G_UNLIKELY (sample_size <= 0))
5618 /* last pushed sample was out of boundary, goto next sample */
5619 if (G_UNLIKELY (GST_PAD_LAST_FLOW_RETURN (stream->pad) == GST_FLOW_EOS))
5622 if (stream->max_buffer_size == 0 || sample_size <= stream->max_buffer_size) {
5625 GST_DEBUG_OBJECT (qtdemux,
5626 "size %d larger than stream max_buffer_size %d, trimming",
5627 sample_size, stream->max_buffer_size);
5629 MIN (sample_size - stream->offset_in_sample, stream->max_buffer_size);
5632 if (qtdemux->cenc_aux_info_offset > 0) {
5635 GstBuffer *aux_info = NULL;
5637 /* pull the data stored before the sample */
5639 gst_qtdemux_pull_atom (qtdemux, qtdemux->offset,
5640 offset + stream->offset_in_sample - qtdemux->offset, &aux_info);
5641 if (G_UNLIKELY (ret != GST_FLOW_OK))
5643 gst_buffer_map (aux_info, &map, GST_MAP_READ);
5644 GST_DEBUG_OBJECT (qtdemux, "parsing cenc auxiliary info");
5645 gst_byte_reader_init (&br, map.data + 8, map.size);
5646 if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
5647 qtdemux->cenc_aux_info_sizes, qtdemux->cenc_aux_sample_count)) {
5648 GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
5649 gst_buffer_unmap (aux_info, &map);
5650 gst_buffer_unref (aux_info);
5651 ret = GST_FLOW_ERROR;
5654 gst_buffer_unmap (aux_info, &map);
5655 gst_buffer_unref (aux_info);
5658 GST_LOG_OBJECT (qtdemux, "reading %d bytes @ %" G_GUINT64_FORMAT, size,
5661 if (stream->use_allocator) {
5662 /* if we have a per-stream allocator, use it */
5663 buf = gst_buffer_new_allocate (stream->allocator, size, &stream->params);
5666 ret = gst_qtdemux_pull_atom (qtdemux, offset + stream->offset_in_sample,
5668 if (G_UNLIKELY (ret != GST_FLOW_OK))
5671 if (size != sample_size) {
5672 pts += gst_util_uint64_scale_int (GST_SECOND,
5673 stream->offset_in_sample / stream->bytes_per_frame, stream->timescale);
5674 dts += gst_util_uint64_scale_int (GST_SECOND,
5675 stream->offset_in_sample / stream->bytes_per_frame, stream->timescale);
5676 duration = gst_util_uint64_scale_int (GST_SECOND,
5677 size / stream->bytes_per_frame, stream->timescale);
5680 ret = gst_qtdemux_decorate_and_push_buffer (qtdemux, stream, buf,
5681 dts, pts, duration, keyframe, min_time, offset);
5683 if (size != sample_size) {
5684 QtDemuxSample *sample = &stream->samples[stream->sample_index];
5685 QtDemuxSegment *segment = &stream->segments[stream->segment_index];
5687 GstClockTime time_position = QTSTREAMTIME_TO_GSTTIME (stream,
5688 sample->timestamp + stream->offset_in_sample / stream->bytes_per_frame);
5689 if (time_position >= segment->media_start) {
5690 /* inside the segment, update time_position, looks very familiar to
5691 * GStreamer segments, doesn't it? */
5692 stream->time_position = (time_position - segment->media_start) +
5695 /* not yet in segment, time does not yet increment. This means
5696 * that we are still prerolling keyframes to the decoder so it can
5697 * decode the first sample of the segment. */
5698 stream->time_position = segment->time;
5703 ret = gst_qtdemux_combine_flows (qtdemux, stream, ret);
5704 /* ignore unlinked, we will not push on the pad anymore and we will EOS when
5705 * we have no more data for the pad to push */
5706 if (ret == GST_FLOW_EOS)
5709 stream->offset_in_sample += size;
5710 if (stream->offset_in_sample >= sample_size) {
5711 gst_qtdemux_advance_sample (qtdemux, stream);
5716 gst_qtdemux_advance_sample (qtdemux, stream);
5724 GST_DEBUG_OBJECT (qtdemux, "No samples left for any streams - EOS");
5730 GST_DEBUG_OBJECT (qtdemux, "No samples left for stream");
5731 /* EOS will be raised if all are EOS */
5738 gst_qtdemux_loop (GstPad * pad)
5740 GstQTDemux *qtdemux;
5744 qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
5746 cur_offset = qtdemux->offset;
5747 GST_LOG_OBJECT (qtdemux, "loop at position %" G_GUINT64_FORMAT ", state %s",
5748 cur_offset, qt_demux_state_string (qtdemux->state));
5750 switch (qtdemux->state) {
5751 case QTDEMUX_STATE_INITIAL:
5752 case QTDEMUX_STATE_HEADER:
5753 ret = gst_qtdemux_loop_state_header (qtdemux);
5755 case QTDEMUX_STATE_MOVIE:
5756 ret = gst_qtdemux_loop_state_movie (qtdemux);
5757 if (qtdemux->segment.rate < 0 && ret == GST_FLOW_EOS) {
5758 ret = gst_qtdemux_seek_to_previous_keyframe (qtdemux);
5766 /* if something went wrong, pause */
5767 if (ret != GST_FLOW_OK)
5771 gst_object_unref (qtdemux);
5777 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
5778 (NULL), ("streaming stopped, invalid state"));
5779 gst_pad_pause_task (pad);
5780 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
5785 const gchar *reason = gst_flow_get_name (ret);
5787 GST_LOG_OBJECT (qtdemux, "pausing task, reason %s", reason);
5789 gst_pad_pause_task (pad);
5791 /* fatal errors need special actions */
5793 if (ret == GST_FLOW_EOS) {
5794 if (qtdemux->n_streams == 0) {
5795 /* we have no streams, post an error */
5796 gst_qtdemux_post_no_playable_stream_error (qtdemux);
5798 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
5801 if ((stop = qtdemux->segment.stop) == -1)
5802 stop = qtdemux->segment.duration;
5804 if (qtdemux->segment.rate >= 0) {
5805 GstMessage *message;
5808 GST_LOG_OBJECT (qtdemux, "Sending segment done, at end of segment");
5809 message = gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
5810 GST_FORMAT_TIME, stop);
5811 event = gst_event_new_segment_done (GST_FORMAT_TIME, stop);
5812 if (qtdemux->segment_seqnum) {
5813 gst_message_set_seqnum (message, qtdemux->segment_seqnum);
5814 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
5816 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), message);
5817 gst_qtdemux_push_event (qtdemux, event);
5819 GstMessage *message;
5822 /* For Reverse Playback */
5823 GST_LOG_OBJECT (qtdemux, "Sending segment done, at start of segment");
5824 message = gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
5825 GST_FORMAT_TIME, qtdemux->segment.start);
5826 event = gst_event_new_segment_done (GST_FORMAT_TIME,
5827 qtdemux->segment.start);
5828 if (qtdemux->segment_seqnum) {
5829 gst_message_set_seqnum (message, qtdemux->segment_seqnum);
5830 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
5832 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), message);
5833 gst_qtdemux_push_event (qtdemux, event);
5838 GST_LOG_OBJECT (qtdemux, "Sending EOS at end of segment");
5839 event = gst_event_new_eos ();
5840 if (qtdemux->segment_seqnum)
5841 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
5842 gst_qtdemux_push_event (qtdemux, event);
5844 } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
5845 GST_ELEMENT_FLOW_ERROR (qtdemux, ret);
5846 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
5855 * Returns if there are samples to be played.
5858 has_next_entry (GstQTDemux * demux)
5860 QtDemuxStream *stream;
5863 GST_DEBUG_OBJECT (demux, "Checking if there are samples not played yet");
5865 for (i = 0; i < demux->n_streams; i++) {
5866 stream = demux->streams[i];
5868 if (stream->sample_index == -1) {
5869 stream->sample_index = 0;
5870 stream->offset_in_sample = 0;
5873 if (stream->sample_index >= stream->n_samples) {
5874 GST_LOG_OBJECT (demux, "stream %d samples exhausted", i);
5877 GST_DEBUG_OBJECT (demux, "Found a sample");
5881 GST_DEBUG_OBJECT (demux, "There wasn't any next sample");
5888 * Returns the size of the first entry at the current offset.
5889 * If -1, there are none (which means EOS or empty file).
5892 next_entry_size (GstQTDemux * demux)
5894 QtDemuxStream *stream;
5897 guint64 smalloffs = (guint64) - 1;
5898 QtDemuxSample *sample;
5900 GST_LOG_OBJECT (demux, "Finding entry at offset %" G_GUINT64_FORMAT,
5903 for (i = 0; i < demux->n_streams; i++) {
5904 stream = demux->streams[i];
5906 if (stream->sample_index == -1) {
5907 stream->sample_index = 0;
5908 stream->offset_in_sample = 0;
5911 if (stream->sample_index >= stream->n_samples) {
5912 GST_LOG_OBJECT (demux, "stream %d samples exhausted", i);
5916 if (!qtdemux_parse_samples (demux, stream, stream->sample_index)) {
5917 GST_LOG_OBJECT (demux, "Parsing of index %u from stbl atom failed!",
5918 stream->sample_index);
5922 sample = &stream->samples[stream->sample_index];
5924 GST_LOG_OBJECT (demux,
5925 "Checking Stream %d (sample_index:%d / offset:%" G_GUINT64_FORMAT
5926 " / size:%" G_GUINT32_FORMAT ")", i, stream->sample_index,
5927 sample->offset, sample->size);
5929 if (((smalloffs == -1)
5930 || (sample->offset < smalloffs)) && (sample->size)) {
5932 smalloffs = sample->offset;
5936 GST_LOG_OBJECT (demux,
5937 "stream %d offset %" G_GUINT64_FORMAT " demux->offset :%"
5938 G_GUINT64_FORMAT, smallidx, smalloffs, demux->offset);
5943 stream = demux->streams[smallidx];
5944 sample = &stream->samples[stream->sample_index];
5946 if (sample->offset >= demux->offset) {
5947 demux->todrop = sample->offset - demux->offset;
5948 return sample->size + demux->todrop;
5951 GST_DEBUG_OBJECT (demux,
5952 "There wasn't any entry at offset %" G_GUINT64_FORMAT, demux->offset);
5957 gst_qtdemux_post_progress (GstQTDemux * demux, gint num, gint denom)
5959 gint perc = (gint) ((gdouble) num * 100.0 / (gdouble) denom);
5961 gst_element_post_message (GST_ELEMENT_CAST (demux),
5962 gst_message_new_element (GST_OBJECT_CAST (demux),
5963 gst_structure_new ("progress", "percent", G_TYPE_INT, perc, NULL)));
5967 qtdemux_seek_offset (GstQTDemux * demux, guint64 offset)
5972 GST_DEBUG_OBJECT (demux, "Seeking to %" G_GUINT64_FORMAT, offset);
5975 gst_event_new_seek (1.0, GST_FORMAT_BYTES,
5976 GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset,
5977 GST_SEEK_TYPE_NONE, -1);
5979 /* store seqnum to drop flush events, they don't need to reach downstream */
5980 demux->offset_seek_seqnum = gst_event_get_seqnum (event);
5981 res = gst_pad_push_event (demux->sinkpad, event);
5982 demux->offset_seek_seqnum = 0;
5987 /* check for seekable upstream, above and beyond a mere query */
5989 gst_qtdemux_check_seekability (GstQTDemux * demux)
5992 gboolean seekable = FALSE;
5993 gint64 start = -1, stop = -1;
5995 if (demux->upstream_size)
5998 query = gst_query_new_seeking (GST_FORMAT_BYTES);
5999 if (!gst_pad_peer_query (demux->sinkpad, query)) {
6000 GST_DEBUG_OBJECT (demux, "seeking query failed");
6004 gst_query_parse_seeking (query, NULL, &seekable, &start, &stop);
6006 /* try harder to query upstream size if we didn't get it the first time */
6007 if (seekable && stop == -1) {
6008 GST_DEBUG_OBJECT (demux, "doing duration query to fix up unset stop");
6009 gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &stop);
6012 /* if upstream doesn't know the size, it's likely that it's not seekable in
6013 * practice even if it technically may be seekable */
6014 if (seekable && (start != 0 || stop <= start)) {
6015 GST_DEBUG_OBJECT (demux, "seekable but unknown start/stop -> disable");
6020 gst_query_unref (query);
6022 GST_DEBUG_OBJECT (demux, "seekable: %d (%" G_GUINT64_FORMAT " - %"
6023 G_GUINT64_FORMAT ")", seekable, start, stop);
6024 demux->upstream_seekable = seekable;
6025 demux->upstream_size = seekable ? stop : -1;
6029 gst_qtdemux_drop_data (GstQTDemux * demux, gint bytes)
6031 g_return_if_fail (bytes <= demux->todrop);
6033 GST_LOG_OBJECT (demux, "Dropping %d bytes", bytes);
6034 gst_adapter_flush (demux->adapter, bytes);
6035 demux->neededbytes -= bytes;
6036 demux->offset += bytes;
6037 demux->todrop -= bytes;
6041 gst_qtdemux_check_send_pending_segment (GstQTDemux * demux)
6043 if (G_UNLIKELY (demux->pending_newsegment)) {
6046 gst_qtdemux_push_pending_newsegment (demux);
6047 /* clear to send tags on all streams */
6048 for (i = 0; i < demux->n_streams; i++) {
6049 QtDemuxStream *stream;
6050 stream = demux->streams[i];
6051 gst_qtdemux_push_tags (demux, stream);
6052 if (stream->sparse) {
6053 GST_INFO_OBJECT (demux, "Sending gap event on stream %d", i);
6054 gst_pad_push_event (stream->pad,
6055 gst_event_new_gap (stream->segment.position, GST_CLOCK_TIME_NONE));
6062 gst_qtdemux_send_gap_for_segment (GstQTDemux * demux,
6063 QtDemuxStream * stream, gint segment_index, GstClockTime pos)
6065 GstClockTime ts, dur;
6070 stream->segments[segment_index].duration - (pos -
6071 stream->segments[segment_index].time);
6072 gap = gst_event_new_gap (ts, dur);
6073 stream->time_position += dur;
6075 GST_DEBUG_OBJECT (stream->pad, "Pushing gap for empty "
6076 "segment: %" GST_PTR_FORMAT, gap);
6077 gst_pad_push_event (stream->pad, gap);
6081 gst_qtdemux_stream_send_initial_gap_segments (GstQTDemux * demux,
6082 QtDemuxStream * stream)
6086 /* Push any initial gap segments before proceeding to the
6088 for (i = 0; i < stream->n_segments; i++) {
6089 gst_qtdemux_activate_segment (demux, stream, i, stream->time_position);
6091 if (QTSEGMENT_IS_EMPTY (&stream->segments[i])) {
6092 gst_qtdemux_send_gap_for_segment (demux, stream, i,
6093 stream->time_position);
6095 /* Only support empty segment at the beginning followed by
6096 * one non-empty segment, this was checked when parsing the
6097 * edts atom, arriving here is unexpected */
6098 g_assert (i + 1 == stream->n_segments);
6104 static GstFlowReturn
6105 gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent, GstBuffer * inbuf)
6109 demux = GST_QTDEMUX (parent);
6111 GST_DEBUG_OBJECT (demux,
6112 "Received buffer pts:%" GST_TIME_FORMAT " dts:%" GST_TIME_FORMAT
6113 " offset:%" G_GUINT64_FORMAT " size:%" G_GSIZE_FORMAT " demux offset:%"
6114 G_GUINT64_FORMAT, GST_TIME_ARGS (GST_BUFFER_PTS (inbuf)),
6115 GST_TIME_ARGS (GST_BUFFER_DTS (inbuf)), GST_BUFFER_OFFSET (inbuf),
6116 gst_buffer_get_size (inbuf), demux->offset);
6118 if (GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_DISCONT)) {
6119 gboolean is_gap_input = FALSE;
6122 GST_DEBUG_OBJECT (demux, "Got DISCONT, marking all streams as DISCONT");
6124 for (i = 0; i < demux->n_streams; i++) {
6125 demux->streams[i]->discont = TRUE;
6128 /* Check if we can land back on our feet in the case where upstream is
6129 * handling the seeking/pushing of samples with gaps in between (like
6130 * in the case of trick-mode DASH for example) */
6131 if (demux->upstream_format_is_time
6132 && GST_BUFFER_OFFSET (inbuf) != GST_BUFFER_OFFSET_NONE) {
6134 for (i = 0; i < demux->n_streams; i++) {
6136 GST_LOG_OBJECT (demux,
6137 "Stream #%d , checking if offset %" G_GUINT64_FORMAT
6138 " is a sample start", i, GST_BUFFER_OFFSET (inbuf));
6140 gst_qtdemux_find_index_for_given_media_offset_linear (demux,
6141 demux->streams[i], GST_BUFFER_OFFSET (inbuf));
6143 QtDemuxSample *sample = &demux->streams[i]->samples[res];
6144 GST_LOG_OBJECT (demux,
6145 "Checking if sample %d from stream %d is valid (offset:%"
6146 G_GUINT64_FORMAT " size:%" G_GUINT32_FORMAT ")", res, i,
6147 sample->offset, sample->size);
6148 if (sample->offset == GST_BUFFER_OFFSET (inbuf)) {
6149 GST_LOG_OBJECT (demux,
6150 "new buffer corresponds to a valid sample : %" G_GUINT32_FORMAT,
6152 is_gap_input = TRUE;
6153 /* We can go back to standard playback mode */
6154 demux->state = QTDEMUX_STATE_MOVIE;
6155 /* Remember which sample this stream is at */
6156 demux->streams[i]->sample_index = res;
6157 /* Finally update all push-based values to the expected values */
6158 demux->neededbytes = demux->streams[i]->samples[res].size;
6160 demux->offset = GST_BUFFER_OFFSET (inbuf);
6164 if (!is_gap_input) {
6165 /* Reset state if it's a real discont */
6166 demux->neededbytes = 16;
6167 demux->state = QTDEMUX_STATE_INITIAL;
6168 demux->offset = GST_BUFFER_OFFSET (inbuf);
6171 /* Reverse fragmented playback, need to flush all we have before
6172 * consuming a new fragment.
6173 * The samples array have the timestamps calculated by accumulating the
6174 * durations but this won't work for reverse playback of fragments as
6175 * the timestamps of a subsequent fragment should be smaller than the
6176 * previously received one. */
6177 if (!is_gap_input && demux->fragmented && demux->segment.rate < 0) {
6178 gst_qtdemux_process_adapter (demux, TRUE);
6179 for (i = 0; i < demux->n_streams; i++)
6180 gst_qtdemux_stream_flush_samples_data (demux, demux->streams[i]);
6184 gst_adapter_push (demux->adapter, inbuf);
6186 GST_DEBUG_OBJECT (demux,
6187 "pushing in inbuf %p, neededbytes:%u, available:%" G_GSIZE_FORMAT, inbuf,
6188 demux->neededbytes, gst_adapter_available (demux->adapter));
6190 return gst_qtdemux_process_adapter (demux, FALSE);
6193 static GstFlowReturn
6194 gst_qtdemux_process_adapter (GstQTDemux * demux, gboolean force)
6196 GstFlowReturn ret = GST_FLOW_OK;
6198 /* we never really mean to buffer that much */
6199 if (demux->neededbytes == -1) {
6203 while (((gst_adapter_available (demux->adapter)) >= demux->neededbytes) &&
6204 (ret == GST_FLOW_OK || (ret == GST_FLOW_NOT_LINKED && force))) {
6206 #ifndef GST_DISABLE_GST_DEBUG
6208 guint64 discont_offset, distance_from_discont;
6210 discont_offset = gst_adapter_offset_at_discont (demux->adapter);
6211 distance_from_discont =
6212 gst_adapter_distance_from_discont (demux->adapter);
6214 GST_DEBUG_OBJECT (demux,
6215 "state:%s , demux->neededbytes:%d, demux->offset:%" G_GUINT64_FORMAT
6216 " adapter offset :%" G_GUINT64_FORMAT " (+ %" G_GUINT64_FORMAT
6217 " bytes)", qt_demux_state_string (demux->state), demux->neededbytes,
6218 demux->offset, discont_offset, distance_from_discont);
6222 switch (demux->state) {
6223 case QTDEMUX_STATE_INITIAL:{
6228 gst_qtdemux_check_seekability (demux);
6230 data = gst_adapter_map (demux->adapter, demux->neededbytes);
6232 /* get fourcc/length, set neededbytes */
6233 extract_initial_length_and_fourcc ((guint8 *) data, demux->neededbytes,
6235 gst_adapter_unmap (demux->adapter);
6237 GST_DEBUG_OBJECT (demux, "Peeking found [%" GST_FOURCC_FORMAT "] "
6238 "size: %" G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), size);
6240 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
6241 (_("This file is invalid and cannot be played.")),
6242 ("initial atom '%" GST_FOURCC_FORMAT "' has empty length",
6243 GST_FOURCC_ARGS (fourcc)));
6244 ret = GST_FLOW_ERROR;
6247 if (fourcc == FOURCC_mdat) {
6248 gint next_entry = next_entry_size (demux);
6249 if (demux->n_streams > 0 && (next_entry != -1 || !demux->fragmented)) {
6250 /* we have the headers, start playback */
6251 demux->state = QTDEMUX_STATE_MOVIE;
6252 demux->neededbytes = next_entry;
6253 demux->mdatleft = size;
6255 /* no headers yet, try to get them */
6258 guint64 old, target;
6261 old = demux->offset;
6262 target = old + size;
6264 /* try to jump over the atom with a seek */
6265 /* only bother if it seems worth doing so,
6266 * and avoids possible upstream/server problems */
6267 if (demux->upstream_seekable &&
6268 demux->upstream_size > 4 * (1 << 20)) {
6269 res = qtdemux_seek_offset (demux, target);
6271 GST_DEBUG_OBJECT (demux, "skipping seek");
6276 GST_DEBUG_OBJECT (demux, "seek success");
6277 /* remember the offset fo the first mdat so we can seek back to it
6278 * after we have the headers */
6279 if (fourcc == FOURCC_mdat && demux->first_mdat == -1) {
6280 demux->first_mdat = old;
6281 GST_DEBUG_OBJECT (demux, "first mdat at %" G_GUINT64_FORMAT,
6284 /* seek worked, continue reading */
6285 demux->offset = target;
6286 demux->neededbytes = 16;
6287 demux->state = QTDEMUX_STATE_INITIAL;
6289 /* seek failed, need to buffer */
6290 demux->offset = old;
6291 GST_DEBUG_OBJECT (demux, "seek failed/skipped");
6292 /* there may be multiple mdat (or alike) buffers */
6294 if (demux->mdatbuffer)
6295 bs = gst_buffer_get_size (demux->mdatbuffer);
6298 if (size + bs > 10 * (1 << 20))
6300 demux->state = QTDEMUX_STATE_BUFFER_MDAT;
6301 demux->neededbytes = size;
6302 if (!demux->mdatbuffer)
6303 demux->mdatoffset = demux->offset;
6306 } else if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
6307 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
6308 (_("This file is invalid and cannot be played.")),
6309 ("atom %" GST_FOURCC_FORMAT " has bogus size %" G_GUINT64_FORMAT,
6310 GST_FOURCC_ARGS (fourcc), size));
6311 ret = GST_FLOW_ERROR;
6314 /* this means we already started buffering and still no moov header,
6315 * let's continue buffering everything till we get moov */
6316 if (demux->mdatbuffer && !(fourcc == FOURCC_moov
6317 || fourcc == FOURCC_moof))
6319 demux->neededbytes = size;
6320 demux->state = QTDEMUX_STATE_HEADER;
6324 case QTDEMUX_STATE_HEADER:{
6328 GST_DEBUG_OBJECT (demux, "In header");
6330 data = gst_adapter_map (demux->adapter, demux->neededbytes);
6332 /* parse the header */
6333 extract_initial_length_and_fourcc (data, demux->neededbytes, NULL,
6335 if (fourcc == FOURCC_moov) {
6338 /* in usual fragmented setup we could try to scan for more
6339 * and end up at the the moov (after mdat) again */
6340 if (demux->got_moov && demux->n_streams > 0 &&
6342 || demux->last_moov_offset == demux->offset)) {
6343 GST_DEBUG_OBJECT (demux,
6344 "Skipping moov atom as we have (this) one already");
6346 GST_DEBUG_OBJECT (demux, "Parsing [moov]");
6348 if (demux->got_moov && demux->fragmented) {
6349 GST_DEBUG_OBJECT (demux,
6350 "Got a second moov, clean up data from old one");
6351 if (demux->moov_node)
6352 g_node_destroy (demux->moov_node);
6353 demux->moov_node = NULL;
6354 demux->moov_node_compressed = NULL;
6356 /* prepare newsegment to send when streaming actually starts */
6357 if (!demux->pending_newsegment) {
6358 demux->pending_newsegment =
6359 gst_event_new_segment (&demux->segment);
6360 if (demux->segment_seqnum)
6361 gst_event_set_seqnum (demux->pending_newsegment,
6362 demux->segment_seqnum);
6366 demux->last_moov_offset = demux->offset;
6368 qtdemux_parse_moov (demux, data, demux->neededbytes);
6369 qtdemux_node_dump (demux, demux->moov_node);
6370 qtdemux_parse_tree (demux);
6371 qtdemux_prepare_streams (demux);
6372 if (!demux->got_moov)
6373 qtdemux_expose_streams (demux);
6376 for (n = 0; n < demux->n_streams; n++) {
6377 QtDemuxStream *stream = demux->streams[n];
6379 gst_qtdemux_configure_stream (demux, stream);
6383 demux->got_moov = TRUE;
6384 gst_qtdemux_check_send_pending_segment (demux);
6386 /* fragmented streams headers shouldn't contain edts atoms */
6387 if (!demux->fragmented) {
6388 for (n = 0; n < demux->n_streams; n++) {
6389 gst_qtdemux_stream_send_initial_gap_segments (demux,
6394 g_node_destroy (demux->moov_node);
6395 demux->moov_node = NULL;
6396 GST_DEBUG_OBJECT (demux, "Finished parsing the header");
6398 } else if (fourcc == FOURCC_moof) {
6399 if ((demux->got_moov || demux->media_caps) && demux->fragmented) {
6401 GstClockTime prev_pts;
6402 guint64 prev_offset;
6403 guint64 adapter_discont_offset, adapter_discont_dist;
6405 GST_DEBUG_OBJECT (demux, "Parsing [moof]");
6408 * The timestamp of the moof buffer is relevant as some scenarios
6409 * won't have the initial timestamp in the atoms. Whenever a new
6410 * buffer has started, we get that buffer's PTS and use it as a base
6411 * timestamp for the trun entries.
6413 * To keep track of the current buffer timestamp and starting point
6414 * we use gst_adapter_prev_pts that gives us the PTS and the distance
6415 * from the beggining of the buffer, with the distance and demux->offset
6416 * we know if it is still the same buffer or not.
6418 prev_pts = gst_adapter_prev_pts (demux->adapter, &dist);
6419 prev_offset = demux->offset - dist;
6420 if (demux->fragment_start_offset == -1
6421 || prev_offset > demux->fragment_start_offset) {
6422 demux->fragment_start_offset = prev_offset;
6423 demux->fragment_start = prev_pts;
6424 GST_DEBUG_OBJECT (demux,
6425 "New fragment start found at: %" G_GUINT64_FORMAT " : %"
6426 GST_TIME_FORMAT, demux->fragment_start_offset,
6427 GST_TIME_ARGS (demux->fragment_start));
6430 /* We can't use prev_offset() here because this would require
6431 * upstream to set consistent and correct offsets on all buffers
6432 * since the discont. Nothing ever did that in the past and we
6433 * would break backwards compatibility here then.
6434 * Instead take the offset we had at the last discont and count
6435 * the bytes from there. This works with old code as there would
6436 * be no discont between moov and moof, and also works with
6437 * adaptivedemux which correctly sets offset and will set the
6438 * DISCONT flag accordingly when needed.
6440 * We also only do this for upstream TIME segments as otherwise
6441 * there are potential backwards compatibility problems with
6442 * seeking in PUSH mode and upstream providing inconsistent
6444 adapter_discont_offset =
6445 gst_adapter_offset_at_discont (demux->adapter);
6446 adapter_discont_dist =
6447 gst_adapter_distance_from_discont (demux->adapter);
6449 GST_DEBUG_OBJECT (demux,
6450 "demux offset %" G_GUINT64_FORMAT " adapter offset %"
6451 G_GUINT64_FORMAT " (+ %" G_GUINT64_FORMAT " bytes)",
6452 demux->offset, adapter_discont_offset, adapter_discont_dist);
6454 if (demux->upstream_format_is_time) {
6455 demux->moof_offset = adapter_discont_offset;
6456 if (demux->moof_offset != GST_BUFFER_OFFSET_NONE)
6457 demux->moof_offset += adapter_discont_dist;
6458 if (demux->moof_offset == GST_BUFFER_OFFSET_NONE)
6459 demux->moof_offset = demux->offset;
6461 demux->moof_offset = demux->offset;
6464 if (!qtdemux_parse_moof (demux, data, demux->neededbytes,
6465 demux->moof_offset, NULL)) {
6466 gst_adapter_unmap (demux->adapter);
6467 ret = GST_FLOW_ERROR;
6470 /* in MSS we need to expose the pads after the first moof as we won't get a moov */
6471 if (demux->mss_mode && !demux->exposed) {
6472 if (!demux->pending_newsegment) {
6473 GST_DEBUG_OBJECT (demux, "new pending_newsegment");
6474 demux->pending_newsegment =
6475 gst_event_new_segment (&demux->segment);
6476 if (demux->segment_seqnum)
6477 gst_event_set_seqnum (demux->pending_newsegment,
6478 demux->segment_seqnum);
6480 qtdemux_expose_streams (demux);
6483 GST_DEBUG_OBJECT (demux, "Discarding [moof]");
6485 } else if (fourcc == FOURCC_ftyp) {
6486 GST_DEBUG_OBJECT (demux, "Parsing [ftyp]");
6487 qtdemux_parse_ftyp (demux, data, demux->neededbytes);
6488 } else if (fourcc == FOURCC_uuid) {
6489 GST_DEBUG_OBJECT (demux, "Parsing [uuid]");
6490 qtdemux_parse_uuid (demux, data, demux->neededbytes);
6491 } else if (fourcc == FOURCC_sidx) {
6492 GST_DEBUG_OBJECT (demux, "Parsing [sidx]");
6493 qtdemux_parse_sidx (demux, data, demux->neededbytes);
6495 GST_WARNING_OBJECT (demux,
6496 "Unknown fourcc while parsing header : %" GST_FOURCC_FORMAT,
6497 GST_FOURCC_ARGS (fourcc));
6498 /* Let's jump that one and go back to initial state */
6500 gst_adapter_unmap (demux->adapter);
6503 if (demux->mdatbuffer && demux->n_streams) {
6504 gsize remaining_data_size = 0;
6506 /* the mdat was before the header */
6507 GST_DEBUG_OBJECT (demux, "We have n_streams:%d and mdatbuffer:%p",
6508 demux->n_streams, demux->mdatbuffer);
6509 /* restore our adapter/offset view of things with upstream;
6510 * put preceding buffered data ahead of current moov data.
6511 * This should also handle evil mdat, moov, mdat cases and alike */
6512 gst_adapter_flush (demux->adapter, demux->neededbytes);
6514 /* Store any remaining data after the mdat for later usage */
6515 remaining_data_size = gst_adapter_available (demux->adapter);
6516 if (remaining_data_size > 0) {
6517 g_assert (demux->restoredata_buffer == NULL);
6518 demux->restoredata_buffer =
6519 gst_adapter_take_buffer (demux->adapter, remaining_data_size);
6520 demux->restoredata_offset = demux->offset + demux->neededbytes;
6521 GST_DEBUG_OBJECT (demux,
6522 "Stored %" G_GSIZE_FORMAT " post mdat bytes at offset %"
6523 G_GUINT64_FORMAT, remaining_data_size,
6524 demux->restoredata_offset);
6527 gst_adapter_push (demux->adapter, demux->mdatbuffer);
6528 demux->mdatbuffer = NULL;
6529 demux->offset = demux->mdatoffset;
6530 demux->neededbytes = next_entry_size (demux);
6531 demux->state = QTDEMUX_STATE_MOVIE;
6532 demux->mdatleft = gst_adapter_available (demux->adapter);
6534 GST_DEBUG_OBJECT (demux, "Carrying on normally");
6535 gst_adapter_flush (demux->adapter, demux->neededbytes);
6537 /* only go back to the mdat if there are samples to play */
6538 if (demux->got_moov && demux->first_mdat != -1
6539 && has_next_entry (demux)) {
6542 /* we need to seek back */
6543 res = qtdemux_seek_offset (demux, demux->first_mdat);
6545 demux->offset = demux->first_mdat;
6547 GST_DEBUG_OBJECT (demux, "Seek back failed");
6550 demux->offset += demux->neededbytes;
6552 demux->neededbytes = 16;
6553 demux->state = QTDEMUX_STATE_INITIAL;
6558 case QTDEMUX_STATE_BUFFER_MDAT:{
6562 GST_DEBUG_OBJECT (demux, "Got our buffer at offset %" G_GUINT64_FORMAT,
6564 buf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
6565 gst_buffer_extract (buf, 0, fourcc, 4);
6566 GST_DEBUG_OBJECT (demux, "mdatbuffer starts with %" GST_FOURCC_FORMAT,
6567 GST_FOURCC_ARGS (QT_FOURCC (fourcc)));
6568 if (demux->mdatbuffer)
6569 demux->mdatbuffer = gst_buffer_append (demux->mdatbuffer, buf);
6571 demux->mdatbuffer = buf;
6572 demux->offset += demux->neededbytes;
6573 demux->neededbytes = 16;
6574 demux->state = QTDEMUX_STATE_INITIAL;
6575 gst_qtdemux_post_progress (demux, 1, 1);
6579 case QTDEMUX_STATE_MOVIE:{
6580 QtDemuxStream *stream = NULL;
6581 QtDemuxSample *sample;
6583 GstClockTime dts, pts, duration;
6586 GST_DEBUG_OBJECT (demux,
6587 "BEGIN // in MOVIE for offset %" G_GUINT64_FORMAT, demux->offset);
6589 if (demux->fragmented) {
6590 GST_DEBUG_OBJECT (demux, "mdat remaining %" G_GUINT64_FORMAT,
6592 if (G_LIKELY (demux->todrop < demux->mdatleft)) {
6593 /* if needed data starts within this atom,
6594 * then it should not exceed this atom */
6595 if (G_UNLIKELY (demux->neededbytes > demux->mdatleft)) {
6596 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
6597 (_("This file is invalid and cannot be played.")),
6598 ("sample data crosses atom boundary"));
6599 ret = GST_FLOW_ERROR;
6602 demux->mdatleft -= demux->neededbytes;
6604 GST_DEBUG_OBJECT (demux, "data atom emptied; resuming atom scan");
6605 /* so we are dropping more than left in this atom */
6606 gst_qtdemux_drop_data (demux, demux->mdatleft);
6607 demux->mdatleft = 0;
6609 /* need to resume atom parsing so we do not miss any other pieces */
6610 demux->state = QTDEMUX_STATE_INITIAL;
6611 demux->neededbytes = 16;
6613 /* check if there was any stored post mdat data from previous buffers */
6614 if (demux->restoredata_buffer) {
6615 g_assert (gst_adapter_available (demux->adapter) == 0);
6617 gst_adapter_push (demux->adapter, demux->restoredata_buffer);
6618 demux->restoredata_buffer = NULL;
6619 demux->offset = demux->restoredata_offset;
6626 if (demux->todrop) {
6627 if (demux->cenc_aux_info_offset > 0) {
6631 GST_DEBUG_OBJECT (demux, "parsing cenc auxiliary info");
6632 data = gst_adapter_map (demux->adapter, demux->todrop);
6633 gst_byte_reader_init (&br, data + 8, demux->todrop);
6634 if (!qtdemux_parse_cenc_aux_info (demux, demux->streams[0], &br,
6635 demux->cenc_aux_info_sizes, demux->cenc_aux_sample_count)) {
6636 GST_ERROR_OBJECT (demux, "failed to parse cenc auxiliary info");
6637 ret = GST_FLOW_ERROR;
6638 gst_adapter_unmap (demux->adapter);
6639 g_free (demux->cenc_aux_info_sizes);
6640 demux->cenc_aux_info_sizes = NULL;
6643 demux->cenc_aux_info_offset = 0;
6644 g_free (demux->cenc_aux_info_sizes);
6645 demux->cenc_aux_info_sizes = NULL;
6646 gst_adapter_unmap (demux->adapter);
6648 gst_qtdemux_drop_data (demux, demux->todrop);
6652 /* initial newsegment sent here after having added pads,
6653 * possible others in sink_event */
6654 gst_qtdemux_check_send_pending_segment (demux);
6656 /* Figure out which stream this packet belongs to */
6657 for (i = 0; i < demux->n_streams; i++) {
6658 stream = demux->streams[i];
6659 if (stream->sample_index >= stream->n_samples)
6661 GST_LOG_OBJECT (demux,
6662 "Checking stream %d (sample_index:%d / offset:%" G_GUINT64_FORMAT
6663 " / size:%d)", i, stream->sample_index,
6664 stream->samples[stream->sample_index].offset,
6665 stream->samples[stream->sample_index].size);
6667 if (stream->samples[stream->sample_index].offset == demux->offset)
6671 if (G_UNLIKELY (stream == NULL || i == demux->n_streams))
6672 goto unknown_stream;
6674 if (stream->new_caps) {
6675 gst_qtdemux_configure_stream (demux, stream);
6678 /* Put data in a buffer, set timestamps, caps, ... */
6679 sample = &stream->samples[stream->sample_index];
6681 if (G_LIKELY (!(STREAM_IS_EOS (stream)))) {
6682 GST_DEBUG_OBJECT (demux, "stream : %" GST_FOURCC_FORMAT,
6683 GST_FOURCC_ARGS (stream->fourcc));
6685 dts = QTSAMPLE_DTS (stream, sample);
6686 pts = QTSAMPLE_PTS (stream, sample);
6687 duration = QTSAMPLE_DUR_DTS (stream, sample, dts);
6688 keyframe = QTSAMPLE_KEYFRAME (stream, sample);
6690 /* check for segment end */
6691 if (G_UNLIKELY (demux->segment.stop != -1
6692 && demux->segment.stop <= pts && stream->on_keyframe)) {
6693 GST_DEBUG_OBJECT (demux, "we reached the end of our segment.");
6694 stream->time_position = GST_CLOCK_TIME_NONE; /* this means EOS */
6696 /* skip this data, stream is EOS */
6697 gst_adapter_flush (demux->adapter, demux->neededbytes);
6699 /* check if all streams are eos */
6701 for (i = 0; i < demux->n_streams; i++) {
6702 if (!STREAM_IS_EOS (demux->streams[i])) {
6708 if (ret == GST_FLOW_EOS) {
6709 GST_DEBUG_OBJECT (demux, "All streams are EOS, signal upstream");
6716 gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
6718 /* FIXME: should either be an assert or a plain check */
6719 g_return_val_if_fail (outbuf != NULL, GST_FLOW_ERROR);
6721 ret = gst_qtdemux_decorate_and_push_buffer (demux, stream, outbuf,
6722 dts, pts, duration, keyframe, dts, demux->offset);
6726 ret = gst_qtdemux_combine_flows (demux, stream, ret);
6727 if (ret != GST_FLOW_OK && ret != GST_FLOW_NOT_LINKED)
6728 goto non_ok_unlinked_flow;
6730 /* skip this data, stream is EOS */
6731 gst_adapter_flush (demux->adapter, demux->neededbytes);
6734 stream->sample_index++;
6735 stream->offset_in_sample = 0;
6737 /* update current offset and figure out size of next buffer */
6738 GST_LOG_OBJECT (demux, "increasing offset %" G_GUINT64_FORMAT " by %u",
6739 demux->offset, demux->neededbytes);
6740 demux->offset += demux->neededbytes;
6741 GST_LOG_OBJECT (demux, "offset is now %" G_GUINT64_FORMAT,
6744 if ((demux->neededbytes = next_entry_size (demux)) == -1) {
6745 if (demux->fragmented) {
6746 GST_DEBUG_OBJECT (demux, "(temporarily) out of fragmented samples");
6747 /* there may be more to follow, only finish this atom */
6748 demux->todrop = demux->mdatleft;
6749 demux->neededbytes = demux->todrop;
6761 /* when buffering movie data, at least show user something is happening */
6762 if (ret == GST_FLOW_OK && demux->state == QTDEMUX_STATE_BUFFER_MDAT &&
6763 gst_adapter_available (demux->adapter) <= demux->neededbytes) {
6764 gst_qtdemux_post_progress (demux, gst_adapter_available (demux->adapter),
6765 demux->neededbytes);
6772 non_ok_unlinked_flow:
6774 GST_DEBUG_OBJECT (demux, "Stopping, combined return flow %s",
6775 gst_flow_get_name (ret));
6780 GST_ELEMENT_ERROR (demux, STREAM, FAILED, (NULL), ("unknown stream found"));
6781 ret = GST_FLOW_ERROR;
6786 GST_DEBUG_OBJECT (demux, "no next entry, EOS");
6792 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
6793 (NULL), ("qtdemuxer invalid state %d", demux->state));
6794 ret = GST_FLOW_ERROR;
6799 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
6800 (NULL), ("no 'moov' atom within the first 10 MB"));
6801 ret = GST_FLOW_ERROR;
6807 qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent)
6812 query = gst_query_new_scheduling ();
6814 if (!gst_pad_peer_query (sinkpad, query)) {
6815 gst_query_unref (query);
6819 pull_mode = gst_query_has_scheduling_mode_with_flags (query,
6820 GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
6821 gst_query_unref (query);
6826 GST_DEBUG_OBJECT (sinkpad, "activating pull");
6827 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
6831 GST_DEBUG_OBJECT (sinkpad, "activating push");
6832 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
6837 qtdemux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
6838 GstPadMode mode, gboolean active)
6841 GstQTDemux *demux = GST_QTDEMUX (parent);
6844 case GST_PAD_MODE_PUSH:
6845 demux->pullbased = FALSE;
6848 case GST_PAD_MODE_PULL:
6850 demux->pullbased = TRUE;
6851 res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_qtdemux_loop,
6854 res = gst_pad_stop_task (sinkpad);
6866 qtdemux_zalloc (void *opaque, unsigned int items, unsigned int size)
6868 return g_malloc (items * size);
6872 qtdemux_zfree (void *opaque, void *addr)
6878 qtdemux_inflate (void *z_buffer, guint z_length, guint length)
6884 z = g_new0 (z_stream, 1);
6885 z->zalloc = qtdemux_zalloc;
6886 z->zfree = qtdemux_zfree;
6889 z->next_in = z_buffer;
6890 z->avail_in = z_length;
6892 buffer = (guint8 *) g_malloc (length);
6893 ret = inflateInit (z);
6894 while (z->avail_in > 0) {
6895 if (z->avail_out == 0) {
6897 buffer = (guint8 *) g_realloc (buffer, length);
6898 z->next_out = buffer + z->total_out;
6899 z->avail_out = 1024;
6901 ret = inflate (z, Z_SYNC_FLUSH);
6905 if (ret != Z_STREAM_END) {
6906 g_warning ("inflate() returned %d", ret);
6912 #endif /* HAVE_ZLIB */
6915 qtdemux_parse_moov (GstQTDemux * qtdemux, const guint8 * buffer, guint length)
6919 qtdemux->moov_node = g_node_new ((guint8 *) buffer);
6921 /* counts as header data */
6922 qtdemux->header_size += length;
6924 GST_DEBUG_OBJECT (qtdemux, "parsing 'moov' atom");
6925 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buffer, length);
6927 cmov = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_cmov);
6933 dcom = qtdemux_tree_get_child_by_type (cmov, FOURCC_dcom);
6934 cmvd = qtdemux_tree_get_child_by_type (cmov, FOURCC_cmvd);
6935 if (dcom == NULL || cmvd == NULL)
6936 goto invalid_compression;
6938 method = QT_FOURCC ((guint8 *) dcom->data + 8);
6942 guint uncompressed_length;
6943 guint compressed_length;
6946 uncompressed_length = QT_UINT32 ((guint8 *) cmvd->data + 8);
6947 compressed_length = QT_UINT32 ((guint8 *) cmvd->data + 4) - 12;
6948 GST_LOG ("length = %u", uncompressed_length);
6951 (guint8 *) qtdemux_inflate ((guint8 *) cmvd->data + 12,
6952 compressed_length, uncompressed_length);
6954 qtdemux->moov_node_compressed = qtdemux->moov_node;
6955 qtdemux->moov_node = g_node_new (buf);
6957 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buf,
6958 uncompressed_length);
6961 #endif /* HAVE_ZLIB */
6963 GST_WARNING_OBJECT (qtdemux, "unknown or unhandled header compression "
6964 "type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (method));
6971 invalid_compression:
6973 GST_ERROR_OBJECT (qtdemux, "invalid compressed header");
6979 qtdemux_parse_container (GstQTDemux * qtdemux, GNode * node, const guint8 * buf,
6982 while (G_UNLIKELY (buf < end)) {
6986 if (G_UNLIKELY (buf + 4 > end)) {
6987 GST_LOG_OBJECT (qtdemux, "buffer overrun");
6990 len = QT_UINT32 (buf);
6991 if (G_UNLIKELY (len == 0)) {
6992 GST_LOG_OBJECT (qtdemux, "empty container");
6995 if (G_UNLIKELY (len < 8)) {
6996 GST_WARNING_OBJECT (qtdemux, "length too short (%d < 8)", len);
6999 if (G_UNLIKELY (len > (end - buf))) {
7000 GST_WARNING_OBJECT (qtdemux, "length too long (%d > %d)", len,
7001 (gint) (end - buf));
7005 child = g_node_new ((guint8 *) buf);
7006 g_node_append (node, child);
7007 GST_LOG_OBJECT (qtdemux, "adding new node of len %d", len);
7008 qtdemux_parse_node (qtdemux, child, buf, len);
7016 qtdemux_parse_theora_extension (GstQTDemux * qtdemux, QtDemuxStream * stream,
7019 int len = QT_UINT32 (xdxt->data);
7020 guint8 *buf = xdxt->data;
7021 guint8 *end = buf + len;
7024 /* skip size and type */
7032 size = QT_UINT32 (buf);
7033 type = QT_FOURCC (buf + 4);
7035 GST_LOG_OBJECT (qtdemux, "%p %p", buf, end);
7037 if (buf + size > end || size <= 0)
7043 GST_WARNING_OBJECT (qtdemux, "have cookie %" GST_FOURCC_FORMAT,
7044 GST_FOURCC_ARGS (type));
7048 buffer = gst_buffer_new_and_alloc (size);
7049 gst_buffer_fill (buffer, 0, buf, size);
7050 stream->buffers = g_slist_append (stream->buffers, buffer);
7051 GST_LOG_OBJECT (qtdemux, "parsing theora header");
7054 buffer = gst_buffer_new_and_alloc (size);
7055 gst_buffer_fill (buffer, 0, buf, size);
7056 stream->buffers = g_slist_append (stream->buffers, buffer);
7057 GST_LOG_OBJECT (qtdemux, "parsing theora comment");
7060 buffer = gst_buffer_new_and_alloc (size);
7061 gst_buffer_fill (buffer, 0, buf, size);
7062 stream->buffers = g_slist_append (stream->buffers, buffer);
7063 GST_LOG_OBJECT (qtdemux, "parsing theora codebook");
7066 GST_WARNING_OBJECT (qtdemux,
7067 "unknown theora cookie %" GST_FOURCC_FORMAT,
7068 GST_FOURCC_ARGS (type));
7077 qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node, const guint8 * buffer,
7081 guint32 node_length = 0;
7082 const QtNodeType *type;
7085 GST_LOG_OBJECT (qtdemux, "qtdemux_parse buffer %p length %u", buffer, length);
7087 if (G_UNLIKELY (length < 8))
7088 goto not_enough_data;
7090 node_length = QT_UINT32 (buffer);
7091 fourcc = QT_FOURCC (buffer + 4);
7093 /* ignore empty nodes */
7094 if (G_UNLIKELY (fourcc == 0 || node_length == 8))
7097 type = qtdemux_type_get (fourcc);
7099 end = buffer + length;
7101 GST_LOG_OBJECT (qtdemux,
7102 "parsing '%" GST_FOURCC_FORMAT "', length=%u, name '%s'",
7103 GST_FOURCC_ARGS (fourcc), node_length, type->name);
7105 if (node_length > length)
7106 goto broken_atom_size;
7108 if (type->flags & QT_FLAG_CONTAINER) {
7109 qtdemux_parse_container (qtdemux, node, buffer + 8, end);
7114 if (node_length < 20) {
7115 GST_LOG_OBJECT (qtdemux, "skipping small stsd box");
7118 GST_DEBUG_OBJECT (qtdemux,
7119 "parsing stsd (sample table, sample description) atom");
7120 /* Skip over 8 byte atom hdr + 1 byte version, 3 bytes flags, 4 byte num_entries */
7121 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
7132 /* also read alac (or whatever) in stead of mp4a in the following,
7133 * since a similar layout is used in other cases as well */
7134 if (fourcc == FOURCC_mp4a)
7136 else if (fourcc == FOURCC_fLaC)
7141 /* There are two things we might encounter here: a true mp4a atom, and
7142 an mp4a entry in an stsd atom. The latter is what we're interested
7143 in, and it looks like an atom, but isn't really one. The true mp4a
7144 atom is short, so we detect it based on length here. */
7145 if (length < min_size) {
7146 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
7147 GST_FOURCC_ARGS (fourcc));
7151 /* 'version' here is the sound sample description version. Types 0 and
7152 1 are documented in the QTFF reference, but type 2 is not: it's
7153 described in Apple header files instead (struct SoundDescriptionV2
7155 version = QT_UINT16 (buffer + 16);
7157 GST_DEBUG_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT " version 0x%08x",
7158 GST_FOURCC_ARGS (fourcc), version);
7160 /* parse any esds descriptors */
7172 GST_WARNING_OBJECT (qtdemux,
7173 "unhandled %" GST_FOURCC_FORMAT " version 0x%08x",
7174 GST_FOURCC_ARGS (fourcc), version);
7179 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
7196 /* codec_data is contained inside these atoms, which all have
7197 * the same format. */
7199 GST_DEBUG_OBJECT (qtdemux, "parsing in %" GST_FOURCC_FORMAT,
7200 GST_FOURCC_ARGS (fourcc));
7201 version = QT_UINT32 (buffer + 16);
7202 GST_DEBUG_OBJECT (qtdemux, "version %08x", version);
7203 if (1 || version == 0x00000000) {
7204 buf = buffer + 0x32;
7206 /* FIXME Quicktime uses PASCAL string while
7207 * the iso format uses C strings. Check the file
7208 * type before attempting to parse the string here. */
7209 tlen = QT_UINT8 (buf);
7210 GST_DEBUG_OBJECT (qtdemux, "tlen = %d", tlen);
7212 GST_DEBUG_OBJECT (qtdemux, "string = %.*s", tlen, (char *) buf);
7213 /* the string has a reserved space of 32 bytes so skip
7214 * the remaining 31 */
7216 buf += 4; /* and 4 bytes reserved */
7218 GST_MEMDUMP_OBJECT (qtdemux, "mp4v", buf, end - buf);
7220 qtdemux_parse_container (qtdemux, node, buf, end);
7226 GST_MEMDUMP_OBJECT (qtdemux, "H264", buffer, end - buffer);
7227 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
7232 GST_MEMDUMP_OBJECT (qtdemux, "avc1", buffer, end - buffer);
7233 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
7238 GST_MEMDUMP_OBJECT (qtdemux, "avc3", buffer, end - buffer);
7239 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
7244 GST_MEMDUMP_OBJECT (qtdemux, "H265", buffer, end - buffer);
7245 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
7250 GST_MEMDUMP_OBJECT (qtdemux, "hvc1", buffer, end - buffer);
7251 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
7256 GST_MEMDUMP_OBJECT (qtdemux, "hev1", buffer, end - buffer);
7257 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
7262 qtdemux_parse_container (qtdemux, node, buffer + 86, end);
7267 GST_DEBUG_OBJECT (qtdemux, "parsing meta atom");
7268 qtdemux_parse_container (qtdemux, node, buffer + 12, end);
7273 GST_MEMDUMP_OBJECT (qtdemux, "mp4s", buffer, end - buffer);
7274 /* Skip 8 byte header, plus 8 byte version + flags + entry_count */
7275 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
7283 version = QT_UINT32 (buffer + 12);
7284 GST_DEBUG_OBJECT (qtdemux, "parsing XiTh atom version 0x%08x", version);
7291 GST_DEBUG_OBJECT (qtdemux, "unknown version 0x%08x", version);
7296 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
7301 qtdemux_parse_container (qtdemux, node, buffer + 0x34, end);
7306 qtdemux_parse_uuid (qtdemux, buffer, end - buffer);
7311 qtdemux_parse_container (qtdemux, node, buffer + 86, end);
7316 qtdemux_parse_container (qtdemux, node, buffer + 36, end);
7320 if (!strcmp (type->name, "unknown"))
7321 GST_MEMDUMP ("Unknown tag", buffer + 4, end - buffer - 4);
7325 GST_LOG_OBJECT (qtdemux, "parsed '%" GST_FOURCC_FORMAT "'",
7326 GST_FOURCC_ARGS (fourcc));
7332 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
7333 (_("This file is corrupt and cannot be played.")),
7334 ("Not enough data for an atom header, got only %u bytes", length));
7339 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
7340 (_("This file is corrupt and cannot be played.")),
7341 ("Atom '%" GST_FOURCC_FORMAT "' has size of %u bytes, but we have only "
7342 "%u bytes available.", GST_FOURCC_ARGS (fourcc), node_length,
7349 qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc)
7353 guint32 child_fourcc;
7355 for (child = g_node_first_child (node); child;
7356 child = g_node_next_sibling (child)) {
7357 buffer = (guint8 *) child->data;
7359 child_fourcc = QT_FOURCC (buffer + 4);
7361 if (G_UNLIKELY (child_fourcc == fourcc)) {
7369 qtdemux_tree_get_child_by_type_full (GNode * node, guint32 fourcc,
7370 GstByteReader * parser)
7374 guint32 child_fourcc, child_len;
7376 for (child = g_node_first_child (node); child;
7377 child = g_node_next_sibling (child)) {
7378 buffer = (guint8 *) child->data;
7380 child_len = QT_UINT32 (buffer);
7381 child_fourcc = QT_FOURCC (buffer + 4);
7383 if (G_UNLIKELY (child_fourcc == fourcc)) {
7384 if (G_UNLIKELY (child_len < (4 + 4)))
7386 /* FIXME: must verify if atom length < parent atom length */
7387 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
7395 qtdemux_tree_get_sibling_by_type_full (GNode * node, guint32 fourcc,
7396 GstByteReader * parser)
7400 guint32 child_fourcc, child_len;
7402 for (child = g_node_next_sibling (node); child;
7403 child = g_node_next_sibling (child)) {
7404 buffer = (guint8 *) child->data;
7406 child_fourcc = QT_FOURCC (buffer + 4);
7408 if (child_fourcc == fourcc) {
7410 child_len = QT_UINT32 (buffer);
7411 if (G_UNLIKELY (child_len < (4 + 4)))
7413 /* FIXME: must verify if atom length < parent atom length */
7414 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
7423 qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc)
7425 return qtdemux_tree_get_sibling_by_type_full (node, fourcc, NULL);
7429 qtdemux_do_allocation (GstQTDemux * qtdemux, QtDemuxStream * stream)
7431 /* FIXME: This can only reliably work if demuxers have a
7432 * separate streaming thread per srcpad. This should be
7433 * done in a demuxer base class, which integrates parts
7436 * https://bugzilla.gnome.org/show_bug.cgi?id=701856
7441 query = gst_query_new_allocation (stream->caps, FALSE);
7443 if (!gst_pad_peer_query (stream->pad, query)) {
7444 /* not a problem, just debug a little */
7445 GST_DEBUG_OBJECT (qtdemux, "peer ALLOCATION query failed");
7448 if (stream->allocator)
7449 gst_object_unref (stream->allocator);
7451 if (gst_query_get_n_allocation_params (query) > 0) {
7452 /* try the allocator */
7453 gst_query_parse_nth_allocation_param (query, 0, &stream->allocator,
7455 stream->use_allocator = TRUE;
7457 stream->allocator = NULL;
7458 gst_allocation_params_init (&stream->params);
7459 stream->use_allocator = FALSE;
7461 gst_query_unref (query);
7466 gst_qtdemux_configure_protected_caps (GstQTDemux * qtdemux,
7467 QtDemuxStream * stream)
7470 const gchar *selected_system;
7472 g_return_val_if_fail (qtdemux != NULL, FALSE);
7473 g_return_val_if_fail (stream != NULL, FALSE);
7474 g_return_val_if_fail (gst_caps_get_size (stream->caps) == 1, FALSE);
7476 if (stream->protection_scheme_type != FOURCC_cenc) {
7477 GST_ERROR_OBJECT (qtdemux, "unsupported protection scheme");
7480 if (qtdemux->protection_system_ids == NULL) {
7481 GST_ERROR_OBJECT (qtdemux, "stream is protected using cenc, but no "
7482 "cenc protection system information has been found");
7485 g_ptr_array_add (qtdemux->protection_system_ids, NULL);
7486 selected_system = gst_protection_select_system ((const gchar **)
7487 qtdemux->protection_system_ids->pdata);
7488 g_ptr_array_remove_index (qtdemux->protection_system_ids,
7489 qtdemux->protection_system_ids->len - 1);
7490 if (!selected_system) {
7491 GST_ERROR_OBJECT (qtdemux, "stream is protected, but no "
7492 "suitable decryptor element has been found");
7496 s = gst_caps_get_structure (stream->caps, 0);
7497 if (!gst_structure_has_name (s, "application/x-cenc")) {
7498 gst_structure_set (s,
7499 "original-media-type", G_TYPE_STRING, gst_structure_get_name (s),
7500 GST_PROTECTION_SYSTEM_ID_CAPS_FIELD, G_TYPE_STRING, selected_system,
7502 gst_structure_set_name (s, "application/x-cenc");
7508 gst_qtdemux_configure_stream (GstQTDemux * qtdemux, QtDemuxStream * stream)
7510 if (stream->subtype == FOURCC_vide) {
7511 /* fps is calculated base on the duration of the average framerate since
7512 * qt does not have a fixed framerate. */
7513 gboolean fps_available = TRUE;
7515 if ((stream->n_samples == 1) && (stream->first_duration == 0)) {
7520 if (stream->duration == 0 || stream->n_samples < 2) {
7521 stream->fps_n = stream->timescale;
7523 fps_available = FALSE;
7525 GstClockTime avg_duration;
7529 /* duration and n_samples can be updated for fragmented format
7530 * so, framerate of fragmented format is calculated using data in a moof */
7531 if (qtdemux->fragmented && stream->n_samples_moof > 0
7532 && stream->duration_moof > 0) {
7533 n_samples = stream->n_samples_moof;
7534 duration = stream->duration_moof;
7536 n_samples = stream->n_samples;
7537 duration = stream->duration;
7540 /* Calculate a framerate, ignoring the first sample which is sometimes truncated */
7541 /* stream->duration is guint64, timescale, n_samples are guint32 */
7543 gst_util_uint64_scale_round (duration -
7544 stream->first_duration, GST_SECOND,
7545 (guint64) (stream->timescale) * (n_samples - 1));
7547 GST_LOG_OBJECT (qtdemux,
7548 "Calculating avg sample duration based on stream (or moof) duration %"
7550 " minus first sample %u, leaving %d samples gives %"
7551 GST_TIME_FORMAT, duration, stream->first_duration,
7552 n_samples - 1, GST_TIME_ARGS (avg_duration));
7554 gst_video_guess_framerate (avg_duration, &stream->fps_n,
7557 GST_DEBUG_OBJECT (qtdemux,
7558 "Calculating framerate, timescale %u gave fps_n %d fps_d %d",
7559 stream->timescale, stream->fps_n, stream->fps_d);
7564 stream->caps = gst_caps_make_writable (stream->caps);
7566 gst_caps_set_simple (stream->caps,
7567 "width", G_TYPE_INT, stream->width,
7568 "height", G_TYPE_INT, stream->height, NULL);
7570 /* set framerate if calculated framerate is reliable */
7571 if (fps_available) {
7572 gst_caps_set_simple (stream->caps,
7573 "framerate", GST_TYPE_FRACTION, stream->fps_n, stream->fps_d, NULL);
7576 /* calculate pixel-aspect-ratio using display width and height */
7577 GST_DEBUG_OBJECT (qtdemux,
7578 "video size %dx%d, target display size %dx%d", stream->width,
7579 stream->height, stream->display_width, stream->display_height);
7580 /* qt file might have pasp atom */
7581 if (stream->par_w > 0 && stream->par_h > 0) {
7582 GST_DEBUG_OBJECT (qtdemux, "par %d:%d", stream->par_w, stream->par_h);
7583 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
7584 GST_TYPE_FRACTION, stream->par_w, stream->par_h, NULL);
7585 } else if (stream->display_width > 0 && stream->display_height > 0 &&
7586 stream->width > 0 && stream->height > 0) {
7589 /* calculate the pixel aspect ratio using the display and pixel w/h */
7590 n = stream->display_width * stream->height;
7591 d = stream->display_height * stream->width;
7594 GST_DEBUG_OBJECT (qtdemux, "setting PAR to %d/%d", n, d);
7597 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
7598 GST_TYPE_FRACTION, stream->par_w, stream->par_h, NULL);
7601 /* Create incomplete colorimetry here if needed */
7602 if (stream->colorimetry.range ||
7603 stream->colorimetry.matrix ||
7604 stream->colorimetry.transfer || stream->colorimetry.primaries) {
7605 gchar *colorimetry =
7606 gst_video_colorimetry_to_string (&stream->colorimetry);
7607 gst_caps_set_simple (stream->caps, "colorimetry", G_TYPE_STRING,
7609 g_free (colorimetry);
7612 if (stream->multiview_mode != GST_VIDEO_MULTIVIEW_MODE_NONE) {
7613 guint par_w = 1, par_h = 1;
7615 if (stream->par_w > 0 && stream->par_h > 0) {
7616 par_w = stream->par_w;
7617 par_h = stream->par_h;
7620 if (gst_video_multiview_guess_half_aspect (stream->multiview_mode,
7621 stream->width, stream->height, par_w, par_h)) {
7622 stream->multiview_flags |= GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT;
7625 gst_caps_set_simple (stream->caps,
7626 "multiview-mode", G_TYPE_STRING,
7627 gst_video_multiview_mode_to_caps_string (stream->multiview_mode),
7628 "multiview-flags", GST_TYPE_VIDEO_MULTIVIEW_FLAGSET,
7629 stream->multiview_flags, GST_FLAG_SET_MASK_EXACT, NULL);
7634 else if (stream->subtype == FOURCC_soun) {
7636 stream->caps = gst_caps_make_writable (stream->caps);
7637 if (stream->rate > 0)
7638 gst_caps_set_simple (stream->caps,
7639 "rate", G_TYPE_INT, (int) stream->rate, NULL);
7640 if (stream->n_channels > 0)
7641 gst_caps_set_simple (stream->caps,
7642 "channels", G_TYPE_INT, stream->n_channels, NULL);
7643 if (stream->n_channels > 2) {
7644 /* FIXME: Need to parse the 'chan' atom to get channel layouts
7645 * correctly; this is just the minimum we can do - assume
7646 * we don't actually have any channel positions. */
7647 gst_caps_set_simple (stream->caps,
7648 "channel-mask", GST_TYPE_BITMASK, G_GUINT64_CONSTANT (0), NULL);
7654 GstCaps *prev_caps = NULL;
7656 GST_PAD_ELEMENT_PRIVATE (stream->pad) = stream;
7657 gst_pad_set_event_function (stream->pad, gst_qtdemux_handle_src_event);
7658 gst_pad_set_query_function (stream->pad, gst_qtdemux_handle_src_query);
7659 gst_pad_set_active (stream->pad, TRUE);
7661 gst_pad_use_fixed_caps (stream->pad);
7663 if (stream->protected) {
7664 if (!gst_qtdemux_configure_protected_caps (qtdemux, stream)) {
7665 GST_ERROR_OBJECT (qtdemux,
7666 "Failed to configure protected stream caps.");
7671 if (stream->new_stream) {
7674 GstStreamFlags stream_flags;
7677 gst_pad_get_sticky_event (qtdemux->sinkpad, GST_EVENT_STREAM_START,
7680 if (gst_event_parse_group_id (event, &qtdemux->group_id))
7681 qtdemux->have_group_id = TRUE;
7683 qtdemux->have_group_id = FALSE;
7684 gst_event_unref (event);
7685 } else if (!qtdemux->have_group_id) {
7686 qtdemux->have_group_id = TRUE;
7687 qtdemux->group_id = gst_util_group_id_next ();
7690 stream->new_stream = FALSE;
7692 gst_pad_create_stream_id_printf (stream->pad,
7693 GST_ELEMENT_CAST (qtdemux), "%03u", stream->track_id);
7694 event = gst_event_new_stream_start (stream_id);
7695 if (qtdemux->have_group_id)
7696 gst_event_set_group_id (event, qtdemux->group_id);
7697 stream_flags = GST_STREAM_FLAG_NONE;
7698 if (stream->disabled)
7699 stream_flags |= GST_STREAM_FLAG_UNSELECT;
7701 stream_flags |= GST_STREAM_FLAG_SPARSE;
7702 gst_event_set_stream_flags (event, stream_flags);
7703 gst_pad_push_event (stream->pad, event);
7707 prev_caps = gst_pad_get_current_caps (stream->pad);
7709 if (!prev_caps || !gst_caps_is_equal_fixed (prev_caps, stream->caps)) {
7710 GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT, stream->caps);
7711 gst_pad_set_caps (stream->pad, stream->caps);
7713 GST_DEBUG_OBJECT (qtdemux, "ignore duplicated caps");
7717 gst_caps_unref (prev_caps);
7718 stream->new_caps = FALSE;
7724 gst_qtdemux_add_stream (GstQTDemux * qtdemux,
7725 QtDemuxStream * stream, GstTagList * list)
7727 gboolean ret = TRUE;
7728 /* consistent default for push based mode */
7729 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
7731 if (stream->subtype == FOURCC_vide) {
7732 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
7735 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
7738 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
7739 gst_object_unref (stream->pad);
7745 qtdemux->n_video_streams++;
7746 } else if (stream->subtype == FOURCC_soun) {
7747 gchar *name = g_strdup_printf ("audio_%u", qtdemux->n_audio_streams);
7750 gst_pad_new_from_static_template (&gst_qtdemux_audiosrc_template, name);
7752 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
7753 gst_object_unref (stream->pad);
7758 qtdemux->n_audio_streams++;
7759 } else if (stream->subtype == FOURCC_strm) {
7760 GST_DEBUG_OBJECT (qtdemux, "stream type, not creating pad");
7761 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
7762 || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt) {
7763 gchar *name = g_strdup_printf ("subtitle_%u", qtdemux->n_sub_streams);
7766 gst_pad_new_from_static_template (&gst_qtdemux_subsrc_template, name);
7768 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
7769 gst_object_unref (stream->pad);
7774 qtdemux->n_sub_streams++;
7775 } else if (stream->caps) {
7776 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
7779 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
7781 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
7782 gst_object_unref (stream->pad);
7787 qtdemux->n_video_streams++;
7789 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
7796 GST_DEBUG_OBJECT (qtdemux, "adding pad %s %p to qtdemux %p",
7797 GST_OBJECT_NAME (stream->pad), stream->pad, qtdemux);
7798 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
7799 gst_flow_combiner_add_pad (qtdemux->flowcombiner, stream->pad);
7801 if (stream->pending_tags)
7802 gst_tag_list_unref (stream->pending_tags);
7803 stream->pending_tags = list;
7805 /* global tags go on each pad anyway */
7806 stream->send_global_tags = TRUE;
7807 /* send upstream GST_EVENT_PROTECTION events that were received before
7808 this source pad was created */
7809 for (l = qtdemux->protection_event_queue.head; l != NULL; l = l->next)
7810 gst_pad_push_event (stream->pad, gst_event_ref (l->data));
7814 gst_tag_list_unref (list);
7818 /* find next atom with @fourcc starting at @offset */
7819 static GstFlowReturn
7820 qtdemux_find_atom (GstQTDemux * qtdemux, guint64 * offset,
7821 guint64 * length, guint32 fourcc)
7827 GST_LOG_OBJECT (qtdemux, "finding fourcc %" GST_FOURCC_FORMAT " at offset %"
7828 G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), *offset);
7834 ret = gst_pad_pull_range (qtdemux->sinkpad, *offset, 16, &buf);
7835 if (G_UNLIKELY (ret != GST_FLOW_OK))
7837 if (G_UNLIKELY (gst_buffer_get_size (buf) != 16)) {
7840 gst_buffer_unref (buf);
7843 gst_buffer_map (buf, &map, GST_MAP_READ);
7844 extract_initial_length_and_fourcc (map.data, 16, length, &lfourcc);
7845 gst_buffer_unmap (buf, &map);
7846 gst_buffer_unref (buf);
7848 if (G_UNLIKELY (*length == 0)) {
7849 GST_DEBUG_OBJECT (qtdemux, "invalid length 0");
7850 ret = GST_FLOW_ERROR;
7854 if (lfourcc == fourcc) {
7855 GST_DEBUG_OBJECT (qtdemux, "found fourcc at offset %" G_GUINT64_FORMAT,
7859 GST_LOG_OBJECT (qtdemux,
7860 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
7861 GST_FOURCC_ARGS (fourcc), *offset);
7870 /* might simply have had last one */
7871 GST_DEBUG_OBJECT (qtdemux, "fourcc not found");
7876 /* should only do something in pull mode */
7877 /* call with OBJECT lock */
7878 static GstFlowReturn
7879 qtdemux_add_fragmented_samples (GstQTDemux * qtdemux)
7881 guint64 length, offset;
7882 GstBuffer *buf = NULL;
7883 GstFlowReturn ret = GST_FLOW_OK;
7884 GstFlowReturn res = GST_FLOW_OK;
7887 offset = qtdemux->moof_offset;
7888 GST_DEBUG_OBJECT (qtdemux, "next moof at offset %" G_GUINT64_FORMAT, offset);
7891 GST_DEBUG_OBJECT (qtdemux, "no next moof");
7892 return GST_FLOW_EOS;
7895 /* best not do pull etc with lock held */
7896 GST_OBJECT_UNLOCK (qtdemux);
7898 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
7899 if (ret != GST_FLOW_OK)
7902 ret = gst_qtdemux_pull_atom (qtdemux, offset, length, &buf);
7903 if (G_UNLIKELY (ret != GST_FLOW_OK))
7905 gst_buffer_map (buf, &map, GST_MAP_READ);
7906 if (!qtdemux_parse_moof (qtdemux, map.data, map.size, offset, NULL)) {
7907 gst_buffer_unmap (buf, &map);
7908 gst_buffer_unref (buf);
7913 gst_buffer_unmap (buf, &map);
7914 gst_buffer_unref (buf);
7918 /* look for next moof */
7919 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
7920 if (G_UNLIKELY (ret != GST_FLOW_OK))
7924 GST_OBJECT_LOCK (qtdemux);
7926 qtdemux->moof_offset = offset;
7932 GST_DEBUG_OBJECT (qtdemux, "failed to parse moof");
7934 res = GST_FLOW_ERROR;
7939 /* maybe upstream temporarily flushing */
7940 if (ret != GST_FLOW_FLUSHING) {
7941 GST_DEBUG_OBJECT (qtdemux, "no next moof");
7944 GST_DEBUG_OBJECT (qtdemux, "upstream WRONG_STATE");
7945 /* resume at current position next time */
7952 /* initialise bytereaders for stbl sub-atoms */
7954 qtdemux_stbl_init (GstQTDemux * qtdemux, QtDemuxStream * stream, GNode * stbl)
7956 stream->stbl_index = -1; /* no samples have yet been parsed */
7957 stream->sample_index = -1;
7959 /* time-to-sample atom */
7960 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stts, &stream->stts))
7963 /* copy atom data into a new buffer for later use */
7964 stream->stts.data = g_memdup (stream->stts.data, stream->stts.size);
7966 /* skip version + flags */
7967 if (!gst_byte_reader_skip (&stream->stts, 1 + 3) ||
7968 !gst_byte_reader_get_uint32_be (&stream->stts, &stream->n_sample_times))
7970 GST_LOG_OBJECT (qtdemux, "%u timestamp blocks", stream->n_sample_times);
7972 /* make sure there's enough data */
7973 if (!qt_atom_parser_has_chunks (&stream->stts, stream->n_sample_times, 8)) {
7974 stream->n_sample_times = gst_byte_reader_get_remaining (&stream->stts) / 8;
7975 GST_LOG_OBJECT (qtdemux, "overriding to %u timestamp blocks",
7976 stream->n_sample_times);
7977 if (!stream->n_sample_times)
7981 /* sync sample atom */
7982 stream->stps_present = FALSE;
7983 if ((stream->stss_present =
7984 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stss,
7985 &stream->stss) ? TRUE : FALSE) == TRUE) {
7986 /* copy atom data into a new buffer for later use */
7987 stream->stss.data = g_memdup (stream->stss.data, stream->stss.size);
7989 /* skip version + flags */
7990 if (!gst_byte_reader_skip (&stream->stss, 1 + 3) ||
7991 !gst_byte_reader_get_uint32_be (&stream->stss, &stream->n_sample_syncs))
7994 if (stream->n_sample_syncs) {
7995 /* make sure there's enough data */
7996 if (!qt_atom_parser_has_chunks (&stream->stss, stream->n_sample_syncs, 4))
8000 /* partial sync sample atom */
8001 if ((stream->stps_present =
8002 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stps,
8003 &stream->stps) ? TRUE : FALSE) == TRUE) {
8004 /* copy atom data into a new buffer for later use */
8005 stream->stps.data = g_memdup (stream->stps.data, stream->stps.size);
8007 /* skip version + flags */
8008 if (!gst_byte_reader_skip (&stream->stps, 1 + 3) ||
8009 !gst_byte_reader_get_uint32_be (&stream->stps,
8010 &stream->n_sample_partial_syncs))
8013 /* if there are no entries, the stss table contains the real
8015 if (stream->n_sample_partial_syncs) {
8016 /* make sure there's enough data */
8017 if (!qt_atom_parser_has_chunks (&stream->stps,
8018 stream->n_sample_partial_syncs, 4))
8025 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsz, &stream->stsz))
8028 /* copy atom data into a new buffer for later use */
8029 stream->stsz.data = g_memdup (stream->stsz.data, stream->stsz.size);
8031 /* skip version + flags */
8032 if (!gst_byte_reader_skip (&stream->stsz, 1 + 3) ||
8033 !gst_byte_reader_get_uint32_be (&stream->stsz, &stream->sample_size))
8036 if (!gst_byte_reader_get_uint32_be (&stream->stsz, &stream->n_samples))
8039 if (!stream->n_samples)
8042 /* sample-to-chunk atom */
8043 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsc, &stream->stsc))
8046 /* copy atom data into a new buffer for later use */
8047 stream->stsc.data = g_memdup (stream->stsc.data, stream->stsc.size);
8049 /* skip version + flags */
8050 if (!gst_byte_reader_skip (&stream->stsc, 1 + 3) ||
8051 !gst_byte_reader_get_uint32_be (&stream->stsc,
8052 &stream->n_samples_per_chunk))
8055 GST_DEBUG_OBJECT (qtdemux, "n_samples_per_chunk %u",
8056 stream->n_samples_per_chunk);
8058 /* make sure there's enough data */
8059 if (!qt_atom_parser_has_chunks (&stream->stsc, stream->n_samples_per_chunk,
8065 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stco, &stream->stco))
8066 stream->co_size = sizeof (guint32);
8067 else if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_co64,
8069 stream->co_size = sizeof (guint64);
8073 /* copy atom data into a new buffer for later use */
8074 stream->stco.data = g_memdup (stream->stco.data, stream->stco.size);
8076 /* skip version + flags */
8077 if (!gst_byte_reader_skip (&stream->stco, 1 + 3))
8080 /* chunks_are_samples == TRUE means treat chunks as samples */
8081 stream->chunks_are_samples = stream->sample_size && !stream->sampled;
8082 if (stream->chunks_are_samples) {
8083 /* treat chunks as samples */
8084 if (!gst_byte_reader_get_uint32_be (&stream->stco, &stream->n_samples))
8087 /* skip number of entries */
8088 if (!gst_byte_reader_skip (&stream->stco, 4))
8091 /* make sure there are enough data in the stsz atom */
8092 if (!stream->sample_size) {
8093 /* different sizes for each sample */
8094 if (!qt_atom_parser_has_chunks (&stream->stsz, stream->n_samples, 4))
8099 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
8100 stream->n_samples, (guint) sizeof (QtDemuxSample),
8101 stream->n_samples * sizeof (QtDemuxSample) / (1024.0 * 1024.0));
8103 if (stream->n_samples >=
8104 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample)) {
8105 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
8106 "be larger than %uMB (broken file?)", stream->n_samples,
8107 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
8111 g_assert (stream->samples == NULL);
8112 stream->samples = g_try_new0 (QtDemuxSample, stream->n_samples);
8113 if (!stream->samples) {
8114 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
8119 /* composition time-to-sample */
8120 if ((stream->ctts_present =
8121 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_ctts,
8122 &stream->ctts) ? TRUE : FALSE) == TRUE) {
8123 GstByteReader cslg = GST_BYTE_READER_INIT (NULL, 0);
8125 /* copy atom data into a new buffer for later use */
8126 stream->ctts.data = g_memdup (stream->ctts.data, stream->ctts.size);
8128 /* skip version + flags */
8129 if (!gst_byte_reader_skip (&stream->ctts, 1 + 3)
8130 || !gst_byte_reader_get_uint32_be (&stream->ctts,
8131 &stream->n_composition_times))
8134 /* make sure there's enough data */
8135 if (!qt_atom_parser_has_chunks (&stream->ctts, stream->n_composition_times,
8139 /* This is optional, if missing we iterate the ctts */
8140 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_cslg, &cslg)) {
8141 if (!gst_byte_reader_skip (&cslg, 1 + 3)
8142 || !gst_byte_reader_get_uint32_be (&cslg, &stream->cslg_shift)) {
8143 g_free ((gpointer) cslg.data);
8147 gint32 cslg_least = 0;
8148 guint num_entries, pos;
8151 pos = gst_byte_reader_get_pos (&stream->ctts);
8152 num_entries = stream->n_composition_times;
8154 stream->cslg_shift = 0;
8156 for (i = 0; i < num_entries; i++) {
8159 gst_byte_reader_skip_unchecked (&stream->ctts, 4);
8160 offset = gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
8162 if (offset < cslg_least)
8163 cslg_least = offset;
8167 stream->cslg_shift = ABS (cslg_least);
8169 stream->cslg_shift = 0;
8171 /* reset the reader so we can generate sample table */
8172 gst_byte_reader_set_pos (&stream->ctts, pos);
8175 /* Ensure the cslg_shift value is consistent so we can use it
8176 * unconditionnally to produce TS and Segment */
8177 stream->cslg_shift = 0;
8184 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8185 (_("This file is corrupt and cannot be played.")), (NULL));
8190 gst_qtdemux_stbl_free (stream);
8191 if (!qtdemux->fragmented) {
8192 /* not quite good */
8193 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
8196 /* may pick up samples elsewhere */
8202 /* collect samples from the next sample to be parsed up to sample @n for @stream
8203 * by reading the info from @stbl
8205 * This code can be executed from both the streaming thread and the seeking
8206 * thread so it takes the object lock to protect itself
8209 qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream, guint32 n)
8212 QtDemuxSample *samples, *first, *cur, *last;
8213 guint32 n_samples_per_chunk;
8216 GST_LOG_OBJECT (qtdemux, "parsing samples for stream fourcc %"
8217 GST_FOURCC_FORMAT ", pad %s", GST_FOURCC_ARGS (stream->fourcc),
8218 stream->pad ? GST_PAD_NAME (stream->pad) : "(NULL)");
8220 n_samples = stream->n_samples;
8223 goto out_of_samples;
8225 GST_OBJECT_LOCK (qtdemux);
8226 if (n <= stream->stbl_index)
8227 goto already_parsed;
8229 GST_DEBUG_OBJECT (qtdemux, "parsing up to sample %u", n);
8231 if (!stream->stsz.data) {
8232 /* so we already parsed and passed all the moov samples;
8233 * onto fragmented ones */
8234 g_assert (qtdemux->fragmented);
8238 /* pointer to the sample table */
8239 samples = stream->samples;
8241 /* starts from -1, moves to the next sample index to parse */
8242 stream->stbl_index++;
8244 /* keep track of the first and last sample to fill */
8245 first = &samples[stream->stbl_index];
8248 if (!stream->chunks_are_samples) {
8249 /* set the sample sizes */
8250 if (stream->sample_size == 0) {
8251 /* different sizes for each sample */
8252 for (cur = first; cur <= last; cur++) {
8253 cur->size = gst_byte_reader_get_uint32_be_unchecked (&stream->stsz);
8254 GST_LOG_OBJECT (qtdemux, "sample %d has size %u",
8255 (guint) (cur - samples), cur->size);
8258 /* samples have the same size */
8259 GST_LOG_OBJECT (qtdemux, "all samples have size %u", stream->sample_size);
8260 for (cur = first; cur <= last; cur++)
8261 cur->size = stream->sample_size;
8265 n_samples_per_chunk = stream->n_samples_per_chunk;
8268 for (i = stream->stsc_index; i < n_samples_per_chunk; i++) {
8271 if (stream->stsc_chunk_index >= stream->last_chunk
8272 || stream->stsc_chunk_index < stream->first_chunk) {
8273 stream->first_chunk =
8274 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
8275 stream->samples_per_chunk =
8276 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
8277 gst_byte_reader_skip_unchecked (&stream->stsc, 4);
8279 /* chunk numbers are counted from 1 it seems */
8280 if (G_UNLIKELY (stream->first_chunk == 0))
8283 --stream->first_chunk;
8285 /* the last chunk of each entry is calculated by taking the first chunk
8286 * of the next entry; except if there is no next, where we fake it with
8288 if (G_UNLIKELY (i == (stream->n_samples_per_chunk - 1))) {
8289 stream->last_chunk = G_MAXUINT32;
8291 stream->last_chunk =
8292 gst_byte_reader_peek_uint32_be_unchecked (&stream->stsc);
8293 if (G_UNLIKELY (stream->last_chunk == 0))
8296 --stream->last_chunk;
8299 GST_LOG_OBJECT (qtdemux,
8300 "entry %d has first_chunk %d, last_chunk %d, samples_per_chunk %d", i,
8301 stream->first_chunk, stream->last_chunk, stream->samples_per_chunk);
8303 if (G_UNLIKELY (stream->last_chunk < stream->first_chunk))
8306 if (stream->last_chunk != G_MAXUINT32) {
8307 if (!qt_atom_parser_peek_sub (&stream->stco,
8308 stream->first_chunk * stream->co_size,
8309 (stream->last_chunk - stream->first_chunk) * stream->co_size,
8314 stream->co_chunk = stream->stco;
8315 if (!gst_byte_reader_skip (&stream->co_chunk,
8316 stream->first_chunk * stream->co_size))
8320 stream->stsc_chunk_index = stream->first_chunk;
8323 last_chunk = stream->last_chunk;
8325 if (stream->chunks_are_samples) {
8326 cur = &samples[stream->stsc_chunk_index];
8328 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
8331 stream->stsc_chunk_index = j;
8336 qt_atom_parser_get_offset_unchecked (&stream->co_chunk,
8339 GST_LOG_OBJECT (qtdemux, "Created entry %d with offset "
8340 "%" G_GUINT64_FORMAT, j, cur->offset);
8342 if (stream->samples_per_frame * stream->bytes_per_frame) {
8344 (stream->samples_per_chunk * stream->n_channels) /
8345 stream->samples_per_frame * stream->bytes_per_frame;
8347 cur->size = stream->samples_per_chunk;
8350 GST_DEBUG_OBJECT (qtdemux,
8351 "keyframe sample %d: timestamp %" GST_TIME_FORMAT ", size %u",
8352 j, GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream,
8353 stream->stco_sample_index)), cur->size);
8355 cur->timestamp = stream->stco_sample_index;
8356 cur->duration = stream->samples_per_chunk;
8357 cur->keyframe = TRUE;
8360 stream->stco_sample_index += stream->samples_per_chunk;
8362 stream->stsc_chunk_index = j;
8364 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
8365 guint32 samples_per_chunk;
8366 guint64 chunk_offset;
8368 if (!stream->stsc_sample_index
8369 && !qt_atom_parser_get_offset (&stream->co_chunk, stream->co_size,
8370 &stream->chunk_offset))
8373 samples_per_chunk = stream->samples_per_chunk;
8374 chunk_offset = stream->chunk_offset;
8376 for (k = stream->stsc_sample_index; k < samples_per_chunk; k++) {
8377 GST_LOG_OBJECT (qtdemux, "creating entry %d with offset %"
8378 G_GUINT64_FORMAT " and size %d",
8379 (guint) (cur - samples), chunk_offset, cur->size);
8381 cur->offset = chunk_offset;
8382 chunk_offset += cur->size;
8385 if (G_UNLIKELY (cur > last)) {
8387 stream->stsc_sample_index = k + 1;
8388 stream->chunk_offset = chunk_offset;
8389 stream->stsc_chunk_index = j;
8393 stream->stsc_sample_index = 0;
8395 stream->stsc_chunk_index = j;
8397 stream->stsc_index++;
8400 if (stream->chunks_are_samples)
8404 guint32 n_sample_times;
8406 n_sample_times = stream->n_sample_times;
8409 for (i = stream->stts_index; i < n_sample_times; i++) {
8410 guint32 stts_samples;
8411 gint32 stts_duration;
8414 if (stream->stts_sample_index >= stream->stts_samples
8415 || !stream->stts_sample_index) {
8417 stream->stts_samples =
8418 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
8419 stream->stts_duration =
8420 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
8422 GST_LOG_OBJECT (qtdemux, "block %d, %u timestamps, duration %u",
8423 i, stream->stts_samples, stream->stts_duration);
8425 stream->stts_sample_index = 0;
8428 stts_samples = stream->stts_samples;
8429 stts_duration = stream->stts_duration;
8430 stts_time = stream->stts_time;
8432 for (j = stream->stts_sample_index; j < stts_samples; j++) {
8433 GST_DEBUG_OBJECT (qtdemux,
8434 "sample %d: index %d, timestamp %" GST_TIME_FORMAT,
8435 (guint) (cur - samples), j,
8436 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stts_time)));
8438 cur->timestamp = stts_time;
8439 cur->duration = stts_duration;
8441 /* avoid 32-bit wrap-around,
8442 * but still mind possible 'negative' duration */
8443 stts_time += (gint64) stts_duration;
8446 if (G_UNLIKELY (cur > last)) {
8448 stream->stts_time = stts_time;
8449 stream->stts_sample_index = j + 1;
8453 stream->stts_sample_index = 0;
8454 stream->stts_time = stts_time;
8455 stream->stts_index++;
8457 /* fill up empty timestamps with the last timestamp, this can happen when
8458 * the last samples do not decode and so we don't have timestamps for them.
8459 * We however look at the last timestamp to estimate the track length so we
8460 * need something in here. */
8461 for (; cur < last; cur++) {
8462 GST_DEBUG_OBJECT (qtdemux,
8463 "fill sample %d: timestamp %" GST_TIME_FORMAT,
8464 (guint) (cur - samples),
8465 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stream->stts_time)));
8466 cur->timestamp = stream->stts_time;
8472 /* sample sync, can be NULL */
8473 if (stream->stss_present == TRUE) {
8474 guint32 n_sample_syncs;
8476 n_sample_syncs = stream->n_sample_syncs;
8478 if (!n_sample_syncs) {
8479 GST_DEBUG_OBJECT (qtdemux, "all samples are keyframes");
8480 stream->all_keyframe = TRUE;
8482 for (i = stream->stss_index; i < n_sample_syncs; i++) {
8483 /* note that the first sample is index 1, not 0 */
8486 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stss);
8488 if (G_LIKELY (index > 0 && index <= n_samples)) {
8490 samples[index].keyframe = TRUE;
8491 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
8492 /* and exit if we have enough samples */
8493 if (G_UNLIKELY (index >= n)) {
8500 stream->stss_index = i;
8503 /* stps marks partial sync frames like open GOP I-Frames */
8504 if (stream->stps_present == TRUE) {
8505 guint32 n_sample_partial_syncs;
8507 n_sample_partial_syncs = stream->n_sample_partial_syncs;
8509 /* if there are no entries, the stss table contains the real
8511 if (n_sample_partial_syncs) {
8512 for (i = stream->stps_index; i < n_sample_partial_syncs; i++) {
8513 /* note that the first sample is index 1, not 0 */
8516 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stps);
8518 if (G_LIKELY (index > 0 && index <= n_samples)) {
8520 samples[index].keyframe = TRUE;
8521 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
8522 /* and exit if we have enough samples */
8523 if (G_UNLIKELY (index >= n)) {
8530 stream->stps_index = i;
8534 /* no stss, all samples are keyframes */
8535 stream->all_keyframe = TRUE;
8536 GST_DEBUG_OBJECT (qtdemux, "setting all keyframes");
8541 /* composition time to sample */
8542 if (stream->ctts_present == TRUE) {
8543 guint32 n_composition_times;
8545 gint32 ctts_soffset;
8547 /* Fill in the pts_offsets */
8549 n_composition_times = stream->n_composition_times;
8551 for (i = stream->ctts_index; i < n_composition_times; i++) {
8552 if (stream->ctts_sample_index >= stream->ctts_count
8553 || !stream->ctts_sample_index) {
8554 stream->ctts_count =
8555 gst_byte_reader_get_uint32_be_unchecked (&stream->ctts);
8556 stream->ctts_soffset =
8557 gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
8558 stream->ctts_sample_index = 0;
8561 ctts_count = stream->ctts_count;
8562 ctts_soffset = stream->ctts_soffset;
8564 for (j = stream->ctts_sample_index; j < ctts_count; j++) {
8565 cur->pts_offset = ctts_soffset;
8568 if (G_UNLIKELY (cur > last)) {
8570 stream->ctts_sample_index = j + 1;
8574 stream->ctts_sample_index = 0;
8575 stream->ctts_index++;
8579 stream->stbl_index = n;
8580 /* if index has been completely parsed, free data that is no-longer needed */
8581 if (n + 1 == stream->n_samples) {
8582 gst_qtdemux_stbl_free (stream);
8583 GST_DEBUG_OBJECT (qtdemux, "parsed all available samples;");
8584 if (qtdemux->pullbased) {
8585 GST_DEBUG_OBJECT (qtdemux, "checking for more samples");
8586 while (n + 1 == stream->n_samples)
8587 if (qtdemux_add_fragmented_samples (qtdemux) != GST_FLOW_OK)
8591 GST_OBJECT_UNLOCK (qtdemux);
8598 GST_LOG_OBJECT (qtdemux,
8599 "Tried to parse up to sample %u but this sample has already been parsed",
8601 /* if fragmented, there may be more */
8602 if (qtdemux->fragmented && n == stream->stbl_index)
8604 GST_OBJECT_UNLOCK (qtdemux);
8610 GST_LOG_OBJECT (qtdemux,
8611 "Tried to parse up to sample %u but there are only %u samples", n + 1,
8613 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8614 (_("This file is corrupt and cannot be played.")), (NULL));
8619 GST_OBJECT_UNLOCK (qtdemux);
8620 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8621 (_("This file is corrupt and cannot be played.")), (NULL));
8626 /* collect all segment info for @stream.
8629 qtdemux_parse_segments (GstQTDemux * qtdemux, QtDemuxStream * stream,
8633 /* accept edts if they contain gaps at start and there is only
8634 * one media segment */
8635 gboolean allow_pushbased_edts = TRUE;
8636 gint media_segments_count = 0;
8638 /* parse and prepare segment info from the edit list */
8639 GST_DEBUG_OBJECT (qtdemux, "looking for edit list container");
8640 stream->n_segments = 0;
8641 stream->segments = NULL;
8642 if ((edts = qtdemux_tree_get_child_by_type (trak, FOURCC_edts))) {
8645 gint i, count, entry_size;
8651 GST_DEBUG_OBJECT (qtdemux, "looking for edit list");
8652 if (!(elst = qtdemux_tree_get_child_by_type (edts, FOURCC_elst)))
8655 buffer = elst->data;
8657 version = QT_UINT8 (buffer + 8);
8658 entry_size = (version == 1) ? 20 : 12;
8660 n_segments = QT_UINT32 (buffer + 12);
8662 /* we might allocate a bit too much, at least allocate 1 segment */
8663 stream->segments = g_new (QtDemuxSegment, MAX (n_segments, 1));
8665 /* segments always start from 0 */
8669 for (i = 0; i < n_segments; i++) {
8672 gboolean time_valid = TRUE;
8673 QtDemuxSegment *segment;
8675 GstClockTime media_start = GST_CLOCK_TIME_NONE;
8678 media_time = QT_UINT64 (buffer + 24 + i * entry_size);
8679 duration = QT_UINT64 (buffer + 16 + i * entry_size);
8680 if (media_time == G_MAXUINT64)
8683 media_time = QT_UINT32 (buffer + 20 + i * entry_size);
8684 duration = QT_UINT32 (buffer + 16 + i * entry_size);
8685 if (media_time == G_MAXUINT32)
8690 media_start = QTSTREAMTIME_TO_GSTTIME (stream, media_time);
8692 segment = &stream->segments[count++];
8694 /* time and duration expressed in global timescale */
8695 segment->time = stime;
8696 /* add non scaled values so we don't cause roundoff errors */
8697 if (duration || media_start == GST_CLOCK_TIME_NONE) {
8699 stime = QTTIME_TO_GSTTIME (qtdemux, time);
8700 segment->duration = stime - segment->time;
8702 /* zero duration does not imply media_start == media_stop
8703 * but, only specify media_start.*/
8704 stime = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
8705 if (GST_CLOCK_TIME_IS_VALID (stime) && time_valid
8706 && stime >= media_start) {
8707 segment->duration = stime - media_start;
8709 segment->duration = GST_CLOCK_TIME_NONE;
8712 segment->stop_time = stime;
8714 segment->trak_media_start = media_time;
8715 /* media_time expressed in stream timescale */
8717 segment->media_start = media_start;
8718 segment->media_stop = segment->media_start + segment->duration;
8719 media_segments_count++;
8721 segment->media_start = GST_CLOCK_TIME_NONE;
8722 segment->media_stop = GST_CLOCK_TIME_NONE;
8725 QT_UINT32 (buffer + ((version == 1) ? 32 : 24) + i * entry_size);
8727 if (rate_int <= 1) {
8728 /* 0 is not allowed, some programs write 1 instead of the floating point
8730 GST_WARNING_OBJECT (qtdemux, "found suspicious rate %" G_GUINT32_FORMAT,
8734 segment->rate = rate_int / 65536.0;
8737 GST_DEBUG_OBJECT (qtdemux, "created segment %d time %" GST_TIME_FORMAT
8738 ", duration %" GST_TIME_FORMAT ", media_start %" GST_TIME_FORMAT
8739 " (%" G_GUINT64_FORMAT ") , media_stop %" GST_TIME_FORMAT
8740 " stop_time %" GST_TIME_FORMAT " rate %g, (%d) timescale %u",
8741 i, GST_TIME_ARGS (segment->time),
8742 GST_TIME_ARGS (segment->duration),
8743 GST_TIME_ARGS (segment->media_start), media_time,
8744 GST_TIME_ARGS (segment->media_stop),
8745 GST_TIME_ARGS (segment->stop_time), segment->rate, rate_int,
8747 if (segment->stop_time > qtdemux->segment.stop) {
8748 GST_WARNING_OBJECT (qtdemux, "Segment %d "
8749 " extends to %" GST_TIME_FORMAT
8750 " past the end of the file duration %" GST_TIME_FORMAT
8751 " it will be truncated", i, GST_TIME_ARGS (segment->stop_time),
8752 GST_TIME_ARGS (qtdemux->segment.stop));
8753 qtdemux->segment.stop = segment->stop_time;
8756 GST_DEBUG_OBJECT (qtdemux, "found %d segments", count);
8757 stream->n_segments = count;
8758 if (media_segments_count != 1)
8759 allow_pushbased_edts = FALSE;
8763 /* push based does not handle segments, so act accordingly here,
8764 * and warn if applicable */
8765 if (!qtdemux->pullbased && !allow_pushbased_edts) {
8766 GST_WARNING_OBJECT (qtdemux, "streaming; discarding edit list segments");
8767 /* remove and use default one below, we stream like it anyway */
8768 g_free (stream->segments);
8769 stream->segments = NULL;
8770 stream->n_segments = 0;
8773 /* no segments, create one to play the complete trak */
8774 if (stream->n_segments == 0) {
8775 GstClockTime stream_duration =
8776 QTSTREAMTIME_TO_GSTTIME (stream, stream->duration);
8778 if (stream->segments == NULL)
8779 stream->segments = g_new (QtDemuxSegment, 1);
8781 /* represent unknown our way */
8782 if (stream_duration == 0)
8783 stream_duration = GST_CLOCK_TIME_NONE;
8785 stream->segments[0].time = 0;
8786 stream->segments[0].stop_time = stream_duration;
8787 stream->segments[0].duration = stream_duration;
8788 stream->segments[0].media_start = 0;
8789 stream->segments[0].media_stop = stream_duration;
8790 stream->segments[0].rate = 1.0;
8791 stream->segments[0].trak_media_start = 0;
8793 GST_DEBUG_OBJECT (qtdemux, "created dummy segment %" GST_TIME_FORMAT,
8794 GST_TIME_ARGS (stream_duration));
8795 stream->n_segments = 1;
8796 stream->dummy_segment = TRUE;
8798 GST_DEBUG_OBJECT (qtdemux, "using %d segments", stream->n_segments);
8804 * Parses the stsd atom of a svq3 trak looking for
8805 * the SMI and gama atoms.
8808 qtdemux_parse_svq3_stsd_data (GstQTDemux * qtdemux, GNode * stsd,
8809 guint8 ** gamma, GstBuffer ** seqh)
8811 guint8 *_gamma = NULL;
8812 GstBuffer *_seqh = NULL;
8813 guint8 *stsd_data = stsd->data;
8814 guint32 length = QT_UINT32 (stsd_data);
8818 GST_WARNING_OBJECT (qtdemux, "stsd too short");
8824 version = QT_UINT16 (stsd_data);
8829 while (length > 8) {
8830 guint32 fourcc, size;
8832 size = QT_UINT32 (stsd_data);
8833 fourcc = QT_FOURCC (stsd_data + 4);
8834 data = stsd_data + 8;
8837 GST_WARNING_OBJECT (qtdemux, "Atom of size 0 found, aborting "
8838 "svq3 atom parsing");
8847 GST_WARNING_OBJECT (qtdemux, "Unexpected size %" G_GUINT32_FORMAT
8848 " for gama atom, expected 12", size);
8853 if (size > 16 && QT_FOURCC (data) == FOURCC_SEQH) {
8855 if (_seqh != NULL) {
8856 GST_WARNING_OBJECT (qtdemux, "Unexpected second SEQH SMI atom "
8857 " found, ignoring");
8859 seqh_size = QT_UINT32 (data + 4);
8860 if (seqh_size > 0) {
8861 _seqh = gst_buffer_new_and_alloc (seqh_size);
8862 gst_buffer_fill (_seqh, 0, data + 8, seqh_size);
8869 GST_WARNING_OBJECT (qtdemux, "Unhandled atom %" GST_FOURCC_FORMAT
8870 " in SVQ3 entry in stsd atom", GST_FOURCC_ARGS (fourcc));
8874 if (size <= length) {
8880 GST_WARNING_OBJECT (qtdemux, "SVQ3 entry too short in stsd atom");
8883 GST_WARNING_OBJECT (qtdemux, "Unexpected version for SVQ3 entry %"
8884 G_GUINT16_FORMAT, version);
8895 gst_buffer_unref (_seqh);
8900 qtdemux_get_rtsp_uri_from_hndl (GstQTDemux * qtdemux, GNode * minf)
8907 * Get 'dinf', to get its child 'dref', that might contain a 'hndl'
8908 * atom that might contain a 'data' atom with the rtsp uri.
8909 * This case was reported in bug #597497, some info about
8910 * the hndl atom can be found in TN1195
8912 dinf = qtdemux_tree_get_child_by_type (minf, FOURCC_dinf);
8913 GST_DEBUG_OBJECT (qtdemux, "Trying to obtain rtsp URI for stream trak");
8916 guint32 dref_num_entries = 0;
8917 if (qtdemux_tree_get_child_by_type_full (dinf, FOURCC_dref, &dref) &&
8918 gst_byte_reader_skip (&dref, 4) &&
8919 gst_byte_reader_get_uint32_be (&dref, &dref_num_entries)) {
8922 /* search dref entries for hndl atom */
8923 for (i = 0; i < dref_num_entries; i++) {
8924 guint32 size = 0, type;
8925 guint8 string_len = 0;
8926 if (gst_byte_reader_get_uint32_be (&dref, &size) &&
8927 qt_atom_parser_get_fourcc (&dref, &type)) {
8928 if (type == FOURCC_hndl) {
8929 GST_DEBUG_OBJECT (qtdemux, "Found hndl atom");
8931 /* skip data reference handle bytes and the
8932 * following pascal string and some extra 4
8933 * bytes I have no idea what are */
8934 if (!gst_byte_reader_skip (&dref, 4) ||
8935 !gst_byte_reader_get_uint8 (&dref, &string_len) ||
8936 !gst_byte_reader_skip (&dref, string_len + 4)) {
8937 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl atom");
8941 /* iterate over the atoms to find the data atom */
8942 while (gst_byte_reader_get_remaining (&dref) >= 8) {
8946 if (gst_byte_reader_get_uint32_be (&dref, &atom_size) &&
8947 qt_atom_parser_get_fourcc (&dref, &atom_type)) {
8948 if (atom_type == FOURCC_data) {
8949 const guint8 *uri_aux = NULL;
8951 /* found the data atom that might contain the rtsp uri */
8952 GST_DEBUG_OBJECT (qtdemux, "Found data atom inside "
8953 "hndl atom, interpreting it as an URI");
8954 if (gst_byte_reader_peek_data (&dref, atom_size - 8,
8956 if (g_strstr_len ((gchar *) uri_aux, 7, "rtsp://") != NULL)
8957 uri = g_strndup ((gchar *) uri_aux, atom_size - 8);
8959 GST_WARNING_OBJECT (qtdemux, "Data atom in hndl atom "
8960 "didn't contain a rtsp address");
8962 GST_WARNING_OBJECT (qtdemux, "Failed to get the data "
8967 /* skipping to the next entry */
8968 if (!gst_byte_reader_skip (&dref, atom_size - 8))
8971 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl child "
8978 /* skip to the next entry */
8979 if (!gst_byte_reader_skip (&dref, size - 8))
8982 GST_WARNING_OBJECT (qtdemux, "Error parsing dref atom");
8985 GST_DEBUG_OBJECT (qtdemux, "Finished parsing dref atom");
8991 #define AMR_NB_ALL_MODES 0x81ff
8992 #define AMR_WB_ALL_MODES 0x83ff
8994 qtdemux_parse_amr_bitrate (GstBuffer * buf, gboolean wb)
8996 /* The 'damr' atom is of the form:
8998 * | vendor | decoder_ver | mode_set | mode_change_period | frames/sample |
8999 * 32 b 8 b 16 b 8 b 8 b
9001 * The highest set bit of the first 7 (AMR-NB) or 8 (AMR-WB) bits of mode_set
9002 * represents the highest mode used in the stream (and thus the maximum
9003 * bitrate), with a couple of special cases as seen below.
9006 /* Map of frame type ID -> bitrate */
9007 static const guint nb_bitrates[] = {
9008 4750, 5150, 5900, 6700, 7400, 7950, 10200, 12200
9010 static const guint wb_bitrates[] = {
9011 6600, 8850, 12650, 14250, 15850, 18250, 19850, 23050, 23850
9017 gst_buffer_map (buf, &map, GST_MAP_READ);
9019 if (map.size != 0x11) {
9020 GST_DEBUG ("Atom should have size 0x11, not %" G_GSIZE_FORMAT, map.size);
9024 if (QT_FOURCC (map.data + 4) != FOURCC_damr) {
9025 GST_DEBUG ("Unknown atom in %" GST_FOURCC_FORMAT,
9026 GST_FOURCC_ARGS (QT_UINT32 (map.data + 4)));
9030 mode_set = QT_UINT16 (map.data + 13);
9032 if (mode_set == (wb ? AMR_WB_ALL_MODES : AMR_NB_ALL_MODES))
9033 max_mode = 7 + (wb ? 1 : 0);
9035 /* AMR-NB modes fo from 0-7, and AMR-WB modes go from 0-8 */
9036 max_mode = g_bit_nth_msf ((gulong) mode_set & (wb ? 0x1ff : 0xff), -1);
9038 if (max_mode == -1) {
9039 GST_DEBUG ("No mode indication was found (mode set) = %x",
9044 gst_buffer_unmap (buf, &map);
9045 return wb ? wb_bitrates[max_mode] : nb_bitrates[max_mode];
9048 gst_buffer_unmap (buf, &map);
9053 qtdemux_parse_transformation_matrix (GstQTDemux * qtdemux,
9054 GstByteReader * reader, guint32 * matrix, const gchar * atom)
9057 * 9 values of 32 bits (fixed point 16.16, except 2 5 and 8 that are 2.30)
9063 if (gst_byte_reader_get_remaining (reader) < 36)
9066 matrix[0] = gst_byte_reader_get_uint32_be_unchecked (reader);
9067 matrix[1] = gst_byte_reader_get_uint32_be_unchecked (reader);
9068 matrix[2] = gst_byte_reader_get_uint32_be_unchecked (reader);
9069 matrix[3] = gst_byte_reader_get_uint32_be_unchecked (reader);
9070 matrix[4] = gst_byte_reader_get_uint32_be_unchecked (reader);
9071 matrix[5] = gst_byte_reader_get_uint32_be_unchecked (reader);
9072 matrix[6] = gst_byte_reader_get_uint32_be_unchecked (reader);
9073 matrix[7] = gst_byte_reader_get_uint32_be_unchecked (reader);
9074 matrix[8] = gst_byte_reader_get_uint32_be_unchecked (reader);
9076 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix from atom %s", atom);
9077 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[0] >> 16,
9078 matrix[0] & 0xFFFF, matrix[1] >> 16, matrix[1] & 0xFF, matrix[2] >> 16,
9080 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[3] >> 16,
9081 matrix[3] & 0xFFFF, matrix[4] >> 16, matrix[4] & 0xFF, matrix[5] >> 16,
9083 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[6] >> 16,
9084 matrix[6] & 0xFFFF, matrix[7] >> 16, matrix[7] & 0xFF, matrix[8] >> 16,
9091 qtdemux_inspect_transformation_matrix (GstQTDemux * qtdemux,
9092 QtDemuxStream * stream, guint32 * matrix, GstTagList ** taglist)
9099 * This macro will only compare value abdegh, it expects cfi to have already
9102 #define QTCHECK_MATRIX(m,a,b,d,e) ((m)[0] == (a << 16) && (m)[1] == (b << 16) && \
9103 (m)[3] == (d << 16) && (m)[4] == (e << 16))
9105 /* only handle the cases where the last column has standard values */
9106 if (matrix[2] == 0 && matrix[5] == 0 && matrix[8] == 1 << 30) {
9107 const gchar *rotation_tag = NULL;
9109 /* no rotation needed */
9110 if (QTCHECK_MATRIX (matrix, 1, 0, 0, 1)) {
9112 } else if (QTCHECK_MATRIX (matrix, 0, 1, G_MAXUINT16, 0)) {
9113 rotation_tag = "rotate-90";
9114 } else if (QTCHECK_MATRIX (matrix, G_MAXUINT16, 0, 0, G_MAXUINT16)) {
9115 rotation_tag = "rotate-180";
9116 } else if (QTCHECK_MATRIX (matrix, 0, G_MAXUINT16, 1, 0)) {
9117 rotation_tag = "rotate-270";
9119 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
9122 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix rotation %s",
9124 if (rotation_tag != NULL) {
9125 if (*taglist == NULL)
9126 *taglist = gst_tag_list_new_empty ();
9127 gst_tag_list_add (*taglist, GST_TAG_MERGE_REPLACE,
9128 GST_TAG_IMAGE_ORIENTATION, rotation_tag, NULL);
9131 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
9135 /* Parses the boxes defined in ISO/IEC 14496-12 that enable support for
9136 * protected streams (sinf, frma, schm and schi); if the protection scheme is
9137 * Common Encryption (cenc), the function will also parse the tenc box (defined
9138 * in ISO/IEC 23001-7). @container points to the node that contains these boxes
9139 * (typically an enc[v|a|t|s] sample entry); the function will set
9140 * @original_fmt to the fourcc of the original unencrypted stream format.
9141 * Returns TRUE if successful; FALSE otherwise. */
9143 qtdemux_parse_protection_scheme_info (GstQTDemux * qtdemux,
9144 QtDemuxStream * stream, GNode * container, guint32 * original_fmt)
9151 g_return_val_if_fail (qtdemux != NULL, FALSE);
9152 g_return_val_if_fail (stream != NULL, FALSE);
9153 g_return_val_if_fail (container != NULL, FALSE);
9154 g_return_val_if_fail (original_fmt != NULL, FALSE);
9156 sinf = qtdemux_tree_get_child_by_type (container, FOURCC_sinf);
9157 if (G_UNLIKELY (!sinf)) {
9158 if (stream->protection_scheme_type == FOURCC_cenc) {
9159 GST_ERROR_OBJECT (qtdemux, "sinf box does not contain schi box, which is "
9160 "mandatory for Common Encryption");
9166 frma = qtdemux_tree_get_child_by_type (sinf, FOURCC_frma);
9167 if (G_UNLIKELY (!frma)) {
9168 GST_ERROR_OBJECT (qtdemux, "sinf box does not contain mandatory frma box");
9172 *original_fmt = QT_FOURCC ((const guint8 *) frma->data + 8);
9173 GST_DEBUG_OBJECT (qtdemux, "original stream format: '%" GST_FOURCC_FORMAT "'",
9174 GST_FOURCC_ARGS (*original_fmt));
9176 schm = qtdemux_tree_get_child_by_type (sinf, FOURCC_schm);
9178 GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schm box");
9181 stream->protection_scheme_type = QT_FOURCC ((const guint8 *) schm->data + 12);
9182 stream->protection_scheme_version =
9183 QT_UINT32 ((const guint8 *) schm->data + 16);
9185 GST_DEBUG_OBJECT (qtdemux,
9186 "protection_scheme_type: %" GST_FOURCC_FORMAT ", "
9187 "protection_scheme_version: %#010x",
9188 GST_FOURCC_ARGS (stream->protection_scheme_type),
9189 stream->protection_scheme_version);
9191 schi = qtdemux_tree_get_child_by_type (sinf, FOURCC_schi);
9193 GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schi box");
9196 if (stream->protection_scheme_type == FOURCC_cenc) {
9197 QtDemuxCencSampleSetInfo *info;
9199 const guint8 *tenc_data;
9200 guint32 isEncrypted;
9202 const guint8 *default_kid;
9205 if (G_UNLIKELY (!stream->protection_scheme_info))
9206 stream->protection_scheme_info =
9207 g_malloc0 (sizeof (QtDemuxCencSampleSetInfo));
9209 info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
9211 tenc = qtdemux_tree_get_child_by_type (schi, FOURCC_tenc);
9213 GST_ERROR_OBJECT (qtdemux, "schi box does not contain tenc box, "
9214 "which is mandatory for Common Encryption");
9217 tenc_data = (const guint8 *) tenc->data + 12;
9218 isEncrypted = QT_UINT24 (tenc_data);
9219 iv_size = QT_UINT8 (tenc_data + 3);
9220 default_kid = (tenc_data + 4);
9221 kid_buf = gst_buffer_new_allocate (NULL, 16, NULL);
9222 gst_buffer_fill (kid_buf, 0, default_kid, 16);
9223 if (info->default_properties)
9224 gst_structure_free (info->default_properties);
9225 info->default_properties =
9226 gst_structure_new ("application/x-cenc",
9227 "iv_size", G_TYPE_UINT, iv_size,
9228 "encrypted", G_TYPE_BOOLEAN, (isEncrypted == 1),
9229 "kid", GST_TYPE_BUFFER, kid_buf, NULL);
9230 GST_DEBUG_OBJECT (qtdemux, "default sample properties: "
9231 "is_encrypted=%u, iv_size=%u", isEncrypted, iv_size);
9232 gst_buffer_unref (kid_buf);
9238 * With each track we associate a new QtDemuxStream that contains all the info
9240 * traks that do not decode to something (like strm traks) will not have a pad.
9243 qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
9263 QtDemuxStream *stream = NULL;
9264 gboolean new_stream = FALSE;
9265 gchar *codec = NULL;
9266 const guint8 *stsd_data;
9267 guint16 lang_code; /* quicktime lang code or packed iso code */
9269 guint32 tkhd_flags = 0;
9270 guint8 tkhd_version = 0;
9272 guint value_size, stsd_len, len;
9276 GST_DEBUG_OBJECT (qtdemux, "parse_trak");
9278 if (!qtdemux_tree_get_child_by_type_full (trak, FOURCC_tkhd, &tkhd)
9279 || !gst_byte_reader_get_uint8 (&tkhd, &tkhd_version)
9280 || !gst_byte_reader_get_uint24_be (&tkhd, &tkhd_flags))
9283 /* pick between 64 or 32 bits */
9284 value_size = tkhd_version == 1 ? 8 : 4;
9285 if (!gst_byte_reader_skip (&tkhd, value_size * 2) ||
9286 !gst_byte_reader_get_uint32_be (&tkhd, &track_id))
9289 if (!qtdemux->got_moov) {
9290 if (qtdemux_find_stream (qtdemux, track_id))
9291 goto existing_stream;
9292 stream = _create_stream ();
9293 stream->track_id = track_id;
9296 stream = qtdemux_find_stream (qtdemux, track_id);
9298 GST_WARNING_OBJECT (qtdemux, "Stream not found, going to ignore it");
9302 /* flush samples data from this track from previous moov */
9303 gst_qtdemux_stream_flush_segments_data (qtdemux, stream);
9304 gst_qtdemux_stream_flush_samples_data (qtdemux, stream);
9306 /* need defaults for fragments */
9307 qtdemux_parse_trex (qtdemux, stream, &dummy, &dummy, &dummy);
9309 if (stream->pending_tags == NULL)
9310 stream->pending_tags = gst_tag_list_new_empty ();
9312 if ((tkhd_flags & 1) == 0)
9313 stream->disabled = TRUE;
9315 GST_LOG_OBJECT (qtdemux, "track[tkhd] version/flags/id: 0x%02x/%06x/%u",
9316 tkhd_version, tkhd_flags, stream->track_id);
9318 if (!(mdia = qtdemux_tree_get_child_by_type (trak, FOURCC_mdia)))
9321 if (!(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mdhd))) {
9322 /* be nice for some crooked mjp2 files that use mhdr for mdhd */
9323 if (qtdemux->major_brand != FOURCC_mjp2 ||
9324 !(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mhdr)))
9328 len = QT_UINT32 ((guint8 *) mdhd->data);
9329 version = QT_UINT32 ((guint8 *) mdhd->data + 8);
9330 GST_LOG_OBJECT (qtdemux, "track version/flags: %08x", version);
9331 if (version == 0x01000000) {
9334 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 28);
9335 stream->duration = QT_UINT64 ((guint8 *) mdhd->data + 32);
9336 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 36);
9340 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 20);
9341 stream->duration = QT_UINT32 ((guint8 *) mdhd->data + 24);
9342 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 28);
9345 if (lang_code < 0x400) {
9346 qtdemux_lang_map_qt_code_to_iso (stream->lang_id, lang_code);
9347 } else if (lang_code == 0x7fff) {
9348 stream->lang_id[0] = 0; /* unspecified */
9350 stream->lang_id[0] = 0x60 + ((lang_code >> 10) & 0x1F);
9351 stream->lang_id[1] = 0x60 + ((lang_code >> 5) & 0x1F);
9352 stream->lang_id[2] = 0x60 + (lang_code & 0x1F);
9353 stream->lang_id[3] = 0;
9356 GST_LOG_OBJECT (qtdemux, "track timescale: %" G_GUINT32_FORMAT,
9358 GST_LOG_OBJECT (qtdemux, "track duration: %" G_GUINT64_FORMAT,
9360 GST_LOG_OBJECT (qtdemux, "track language code/id: 0x%04x/%s",
9361 lang_code, stream->lang_id);
9363 if (G_UNLIKELY (stream->timescale == 0 || qtdemux->timescale == 0))
9366 if ((tref = qtdemux_tree_get_child_by_type (trak, FOURCC_tref))) {
9367 /* chapters track reference */
9368 GNode *chap = qtdemux_tree_get_child_by_type (tref, FOURCC_chap);
9370 gsize length = GST_READ_UINT32_BE (chap->data);
9371 if (qtdemux->chapters_track_id)
9372 GST_FIXME_OBJECT (qtdemux, "Multiple CHAP tracks");
9375 qtdemux->chapters_track_id =
9376 GST_READ_UINT32_BE ((gint8 *) chap->data + 8);
9381 /* fragmented files may have bogus duration in moov */
9382 if (!qtdemux->fragmented &&
9383 qtdemux->duration != G_MAXINT64 && stream->duration != G_MAXINT32) {
9384 guint64 tdur1, tdur2;
9386 /* don't overflow */
9387 tdur1 = stream->timescale * (guint64) qtdemux->duration;
9388 tdur2 = qtdemux->timescale * (guint64) stream->duration;
9391 * some of those trailers, nowadays, have prologue images that are
9392 * themselves video tracks as well. I haven't really found a way to
9393 * identify those yet, except for just looking at their duration. */
9394 if (tdur1 != 0 && (tdur2 * 10 / tdur1) < 2) {
9395 GST_WARNING_OBJECT (qtdemux,
9396 "Track shorter than 20%% (%" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT
9397 " vs. %" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT ") of the stream "
9398 "found, assuming preview image or something; skipping track",
9399 stream->duration, stream->timescale, qtdemux->duration,
9400 qtdemux->timescale);
9402 gst_qtdemux_stream_free (qtdemux, stream);
9407 if (!(hdlr = qtdemux_tree_get_child_by_type (mdia, FOURCC_hdlr)))
9410 GST_LOG_OBJECT (qtdemux, "track type: %" GST_FOURCC_FORMAT,
9411 GST_FOURCC_ARGS (QT_FOURCC ((guint8 *) hdlr->data + 12)));
9413 len = QT_UINT32 ((guint8 *) hdlr->data);
9415 stream->subtype = QT_FOURCC ((guint8 *) hdlr->data + 16);
9416 GST_LOG_OBJECT (qtdemux, "track subtype: %" GST_FOURCC_FORMAT,
9417 GST_FOURCC_ARGS (stream->subtype));
9419 if (!(minf = qtdemux_tree_get_child_by_type (mdia, FOURCC_minf)))
9422 if (!(stbl = qtdemux_tree_get_child_by_type (minf, FOURCC_stbl)))
9425 /*parse svmi header if existing */
9426 svmi = qtdemux_tree_get_child_by_type (stbl, FOURCC_svmi);
9428 len = QT_UINT32 ((guint8 *) svmi->data);
9429 version = QT_UINT32 ((guint8 *) svmi->data + 8);
9431 GstVideoMultiviewMode mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
9432 GstVideoMultiviewFlags flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
9433 guint8 frame_type, frame_layout;
9435 /* MPEG-A stereo video */
9436 if (qtdemux->major_brand == FOURCC_ss02)
9437 flags |= GST_VIDEO_MULTIVIEW_FLAGS_MIXED_MONO;
9439 frame_type = QT_UINT8 ((guint8 *) svmi->data + 12);
9440 frame_layout = QT_UINT8 ((guint8 *) svmi->data + 13) & 0x01;
9441 switch (frame_type) {
9443 mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
9446 mode = GST_VIDEO_MULTIVIEW_MODE_ROW_INTERLEAVED;
9449 mode = GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME;
9452 /* mode 3 is primary/secondary view sequence, ie
9453 * left/right views in separate tracks. See section 7.2
9454 * of ISO/IEC 23000-11:2009 */
9455 GST_FIXME_OBJECT (qtdemux,
9456 "Implement stereo video in separate streams");
9459 if ((frame_layout & 0x1) == 0)
9460 flags |= GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
9462 GST_LOG_OBJECT (qtdemux,
9463 "StereoVideo: composition type: %u, is_left_first: %u",
9464 frame_type, frame_layout);
9465 stream->multiview_mode = mode;
9466 stream->multiview_flags = flags;
9471 if (!(stsd = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsd)))
9473 stsd_data = (const guint8 *) stsd->data;
9475 /* stsd should at least have one entry */
9476 stsd_len = QT_UINT32 (stsd_data);
9477 if (stsd_len < 24) {
9478 /* .. but skip stream with empty stsd produced by some Vivotek cameras */
9479 if (stream->subtype == FOURCC_vivo) {
9481 gst_qtdemux_stream_free (qtdemux, stream);
9488 GST_LOG_OBJECT (qtdemux, "stsd len: %d", stsd_len);
9490 /* and that entry should fit within stsd */
9491 len = QT_UINT32 (stsd_data + 16);
9492 if (len > stsd_len + 16)
9495 stream->fourcc = fourcc = QT_FOURCC (stsd_data + 16 + 4);
9496 GST_LOG_OBJECT (qtdemux, "stsd type: %" GST_FOURCC_FORMAT,
9497 GST_FOURCC_ARGS (stream->fourcc));
9498 GST_LOG_OBJECT (qtdemux, "stsd type len: %d", len);
9500 if ((fourcc == FOURCC_drms) || (fourcc == FOURCC_drmi))
9501 goto error_encrypted;
9503 if (fourcc == FOURCC_encv || fourcc == FOURCC_enca) {
9504 GNode *enc = qtdemux_tree_get_child_by_type (stsd, fourcc);
9505 stream->protected = TRUE;
9506 if (!qtdemux_parse_protection_scheme_info (qtdemux, stream, enc, &fourcc))
9507 GST_ERROR_OBJECT (qtdemux, "Failed to parse protection scheme info");
9510 if (stream->subtype == FOURCC_vide) {
9511 guint32 w = 0, h = 0;
9513 gint depth, palette_size, palette_count;
9515 guint32 *palette_data = NULL;
9517 stream->sampled = TRUE;
9519 /* version 1 uses some 64-bit ints */
9520 if (!gst_byte_reader_skip (&tkhd, 20 + value_size))
9523 if (!qtdemux_parse_transformation_matrix (qtdemux, &tkhd, matrix, "tkhd"))
9526 if (!gst_byte_reader_get_uint32_be (&tkhd, &w)
9527 || !gst_byte_reader_get_uint32_be (&tkhd, &h))
9530 stream->display_width = w >> 16;
9531 stream->display_height = h >> 16;
9533 qtdemux_inspect_transformation_matrix (qtdemux, stream, matrix,
9534 &stream->pending_tags);
9540 stream->width = QT_UINT16 (stsd_data + offset + 32);
9541 stream->height = QT_UINT16 (stsd_data + offset + 34);
9542 stream->fps_n = 0; /* this is filled in later */
9543 stream->fps_d = 0; /* this is filled in later */
9544 stream->bits_per_sample = QT_UINT16 (stsd_data + offset + 82);
9545 stream->color_table_id = QT_UINT16 (stsd_data + offset + 84);
9547 /* if color_table_id is 0, ctab atom must follow; however some files
9548 * produced by TMPEGEnc have color_table_id = 0 and no ctab atom, so
9549 * if color table is not present we'll correct the value */
9550 if (stream->color_table_id == 0 &&
9551 (len < 90 || QT_FOURCC (stsd_data + offset + 86) != FOURCC_ctab)) {
9552 stream->color_table_id = -1;
9555 GST_LOG_OBJECT (qtdemux, "width %d, height %d, bps %d, color table id %d",
9556 stream->width, stream->height, stream->bits_per_sample,
9557 stream->color_table_id);
9559 depth = stream->bits_per_sample;
9561 /* more than 32 bits means grayscale */
9562 gray = (depth > 32);
9563 /* low 32 bits specify the depth */
9566 /* different number of palette entries is determined by depth. */
9568 if ((depth == 1) || (depth == 2) || (depth == 4) || (depth == 8))
9569 palette_count = (1 << depth);
9570 palette_size = palette_count * 4;
9572 if (stream->color_table_id) {
9573 switch (palette_count) {
9577 palette_data = g_memdup (ff_qt_default_palette_2, palette_size);
9580 palette_data = g_memdup (ff_qt_default_palette_4, palette_size);
9584 palette_data = g_memdup (ff_qt_grayscale_palette_16, palette_size);
9586 palette_data = g_memdup (ff_qt_default_palette_16, palette_size);
9590 palette_data = g_memdup (ff_qt_grayscale_palette_256, palette_size);
9592 palette_data = g_memdup (ff_qt_default_palette_256, palette_size);
9595 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
9596 (_("The video in this file might not play correctly.")),
9597 ("unsupported palette depth %d", depth));
9601 gint i, j, start, end;
9607 start = QT_UINT32 (stsd_data + offset + 86);
9608 palette_count = QT_UINT16 (stsd_data + offset + 90);
9609 end = QT_UINT16 (stsd_data + offset + 92);
9611 GST_LOG_OBJECT (qtdemux, "start %d, end %d, palette_count %d",
9612 start, end, palette_count);
9619 if (len < 94 + (end - start) * 8)
9622 /* palette is always the same size */
9623 palette_data = g_malloc0 (256 * 4);
9624 palette_size = 256 * 4;
9626 for (j = 0, i = start; i <= end; j++, i++) {
9629 a = QT_UINT16 (stsd_data + offset + 94 + (j * 8));
9630 r = QT_UINT16 (stsd_data + offset + 96 + (j * 8));
9631 g = QT_UINT16 (stsd_data + offset + 98 + (j * 8));
9632 b = QT_UINT16 (stsd_data + offset + 100 + (j * 8));
9634 palette_data[i] = ((a & 0xff00) << 16) | ((r & 0xff00) << 8) |
9635 (g & 0xff00) | (b >> 8);
9640 gst_caps_unref (stream->caps);
9643 qtdemux_video_caps (qtdemux, stream, fourcc, stsd_data, &codec);
9644 if (G_UNLIKELY (!stream->caps)) {
9645 g_free (palette_data);
9646 goto unknown_stream;
9650 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
9651 GST_TAG_VIDEO_CODEC, codec, NULL);
9660 if (stream->rgb8_palette)
9661 gst_memory_unref (stream->rgb8_palette);
9662 stream->rgb8_palette = gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY,
9663 palette_data, palette_size, 0, palette_size, palette_data, g_free);
9665 s = gst_caps_get_structure (stream->caps, 0);
9667 /* non-raw video has a palette_data property. raw video has the palette as
9668 * an extra plane that we append to the output buffers before we push
9670 if (!gst_structure_has_name (s, "video/x-raw")) {
9673 palette = gst_buffer_new ();
9674 gst_buffer_append_memory (palette, stream->rgb8_palette);
9675 stream->rgb8_palette = NULL;
9677 gst_caps_set_simple (stream->caps, "palette_data",
9678 GST_TYPE_BUFFER, palette, NULL);
9679 gst_buffer_unref (palette);
9681 } else if (palette_count != 0) {
9682 GST_ELEMENT_WARNING (qtdemux, STREAM, NOT_IMPLEMENTED,
9683 (NULL), ("Unsupported palette depth %d", depth));
9686 GST_LOG_OBJECT (qtdemux, "frame count: %u",
9687 QT_UINT16 (stsd_data + offset + 48));
9692 /* pick 'the' stsd child */
9693 if (!stream->protected)
9694 mp4v = qtdemux_tree_get_child_by_type (stsd, fourcc);
9696 mp4v = qtdemux_tree_get_child_by_type (stsd, FOURCC_encv);
9699 esds = qtdemux_tree_get_child_by_type (mp4v, FOURCC_esds);
9700 pasp = qtdemux_tree_get_child_by_type (mp4v, FOURCC_pasp);
9701 colr = qtdemux_tree_get_child_by_type (mp4v, FOURCC_colr);
9705 const guint8 *pasp_data = (const guint8 *) pasp->data;
9707 stream->par_w = QT_UINT32 (pasp_data + 8);
9708 stream->par_h = QT_UINT32 (pasp_data + 12);
9715 const guint8 *colr_data = (const guint8 *) colr->data;
9716 gint len = QT_UINT32 (colr_data);
9718 if (len == 19 || len == 18) {
9719 guint32 color_type = GST_READ_UINT32_LE (colr_data + 8);
9721 if (color_type == FOURCC_nclx || color_type == FOURCC_nclc) {
9722 guint16 primaries = GST_READ_UINT16_BE (colr_data + 12);
9723 guint16 transfer_function = GST_READ_UINT16_BE (colr_data + 14);
9724 guint16 matrix = GST_READ_UINT16_BE (colr_data + 16);
9725 gboolean full_range = len == 19 ? colr_data[17] >> 7 : FALSE;
9727 switch (primaries) {
9729 stream->colorimetry.primaries = GST_VIDEO_COLOR_PRIMARIES_BT709;
9732 stream->colorimetry.primaries = GST_VIDEO_COLOR_PRIMARIES_BT470BG;
9735 stream->colorimetry.primaries =
9736 GST_VIDEO_COLOR_PRIMARIES_SMPTE170M;
9739 stream->colorimetry.primaries = GST_VIDEO_COLOR_PRIMARIES_BT2020;
9745 switch (transfer_function) {
9747 stream->colorimetry.transfer = GST_VIDEO_TRANSFER_BT709;
9750 stream->colorimetry.transfer = GST_VIDEO_TRANSFER_SMPTE240M;
9758 stream->colorimetry.matrix = GST_VIDEO_COLOR_MATRIX_BT709;
9761 stream->colorimetry.matrix = GST_VIDEO_COLOR_MATRIX_BT601;
9764 stream->colorimetry.matrix = GST_VIDEO_COLOR_MATRIX_SMPTE240M;
9767 stream->colorimetry.matrix = GST_VIDEO_COLOR_MATRIX_BT2020;
9773 stream->colorimetry.range =
9774 full_range ? GST_VIDEO_COLOR_RANGE_0_255 :
9775 GST_VIDEO_COLOR_RANGE_16_235;
9777 GST_DEBUG_OBJECT (qtdemux, "Unsupported color type");
9780 GST_WARNING_OBJECT (qtdemux, "Invalid colr atom size");
9785 gst_qtdemux_handle_esds (qtdemux, stream, esds, stream->pending_tags);
9792 gint len = QT_UINT32 (stsd_data) - 0x66;
9793 const guint8 *avc_data = stsd_data + 0x66;
9796 while (len >= 0x8) {
9799 if (QT_UINT32 (avc_data) <= len)
9800 size = QT_UINT32 (avc_data) - 0x8;
9805 /* No real data, so break out */
9808 switch (QT_FOURCC (avc_data + 0x4)) {
9811 /* parse, if found */
9814 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
9816 /* First 4 bytes are the length of the atom, the next 4 bytes
9817 * are the fourcc, the next 1 byte is the version, and the
9818 * subsequent bytes are profile_tier_level structure like data. */
9819 gst_codec_utils_h264_caps_set_level_and_profile (stream->caps,
9820 avc_data + 8 + 1, size - 1);
9821 buf = gst_buffer_new_and_alloc (size);
9822 gst_buffer_fill (buf, 0, avc_data + 0x8, size);
9823 gst_caps_set_simple (stream->caps,
9824 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9825 gst_buffer_unref (buf);
9833 GST_DEBUG_OBJECT (qtdemux, "found strf codec_data in stsd");
9835 /* First 4 bytes are the length of the atom, the next 4 bytes
9836 * are the fourcc, next 40 bytes are BITMAPINFOHEADER,
9837 * next 1 byte is the version, and the
9838 * subsequent bytes are sequence parameter set like data. */
9840 size -= 40; /* we'll be skipping BITMAPINFOHEADER */
9842 gst_codec_utils_h264_caps_set_level_and_profile (stream->caps,
9843 avc_data + 8 + 40 + 1, size - 1);
9845 buf = gst_buffer_new_and_alloc (size);
9846 gst_buffer_fill (buf, 0, avc_data + 8 + 40, size);
9847 gst_caps_set_simple (stream->caps,
9848 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9849 gst_buffer_unref (buf);
9855 guint avg_bitrate, max_bitrate;
9857 /* bufferSizeDB, maxBitrate and avgBitrate - 4 bytes each */
9861 max_bitrate = QT_UINT32 (avc_data + 0xc);
9862 avg_bitrate = QT_UINT32 (avc_data + 0x10);
9864 if (!max_bitrate && !avg_bitrate)
9867 /* Some muxers seem to swap the average and maximum bitrates
9868 * (I'm looking at you, YouTube), so we swap for sanity. */
9869 if (max_bitrate > 0 && max_bitrate < avg_bitrate) {
9870 guint temp = avg_bitrate;
9872 avg_bitrate = max_bitrate;
9876 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
9877 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
9878 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
9880 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
9881 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
9882 GST_TAG_BITRATE, avg_bitrate, NULL);
9893 avc_data += size + 8;
9902 gint len = QT_UINT32 (stsd_data) - 0x66;
9903 const guint8 *hevc_data = stsd_data + 0x66;
9906 while (len >= 0x8) {
9909 if (QT_UINT32 (hevc_data) <= len)
9910 size = QT_UINT32 (hevc_data) - 0x8;
9915 /* No real data, so break out */
9918 switch (QT_FOURCC (hevc_data + 0x4)) {
9921 /* parse, if found */
9924 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
9926 /* First 4 bytes are the length of the atom, the next 4 bytes
9927 * are the fourcc, the next 1 byte is the version, and the
9928 * subsequent bytes are sequence parameter set like data. */
9929 gst_codec_utils_h265_caps_set_level_tier_and_profile
9930 (stream->caps, hevc_data + 8 + 1, size - 1);
9932 buf = gst_buffer_new_and_alloc (size);
9933 gst_buffer_fill (buf, 0, hevc_data + 0x8, size);
9934 gst_caps_set_simple (stream->caps,
9935 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9936 gst_buffer_unref (buf);
9943 hevc_data += size + 8;
9954 GST_DEBUG_OBJECT (qtdemux, "found %" GST_FOURCC_FORMAT,
9955 GST_FOURCC_ARGS (fourcc));
9957 /* codec data might be in glbl extension atom */
9959 qtdemux_tree_get_child_by_type (mp4v, FOURCC_glbl) : NULL;
9965 GST_DEBUG_OBJECT (qtdemux, "found glbl data in stsd");
9967 len = QT_UINT32 (data);
9970 buf = gst_buffer_new_and_alloc (len);
9971 gst_buffer_fill (buf, 0, data + 8, len);
9972 gst_caps_set_simple (stream->caps,
9973 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9974 gst_buffer_unref (buf);
9981 /* see annex I of the jpeg2000 spec */
9982 GNode *jp2h, *ihdr, *colr, *mjp2, *field, *prefix, *cmap, *cdef;
9984 const gchar *colorspace = NULL;
9986 guint32 ncomp_map = 0;
9987 gint32 *comp_map = NULL;
9988 guint32 nchan_def = 0;
9989 gint32 *chan_def = NULL;
9991 GST_DEBUG_OBJECT (qtdemux, "found mjp2");
9992 /* some required atoms */
9993 mjp2 = qtdemux_tree_get_child_by_type (stsd, FOURCC_mjp2);
9996 jp2h = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2h);
10000 /* number of components; redundant with info in codestream, but useful
10002 ihdr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_ihdr);
10003 if (!ihdr || QT_UINT32 (ihdr->data) != 22)
10005 ncomp = QT_UINT16 (((guint8 *) ihdr->data) + 16);
10007 colr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_colr);
10010 GST_DEBUG_OBJECT (qtdemux, "found colr");
10011 /* extract colour space info */
10012 if (QT_UINT8 ((guint8 *) colr->data + 8) == 1) {
10013 switch (QT_UINT32 ((guint8 *) colr->data + 11)) {
10015 colorspace = "sRGB";
10018 colorspace = "GRAY";
10021 colorspace = "sYUV";
10029 /* colr is required, and only values 16, 17, and 18 are specified,
10030 so error if we have no colorspace */
10033 /* extract component mapping */
10034 cmap = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cmap);
10036 guint32 cmap_len = 0;
10038 cmap_len = QT_UINT32 (cmap->data);
10039 if (cmap_len >= 8) {
10040 /* normal box, subtract off header */
10042 /* cmap: { u16 cmp; u8 mtyp; u8 pcol; }* */
10043 if (cmap_len % 4 == 0) {
10044 ncomp_map = (cmap_len / 4);
10045 comp_map = g_new0 (gint32, ncomp_map);
10046 for (i = 0; i < ncomp_map; i++) {
10049 cmp = QT_UINT16 (((guint8 *) cmap->data) + 8 + i * 4);
10050 mtyp = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 2);
10051 pcol = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 3);
10052 comp_map[i] = (mtyp << 24) | (pcol << 16) | cmp;
10057 /* extract channel definitions */
10058 cdef = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cdef);
10060 guint32 cdef_len = 0;
10062 cdef_len = QT_UINT32 (cdef->data);
10063 if (cdef_len >= 10) {
10064 /* normal box, subtract off header and len */
10066 /* cdef: u16 n; { u16 cn; u16 typ; u16 asoc; }* */
10067 if (cdef_len % 6 == 0) {
10068 nchan_def = (cdef_len / 6);
10069 chan_def = g_new0 (gint32, nchan_def);
10070 for (i = 0; i < nchan_def; i++)
10072 for (i = 0; i < nchan_def; i++) {
10073 guint16 cn, typ, asoc;
10074 cn = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6);
10075 typ = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 2);
10076 asoc = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 4);
10077 if (cn < nchan_def) {
10080 chan_def[cn] = asoc;
10083 chan_def[cn] = 0; /* alpha */
10086 chan_def[cn] = -typ;
10094 gst_caps_set_simple (stream->caps,
10095 "num-components", G_TYPE_INT, ncomp, NULL);
10096 gst_caps_set_simple (stream->caps,
10097 "colorspace", G_TYPE_STRING, colorspace, NULL);
10100 GValue arr = { 0, };
10101 GValue elt = { 0, };
10103 g_value_init (&arr, GST_TYPE_ARRAY);
10104 g_value_init (&elt, G_TYPE_INT);
10105 for (i = 0; i < ncomp_map; i++) {
10106 g_value_set_int (&elt, comp_map[i]);
10107 gst_value_array_append_value (&arr, &elt);
10109 gst_structure_set_value (gst_caps_get_structure (stream->caps, 0),
10110 "component-map", &arr);
10111 g_value_unset (&elt);
10112 g_value_unset (&arr);
10117 GValue arr = { 0, };
10118 GValue elt = { 0, };
10120 g_value_init (&arr, GST_TYPE_ARRAY);
10121 g_value_init (&elt, G_TYPE_INT);
10122 for (i = 0; i < nchan_def; i++) {
10123 g_value_set_int (&elt, chan_def[i]);
10124 gst_value_array_append_value (&arr, &elt);
10126 gst_structure_set_value (gst_caps_get_structure (stream->caps, 0),
10127 "channel-definitions", &arr);
10128 g_value_unset (&elt);
10129 g_value_unset (&arr);
10133 /* some optional atoms */
10134 field = qtdemux_tree_get_child_by_type (mjp2, FOURCC_fiel);
10135 prefix = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2x);
10137 /* indicate possible fields in caps */
10139 data = (guint8 *) field->data + 8;
10141 gst_caps_set_simple (stream->caps, "fields", G_TYPE_INT,
10142 (gint) * data, NULL);
10144 /* add codec_data if provided */
10149 GST_DEBUG_OBJECT (qtdemux, "found prefix data in stsd");
10150 data = prefix->data;
10151 len = QT_UINT32 (data);
10154 buf = gst_buffer_new_and_alloc (len);
10155 gst_buffer_fill (buf, 0, data + 8, len);
10156 gst_caps_set_simple (stream->caps,
10157 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10158 gst_buffer_unref (buf);
10165 /* https://developer.apple.com/standards/qtff-2001.pdf,
10166 * page 92, "Video Sample Description", under table 3.1 */
10169 const off_t compressor_offset =
10170 16 + 4 + 4 * 3 + 2 * 2 + 2 * 4 + 4 + 2;
10171 const off_t min_size = compressor_offset + 32 + 2 + 2;
10174 guint16 color_table_id = 0;
10177 GST_DEBUG_OBJECT (qtdemux, "found jpeg");
10179 /* recover information on interlaced/progressive */
10180 jpeg = qtdemux_tree_get_child_by_type (stsd, FOURCC_jpeg);
10184 len = QT_UINT32 (jpeg->data);
10185 GST_DEBUG_OBJECT (qtdemux, "Found jpeg: len %u, need %lu", len,
10187 if (len >= min_size) {
10188 gst_byte_reader_init (&br, jpeg->data, len);
10190 gst_byte_reader_skip (&br, compressor_offset + 32 + 2);
10191 gst_byte_reader_get_uint16_le (&br, &color_table_id);
10192 if (color_table_id != 0) {
10193 /* the spec says there can be concatenated chunks in the data, and we want
10194 * to find one called field. Walk through them. */
10195 off_t offset = min_size;
10196 while (offset + 8 < len) {
10197 guint32 size = 0, tag;
10198 ok = gst_byte_reader_get_uint32_le (&br, &size);
10199 ok &= gst_byte_reader_get_uint32_le (&br, &tag);
10200 if (!ok || size < 8) {
10201 GST_WARNING_OBJECT (qtdemux,
10202 "Failed to walk optional chunk list");
10205 GST_DEBUG_OBJECT (qtdemux,
10206 "Found optional %4.4s chunk, size %u", (const char *) &tag,
10208 if (tag == FOURCC_fiel) {
10209 guint8 n_fields, ordering;
10210 gst_byte_reader_get_uint8 (&br, &n_fields);
10211 gst_byte_reader_get_uint8 (&br, &ordering);
10212 if (n_fields == 1 || n_fields == 2) {
10213 GST_DEBUG_OBJECT (qtdemux,
10214 "Found fiel tag with %u fields, ordering %u", n_fields,
10217 gst_caps_set_simple (stream->caps, "interlace-mode",
10218 G_TYPE_STRING, "interleaved", NULL);
10220 GST_WARNING_OBJECT (qtdemux,
10221 "Found fiel tag with invalid fields (%u)", n_fields);
10227 GST_DEBUG_OBJECT (qtdemux,
10228 "Color table ID is 0, not trying to get interlacedness");
10231 GST_WARNING_OBJECT (qtdemux,
10232 "Length of jpeg chunk is too small, not trying to get interlacedness");
10241 GstBuffer *seqh = NULL;
10242 guint8 *gamma_data = NULL;
10243 gint len = QT_UINT32 (stsd_data);
10245 qtdemux_parse_svq3_stsd_data (qtdemux, stsd, &gamma_data, &seqh);
10247 gst_caps_set_simple (stream->caps, "applied-gamma", G_TYPE_DOUBLE,
10248 QT_FP32 (gamma_data), NULL);
10251 /* sorry for the bad name, but we don't know what this is, other
10252 * than its own fourcc */
10253 gst_caps_set_simple (stream->caps, "seqh", GST_TYPE_BUFFER, seqh,
10257 GST_DEBUG_OBJECT (qtdemux, "found codec_data in stsd");
10258 buf = gst_buffer_new_and_alloc (len);
10259 gst_buffer_fill (buf, 0, stsd_data, len);
10260 gst_caps_set_simple (stream->caps,
10261 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10262 gst_buffer_unref (buf);
10268 gst_caps_set_simple (stream->caps,
10269 "depth", G_TYPE_INT, QT_UINT16 (stsd_data + offset + 82), NULL);
10274 GNode *xith, *xdxt;
10276 GST_DEBUG_OBJECT (qtdemux, "found XiTh");
10277 xith = qtdemux_tree_get_child_by_type (stsd, FOURCC_XiTh);
10281 xdxt = qtdemux_tree_get_child_by_type (xith, FOURCC_XdxT);
10285 GST_DEBUG_OBJECT (qtdemux, "found XdxT node");
10286 /* collect the headers and store them in a stream list so that we can
10287 * send them out first */
10288 qtdemux_parse_theora_extension (qtdemux, stream, xdxt);
10298 GST_DEBUG_OBJECT (qtdemux, "parse ovc1 header");
10299 ovc1 = qtdemux_tree_get_child_by_type (stsd, FOURCC_ovc1);
10302 ovc1_data = ovc1->data;
10303 ovc1_len = QT_UINT32 (ovc1_data);
10304 if (ovc1_len <= 198) {
10305 GST_WARNING_OBJECT (qtdemux, "Too small ovc1 header, skipping");
10308 buf = gst_buffer_new_and_alloc (ovc1_len - 198);
10309 gst_buffer_fill (buf, 0, ovc1_data + 198, ovc1_len - 198);
10310 gst_caps_set_simple (stream->caps,
10311 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10312 gst_buffer_unref (buf);
10317 gint len = QT_UINT32 (stsd_data) - 0x66;
10318 const guint8 *vc1_data = stsd_data + 0x66;
10324 if (QT_UINT32 (vc1_data) <= len)
10325 size = QT_UINT32 (vc1_data) - 8;
10330 /* No real data, so break out */
10333 switch (QT_FOURCC (vc1_data + 0x4)) {
10334 case GST_MAKE_FOURCC ('d', 'v', 'c', '1'):
10338 GST_DEBUG_OBJECT (qtdemux, "found dvc1 codec_data in stsd");
10339 buf = gst_buffer_new_and_alloc (size);
10340 gst_buffer_fill (buf, 0, vc1_data + 8, size);
10341 gst_caps_set_simple (stream->caps,
10342 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10343 gst_buffer_unref (buf);
10350 vc1_data += size + 8;
10359 GST_INFO_OBJECT (qtdemux,
10360 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
10361 GST_FOURCC_ARGS (fourcc), stream->caps);
10363 } else if (stream->subtype == FOURCC_soun) {
10364 int version, samplesize;
10365 guint16 compression_id;
10366 gboolean amrwb = FALSE;
10369 /* sample description entry (16) + sound sample description v0 (20) */
10373 version = QT_UINT32 (stsd_data + offset);
10374 stream->n_channels = QT_UINT16 (stsd_data + offset + 8);
10375 samplesize = QT_UINT16 (stsd_data + offset + 10);
10376 compression_id = QT_UINT16 (stsd_data + offset + 12);
10377 stream->rate = QT_FP32 (stsd_data + offset + 16);
10379 GST_LOG_OBJECT (qtdemux, "version/rev: %08x", version);
10380 GST_LOG_OBJECT (qtdemux, "vendor: %08x",
10381 QT_UINT32 (stsd_data + offset + 4));
10382 GST_LOG_OBJECT (qtdemux, "n_channels: %d", stream->n_channels);
10383 GST_LOG_OBJECT (qtdemux, "sample_size: %d", samplesize);
10384 GST_LOG_OBJECT (qtdemux, "compression_id: %d", compression_id);
10385 GST_LOG_OBJECT (qtdemux, "packet size: %d",
10386 QT_UINT16 (stsd_data + offset + 14));
10387 GST_LOG_OBJECT (qtdemux, "sample rate: %g", stream->rate);
10389 if (compression_id == 0xfffe)
10390 stream->sampled = TRUE;
10392 /* first assume uncompressed audio */
10393 stream->bytes_per_sample = samplesize / 8;
10394 stream->samples_per_frame = stream->n_channels;
10395 stream->bytes_per_frame = stream->n_channels * stream->bytes_per_sample;
10396 stream->samples_per_packet = stream->samples_per_frame;
10397 stream->bytes_per_packet = stream->bytes_per_sample;
10401 /* Yes, these have to be hard-coded */
10404 stream->samples_per_packet = 6;
10405 stream->bytes_per_packet = 1;
10406 stream->bytes_per_frame = 1 * stream->n_channels;
10407 stream->bytes_per_sample = 1;
10408 stream->samples_per_frame = 6 * stream->n_channels;
10413 stream->samples_per_packet = 3;
10414 stream->bytes_per_packet = 1;
10415 stream->bytes_per_frame = 1 * stream->n_channels;
10416 stream->bytes_per_sample = 1;
10417 stream->samples_per_frame = 3 * stream->n_channels;
10422 stream->samples_per_packet = 64;
10423 stream->bytes_per_packet = 34;
10424 stream->bytes_per_frame = 34 * stream->n_channels;
10425 stream->bytes_per_sample = 2;
10426 stream->samples_per_frame = 64 * stream->n_channels;
10432 stream->samples_per_packet = 1;
10433 stream->bytes_per_packet = 1;
10434 stream->bytes_per_frame = 1 * stream->n_channels;
10435 stream->bytes_per_sample = 1;
10436 stream->samples_per_frame = 1 * stream->n_channels;
10441 stream->samples_per_packet = 160;
10442 stream->bytes_per_packet = 33;
10443 stream->bytes_per_frame = 33 * stream->n_channels;
10444 stream->bytes_per_sample = 2;
10445 stream->samples_per_frame = 160 * stream->n_channels;
10452 if (version == 0x00010000) {
10453 /* sample description entry (16) + sound sample description v1 (20+16) */
10464 /* only parse extra decoding config for non-pcm audio */
10465 stream->samples_per_packet = QT_UINT32 (stsd_data + offset);
10466 stream->bytes_per_packet = QT_UINT32 (stsd_data + offset + 4);
10467 stream->bytes_per_frame = QT_UINT32 (stsd_data + offset + 8);
10468 stream->bytes_per_sample = QT_UINT32 (stsd_data + offset + 12);
10470 GST_LOG_OBJECT (qtdemux, "samples/packet: %d",
10471 stream->samples_per_packet);
10472 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
10473 stream->bytes_per_packet);
10474 GST_LOG_OBJECT (qtdemux, "bytes/frame: %d",
10475 stream->bytes_per_frame);
10476 GST_LOG_OBJECT (qtdemux, "bytes/sample: %d",
10477 stream->bytes_per_sample);
10479 if (!stream->sampled && stream->bytes_per_packet) {
10480 stream->samples_per_frame = (stream->bytes_per_frame /
10481 stream->bytes_per_packet) * stream->samples_per_packet;
10482 GST_LOG_OBJECT (qtdemux, "samples/frame: %d",
10483 stream->samples_per_frame);
10488 } else if (version == 0x00020000) {
10495 /* sample description entry (16) + sound sample description v2 (56) */
10499 qtfp.val = QT_UINT64 (stsd_data + offset + 4);
10500 stream->rate = qtfp.fp;
10501 stream->n_channels = QT_UINT32 (stsd_data + offset + 12);
10503 GST_LOG_OBJECT (qtdemux, "Sound sample description Version 2");
10504 GST_LOG_OBJECT (qtdemux, "sample rate: %g", stream->rate);
10505 GST_LOG_OBJECT (qtdemux, "n_channels: %d", stream->n_channels);
10506 GST_LOG_OBJECT (qtdemux, "bits/channel: %d",
10507 QT_UINT32 (stsd_data + offset + 20));
10508 GST_LOG_OBJECT (qtdemux, "format flags: %X",
10509 QT_UINT32 (stsd_data + offset + 24));
10510 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
10511 QT_UINT32 (stsd_data + offset + 28));
10512 GST_LOG_OBJECT (qtdemux, "LPCM frames/packet: %d",
10513 QT_UINT32 (stsd_data + offset + 32));
10514 } else if (version != 0x00000) {
10515 GST_WARNING_OBJECT (qtdemux, "unknown audio STSD version %08x", version);
10519 gst_caps_unref (stream->caps);
10521 stream->caps = qtdemux_audio_caps (qtdemux, stream, fourcc,
10522 stsd_data + 32, len - 16, &codec);
10530 in24 = qtdemux_tree_get_child_by_type (stsd, FOURCC_in24);
10532 enda = qtdemux_tree_get_child_by_type (in24, FOURCC_enda);
10534 wave = qtdemux_tree_get_child_by_type (in24, FOURCC_wave);
10536 enda = qtdemux_tree_get_child_by_type (wave, FOURCC_enda);
10539 int enda_value = QT_UINT16 ((guint8 *) enda->data + 8);
10540 gst_caps_set_simple (stream->caps,
10541 "format", G_TYPE_STRING, (enda_value) ? "S24LE" : "S24BE", NULL);
10548 const guint8 *owma_data;
10549 const gchar *codec_name = NULL;
10553 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
10554 /* FIXME this should also be gst_riff_strf_auds,
10555 * but the latter one is actually missing bits-per-sample :( */
10560 gint32 nSamplesPerSec;
10561 gint32 nAvgBytesPerSec;
10562 gint16 nBlockAlign;
10563 gint16 wBitsPerSample;
10566 WAVEFORMATEX *wfex;
10568 GST_DEBUG_OBJECT (qtdemux, "parse owma");
10569 owma = qtdemux_tree_get_child_by_type (stsd, FOURCC_owma);
10572 owma_data = owma->data;
10573 owma_len = QT_UINT32 (owma_data);
10574 if (owma_len <= 54) {
10575 GST_WARNING_OBJECT (qtdemux, "Too small owma header, skipping");
10578 wfex = (WAVEFORMATEX *) (owma_data + 36);
10579 buf = gst_buffer_new_and_alloc (owma_len - 54);
10580 gst_buffer_fill (buf, 0, owma_data + 54, owma_len - 54);
10581 if (wfex->wFormatTag == 0x0161) {
10582 codec_name = "Windows Media Audio";
10584 } else if (wfex->wFormatTag == 0x0162) {
10585 codec_name = "Windows Media Audio 9 Pro";
10587 } else if (wfex->wFormatTag == 0x0163) {
10588 codec_name = "Windows Media Audio 9 Lossless";
10589 /* is that correct? gstffmpegcodecmap.c is missing it, but
10590 * fluendo codec seems to support it */
10594 gst_caps_set_simple (stream->caps,
10595 "codec_data", GST_TYPE_BUFFER, buf,
10596 "wmaversion", G_TYPE_INT, version,
10597 "block_align", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->nBlockAlign),
10598 "bitrate", G_TYPE_INT, GST_READ_UINT32_LE (&wfex->nAvgBytesPerSec),
10599 "width", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->wBitsPerSample),
10600 "depth", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->wBitsPerSample),
10602 gst_buffer_unref (buf);
10606 codec = g_strdup (codec_name);
10612 gint len = QT_UINT32 (stsd_data) - offset;
10613 const guint8 *wfex_data = stsd_data + offset;
10614 const gchar *codec_name = NULL;
10616 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
10617 /* FIXME this should also be gst_riff_strf_auds,
10618 * but the latter one is actually missing bits-per-sample :( */
10623 gint32 nSamplesPerSec;
10624 gint32 nAvgBytesPerSec;
10625 gint16 nBlockAlign;
10626 gint16 wBitsPerSample;
10631 /* FIXME: unify with similar wavformatex parsing code above */
10632 GST_DEBUG_OBJECT (qtdemux, "parse wma, looking for wfex");
10638 if (QT_UINT32 (wfex_data) <= len)
10639 size = QT_UINT32 (wfex_data) - 8;
10644 /* No real data, so break out */
10647 switch (QT_FOURCC (wfex_data + 4)) {
10648 case GST_MAKE_FOURCC ('w', 'f', 'e', 'x'):
10650 GST_DEBUG_OBJECT (qtdemux, "found wfex in stsd");
10655 wfex.wFormatTag = GST_READ_UINT16_LE (wfex_data + 8 + 0);
10656 wfex.nChannels = GST_READ_UINT16_LE (wfex_data + 8 + 2);
10657 wfex.nSamplesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 4);
10658 wfex.nAvgBytesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 8);
10659 wfex.nBlockAlign = GST_READ_UINT16_LE (wfex_data + 8 + 12);
10660 wfex.wBitsPerSample = GST_READ_UINT16_LE (wfex_data + 8 + 14);
10661 wfex.cbSize = GST_READ_UINT16_LE (wfex_data + 8 + 16);
10663 GST_LOG_OBJECT (qtdemux, "Found wfex box in stsd:");
10664 GST_LOG_OBJECT (qtdemux, "FormatTag = 0x%04x, Channels = %u, "
10665 "SamplesPerSec = %u, AvgBytesPerSec = %u, BlockAlign = %u, "
10666 "BitsPerSample = %u, Size = %u", wfex.wFormatTag,
10667 wfex.nChannels, wfex.nSamplesPerSec, wfex.nAvgBytesPerSec,
10668 wfex.nBlockAlign, wfex.wBitsPerSample, wfex.cbSize);
10670 if (wfex.wFormatTag == 0x0161) {
10671 codec_name = "Windows Media Audio";
10673 } else if (wfex.wFormatTag == 0x0162) {
10674 codec_name = "Windows Media Audio 9 Pro";
10676 } else if (wfex.wFormatTag == 0x0163) {
10677 codec_name = "Windows Media Audio 9 Lossless";
10678 /* is that correct? gstffmpegcodecmap.c is missing it, but
10679 * fluendo codec seems to support it */
10683 gst_caps_set_simple (stream->caps,
10684 "wmaversion", G_TYPE_INT, version,
10685 "block_align", G_TYPE_INT, wfex.nBlockAlign,
10686 "bitrate", G_TYPE_INT, wfex.nAvgBytesPerSec,
10687 "width", G_TYPE_INT, wfex.wBitsPerSample,
10688 "depth", G_TYPE_INT, wfex.wBitsPerSample, NULL);
10690 if (size > wfex.cbSize) {
10693 buf = gst_buffer_new_and_alloc (size - wfex.cbSize);
10694 gst_buffer_fill (buf, 0, wfex_data + 8 + wfex.cbSize,
10695 size - wfex.cbSize);
10696 gst_caps_set_simple (stream->caps,
10697 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10698 gst_buffer_unref (buf);
10700 GST_WARNING_OBJECT (qtdemux, "no codec data");
10705 codec = g_strdup (codec_name);
10713 wfex_data += size + 8;
10720 const guint8 *opus_data;
10721 guint8 *channel_mapping = NULL;
10724 guint8 channel_mapping_family;
10725 guint8 stream_count;
10726 guint8 coupled_count;
10729 opus = qtdemux_tree_get_child_by_type (stsd, FOURCC_opus);
10730 opus_data = opus->data;
10732 channels = GST_READ_UINT8 (opus_data + 45);
10733 rate = GST_READ_UINT32_LE (opus_data + 48);
10734 channel_mapping_family = GST_READ_UINT8 (opus_data + 54);
10735 stream_count = GST_READ_UINT8 (opus_data + 55);
10736 coupled_count = GST_READ_UINT8 (opus_data + 56);
10738 if (channels > 0) {
10739 channel_mapping = g_malloc (channels * sizeof (guint8));
10740 for (i = 0; i < channels; i++)
10741 channel_mapping[i] = GST_READ_UINT8 (opus_data + i + 57);
10744 stream->caps = gst_codec_utils_opus_create_caps (rate, channels,
10745 channel_mapping_family, stream_count, coupled_count,
10757 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
10758 GST_TAG_AUDIO_CODEC, codec, NULL);
10762 /* some bitrate info may have ended up in caps */
10763 s = gst_caps_get_structure (stream->caps, 0);
10764 gst_structure_get_int (s, "bitrate", &bitrate);
10766 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
10767 GST_TAG_BITRATE, bitrate, NULL);
10770 if (stream->protected && fourcc == FOURCC_mp4a)
10771 mp4a = qtdemux_tree_get_child_by_type (stsd, FOURCC_enca);
10773 mp4a = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4a);
10778 wave = qtdemux_tree_get_child_by_type (mp4a, FOURCC_wave);
10780 esds = qtdemux_tree_get_child_by_type (wave, FOURCC_esds);
10782 esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
10786 /* If the fourcc's bottom 16 bits gives 'sm', then the top
10787 16 bits is a byte-swapped wave-style codec identifier,
10788 and we can find a WAVE header internally to a 'wave' atom here.
10789 This can more clearly be thought of as 'ms' as the top 16 bits, and a
10790 codec id as the bottom 16 bits - but byte-swapped to store in QT (which
10793 if ((fourcc & 0xffff) == (('s' << 8) | 'm')) {
10794 if (len < offset + 20) {
10795 GST_WARNING_OBJECT (qtdemux, "No wave atom in MS-style audio");
10797 guint32 datalen = QT_UINT32 (stsd_data + offset + 16);
10798 const guint8 *data = stsd_data + offset + 16;
10800 GNode *waveheadernode;
10802 wavenode = g_node_new ((guint8 *) data);
10803 if (qtdemux_parse_node (qtdemux, wavenode, data, datalen)) {
10804 const guint8 *waveheader;
10807 waveheadernode = qtdemux_tree_get_child_by_type (wavenode, fourcc);
10808 if (waveheadernode) {
10809 waveheader = (const guint8 *) waveheadernode->data;
10810 headerlen = QT_UINT32 (waveheader);
10812 if (headerlen > 8) {
10813 gst_riff_strf_auds *header = NULL;
10814 GstBuffer *headerbuf;
10820 headerbuf = gst_buffer_new_and_alloc (headerlen);
10821 gst_buffer_fill (headerbuf, 0, waveheader, headerlen);
10823 if (gst_riff_parse_strf_auds (GST_ELEMENT_CAST (qtdemux),
10824 headerbuf, &header, &extra)) {
10825 gst_caps_unref (stream->caps);
10826 /* FIXME: Need to do something with the channel reorder map */
10827 stream->caps = gst_riff_create_audio_caps (header->format, NULL,
10828 header, extra, NULL, NULL, NULL);
10831 gst_buffer_unref (extra);
10836 GST_DEBUG ("Didn't find waveheadernode for this codec");
10838 g_node_destroy (wavenode);
10841 gst_qtdemux_handle_esds (qtdemux, stream, esds, stream->pending_tags);
10845 /* FIXME: what is in the chunk? */
10848 gint len = QT_UINT32 (stsd_data);
10850 /* seems to be always = 116 = 0x74 */
10856 gint len = QT_UINT32 (stsd_data);
10859 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x4C);
10861 gst_buffer_fill (buf, 0, stsd_data + 0x4C, len - 0x4C);
10862 gst_caps_set_simple (stream->caps,
10863 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10864 gst_buffer_unref (buf);
10866 gst_caps_set_simple (stream->caps,
10867 "samplesize", G_TYPE_INT, samplesize, NULL);
10872 GNode *alac, *wave = NULL;
10874 /* apparently, m4a has this atom appended directly in the stsd entry,
10875 * while mov has it in a wave atom */
10876 alac = qtdemux_tree_get_child_by_type (stsd, FOURCC_alac);
10878 /* alac now refers to stsd entry atom */
10879 wave = qtdemux_tree_get_child_by_type (alac, FOURCC_wave);
10881 alac = qtdemux_tree_get_child_by_type (wave, FOURCC_alac);
10883 alac = qtdemux_tree_get_child_by_type (alac, FOURCC_alac);
10886 const guint8 *alac_data = alac->data;
10887 gint len = QT_UINT32 (alac->data);
10891 GST_DEBUG_OBJECT (qtdemux,
10892 "discarding alac atom with unexpected len %d", len);
10894 /* codec-data contains alac atom size and prefix,
10895 * ffmpeg likes it that way, not quite gst-ish though ...*/
10896 buf = gst_buffer_new_and_alloc (len);
10897 gst_buffer_fill (buf, 0, alac->data, len);
10898 gst_caps_set_simple (stream->caps,
10899 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10900 gst_buffer_unref (buf);
10902 stream->bytes_per_frame = QT_UINT32 (alac_data + 12);
10903 stream->n_channels = QT_UINT8 (alac_data + 21);
10904 stream->rate = QT_UINT32 (alac_data + 32);
10907 gst_caps_set_simple (stream->caps,
10908 "samplesize", G_TYPE_INT, samplesize, NULL);
10913 /* The codingname of the sample entry is 'fLaC' */
10914 GNode *flac = qtdemux_tree_get_child_by_type (stsd, FOURCC_fLaC);
10917 /* The 'dfLa' box is added to the sample entry to convey
10918 initializing information for the decoder. */
10919 const GNode *dfla =
10920 qtdemux_tree_get_child_by_type (flac, FOURCC_dfLa);
10923 const guint32 len = QT_UINT32 (dfla->data);
10925 /* Must contain at least dfLa box header (12),
10926 * METADATA_BLOCK_HEADER (4), METADATA_BLOCK_STREAMINFO (34) */
10928 GST_DEBUG_OBJECT (qtdemux,
10929 "discarding dfla atom with unexpected len %d", len);
10931 /* skip dfLa header to get the METADATA_BLOCKs */
10932 const guint8 *metadata_blocks = (guint8 *) dfla->data + 12;
10933 const guint32 metadata_blocks_len = len - 12;
10935 gchar *stream_marker = g_strdup ("fLaC");
10936 GstBuffer *block = gst_buffer_new_wrapped (stream_marker,
10937 strlen (stream_marker));
10940 gboolean is_last = FALSE;
10942 GValue array = G_VALUE_INIT;
10943 GValue value = G_VALUE_INIT;
10945 g_value_init (&array, GST_TYPE_ARRAY);
10946 g_value_init (&value, GST_TYPE_BUFFER);
10948 gst_value_set_buffer (&value, block);
10949 gst_value_array_append_value (&array, &value);
10950 g_value_reset (&value);
10952 gst_buffer_unref (block);
10954 while (is_last == FALSE && index < metadata_blocks_len) {
10955 /* add the METADATA_BLOCK_HEADER size to the signalled size */
10956 const guint block_size = 4 +
10957 (metadata_blocks[index + 1] << 16) +
10958 (metadata_blocks[index + 2] << 8) +
10959 metadata_blocks[index + 3];
10961 is_last = metadata_blocks[index] >> 7;
10963 block = gst_buffer_new_and_alloc (block_size);
10965 gst_buffer_fill (block, 0, &metadata_blocks[index],
10968 gst_value_set_buffer (&value, block);
10969 gst_value_array_append_value (&array, &value);
10970 g_value_reset (&value);
10972 gst_buffer_unref (block);
10974 index += block_size;
10977 gst_structure_set_value (gst_caps_get_structure (stream->caps,
10978 0), "streamheader", &array);
10980 g_value_unset (&value);
10981 g_value_unset (&array);
10983 /* The sample rate obtained from the stsd may not be accurate
10984 * since it cannot represent rates greater than 65535Hz, so
10985 * override that value with the sample rate from the
10986 * METADATA_BLOCK_STREAMINFO block */
10988 (QT_UINT32 (metadata_blocks + 14) >> 12) & 0xFFFFF;
10999 gint len = QT_UINT32 (stsd_data);
11002 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x34);
11005 gst_buffer_fill (buf, 0, stsd_data + 0x34, len - 0x34);
11007 /* If we have enough data, let's try to get the 'damr' atom. See
11008 * the 3GPP container spec (26.244) for more details. */
11009 if ((len - 0x34) > 8 &&
11010 (bitrate = qtdemux_parse_amr_bitrate (buf, amrwb))) {
11011 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
11012 GST_TAG_MAXIMUM_BITRATE, bitrate, NULL);
11015 gst_caps_set_simple (stream->caps,
11016 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11017 gst_buffer_unref (buf);
11023 /* mp4a atom withtout ESDS; Attempt to build codec data from atom */
11024 gint len = QT_UINT32 (stsd_data);
11027 guint16 sound_version = QT_UINT16 (stsd_data + 32);
11029 if (sound_version == 1) {
11030 guint16 channels = QT_UINT16 (stsd_data + 40);
11031 guint32 time_scale = QT_UINT32 (stsd_data + 46);
11032 guint8 codec_data[2];
11034 gint profile = 2; /* FIXME: Can this be determined somehow? There doesn't seem to be anything in mp4a atom that specifis compression */
11036 gint sample_rate_index =
11037 gst_codec_utils_aac_get_index_from_sample_rate (time_scale);
11039 /* build AAC codec data */
11040 codec_data[0] = profile << 3;
11041 codec_data[0] |= ((sample_rate_index >> 1) & 0x7);
11042 codec_data[1] = (sample_rate_index & 0x01) << 7;
11043 codec_data[1] |= (channels & 0xF) << 3;
11045 buf = gst_buffer_new_and_alloc (2);
11046 gst_buffer_fill (buf, 0, codec_data, 2);
11047 gst_caps_set_simple (stream->caps,
11048 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11049 gst_buffer_unref (buf);
11055 GST_INFO_OBJECT (qtdemux,
11056 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
11060 GST_INFO_OBJECT (qtdemux,
11061 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
11062 GST_FOURCC_ARGS (fourcc), stream->caps);
11064 } else if (stream->subtype == FOURCC_strm) {
11065 if (fourcc == FOURCC_rtsp) {
11066 stream->redirect_uri = qtdemux_get_rtsp_uri_from_hndl (qtdemux, minf);
11068 GST_INFO_OBJECT (qtdemux, "unhandled stream type %" GST_FOURCC_FORMAT,
11069 GST_FOURCC_ARGS (fourcc));
11070 goto unknown_stream;
11072 stream->sampled = TRUE;
11073 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
11074 || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt) {
11076 stream->sampled = TRUE;
11077 stream->sparse = TRUE;
11080 qtdemux_sub_caps (qtdemux, stream, fourcc, stsd_data, &codec);
11082 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
11083 GST_TAG_SUBTITLE_CODEC, codec, NULL);
11088 /* hunt for sort-of codec data */
11092 GNode *mp4s = NULL;
11093 GNode *esds = NULL;
11095 /* look for palette in a stsd->mp4s->esds sub-atom */
11096 mp4s = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4s);
11098 esds = qtdemux_tree_get_child_by_type (mp4s, FOURCC_esds);
11099 if (esds == NULL) {
11101 GST_LOG_OBJECT (qtdemux, "Skipping invalid stsd: no esds child");
11105 gst_qtdemux_handle_esds (qtdemux, stream, esds, stream->pending_tags);
11109 GST_INFO_OBJECT (qtdemux,
11110 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
11113 GST_INFO_OBJECT (qtdemux,
11114 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
11115 GST_FOURCC_ARGS (fourcc), stream->caps);
11117 /* everything in 1 sample */
11118 stream->sampled = TRUE;
11121 qtdemux_generic_caps (qtdemux, stream, fourcc, stsd_data, &codec);
11123 if (stream->caps == NULL)
11124 goto unknown_stream;
11127 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
11128 GST_TAG_SUBTITLE_CODEC, codec, NULL);
11134 /* promote to sampled format */
11135 if (stream->fourcc == FOURCC_samr) {
11136 /* force mono 8000 Hz for AMR */
11137 stream->sampled = TRUE;
11138 stream->n_channels = 1;
11139 stream->rate = 8000;
11140 } else if (stream->fourcc == FOURCC_sawb) {
11141 /* force mono 16000 Hz for AMR-WB */
11142 stream->sampled = TRUE;
11143 stream->n_channels = 1;
11144 stream->rate = 16000;
11145 } else if (stream->fourcc == FOURCC_mp4a) {
11146 stream->sampled = TRUE;
11149 /* collect sample information */
11150 if (!qtdemux_stbl_init (qtdemux, stream, stbl))
11151 goto samples_failed;
11153 if (qtdemux->fragmented) {
11156 /* need all moov samples as basis; probably not many if any at all */
11157 /* prevent moof parsing taking of at this time */
11158 offset = qtdemux->moof_offset;
11159 qtdemux->moof_offset = 0;
11160 if (stream->n_samples &&
11161 !qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
11162 qtdemux->moof_offset = offset;
11163 goto samples_failed;
11165 qtdemux->moof_offset = 0;
11166 /* movie duration more reliable in this case (e.g. mehd) */
11167 if (qtdemux->segment.duration &&
11168 GST_CLOCK_TIME_IS_VALID (qtdemux->segment.duration))
11170 GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->segment.duration);
11173 /* configure segments */
11174 if (!qtdemux_parse_segments (qtdemux, stream, trak))
11175 goto segments_failed;
11177 /* add some language tag, if useful */
11178 if (stream->lang_id[0] != '\0' && strcmp (stream->lang_id, "unk") &&
11179 strcmp (stream->lang_id, "und")) {
11180 const gchar *lang_code;
11182 /* convert ISO 639-2 code to ISO 639-1 */
11183 lang_code = gst_tag_get_language_code (stream->lang_id);
11184 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
11185 GST_TAG_LANGUAGE_CODE, (lang_code) ? lang_code : stream->lang_id, NULL);
11188 /* Check for UDTA tags */
11189 if ((udta = qtdemux_tree_get_child_by_type (trak, FOURCC_udta))) {
11190 qtdemux_parse_udta (qtdemux, stream->pending_tags, udta);
11193 /* now we are ready to add the stream */
11194 if (qtdemux->n_streams >= GST_QTDEMUX_MAX_STREAMS)
11195 goto too_many_streams;
11197 if (!qtdemux->got_moov) {
11198 qtdemux->streams[qtdemux->n_streams] = stream;
11199 qtdemux->n_streams++;
11200 GST_DEBUG_OBJECT (qtdemux, "n_streams is now %d", qtdemux->n_streams);
11208 GST_INFO_OBJECT (qtdemux, "skip disabled track");
11210 gst_qtdemux_stream_free (qtdemux, stream);
11215 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
11216 (_("This file is corrupt and cannot be played.")), (NULL));
11218 gst_qtdemux_stream_free (qtdemux, stream);
11223 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT, (NULL), (NULL));
11225 gst_qtdemux_stream_free (qtdemux, stream);
11231 /* we posted an error already */
11232 /* free stbl sub-atoms */
11233 gst_qtdemux_stbl_free (stream);
11235 gst_qtdemux_stream_free (qtdemux, stream);
11240 GST_INFO_OBJECT (qtdemux, "stream with track id %i already exists",
11243 gst_qtdemux_stream_free (qtdemux, stream);
11248 GST_INFO_OBJECT (qtdemux, "unknown subtype %" GST_FOURCC_FORMAT,
11249 GST_FOURCC_ARGS (stream->subtype));
11251 gst_qtdemux_stream_free (qtdemux, stream);
11256 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
11257 (_("This file contains too many streams. Only playing first %d"),
11258 GST_QTDEMUX_MAX_STREAMS), (NULL));
11263 /* If we can estimate the overall bitrate, and don't have information about the
11264 * stream bitrate for exactly one stream, this guesses the stream bitrate as
11265 * the overall bitrate minus the sum of the bitrates of all other streams. This
11266 * should be useful for the common case where we have one audio and one video
11267 * stream and can estimate the bitrate of one, but not the other. */
11269 gst_qtdemux_guess_bitrate (GstQTDemux * qtdemux)
11271 QtDemuxStream *stream = NULL;
11272 gint64 size, sys_bitrate, sum_bitrate = 0;
11273 GstClockTime duration;
11277 if (qtdemux->fragmented)
11280 GST_DEBUG_OBJECT (qtdemux, "Looking for streams with unknown bitrate");
11282 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &size)
11284 GST_DEBUG_OBJECT (qtdemux,
11285 "Size in bytes of the stream not known - bailing");
11289 /* Subtract the header size */
11290 GST_DEBUG_OBJECT (qtdemux, "Total size %" G_GINT64_FORMAT ", header size %u",
11291 size, qtdemux->header_size);
11293 if (size < qtdemux->header_size)
11296 size = size - qtdemux->header_size;
11298 if (!gst_qtdemux_get_duration (qtdemux, &duration)) {
11299 GST_DEBUG_OBJECT (qtdemux, "Stream duration not known - bailing");
11303 for (i = 0; i < qtdemux->n_streams; i++) {
11304 switch (qtdemux->streams[i]->subtype) {
11307 GST_DEBUG_OBJECT (qtdemux, "checking bitrate for %" GST_PTR_FORMAT,
11308 qtdemux->streams[i]->caps);
11309 /* retrieve bitrate, prefer avg then max */
11311 if (qtdemux->streams[i]->pending_tags) {
11312 gst_tag_list_get_uint (qtdemux->streams[i]->pending_tags,
11313 GST_TAG_MAXIMUM_BITRATE, &bitrate);
11314 GST_DEBUG_OBJECT (qtdemux, "max-bitrate: %u", bitrate);
11315 gst_tag_list_get_uint (qtdemux->streams[i]->pending_tags,
11316 GST_TAG_NOMINAL_BITRATE, &bitrate);
11317 GST_DEBUG_OBJECT (qtdemux, "nominal-bitrate: %u", bitrate);
11318 gst_tag_list_get_uint (qtdemux->streams[i]->pending_tags,
11319 GST_TAG_BITRATE, &bitrate);
11320 GST_DEBUG_OBJECT (qtdemux, "bitrate: %u", bitrate);
11323 sum_bitrate += bitrate;
11326 GST_DEBUG_OBJECT (qtdemux,
11327 ">1 stream with unknown bitrate - bailing");
11330 stream = qtdemux->streams[i];
11334 /* For other subtypes, we assume no significant impact on bitrate */
11340 GST_DEBUG_OBJECT (qtdemux, "All stream bitrates are known");
11344 sys_bitrate = gst_util_uint64_scale (size, GST_SECOND * 8, duration);
11346 if (sys_bitrate < sum_bitrate) {
11347 /* This can happen, since sum_bitrate might be derived from maximum
11348 * bitrates and not average bitrates */
11349 GST_DEBUG_OBJECT (qtdemux,
11350 "System bitrate less than sum bitrate - bailing");
11354 bitrate = sys_bitrate - sum_bitrate;
11355 GST_DEBUG_OBJECT (qtdemux, "System bitrate = %" G_GINT64_FORMAT
11356 ", Stream bitrate = %u", sys_bitrate, bitrate);
11358 if (!stream->pending_tags)
11359 stream->pending_tags = gst_tag_list_new_empty ();
11361 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
11362 GST_TAG_BITRATE, bitrate, NULL);
11365 static GstFlowReturn
11366 qtdemux_prepare_streams (GstQTDemux * qtdemux)
11369 GstFlowReturn ret = GST_FLOW_OK;
11371 GST_DEBUG_OBJECT (qtdemux, "prepare streams");
11373 for (i = 0; ret == GST_FLOW_OK && i < qtdemux->n_streams; i++) {
11374 QtDemuxStream *stream = qtdemux->streams[i];
11375 guint32 sample_num = 0;
11377 GST_DEBUG_OBJECT (qtdemux, "stream %d, id %d, fourcc %" GST_FOURCC_FORMAT,
11378 i, stream->track_id, GST_FOURCC_ARGS (stream->fourcc));
11380 if (qtdemux->fragmented) {
11381 /* need all moov samples first */
11382 GST_OBJECT_LOCK (qtdemux);
11383 while (stream->n_samples == 0)
11384 if ((ret = qtdemux_add_fragmented_samples (qtdemux)) != GST_FLOW_OK)
11386 GST_OBJECT_UNLOCK (qtdemux);
11388 /* discard any stray moof */
11389 qtdemux->moof_offset = 0;
11392 /* prepare braking */
11393 if (ret != GST_FLOW_ERROR)
11396 /* in pull mode, we should have parsed some sample info by now;
11397 * and quite some code will not handle no samples.
11398 * in push mode, we'll just have to deal with it */
11399 if (G_UNLIKELY (qtdemux->pullbased && !stream->n_samples)) {
11400 GST_DEBUG_OBJECT (qtdemux, "no samples for stream; discarding");
11401 gst_qtdemux_remove_stream (qtdemux, i);
11406 /* parse the initial sample for use in setting the frame rate cap */
11407 while (sample_num == 0 && sample_num < stream->n_samples) {
11408 if (!qtdemux_parse_samples (qtdemux, stream, sample_num))
11412 if (stream->n_samples > 0 && stream->stbl_index >= 0) {
11413 stream->first_duration = stream->samples[0].duration;
11414 GST_LOG_OBJECT (qtdemux, "stream %d first duration %u",
11415 stream->track_id, stream->first_duration);
11422 static GstFlowReturn
11423 qtdemux_expose_streams (GstQTDemux * qtdemux)
11426 GSList *oldpads = NULL;
11429 GST_DEBUG_OBJECT (qtdemux, "exposing streams");
11431 for (i = 0; i < qtdemux->n_streams; i++) {
11432 QtDemuxStream *stream = qtdemux->streams[i];
11433 GstPad *oldpad = stream->pad;
11436 GST_DEBUG_OBJECT (qtdemux, "stream %d, id %d, fourcc %" GST_FOURCC_FORMAT,
11437 i, stream->track_id, GST_FOURCC_ARGS (stream->fourcc));
11439 if ((stream->subtype == FOURCC_text || stream->subtype == FOURCC_sbtl) &&
11440 stream->track_id == qtdemux->chapters_track_id) {
11441 /* TODO - parse chapters track and expose it as GstToc; For now just ignore it
11442 so that it doesn't look like a subtitle track */
11443 gst_qtdemux_remove_stream (qtdemux, i);
11448 /* now we have all info and can expose */
11449 list = stream->pending_tags;
11450 stream->pending_tags = NULL;
11452 oldpads = g_slist_prepend (oldpads, oldpad);
11453 if (!gst_qtdemux_add_stream (qtdemux, stream, list))
11454 return GST_FLOW_ERROR;
11457 gst_qtdemux_guess_bitrate (qtdemux);
11459 gst_element_no_more_pads (GST_ELEMENT_CAST (qtdemux));
11461 for (iter = oldpads; iter; iter = g_slist_next (iter)) {
11462 GstPad *oldpad = iter->data;
11465 event = gst_event_new_eos ();
11466 if (qtdemux->segment_seqnum)
11467 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
11469 gst_pad_push_event (oldpad, event);
11470 gst_pad_set_active (oldpad, FALSE);
11471 gst_element_remove_pad (GST_ELEMENT (qtdemux), oldpad);
11472 gst_flow_combiner_remove_pad (qtdemux->flowcombiner, oldpad);
11473 gst_object_unref (oldpad);
11476 /* check if we should post a redirect in case there is a single trak
11477 * and it is a redirecting trak */
11478 if (qtdemux->n_streams == 1 && qtdemux->streams[0]->redirect_uri != NULL) {
11481 GST_INFO_OBJECT (qtdemux, "Issuing a redirect due to a single track with "
11482 "an external content");
11483 m = gst_message_new_element (GST_OBJECT_CAST (qtdemux),
11484 gst_structure_new ("redirect",
11485 "new-location", G_TYPE_STRING, qtdemux->streams[0]->redirect_uri,
11487 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), m);
11488 qtdemux->posted_redirect = TRUE;
11491 for (i = 0; i < qtdemux->n_streams; i++) {
11492 QtDemuxStream *stream = qtdemux->streams[i];
11494 qtdemux_do_allocation (qtdemux, stream);
11497 qtdemux->exposed = TRUE;
11498 return GST_FLOW_OK;
11501 /* check if major or compatible brand is 3GP */
11502 static inline gboolean
11503 qtdemux_is_brand_3gp (GstQTDemux * qtdemux, gboolean major)
11506 return ((qtdemux->major_brand & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
11508 } else if (qtdemux->comp_brands != NULL) {
11512 gboolean res = FALSE;
11514 gst_buffer_map (qtdemux->comp_brands, &map, GST_MAP_READ);
11517 while (size >= 4) {
11518 res = res || ((QT_FOURCC (data) & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
11523 gst_buffer_unmap (qtdemux->comp_brands, &map);
11530 /* check if tag is a spec'ed 3GP tag keyword storing a string */
11531 static inline gboolean
11532 qtdemux_is_string_tag_3gp (GstQTDemux * qtdemux, guint32 fourcc)
11534 return fourcc == FOURCC_cprt || fourcc == FOURCC_gnre || fourcc == FOURCC_titl
11535 || fourcc == FOURCC_dscp || fourcc == FOURCC_perf || fourcc == FOURCC_auth
11536 || fourcc == FOURCC_albm;
11540 qtdemux_tag_add_location (GstQTDemux * qtdemux, GstTagList * taglist,
11541 const char *tag, const char *dummy, GNode * node)
11543 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
11547 gdouble longitude, latitude, altitude;
11550 len = QT_UINT32 (node->data);
11557 /* TODO: language code skipped */
11559 name = gst_tag_freeform_string_to_utf8 (data + offset, -1, env_vars);
11562 /* do not alarm in trivial case, but bail out otherwise */
11563 if (*(data + offset) != 0) {
11564 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8, "
11568 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
11569 GST_TAG_GEO_LOCATION_NAME, name, NULL);
11570 offset += strlen (name);
11574 if (len < offset + 2 + 4 + 4 + 4)
11577 /* +1 +1 = skip null-terminator and location role byte */
11579 /* table in spec says unsigned, semantics say negative has meaning ... */
11580 longitude = QT_SFP32 (data + offset);
11583 latitude = QT_SFP32 (data + offset);
11586 altitude = QT_SFP32 (data + offset);
11588 /* one invalid means all are invalid */
11589 if (longitude >= -180.0 && longitude <= 180.0 &&
11590 latitude >= -90.0 && latitude <= 90.0) {
11591 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
11592 GST_TAG_GEO_LOCATION_LATITUDE, latitude,
11593 GST_TAG_GEO_LOCATION_LONGITUDE, longitude,
11594 GST_TAG_GEO_LOCATION_ELEVATION, altitude, NULL);
11597 /* TODO: no GST_TAG_, so astronomical body and additional notes skipped */
11604 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP location");
11611 qtdemux_tag_add_year (GstQTDemux * qtdemux, GstTagList * taglist,
11612 const char *tag, const char *dummy, GNode * node)
11618 len = QT_UINT32 (node->data);
11622 y = QT_UINT16 ((guint8 *) node->data + 12);
11624 GST_DEBUG_OBJECT (qtdemux, "year: %u is not a valid year", y);
11627 GST_DEBUG_OBJECT (qtdemux, "year: %u", y);
11629 date = g_date_new_dmy (1, 1, y);
11630 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, date, NULL);
11631 g_date_free (date);
11635 qtdemux_tag_add_classification (GstQTDemux * qtdemux, GstTagList * taglist,
11636 const char *tag, const char *dummy, GNode * node)
11639 char *tag_str = NULL;
11644 len = QT_UINT32 (node->data);
11649 entity = (guint8 *) node->data + offset;
11650 if (entity[0] == 0 || entity[1] == 0 || entity[2] == 0 || entity[3] == 0) {
11651 GST_DEBUG_OBJECT (qtdemux,
11652 "classification info: %c%c%c%c invalid classification entity",
11653 entity[0], entity[1], entity[2], entity[3]);
11658 table = QT_UINT16 ((guint8 *) node->data + offset);
11660 /* Language code skipped */
11664 /* Tag format: "XXXX://Y[YYYY]/classification info string"
11665 * XXXX: classification entity, fixed length 4 chars.
11666 * Y[YYYY]: classification table, max 5 chars.
11668 tag_str = g_strdup_printf ("----://%u/%s",
11669 table, (char *) node->data + offset);
11671 /* memcpy To be sure we're preserving byte order */
11672 memcpy (tag_str, entity, 4);
11673 GST_DEBUG_OBJECT (qtdemux, "classification info: %s", tag_str);
11675 gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND, tag, tag_str, NULL);
11684 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP classification");
11690 qtdemux_tag_add_str_full (GstQTDemux * qtdemux, GstTagList * taglist,
11691 const char *tag, const char *dummy, GNode * node)
11693 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
11699 gboolean ret = TRUE;
11700 const gchar *charset = NULL;
11702 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
11704 len = QT_UINT32 (data->data);
11705 type = QT_UINT32 ((guint8 *) data->data + 8);
11706 if (type == 0x00000001 && len > 16) {
11707 s = gst_tag_freeform_string_to_utf8 ((char *) data->data + 16, len - 16,
11710 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
11711 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, s, NULL);
11714 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
11718 len = QT_UINT32 (node->data);
11719 type = QT_UINT32 ((guint8 *) node->data + 4);
11720 if ((type >> 24) == 0xa9) {
11724 /* Type starts with the (C) symbol, so the next data is a list
11725 * of (string size(16), language code(16), string) */
11727 str_len = QT_UINT16 ((guint8 *) node->data + 8);
11728 lang_code = QT_UINT16 ((guint8 *) node->data + 10);
11730 /* the string + fourcc + size + 2 16bit fields,
11731 * means that there are more tags in this atom */
11732 if (len > str_len + 8 + 4) {
11733 /* TODO how to represent the same tag in different languages? */
11734 GST_WARNING_OBJECT (qtdemux, "Ignoring metadata entry with multiple "
11735 "text alternatives, reading only first one");
11739 len = str_len + 8 + 4; /* remove trailing strings that we don't use */
11740 GST_DEBUG_OBJECT (qtdemux, "found international text tag");
11742 if (lang_code < 0x800) { /* MAC encoded string */
11745 } else if (len > 14 && qtdemux_is_string_tag_3gp (qtdemux,
11746 QT_FOURCC ((guint8 *) node->data + 4))) {
11747 guint32 type = QT_UINT32 ((guint8 *) node->data + 8);
11749 /* we go for 3GP style encoding if major brands claims so,
11750 * or if no hope for data be ok UTF-8, and compatible 3GP brand present */
11751 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
11752 (qtdemux_is_brand_3gp (qtdemux, FALSE) &&
11753 ((type & 0x00FFFFFF) == 0x0) && (type >> 24 <= 0xF))) {
11755 /* 16-bit Language code is ignored here as well */
11756 GST_DEBUG_OBJECT (qtdemux, "found 3gpp text tag");
11763 GST_DEBUG_OBJECT (qtdemux, "found normal text tag");
11764 ret = FALSE; /* may have to fallback */
11767 GError *err = NULL;
11769 s = g_convert ((gchar *) node->data + offset, len - offset, "utf8",
11770 charset, NULL, NULL, &err);
11772 GST_DEBUG_OBJECT (qtdemux, "Failed to convert string from charset %s:"
11773 " %s(%d): %s", charset, g_quark_to_string (err->domain), err->code,
11775 g_error_free (err);
11778 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
11779 len - offset, env_vars);
11782 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
11783 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, s, NULL);
11787 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
11794 qtdemux_tag_add_str (GstQTDemux * qtdemux, GstTagList * taglist,
11795 const char *tag, const char *dummy, GNode * node)
11797 qtdemux_tag_add_str_full (qtdemux, taglist, tag, dummy, node);
11801 qtdemux_tag_add_keywords (GstQTDemux * qtdemux, GstTagList * taglist,
11802 const char *tag, const char *dummy, GNode * node)
11804 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
11806 char *s, *t, *k = NULL;
11811 /* first try normal string tag if major brand not 3GP */
11812 if (!qtdemux_is_brand_3gp (qtdemux, TRUE)) {
11813 if (!qtdemux_tag_add_str_full (qtdemux, taglist, tag, dummy, node)) {
11814 /* hm, that did not work, maybe 3gpp storage in non-3gpp major brand;
11815 * let's try it 3gpp way after minor safety check */
11817 if (QT_UINT32 (data) < 15 || !qtdemux_is_brand_3gp (qtdemux, FALSE))
11823 GST_DEBUG_OBJECT (qtdemux, "found 3gpp keyword tag");
11827 len = QT_UINT32 (data);
11831 count = QT_UINT8 (data + 14);
11833 for (; count; count--) {
11836 if (offset + 1 > len)
11838 slen = QT_UINT8 (data + offset);
11840 if (offset + slen > len)
11842 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
11845 GST_DEBUG_OBJECT (qtdemux, "adding keyword %s", GST_STR_NULL (s));
11847 t = g_strjoin (",", k, s, NULL);
11855 GST_DEBUG_OBJECT (qtdemux, "failed to convert keyword to UTF-8");
11862 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (k));
11863 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, k, NULL);
11872 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP keywords");
11878 qtdemux_tag_add_num (GstQTDemux * qtdemux, GstTagList * taglist,
11879 const char *tag1, const char *tag2, GNode * node)
11886 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
11888 len = QT_UINT32 (data->data);
11889 type = QT_UINT32 ((guint8 *) data->data + 8);
11890 if (type == 0x00000000 && len >= 22) {
11891 n1 = QT_UINT16 ((guint8 *) data->data + 18);
11892 n2 = QT_UINT16 ((guint8 *) data->data + 20);
11894 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag1, n1);
11895 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, n1, NULL);
11898 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag2, n2);
11899 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag2, n2, NULL);
11906 qtdemux_tag_add_tmpo (GstQTDemux * qtdemux, GstTagList * taglist,
11907 const char *tag1, const char *dummy, GNode * node)
11914 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
11916 len = QT_UINT32 (data->data);
11917 type = QT_UINT32 ((guint8 *) data->data + 8);
11918 GST_DEBUG_OBJECT (qtdemux, "have tempo tag, type=%d,len=%d", type, len);
11919 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
11920 if ((type == 0x00000015 || type == 0x0000000f) && len >= 18) {
11921 n1 = QT_UINT16 ((guint8 *) data->data + 16);
11923 /* do not add bpm=0 */
11924 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", n1);
11925 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, (gdouble) n1,
11933 qtdemux_tag_add_uint32 (GstQTDemux * qtdemux, GstTagList * taglist,
11934 const char *tag1, const char *dummy, GNode * node)
11941 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
11943 len = QT_UINT32 (data->data);
11944 type = QT_UINT32 ((guint8 *) data->data + 8);
11945 GST_DEBUG_OBJECT (qtdemux, "have %s tag, type=%d,len=%d", tag1, type, len);
11946 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
11947 if ((type == 0x00000015 || type == 0x0000000f) && len >= 20) {
11948 num = QT_UINT32 ((guint8 *) data->data + 16);
11950 /* do not add num=0 */
11951 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", num);
11952 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, num, NULL);
11959 qtdemux_tag_add_covr (GstQTDemux * qtdemux, GstTagList * taglist,
11960 const char *tag1, const char *dummy, GNode * node)
11967 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
11969 len = QT_UINT32 (data->data);
11970 type = QT_UINT32 ((guint8 *) data->data + 8);
11971 GST_DEBUG_OBJECT (qtdemux, "have covr tag, type=%d,len=%d", type, len);
11972 if ((type == 0x0000000d || type == 0x0000000e) && len > 16) {
11974 gst_tag_image_data_to_image_sample ((guint8 *) data->data + 16,
11975 len - 16, GST_TAG_IMAGE_TYPE_NONE))) {
11976 GST_DEBUG_OBJECT (qtdemux, "adding tag size %d", len - 16);
11977 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, sample, NULL);
11978 gst_sample_unref (sample);
11985 qtdemux_tag_add_date (GstQTDemux * qtdemux, GstTagList * taglist,
11986 const char *tag, const char *dummy, GNode * node)
11993 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
11995 len = QT_UINT32 (data->data);
11996 type = QT_UINT32 ((guint8 *) data->data + 8);
11997 if (type == 0x00000001 && len > 16) {
11998 guint y, m = 1, d = 1;
12001 s = g_strndup ((char *) data->data + 16, len - 16);
12002 GST_DEBUG_OBJECT (qtdemux, "adding date '%s'", s);
12003 ret = sscanf (s, "%u-%u-%u", &y, &m, &d);
12004 if (ret >= 1 && y > 1500 && y < 3000) {
12007 date = g_date_new_dmy (d, m, y);
12008 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, date, NULL);
12009 g_date_free (date);
12011 GST_DEBUG_OBJECT (qtdemux, "could not parse date string '%s'", s);
12019 qtdemux_tag_add_gnre (GstQTDemux * qtdemux, GstTagList * taglist,
12020 const char *tag, const char *dummy, GNode * node)
12024 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12026 /* re-route to normal string tag if major brand says so
12027 * or no data atom and compatible brand suggests so */
12028 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
12029 (qtdemux_is_brand_3gp (qtdemux, FALSE) && !data)) {
12030 qtdemux_tag_add_str (qtdemux, taglist, tag, dummy, node);
12035 guint len, type, n;
12037 len = QT_UINT32 (data->data);
12038 type = QT_UINT32 ((guint8 *) data->data + 8);
12039 if (type == 0x00000000 && len >= 18) {
12040 n = QT_UINT16 ((guint8 *) data->data + 16);
12042 const gchar *genre;
12044 genre = gst_tag_id3_genre_get (n - 1);
12045 if (genre != NULL) {
12046 GST_DEBUG_OBJECT (qtdemux, "adding %d [%s]", n, genre);
12047 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, genre, NULL);
12055 qtdemux_add_double_tag_from_str (GstQTDemux * demux, GstTagList * taglist,
12056 const gchar * tag, guint8 * data, guint32 datasize)
12061 /* make a copy to have \0 at the end */
12062 datacopy = g_strndup ((gchar *) data, datasize);
12064 /* convert the str to double */
12065 if (sscanf (datacopy, "%lf", &value) == 1) {
12066 GST_DEBUG_OBJECT (demux, "adding tag: %s [%s]", tag, datacopy);
12067 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, value, NULL);
12069 GST_WARNING_OBJECT (demux, "Failed to parse double from string: %s",
12077 qtdemux_tag_add_revdns (GstQTDemux * demux, GstTagList * taglist,
12078 const char *tag, const char *tag_bis, GNode * node)
12087 const gchar *meanstr;
12088 const gchar *namestr;
12090 /* checking the whole ---- atom size for consistency */
12091 if (QT_UINT32 (node->data) <= 4 + 12 + 12 + 16) {
12092 GST_WARNING_OBJECT (demux, "Tag ---- atom is too small, ignoring");
12096 mean = qtdemux_tree_get_child_by_type (node, FOURCC_mean);
12098 GST_WARNING_OBJECT (demux, "No 'mean' atom found");
12102 meansize = QT_UINT32 (mean->data);
12103 if (meansize <= 12) {
12104 GST_WARNING_OBJECT (demux, "Small mean atom, ignoring the whole tag");
12107 meanstr = ((gchar *) mean->data) + 12;
12110 name = qtdemux_tree_get_child_by_type (node, FOURCC_name);
12112 GST_WARNING_OBJECT (demux, "'name' atom not found, ignoring tag");
12116 namesize = QT_UINT32 (name->data);
12117 if (namesize <= 12) {
12118 GST_WARNING_OBJECT (demux, "'name' atom is too small, ignoring tag");
12121 namestr = ((gchar *) name->data) + 12;
12129 * uint24 - data type
12133 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12135 GST_WARNING_OBJECT (demux, "No data atom in this tag");
12138 datasize = QT_UINT32 (data->data);
12139 if (datasize <= 16) {
12140 GST_WARNING_OBJECT (demux, "Data atom too small");
12143 datatype = QT_UINT32 (((gchar *) data->data) + 8) & 0xFFFFFF;
12145 if ((strncmp (meanstr, "com.apple.iTunes", meansize) == 0) ||
12146 (strncmp (meanstr, "org.hydrogenaudio.replaygain", meansize) == 0)) {
12147 static const struct
12149 const gchar name[28];
12150 const gchar tag[28];
12153 "replaygain_track_gain", GST_TAG_TRACK_GAIN}, {
12154 "replaygain_track_peak", GST_TAG_TRACK_PEAK}, {
12155 "replaygain_album_gain", GST_TAG_ALBUM_GAIN}, {
12156 "replaygain_album_peak", GST_TAG_ALBUM_PEAK}, {
12157 "MusicBrainz Track Id", GST_TAG_MUSICBRAINZ_TRACKID}, {
12158 "MusicBrainz Artist Id", GST_TAG_MUSICBRAINZ_ARTISTID}, {
12159 "MusicBrainz Album Id", GST_TAG_MUSICBRAINZ_ALBUMID}, {
12160 "MusicBrainz Album Artist Id", GST_TAG_MUSICBRAINZ_ALBUMARTISTID}
12164 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
12165 if (!g_ascii_strncasecmp (tags[i].name, namestr, namesize)) {
12166 switch (gst_tag_get_type (tags[i].tag)) {
12167 case G_TYPE_DOUBLE:
12168 qtdemux_add_double_tag_from_str (demux, taglist, tags[i].tag,
12169 ((guint8 *) data->data) + 16, datasize - 16);
12171 case G_TYPE_STRING:
12172 qtdemux_tag_add_str (demux, taglist, tags[i].tag, NULL, node);
12181 if (i == G_N_ELEMENTS (tags))
12191 #ifndef GST_DISABLE_GST_DEBUG
12193 gchar *namestr_dbg;
12194 gchar *meanstr_dbg;
12196 meanstr_dbg = g_strndup (meanstr, meansize);
12197 namestr_dbg = g_strndup (namestr, namesize);
12199 GST_WARNING_OBJECT (demux, "This tag %s:%s type:%u is not mapped, "
12200 "file a bug at bugzilla.gnome.org", meanstr_dbg, namestr_dbg, datatype);
12202 g_free (namestr_dbg);
12203 g_free (meanstr_dbg);
12210 qtdemux_tag_add_id32 (GstQTDemux * demux, GstTagList * taglist, const char *tag,
12211 const char *tag_bis, GNode * node)
12216 GstTagList *id32_taglist = NULL;
12218 GST_LOG_OBJECT (demux, "parsing ID32");
12221 len = GST_READ_UINT32_BE (data);
12223 /* need at least full box and language tag */
12227 buf = gst_buffer_new_allocate (NULL, len - 14, NULL);
12228 gst_buffer_fill (buf, 0, data + 14, len - 14);
12230 id32_taglist = gst_tag_list_from_id3v2_tag (buf);
12231 if (id32_taglist) {
12232 GST_LOG_OBJECT (demux, "parsing ok");
12233 gst_tag_list_insert (taglist, id32_taglist, GST_TAG_MERGE_KEEP);
12234 gst_tag_list_unref (id32_taglist);
12236 GST_LOG_OBJECT (demux, "parsing failed");
12239 gst_buffer_unref (buf);
12242 typedef void (*GstQTDemuxAddTagFunc) (GstQTDemux * demux, GstTagList * taglist,
12243 const char *tag, const char *tag_bis, GNode * node);
12246 FOURCC_pcst -> if media is a podcast -> bool
12247 FOURCC_cpil -> if media is part of a compilation -> bool
12248 FOURCC_pgap -> if media is part of a gapless context -> bool
12249 FOURCC_tven -> the tv episode id e.g. S01E23 -> str
12252 static const struct
12255 const gchar *gst_tag;
12256 const gchar *gst_tag_bis;
12257 const GstQTDemuxAddTagFunc func;
12260 FOURCC__nam, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
12261 FOURCC_titl, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
12262 FOURCC__grp, GST_TAG_GROUPING, NULL, qtdemux_tag_add_str}, {
12263 FOURCC__wrt, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
12264 FOURCC__ART, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
12265 FOURCC_aART, GST_TAG_ALBUM_ARTIST, NULL, qtdemux_tag_add_str}, {
12266 FOURCC_perf, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
12267 FOURCC_auth, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
12268 FOURCC__alb, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
12269 FOURCC_albm, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
12270 FOURCC_cprt, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
12271 FOURCC__cpy, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
12272 FOURCC__cmt, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
12273 FOURCC__des, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
12274 FOURCC_desc, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
12275 FOURCC_dscp, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
12276 FOURCC__lyr, GST_TAG_LYRICS, NULL, qtdemux_tag_add_str}, {
12277 FOURCC__day, GST_TAG_DATE, NULL, qtdemux_tag_add_date}, {
12278 FOURCC_yrrc, GST_TAG_DATE, NULL, qtdemux_tag_add_year}, {
12279 FOURCC__too, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
12280 FOURCC__inf, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
12281 FOURCC_trkn, GST_TAG_TRACK_NUMBER, GST_TAG_TRACK_COUNT, qtdemux_tag_add_num}, {
12282 FOURCC_disk, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
12283 qtdemux_tag_add_num}, {
12284 FOURCC_disc, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
12285 qtdemux_tag_add_num}, {
12286 FOURCC__gen, GST_TAG_GENRE, NULL, qtdemux_tag_add_str}, {
12287 FOURCC_gnre, GST_TAG_GENRE, NULL, qtdemux_tag_add_gnre}, {
12288 FOURCC_tmpo, GST_TAG_BEATS_PER_MINUTE, NULL, qtdemux_tag_add_tmpo}, {
12289 FOURCC_covr, GST_TAG_PREVIEW_IMAGE, NULL, qtdemux_tag_add_covr}, {
12290 FOURCC_sonm, GST_TAG_TITLE_SORTNAME, NULL, qtdemux_tag_add_str}, {
12291 FOURCC_soal, GST_TAG_ALBUM_SORTNAME, NULL, qtdemux_tag_add_str}, {
12292 FOURCC_soar, GST_TAG_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
12293 FOURCC_soaa, GST_TAG_ALBUM_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
12294 FOURCC_soco, GST_TAG_COMPOSER_SORTNAME, NULL, qtdemux_tag_add_str}, {
12295 FOURCC_sosn, GST_TAG_SHOW_SORTNAME, NULL, qtdemux_tag_add_str}, {
12296 FOURCC_tvsh, GST_TAG_SHOW_NAME, NULL, qtdemux_tag_add_str}, {
12297 FOURCC_tvsn, GST_TAG_SHOW_SEASON_NUMBER, NULL, qtdemux_tag_add_uint32}, {
12298 FOURCC_tves, GST_TAG_SHOW_EPISODE_NUMBER, NULL, qtdemux_tag_add_uint32}, {
12299 FOURCC_kywd, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_keywords}, {
12300 FOURCC_keyw, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_str}, {
12301 FOURCC__enc, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
12302 FOURCC_loci, GST_TAG_GEO_LOCATION_NAME, NULL, qtdemux_tag_add_location}, {
12303 FOURCC_clsf, GST_QT_DEMUX_CLASSIFICATION_TAG, NULL,
12304 qtdemux_tag_add_classification}, {
12305 FOURCC__mak, GST_TAG_DEVICE_MANUFACTURER, NULL, qtdemux_tag_add_str}, {
12306 FOURCC__mod, GST_TAG_DEVICE_MODEL, NULL, qtdemux_tag_add_str}, {
12307 FOURCC__swr, GST_TAG_APPLICATION_NAME, NULL, qtdemux_tag_add_str}, {
12309 /* This is a special case, some tags are stored in this
12310 * 'reverse dns naming', according to:
12311 * http://atomicparsley.sourceforge.net/mpeg-4files.html and
12314 FOURCC_____, "", NULL, qtdemux_tag_add_revdns}, {
12315 /* see http://www.mp4ra.org/specs.html for ID32 in meta box */
12316 FOURCC_ID32, "", NULL, qtdemux_tag_add_id32}
12319 struct _GstQtDemuxTagList
12322 GstTagList *taglist;
12324 typedef struct _GstQtDemuxTagList GstQtDemuxTagList;
12327 qtdemux_tag_add_blob (GNode * node, GstQtDemuxTagList * qtdemuxtaglist)
12333 const gchar *style;
12338 GstQTDemux *demux = qtdemuxtaglist->demux;
12339 GstTagList *taglist = qtdemuxtaglist->taglist;
12342 len = QT_UINT32 (data);
12343 buf = gst_buffer_new_and_alloc (len);
12344 gst_buffer_fill (buf, 0, data, len);
12346 /* heuristic to determine style of tag */
12347 if (QT_FOURCC (data + 4) == FOURCC_____ ||
12348 (len > 8 + 12 && QT_FOURCC (data + 12) == FOURCC_data))
12350 else if (demux->major_brand == FOURCC_qt__)
12351 style = "quicktime";
12352 /* fall back to assuming iso/3gp tag style */
12356 /* santize the name for the caps. */
12357 for (i = 0; i < 4; i++) {
12358 guint8 d = data[4 + i];
12359 if (g_ascii_isalnum (d))
12360 ndata[i] = g_ascii_tolower (d);
12365 media_type = g_strdup_printf ("application/x-gst-qt-%c%c%c%c-tag",
12366 ndata[0], ndata[1], ndata[2], ndata[3]);
12367 GST_DEBUG_OBJECT (demux, "media type %s", media_type);
12369 s = gst_structure_new (media_type, "style", G_TYPE_STRING, style, NULL);
12370 sample = gst_sample_new (buf, NULL, NULL, s);
12371 gst_buffer_unref (buf);
12372 g_free (media_type);
12374 GST_DEBUG_OBJECT (demux, "adding private tag; size %d, info %" GST_PTR_FORMAT,
12377 gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND,
12378 GST_QT_DEMUX_PRIVATE_TAG, sample, NULL);
12380 gst_sample_unref (sample);
12384 qtdemux_parse_udta (GstQTDemux * qtdemux, GstTagList * taglist, GNode * udta)
12391 GstQtDemuxTagList demuxtaglist;
12393 demuxtaglist.demux = qtdemux;
12394 demuxtaglist.taglist = taglist;
12396 meta = qtdemux_tree_get_child_by_type (udta, FOURCC_meta);
12397 if (meta != NULL) {
12398 ilst = qtdemux_tree_get_child_by_type (meta, FOURCC_ilst);
12399 if (ilst == NULL) {
12400 GST_LOG_OBJECT (qtdemux, "no ilst");
12405 GST_LOG_OBJECT (qtdemux, "no meta so using udta itself");
12409 while (i < G_N_ELEMENTS (add_funcs)) {
12410 node = qtdemux_tree_get_child_by_type (ilst, add_funcs[i].fourcc);
12414 len = QT_UINT32 (node->data);
12416 GST_DEBUG_OBJECT (qtdemux, "too small tag atom %" GST_FOURCC_FORMAT,
12417 GST_FOURCC_ARGS (add_funcs[i].fourcc));
12419 add_funcs[i].func (qtdemux, taglist, add_funcs[i].gst_tag,
12420 add_funcs[i].gst_tag_bis, node);
12422 g_node_destroy (node);
12428 /* parsed nodes have been removed, pass along remainder as blob */
12429 g_node_children_foreach (ilst, G_TRAVERSE_ALL,
12430 (GNodeForeachFunc) qtdemux_tag_add_blob, &demuxtaglist);
12432 /* parse up XMP_ node if existing */
12433 xmp_ = qtdemux_tree_get_child_by_type (udta, FOURCC_XMP_);
12434 if (xmp_ != NULL) {
12436 GstTagList *xmptaglist;
12438 buf = _gst_buffer_new_wrapped (((guint8 *) xmp_->data) + 8,
12439 QT_UINT32 ((guint8 *) xmp_->data) - 8, NULL);
12440 xmptaglist = gst_tag_list_from_xmp_buffer (buf);
12441 gst_buffer_unref (buf);
12443 qtdemux_handle_xmp_taglist (qtdemux, taglist, xmptaglist);
12445 GST_DEBUG_OBJECT (qtdemux, "No XMP_ node found");
12451 GstStructure *structure; /* helper for sort function */
12453 guint min_req_bitrate;
12454 guint min_req_qt_version;
12458 qtdemux_redirects_sort_func (gconstpointer a, gconstpointer b)
12460 GstQtReference *ref_a = (GstQtReference *) a;
12461 GstQtReference *ref_b = (GstQtReference *) b;
12463 if (ref_b->min_req_qt_version != ref_a->min_req_qt_version)
12464 return ref_b->min_req_qt_version - ref_a->min_req_qt_version;
12466 /* known bitrates go before unknown; higher bitrates go first */
12467 return ref_b->min_req_bitrate - ref_a->min_req_bitrate;
12470 /* sort the redirects and post a message for the application.
12473 qtdemux_process_redirects (GstQTDemux * qtdemux, GList * references)
12475 GstQtReference *best;
12478 GValue list_val = { 0, };
12481 g_assert (references != NULL);
12483 references = g_list_sort (references, qtdemux_redirects_sort_func);
12485 best = (GstQtReference *) references->data;
12487 g_value_init (&list_val, GST_TYPE_LIST);
12489 for (l = references; l != NULL; l = l->next) {
12490 GstQtReference *ref = (GstQtReference *) l->data;
12491 GValue struct_val = { 0, };
12493 ref->structure = gst_structure_new ("redirect",
12494 "new-location", G_TYPE_STRING, ref->location, NULL);
12496 if (ref->min_req_bitrate > 0) {
12497 gst_structure_set (ref->structure, "minimum-bitrate", G_TYPE_INT,
12498 ref->min_req_bitrate, NULL);
12501 g_value_init (&struct_val, GST_TYPE_STRUCTURE);
12502 g_value_set_boxed (&struct_val, ref->structure);
12503 gst_value_list_append_value (&list_val, &struct_val);
12504 g_value_unset (&struct_val);
12505 /* don't free anything here yet, since we need best->structure below */
12508 g_assert (best != NULL);
12509 s = gst_structure_copy (best->structure);
12511 if (g_list_length (references) > 1) {
12512 gst_structure_set_value (s, "locations", &list_val);
12515 g_value_unset (&list_val);
12517 for (l = references; l != NULL; l = l->next) {
12518 GstQtReference *ref = (GstQtReference *) l->data;
12520 gst_structure_free (ref->structure);
12521 g_free (ref->location);
12524 g_list_free (references);
12526 GST_INFO_OBJECT (qtdemux, "posting redirect message: %" GST_PTR_FORMAT, s);
12527 msg = gst_message_new_element (GST_OBJECT_CAST (qtdemux), s);
12528 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
12529 qtdemux->posted_redirect = TRUE;
12532 /* look for redirect nodes, collect all redirect information and
12536 qtdemux_parse_redirects (GstQTDemux * qtdemux)
12538 GNode *rmra, *rmda, *rdrf;
12540 rmra = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_rmra);
12542 GList *redirects = NULL;
12544 rmda = qtdemux_tree_get_child_by_type (rmra, FOURCC_rmda);
12546 GstQtReference ref = { NULL, NULL, 0, 0 };
12547 GNode *rmdr, *rmvc;
12549 if ((rmdr = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmdr))) {
12550 ref.min_req_bitrate = QT_UINT32 ((guint8 *) rmdr->data + 12);
12551 GST_LOG_OBJECT (qtdemux, "data rate atom, required bitrate = %u",
12552 ref.min_req_bitrate);
12555 if ((rmvc = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmvc))) {
12556 guint32 package = QT_FOURCC ((guint8 *) rmvc->data + 12);
12557 guint version = QT_UINT32 ((guint8 *) rmvc->data + 16);
12559 #ifndef GST_DISABLE_GST_DEBUG
12560 guint bitmask = QT_UINT32 ((guint8 *) rmvc->data + 20);
12562 guint check_type = QT_UINT16 ((guint8 *) rmvc->data + 24);
12564 GST_LOG_OBJECT (qtdemux,
12565 "version check atom [%" GST_FOURCC_FORMAT "], version=0x%08x"
12566 ", mask=%08x, check_type=%u", GST_FOURCC_ARGS (package), version,
12567 bitmask, check_type);
12568 if (package == FOURCC_qtim && check_type == 0) {
12569 ref.min_req_qt_version = version;
12573 rdrf = qtdemux_tree_get_child_by_type (rmda, FOURCC_rdrf);
12579 ref_len = QT_UINT32 ((guint8 *) rdrf->data);
12580 if (ref_len > 20) {
12581 ref_type = QT_FOURCC ((guint8 *) rdrf->data + 12);
12582 ref_data = (guint8 *) rdrf->data + 20;
12583 if (ref_type == FOURCC_alis) {
12584 guint record_len, record_version, fn_len;
12586 if (ref_len > 70) {
12587 /* MacOSX alias record, google for alias-layout.txt */
12588 record_len = QT_UINT16 (ref_data + 4);
12589 record_version = QT_UINT16 (ref_data + 4 + 2);
12590 fn_len = QT_UINT8 (ref_data + 50);
12591 if (record_len > 50 && record_version == 2 && fn_len > 0) {
12592 ref.location = g_strndup ((gchar *) ref_data + 51, fn_len);
12595 GST_WARNING_OBJECT (qtdemux, "Invalid rdrf/alis size (%u < 70)",
12598 } else if (ref_type == FOURCC_url_) {
12599 ref.location = g_strndup ((gchar *) ref_data, ref_len - 8);
12601 GST_DEBUG_OBJECT (qtdemux,
12602 "unknown rdrf reference type %" GST_FOURCC_FORMAT,
12603 GST_FOURCC_ARGS (ref_type));
12605 if (ref.location != NULL) {
12606 GST_INFO_OBJECT (qtdemux, "New location: %s", ref.location);
12608 g_list_prepend (redirects, g_memdup (&ref, sizeof (ref)));
12610 GST_WARNING_OBJECT (qtdemux,
12611 "Failed to extract redirect location from rdrf atom");
12614 GST_WARNING_OBJECT (qtdemux, "Invalid rdrf size (%u < 20)", ref_len);
12618 /* look for others */
12619 rmda = qtdemux_tree_get_sibling_by_type (rmda, FOURCC_rmda);
12622 if (redirects != NULL) {
12623 qtdemux_process_redirects (qtdemux, redirects);
12629 static GstTagList *
12630 qtdemux_add_container_format (GstQTDemux * qtdemux, GstTagList * tags)
12634 if (tags == NULL) {
12635 tags = gst_tag_list_new_empty ();
12636 gst_tag_list_set_scope (tags, GST_TAG_SCOPE_GLOBAL);
12639 if (qtdemux->major_brand == FOURCC_mjp2)
12640 fmt = "Motion JPEG 2000";
12641 else if ((qtdemux->major_brand & 0xffff) == FOURCC_3g__)
12643 else if (qtdemux->major_brand == FOURCC_qt__)
12645 else if (qtdemux->fragmented)
12648 fmt = "ISO MP4/M4A";
12650 GST_LOG_OBJECT (qtdemux, "mapped %" GST_FOURCC_FORMAT " to '%s'",
12651 GST_FOURCC_ARGS (qtdemux->major_brand), fmt);
12653 gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_CONTAINER_FORMAT,
12659 /* we have read the complete moov node now.
12660 * This function parses all of the relevant info, creates the traks and
12661 * prepares all data structures for playback
12664 qtdemux_parse_tree (GstQTDemux * qtdemux)
12670 GstClockTime duration;
12672 guint64 creation_time;
12673 GstDateTime *datetime = NULL;
12676 /* make sure we have a usable taglist */
12677 if (!qtdemux->tag_list) {
12678 qtdemux->tag_list = gst_tag_list_new_empty ();
12679 gst_tag_list_set_scope (qtdemux->tag_list, GST_TAG_SCOPE_GLOBAL);
12681 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
12684 mvhd = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvhd);
12685 if (mvhd == NULL) {
12686 GST_LOG_OBJECT (qtdemux, "No mvhd node found, looking for redirects.");
12687 return qtdemux_parse_redirects (qtdemux);
12690 version = QT_UINT8 ((guint8 *) mvhd->data + 8);
12691 if (version == 1) {
12692 creation_time = QT_UINT64 ((guint8 *) mvhd->data + 12);
12693 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 28);
12694 qtdemux->duration = QT_UINT64 ((guint8 *) mvhd->data + 32);
12695 } else if (version == 0) {
12696 creation_time = QT_UINT32 ((guint8 *) mvhd->data + 12);
12697 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 20);
12698 qtdemux->duration = QT_UINT32 ((guint8 *) mvhd->data + 24);
12700 GST_WARNING_OBJECT (qtdemux, "Unhandled mvhd version %d", version);
12704 /* Moving qt creation time (secs since 1904) to unix time */
12705 if (creation_time != 0) {
12706 /* Try to use epoch first as it should be faster and more commonly found */
12707 if (creation_time >= QTDEMUX_SECONDS_FROM_1904_TO_1970) {
12710 creation_time -= QTDEMUX_SECONDS_FROM_1904_TO_1970;
12711 /* some data cleansing sanity */
12712 g_get_current_time (&now);
12713 if (now.tv_sec + 24 * 3600 < creation_time) {
12714 GST_DEBUG_OBJECT (qtdemux, "discarding bogus future creation time");
12716 datetime = gst_date_time_new_from_unix_epoch_utc (creation_time);
12719 GDateTime *base_dt = g_date_time_new_utc (1904, 1, 1, 0, 0, 0);
12720 GDateTime *dt, *dt_local;
12722 dt = g_date_time_add_seconds (base_dt, creation_time);
12723 dt_local = g_date_time_to_local (dt);
12724 datetime = gst_date_time_new_from_g_date_time (dt_local);
12726 g_date_time_unref (base_dt);
12727 g_date_time_unref (dt);
12731 /* Use KEEP as explicit tags should have a higher priority than mvhd tag */
12732 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_KEEP, GST_TAG_DATE_TIME,
12734 gst_date_time_unref (datetime);
12737 GST_INFO_OBJECT (qtdemux, "timescale: %u", qtdemux->timescale);
12738 GST_INFO_OBJECT (qtdemux, "duration: %" G_GUINT64_FORMAT, qtdemux->duration);
12740 /* check for fragmented file and get some (default) data */
12741 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
12744 GstByteReader mehd_data;
12746 /* let track parsing or anyone know weird stuff might happen ... */
12747 qtdemux->fragmented = TRUE;
12749 /* compensate for total duration */
12750 mehd = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_mehd, &mehd_data);
12752 qtdemux_parse_mehd (qtdemux, &mehd_data);
12755 /* set duration in the segment info */
12756 gst_qtdemux_get_duration (qtdemux, &duration);
12758 qtdemux->segment.duration = duration;
12759 /* also do not exceed duration; stop is set that way post seek anyway,
12760 * and segment activation falls back to duration,
12761 * whereas loop only checks stop, so let's align this here as well */
12762 qtdemux->segment.stop = duration;
12765 /* parse all traks */
12766 trak = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_trak);
12768 qtdemux_parse_trak (qtdemux, trak);
12769 /* iterate all siblings */
12770 trak = qtdemux_tree_get_sibling_by_type (trak, FOURCC_trak);
12773 if (!qtdemux->tag_list) {
12774 GST_DEBUG_OBJECT (qtdemux, "new tag list");
12775 qtdemux->tag_list = gst_tag_list_new_empty ();
12776 gst_tag_list_set_scope (qtdemux->tag_list, GST_TAG_SCOPE_GLOBAL);
12778 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
12782 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_udta);
12784 qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
12786 GST_LOG_OBJECT (qtdemux, "No udta node found.");
12789 /* maybe also some tags in meta box */
12790 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_meta);
12792 GST_DEBUG_OBJECT (qtdemux, "Parsing meta box for tags.");
12793 qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
12795 GST_LOG_OBJECT (qtdemux, "No meta node found.");
12798 /* parse any protection system info */
12799 pssh = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_pssh);
12801 GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
12802 qtdemux_parse_pssh (qtdemux, pssh);
12803 pssh = qtdemux_tree_get_sibling_by_type (pssh, FOURCC_pssh);
12806 qtdemux->tag_list = qtdemux_add_container_format (qtdemux, qtdemux->tag_list);
12811 /* taken from ffmpeg */
12813 read_descr_size (guint8 * ptr, guint8 * end, guint8 ** end_out)
12825 len = (len << 7) | (c & 0x7f);
12833 /* this can change the codec originally present in @list */
12835 gst_qtdemux_handle_esds (GstQTDemux * qtdemux, QtDemuxStream * stream,
12836 GNode * esds, GstTagList * list)
12838 int len = QT_UINT32 (esds->data);
12839 guint8 *ptr = esds->data;
12840 guint8 *end = ptr + len;
12842 guint8 *data_ptr = NULL;
12844 guint8 object_type_id = 0;
12845 const char *codec_name = NULL;
12846 GstCaps *caps = NULL;
12848 GST_MEMDUMP_OBJECT (qtdemux, "esds", ptr, len);
12850 GST_DEBUG_OBJECT (qtdemux, "version/flags = %08x", QT_UINT32 (ptr));
12852 while (ptr + 1 < end) {
12853 tag = QT_UINT8 (ptr);
12854 GST_DEBUG_OBJECT (qtdemux, "tag = %02x", tag);
12856 len = read_descr_size (ptr, end, &ptr);
12857 GST_DEBUG_OBJECT (qtdemux, "len = %d", len);
12859 /* Check the stated amount of data is available for reading */
12860 if (len < 0 || ptr + len > end)
12864 case ES_DESCRIPTOR_TAG:
12865 GST_DEBUG_OBJECT (qtdemux, "ID %04x", QT_UINT16 (ptr));
12866 GST_DEBUG_OBJECT (qtdemux, "priority %04x", QT_UINT8 (ptr + 2));
12869 case DECODER_CONFIG_DESC_TAG:{
12870 guint max_bitrate, avg_bitrate;
12872 object_type_id = QT_UINT8 (ptr);
12873 max_bitrate = QT_UINT32 (ptr + 5);
12874 avg_bitrate = QT_UINT32 (ptr + 9);
12875 GST_DEBUG_OBJECT (qtdemux, "object_type_id %02x", object_type_id);
12876 GST_DEBUG_OBJECT (qtdemux, "stream_type %02x", QT_UINT8 (ptr + 1));
12877 GST_DEBUG_OBJECT (qtdemux, "buffer_size_db %02x", QT_UINT24 (ptr + 2));
12878 GST_DEBUG_OBJECT (qtdemux, "max bitrate %u", max_bitrate);
12879 GST_DEBUG_OBJECT (qtdemux, "avg bitrate %u", avg_bitrate);
12880 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
12881 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
12882 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
12884 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
12885 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
12886 avg_bitrate, NULL);
12891 case DECODER_SPECIFIC_INFO_TAG:
12892 GST_MEMDUMP_OBJECT (qtdemux, "data", ptr, len);
12893 if (object_type_id == 0xe0 && len == 0x40) {
12899 GST_DEBUG_OBJECT (qtdemux,
12900 "Have VOBSUB palette. Creating palette event");
12901 /* move to decConfigDescr data and read palette */
12903 for (i = 0; i < 16; i++) {
12904 clut[i] = QT_UINT32 (data);
12908 s = gst_structure_new ("application/x-gst-dvd", "event",
12909 G_TYPE_STRING, "dvd-spu-clut-change",
12910 "clut00", G_TYPE_INT, clut[0], "clut01", G_TYPE_INT, clut[1],
12911 "clut02", G_TYPE_INT, clut[2], "clut03", G_TYPE_INT, clut[3],
12912 "clut04", G_TYPE_INT, clut[4], "clut05", G_TYPE_INT, clut[5],
12913 "clut06", G_TYPE_INT, clut[6], "clut07", G_TYPE_INT, clut[7],
12914 "clut08", G_TYPE_INT, clut[8], "clut09", G_TYPE_INT, clut[9],
12915 "clut10", G_TYPE_INT, clut[10], "clut11", G_TYPE_INT, clut[11],
12916 "clut12", G_TYPE_INT, clut[12], "clut13", G_TYPE_INT, clut[13],
12917 "clut14", G_TYPE_INT, clut[14], "clut15", G_TYPE_INT, clut[15],
12920 /* store event and trigger custom processing */
12921 stream->pending_event =
12922 gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s);
12924 /* Generic codec_data handler puts it on the caps */
12931 case SL_CONFIG_DESC_TAG:
12932 GST_DEBUG_OBJECT (qtdemux, "data %02x", QT_UINT8 (ptr));
12936 GST_DEBUG_OBJECT (qtdemux, "Unknown/unhandled descriptor tag %02x",
12938 GST_MEMDUMP_OBJECT (qtdemux, "descriptor data", ptr, len);
12944 /* object_type_id in the esds atom in mp4a and mp4v tells us which codec is
12945 * in use, and should also be used to override some other parameters for some
12947 switch (object_type_id) {
12948 case 0x20: /* MPEG-4 */
12949 /* 4 bytes for the visual_object_sequence_start_code and 1 byte for the
12950 * profile_and_level_indication */
12951 if (data_ptr != NULL && data_len >= 5 &&
12952 GST_READ_UINT32_BE (data_ptr) == 0x000001b0) {
12953 gst_codec_utils_mpeg4video_caps_set_level_and_profile (stream->caps,
12954 data_ptr + 4, data_len - 4);
12956 break; /* Nothing special needed here */
12957 case 0x21: /* H.264 */
12958 codec_name = "H.264 / AVC";
12959 caps = gst_caps_new_simple ("video/x-h264",
12960 "stream-format", G_TYPE_STRING, "avc",
12961 "alignment", G_TYPE_STRING, "au", NULL);
12963 case 0x40: /* AAC (any) */
12964 case 0x66: /* AAC Main */
12965 case 0x67: /* AAC LC */
12966 case 0x68: /* AAC SSR */
12967 /* Override channels and rate based on the codec_data, as it's often
12969 /* Only do so for basic setup without HE-AAC extension */
12970 if (data_ptr && data_len == 2) {
12971 guint channels, rate;
12973 channels = gst_codec_utils_aac_get_channels (data_ptr, data_len);
12975 stream->n_channels = channels;
12977 rate = gst_codec_utils_aac_get_sample_rate (data_ptr, data_len);
12979 stream->rate = rate;
12982 /* Set level and profile if possible */
12983 if (data_ptr != NULL && data_len >= 2) {
12984 gst_codec_utils_aac_caps_set_level_and_profile (stream->caps,
12985 data_ptr, data_len);
12987 const gchar *profile_str = NULL;
12990 guint8 *codec_data;
12991 gint rate_idx, profile;
12993 /* No codec_data, let's invent something.
12994 * FIXME: This is wrong for SBR! */
12996 GST_WARNING_OBJECT (qtdemux, "No codec_data for AAC available");
12998 buffer = gst_buffer_new_and_alloc (2);
12999 gst_buffer_map (buffer, &map, GST_MAP_WRITE);
13000 codec_data = map.data;
13003 gst_codec_utils_aac_get_index_from_sample_rate (stream->rate);
13005 switch (object_type_id) {
13007 profile_str = "main";
13011 profile_str = "lc";
13015 profile_str = "ssr";
13023 codec_data[0] = ((profile + 1) << 3) | ((rate_idx & 0xE) >> 1);
13024 codec_data[1] = ((rate_idx & 0x1) << 7) | (stream->n_channels << 3);
13026 gst_buffer_unmap (buffer, &map);
13027 gst_caps_set_simple (stream->caps, "codec_data", GST_TYPE_BUFFER,
13029 gst_buffer_unref (buffer);
13032 gst_caps_set_simple (stream->caps, "profile", G_TYPE_STRING,
13033 profile_str, NULL);
13037 case 0x60: /* MPEG-2, various profiles */
13043 codec_name = "MPEG-2 video";
13044 caps = gst_caps_new_simple ("video/mpeg",
13045 "mpegversion", G_TYPE_INT, 2,
13046 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13048 case 0x69: /* MPEG-2 BC audio */
13049 case 0x6B: /* MPEG-1 audio */
13050 caps = gst_caps_new_simple ("audio/mpeg",
13051 "mpegversion", G_TYPE_INT, 1, "parsed", G_TYPE_BOOLEAN, TRUE, NULL);
13052 codec_name = "MPEG-1 audio";
13054 case 0x6A: /* MPEG-1 */
13055 codec_name = "MPEG-1 video";
13056 caps = gst_caps_new_simple ("video/mpeg",
13057 "mpegversion", G_TYPE_INT, 1,
13058 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13060 case 0x6C: /* MJPEG */
13062 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
13064 codec_name = "Motion-JPEG";
13066 case 0x6D: /* PNG */
13068 gst_caps_new_simple ("image/png", "parsed", G_TYPE_BOOLEAN, TRUE,
13070 codec_name = "PNG still images";
13072 case 0x6E: /* JPEG2000 */
13073 codec_name = "JPEG-2000";
13074 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
13076 case 0xA4: /* Dirac */
13077 codec_name = "Dirac";
13078 caps = gst_caps_new_empty_simple ("video/x-dirac");
13080 case 0xA5: /* AC3 */
13081 codec_name = "AC-3 audio";
13082 caps = gst_caps_new_simple ("audio/x-ac3",
13083 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
13085 case 0xA9: /* AC3 */
13086 codec_name = "DTS audio";
13087 caps = gst_caps_new_simple ("audio/x-dts",
13088 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
13090 case 0xE1: /* QCELP */
13091 /* QCELP, the codec_data is a riff tag (little endian) with
13092 * 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). */
13093 caps = gst_caps_new_empty_simple ("audio/qcelp");
13094 codec_name = "QCELP";
13100 /* If we have a replacement caps, then change our caps for this stream */
13102 gst_caps_unref (stream->caps);
13103 stream->caps = caps;
13106 if (codec_name && list)
13107 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
13108 GST_TAG_AUDIO_CODEC, codec_name, NULL);
13110 /* Add the codec_data attribute to caps, if we have it */
13114 buffer = gst_buffer_new_and_alloc (data_len);
13115 gst_buffer_fill (buffer, 0, data_ptr, data_len);
13117 GST_DEBUG_OBJECT (qtdemux, "setting codec_data from esds");
13118 GST_MEMDUMP_OBJECT (qtdemux, "codec_data from esds", data_ptr, data_len);
13120 gst_caps_set_simple (stream->caps, "codec_data", GST_TYPE_BUFFER,
13122 gst_buffer_unref (buffer);
13127 #define _codec(name) \
13129 if (codec_name) { \
13130 *codec_name = g_strdup (name); \
13135 qtdemux_video_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
13136 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
13138 GstCaps *caps = NULL;
13139 GstVideoFormat format = GST_VIDEO_FORMAT_UNKNOWN;
13142 case GST_MAKE_FOURCC ('p', 'n', 'g', ' '):
13143 _codec ("PNG still images");
13144 caps = gst_caps_new_empty_simple ("image/png");
13147 _codec ("JPEG still images");
13149 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
13152 case GST_MAKE_FOURCC ('m', 'j', 'p', 'a'):
13153 case GST_MAKE_FOURCC ('A', 'V', 'D', 'J'):
13154 case GST_MAKE_FOURCC ('M', 'J', 'P', 'G'):
13155 case GST_MAKE_FOURCC ('d', 'm', 'b', '1'):
13156 _codec ("Motion-JPEG");
13158 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
13161 case GST_MAKE_FOURCC ('m', 'j', 'p', 'b'):
13162 _codec ("Motion-JPEG format B");
13163 caps = gst_caps_new_empty_simple ("video/x-mjpeg-b");
13166 _codec ("JPEG-2000");
13167 /* override to what it should be according to spec, avoid palette_data */
13168 stream->bits_per_sample = 24;
13169 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
13172 _codec ("Sorensen video v.3");
13173 caps = gst_caps_new_simple ("video/x-svq",
13174 "svqversion", G_TYPE_INT, 3, NULL);
13176 case GST_MAKE_FOURCC ('s', 'v', 'q', 'i'):
13177 case GST_MAKE_FOURCC ('S', 'V', 'Q', '1'):
13178 _codec ("Sorensen video v.1");
13179 caps = gst_caps_new_simple ("video/x-svq",
13180 "svqversion", G_TYPE_INT, 1, NULL);
13182 case GST_MAKE_FOURCC ('W', 'R', 'A', 'W'):
13183 caps = gst_caps_new_empty_simple ("video/x-raw");
13184 gst_caps_set_simple (caps, "format", G_TYPE_STRING, "RGB8P", NULL);
13185 _codec ("Windows Raw RGB");
13186 stream->alignment = 32;
13192 bps = QT_UINT16 (stsd_data + 98);
13195 format = GST_VIDEO_FORMAT_RGB15;
13198 format = GST_VIDEO_FORMAT_RGB16;
13201 format = GST_VIDEO_FORMAT_RGB;
13204 format = GST_VIDEO_FORMAT_ARGB;
13212 case GST_MAKE_FOURCC ('y', 'v', '1', '2'):
13213 format = GST_VIDEO_FORMAT_I420;
13215 case GST_MAKE_FOURCC ('y', 'u', 'v', '2'):
13216 case GST_MAKE_FOURCC ('Y', 'u', 'v', '2'):
13217 format = GST_VIDEO_FORMAT_I420;
13220 case GST_MAKE_FOURCC ('2', 'V', 'u', 'y'):
13221 format = GST_VIDEO_FORMAT_UYVY;
13223 case GST_MAKE_FOURCC ('v', '3', '0', '8'):
13224 format = GST_VIDEO_FORMAT_v308;
13226 case GST_MAKE_FOURCC ('v', '2', '1', '6'):
13227 format = GST_VIDEO_FORMAT_v216;
13230 format = GST_VIDEO_FORMAT_v210;
13232 case GST_MAKE_FOURCC ('r', '2', '1', '0'):
13233 format = GST_VIDEO_FORMAT_r210;
13235 /* Packed YUV 4:4:4 10 bit in 32 bits, complex
13236 case GST_MAKE_FOURCC ('v', '4', '1', '0'):
13237 format = GST_VIDEO_FORMAT_v410;
13240 /* Packed YUV 4:4:4:4 8 bit in 32 bits
13241 * but different order than AYUV
13242 case GST_MAKE_FOURCC ('v', '4', '0', '8'):
13243 format = GST_VIDEO_FORMAT_v408;
13246 case GST_MAKE_FOURCC ('m', 'p', 'e', 'g'):
13247 case GST_MAKE_FOURCC ('m', 'p', 'g', '1'):
13248 _codec ("MPEG-1 video");
13249 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
13250 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13252 case GST_MAKE_FOURCC ('h', 'd', 'v', '1'): /* HDV 720p30 */
13253 case GST_MAKE_FOURCC ('h', 'd', 'v', '2'): /* HDV 1080i60 */
13254 case GST_MAKE_FOURCC ('h', 'd', 'v', '3'): /* HDV 1080i50 */
13255 case GST_MAKE_FOURCC ('h', 'd', 'v', '4'): /* HDV 720p24 */
13256 case GST_MAKE_FOURCC ('h', 'd', 'v', '5'): /* HDV 720p25 */
13257 case GST_MAKE_FOURCC ('h', 'd', 'v', '6'): /* HDV 1080p24 */
13258 case GST_MAKE_FOURCC ('h', 'd', 'v', '7'): /* HDV 1080p25 */
13259 case GST_MAKE_FOURCC ('h', 'd', 'v', '8'): /* HDV 1080p30 */
13260 case GST_MAKE_FOURCC ('h', 'd', 'v', '9'): /* HDV 720p60 */
13261 case GST_MAKE_FOURCC ('h', 'd', 'v', 'a'): /* HDV 720p50 */
13262 case GST_MAKE_FOURCC ('m', 'x', '5', 'n'): /* MPEG2 IMX NTSC 525/60 50mb/s produced by FCP */
13263 case GST_MAKE_FOURCC ('m', 'x', '5', 'p'): /* MPEG2 IMX PAL 625/60 50mb/s produced by FCP */
13264 case GST_MAKE_FOURCC ('m', 'x', '4', 'n'): /* MPEG2 IMX NTSC 525/60 40mb/s produced by FCP */
13265 case GST_MAKE_FOURCC ('m', 'x', '4', 'p'): /* MPEG2 IMX PAL 625/60 40mb/s produced by FCP */
13266 case GST_MAKE_FOURCC ('m', 'x', '3', 'n'): /* MPEG2 IMX NTSC 525/60 30mb/s produced by FCP */
13267 case GST_MAKE_FOURCC ('m', 'x', '3', 'p'): /* MPEG2 IMX PAL 625/50 30mb/s produced by FCP */
13268 case GST_MAKE_FOURCC ('x', 'd', 'v', '1'): /* XDCAM HD 720p30 35Mb/s */
13269 case GST_MAKE_FOURCC ('x', 'd', 'v', '2'): /* XDCAM HD 1080i60 35Mb/s */
13270 case GST_MAKE_FOURCC ('x', 'd', 'v', '3'): /* XDCAM HD 1080i50 35Mb/s */
13271 case GST_MAKE_FOURCC ('x', 'd', 'v', '4'): /* XDCAM HD 720p24 35Mb/s */
13272 case GST_MAKE_FOURCC ('x', 'd', 'v', '5'): /* XDCAM HD 720p25 35Mb/s */
13273 case GST_MAKE_FOURCC ('x', 'd', 'v', '6'): /* XDCAM HD 1080p24 35Mb/s */
13274 case GST_MAKE_FOURCC ('x', 'd', 'v', '7'): /* XDCAM HD 1080p25 35Mb/s */
13275 case GST_MAKE_FOURCC ('x', 'd', 'v', '8'): /* XDCAM HD 1080p30 35Mb/s */
13276 case GST_MAKE_FOURCC ('x', 'd', 'v', '9'): /* XDCAM HD 720p60 35Mb/s */
13277 case GST_MAKE_FOURCC ('x', 'd', 'v', 'a'): /* XDCAM HD 720p50 35Mb/s */
13278 case GST_MAKE_FOURCC ('x', 'd', 'v', 'b'): /* XDCAM EX 1080i60 50Mb/s CBR */
13279 case GST_MAKE_FOURCC ('x', 'd', 'v', 'c'): /* XDCAM EX 1080i50 50Mb/s CBR */
13280 case GST_MAKE_FOURCC ('x', 'd', 'v', 'd'): /* XDCAM HD 1080p24 50Mb/s CBR */
13281 case GST_MAKE_FOURCC ('x', 'd', 'v', 'e'): /* XDCAM HD 1080p25 50Mb/s CBR */
13282 case GST_MAKE_FOURCC ('x', 'd', 'v', 'f'): /* XDCAM HD 1080p30 50Mb/s CBR */
13283 case GST_MAKE_FOURCC ('x', 'd', '5', '1'): /* XDCAM HD422 720p30 50Mb/s CBR */
13284 case GST_MAKE_FOURCC ('x', 'd', '5', '4'): /* XDCAM HD422 720p24 50Mb/s CBR */
13285 case GST_MAKE_FOURCC ('x', 'd', '5', '5'): /* XDCAM HD422 720p25 50Mb/s CBR */
13286 case GST_MAKE_FOURCC ('x', 'd', '5', '9'): /* XDCAM HD422 720p60 50Mb/s CBR */
13287 case GST_MAKE_FOURCC ('x', 'd', '5', 'a'): /* XDCAM HD422 720p50 50Mb/s CBR */
13288 case GST_MAKE_FOURCC ('x', 'd', '5', 'b'): /* XDCAM HD422 1080i50 50Mb/s CBR */
13289 case GST_MAKE_FOURCC ('x', 'd', '5', 'c'): /* XDCAM HD422 1080i50 50Mb/s CBR */
13290 case GST_MAKE_FOURCC ('x', 'd', '5', 'd'): /* XDCAM HD422 1080p24 50Mb/s CBR */
13291 case GST_MAKE_FOURCC ('x', 'd', '5', 'e'): /* XDCAM HD422 1080p25 50Mb/s CBR */
13292 case GST_MAKE_FOURCC ('x', 'd', '5', 'f'): /* XDCAM HD422 1080p30 50Mb/s CBR */
13293 case GST_MAKE_FOURCC ('x', 'd', 'h', 'd'): /* XDCAM HD 540p */
13294 case GST_MAKE_FOURCC ('x', 'd', 'h', '2'): /* XDCAM HD422 540p */
13295 case GST_MAKE_FOURCC ('A', 'V', 'm', 'p'): /* AVID IMX PAL */
13296 case GST_MAKE_FOURCC ('m', 'p', 'g', '2'): /* AVID IMX PAL */
13297 case GST_MAKE_FOURCC ('m', 'p', '2', 'v'): /* AVID IMX PAL */
13298 _codec ("MPEG-2 video");
13299 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 2,
13300 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13302 case GST_MAKE_FOURCC ('g', 'i', 'f', ' '):
13303 _codec ("GIF still images");
13304 caps = gst_caps_new_empty_simple ("image/gif");
13307 case GST_MAKE_FOURCC ('H', '2', '6', '3'):
13309 case GST_MAKE_FOURCC ('U', '2', '6', '3'):
13311 /* ffmpeg uses the height/width props, don't know why */
13312 caps = gst_caps_new_simple ("video/x-h263",
13313 "variant", G_TYPE_STRING, "itu", NULL);
13317 _codec ("MPEG-4 video");
13318 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
13319 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13321 case GST_MAKE_FOURCC ('3', 'i', 'v', 'd'):
13322 case GST_MAKE_FOURCC ('3', 'I', 'V', 'D'):
13323 _codec ("Microsoft MPEG-4 4.3"); /* FIXME? */
13324 caps = gst_caps_new_simple ("video/x-msmpeg",
13325 "msmpegversion", G_TYPE_INT, 43, NULL);
13327 case GST_MAKE_FOURCC ('D', 'I', 'V', '3'):
13329 caps = gst_caps_new_simple ("video/x-divx",
13330 "divxversion", G_TYPE_INT, 3, NULL);
13332 case GST_MAKE_FOURCC ('D', 'I', 'V', 'X'):
13333 case GST_MAKE_FOURCC ('d', 'i', 'v', 'x'):
13335 caps = gst_caps_new_simple ("video/x-divx",
13336 "divxversion", G_TYPE_INT, 4, NULL);
13338 case GST_MAKE_FOURCC ('D', 'X', '5', '0'):
13340 caps = gst_caps_new_simple ("video/x-divx",
13341 "divxversion", G_TYPE_INT, 5, NULL);
13344 case GST_MAKE_FOURCC ('F', 'F', 'V', '1'):
13346 caps = gst_caps_new_simple ("video/x-ffv",
13347 "ffvversion", G_TYPE_INT, 1, NULL);
13350 case GST_MAKE_FOURCC ('3', 'I', 'V', '1'):
13351 case GST_MAKE_FOURCC ('3', 'I', 'V', '2'):
13352 case GST_MAKE_FOURCC ('X', 'V', 'I', 'D'):
13353 case GST_MAKE_FOURCC ('x', 'v', 'i', 'd'):
13355 case GST_MAKE_FOURCC ('U', 'M', 'P', '4'):
13356 caps = gst_caps_new_simple ("video/mpeg",
13357 "mpegversion", G_TYPE_INT, 4, NULL);
13361 case GST_MAKE_FOURCC ('c', 'v', 'i', 'd'):
13362 _codec ("Cinepak");
13363 caps = gst_caps_new_empty_simple ("video/x-cinepak");
13365 case GST_MAKE_FOURCC ('q', 'd', 'r', 'w'):
13366 _codec ("Apple QuickDraw");
13367 caps = gst_caps_new_empty_simple ("video/x-qdrw");
13369 case GST_MAKE_FOURCC ('r', 'p', 'z', 'a'):
13370 _codec ("Apple video");
13371 caps = gst_caps_new_empty_simple ("video/x-apple-video");
13375 _codec ("H.264 / AVC");
13376 caps = gst_caps_new_simple ("video/x-h264",
13377 "stream-format", G_TYPE_STRING, "avc",
13378 "alignment", G_TYPE_STRING, "au", NULL);
13381 _codec ("H.264 / AVC");
13382 caps = gst_caps_new_simple ("video/x-h264",
13383 "stream-format", G_TYPE_STRING, "avc3",
13384 "alignment", G_TYPE_STRING, "au", NULL);
13388 _codec ("H.265 / HEVC");
13389 caps = gst_caps_new_simple ("video/x-h265",
13390 "stream-format", G_TYPE_STRING, "hvc1",
13391 "alignment", G_TYPE_STRING, "au", NULL);
13394 _codec ("H.265 / HEVC");
13395 caps = gst_caps_new_simple ("video/x-h265",
13396 "stream-format", G_TYPE_STRING, "hev1",
13397 "alignment", G_TYPE_STRING, "au", NULL);
13400 _codec ("Run-length encoding");
13401 caps = gst_caps_new_simple ("video/x-rle",
13402 "layout", G_TYPE_STRING, "quicktime", NULL);
13405 _codec ("Run-length encoding");
13406 caps = gst_caps_new_simple ("video/x-rle",
13407 "layout", G_TYPE_STRING, "microsoft", NULL);
13409 case GST_MAKE_FOURCC ('I', 'V', '3', '2'):
13410 case GST_MAKE_FOURCC ('i', 'v', '3', '2'):
13411 _codec ("Indeo Video 3");
13412 caps = gst_caps_new_simple ("video/x-indeo",
13413 "indeoversion", G_TYPE_INT, 3, NULL);
13415 case GST_MAKE_FOURCC ('I', 'V', '4', '1'):
13416 case GST_MAKE_FOURCC ('i', 'v', '4', '1'):
13417 _codec ("Intel Video 4");
13418 caps = gst_caps_new_simple ("video/x-indeo",
13419 "indeoversion", G_TYPE_INT, 4, NULL);
13423 case GST_MAKE_FOURCC ('d', 'v', 's', 'd'):
13424 case GST_MAKE_FOURCC ('D', 'V', 'S', 'D'):
13425 case GST_MAKE_FOURCC ('d', 'v', 'c', 's'):
13426 case GST_MAKE_FOURCC ('D', 'V', 'C', 'S'):
13427 case GST_MAKE_FOURCC ('d', 'v', '2', '5'):
13428 case GST_MAKE_FOURCC ('d', 'v', 'p', 'p'):
13429 _codec ("DV Video");
13430 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 25,
13431 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13433 case FOURCC_dv5n: /* DVCPRO50 NTSC */
13434 case FOURCC_dv5p: /* DVCPRO50 PAL */
13435 _codec ("DVCPro50 Video");
13436 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 50,
13437 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13439 case GST_MAKE_FOURCC ('d', 'v', 'h', '5'): /* DVCPRO HD 50i produced by FCP */
13440 case GST_MAKE_FOURCC ('d', 'v', 'h', '6'): /* DVCPRO HD 60i produced by FCP */
13441 _codec ("DVCProHD Video");
13442 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 100,
13443 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13445 case GST_MAKE_FOURCC ('s', 'm', 'c', ' '):
13446 _codec ("Apple Graphics (SMC)");
13447 caps = gst_caps_new_empty_simple ("video/x-smc");
13449 case GST_MAKE_FOURCC ('V', 'P', '3', '1'):
13451 caps = gst_caps_new_empty_simple ("video/x-vp3");
13453 case GST_MAKE_FOURCC ('V', 'P', '6', 'F'):
13454 _codec ("VP6 Flash");
13455 caps = gst_caps_new_empty_simple ("video/x-vp6-flash");
13459 caps = gst_caps_new_empty_simple ("video/x-theora");
13460 /* theora uses one byte of padding in the data stream because it does not
13461 * allow 0 sized packets while theora does */
13462 stream->padding = 1;
13466 caps = gst_caps_new_empty_simple ("video/x-dirac");
13468 case GST_MAKE_FOURCC ('t', 'i', 'f', 'f'):
13469 _codec ("TIFF still images");
13470 caps = gst_caps_new_empty_simple ("image/tiff");
13472 case GST_MAKE_FOURCC ('i', 'c', 'o', 'd'):
13473 _codec ("Apple Intermediate Codec");
13474 caps = gst_caps_from_string ("video/x-apple-intermediate-codec");
13476 case GST_MAKE_FOURCC ('A', 'V', 'd', 'n'):
13477 _codec ("AVID DNxHD");
13478 caps = gst_caps_from_string ("video/x-dnxhd");
13481 _codec ("On2 VP8");
13482 caps = gst_caps_from_string ("video/x-vp8");
13485 _codec ("Apple ProRes LT");
13487 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "lt",
13491 _codec ("Apple ProRes HQ");
13493 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "hq",
13497 _codec ("Apple ProRes");
13499 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
13503 _codec ("Apple ProRes Proxy");
13505 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
13509 _codec ("Apple ProRes 4444");
13511 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
13515 _codec ("Apple ProRes 4444 XQ");
13517 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
13523 caps = gst_caps_new_simple ("video/x-wmv",
13524 "wmvversion", G_TYPE_INT, 3, "format", G_TYPE_STRING, "WVC1", NULL);
13526 case GST_MAKE_FOURCC ('k', 'p', 'c', 'd'):
13529 char *s, fourstr[5];
13531 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
13532 s = g_strdup_printf ("video/x-gst-fourcc-%s", g_strstrip (fourstr));
13533 caps = gst_caps_new_empty_simple (s);
13539 if (format != GST_VIDEO_FORMAT_UNKNOWN) {
13542 gst_video_info_init (&info);
13543 gst_video_info_set_format (&info, format, stream->width, stream->height);
13545 caps = gst_video_info_to_caps (&info);
13546 *codec_name = gst_pb_utils_get_codec_description (caps);
13548 /* enable clipping for raw video streams */
13549 stream->need_clip = TRUE;
13550 stream->alignment = 32;
13557 round_up_pow2 (guint n)
13569 qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
13570 guint32 fourcc, const guint8 * data, int len, gchar ** codec_name)
13573 const GstStructure *s;
13576 GstAudioFormat format = 0;
13579 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
13581 depth = stream->bytes_per_packet * 8;
13584 case GST_MAKE_FOURCC ('N', 'O', 'N', 'E'):
13586 /* 8-bit audio is unsigned */
13588 format = GST_AUDIO_FORMAT_U8;
13589 /* otherwise it's signed and big-endian just like 'twos' */
13591 endian = G_BIG_ENDIAN;
13598 endian = G_LITTLE_ENDIAN;
13601 format = gst_audio_format_build_integer (TRUE, endian, depth, depth);
13603 str = g_strdup_printf ("Raw %d-bit PCM audio", depth);
13607 caps = gst_caps_new_simple ("audio/x-raw",
13608 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
13609 "layout", G_TYPE_STRING, "interleaved", NULL);
13610 stream->alignment = GST_ROUND_UP_8 (depth);
13611 stream->alignment = round_up_pow2 (stream->alignment);
13614 case GST_MAKE_FOURCC ('f', 'l', '6', '4'):
13615 _codec ("Raw 64-bit floating-point audio");
13616 caps = gst_caps_new_simple ("audio/x-raw",
13617 "format", G_TYPE_STRING, "F64BE",
13618 "layout", G_TYPE_STRING, "interleaved", NULL);
13619 stream->alignment = 8;
13621 case GST_MAKE_FOURCC ('f', 'l', '3', '2'):
13622 _codec ("Raw 32-bit floating-point audio");
13623 caps = gst_caps_new_simple ("audio/x-raw",
13624 "format", G_TYPE_STRING, "F32BE",
13625 "layout", G_TYPE_STRING, "interleaved", NULL);
13626 stream->alignment = 4;
13629 _codec ("Raw 24-bit PCM audio");
13630 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
13632 caps = gst_caps_new_simple ("audio/x-raw",
13633 "format", G_TYPE_STRING, "S24BE",
13634 "layout", G_TYPE_STRING, "interleaved", NULL);
13635 stream->alignment = 4;
13637 case GST_MAKE_FOURCC ('i', 'n', '3', '2'):
13638 _codec ("Raw 32-bit PCM audio");
13639 caps = gst_caps_new_simple ("audio/x-raw",
13640 "format", G_TYPE_STRING, "S32BE",
13641 "layout", G_TYPE_STRING, "interleaved", NULL);
13642 stream->alignment = 4;
13645 _codec ("Mu-law audio");
13646 caps = gst_caps_new_empty_simple ("audio/x-mulaw");
13649 _codec ("A-law audio");
13650 caps = gst_caps_new_empty_simple ("audio/x-alaw");
13654 _codec ("Microsoft ADPCM");
13655 /* Microsoft ADPCM-ACM code 2 */
13656 caps = gst_caps_new_simple ("audio/x-adpcm",
13657 "layout", G_TYPE_STRING, "microsoft", NULL);
13661 _codec ("DVI/IMA ADPCM");
13662 caps = gst_caps_new_simple ("audio/x-adpcm",
13663 "layout", G_TYPE_STRING, "dvi", NULL);
13667 _codec ("DVI/Intel IMA ADPCM");
13668 /* FIXME DVI/Intel IMA ADPCM/ACM code 17 */
13669 caps = gst_caps_new_simple ("audio/x-adpcm",
13670 "layout", G_TYPE_STRING, "quicktime", NULL);
13674 /* MPEG layer 3, CBR only (pre QT4.1) */
13676 _codec ("MPEG-1 layer 3");
13677 /* MPEG layer 3, CBR & VBR (QT4.1 and later) */
13678 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 3,
13679 "mpegversion", G_TYPE_INT, 1, NULL);
13682 case GST_MAKE_FOURCC ('e', 'c', '-', '3'):
13683 _codec ("EAC-3 audio");
13684 caps = gst_caps_new_simple ("audio/x-eac3",
13685 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
13686 stream->sampled = TRUE;
13688 case GST_MAKE_FOURCC ('s', 'a', 'c', '3'): // Nero Recode
13690 _codec ("AC-3 audio");
13691 caps = gst_caps_new_simple ("audio/x-ac3",
13692 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
13693 stream->sampled = TRUE;
13695 case GST_MAKE_FOURCC ('d', 't', 's', 'c'):
13696 case GST_MAKE_FOURCC ('D', 'T', 'S', ' '):
13697 _codec ("DTS audio");
13698 caps = gst_caps_new_simple ("audio/x-dts",
13699 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
13700 stream->sampled = TRUE;
13702 case GST_MAKE_FOURCC ('d', 't', 's', 'h'): // DTS-HD
13703 case GST_MAKE_FOURCC ('d', 't', 's', 'l'): // DTS-HD Lossless
13704 _codec ("DTS-HD audio");
13705 caps = gst_caps_new_simple ("audio/x-dts",
13706 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
13707 stream->sampled = TRUE;
13711 caps = gst_caps_new_simple ("audio/x-mace",
13712 "maceversion", G_TYPE_INT, 3, NULL);
13716 caps = gst_caps_new_simple ("audio/x-mace",
13717 "maceversion", G_TYPE_INT, 6, NULL);
13719 case GST_MAKE_FOURCC ('O', 'g', 'g', 'V'):
13721 caps = gst_caps_new_empty_simple ("application/ogg");
13723 case GST_MAKE_FOURCC ('d', 'v', 'c', 'a'):
13724 _codec ("DV audio");
13725 caps = gst_caps_new_empty_simple ("audio/x-dv");
13728 _codec ("MPEG-4 AAC audio");
13729 caps = gst_caps_new_simple ("audio/mpeg",
13730 "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE,
13731 "stream-format", G_TYPE_STRING, "raw", NULL);
13733 case GST_MAKE_FOURCC ('Q', 'D', 'M', 'C'):
13734 _codec ("QDesign Music");
13735 caps = gst_caps_new_empty_simple ("audio/x-qdm");
13738 _codec ("QDesign Music v.2");
13739 /* FIXME: QDesign music version 2 (no constant) */
13740 if (FALSE && data) {
13741 caps = gst_caps_new_simple ("audio/x-qdm2",
13742 "framesize", G_TYPE_INT, QT_UINT32 (data + 52),
13743 "bitrate", G_TYPE_INT, QT_UINT32 (data + 40),
13744 "blocksize", G_TYPE_INT, QT_UINT32 (data + 44), NULL);
13746 caps = gst_caps_new_empty_simple ("audio/x-qdm2");
13750 _codec ("GSM audio");
13751 caps = gst_caps_new_empty_simple ("audio/x-gsm");
13754 _codec ("AMR audio");
13755 caps = gst_caps_new_empty_simple ("audio/AMR");
13758 _codec ("AMR-WB audio");
13759 caps = gst_caps_new_empty_simple ("audio/AMR-WB");
13762 _codec ("Quicktime IMA ADPCM");
13763 caps = gst_caps_new_simple ("audio/x-adpcm",
13764 "layout", G_TYPE_STRING, "quicktime", NULL);
13767 _codec ("Apple lossless audio");
13768 caps = gst_caps_new_empty_simple ("audio/x-alac");
13771 _codec ("Free Lossless Audio Codec");
13772 caps = gst_caps_new_simple ("audio/x-flac",
13773 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
13775 case GST_MAKE_FOURCC ('Q', 'c', 'l', 'p'):
13776 _codec ("QualComm PureVoice");
13777 caps = gst_caps_from_string ("audio/qcelp");
13782 caps = gst_caps_new_empty_simple ("audio/x-wma");
13786 caps = gst_caps_new_empty_simple ("audio/x-opus");
13788 case GST_MAKE_FOURCC ('l', 'p', 'c', 'm'):
13793 GstAudioFormat format;
13796 FLAG_IS_FLOAT = 0x1,
13797 FLAG_IS_BIG_ENDIAN = 0x2,
13798 FLAG_IS_SIGNED = 0x4,
13799 FLAG_IS_PACKED = 0x8,
13800 FLAG_IS_ALIGNED_HIGH = 0x10,
13801 FLAG_IS_NON_INTERLEAVED = 0x20
13803 _codec ("Raw LPCM audio");
13805 if (data && len >= 56) {
13806 depth = QT_UINT32 (data + 40);
13807 flags = QT_UINT32 (data + 44);
13808 width = QT_UINT32 (data + 48) * 8 / stream->n_channels;
13810 if ((flags & FLAG_IS_FLOAT) == 0) {
13815 format = gst_audio_format_build_integer ((flags & FLAG_IS_SIGNED) ?
13816 TRUE : FALSE, (flags & FLAG_IS_BIG_ENDIAN) ?
13817 G_BIG_ENDIAN : G_LITTLE_ENDIAN, width, depth);
13818 caps = gst_caps_new_simple ("audio/x-raw",
13819 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
13820 "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
13821 "non-interleaved" : "interleaved", NULL);
13822 stream->alignment = GST_ROUND_UP_8 (depth);
13823 stream->alignment = round_up_pow2 (stream->alignment);
13828 if (flags & FLAG_IS_BIG_ENDIAN)
13829 format = GST_AUDIO_FORMAT_F64BE;
13831 format = GST_AUDIO_FORMAT_F64LE;
13833 if (flags & FLAG_IS_BIG_ENDIAN)
13834 format = GST_AUDIO_FORMAT_F32BE;
13836 format = GST_AUDIO_FORMAT_F32LE;
13838 caps = gst_caps_new_simple ("audio/x-raw",
13839 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
13840 "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
13841 "non-interleaved" : "interleaved", NULL);
13842 stream->alignment = width / 8;
13846 case GST_MAKE_FOURCC ('q', 't', 'v', 'r'):
13850 char *s, fourstr[5];
13852 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
13853 s = g_strdup_printf ("audio/x-gst-fourcc-%s", g_strstrip (fourstr));
13854 caps = gst_caps_new_empty_simple (s);
13861 GstCaps *templ_caps =
13862 gst_static_pad_template_get_caps (&gst_qtdemux_audiosrc_template);
13863 GstCaps *intersection = gst_caps_intersect (caps, templ_caps);
13864 gst_caps_unref (caps);
13865 gst_caps_unref (templ_caps);
13866 caps = intersection;
13869 /* enable clipping for raw audio streams */
13870 s = gst_caps_get_structure (caps, 0);
13871 name = gst_structure_get_name (s);
13872 if (g_str_has_prefix (name, "audio/x-raw")) {
13873 stream->need_clip = TRUE;
13874 stream->max_buffer_size = 4096 * stream->bytes_per_frame;
13875 GST_DEBUG ("setting max buffer size to %d", stream->max_buffer_size);
13881 qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
13882 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
13886 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
13890 _codec ("DVD subtitle");
13891 caps = gst_caps_new_empty_simple ("subpicture/x-dvd");
13892 stream->need_process = TRUE;
13895 _codec ("Quicktime timed text");
13898 _codec ("3GPP timed text");
13900 caps = gst_caps_new_simple ("text/x-raw", "format", G_TYPE_STRING,
13902 /* actual text piece needs to be extracted */
13903 stream->need_process = TRUE;
13906 _codec ("XML subtitles");
13907 caps = gst_caps_new_empty_simple ("application/ttml+xml");
13911 char *s, fourstr[5];
13913 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
13914 s = g_strdup_printf ("text/x-gst-fourcc-%s", g_strstrip (fourstr));
13915 caps = gst_caps_new_empty_simple (s);
13924 qtdemux_generic_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
13925 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
13931 _codec ("MPEG 1 video");
13932 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
13933 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13943 gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux,
13944 const gchar * system_id)
13948 if (!qtdemux->protection_system_ids)
13949 qtdemux->protection_system_ids =
13950 g_ptr_array_new_with_free_func ((GDestroyNotify) g_free);
13951 /* Check whether we already have an entry for this system ID. */
13952 for (i = 0; i < qtdemux->protection_system_ids->len; ++i) {
13953 const gchar *id = g_ptr_array_index (qtdemux->protection_system_ids, i);
13954 if (g_ascii_strcasecmp (system_id, id) == 0) {
13958 GST_DEBUG_OBJECT (qtdemux, "Adding cenc protection system ID %s", system_id);
13959 g_ptr_array_add (qtdemux->protection_system_ids, g_ascii_strdown (system_id,