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;
285 guint interlace_mode;
291 guint samples_per_packet;
292 guint samples_per_frame;
293 guint bytes_per_packet;
294 guint bytes_per_sample;
295 guint bytes_per_frame;
299 gboolean use_allocator;
300 GstAllocator *allocator;
301 GstAllocationParams params;
305 /* when a discontinuity is pending */
308 /* list of buffers to push first */
311 /* if we need to clip this buffer. This is only needed for uncompressed
315 /* buffer needs some custom processing, e.g. subtitles */
316 gboolean need_process;
318 /* current position */
319 guint32 segment_index;
320 guint32 sample_index;
321 GstClockTime time_position; /* in gst time */
322 guint64 accumulated_base;
324 /* the Gst segment we are processing out, used for clipping */
327 /* quicktime segments */
329 QtDemuxSegment *segments;
330 gboolean dummy_segment;
335 GstTagList *pending_tags;
336 gboolean send_global_tags;
338 GstEvent *pending_event;
348 gboolean chunks_are_samples; /* TRUE means treat chunks as samples */
352 GstByteReader co_chunk;
354 guint32 current_chunk;
356 guint32 samples_per_chunk;
357 guint32 stco_sample_index;
359 guint32 sample_size; /* 0 means variable sizes are stored in stsz */
362 guint32 n_samples_per_chunk;
363 guint32 stsc_chunk_index;
364 guint32 stsc_sample_index;
365 guint64 chunk_offset;
368 guint32 stts_samples;
369 guint32 n_sample_times;
370 guint32 stts_sample_index;
372 guint32 stts_duration;
374 gboolean stss_present;
375 guint32 n_sample_syncs;
378 gboolean stps_present;
379 guint32 n_sample_partial_syncs;
381 QtDemuxRandomAccessEntry *ra_entries;
384 const QtDemuxRandomAccessEntry *pending_seek;
387 gboolean ctts_present;
388 guint32 n_composition_times;
390 guint32 ctts_sample_index;
398 gboolean parsed_trex;
399 guint32 def_sample_duration;
400 guint32 def_sample_size;
401 guint32 def_sample_flags;
405 /* stereoscopic video streams */
406 GstVideoMultiviewMode multiview_mode;
407 GstVideoMultiviewFlags multiview_flags;
409 /* protected streams */
411 guint32 protection_scheme_type;
412 guint32 protection_scheme_version;
413 gpointer protection_scheme_info; /* specific to the protection scheme */
414 GQueue protection_scheme_event_queue;
417 /* Contains properties and cryptographic info for a set of samples from a
418 * track protected using Common Encryption (cenc) */
419 struct _QtDemuxCencSampleSetInfo
421 GstStructure *default_properties;
423 /* @crypto_info holds one GstStructure per sample */
424 GPtrArray *crypto_info;
428 qt_demux_state_string (enum QtDemuxState state)
431 case QTDEMUX_STATE_INITIAL:
433 case QTDEMUX_STATE_HEADER:
435 case QTDEMUX_STATE_MOVIE:
437 case QTDEMUX_STATE_BUFFER_MDAT:
438 return "<BUFFER_MDAT>";
444 static GNode *qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc);
445 static GNode *qtdemux_tree_get_child_by_type_full (GNode * node,
446 guint32 fourcc, GstByteReader * parser);
447 static GNode *qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc);
448 static GNode *qtdemux_tree_get_sibling_by_type_full (GNode * node,
449 guint32 fourcc, GstByteReader * parser);
451 static GstFlowReturn qtdemux_add_fragmented_samples (GstQTDemux * qtdemux);
453 static GstStaticPadTemplate gst_qtdemux_sink_template =
454 GST_STATIC_PAD_TEMPLATE ("sink",
457 GST_STATIC_CAPS ("video/quicktime; video/mj2; audio/x-m4a; "
461 static GstStaticPadTemplate gst_qtdemux_videosrc_template =
462 GST_STATIC_PAD_TEMPLATE ("video_%u",
465 GST_STATIC_CAPS_ANY);
467 static GstStaticPadTemplate gst_qtdemux_audiosrc_template =
468 GST_STATIC_PAD_TEMPLATE ("audio_%u",
471 GST_STATIC_CAPS_ANY);
473 static GstStaticPadTemplate gst_qtdemux_subsrc_template =
474 GST_STATIC_PAD_TEMPLATE ("subtitle_%u",
477 GST_STATIC_CAPS_ANY);
479 #define gst_qtdemux_parent_class parent_class
480 G_DEFINE_TYPE (GstQTDemux, gst_qtdemux, GST_TYPE_ELEMENT);
482 static void gst_qtdemux_dispose (GObject * object);
485 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
486 GstClockTime media_time);
488 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
489 QtDemuxStream * str, gint64 media_offset);
492 static void gst_qtdemux_set_index (GstElement * element, GstIndex * index);
493 static GstIndex *gst_qtdemux_get_index (GstElement * element);
495 static GstStateChangeReturn gst_qtdemux_change_state (GstElement * element,
496 GstStateChange transition);
497 static gboolean qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent);
498 static gboolean qtdemux_sink_activate_mode (GstPad * sinkpad,
499 GstObject * parent, GstPadMode mode, gboolean active);
501 static void gst_qtdemux_loop (GstPad * pad);
502 static GstFlowReturn gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent,
504 static gboolean gst_qtdemux_handle_sink_event (GstPad * pad, GstObject * parent,
506 static gboolean gst_qtdemux_setcaps (GstQTDemux * qtdemux, GstCaps * caps);
507 static gboolean gst_qtdemux_configure_stream (GstQTDemux * qtdemux,
508 QtDemuxStream * stream);
509 static GstFlowReturn gst_qtdemux_process_adapter (GstQTDemux * demux,
512 static gboolean qtdemux_parse_moov (GstQTDemux * qtdemux,
513 const guint8 * buffer, guint length);
514 static gboolean qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node,
515 const guint8 * buffer, guint length);
516 static gboolean qtdemux_parse_tree (GstQTDemux * qtdemux);
517 static void qtdemux_parse_udta (GstQTDemux * qtdemux, GstTagList * taglist,
520 static void gst_qtdemux_handle_esds (GstQTDemux * qtdemux,
521 QtDemuxStream * stream, GNode * esds, GstTagList * list);
522 static GstCaps *qtdemux_video_caps (GstQTDemux * qtdemux,
523 QtDemuxStream * stream, guint32 fourcc, const guint8 * stsd_data,
524 gchar ** codec_name);
525 static GstCaps *qtdemux_audio_caps (GstQTDemux * qtdemux,
526 QtDemuxStream * stream, guint32 fourcc, const guint8 * data, int len,
527 gchar ** codec_name);
528 static GstCaps *qtdemux_sub_caps (GstQTDemux * qtdemux,
529 QtDemuxStream * stream, guint32 fourcc, const guint8 * data,
530 gchar ** codec_name);
531 static GstCaps *qtdemux_generic_caps (GstQTDemux * qtdemux,
532 QtDemuxStream * stream, guint32 fourcc, const guint8 * stsd_data,
533 gchar ** codec_name);
535 static gboolean qtdemux_parse_samples (GstQTDemux * qtdemux,
536 QtDemuxStream * stream, guint32 n);
537 static GstFlowReturn qtdemux_expose_streams (GstQTDemux * qtdemux);
538 static void gst_qtdemux_stream_free (GstQTDemux * qtdemux,
539 QtDemuxStream * stream);
540 static void gst_qtdemux_stream_clear (GstQTDemux * qtdemux,
541 QtDemuxStream * stream);
542 static void gst_qtdemux_remove_stream (GstQTDemux * qtdemux, int index);
543 static GstFlowReturn qtdemux_prepare_streams (GstQTDemux * qtdemux);
544 static void qtdemux_do_allocation (GstQTDemux * qtdemux,
545 QtDemuxStream * stream);
546 static gboolean gst_qtdemux_activate_segment (GstQTDemux * qtdemux,
547 QtDemuxStream * stream, guint32 seg_idx, GstClockTime offset);
548 static gboolean gst_qtdemux_stream_update_segment (GstQTDemux * qtdemux,
549 QtDemuxStream * stream, gint seg_idx, GstClockTime offset,
550 GstClockTime * _start, GstClockTime * _stop);
551 static void gst_qtdemux_send_gap_for_segment (GstQTDemux * demux,
552 QtDemuxStream * stream, gint segment_index, GstClockTime pos);
554 static gboolean qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux);
555 static void check_update_duration (GstQTDemux * qtdemux, GstClockTime duration);
557 static gchar *qtdemux_uuid_bytes_to_string (gconstpointer uuid_bytes);
559 static GstStructure *qtdemux_get_cenc_sample_properties (GstQTDemux * qtdemux,
560 QtDemuxStream * stream, guint sample_index);
561 static void gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux,
563 static void qtdemux_gst_structure_free (GstStructure * gststructure);
566 gst_qtdemux_class_init (GstQTDemuxClass * klass)
568 GObjectClass *gobject_class;
569 GstElementClass *gstelement_class;
571 gobject_class = (GObjectClass *) klass;
572 gstelement_class = (GstElementClass *) klass;
574 parent_class = g_type_class_peek_parent (klass);
576 gobject_class->dispose = gst_qtdemux_dispose;
578 gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_qtdemux_change_state);
580 gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_qtdemux_set_index);
581 gstelement_class->get_index = GST_DEBUG_FUNCPTR (gst_qtdemux_get_index);
584 gst_tag_register_musicbrainz_tags ();
586 gst_element_class_add_static_pad_template (gstelement_class,
587 &gst_qtdemux_sink_template);
588 gst_element_class_add_static_pad_template (gstelement_class,
589 &gst_qtdemux_videosrc_template);
590 gst_element_class_add_static_pad_template (gstelement_class,
591 &gst_qtdemux_audiosrc_template);
592 gst_element_class_add_static_pad_template (gstelement_class,
593 &gst_qtdemux_subsrc_template);
594 gst_element_class_set_static_metadata (gstelement_class, "QuickTime demuxer",
596 "Demultiplex a QuickTime file into audio and video streams",
597 "David Schleef <ds@schleef.org>, Wim Taymans <wim@fluendo.com>");
599 GST_DEBUG_CATEGORY_INIT (qtdemux_debug, "qtdemux", 0, "qtdemux plugin");
604 gst_qtdemux_init (GstQTDemux * qtdemux)
607 gst_pad_new_from_static_template (&gst_qtdemux_sink_template, "sink");
608 gst_pad_set_activate_function (qtdemux->sinkpad, qtdemux_sink_activate);
609 gst_pad_set_activatemode_function (qtdemux->sinkpad,
610 qtdemux_sink_activate_mode);
611 gst_pad_set_chain_function (qtdemux->sinkpad, gst_qtdemux_chain);
612 gst_pad_set_event_function (qtdemux->sinkpad, gst_qtdemux_handle_sink_event);
613 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), qtdemux->sinkpad);
615 qtdemux->state = QTDEMUX_STATE_INITIAL;
616 qtdemux->pullbased = FALSE;
617 qtdemux->posted_redirect = FALSE;
618 qtdemux->neededbytes = 16;
620 qtdemux->adapter = gst_adapter_new ();
622 qtdemux->first_mdat = -1;
623 qtdemux->got_moov = FALSE;
624 qtdemux->mdatoffset = -1;
625 qtdemux->mdatbuffer = NULL;
626 qtdemux->restoredata_buffer = NULL;
627 qtdemux->restoredata_offset = -1;
628 qtdemux->fragment_start = -1;
629 qtdemux->fragment_start_offset = -1;
630 qtdemux->media_caps = NULL;
631 qtdemux->exposed = FALSE;
632 qtdemux->mss_mode = FALSE;
633 qtdemux->pending_newsegment = NULL;
634 qtdemux->upstream_format_is_time = FALSE;
635 qtdemux->have_group_id = FALSE;
636 qtdemux->group_id = G_MAXUINT;
637 qtdemux->cenc_aux_info_offset = 0;
638 qtdemux->cenc_aux_info_sizes = NULL;
639 qtdemux->cenc_aux_sample_count = 0;
640 qtdemux->protection_system_ids = NULL;
641 g_queue_init (&qtdemux->protection_event_queue);
642 gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
643 qtdemux->flowcombiner = gst_flow_combiner_new ();
645 GST_OBJECT_FLAG_SET (qtdemux, GST_ELEMENT_FLAG_INDEXABLE);
649 gst_qtdemux_dispose (GObject * object)
651 GstQTDemux *qtdemux = GST_QTDEMUX (object);
653 if (qtdemux->adapter) {
654 g_object_unref (G_OBJECT (qtdemux->adapter));
655 qtdemux->adapter = NULL;
657 gst_flow_combiner_free (qtdemux->flowcombiner);
658 g_queue_foreach (&qtdemux->protection_event_queue, (GFunc) gst_event_unref,
660 g_queue_clear (&qtdemux->protection_event_queue);
662 g_free (qtdemux->cenc_aux_info_sizes);
663 qtdemux->cenc_aux_info_sizes = NULL;
665 G_OBJECT_CLASS (parent_class)->dispose (object);
669 gst_qtdemux_post_no_playable_stream_error (GstQTDemux * qtdemux)
671 if (qtdemux->posted_redirect) {
672 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
673 (_("This file contains no playable streams.")),
674 ("no known streams found, a redirect message has been posted"));
676 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
677 (_("This file contains no playable streams.")),
678 ("no known streams found"));
683 _gst_buffer_new_wrapped (gpointer mem, gsize size, GFreeFunc free_func)
685 return gst_buffer_new_wrapped_full (free_func ? 0 : GST_MEMORY_FLAG_READONLY,
686 mem, size, 0, size, mem, free_func);
690 gst_qtdemux_pull_atom (GstQTDemux * qtdemux, guint64 offset, guint64 size,
697 if (G_UNLIKELY (size == 0)) {
699 GstBuffer *tmp = NULL;
701 ret = gst_qtdemux_pull_atom (qtdemux, offset, sizeof (guint32), &tmp);
702 if (ret != GST_FLOW_OK)
705 gst_buffer_map (tmp, &map, GST_MAP_READ);
706 size = QT_UINT32 (map.data);
707 GST_DEBUG_OBJECT (qtdemux, "size 0x%08" G_GINT64_MODIFIER "x", size);
709 gst_buffer_unmap (tmp, &map);
710 gst_buffer_unref (tmp);
713 /* Sanity check: catch bogus sizes (fuzzed/broken files) */
714 if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
715 if (qtdemux->state != QTDEMUX_STATE_MOVIE && qtdemux->got_moov) {
716 /* we're pulling header but already got most interesting bits,
717 * so never mind the rest (e.g. tags) (that much) */
718 GST_WARNING_OBJECT (qtdemux, "atom has bogus size %" G_GUINT64_FORMAT,
722 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
723 (_("This file is invalid and cannot be played.")),
724 ("atom has bogus size %" G_GUINT64_FORMAT, size));
725 return GST_FLOW_ERROR;
729 flow = gst_pad_pull_range (qtdemux->sinkpad, offset, size, buf);
731 if (G_UNLIKELY (flow != GST_FLOW_OK))
734 bsize = gst_buffer_get_size (*buf);
735 /* Catch short reads - we don't want any partial atoms */
736 if (G_UNLIKELY (bsize < size)) {
737 GST_WARNING_OBJECT (qtdemux,
738 "short read: %" G_GSIZE_FORMAT " < %" G_GUINT64_FORMAT, bsize, size);
739 gst_buffer_unref (*buf);
749 gst_qtdemux_src_convert (GstQTDemux * qtdemux, GstPad * pad,
750 GstFormat src_format, gint64 src_value, GstFormat dest_format,
754 QtDemuxStream *stream = gst_pad_get_element_private (pad);
757 if (stream->subtype != FOURCC_vide) {
762 switch (src_format) {
763 case GST_FORMAT_TIME:
764 switch (dest_format) {
765 case GST_FORMAT_BYTES:{
766 index = gst_qtdemux_find_index_linear (qtdemux, stream, src_value);
772 *dest_value = stream->samples[index].offset;
774 GST_DEBUG_OBJECT (qtdemux, "Format Conversion Time->Offset :%"
775 GST_TIME_FORMAT "->%" G_GUINT64_FORMAT,
776 GST_TIME_ARGS (src_value), *dest_value);
784 case GST_FORMAT_BYTES:
785 switch (dest_format) {
786 case GST_FORMAT_TIME:{
788 gst_qtdemux_find_index_for_given_media_offset_linear (qtdemux,
797 QTSTREAMTIME_TO_GSTTIME (stream,
798 stream->samples[index].timestamp);
799 GST_DEBUG_OBJECT (qtdemux,
800 "Format Conversion Offset->Time :%" G_GUINT64_FORMAT "->%"
801 GST_TIME_FORMAT, src_value, GST_TIME_ARGS (*dest_value));
820 gst_qtdemux_get_duration (GstQTDemux * qtdemux, GstClockTime * duration)
822 gboolean res = FALSE;
824 *duration = GST_CLOCK_TIME_NONE;
826 if (qtdemux->duration != 0 &&
827 qtdemux->duration != G_MAXINT64 && qtdemux->timescale != 0) {
828 *duration = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
831 *duration = GST_CLOCK_TIME_NONE;
838 gst_qtdemux_handle_src_query (GstPad * pad, GstObject * parent,
841 gboolean res = FALSE;
842 GstQTDemux *qtdemux = GST_QTDEMUX (parent);
844 GST_LOG_OBJECT (pad, "%s query", GST_QUERY_TYPE_NAME (query));
846 switch (GST_QUERY_TYPE (query)) {
847 case GST_QUERY_POSITION:{
850 gst_query_parse_position (query, &fmt, NULL);
851 if (fmt == GST_FORMAT_TIME
852 && GST_CLOCK_TIME_IS_VALID (qtdemux->segment.position)) {
853 gst_query_set_position (query, GST_FORMAT_TIME,
854 qtdemux->segment.position);
859 case GST_QUERY_DURATION:{
862 gst_query_parse_duration (query, &fmt, NULL);
863 if (fmt == GST_FORMAT_TIME) {
864 /* First try to query upstream */
865 res = gst_pad_query_default (pad, parent, query);
867 GstClockTime duration;
868 if (gst_qtdemux_get_duration (qtdemux, &duration) && duration > 0) {
869 gst_query_set_duration (query, GST_FORMAT_TIME, duration);
876 case GST_QUERY_CONVERT:{
877 GstFormat src_fmt, dest_fmt;
878 gint64 src_value, dest_value = 0;
880 gst_query_parse_convert (query, &src_fmt, &src_value, &dest_fmt, NULL);
882 res = gst_qtdemux_src_convert (qtdemux, pad,
883 src_fmt, src_value, dest_fmt, &dest_value);
885 gst_query_set_convert (query, src_fmt, src_value, dest_fmt, dest_value);
890 case GST_QUERY_FORMATS:
891 gst_query_set_formats (query, 2, GST_FORMAT_TIME, GST_FORMAT_BYTES);
894 case GST_QUERY_SEEKING:{
898 /* try upstream first */
899 res = gst_pad_query_default (pad, parent, query);
902 gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
903 if (fmt == GST_FORMAT_TIME) {
904 GstClockTime duration;
906 gst_qtdemux_get_duration (qtdemux, &duration);
908 if (!qtdemux->pullbased) {
911 /* we might be able with help from upstream */
913 q = gst_query_new_seeking (GST_FORMAT_BYTES);
914 if (gst_pad_peer_query (qtdemux->sinkpad, q)) {
915 gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL);
916 GST_LOG_OBJECT (qtdemux, "upstream BYTE seekable %d", seekable);
920 gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0, duration);
926 case GST_QUERY_SEGMENT:
931 format = qtdemux->segment.format;
934 gst_segment_to_stream_time (&qtdemux->segment, format,
935 qtdemux->segment.start);
936 if ((stop = qtdemux->segment.stop) == -1)
937 stop = qtdemux->segment.duration;
939 stop = gst_segment_to_stream_time (&qtdemux->segment, format, stop);
941 gst_query_set_segment (query, qtdemux->segment.rate, format, start, stop);
946 res = gst_pad_query_default (pad, parent, query);
954 gst_qtdemux_push_tags (GstQTDemux * qtdemux, QtDemuxStream * stream)
956 if (G_LIKELY (stream->pad)) {
957 GST_DEBUG_OBJECT (qtdemux, "Checking pad %s:%s for tags",
958 GST_DEBUG_PAD_NAME (stream->pad));
960 if (G_UNLIKELY (stream->pending_tags)) {
961 GST_DEBUG_OBJECT (qtdemux, "Sending tags %" GST_PTR_FORMAT,
962 stream->pending_tags);
963 gst_pad_push_event (stream->pad,
964 gst_event_new_tag (stream->pending_tags));
965 stream->pending_tags = NULL;
968 if (G_UNLIKELY (stream->send_global_tags && qtdemux->tag_list)) {
969 GST_DEBUG_OBJECT (qtdemux, "Sending global tags %" GST_PTR_FORMAT,
971 gst_pad_push_event (stream->pad,
972 gst_event_new_tag (gst_tag_list_ref (qtdemux->tag_list)));
973 stream->send_global_tags = FALSE;
978 /* push event on all source pads; takes ownership of the event */
980 gst_qtdemux_push_event (GstQTDemux * qtdemux, GstEvent * event)
983 gboolean has_valid_stream = FALSE;
984 GstEventType etype = GST_EVENT_TYPE (event);
986 GST_DEBUG_OBJECT (qtdemux, "pushing %s event on all source pads",
987 GST_EVENT_TYPE_NAME (event));
989 for (n = 0; n < qtdemux->n_streams; n++) {
991 QtDemuxStream *stream = qtdemux->streams[n];
992 GST_DEBUG_OBJECT (qtdemux, "pushing on pad %i", n);
994 if ((pad = stream->pad)) {
995 has_valid_stream = TRUE;
997 if (etype == GST_EVENT_EOS) {
998 /* let's not send twice */
999 if (stream->sent_eos)
1001 stream->sent_eos = TRUE;
1004 gst_pad_push_event (pad, gst_event_ref (event));
1008 gst_event_unref (event);
1010 /* if it is EOS and there are no pads, post an error */
1011 if (!has_valid_stream && etype == GST_EVENT_EOS) {
1012 gst_qtdemux_post_no_playable_stream_error (qtdemux);
1016 /* push a pending newsegment event, if any from the streaming thread */
1018 gst_qtdemux_push_pending_newsegment (GstQTDemux * qtdemux)
1020 if (qtdemux->pending_newsegment) {
1021 gst_qtdemux_push_event (qtdemux, qtdemux->pending_newsegment);
1022 qtdemux->pending_newsegment = NULL;
1032 find_func (QtDemuxSample * s1, gint64 * media_time, gpointer user_data)
1034 if ((gint64) s1->timestamp + s1->pts_offset > *media_time)
1036 if ((gint64) s1->timestamp + s1->pts_offset == *media_time)
1042 /* find the index of the sample that includes the data for @media_time using a
1043 * binary search. Only to be called in optimized cases of linear search below.
1045 * Returns the index of the sample.
1048 gst_qtdemux_find_index (GstQTDemux * qtdemux, QtDemuxStream * str,
1051 QtDemuxSample *result;
1054 /* convert media_time to mov format */
1056 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
1058 result = gst_util_array_binary_search (str->samples, str->stbl_index + 1,
1059 sizeof (QtDemuxSample), (GCompareDataFunc) find_func,
1060 GST_SEARCH_MODE_BEFORE, &media_time, NULL);
1062 if (G_LIKELY (result))
1063 index = result - str->samples;
1072 /* find the index of the sample that includes the data for @media_offset using a
1075 * Returns the index of the sample.
1078 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
1079 QtDemuxStream * str, gint64 media_offset)
1081 QtDemuxSample *result = str->samples;
1084 if (result == NULL || str->n_samples == 0)
1087 if (media_offset == result->offset)
1091 while (index < str->n_samples - 1) {
1092 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
1095 if (media_offset < result->offset)
1106 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
1111 /* find the index of the sample that includes the data for @media_time using a
1112 * linear search, and keeping in mind that not all samples may have been parsed
1113 * yet. If possible, it will delegate to binary search.
1115 * Returns the index of the sample.
1118 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
1119 GstClockTime media_time)
1123 QtDemuxSample *sample;
1125 /* convert media_time to mov format */
1127 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
1129 sample = str->samples;
1130 if (mov_time == sample->timestamp + sample->pts_offset)
1133 /* use faster search if requested time in already parsed range */
1134 sample = str->samples + str->stbl_index;
1135 if (str->stbl_index >= 0 &&
1136 mov_time <= (sample->timestamp + sample->pts_offset))
1137 return gst_qtdemux_find_index (qtdemux, str, media_time);
1139 while (index < str->n_samples - 1) {
1140 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
1143 sample = str->samples + index + 1;
1144 if (mov_time < (sample->timestamp + sample->pts_offset))
1154 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
1159 /* find the index of the keyframe needed to decode the sample at @index
1160 * of stream @str, or of a subsequent keyframe (depending on @next)
1162 * Returns the index of the keyframe.
1165 gst_qtdemux_find_keyframe (GstQTDemux * qtdemux, QtDemuxStream * str,
1166 guint32 index, gboolean next)
1168 guint32 new_index = index;
1170 if (index >= str->n_samples) {
1171 new_index = str->n_samples;
1175 /* all keyframes, return index */
1176 if (str->all_keyframe) {
1181 /* else search until we have a keyframe */
1182 while (new_index < str->n_samples) {
1183 if (next && !qtdemux_parse_samples (qtdemux, str, new_index))
1186 if (str->samples[new_index].keyframe)
1198 if (new_index == str->n_samples) {
1199 GST_DEBUG_OBJECT (qtdemux, "no next keyframe");
1204 GST_DEBUG_OBJECT (qtdemux, "searching for keyframe index %s index %u "
1205 "gave %u", next ? "after" : "before", index, new_index);
1212 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", new_index);
1217 /* find the segment for @time_position for @stream
1219 * Returns the index of the segment containing @time_position.
1220 * Returns the last segment and sets the @eos variable to TRUE
1221 * if the time is beyond the end. @eos may be NULL
1224 gst_qtdemux_find_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
1225 GstClockTime time_position)
1230 GST_LOG_OBJECT (stream->pad, "finding segment for %" GST_TIME_FORMAT,
1231 GST_TIME_ARGS (time_position));
1234 for (i = 0; i < stream->n_segments; i++) {
1235 QtDemuxSegment *segment = &stream->segments[i];
1237 GST_LOG_OBJECT (stream->pad,
1238 "looking at segment %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT,
1239 GST_TIME_ARGS (segment->time), GST_TIME_ARGS (segment->stop_time));
1241 /* For the last segment we include stop_time in the last segment */
1242 if (i < stream->n_segments - 1) {
1243 if (segment->time <= time_position && time_position < segment->stop_time) {
1244 GST_LOG_OBJECT (stream->pad, "segment %d matches", i);
1249 /* Last segment always matches */
1257 /* move the stream @str to the sample position @index.
1259 * Updates @str->sample_index and marks discontinuity if needed.
1262 gst_qtdemux_move_stream (GstQTDemux * qtdemux, QtDemuxStream * str,
1265 /* no change needed */
1266 if (index == str->sample_index)
1269 GST_DEBUG_OBJECT (qtdemux, "moving to sample %u of %u", index,
1272 /* position changed, we have a discont */
1273 str->sample_index = index;
1274 str->offset_in_sample = 0;
1275 /* Each time we move in the stream we store the position where we are
1277 str->from_sample = index;
1278 str->discont = TRUE;
1282 gst_qtdemux_adjust_seek (GstQTDemux * qtdemux, gint64 desired_time,
1283 gboolean use_sparse, gboolean next, gint64 * key_time, gint64 * key_offset)
1286 gint64 min_byte_offset = -1;
1289 min_offset = desired_time;
1291 /* for each stream, find the index of the sample in the segment
1292 * and move back to the previous keyframe. */
1293 for (n = 0; n < qtdemux->n_streams; n++) {
1295 guint32 index, kindex;
1297 GstClockTime media_start;
1298 GstClockTime media_time;
1299 GstClockTime seg_time;
1300 QtDemuxSegment *seg;
1301 gboolean empty_segment = FALSE;
1303 str = qtdemux->streams[n];
1305 if (str->sparse && !use_sparse)
1308 seg_idx = gst_qtdemux_find_segment (qtdemux, str, desired_time);
1309 GST_DEBUG_OBJECT (qtdemux, "align segment %d", seg_idx);
1311 /* get segment and time in the segment */
1312 seg = &str->segments[seg_idx];
1313 seg_time = (desired_time - seg->time) * seg->rate;
1315 while (QTSEGMENT_IS_EMPTY (seg)) {
1317 empty_segment = TRUE;
1318 GST_DEBUG_OBJECT (str->pad, "Segment %d is empty, moving to next one",
1321 if (seg_idx == str->n_segments)
1323 seg = &str->segments[seg_idx];
1326 if (seg_idx == str->n_segments) {
1327 /* FIXME track shouldn't have the last segment as empty, but if it
1328 * happens we better handle it */
1332 /* get the media time in the segment */
1333 media_start = seg->media_start + seg_time;
1335 /* get the index of the sample with media time */
1336 index = gst_qtdemux_find_index_linear (qtdemux, str, media_start);
1337 GST_DEBUG_OBJECT (qtdemux, "sample for %" GST_TIME_FORMAT " at %u"
1338 " at offset %" G_GUINT64_FORMAT " (empty segment: %d)",
1339 GST_TIME_ARGS (media_start), index, str->samples[index].offset,
1342 /* shift to next frame if we are looking for next keyframe */
1343 if (next && QTSAMPLE_PTS (str, &str->samples[index]) < media_start &&
1344 index < str->stbl_index)
1347 if (!empty_segment) {
1348 /* find previous keyframe */
1349 kindex = gst_qtdemux_find_keyframe (qtdemux, str, index, next);
1351 /* we will settle for one before if none found after */
1352 if (next && kindex == -1)
1353 kindex = gst_qtdemux_find_keyframe (qtdemux, str, index, FALSE);
1355 /* if the keyframe is at a different position, we need to update the
1356 * requested seek time */
1357 if (index != kindex) {
1360 /* get timestamp of keyframe */
1361 media_time = QTSAMPLE_PTS (str, &str->samples[kindex]);
1362 GST_DEBUG_OBJECT (qtdemux,
1363 "keyframe at %u with time %" GST_TIME_FORMAT " at offset %"
1364 G_GUINT64_FORMAT, kindex, GST_TIME_ARGS (media_time),
1365 str->samples[kindex].offset);
1367 /* keyframes in the segment get a chance to change the
1368 * desired_offset. keyframes out of the segment are
1370 if (media_time >= seg->media_start) {
1371 GstClockTime seg_time;
1373 /* this keyframe is inside the segment, convert back to
1375 seg_time = (media_time - seg->media_start) + seg->time;
1376 if ((!next && (seg_time < min_offset)) ||
1377 (next && (seg_time > min_offset)))
1378 min_offset = seg_time;
1383 if (min_byte_offset < 0 || str->samples[index].offset < min_byte_offset)
1384 min_byte_offset = str->samples[index].offset;
1388 *key_time = min_offset;
1390 *key_offset = min_byte_offset;
1394 gst_qtdemux_convert_seek (GstPad * pad, GstFormat * format,
1395 GstSeekType cur_type, gint64 * cur, GstSeekType stop_type, gint64 * stop)
1399 g_return_val_if_fail (format != NULL, FALSE);
1400 g_return_val_if_fail (cur != NULL, FALSE);
1401 g_return_val_if_fail (stop != NULL, FALSE);
1403 if (*format == GST_FORMAT_TIME)
1407 if (cur_type != GST_SEEK_TYPE_NONE)
1408 res = gst_pad_query_convert (pad, *format, *cur, GST_FORMAT_TIME, cur);
1409 if (res && stop_type != GST_SEEK_TYPE_NONE)
1410 res = gst_pad_query_convert (pad, *format, *stop, GST_FORMAT_TIME, stop);
1413 *format = GST_FORMAT_TIME;
1418 /* perform seek in push based mode:
1419 find BYTE position to move to based on time and delegate to upstream
1422 gst_qtdemux_do_push_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1427 GstSeekType cur_type, stop_type;
1428 gint64 cur, stop, key_cur;
1431 gint64 original_stop;
1434 GST_DEBUG_OBJECT (qtdemux, "doing push-based seek");
1436 gst_event_parse_seek (event, &rate, &format, &flags,
1437 &cur_type, &cur, &stop_type, &stop);
1438 seqnum = gst_event_get_seqnum (event);
1440 /* only forward streaming and seeking is possible */
1442 goto unsupported_seek;
1444 /* convert to TIME if needed and possible */
1445 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1449 /* Upstream seek in bytes will have undefined stop, but qtdemux stores
1450 * the original stop position to use when upstream pushes the new segment
1452 original_stop = stop;
1455 /* find reasonable corresponding BYTE position,
1456 * also try to mind about keyframes, since we can not go back a bit for them
1458 /* determining @next here based on SNAP_BEFORE/SNAP_AFTER should
1459 * mostly just work, but let's not yet boldly go there ... */
1460 gst_qtdemux_adjust_seek (qtdemux, cur, FALSE, FALSE, &key_cur, &byte_cur);
1465 GST_DEBUG_OBJECT (qtdemux, "Pushing BYTE seek rate %g, "
1466 "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, byte_cur,
1469 GST_OBJECT_LOCK (qtdemux);
1470 qtdemux->seek_offset = byte_cur;
1471 if (!(flags & GST_SEEK_FLAG_KEY_UNIT)) {
1472 qtdemux->push_seek_start = cur;
1474 qtdemux->push_seek_start = key_cur;
1477 if (stop_type == GST_SEEK_TYPE_NONE) {
1478 qtdemux->push_seek_stop = qtdemux->segment.stop;
1480 qtdemux->push_seek_stop = original_stop;
1482 GST_OBJECT_UNLOCK (qtdemux);
1484 /* BYTE seek event */
1485 event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type, byte_cur,
1487 gst_event_set_seqnum (event, seqnum);
1488 res = gst_pad_push_event (qtdemux->sinkpad, event);
1495 GST_DEBUG_OBJECT (qtdemux, "could not determine byte position to seek to, "
1501 GST_DEBUG_OBJECT (qtdemux, "unsupported seek, seek aborted.");
1506 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1511 /* perform the seek.
1513 * We set all segment_indexes in the streams to unknown and
1514 * adjust the time_position to the desired position. this is enough
1515 * to trigger a segment switch in the streaming thread to start
1516 * streaming from the desired position.
1518 * Keyframe seeking is a little more complicated when dealing with
1519 * segments. Ideally we want to move to the previous keyframe in
1520 * the segment but there might not be a keyframe in the segment. In
1521 * fact, none of the segments could contain a keyframe. We take a
1522 * practical approach: seek to the previous keyframe in the segment,
1523 * if there is none, seek to the beginning of the segment.
1525 * Called with STREAM_LOCK
1528 gst_qtdemux_perform_seek (GstQTDemux * qtdemux, GstSegment * segment,
1529 guint32 seqnum, GstSeekFlags flags)
1531 gint64 desired_offset;
1534 desired_offset = segment->position;
1536 GST_DEBUG_OBJECT (qtdemux, "seeking to %" GST_TIME_FORMAT,
1537 GST_TIME_ARGS (desired_offset));
1539 /* may not have enough fragmented info to do this adjustment,
1540 * and we can't scan (and probably should not) at this time with
1541 * possibly flushing upstream */
1542 if ((flags & GST_SEEK_FLAG_KEY_UNIT) && !qtdemux->fragmented) {
1544 gboolean next, before, after;
1546 before = ! !(flags & GST_SEEK_FLAG_SNAP_BEFORE);
1547 after = ! !(flags & GST_SEEK_FLAG_SNAP_AFTER);
1548 next = after && !before;
1549 if (segment->rate < 0)
1552 gst_qtdemux_adjust_seek (qtdemux, desired_offset, TRUE, next, &min_offset,
1554 GST_DEBUG_OBJECT (qtdemux, "keyframe seek, align to %"
1555 GST_TIME_FORMAT, GST_TIME_ARGS (min_offset));
1556 desired_offset = min_offset;
1559 /* and set all streams to the final position */
1560 gst_flow_combiner_reset (qtdemux->flowcombiner);
1561 qtdemux->segment_seqnum = seqnum;
1562 for (n = 0; n < qtdemux->n_streams; n++) {
1563 QtDemuxStream *stream = qtdemux->streams[n];
1565 stream->time_position = desired_offset;
1566 stream->accumulated_base = 0;
1567 stream->sample_index = -1;
1568 stream->offset_in_sample = 0;
1569 stream->segment_index = -1;
1570 stream->sent_eos = FALSE;
1572 if (segment->flags & GST_SEEK_FLAG_FLUSH)
1573 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
1575 segment->position = desired_offset;
1576 segment->time = desired_offset;
1577 if (segment->rate >= 0) {
1578 segment->start = desired_offset;
1580 /* we stop at the end */
1581 if (segment->stop == -1)
1582 segment->stop = segment->duration;
1584 segment->stop = desired_offset;
1587 if (qtdemux->fragmented)
1588 qtdemux->fragmented_seek_pending = TRUE;
1593 /* do a seek in pull based mode */
1595 gst_qtdemux_do_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1600 GstSeekType cur_type, stop_type;
1604 GstSegment seeksegment;
1606 GstEvent *flush_event;
1609 GST_DEBUG_OBJECT (qtdemux, "doing seek with event");
1611 gst_event_parse_seek (event, &rate, &format, &flags,
1612 &cur_type, &cur, &stop_type, &stop);
1613 seqnum = gst_event_get_seqnum (event);
1615 /* we have to have a format as the segment format. Try to convert
1617 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1621 GST_DEBUG_OBJECT (qtdemux, "seek format %s", gst_format_get_name (format));
1623 GST_DEBUG_OBJECT (qtdemux, "doing seek without event");
1627 flush = flags & GST_SEEK_FLAG_FLUSH;
1629 /* stop streaming, either by flushing or by pausing the task */
1631 flush_event = gst_event_new_flush_start ();
1633 gst_event_set_seqnum (flush_event, seqnum);
1634 /* unlock upstream pull_range */
1635 gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event));
1636 /* make sure out loop function exits */
1637 gst_qtdemux_push_event (qtdemux, flush_event);
1639 /* non flushing seek, pause the task */
1640 gst_pad_pause_task (qtdemux->sinkpad);
1643 /* wait for streaming to finish */
1644 GST_PAD_STREAM_LOCK (qtdemux->sinkpad);
1646 /* copy segment, we need this because we still need the old
1647 * segment when we close the current segment. */
1648 memcpy (&seeksegment, &qtdemux->segment, sizeof (GstSegment));
1651 /* configure the segment with the seek variables */
1652 GST_DEBUG_OBJECT (qtdemux, "configuring seek");
1653 gst_segment_do_seek (&seeksegment, rate, format, flags,
1654 cur_type, cur, stop_type, stop, &update);
1657 /* now do the seek, this actually never returns FALSE */
1658 gst_qtdemux_perform_seek (qtdemux, &seeksegment, seqnum, flags);
1660 /* prepare for streaming again */
1662 flush_event = gst_event_new_flush_stop (TRUE);
1664 gst_event_set_seqnum (flush_event, seqnum);
1666 gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event));
1667 gst_qtdemux_push_event (qtdemux, flush_event);
1670 /* commit the new segment */
1671 memcpy (&qtdemux->segment, &seeksegment, sizeof (GstSegment));
1673 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
1674 GstMessage *msg = gst_message_new_segment_start (GST_OBJECT_CAST (qtdemux),
1675 qtdemux->segment.format, qtdemux->segment.position);
1677 gst_message_set_seqnum (msg, seqnum);
1678 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
1681 /* restart streaming, NEWSEGMENT will be sent from the streaming thread. */
1682 gst_pad_start_task (qtdemux->sinkpad, (GstTaskFunction) gst_qtdemux_loop,
1683 qtdemux->sinkpad, NULL);
1685 GST_PAD_STREAM_UNLOCK (qtdemux->sinkpad);
1692 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1698 qtdemux_ensure_index (GstQTDemux * qtdemux)
1702 GST_DEBUG_OBJECT (qtdemux, "collecting all metadata for all streams");
1704 /* Build complete index */
1705 for (i = 0; i < qtdemux->n_streams; i++) {
1706 QtDemuxStream *stream = qtdemux->streams[i];
1708 if (!qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1))
1716 GST_LOG_OBJECT (qtdemux,
1717 "Building complete index of stream %u for seeking failed!", i);
1723 gst_qtdemux_handle_src_event (GstPad * pad, GstObject * parent,
1726 gboolean res = TRUE;
1727 GstQTDemux *qtdemux = GST_QTDEMUX (parent);
1729 switch (GST_EVENT_TYPE (event)) {
1730 case GST_EVENT_SEEK:
1732 #ifndef GST_DISABLE_GST_DEBUG
1733 GstClockTime ts = gst_util_get_timestamp ();
1736 if (qtdemux->upstream_format_is_time && qtdemux->fragmented) {
1737 /* seek should be handled by upstream, we might need to re-download fragments */
1738 GST_DEBUG_OBJECT (qtdemux,
1739 "let upstream handle seek for fragmented playback");
1743 /* Build complete index for seeking;
1744 * if not a fragmented file at least */
1745 if (!qtdemux->fragmented)
1746 if (!qtdemux_ensure_index (qtdemux))
1748 #ifndef GST_DISABLE_GST_DEBUG
1749 ts = gst_util_get_timestamp () - ts;
1750 GST_INFO_OBJECT (qtdemux,
1751 "Time taken to parse index %" GST_TIME_FORMAT, GST_TIME_ARGS (ts));
1754 if (qtdemux->pullbased) {
1755 res = gst_qtdemux_do_seek (qtdemux, pad, event);
1756 } else if (gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (event))) {
1757 GST_DEBUG_OBJECT (qtdemux, "Upstream successfully seeked");
1759 } else if (qtdemux->state == QTDEMUX_STATE_MOVIE && qtdemux->n_streams
1760 && !qtdemux->fragmented) {
1761 res = gst_qtdemux_do_push_seek (qtdemux, pad, event);
1763 GST_DEBUG_OBJECT (qtdemux,
1764 "ignoring seek in push mode in current state");
1767 gst_event_unref (event);
1771 res = gst_pad_event_default (pad, parent, event);
1781 GST_ERROR_OBJECT (qtdemux, "Index failed");
1782 gst_event_unref (event);
1788 /* stream/index return sample that is min/max w.r.t. byte position,
1789 * time is min/max w.r.t. time of samples,
1790 * the latter need not be time of the former sample */
1792 gst_qtdemux_find_sample (GstQTDemux * qtdemux, gint64 byte_pos, gboolean fw,
1793 gboolean set, QtDemuxStream ** _stream, gint * _index, gint64 * _time)
1796 gint64 time, min_time;
1797 QtDemuxStream *stream;
1803 for (n = 0; n < qtdemux->n_streams; ++n) {
1806 gboolean set_sample;
1808 str = qtdemux->streams[n];
1815 i = str->n_samples - 1;
1819 for (; (i >= 0) && (i < str->n_samples); i += inc) {
1820 if (str->samples[i].size == 0)
1823 if (fw && (str->samples[i].offset < byte_pos))
1826 if (!fw && (str->samples[i].offset + str->samples[i].size > byte_pos))
1829 /* move stream to first available sample */
1831 gst_qtdemux_move_stream (qtdemux, str, i);
1835 /* avoid index from sparse streams since they might be far away */
1837 /* determine min/max time */
1838 time = QTSAMPLE_PTS (str, &str->samples[i]);
1839 if (min_time == -1 || (!fw && time > min_time) ||
1840 (fw && time < min_time)) {
1844 /* determine stream with leading sample, to get its position */
1846 (fw && (str->samples[i].offset < stream->samples[index].offset)) ||
1847 (!fw && (str->samples[i].offset > stream->samples[index].offset))) {
1855 /* no sample for this stream, mark eos */
1857 gst_qtdemux_move_stream (qtdemux, str, str->n_samples);
1868 static QtDemuxStream *
1869 _create_stream (void)
1871 QtDemuxStream *stream;
1873 stream = g_new0 (QtDemuxStream, 1);
1874 /* new streams always need a discont */
1875 stream->discont = TRUE;
1876 /* we enable clipping for raw audio/video streams */
1877 stream->need_clip = FALSE;
1878 stream->need_process = FALSE;
1879 stream->segment_index = -1;
1880 stream->time_position = 0;
1881 stream->sample_index = -1;
1882 stream->offset_in_sample = 0;
1883 stream->new_stream = TRUE;
1884 stream->multiview_mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
1885 stream->multiview_flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
1886 stream->protected = FALSE;
1887 stream->protection_scheme_type = 0;
1888 stream->protection_scheme_version = 0;
1889 stream->protection_scheme_info = NULL;
1890 stream->n_samples_moof = 0;
1891 stream->duration_moof = 0;
1892 stream->duration_last_moof = 0;
1893 stream->alignment = 1;
1894 g_queue_init (&stream->protection_scheme_event_queue);
1899 gst_qtdemux_setcaps (GstQTDemux * demux, GstCaps * caps)
1901 GstStructure *structure;
1902 const gchar *variant;
1903 const GstCaps *mediacaps = NULL;
1905 GST_DEBUG_OBJECT (demux, "Sink set caps: %" GST_PTR_FORMAT, caps);
1907 structure = gst_caps_get_structure (caps, 0);
1908 variant = gst_structure_get_string (structure, "variant");
1910 if (variant && strcmp (variant, "mss-fragmented") == 0) {
1911 QtDemuxStream *stream;
1912 const GValue *value;
1914 demux->fragmented = TRUE;
1915 demux->mss_mode = TRUE;
1917 if (demux->n_streams > 1) {
1918 /* can't do this, we can only renegotiate for another mss format */
1922 value = gst_structure_get_value (structure, "media-caps");
1925 const GValue *timescale_v;
1927 /* TODO update when stream changes during playback */
1929 if (demux->n_streams == 0) {
1930 stream = _create_stream ();
1931 demux->streams[demux->n_streams] = stream;
1932 demux->n_streams = 1;
1934 stream = demux->streams[0];
1937 timescale_v = gst_structure_get_value (structure, "timescale");
1939 stream->timescale = g_value_get_uint64 (timescale_v);
1941 /* default mss timescale */
1942 stream->timescale = 10000000;
1944 demux->timescale = stream->timescale;
1946 mediacaps = gst_value_get_caps (value);
1947 if (!stream->caps || !gst_caps_is_equal_fixed (mediacaps, stream->caps)) {
1948 GST_DEBUG_OBJECT (demux, "We have a new caps %" GST_PTR_FORMAT,
1950 stream->new_caps = TRUE;
1952 gst_caps_replace (&stream->caps, (GstCaps *) mediacaps);
1953 structure = gst_caps_get_structure (mediacaps, 0);
1954 if (g_str_has_prefix (gst_structure_get_name (structure), "video")) {
1955 stream->subtype = FOURCC_vide;
1957 gst_structure_get_int (structure, "width", &stream->width);
1958 gst_structure_get_int (structure, "height", &stream->height);
1959 gst_structure_get_fraction (structure, "framerate", &stream->fps_n,
1961 } else if (g_str_has_prefix (gst_structure_get_name (structure), "audio")) {
1963 stream->subtype = FOURCC_soun;
1964 gst_structure_get_int (structure, "channels", &stream->n_channels);
1965 gst_structure_get_int (structure, "rate", &rate);
1966 stream->rate = rate;
1969 gst_caps_replace (&demux->media_caps, (GstCaps *) mediacaps);
1971 demux->mss_mode = FALSE;
1978 gst_qtdemux_reset (GstQTDemux * qtdemux, gboolean hard)
1982 GST_DEBUG_OBJECT (qtdemux, "Resetting demux");
1983 gst_pad_stop_task (qtdemux->sinkpad);
1985 if (hard || qtdemux->upstream_format_is_time) {
1986 qtdemux->state = QTDEMUX_STATE_INITIAL;
1987 qtdemux->neededbytes = 16;
1988 qtdemux->todrop = 0;
1989 qtdemux->pullbased = FALSE;
1990 qtdemux->posted_redirect = FALSE;
1991 qtdemux->first_mdat = -1;
1992 qtdemux->header_size = 0;
1993 qtdemux->mdatoffset = -1;
1994 qtdemux->restoredata_offset = -1;
1995 if (qtdemux->mdatbuffer)
1996 gst_buffer_unref (qtdemux->mdatbuffer);
1997 if (qtdemux->restoredata_buffer)
1998 gst_buffer_unref (qtdemux->restoredata_buffer);
1999 qtdemux->mdatbuffer = NULL;
2000 qtdemux->restoredata_buffer = NULL;
2001 qtdemux->mdatleft = 0;
2002 if (qtdemux->comp_brands)
2003 gst_buffer_unref (qtdemux->comp_brands);
2004 qtdemux->comp_brands = NULL;
2005 qtdemux->last_moov_offset = -1;
2006 if (qtdemux->moov_node_compressed) {
2007 g_node_destroy (qtdemux->moov_node_compressed);
2008 if (qtdemux->moov_node)
2009 g_free (qtdemux->moov_node->data);
2011 qtdemux->moov_node_compressed = NULL;
2012 if (qtdemux->moov_node)
2013 g_node_destroy (qtdemux->moov_node);
2014 qtdemux->moov_node = NULL;
2015 if (qtdemux->tag_list)
2016 gst_mini_object_unref (GST_MINI_OBJECT_CAST (qtdemux->tag_list));
2017 qtdemux->tag_list = NULL;
2019 if (qtdemux->element_index)
2020 gst_object_unref (qtdemux->element_index);
2021 qtdemux->element_index = NULL;
2023 qtdemux->major_brand = 0;
2024 if (qtdemux->pending_newsegment)
2025 gst_event_unref (qtdemux->pending_newsegment);
2026 qtdemux->pending_newsegment = NULL;
2027 qtdemux->upstream_format_is_time = FALSE;
2028 qtdemux->upstream_seekable = FALSE;
2029 qtdemux->upstream_size = 0;
2031 qtdemux->fragment_start = -1;
2032 qtdemux->fragment_start_offset = -1;
2033 qtdemux->duration = 0;
2034 qtdemux->moof_offset = 0;
2035 qtdemux->chapters_track_id = 0;
2036 qtdemux->have_group_id = FALSE;
2037 qtdemux->group_id = G_MAXUINT;
2039 g_queue_foreach (&qtdemux->protection_event_queue, (GFunc) gst_event_unref,
2041 g_queue_clear (&qtdemux->protection_event_queue);
2043 qtdemux->offset = 0;
2044 gst_adapter_clear (qtdemux->adapter);
2045 gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
2046 qtdemux->segment_seqnum = 0;
2049 for (n = 0; n < qtdemux->n_streams; n++) {
2050 gst_qtdemux_stream_free (qtdemux, qtdemux->streams[n]);
2051 qtdemux->streams[n] = NULL;
2053 qtdemux->n_streams = 0;
2054 qtdemux->n_video_streams = 0;
2055 qtdemux->n_audio_streams = 0;
2056 qtdemux->n_sub_streams = 0;
2057 qtdemux->exposed = FALSE;
2058 qtdemux->fragmented = FALSE;
2059 qtdemux->mss_mode = FALSE;
2060 gst_caps_replace (&qtdemux->media_caps, NULL);
2061 qtdemux->timescale = 0;
2062 qtdemux->got_moov = FALSE;
2063 if (qtdemux->protection_system_ids) {
2064 g_ptr_array_free (qtdemux->protection_system_ids, TRUE);
2065 qtdemux->protection_system_ids = NULL;
2067 } else if (qtdemux->mss_mode) {
2068 gst_flow_combiner_reset (qtdemux->flowcombiner);
2069 for (n = 0; n < qtdemux->n_streams; n++)
2070 gst_qtdemux_stream_clear (qtdemux, qtdemux->streams[n]);
2072 gst_flow_combiner_reset (qtdemux->flowcombiner);
2073 for (n = 0; n < qtdemux->n_streams; n++) {
2074 qtdemux->streams[n]->sent_eos = FALSE;
2075 qtdemux->streams[n]->time_position = 0;
2076 qtdemux->streams[n]->accumulated_base = 0;
2078 if (!qtdemux->pending_newsegment) {
2079 qtdemux->pending_newsegment = gst_event_new_segment (&qtdemux->segment);
2080 if (qtdemux->segment_seqnum)
2081 gst_event_set_seqnum (qtdemux->pending_newsegment,
2082 qtdemux->segment_seqnum);
2088 /* Maps the @segment to the qt edts internal segments and pushes
2089 * the correspnding segment event.
2091 * If it ends up being at a empty segment, a gap will be pushed and the next
2092 * edts segment will be activated in sequence.
2094 * To be used in push-mode only */
2096 gst_qtdemux_map_and_push_segments (GstQTDemux * qtdemux, GstSegment * segment)
2100 for (n = 0; n < qtdemux->n_streams; n++) {
2101 QtDemuxStream *stream = qtdemux->streams[n];
2103 stream->time_position = segment->start;
2105 /* in push mode we should be guaranteed that we will have empty segments
2106 * at the beginning and then one segment after, other scenarios are not
2107 * supported and are discarded when parsing the edts */
2108 for (i = 0; i < stream->n_segments; i++) {
2109 if (stream->segments[i].stop_time > segment->start) {
2110 gst_qtdemux_activate_segment (qtdemux, stream, i,
2111 stream->time_position);
2112 if (QTSEGMENT_IS_EMPTY (&stream->segments[i])) {
2113 /* push the empty segment and move to the next one */
2114 gst_qtdemux_send_gap_for_segment (qtdemux, stream, i,
2115 stream->time_position);
2119 g_assert (i == stream->n_segments - 1);
2126 gst_qtdemux_handle_sink_event (GstPad * sinkpad, GstObject * parent,
2129 GstQTDemux *demux = GST_QTDEMUX (parent);
2130 gboolean res = TRUE;
2132 GST_LOG_OBJECT (demux, "handling %s event", GST_EVENT_TYPE_NAME (event));
2134 switch (GST_EVENT_TYPE (event)) {
2135 case GST_EVENT_SEGMENT:
2138 QtDemuxStream *stream;
2142 /* some debug output */
2143 gst_event_copy_segment (event, &segment);
2144 GST_DEBUG_OBJECT (demux, "received newsegment %" GST_SEGMENT_FORMAT,
2147 /* erase any previously set segment */
2148 gst_event_replace (&demux->pending_newsegment, NULL);
2150 if (segment.format == GST_FORMAT_TIME) {
2151 GST_DEBUG_OBJECT (demux, "new pending_newsegment");
2152 gst_event_replace (&demux->pending_newsegment, event);
2153 demux->upstream_format_is_time = TRUE;
2155 GST_DEBUG_OBJECT (demux, "Not storing upstream newsegment, "
2156 "not in time format");
2158 /* chain will send initial newsegment after pads have been added */
2159 if (demux->state != QTDEMUX_STATE_MOVIE || !demux->n_streams) {
2160 GST_DEBUG_OBJECT (demux, "still starting, eating event");
2165 /* check if this matches a time seek we received previously
2166 * FIXME for backwards compatibility reasons we use the
2167 * seek_offset here to compare. In the future we might want to
2168 * change this to use the seqnum as it uniquely should identify
2169 * the segment that corresponds to the seek. */
2170 GST_DEBUG_OBJECT (demux, "Stored seek offset: %" G_GINT64_FORMAT
2171 ", received segment offset %" G_GINT64_FORMAT,
2172 demux->seek_offset, segment.start);
2173 if (segment.format == GST_FORMAT_BYTES
2174 && demux->seek_offset == segment.start) {
2175 GST_OBJECT_LOCK (demux);
2176 offset = segment.start;
2178 segment.format = GST_FORMAT_TIME;
2179 segment.start = demux->push_seek_start;
2180 segment.stop = demux->push_seek_stop;
2181 GST_DEBUG_OBJECT (demux, "Replaced segment with stored seek "
2182 "segment %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT,
2183 GST_TIME_ARGS (segment.start), GST_TIME_ARGS (segment.stop));
2184 GST_OBJECT_UNLOCK (demux);
2187 /* we only expect a BYTE segment, e.g. following a seek */
2188 if (segment.format == GST_FORMAT_BYTES) {
2189 if (GST_CLOCK_TIME_IS_VALID (segment.start)) {
2190 offset = segment.start;
2192 gst_qtdemux_find_sample (demux, segment.start, TRUE, FALSE, NULL,
2193 NULL, (gint64 *) & segment.start);
2194 if ((gint64) segment.start < 0)
2197 if (GST_CLOCK_TIME_IS_VALID (segment.stop)) {
2198 gst_qtdemux_find_sample (demux, segment.stop, FALSE, FALSE, NULL,
2199 NULL, (gint64 *) & segment.stop);
2200 /* keyframe seeking should already arrange for start >= stop,
2201 * but make sure in other rare cases */
2202 segment.stop = MAX (segment.stop, segment.start);
2204 } else if (segment.format == GST_FORMAT_TIME) {
2205 /* push all data on the adapter before starting this
2207 gst_qtdemux_process_adapter (demux, TRUE);
2209 GST_DEBUG_OBJECT (demux, "unsupported segment format, ignoring");
2213 /* We shouldn't modify upstream driven TIME FORMAT segment */
2214 if (!demux->upstream_format_is_time) {
2215 /* accept upstream's notion of segment and distribute along */
2216 segment.format = GST_FORMAT_TIME;
2217 segment.position = segment.time = segment.start;
2218 segment.duration = demux->segment.duration;
2219 segment.base = gst_segment_to_running_time (&demux->segment,
2220 GST_FORMAT_TIME, demux->segment.position);
2223 gst_segment_copy_into (&segment, &demux->segment);
2224 GST_DEBUG_OBJECT (demux, "Pushing newseg %" GST_SEGMENT_FORMAT, &segment);
2226 /* map segment to internal qt segments and push on each stream */
2227 if (demux->n_streams) {
2228 if (demux->fragmented) {
2229 GstEvent *segment_event = gst_event_new_segment (&segment);
2231 gst_event_replace (&demux->pending_newsegment, NULL);
2232 gst_event_set_seqnum (segment_event, demux->segment_seqnum);
2233 gst_qtdemux_push_event (demux, segment_event);
2235 gst_event_replace (&demux->pending_newsegment, NULL);
2236 gst_qtdemux_map_and_push_segments (demux, &segment);
2240 /* clear leftover in current segment, if any */
2241 gst_adapter_clear (demux->adapter);
2243 /* set up streaming thread */
2244 demux->offset = offset;
2245 if (demux->upstream_format_is_time) {
2246 GST_DEBUG_OBJECT (demux, "Upstream is driving in time format, "
2247 "set values to restart reading from a new atom");
2248 demux->neededbytes = 16;
2251 gst_qtdemux_find_sample (demux, offset, TRUE, TRUE, &stream, &idx,
2254 demux->todrop = stream->samples[idx].offset - offset;
2255 demux->neededbytes = demux->todrop + stream->samples[idx].size;
2257 /* set up for EOS */
2258 demux->neededbytes = -1;
2263 gst_event_unref (event);
2267 case GST_EVENT_FLUSH_START:
2269 if (gst_event_get_seqnum (event) == demux->offset_seek_seqnum) {
2270 gst_event_unref (event);
2275 case GST_EVENT_FLUSH_STOP:
2279 dur = demux->segment.duration;
2280 gst_qtdemux_reset (demux, FALSE);
2281 demux->segment.duration = dur;
2283 if (gst_event_get_seqnum (event) == demux->offset_seek_seqnum) {
2284 gst_event_unref (event);
2290 /* If we are in push mode, and get an EOS before we've seen any streams,
2291 * then error out - we have nowhere to send the EOS */
2292 if (!demux->pullbased) {
2294 gboolean has_valid_stream = FALSE;
2295 for (i = 0; i < demux->n_streams; i++) {
2296 if (demux->streams[i]->pad != NULL) {
2297 has_valid_stream = TRUE;
2301 if (!has_valid_stream)
2302 gst_qtdemux_post_no_playable_stream_error (demux);
2304 GST_DEBUG_OBJECT (demux, "Data still available after EOS: %u",
2305 (guint) gst_adapter_available (demux->adapter));
2306 if (gst_qtdemux_process_adapter (demux, TRUE) != GST_FLOW_OK) {
2312 case GST_EVENT_CAPS:{
2313 GstCaps *caps = NULL;
2315 gst_event_parse_caps (event, &caps);
2316 gst_qtdemux_setcaps (demux, caps);
2318 gst_event_unref (event);
2321 case GST_EVENT_PROTECTION:
2323 const gchar *system_id = NULL;
2325 gst_event_parse_protection (event, &system_id, NULL, NULL);
2326 GST_DEBUG_OBJECT (demux, "Received protection event for system ID %s",
2328 gst_qtdemux_append_protection_system_id (demux, system_id);
2329 /* save the event for later, for source pads that have not been created */
2330 g_queue_push_tail (&demux->protection_event_queue, gst_event_ref (event));
2331 /* send it to all pads that already exist */
2332 gst_qtdemux_push_event (demux, event);
2340 res = gst_pad_event_default (demux->sinkpad, parent, event) & res;
2348 gst_qtdemux_set_index (GstElement * element, GstIndex * index)
2350 GstQTDemux *demux = GST_QTDEMUX (element);
2352 GST_OBJECT_LOCK (demux);
2353 if (demux->element_index)
2354 gst_object_unref (demux->element_index);
2356 demux->element_index = gst_object_ref (index);
2358 demux->element_index = NULL;
2360 GST_OBJECT_UNLOCK (demux);
2361 /* object lock might be taken again */
2363 gst_index_get_writer_id (index, GST_OBJECT (element), &demux->index_id);
2364 GST_DEBUG_OBJECT (demux, "Set index %" GST_PTR_FORMAT "for writer id %d",
2365 demux->element_index, demux->index_id);
2369 gst_qtdemux_get_index (GstElement * element)
2371 GstIndex *result = NULL;
2372 GstQTDemux *demux = GST_QTDEMUX (element);
2374 GST_OBJECT_LOCK (demux);
2375 if (demux->element_index)
2376 result = gst_object_ref (demux->element_index);
2377 GST_OBJECT_UNLOCK (demux);
2379 GST_DEBUG_OBJECT (demux, "Returning index %" GST_PTR_FORMAT, result);
2386 gst_qtdemux_stbl_free (QtDemuxStream * stream)
2388 g_free ((gpointer) stream->stco.data);
2389 stream->stco.data = NULL;
2390 g_free ((gpointer) stream->stsz.data);
2391 stream->stsz.data = NULL;
2392 g_free ((gpointer) stream->stsc.data);
2393 stream->stsc.data = NULL;
2394 g_free ((gpointer) stream->stts.data);
2395 stream->stts.data = NULL;
2396 g_free ((gpointer) stream->stss.data);
2397 stream->stss.data = NULL;
2398 g_free ((gpointer) stream->stps.data);
2399 stream->stps.data = NULL;
2400 g_free ((gpointer) stream->ctts.data);
2401 stream->ctts.data = NULL;
2405 gst_qtdemux_stream_flush_segments_data (GstQTDemux * qtdemux,
2406 QtDemuxStream * stream)
2408 g_free (stream->segments);
2409 stream->segments = NULL;
2410 stream->segment_index = -1;
2411 stream->accumulated_base = 0;
2415 gst_qtdemux_stream_flush_samples_data (GstQTDemux * qtdemux,
2416 QtDemuxStream * stream)
2418 g_free (stream->samples);
2419 stream->samples = NULL;
2420 gst_qtdemux_stbl_free (stream);
2423 g_free (stream->ra_entries);
2424 stream->ra_entries = NULL;
2425 stream->n_ra_entries = 0;
2427 stream->sample_index = -1;
2428 stream->stbl_index = -1;
2429 stream->n_samples = 0;
2430 stream->time_position = 0;
2432 stream->n_samples_moof = 0;
2433 stream->duration_moof = 0;
2434 stream->duration_last_moof = 0;
2438 gst_qtdemux_stream_clear (GstQTDemux * qtdemux, QtDemuxStream * stream)
2440 if (stream->allocator)
2441 gst_object_unref (stream->allocator);
2442 while (stream->buffers) {
2443 gst_buffer_unref (GST_BUFFER_CAST (stream->buffers->data));
2444 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
2446 if (stream->rgb8_palette) {
2447 gst_memory_unref (stream->rgb8_palette);
2448 stream->rgb8_palette = NULL;
2451 if (stream->pending_tags)
2452 gst_tag_list_unref (stream->pending_tags);
2453 stream->pending_tags = NULL;
2454 g_free (stream->redirect_uri);
2455 stream->redirect_uri = NULL;
2456 stream->sent_eos = FALSE;
2457 stream->sparse = FALSE;
2458 stream->protected = FALSE;
2459 if (stream->protection_scheme_info) {
2460 if (stream->protection_scheme_type == FOURCC_cenc) {
2461 QtDemuxCencSampleSetInfo *info =
2462 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
2463 if (info->default_properties)
2464 gst_structure_free (info->default_properties);
2465 if (info->crypto_info)
2466 g_ptr_array_free (info->crypto_info, TRUE);
2468 g_free (stream->protection_scheme_info);
2469 stream->protection_scheme_info = NULL;
2471 stream->protection_scheme_type = 0;
2472 stream->protection_scheme_version = 0;
2473 g_queue_foreach (&stream->protection_scheme_event_queue,
2474 (GFunc) gst_event_unref, NULL);
2475 g_queue_clear (&stream->protection_scheme_event_queue);
2476 gst_qtdemux_stream_flush_segments_data (qtdemux, stream);
2477 gst_qtdemux_stream_flush_samples_data (qtdemux, stream);
2481 gst_qtdemux_stream_free (GstQTDemux * qtdemux, QtDemuxStream * stream)
2483 gst_qtdemux_stream_clear (qtdemux, stream);
2485 gst_caps_unref (stream->caps);
2486 stream->caps = NULL;
2488 gst_element_remove_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
2489 gst_flow_combiner_remove_pad (qtdemux->flowcombiner, stream->pad);
2495 gst_qtdemux_remove_stream (GstQTDemux * qtdemux, int i)
2497 g_assert (i >= 0 && i < qtdemux->n_streams && qtdemux->streams[i] != NULL);
2499 gst_qtdemux_stream_free (qtdemux, qtdemux->streams[i]);
2500 qtdemux->streams[i] = qtdemux->streams[qtdemux->n_streams - 1];
2501 qtdemux->streams[qtdemux->n_streams - 1] = NULL;
2502 qtdemux->n_streams--;
2505 static GstStateChangeReturn
2506 gst_qtdemux_change_state (GstElement * element, GstStateChange transition)
2508 GstQTDemux *qtdemux = GST_QTDEMUX (element);
2509 GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
2511 switch (transition) {
2512 case GST_STATE_CHANGE_PAUSED_TO_READY:
2518 result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
2520 switch (transition) {
2521 case GST_STATE_CHANGE_PAUSED_TO_READY:{
2522 gst_qtdemux_reset (qtdemux, TRUE);
2533 qtdemux_parse_ftyp (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2535 /* counts as header data */
2536 qtdemux->header_size += length;
2538 /* only consider at least a sufficiently complete ftyp atom */
2542 qtdemux->major_brand = QT_FOURCC (buffer + 8);
2543 GST_DEBUG_OBJECT (qtdemux, "major brand: %" GST_FOURCC_FORMAT,
2544 GST_FOURCC_ARGS (qtdemux->major_brand));
2545 if (qtdemux->comp_brands)
2546 gst_buffer_unref (qtdemux->comp_brands);
2547 buf = qtdemux->comp_brands = gst_buffer_new_and_alloc (length - 16);
2548 gst_buffer_fill (buf, 0, buffer + 16, length - 16);
2553 qtdemux_handle_xmp_taglist (GstQTDemux * qtdemux, GstTagList * taglist,
2554 GstTagList * xmptaglist)
2556 /* Strip out bogus fields */
2558 if (gst_tag_list_get_scope (taglist) == GST_TAG_SCOPE_GLOBAL) {
2559 gst_tag_list_remove_tag (xmptaglist, GST_TAG_VIDEO_CODEC);
2560 gst_tag_list_remove_tag (xmptaglist, GST_TAG_AUDIO_CODEC);
2562 gst_tag_list_remove_tag (xmptaglist, GST_TAG_CONTAINER_FORMAT);
2565 GST_DEBUG_OBJECT (qtdemux, "Found XMP tags %" GST_PTR_FORMAT, xmptaglist);
2567 /* prioritize native tags using _KEEP mode */
2568 gst_tag_list_insert (taglist, xmptaglist, GST_TAG_MERGE_KEEP);
2569 gst_tag_list_unref (xmptaglist);
2574 qtdemux_parse_piff (GstQTDemux * qtdemux, const guint8 * buffer, gint length,
2582 QtDemuxStream *stream;
2583 GstStructure *structure;
2584 QtDemuxCencSampleSetInfo *ss_info = NULL;
2585 const gchar *system_id;
2586 gboolean uses_sub_sample_encryption = FALSE;
2588 if (qtdemux->n_streams == 0)
2591 stream = qtdemux->streams[0];
2593 structure = gst_caps_get_structure (stream->caps, 0);
2594 if (!gst_structure_has_name (structure, "application/x-cenc")) {
2595 GST_WARNING_OBJECT (qtdemux,
2596 "Attempting PIFF box parsing on an unencrypted stream.");
2600 gst_structure_get (structure, GST_PROTECTION_SYSTEM_ID_CAPS_FIELD,
2601 G_TYPE_STRING, &system_id, NULL);
2602 gst_qtdemux_append_protection_system_id (qtdemux, system_id);
2604 stream->protected = TRUE;
2605 stream->protection_scheme_type = FOURCC_cenc;
2607 if (!stream->protection_scheme_info)
2608 stream->protection_scheme_info = g_new0 (QtDemuxCencSampleSetInfo, 1);
2610 ss_info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
2612 if (ss_info->default_properties)
2613 gst_structure_free (ss_info->default_properties);
2615 ss_info->default_properties =
2616 gst_structure_new ("application/x-cenc",
2617 "iv_size", G_TYPE_UINT, iv_size, "encrypted", G_TYPE_BOOLEAN, TRUE, NULL);
2619 if (ss_info->crypto_info) {
2620 GST_LOG_OBJECT (qtdemux, "unreffing existing crypto_info");
2621 g_ptr_array_free (ss_info->crypto_info, TRUE);
2622 ss_info->crypto_info = NULL;
2626 gst_byte_reader_init (&br, buffer + offset + 16, length - offset - 16);
2628 if (!gst_byte_reader_get_uint8 (&br, &version)) {
2629 GST_ERROR_OBJECT (qtdemux, "Error getting box's version field");
2633 if (!gst_byte_reader_get_uint24_be (&br, &flags)) {
2634 GST_ERROR_OBJECT (qtdemux, "Error getting box's flags field");
2638 if ((flags & 0x000001)) {
2639 guint32 algorithm_id = 0;
2642 gboolean is_encrypted = TRUE;
2644 if (!gst_byte_reader_get_uint24_le (&br, &algorithm_id)) {
2645 GST_ERROR_OBJECT (qtdemux, "Error getting box's algorithm ID field");
2650 if (algorithm_id == 0) {
2651 is_encrypted = FALSE;
2652 } else if (algorithm_id == 1) {
2653 /* FIXME: maybe store this in properties? */
2654 GST_DEBUG_OBJECT (qtdemux, "AES 128-bits CTR encrypted stream");
2655 } else if (algorithm_id == 2) {
2656 /* FIXME: maybe store this in properties? */
2657 GST_DEBUG_OBJECT (qtdemux, "AES 128-bits CBC encrypted stream");
2660 if (!gst_byte_reader_get_uint8 (&br, &iv_size))
2663 if (!gst_byte_reader_get_data (&br, 16, &kid))
2666 kid_buf = gst_buffer_new_allocate (NULL, 16, NULL);
2667 gst_buffer_fill (kid_buf, 0, kid, 16);
2668 if (ss_info->default_properties)
2669 gst_structure_free (ss_info->default_properties);
2670 ss_info->default_properties =
2671 gst_structure_new ("application/x-cenc",
2672 "iv_size", G_TYPE_UINT, iv_size,
2673 "encrypted", G_TYPE_BOOLEAN, is_encrypted,
2674 "kid", GST_TYPE_BUFFER, kid_buf, NULL);
2675 GST_DEBUG_OBJECT (qtdemux, "default sample properties: "
2676 "is_encrypted=%u, iv_size=%u", is_encrypted, iv_size);
2677 gst_buffer_unref (kid_buf);
2678 } else if ((flags & 0x000002)) {
2679 uses_sub_sample_encryption = TRUE;
2682 if (!gst_byte_reader_get_uint32_be (&br, &qtdemux->cenc_aux_sample_count)) {
2683 GST_ERROR_OBJECT (qtdemux, "Error getting box's sample count field");
2687 ss_info->crypto_info =
2688 g_ptr_array_new_full (qtdemux->cenc_aux_sample_count,
2689 (GDestroyNotify) qtdemux_gst_structure_free);
2691 for (i = 0; i < qtdemux->cenc_aux_sample_count; ++i) {
2692 GstStructure *properties;
2696 properties = qtdemux_get_cenc_sample_properties (qtdemux, stream, i);
2697 if (properties == NULL) {
2698 GST_ERROR_OBJECT (qtdemux, "failed to get properties for sample %u", i);
2702 if (!gst_byte_reader_dup_data (&br, iv_size, &data)) {
2703 GST_ERROR_OBJECT (qtdemux, "IV data not present for sample %u", i);
2704 gst_structure_free (properties);
2707 buf = gst_buffer_new_wrapped (data, iv_size);
2708 gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL);
2709 gst_buffer_unref (buf);
2711 if (uses_sub_sample_encryption) {
2712 guint16 n_subsamples;
2714 if (!gst_byte_reader_get_uint16_be (&br, &n_subsamples)
2715 || n_subsamples == 0) {
2716 GST_ERROR_OBJECT (qtdemux,
2717 "failed to get subsample count for sample %u", i);
2718 gst_structure_free (properties);
2721 GST_LOG_OBJECT (qtdemux, "subsample count: %u", n_subsamples);
2722 if (!gst_byte_reader_dup_data (&br, n_subsamples * 6, &data)) {
2723 GST_ERROR_OBJECT (qtdemux, "failed to get subsample data for sample %u",
2725 gst_structure_free (properties);
2728 buf = gst_buffer_new_wrapped (data, n_subsamples * 6);
2729 gst_structure_set (properties,
2730 "subsample_count", G_TYPE_UINT, n_subsamples,
2731 "subsamples", GST_TYPE_BUFFER, buf, NULL);
2732 gst_buffer_unref (buf);
2734 gst_structure_set (properties, "subsample_count", G_TYPE_UINT, 0, NULL);
2737 g_ptr_array_add (ss_info->crypto_info, properties);
2742 qtdemux_parse_uuid (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2744 static const guint8 xmp_uuid[] = { 0xBE, 0x7A, 0xCF, 0xCB,
2745 0x97, 0xA9, 0x42, 0xE8,
2746 0x9C, 0x71, 0x99, 0x94,
2747 0x91, 0xE3, 0xAF, 0xAC
2749 static const guint8 playready_uuid[] = {
2750 0xd0, 0x8a, 0x4f, 0x18, 0x10, 0xf3, 0x4a, 0x82,
2751 0xb6, 0xc8, 0x32, 0xd8, 0xab, 0xa1, 0x83, 0xd3
2754 static const guint8 piff_sample_encryption_uuid[] = {
2755 0xa2, 0x39, 0x4f, 0x52, 0x5a, 0x9b, 0x4f, 0x14,
2756 0xa2, 0x44, 0x6c, 0x42, 0x7c, 0x64, 0x8d, 0xf4
2761 /* counts as header data */
2762 qtdemux->header_size += length;
2764 offset = (QT_UINT32 (buffer) == 0) ? 16 : 8;
2766 if (length <= offset + 16) {
2767 GST_DEBUG_OBJECT (qtdemux, "uuid atom is too short, skipping");
2771 if (memcmp (buffer + offset, xmp_uuid, 16) == 0) {
2773 GstTagList *taglist;
2775 buf = _gst_buffer_new_wrapped ((guint8 *) buffer + offset + 16,
2776 length - offset - 16, NULL);
2777 taglist = gst_tag_list_from_xmp_buffer (buf);
2778 gst_buffer_unref (buf);
2780 qtdemux_handle_xmp_taglist (qtdemux, qtdemux->tag_list, taglist);
2782 } else if (memcmp (buffer + offset, playready_uuid, 16) == 0) {
2784 const gunichar2 *s_utf16;
2787 len = GST_READ_UINT16_LE (buffer + offset + 0x30);
2788 s_utf16 = (const gunichar2 *) (buffer + offset + 0x32);
2789 contents = g_utf16_to_utf8 (s_utf16, len / 2, NULL, NULL, NULL);
2790 GST_ERROR_OBJECT (qtdemux, "contents: %s", contents);
2794 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT,
2795 (_("Cannot play stream because it is encrypted with PlayReady DRM.")),
2797 } else if (memcmp (buffer + offset, piff_sample_encryption_uuid, 16) == 0) {
2798 qtdemux_parse_piff (qtdemux, buffer, length, offset);
2800 GST_DEBUG_OBJECT (qtdemux, "Ignoring unknown uuid: %08x-%08x-%08x-%08x",
2801 GST_READ_UINT32_LE (buffer + offset),
2802 GST_READ_UINT32_LE (buffer + offset + 4),
2803 GST_READ_UINT32_LE (buffer + offset + 8),
2804 GST_READ_UINT32_LE (buffer + offset + 12));
2809 qtdemux_parse_sidx (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2811 GstSidxParser sidx_parser;
2812 GstIsoffParserResult res;
2815 gst_isoff_qt_sidx_parser_init (&sidx_parser);
2818 gst_isoff_qt_sidx_parser_add_data (&sidx_parser, buffer, length,
2820 GST_DEBUG_OBJECT (qtdemux, "sidx parse result: %d", res);
2821 if (res == GST_ISOFF_QT_PARSER_DONE) {
2822 check_update_duration (qtdemux, sidx_parser.cumulative_pts);
2824 gst_isoff_qt_sidx_parser_clear (&sidx_parser);
2827 /* caller verifies at least 8 bytes in buf */
2829 extract_initial_length_and_fourcc (const guint8 * data, guint size,
2830 guint64 * plength, guint32 * pfourcc)
2835 length = QT_UINT32 (data);
2836 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
2837 fourcc = QT_FOURCC (data + 4);
2838 GST_DEBUG ("atom type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
2841 length = G_MAXUINT64;
2842 } else if (length == 1 && size >= 16) {
2843 /* this means we have an extended size, which is the 64 bit value of
2844 * the next 8 bytes */
2845 length = QT_UINT64 (data + 8);
2846 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
2856 qtdemux_parse_mehd (GstQTDemux * qtdemux, GstByteReader * br)
2858 guint32 version = 0;
2859 GstClockTime duration = 0;
2861 if (!gst_byte_reader_get_uint32_be (br, &version))
2866 if (!gst_byte_reader_get_uint64_be (br, &duration))
2871 if (!gst_byte_reader_get_uint32_be (br, &dur))
2876 GST_INFO_OBJECT (qtdemux, "mehd duration: %" G_GUINT64_FORMAT, duration);
2877 qtdemux->duration = duration;
2883 GST_DEBUG_OBJECT (qtdemux, "parsing mehd failed");
2889 qtdemux_parse_trex (GstQTDemux * qtdemux, QtDemuxStream * stream,
2890 guint32 * ds_duration, guint32 * ds_size, guint32 * ds_flags)
2892 if (!stream->parsed_trex && qtdemux->moov_node) {
2894 GstByteReader trex_data;
2896 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
2898 trex = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_trex,
2901 guint32 id = 0, dur = 0, size = 0, flags = 0, dummy = 0;
2903 /* skip version/flags */
2904 if (!gst_byte_reader_skip (&trex_data, 4))
2906 if (!gst_byte_reader_get_uint32_be (&trex_data, &id))
2908 if (id != stream->track_id)
2910 /* sample description index; ignore */
2911 if (!gst_byte_reader_get_uint32_be (&trex_data, &dummy))
2913 if (!gst_byte_reader_get_uint32_be (&trex_data, &dur))
2915 if (!gst_byte_reader_get_uint32_be (&trex_data, &size))
2917 if (!gst_byte_reader_get_uint32_be (&trex_data, &flags))
2920 GST_DEBUG_OBJECT (qtdemux, "fragment defaults for stream %d; "
2921 "duration %d, size %d, flags 0x%x", stream->track_id,
2924 stream->parsed_trex = TRUE;
2925 stream->def_sample_duration = dur;
2926 stream->def_sample_size = size;
2927 stream->def_sample_flags = flags;
2930 /* iterate all siblings */
2931 trex = qtdemux_tree_get_sibling_by_type_full (trex, FOURCC_trex,
2937 *ds_duration = stream->def_sample_duration;
2938 *ds_size = stream->def_sample_size;
2939 *ds_flags = stream->def_sample_flags;
2941 /* even then, above values are better than random ... */
2942 if (G_UNLIKELY (!stream->parsed_trex)) {
2943 GST_WARNING_OBJECT (qtdemux,
2944 "failed to find fragment defaults for stream %d", stream->track_id);
2951 /* This method should be called whenever a more accurate duration might
2952 * have been found. It will update all relevant variables if/where needed
2955 check_update_duration (GstQTDemux * qtdemux, GstClockTime duration)
2959 GstClockTime prevdur;
2961 movdur = GSTTIME_TO_QTTIME (qtdemux, duration);
2963 if (movdur > qtdemux->duration) {
2964 prevdur = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
2965 GST_DEBUG_OBJECT (qtdemux,
2966 "Updating total duration to %" GST_TIME_FORMAT " was %" GST_TIME_FORMAT,
2967 GST_TIME_ARGS (duration), GST_TIME_ARGS (prevdur));
2968 qtdemux->duration = movdur;
2969 GST_DEBUG_OBJECT (qtdemux,
2970 "qtdemux->segment.duration: %" GST_TIME_FORMAT " .stop: %"
2971 GST_TIME_FORMAT, GST_TIME_ARGS (qtdemux->segment.duration),
2972 GST_TIME_ARGS (qtdemux->segment.stop));
2973 if (qtdemux->segment.duration == prevdur) {
2974 /* If the current segment has duration/stop identical to previous duration
2975 * update them also (because they were set at that point in time with
2976 * the wrong duration */
2977 /* We convert the value *from* the timescale version to avoid rounding errors */
2978 GstClockTime fixeddur = QTTIME_TO_GSTTIME (qtdemux, movdur);
2979 GST_DEBUG_OBJECT (qtdemux, "Updated segment.duration and segment.stop");
2980 qtdemux->segment.duration = fixeddur;
2981 qtdemux->segment.stop = fixeddur;
2984 for (i = 0; i < qtdemux->n_streams; i++) {
2985 QtDemuxStream *stream = qtdemux->streams[i];
2987 movdur = GSTTIME_TO_QTSTREAMTIME (stream, duration);
2988 if (movdur > stream->duration) {
2989 GST_DEBUG_OBJECT (qtdemux,
2990 "Updating stream #%d duration to %" GST_TIME_FORMAT, i,
2991 GST_TIME_ARGS (duration));
2992 stream->duration = movdur;
2993 if (stream->dummy_segment) {
2994 /* Update all dummy values to new duration */
2995 stream->segments[0].stop_time = duration;
2996 stream->segments[0].duration = duration;
2997 stream->segments[0].media_stop = duration;
2999 /* let downstream know we possibly have a new stop time */
3000 if (stream->segment_index != -1) {
3003 if (qtdemux->segment.rate >= 0) {
3004 pos = stream->segment.start;
3006 pos = stream->segment.stop;
3009 gst_qtdemux_stream_update_segment (qtdemux, stream,
3010 stream->segment_index, pos, NULL, NULL);
3019 qtdemux_parse_trun (GstQTDemux * qtdemux, GstByteReader * trun,
3020 QtDemuxStream * stream, guint32 d_sample_duration, guint32 d_sample_size,
3021 guint32 d_sample_flags, gint64 moof_offset, gint64 moof_length,
3022 gint64 * base_offset, gint64 * running_offset, gint64 decode_ts)
3024 GstClockTime gst_ts = GST_CLOCK_TIME_NONE;
3026 gint32 data_offset = 0;
3027 guint32 flags = 0, first_flags = 0, samples_count = 0;
3030 guint entry_size, dur_offset, size_offset, flags_offset = 0, ct_offset = 0;
3031 QtDemuxSample *sample;
3032 gboolean ismv = FALSE;
3033 gint64 initial_offset;
3035 GST_LOG_OBJECT (qtdemux, "parsing trun stream %d; "
3036 "default dur %d, size %d, flags 0x%x, base offset %" G_GINT64_FORMAT ", "
3037 "decode ts %" G_GINT64_FORMAT, stream->track_id, d_sample_duration,
3038 d_sample_size, d_sample_flags, *base_offset, decode_ts);
3040 if (stream->pending_seek && moof_offset < stream->pending_seek->moof_offset) {
3041 GST_INFO_OBJECT (stream->pad, "skipping trun before seek target fragment");
3045 /* presence of stss or not can't really tell us much,
3046 * and flags and so on tend to be marginally reliable in these files */
3047 if (stream->subtype == FOURCC_soun) {
3048 GST_DEBUG_OBJECT (qtdemux,
3049 "sound track in fragmented file; marking all keyframes");
3050 stream->all_keyframe = TRUE;
3053 if (!gst_byte_reader_skip (trun, 1) ||
3054 !gst_byte_reader_get_uint24_be (trun, &flags))
3057 if (!gst_byte_reader_get_uint32_be (trun, &samples_count))
3060 if (flags & TR_DATA_OFFSET) {
3061 /* note this is really signed */
3062 if (!gst_byte_reader_get_int32_be (trun, &data_offset))
3064 GST_LOG_OBJECT (qtdemux, "trun data offset %d", data_offset);
3065 /* default base offset = first byte of moof */
3066 if (*base_offset == -1) {
3067 GST_LOG_OBJECT (qtdemux, "base_offset at moof");
3068 *base_offset = moof_offset;
3070 *running_offset = *base_offset + data_offset;
3072 /* if no offset at all, that would mean data starts at moof start,
3073 * which is a bit wrong and is ismv crappy way, so compensate
3074 * assuming data is in mdat following moof */
3075 if (*base_offset == -1) {
3076 *base_offset = moof_offset + moof_length + 8;
3077 GST_LOG_OBJECT (qtdemux, "base_offset assumed in mdat after moof");
3080 if (*running_offset == -1)
3081 *running_offset = *base_offset;
3084 GST_LOG_OBJECT (qtdemux, "running offset now %" G_GINT64_FORMAT,
3086 GST_LOG_OBJECT (qtdemux, "trun offset %d, flags 0x%x, entries %d",
3087 data_offset, flags, samples_count);
3089 if (flags & TR_FIRST_SAMPLE_FLAGS) {
3090 if (G_UNLIKELY (flags & TR_SAMPLE_FLAGS)) {
3091 GST_DEBUG_OBJECT (qtdemux,
3092 "invalid flags; SAMPLE and FIRST_SAMPLE present, discarding latter");
3093 flags ^= TR_FIRST_SAMPLE_FLAGS;
3095 if (!gst_byte_reader_get_uint32_be (trun, &first_flags))
3097 GST_LOG_OBJECT (qtdemux, "first flags: 0x%x", first_flags);
3101 /* FIXME ? spec says other bits should also be checked to determine
3102 * entry size (and prefix size for that matter) */
3104 dur_offset = size_offset = 0;
3105 if (flags & TR_SAMPLE_DURATION) {
3106 GST_LOG_OBJECT (qtdemux, "entry duration present");
3107 dur_offset = entry_size;
3110 if (flags & TR_SAMPLE_SIZE) {
3111 GST_LOG_OBJECT (qtdemux, "entry size present");
3112 size_offset = entry_size;
3115 if (flags & TR_SAMPLE_FLAGS) {
3116 GST_LOG_OBJECT (qtdemux, "entry flags present");
3117 flags_offset = entry_size;
3120 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
3121 GST_LOG_OBJECT (qtdemux, "entry ct offset present");
3122 ct_offset = entry_size;
3126 if (!qt_atom_parser_has_chunks (trun, samples_count, entry_size))
3128 data = (guint8 *) gst_byte_reader_peek_data_unchecked (trun);
3130 if (stream->n_samples + samples_count >=
3131 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample))
3134 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
3135 stream->n_samples + samples_count, (guint) sizeof (QtDemuxSample),
3136 (stream->n_samples + samples_count) *
3137 sizeof (QtDemuxSample) / (1024.0 * 1024.0));
3139 /* create a new array of samples if it's the first sample parsed */
3140 if (stream->n_samples == 0) {
3141 g_assert (stream->samples == NULL);
3142 stream->samples = g_try_new0 (QtDemuxSample, samples_count);
3143 /* or try to reallocate it with space enough to insert the new samples */
3145 stream->samples = g_try_renew (QtDemuxSample, stream->samples,
3146 stream->n_samples + samples_count);
3147 if (stream->samples == NULL)
3150 if (qtdemux->fragment_start != -1) {
3151 timestamp = GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->fragment_start);
3152 qtdemux->fragment_start = -1;
3154 if (stream->n_samples == 0) {
3155 if (decode_ts > 0) {
3156 timestamp = decode_ts;
3157 } else if (stream->pending_seek != NULL) {
3158 /* if we don't have a timestamp from a tfdt box, we'll use the one
3159 * from the mfra seek table */
3160 GST_INFO_OBJECT (stream->pad, "pending seek ts = %" GST_TIME_FORMAT,
3161 GST_TIME_ARGS (stream->pending_seek->ts));
3163 /* FIXME: this is not fully correct, the timestamp refers to the random
3164 * access sample refered to in the tfra entry, which may not necessarily
3165 * be the first sample in the tfrag/trun (but hopefully/usually is) */
3166 timestamp = GSTTIME_TO_QTSTREAMTIME (stream, stream->pending_seek->ts);
3171 gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
3172 GST_INFO_OBJECT (stream->pad, "first sample ts %" GST_TIME_FORMAT,
3173 GST_TIME_ARGS (gst_ts));
3175 /* subsequent fragments extend stream */
3177 stream->samples[stream->n_samples - 1].timestamp +
3178 stream->samples[stream->n_samples - 1].duration;
3180 /* If this is a GST_FORMAT_BYTES stream and there's a significant
3181 * difference (1 sec.) between decode_ts and timestamp, prefer the
3183 if (!qtdemux->upstream_format_is_time
3184 && ABSDIFF (decode_ts, timestamp) >
3185 MAX (stream->duration_last_moof / 2,
3186 GSTTIME_TO_QTSTREAMTIME (stream, GST_SECOND))) {
3187 GST_INFO_OBJECT (qtdemux,
3188 "decode_ts (%" GST_TIME_FORMAT ") and timestamp (%" GST_TIME_FORMAT
3189 ") are significantly different (more than %" GST_TIME_FORMAT
3190 "), using decode_ts",
3191 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, decode_ts)),
3192 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, timestamp)),
3193 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream,
3194 MAX (stream->duration_last_moof / 2,
3195 GSTTIME_TO_QTSTREAMTIME (stream, GST_SECOND)))));
3196 timestamp = decode_ts;
3199 gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
3200 GST_INFO_OBJECT (qtdemux, "first sample ts %" GST_TIME_FORMAT
3201 " (extends previous samples)", GST_TIME_ARGS (gst_ts));
3205 initial_offset = *running_offset;
3207 sample = stream->samples + stream->n_samples;
3208 for (i = 0; i < samples_count; i++) {
3209 guint32 dur, size, sflags, ct;
3211 /* first read sample data */
3212 if (flags & TR_SAMPLE_DURATION) {
3213 dur = QT_UINT32 (data + dur_offset);
3215 dur = d_sample_duration;
3217 if (flags & TR_SAMPLE_SIZE) {
3218 size = QT_UINT32 (data + size_offset);
3220 size = d_sample_size;
3222 if (flags & TR_FIRST_SAMPLE_FLAGS) {
3224 sflags = first_flags;
3226 sflags = d_sample_flags;
3228 } else if (flags & TR_SAMPLE_FLAGS) {
3229 sflags = QT_UINT32 (data + flags_offset);
3231 sflags = d_sample_flags;
3233 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
3234 ct = QT_UINT32 (data + ct_offset);
3240 /* fill the sample information */
3241 sample->offset = *running_offset;
3242 sample->pts_offset = ct;
3243 sample->size = size;
3244 sample->timestamp = timestamp;
3245 sample->duration = dur;
3246 /* sample-is-difference-sample */
3247 /* ismv seems to use 0x40 for keyframe, 0xc0 for non-keyframe,
3248 * now idea how it relates to bitfield other than massive LE/BE confusion */
3249 sample->keyframe = ismv ? ((sflags & 0xff) == 0x40) : !(sflags & 0x10000);
3250 *running_offset += size;
3252 stream->duration_moof += dur;
3256 /* Update total duration if needed */
3257 check_update_duration (qtdemux, QTSTREAMTIME_TO_GSTTIME (stream, timestamp));
3259 /* Pre-emptively figure out size of mdat based on trun information.
3260 * If the [mdat] atom is effectivelly read, it will be replaced by the actual
3261 * size, else we will still be able to use this when dealing with gap'ed
3263 qtdemux->mdatleft = *running_offset - initial_offset;
3265 stream->n_samples += samples_count;
3266 stream->n_samples_moof += samples_count;
3268 if (stream->pending_seek != NULL)
3269 stream->pending_seek = NULL;
3275 GST_WARNING_OBJECT (qtdemux, "failed to parse trun");
3280 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
3286 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
3287 "be larger than %uMB (broken file?)", stream->n_samples,
3288 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
3293 /* find stream with @id */
3294 static inline QtDemuxStream *
3295 qtdemux_find_stream (GstQTDemux * qtdemux, guint32 id)
3297 QtDemuxStream *stream;
3301 if (G_UNLIKELY (!id)) {
3302 GST_DEBUG_OBJECT (qtdemux, "invalid track id 0");
3306 /* try to get it fast and simple */
3307 if (G_LIKELY (id <= qtdemux->n_streams)) {
3308 stream = qtdemux->streams[id - 1];
3309 if (G_LIKELY (stream->track_id == id))
3313 /* linear search otherwise */
3314 for (i = 0; i < qtdemux->n_streams; i++) {
3315 stream = qtdemux->streams[i];
3316 if (stream->track_id == id)
3319 if (qtdemux->mss_mode) {
3320 /* mss should have only 1 stream anyway */
3321 return qtdemux->streams[0];
3328 qtdemux_parse_mfhd (GstQTDemux * qtdemux, GstByteReader * mfhd,
3329 guint32 * fragment_number)
3331 if (!gst_byte_reader_skip (mfhd, 4))
3333 if (!gst_byte_reader_get_uint32_be (mfhd, fragment_number))
3338 GST_WARNING_OBJECT (qtdemux, "Failed to parse mfhd atom");
3344 qtdemux_parse_tfhd (GstQTDemux * qtdemux, GstByteReader * tfhd,
3345 QtDemuxStream ** stream, guint32 * default_sample_duration,
3346 guint32 * default_sample_size, guint32 * default_sample_flags,
3347 gint64 * base_offset)
3350 guint32 track_id = 0;
3352 if (!gst_byte_reader_skip (tfhd, 1) ||
3353 !gst_byte_reader_get_uint24_be (tfhd, &flags))
3356 if (!gst_byte_reader_get_uint32_be (tfhd, &track_id))
3359 *stream = qtdemux_find_stream (qtdemux, track_id);
3360 if (G_UNLIKELY (!*stream))
3361 goto unknown_stream;
3363 if (flags & TF_DEFAULT_BASE_IS_MOOF)
3364 *base_offset = qtdemux->moof_offset;
3366 if (flags & TF_BASE_DATA_OFFSET)
3367 if (!gst_byte_reader_get_uint64_be (tfhd, (guint64 *) base_offset))
3370 /* obtain stream defaults */
3371 qtdemux_parse_trex (qtdemux, *stream,
3372 default_sample_duration, default_sample_size, default_sample_flags);
3374 /* FIXME: Handle TF_SAMPLE_DESCRIPTION_INDEX properly */
3375 if (flags & TF_SAMPLE_DESCRIPTION_INDEX)
3376 if (!gst_byte_reader_skip (tfhd, 4))
3379 if (flags & TF_DEFAULT_SAMPLE_DURATION)
3380 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_duration))
3383 if (flags & TF_DEFAULT_SAMPLE_SIZE)
3384 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_size))
3387 if (flags & TF_DEFAULT_SAMPLE_FLAGS)
3388 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_flags))
3395 GST_WARNING_OBJECT (qtdemux, "invalid track fragment header");
3400 GST_DEBUG_OBJECT (qtdemux, "unknown stream in tfhd");
3406 qtdemux_parse_tfdt (GstQTDemux * qtdemux, GstByteReader * br,
3407 guint64 * decode_time)
3409 guint32 version = 0;
3411 if (!gst_byte_reader_get_uint32_be (br, &version))
3416 if (!gst_byte_reader_get_uint64_be (br, decode_time))
3419 guint32 dec_time = 0;
3420 if (!gst_byte_reader_get_uint32_be (br, &dec_time))
3422 *decode_time = dec_time;
3425 GST_INFO_OBJECT (qtdemux, "Track fragment decode time: %" G_GUINT64_FORMAT,
3432 GST_DEBUG_OBJECT (qtdemux, "parsing tfdt failed");
3437 /* Returns a pointer to a GstStructure containing the properties of
3438 * the stream sample identified by @sample_index. The caller must unref
3439 * the returned object after use. Returns NULL if unsuccessful. */
3440 static GstStructure *
3441 qtdemux_get_cenc_sample_properties (GstQTDemux * qtdemux,
3442 QtDemuxStream * stream, guint sample_index)
3444 QtDemuxCencSampleSetInfo *info = NULL;
3446 g_return_val_if_fail (stream != NULL, NULL);
3447 g_return_val_if_fail (stream->protected, NULL);
3448 g_return_val_if_fail (stream->protection_scheme_info != NULL, NULL);
3450 info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
3452 /* Currently, cenc properties for groups of samples are not supported, so
3453 * simply return a copy of the default sample properties */
3454 return gst_structure_copy (info->default_properties);
3457 /* Parses the sizes of sample auxiliary information contained within a stream,
3458 * as given in a saiz box. Returns array of sample_count guint8 size values,
3459 * or NULL on failure */
3461 qtdemux_parse_saiz (GstQTDemux * qtdemux, QtDemuxStream * stream,
3462 GstByteReader * br, guint32 * sample_count)
3466 guint8 default_info_size;
3468 g_return_val_if_fail (qtdemux != NULL, NULL);
3469 g_return_val_if_fail (stream != NULL, NULL);
3470 g_return_val_if_fail (br != NULL, NULL);
3471 g_return_val_if_fail (sample_count != NULL, NULL);
3473 if (!gst_byte_reader_get_uint32_be (br, &flags))
3477 /* aux_info_type and aux_info_type_parameter are ignored */
3478 if (!gst_byte_reader_skip (br, 8))
3482 if (!gst_byte_reader_get_uint8 (br, &default_info_size))
3484 GST_DEBUG_OBJECT (qtdemux, "default_info_size: %u", default_info_size);
3486 if (!gst_byte_reader_get_uint32_be (br, sample_count))
3488 GST_DEBUG_OBJECT (qtdemux, "sample_count: %u", *sample_count);
3491 if (default_info_size == 0) {
3492 if (!gst_byte_reader_dup_data (br, *sample_count, &info_sizes)) {
3496 info_sizes = g_new (guint8, *sample_count);
3497 memset (info_sizes, default_info_size, *sample_count);
3503 /* Parses the offset of sample auxiliary information contained within a stream,
3504 * as given in a saio box. Returns TRUE if successful; FALSE otherwise. */
3506 qtdemux_parse_saio (GstQTDemux * qtdemux, QtDemuxStream * stream,
3507 GstByteReader * br, guint32 * info_type, guint32 * info_type_parameter,
3512 guint32 aux_info_type = 0;
3513 guint32 aux_info_type_parameter = 0;
3514 guint32 entry_count;
3517 const guint8 *aux_info_type_data = NULL;
3519 g_return_val_if_fail (qtdemux != NULL, FALSE);
3520 g_return_val_if_fail (stream != NULL, FALSE);
3521 g_return_val_if_fail (br != NULL, FALSE);
3522 g_return_val_if_fail (offset != NULL, FALSE);
3524 if (!gst_byte_reader_get_uint8 (br, &version))
3527 if (!gst_byte_reader_get_uint24_be (br, &flags))
3532 if (!gst_byte_reader_get_data (br, 4, &aux_info_type_data))
3534 aux_info_type = QT_FOURCC (aux_info_type_data);
3536 if (!gst_byte_reader_get_uint32_be (br, &aux_info_type_parameter))
3538 } else if (stream->protected) {
3539 aux_info_type = stream->protection_scheme_type;
3541 aux_info_type = stream->fourcc;
3545 *info_type = aux_info_type;
3546 if (info_type_parameter)
3547 *info_type_parameter = aux_info_type_parameter;
3549 GST_DEBUG_OBJECT (qtdemux, "aux_info_type: '%" GST_FOURCC_FORMAT "', "
3550 "aux_info_type_parameter: %#06x",
3551 GST_FOURCC_ARGS (aux_info_type), aux_info_type_parameter);
3553 if (!gst_byte_reader_get_uint32_be (br, &entry_count))
3556 if (entry_count != 1) {
3557 GST_ERROR_OBJECT (qtdemux, "multiple offsets are not supported");
3562 if (!gst_byte_reader_get_uint32_be (br, &off_32))
3564 *offset = (guint64) off_32;
3566 if (!gst_byte_reader_get_uint64_be (br, &off_64))
3571 GST_DEBUG_OBJECT (qtdemux, "offset: %" G_GUINT64_FORMAT, *offset);
3576 qtdemux_gst_structure_free (GstStructure * gststructure)
3579 gst_structure_free (gststructure);
3583 /* Parses auxiliary information relating to samples protected using Common
3584 * Encryption (cenc); the format of this information is defined in
3585 * ISO/IEC 23001-7. Returns TRUE if successful; FALSE otherwise. */
3587 qtdemux_parse_cenc_aux_info (GstQTDemux * qtdemux, QtDemuxStream * stream,
3588 GstByteReader * br, guint8 * info_sizes, guint32 sample_count)
3590 QtDemuxCencSampleSetInfo *ss_info = NULL;
3594 g_return_val_if_fail (qtdemux != NULL, FALSE);
3595 g_return_val_if_fail (stream != NULL, FALSE);
3596 g_return_val_if_fail (br != NULL, FALSE);
3597 g_return_val_if_fail (stream->protected, FALSE);
3598 g_return_val_if_fail (stream->protection_scheme_info != NULL, FALSE);
3600 ss_info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
3602 if (ss_info->crypto_info) {
3603 GST_LOG_OBJECT (qtdemux, "unreffing existing crypto_info");
3604 g_ptr_array_free (ss_info->crypto_info, TRUE);
3607 ss_info->crypto_info =
3608 g_ptr_array_new_full (sample_count,
3609 (GDestroyNotify) qtdemux_gst_structure_free);
3611 for (i = 0; i < sample_count; ++i) {
3612 GstStructure *properties;
3613 guint16 n_subsamples = 0;
3618 properties = qtdemux_get_cenc_sample_properties (qtdemux, stream, i);
3619 if (properties == NULL) {
3620 GST_ERROR_OBJECT (qtdemux, "failed to get properties for sample %u", i);
3623 if (!gst_structure_get_uint (properties, "iv_size", &iv_size)) {
3624 GST_ERROR_OBJECT (qtdemux, "failed to get iv_size for sample %u", i);
3625 gst_structure_free (properties);
3628 if (!gst_byte_reader_dup_data (br, iv_size, &data)) {
3629 GST_ERROR_OBJECT (qtdemux, "failed to get IV for sample %u", i);
3630 gst_structure_free (properties);
3633 buf = gst_buffer_new_wrapped (data, iv_size);
3634 gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL);
3635 gst_buffer_unref (buf);
3636 size = info_sizes[i];
3637 if (size > iv_size) {
3638 if (!gst_byte_reader_get_uint16_be (br, &n_subsamples)
3639 || !(n_subsamples > 0)) {
3640 gst_structure_free (properties);
3641 GST_ERROR_OBJECT (qtdemux,
3642 "failed to get subsample count for sample %u", i);
3645 GST_LOG_OBJECT (qtdemux, "subsample count: %u", n_subsamples);
3646 if (!gst_byte_reader_dup_data (br, n_subsamples * 6, &data)) {
3647 GST_ERROR_OBJECT (qtdemux, "failed to get subsample data for sample %u",
3649 gst_structure_free (properties);
3652 buf = gst_buffer_new_wrapped (data, n_subsamples * 6);
3654 gst_structure_free (properties);
3657 gst_structure_set (properties,
3658 "subsample_count", G_TYPE_UINT, n_subsamples,
3659 "subsamples", GST_TYPE_BUFFER, buf, NULL);
3660 gst_buffer_unref (buf);
3662 gst_structure_set (properties, "subsample_count", G_TYPE_UINT, 0, NULL);
3664 g_ptr_array_add (ss_info->crypto_info, properties);
3669 /* Converts a UUID in raw byte form to a string representation, as defined in
3670 * RFC 4122. The caller takes ownership of the returned string and is
3671 * responsible for freeing it after use. */
3673 qtdemux_uuid_bytes_to_string (gconstpointer uuid_bytes)
3675 const guint8 *uuid = (const guint8 *) uuid_bytes;
3677 return g_strdup_printf ("%02x%02x%02x%02x-%02x%02x-%02x%02x-"
3678 "%02x%02x-%02x%02x%02x%02x%02x%02x",
3679 uuid[0], uuid[1], uuid[2], uuid[3],
3680 uuid[4], uuid[5], uuid[6], uuid[7],
3681 uuid[8], uuid[9], uuid[10], uuid[11],
3682 uuid[12], uuid[13], uuid[14], uuid[15]);
3685 /* Parses a Protection System Specific Header box (pssh), as defined in the
3686 * Common Encryption (cenc) standard (ISO/IEC 23001-7), which contains
3687 * information needed by a specific content protection system in order to
3688 * decrypt cenc-protected tracks. Returns TRUE if successful; FALSE
3691 qtdemux_parse_pssh (GstQTDemux * qtdemux, GNode * node)
3693 gchar *sysid_string;
3694 guint32 pssh_size = QT_UINT32 (node->data);
3695 GstBuffer *pssh = NULL;
3696 GstEvent *event = NULL;
3697 guint32 parent_box_type;
3700 if (G_UNLIKELY (pssh_size < 32U)) {
3701 GST_ERROR_OBJECT (qtdemux, "invalid box size");
3706 qtdemux_uuid_bytes_to_string ((const guint8 *) node->data + 12);
3708 gst_qtdemux_append_protection_system_id (qtdemux, sysid_string);
3710 pssh = gst_buffer_new_wrapped (g_memdup (node->data, pssh_size), pssh_size);
3711 GST_LOG_OBJECT (qtdemux, "cenc pssh size: %" G_GSIZE_FORMAT,
3712 gst_buffer_get_size (pssh));
3714 parent_box_type = QT_FOURCC ((const guint8 *) node->parent->data + 4);
3716 /* Push an event containing the pssh box onto the queues of all streams. */
3717 event = gst_event_new_protection (sysid_string, pssh,
3718 (parent_box_type == FOURCC_moov) ? "isobmff/moov" : "isobmff/moof");
3719 for (i = 0; i < qtdemux->n_streams; ++i) {
3720 g_queue_push_tail (&qtdemux->streams[i]->protection_scheme_event_queue,
3721 gst_event_ref (event));
3723 g_free (sysid_string);
3724 gst_event_unref (event);
3725 gst_buffer_unref (pssh);
3730 qtdemux_parse_moof (GstQTDemux * qtdemux, const guint8 * buffer, guint length,
3731 guint64 moof_offset, QtDemuxStream * stream)
3733 GNode *moof_node, *traf_node, *tfhd_node, *trun_node, *tfdt_node, *mfhd_node;
3735 GstByteReader mfhd_data, trun_data, tfhd_data, tfdt_data;
3736 GNode *saiz_node, *saio_node, *pssh_node;
3737 GstByteReader saiz_data, saio_data;
3738 guint32 ds_size = 0, ds_duration = 0, ds_flags = 0;
3739 gint64 base_offset, running_offset;
3742 /* NOTE @stream ignored */
3744 moof_node = g_node_new ((guint8 *) buffer);
3745 qtdemux_parse_node (qtdemux, moof_node, buffer, length);
3746 qtdemux_node_dump (qtdemux, moof_node);
3748 /* Get fragment number from mfhd and check it's valid */
3750 qtdemux_tree_get_child_by_type_full (moof_node, FOURCC_mfhd, &mfhd_data);
3751 if (mfhd_node == NULL)
3753 if (!qtdemux_parse_mfhd (qtdemux, &mfhd_data, &frag_num))
3755 GST_DEBUG_OBJECT (qtdemux, "Fragment #%d", frag_num);
3757 /* unknown base_offset to start with */
3758 base_offset = running_offset = -1;
3759 traf_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_traf);
3761 guint64 decode_time = 0;
3763 /* Fragment Header node */
3765 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfhd,
3769 if (!qtdemux_parse_tfhd (qtdemux, &tfhd_data, &stream, &ds_duration,
3770 &ds_size, &ds_flags, &base_offset))
3773 /* The following code assumes at most a single set of sample auxiliary
3774 * data in the fragment (consisting of a saiz box and a corresponding saio
3775 * box); in theory, however, there could be multiple sets of sample
3776 * auxiliary data in a fragment. */
3778 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saiz,
3781 guint32 info_type = 0;
3783 guint32 info_type_parameter = 0;
3785 g_free (qtdemux->cenc_aux_info_sizes);
3787 qtdemux->cenc_aux_info_sizes =
3788 qtdemux_parse_saiz (qtdemux, stream, &saiz_data,
3789 &qtdemux->cenc_aux_sample_count);
3790 if (qtdemux->cenc_aux_info_sizes == NULL) {
3791 GST_ERROR_OBJECT (qtdemux, "failed to parse saiz box");
3795 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saio,
3798 GST_ERROR_OBJECT (qtdemux, "saiz box without a corresponding saio box");
3799 g_free (qtdemux->cenc_aux_info_sizes);
3800 qtdemux->cenc_aux_info_sizes = NULL;
3804 if (G_UNLIKELY (!qtdemux_parse_saio (qtdemux, stream, &saio_data,
3805 &info_type, &info_type_parameter, &offset))) {
3806 GST_ERROR_OBJECT (qtdemux, "failed to parse saio box");
3807 g_free (qtdemux->cenc_aux_info_sizes);
3808 qtdemux->cenc_aux_info_sizes = NULL;
3811 if (base_offset > -1 && base_offset > qtdemux->moof_offset)
3812 offset += (guint64) (base_offset - qtdemux->moof_offset);
3813 if (info_type == FOURCC_cenc && info_type_parameter == 0U) {
3815 if (offset > length) {
3816 GST_DEBUG_OBJECT (qtdemux, "cenc auxiliary info stored out of moof");
3817 qtdemux->cenc_aux_info_offset = offset;
3819 gst_byte_reader_init (&br, buffer + offset, length - offset);
3820 if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
3821 qtdemux->cenc_aux_info_sizes,
3822 qtdemux->cenc_aux_sample_count)) {
3823 GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
3824 g_free (qtdemux->cenc_aux_info_sizes);
3825 qtdemux->cenc_aux_info_sizes = NULL;
3833 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfdt,
3836 /* We'll use decode_time to interpolate timestamps
3837 * in case the input timestamps are missing */
3838 qtdemux_parse_tfdt (qtdemux, &tfdt_data, &decode_time);
3840 GST_DEBUG_OBJECT (qtdemux, "decode time %" G_GINT64_FORMAT
3841 " (%" GST_TIME_FORMAT ")", decode_time,
3842 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, decode_time)));
3844 /* Discard the fragment buffer timestamp info to avoid using it.
3845 * Rely on tfdt instead as it is more accurate than the timestamp
3846 * that is fetched from a manifest/playlist and is usually
3848 qtdemux->fragment_start = -1;
3851 if (G_UNLIKELY (!stream)) {
3852 /* we lost track of offset, we'll need to regain it,
3853 * but can delay complaining until later or avoid doing so altogether */
3857 if (G_UNLIKELY (base_offset < -1))
3860 if (qtdemux->upstream_format_is_time)
3861 gst_qtdemux_stream_flush_samples_data (qtdemux, stream);
3863 /* initialise moof sample data */
3864 stream->n_samples_moof = 0;
3865 stream->duration_last_moof = stream->duration_moof;
3866 stream->duration_moof = 0;
3868 /* Track Run node */
3870 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_trun,
3873 qtdemux_parse_trun (qtdemux, &trun_data, stream,
3874 ds_duration, ds_size, ds_flags, moof_offset, length, &base_offset,
3875 &running_offset, decode_time);
3876 /* iterate all siblings */
3877 trun_node = qtdemux_tree_get_sibling_by_type_full (trun_node, FOURCC_trun,
3881 uuid_node = qtdemux_tree_get_child_by_type (traf_node, FOURCC_uuid);
3883 guint8 *uuid_buffer = (guint8 *) uuid_node->data;
3884 guint32 box_length = QT_UINT32 (uuid_buffer);
3886 qtdemux_parse_uuid (qtdemux, uuid_buffer, box_length);
3889 /* if no new base_offset provided for next traf,
3890 * base is end of current traf */
3891 base_offset = running_offset;
3892 running_offset = -1;
3894 if (stream->n_samples_moof && stream->duration_moof)
3895 stream->new_caps = TRUE;
3898 /* iterate all siblings */
3899 traf_node = qtdemux_tree_get_sibling_by_type (traf_node, FOURCC_traf);
3902 /* parse any protection system info */
3903 pssh_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_pssh);
3905 GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
3906 qtdemux_parse_pssh (qtdemux, pssh_node);
3907 pssh_node = qtdemux_tree_get_sibling_by_type (pssh_node, FOURCC_pssh);
3910 g_node_destroy (moof_node);
3915 GST_DEBUG_OBJECT (qtdemux, "missing tfhd box");
3920 GST_DEBUG_OBJECT (qtdemux, "Missing mfhd box");
3925 GST_DEBUG_OBJECT (qtdemux, "lost offset");
3930 g_node_destroy (moof_node);
3931 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
3932 (_("This file is corrupt and cannot be played.")), (NULL));
3938 /* might be used if some day we actually use mfra & co
3939 * for random access to fragments,
3940 * but that will require quite some modifications and much less relying
3941 * on a sample array */
3945 qtdemux_parse_tfra (GstQTDemux * qtdemux, GNode * tfra_node)
3947 QtDemuxStream *stream;
3948 guint32 ver_flags, track_id, len, num_entries, i;
3949 guint value_size, traf_size, trun_size, sample_size;
3950 guint64 time = 0, moof_offset = 0;
3952 GstBuffer *buf = NULL;
3957 gst_byte_reader_init (&tfra, tfra_node->data, QT_UINT32 (tfra_node->data));
3959 if (!gst_byte_reader_skip (&tfra, 8))
3962 if (!gst_byte_reader_get_uint32_be (&tfra, &ver_flags))
3965 if (!gst_byte_reader_get_uint32_be (&tfra, &track_id)
3966 || !gst_byte_reader_get_uint32_be (&tfra, &len)
3967 || !gst_byte_reader_get_uint32_be (&tfra, &num_entries))
3970 GST_DEBUG_OBJECT (qtdemux, "parsing tfra box for track id %u", track_id);
3972 stream = qtdemux_find_stream (qtdemux, track_id);
3974 goto unknown_trackid;
3976 value_size = ((ver_flags >> 24) == 1) ? sizeof (guint64) : sizeof (guint32);
3977 sample_size = (len & 3) + 1;
3978 trun_size = ((len & 12) >> 2) + 1;
3979 traf_size = ((len & 48) >> 4) + 1;
3981 GST_DEBUG_OBJECT (qtdemux, "%u entries, sizes: value %u, traf %u, trun %u, "
3982 "sample %u", num_entries, value_size, traf_size, trun_size, sample_size);
3984 if (num_entries == 0)
3987 if (!qt_atom_parser_has_chunks (&tfra, num_entries,
3988 value_size + value_size + traf_size + trun_size + sample_size))
3991 g_free (stream->ra_entries);
3992 stream->ra_entries = g_new (QtDemuxRandomAccessEntry, num_entries);
3993 stream->n_ra_entries = num_entries;
3995 for (i = 0; i < num_entries; i++) {
3996 qt_atom_parser_get_offset (&tfra, value_size, &time);
3997 qt_atom_parser_get_offset (&tfra, value_size, &moof_offset);
3998 qt_atom_parser_get_uint_with_size_unchecked (&tfra, traf_size);
3999 qt_atom_parser_get_uint_with_size_unchecked (&tfra, trun_size);
4000 qt_atom_parser_get_uint_with_size_unchecked (&tfra, sample_size);
4002 time = QTSTREAMTIME_TO_GSTTIME (stream, time);
4004 GST_LOG_OBJECT (qtdemux, "fragment time: %" GST_TIME_FORMAT ", "
4005 " moof_offset: %" G_GUINT64_FORMAT, GST_TIME_ARGS (time), moof_offset);
4007 stream->ra_entries[i].ts = time;
4008 stream->ra_entries[i].moof_offset = moof_offset;
4010 /* don't want to go through the entire file and read all moofs at startup */
4012 ret = gst_qtdemux_pull_atom (qtdemux, moof_offset, 0, &buf);
4013 if (ret != GST_FLOW_OK)
4015 qtdemux_parse_moof (qtdemux, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf),
4016 moof_offset, stream);
4017 gst_buffer_unref (buf);
4021 check_update_duration (qtdemux, time);
4028 GST_WARNING_OBJECT (qtdemux, "Couldn't find stream for track %u", track_id);
4033 GST_WARNING_OBJECT (qtdemux, "broken traf box, ignoring");
4038 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
4044 qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux)
4046 GstMapInfo mfro_map = GST_MAP_INFO_INIT;
4047 GstMapInfo mfra_map = GST_MAP_INFO_INIT;
4048 GstBuffer *mfro = NULL, *mfra = NULL;
4050 gboolean ret = FALSE;
4051 GNode *mfra_node, *tfra_node;
4052 guint64 mfra_offset = 0;
4053 guint32 fourcc, mfra_size;
4056 /* query upstream size in bytes */
4057 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &len))
4058 goto size_query_failed;
4060 /* mfro box should be at the very end of the file */
4061 flow = gst_qtdemux_pull_atom (qtdemux, len - 16, 16, &mfro);
4062 if (flow != GST_FLOW_OK)
4065 gst_buffer_map (mfro, &mfro_map, GST_MAP_READ);
4067 fourcc = QT_FOURCC (mfro_map.data + 4);
4068 if (fourcc != FOURCC_mfro)
4071 GST_INFO_OBJECT (qtdemux, "Found mfro box");
4072 if (mfro_map.size < 16)
4073 goto invalid_mfro_size;
4075 mfra_size = QT_UINT32 (mfro_map.data + 12);
4076 if (mfra_size >= len)
4077 goto invalid_mfra_size;
4079 mfra_offset = len - mfra_size;
4081 GST_INFO_OBJECT (qtdemux, "mfra offset: %" G_GUINT64_FORMAT ", size %u",
4082 mfra_offset, mfra_size);
4084 /* now get and parse mfra box */
4085 flow = gst_qtdemux_pull_atom (qtdemux, mfra_offset, mfra_size, &mfra);
4086 if (flow != GST_FLOW_OK)
4089 gst_buffer_map (mfra, &mfra_map, GST_MAP_READ);
4091 mfra_node = g_node_new ((guint8 *) mfra_map.data);
4092 qtdemux_parse_node (qtdemux, mfra_node, mfra_map.data, mfra_map.size);
4094 tfra_node = qtdemux_tree_get_child_by_type (mfra_node, FOURCC_tfra);
4097 qtdemux_parse_tfra (qtdemux, tfra_node);
4098 /* iterate all siblings */
4099 tfra_node = qtdemux_tree_get_sibling_by_type (tfra_node, FOURCC_tfra);
4101 g_node_destroy (mfra_node);
4103 GST_INFO_OBJECT (qtdemux, "parsed movie fragment random access box (mfra)");
4109 if (mfro_map.memory != NULL)
4110 gst_buffer_unmap (mfro, &mfro_map);
4111 gst_buffer_unref (mfro);
4114 if (mfra_map.memory != NULL)
4115 gst_buffer_unmap (mfra, &mfra_map);
4116 gst_buffer_unref (mfra);
4123 GST_WARNING_OBJECT (qtdemux, "could not query upstream size");
4128 GST_WARNING_OBJECT (qtdemux, "mfro size is too small");
4133 GST_WARNING_OBJECT (qtdemux, "mfra_size in mfro box is invalid");
4138 GST_WARNING_OBJECT (qtdemux, "bogus mfra offset or size, broken file");
4144 add_offset (guint64 offset, guint64 advance)
4146 /* Avoid 64-bit overflow by clamping */
4147 if (offset > G_MAXUINT64 - advance)
4149 return offset + advance;
4152 static GstFlowReturn
4153 gst_qtdemux_loop_state_header (GstQTDemux * qtdemux)
4157 GstBuffer *buf = NULL;
4158 GstFlowReturn ret = GST_FLOW_OK;
4159 guint64 cur_offset = qtdemux->offset;
4162 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, 16, &buf);
4163 if (G_UNLIKELY (ret != GST_FLOW_OK))
4165 gst_buffer_map (buf, &map, GST_MAP_READ);
4166 if (G_LIKELY (map.size >= 8))
4167 extract_initial_length_and_fourcc (map.data, map.size, &length, &fourcc);
4168 gst_buffer_unmap (buf, &map);
4169 gst_buffer_unref (buf);
4171 /* maybe we already got most we needed, so only consider this eof */
4172 if (G_UNLIKELY (length == 0)) {
4173 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
4174 (_("Invalid atom size.")),
4175 ("Header atom '%" GST_FOURCC_FORMAT "' has empty length",
4176 GST_FOURCC_ARGS (fourcc)));
4183 /* record for later parsing when needed */
4184 if (!qtdemux->moof_offset) {
4185 qtdemux->moof_offset = qtdemux->offset;
4187 if (qtdemux_pull_mfro_mfra (qtdemux)) {
4190 qtdemux->offset += length; /* skip moof and keep going */
4192 if (qtdemux->got_moov) {
4193 GST_INFO_OBJECT (qtdemux, "moof header, got moov, done with headers");
4204 GST_LOG_OBJECT (qtdemux,
4205 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
4206 GST_FOURCC_ARGS (fourcc), cur_offset);
4207 qtdemux->offset = add_offset (qtdemux->offset, length);
4212 GstBuffer *moov = NULL;
4214 if (qtdemux->got_moov) {
4215 GST_DEBUG_OBJECT (qtdemux, "Skipping moov atom as we have one already");
4216 qtdemux->offset = add_offset (qtdemux->offset, length);
4220 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, length, &moov);
4221 if (ret != GST_FLOW_OK)
4223 gst_buffer_map (moov, &map, GST_MAP_READ);
4225 if (length != map.size) {
4226 /* Some files have a 'moov' atom at the end of the file which contains
4227 * a terminal 'free' atom where the body of the atom is missing.
4228 * Check for, and permit, this special case.
4230 if (map.size >= 8) {
4231 guint8 *final_data = map.data + (map.size - 8);
4232 guint32 final_length = QT_UINT32 (final_data);
4233 guint32 final_fourcc = QT_FOURCC (final_data + 4);
4235 if (final_fourcc == FOURCC_free
4236 && map.size + final_length - 8 == length) {
4237 /* Ok, we've found that special case. Allocate a new buffer with
4238 * that free atom actually present. */
4239 GstBuffer *newmoov = gst_buffer_new_and_alloc (length);
4240 gst_buffer_fill (newmoov, 0, map.data, map.size);
4241 gst_buffer_memset (newmoov, map.size, 0, final_length - 8);
4242 gst_buffer_unmap (moov, &map);
4243 gst_buffer_unref (moov);
4245 gst_buffer_map (moov, &map, GST_MAP_READ);
4250 if (length != map.size) {
4251 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4252 (_("This file is incomplete and cannot be played.")),
4253 ("We got less than expected (received %" G_GSIZE_FORMAT
4254 ", wanted %u, offset %" G_GUINT64_FORMAT ")", map.size,
4255 (guint) length, cur_offset));
4256 gst_buffer_unmap (moov, &map);
4257 gst_buffer_unref (moov);
4258 ret = GST_FLOW_ERROR;
4261 qtdemux->offset += length;
4263 qtdemux_parse_moov (qtdemux, map.data, length);
4264 qtdemux_node_dump (qtdemux, qtdemux->moov_node);
4266 qtdemux_parse_tree (qtdemux);
4267 if (qtdemux->moov_node_compressed) {
4268 g_node_destroy (qtdemux->moov_node_compressed);
4269 g_free (qtdemux->moov_node->data);
4271 qtdemux->moov_node_compressed = NULL;
4272 g_node_destroy (qtdemux->moov_node);
4273 qtdemux->moov_node = NULL;
4274 gst_buffer_unmap (moov, &map);
4275 gst_buffer_unref (moov);
4276 qtdemux->got_moov = TRUE;
4282 GstBuffer *ftyp = NULL;
4284 /* extract major brand; might come in handy for ISO vs QT issues */
4285 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &ftyp);
4286 if (ret != GST_FLOW_OK)
4288 qtdemux->offset += length;
4289 gst_buffer_map (ftyp, &map, GST_MAP_READ);
4290 qtdemux_parse_ftyp (qtdemux, map.data, map.size);
4291 gst_buffer_unmap (ftyp, &map);
4292 gst_buffer_unref (ftyp);
4297 GstBuffer *uuid = NULL;
4299 /* uuid are extension atoms */
4300 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &uuid);
4301 if (ret != GST_FLOW_OK)
4303 qtdemux->offset += length;
4304 gst_buffer_map (uuid, &map, GST_MAP_READ);
4305 qtdemux_parse_uuid (qtdemux, map.data, map.size);
4306 gst_buffer_unmap (uuid, &map);
4307 gst_buffer_unref (uuid);
4312 GstBuffer *sidx = NULL;
4313 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &sidx);
4314 if (ret != GST_FLOW_OK)
4316 qtdemux->offset += length;
4317 gst_buffer_map (sidx, &map, GST_MAP_READ);
4318 qtdemux_parse_sidx (qtdemux, map.data, map.size);
4319 gst_buffer_unmap (sidx, &map);
4320 gst_buffer_unref (sidx);
4325 GstBuffer *unknown = NULL;
4327 GST_LOG_OBJECT (qtdemux,
4328 "unknown %08x '%" GST_FOURCC_FORMAT "' of size %" G_GUINT64_FORMAT
4329 " at %" G_GUINT64_FORMAT, fourcc, GST_FOURCC_ARGS (fourcc), length,
4331 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &unknown);
4332 if (ret != GST_FLOW_OK)
4334 gst_buffer_map (unknown, &map, GST_MAP_READ);
4335 GST_MEMDUMP ("Unknown tag", map.data, map.size);
4336 gst_buffer_unmap (unknown, &map);
4337 gst_buffer_unref (unknown);
4338 qtdemux->offset += length;
4344 if (ret == GST_FLOW_EOS && (qtdemux->got_moov || qtdemux->media_caps)) {
4345 /* digested all data, show what we have */
4346 qtdemux_prepare_streams (qtdemux);
4347 ret = qtdemux_expose_streams (qtdemux);
4349 qtdemux->state = QTDEMUX_STATE_MOVIE;
4350 GST_DEBUG_OBJECT (qtdemux, "switching state to STATE_MOVIE (%d)",
4357 /* Seeks to the previous keyframe of the indexed stream and
4358 * aligns other streams with respect to the keyframe timestamp
4359 * of indexed stream. Only called in case of Reverse Playback
4361 static GstFlowReturn
4362 gst_qtdemux_seek_to_previous_keyframe (GstQTDemux * qtdemux)
4365 guint32 seg_idx = 0, k_index = 0;
4366 guint32 ref_seg_idx, ref_k_index;
4367 GstClockTime k_pos = 0, last_stop = 0;
4368 QtDemuxSegment *seg = NULL;
4369 QtDemuxStream *ref_str = NULL;
4370 guint64 seg_media_start_mov; /* segment media start time in mov format */
4373 /* Now we choose an arbitrary stream, get the previous keyframe timestamp
4374 * and finally align all the other streams on that timestamp with their
4375 * respective keyframes */
4376 for (n = 0; n < qtdemux->n_streams; n++) {
4377 QtDemuxStream *str = qtdemux->streams[n];
4379 /* No candidate yet, take the first stream */
4385 /* So that stream has a segment, we prefer video streams */
4386 if (str->subtype == FOURCC_vide) {
4392 if (G_UNLIKELY (!ref_str)) {
4393 GST_DEBUG_OBJECT (qtdemux, "couldn't find any stream");
4397 if (G_UNLIKELY (!ref_str->from_sample)) {
4398 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of the file");
4402 /* So that stream has been playing from from_sample to to_sample. We will
4403 * get the timestamp of the previous sample and search for a keyframe before
4404 * that. For audio streams we do an arbitrary jump in the past (10 samples) */
4405 if (ref_str->subtype == FOURCC_vide) {
4406 k_index = gst_qtdemux_find_keyframe (qtdemux, ref_str,
4407 ref_str->from_sample - 1, FALSE);
4409 if (ref_str->from_sample >= 10)
4410 k_index = ref_str->from_sample - 10;
4416 ref_str->samples[k_index].timestamp +
4417 ref_str->samples[k_index].pts_offset;
4419 /* get current segment for that stream */
4420 seg = &ref_str->segments[ref_str->segment_index];
4421 /* Use segment start in original timescale for comparisons */
4422 seg_media_start_mov = seg->trak_media_start;
4424 GST_LOG_OBJECT (qtdemux, "keyframe index %u ts %" G_GUINT64_FORMAT
4425 " seg start %" G_GUINT64_FORMAT " %" GST_TIME_FORMAT "\n",
4426 k_index, target_ts, seg_media_start_mov,
4427 GST_TIME_ARGS (seg->media_start));
4429 /* Crawl back through segments to find the one containing this I frame */
4430 while (target_ts < seg_media_start_mov) {
4431 GST_DEBUG_OBJECT (qtdemux,
4432 "keyframe position (sample %u) is out of segment %u " " target %"
4433 G_GUINT64_FORMAT " seg start %" G_GUINT64_FORMAT, k_index,
4434 ref_str->segment_index, target_ts, seg_media_start_mov);
4436 if (G_UNLIKELY (!ref_str->segment_index)) {
4437 /* Reached first segment, let's consider it's EOS */
4440 ref_str->segment_index--;
4441 seg = &ref_str->segments[ref_str->segment_index];
4442 /* Use segment start in original timescale for comparisons */
4443 seg_media_start_mov = seg->trak_media_start;
4445 /* Calculate time position of the keyframe and where we should stop */
4447 QTSTREAMTIME_TO_GSTTIME (ref_str,
4448 target_ts - seg->trak_media_start) + seg->time;
4450 QTSTREAMTIME_TO_GSTTIME (ref_str,
4451 ref_str->samples[ref_str->from_sample].timestamp -
4452 seg->trak_media_start) + seg->time;
4454 GST_DEBUG_OBJECT (qtdemux, "preferred stream played from sample %u, "
4455 "now going to sample %u (pts %" GST_TIME_FORMAT ")", ref_str->from_sample,
4456 k_index, GST_TIME_ARGS (k_pos));
4458 /* Set last_stop with the keyframe timestamp we pushed of that stream */
4459 qtdemux->segment.position = last_stop;
4460 GST_DEBUG_OBJECT (qtdemux, "last_stop now is %" GST_TIME_FORMAT,
4461 GST_TIME_ARGS (last_stop));
4463 if (G_UNLIKELY (last_stop < qtdemux->segment.start)) {
4464 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of segment");
4468 ref_seg_idx = ref_str->segment_index;
4469 ref_k_index = k_index;
4471 /* Align them all on this */
4472 for (n = 0; n < qtdemux->n_streams; n++) {
4474 GstClockTime seg_time = 0;
4475 QtDemuxStream *str = qtdemux->streams[n];
4477 /* aligning reference stream again might lead to backing up to yet another
4478 * keyframe (due to timestamp rounding issues),
4479 * potentially putting more load on downstream; so let's try to avoid */
4480 if (str == ref_str) {
4481 seg_idx = ref_seg_idx;
4482 seg = &str->segments[seg_idx];
4483 k_index = ref_k_index;
4484 GST_DEBUG_OBJECT (qtdemux, "reference stream %d segment %d, "
4485 "sample at index %d", n, ref_str->segment_index, k_index);
4487 seg_idx = gst_qtdemux_find_segment (qtdemux, str, k_pos);
4488 GST_DEBUG_OBJECT (qtdemux,
4489 "stream %d align segment %d for keyframe pos %" GST_TIME_FORMAT, n,
4490 seg_idx, GST_TIME_ARGS (k_pos));
4492 /* get segment and time in the segment */
4493 seg = &str->segments[seg_idx];
4494 seg_time = k_pos - seg->time;
4496 /* get the media time in the segment.
4497 * No adjustment for empty "filler" segments */
4498 if (seg->media_start != GST_CLOCK_TIME_NONE)
4499 seg_time += seg->media_start;
4501 /* get the index of the sample with media time */
4502 index = gst_qtdemux_find_index_linear (qtdemux, str, seg_time);
4503 GST_DEBUG_OBJECT (qtdemux,
4504 "stream %d sample for %" GST_TIME_FORMAT " at %u", n,
4505 GST_TIME_ARGS (seg_time), index);
4507 /* find previous keyframe */
4508 k_index = gst_qtdemux_find_keyframe (qtdemux, str, index, FALSE);
4511 /* Remember until where we want to go */
4512 str->to_sample = str->from_sample - 1;
4513 /* Define our time position */
4515 str->samples[k_index].timestamp + str->samples[k_index].pts_offset;
4516 str->time_position = QTSTREAMTIME_TO_GSTTIME (str, target_ts) + seg->time;
4517 if (seg->media_start != GST_CLOCK_TIME_NONE)
4518 str->time_position -= seg->media_start;
4520 /* Now seek back in time */
4521 gst_qtdemux_move_stream (qtdemux, str, k_index);
4522 GST_DEBUG_OBJECT (qtdemux, "stream %d keyframe at %u, time position %"
4523 GST_TIME_FORMAT " playing from sample %u to %u", n, k_index,
4524 GST_TIME_ARGS (str->time_position), str->from_sample, str->to_sample);
4530 return GST_FLOW_EOS;
4534 * Gets the current qt segment start, stop and position for the
4535 * given time offset. This is used in update_segment()
4538 gst_qtdemux_stream_segment_get_boundaries (GstQTDemux * qtdemux,
4539 QtDemuxStream * stream, GstClockTime offset,
4540 GstClockTime * _start, GstClockTime * _stop, GstClockTime * _time)
4542 GstClockTime seg_time;
4543 GstClockTime start, stop, time;
4544 QtDemuxSegment *segment;
4546 segment = &stream->segments[stream->segment_index];
4548 /* get time in this segment */
4549 seg_time = (offset - segment->time) * segment->rate;
4551 GST_LOG_OBJECT (stream->pad, "seg_time %" GST_TIME_FORMAT,
4552 GST_TIME_ARGS (seg_time));
4554 if (G_UNLIKELY (seg_time > segment->duration)) {
4555 GST_LOG_OBJECT (stream->pad,
4556 "seg_time > segment->duration %" GST_TIME_FORMAT,
4557 GST_TIME_ARGS (segment->duration));
4558 seg_time = segment->duration;
4561 /* qtdemux->segment.stop is in outside-time-realm, whereas
4562 * segment->media_stop is in track-time-realm.
4564 * In order to compare the two, we need to bring segment.stop
4565 * into the track-time-realm
4567 * FIXME - does this comment still hold? Don't see any conversion here */
4569 stop = qtdemux->segment.stop;
4570 if (stop == GST_CLOCK_TIME_NONE)
4571 stop = qtdemux->segment.duration;
4572 if (stop == GST_CLOCK_TIME_NONE)
4573 stop = segment->media_stop;
4576 MIN (segment->media_stop, stop - segment->time + segment->media_start);
4578 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
4579 start = segment->time + seg_time;
4581 stop = start - seg_time + segment->duration;
4582 } else if (qtdemux->segment.rate >= 0) {
4583 start = MIN (segment->media_start + seg_time, stop);
4586 if (segment->media_start >= qtdemux->segment.start) {
4587 time = segment->time;
4589 time = segment->time + (qtdemux->segment.start - segment->media_start);
4592 start = MAX (segment->media_start, qtdemux->segment.start);
4593 stop = MIN (segment->media_start + seg_time, stop);
4602 * Updates the qt segment used for the stream and pushes a new segment event
4603 * downstream on this stream's pad.
4606 gst_qtdemux_stream_update_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
4607 gint seg_idx, GstClockTime offset, GstClockTime * _start,
4608 GstClockTime * _stop)
4610 QtDemuxSegment *segment;
4611 GstClockTime start = 0, stop = GST_CLOCK_TIME_NONE, time = 0;
4615 /* update the current segment */
4616 stream->segment_index = seg_idx;
4618 /* get the segment */
4619 segment = &stream->segments[seg_idx];
4621 if (G_UNLIKELY (offset < segment->time)) {
4622 GST_WARNING_OBJECT (stream->pad, "offset < segment->time %" GST_TIME_FORMAT,
4623 GST_TIME_ARGS (segment->time));
4627 /* segment lies beyond total indicated duration */
4628 if (G_UNLIKELY (qtdemux->segment.duration != GST_CLOCK_TIME_NONE &&
4629 segment->time > qtdemux->segment.duration)) {
4630 GST_WARNING_OBJECT (stream->pad, "file duration %" GST_TIME_FORMAT
4631 " < segment->time %" GST_TIME_FORMAT,
4632 GST_TIME_ARGS (qtdemux->segment.duration),
4633 GST_TIME_ARGS (segment->time));
4637 gst_qtdemux_stream_segment_get_boundaries (qtdemux, stream, offset,
4638 &start, &stop, &time);
4640 GST_DEBUG_OBJECT (stream->pad, "new segment %d from %" GST_TIME_FORMAT
4641 " to %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT, seg_idx,
4642 GST_TIME_ARGS (start), GST_TIME_ARGS (stop), GST_TIME_ARGS (time));
4644 /* combine global rate with that of the segment */
4645 rate = segment->rate * qtdemux->segment.rate;
4647 /* Copy flags from main segment */
4648 stream->segment.flags = qtdemux->segment.flags;
4650 /* update the segment values used for clipping */
4651 stream->segment.offset = qtdemux->segment.offset;
4652 stream->segment.base = qtdemux->segment.base + stream->accumulated_base;
4653 stream->segment.applied_rate = qtdemux->segment.applied_rate;
4654 stream->segment.rate = rate;
4655 stream->segment.start = start + QTSTREAMTIME_TO_GSTTIME (stream,
4656 stream->cslg_shift);
4657 stream->segment.stop = stop + QTSTREAMTIME_TO_GSTTIME (stream,
4658 stream->cslg_shift);
4659 stream->segment.time = time;
4660 stream->segment.position = stream->segment.start;
4662 GST_DEBUG_OBJECT (stream->pad, "New segment: %" GST_SEGMENT_FORMAT,
4665 /* now prepare and send the segment */
4667 event = gst_event_new_segment (&stream->segment);
4668 if (qtdemux->segment_seqnum) {
4669 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
4671 gst_pad_push_event (stream->pad, event);
4672 /* assume we can send more data now */
4673 GST_PAD_LAST_FLOW_RETURN (stream->pad) = GST_FLOW_OK;
4674 /* clear to send tags on this pad now */
4675 gst_qtdemux_push_tags (qtdemux, stream);
4686 /* activate the given segment number @seg_idx of @stream at time @offset.
4687 * @offset is an absolute global position over all the segments.
4689 * This will push out a NEWSEGMENT event with the right values and
4690 * position the stream index to the first decodable sample before
4694 gst_qtdemux_activate_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
4695 guint32 seg_idx, GstClockTime offset)
4697 QtDemuxSegment *segment;
4698 guint32 index, kf_index;
4699 GstClockTime start = 0, stop = GST_CLOCK_TIME_NONE;
4701 GST_LOG_OBJECT (stream->pad, "activate segment %d, offset %" GST_TIME_FORMAT,
4702 seg_idx, GST_TIME_ARGS (offset));
4704 if (!gst_qtdemux_stream_update_segment (qtdemux, stream, seg_idx, offset,
4708 segment = &stream->segments[stream->segment_index];
4710 /* in the fragmented case, we pick a fragment that starts before our
4711 * desired position and rely on downstream to wait for a keyframe
4712 * (FIXME: doesn't seem to work so well with ismv and wmv, as no parser; the
4713 * tfra entries tells us which trun/sample the key unit is in, but we don't
4714 * make use of this additional information at the moment) */
4715 if (qtdemux->fragmented) {
4716 stream->to_sample = G_MAXUINT32;
4720 /* We don't need to look for a sample in push-based */
4721 if (!qtdemux->pullbased)
4724 /* and move to the keyframe before the indicated media time of the
4726 if (G_LIKELY (!QTSEGMENT_IS_EMPTY (segment))) {
4727 if (qtdemux->segment.rate >= 0) {
4728 index = gst_qtdemux_find_index_linear (qtdemux, stream, start);
4729 stream->to_sample = G_MAXUINT32;
4730 GST_DEBUG_OBJECT (stream->pad,
4731 "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
4732 GST_TIME_FORMAT, GST_TIME_ARGS (start), index,
4733 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
4735 index = gst_qtdemux_find_index_linear (qtdemux, stream, stop);
4736 stream->to_sample = index;
4737 GST_DEBUG_OBJECT (stream->pad,
4738 "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
4739 GST_TIME_FORMAT, GST_TIME_ARGS (stop), index,
4740 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
4743 GST_DEBUG_OBJECT (stream->pad, "No need to look for keyframe, "
4744 "this is an empty segment");
4748 /* gst_qtdemux_parse_sample () called from gst_qtdemux_find_index_linear ()
4749 * encountered an error and printed a message so we return appropriately */
4753 /* we're at the right spot */
4754 if (index == stream->sample_index) {
4755 GST_DEBUG_OBJECT (stream->pad, "we are at the right index");
4759 /* find keyframe of the target index */
4760 kf_index = gst_qtdemux_find_keyframe (qtdemux, stream, index, FALSE);
4763 /* indent does stupid stuff with stream->samples[].timestamp */
4765 /* if we move forwards, we don't have to go back to the previous
4766 * keyframe since we already sent that. We can also just jump to
4767 * the keyframe right before the target index if there is one. */
4768 if (index > stream->sample_index) {
4769 /* moving forwards check if we move past a keyframe */
4770 if (kf_index > stream->sample_index) {
4771 GST_DEBUG_OBJECT (stream->pad,
4772 "moving forwards to keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" )", kf_index,
4773 GST_TIME_ARGS (QTSAMPLE_PTS(stream, &stream->samples[kf_index])),
4774 GST_TIME_ARGS (QTSAMPLE_DTS(stream, &stream->samples[kf_index])));
4775 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
4777 GST_DEBUG_OBJECT (stream->pad,
4778 "moving forwards, keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" ) already sent", kf_index,
4779 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[kf_index])),
4780 GST_TIME_ARGS (QTSAMPLE_DTS (stream, &stream->samples[kf_index])));
4783 GST_DEBUG_OBJECT (stream->pad,
4784 "moving backwards to keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" )", kf_index,
4785 GST_TIME_ARGS (QTSAMPLE_PTS(stream, &stream->samples[kf_index])),
4786 GST_TIME_ARGS (QTSAMPLE_DTS(stream, &stream->samples[kf_index])));
4787 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
4795 /* prepare to get the current sample of @stream, getting essential values.
4797 * This function will also prepare and send the segment when needed.
4799 * Return FALSE if the stream is EOS.
4804 gst_qtdemux_prepare_current_sample (GstQTDemux * qtdemux,
4805 QtDemuxStream * stream, gboolean * empty, guint64 * offset, guint * size,
4806 GstClockTime * dts, GstClockTime * pts, GstClockTime * duration,
4807 gboolean * keyframe)
4809 QtDemuxSample *sample;
4810 GstClockTime time_position;
4813 g_return_val_if_fail (stream != NULL, FALSE);
4815 time_position = stream->time_position;
4816 if (G_UNLIKELY (time_position == GST_CLOCK_TIME_NONE))
4819 seg_idx = stream->segment_index;
4820 if (G_UNLIKELY (seg_idx == -1)) {
4821 /* find segment corresponding to time_position if we are looking
4823 seg_idx = gst_qtdemux_find_segment (qtdemux, stream, time_position);
4826 /* different segment, activate it, sample_index will be set. */
4827 if (G_UNLIKELY (stream->segment_index != seg_idx))
4828 gst_qtdemux_activate_segment (qtdemux, stream, seg_idx, time_position);
4830 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (&stream->segments[stream->
4832 QtDemuxSegment *seg = &stream->segments[stream->segment_index];
4834 GST_LOG_OBJECT (qtdemux, "Empty segment activated,"
4835 " prepare empty sample");
4838 *pts = *dts = time_position;
4839 *duration = seg->duration - (time_position - seg->time);
4846 if (stream->sample_index == -1)
4847 stream->sample_index = 0;
4849 GST_LOG_OBJECT (qtdemux, "segment active, index = %u of %u",
4850 stream->sample_index, stream->n_samples);
4852 if (G_UNLIKELY (stream->sample_index >= stream->n_samples)) {
4853 if (!qtdemux->fragmented)
4856 GST_INFO_OBJECT (qtdemux, "out of samples, trying to add more");
4860 GST_OBJECT_LOCK (qtdemux);
4861 flow = qtdemux_add_fragmented_samples (qtdemux);
4862 GST_OBJECT_UNLOCK (qtdemux);
4864 if (flow != GST_FLOW_OK)
4867 while (stream->sample_index >= stream->n_samples);
4870 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
4871 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
4872 stream->sample_index);
4876 /* now get the info for the sample we're at */
4877 sample = &stream->samples[stream->sample_index];
4879 *dts = QTSAMPLE_DTS (stream, sample);
4880 *pts = QTSAMPLE_PTS (stream, sample);
4881 *offset = sample->offset;
4882 *size = sample->size;
4883 *duration = QTSAMPLE_DUR_DTS (stream, sample, *dts);
4884 *keyframe = QTSAMPLE_KEYFRAME (stream, sample);
4891 stream->time_position = GST_CLOCK_TIME_NONE;
4896 /* move to the next sample in @stream.
4898 * Moves to the next segment when needed.
4901 gst_qtdemux_advance_sample (GstQTDemux * qtdemux, QtDemuxStream * stream)
4903 QtDemuxSample *sample;
4904 QtDemuxSegment *segment;
4906 /* get current segment */
4907 segment = &stream->segments[stream->segment_index];
4909 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
4910 GST_DEBUG_OBJECT (qtdemux, "Empty segment, no samples to advance");
4914 if (G_UNLIKELY (stream->sample_index >= stream->to_sample)) {
4915 /* Mark the stream as EOS */
4916 GST_DEBUG_OBJECT (qtdemux,
4917 "reached max allowed sample %u, mark EOS", stream->to_sample);
4918 stream->time_position = GST_CLOCK_TIME_NONE;
4922 /* move to next sample */
4923 stream->sample_index++;
4924 stream->offset_in_sample = 0;
4926 /* reached the last sample, we need the next segment */
4927 if (G_UNLIKELY (stream->sample_index >= stream->n_samples))
4930 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
4931 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
4932 stream->sample_index);
4936 /* get next sample */
4937 sample = &stream->samples[stream->sample_index];
4939 /* see if we are past the segment */
4940 if (G_UNLIKELY (QTSAMPLE_DTS (stream, sample) >= segment->media_stop))
4943 if (QTSAMPLE_DTS (stream, sample) >= segment->media_start) {
4944 /* inside the segment, update time_position, looks very familiar to
4945 * GStreamer segments, doesn't it? */
4946 stream->time_position =
4947 QTSAMPLE_DTS (stream, sample) - segment->media_start + segment->time;
4949 /* not yet in segment, time does not yet increment. This means
4950 * that we are still prerolling keyframes to the decoder so it can
4951 * decode the first sample of the segment. */
4952 stream->time_position = segment->time;
4956 /* move to the next segment */
4959 GST_DEBUG_OBJECT (qtdemux, "segment %d ended ", stream->segment_index);
4961 if (stream->segment_index == stream->n_segments - 1) {
4962 /* are we at the end of the last segment, we're EOS */
4963 stream->time_position = GST_CLOCK_TIME_NONE;
4965 /* else we're only at the end of the current segment */
4966 stream->time_position = segment->stop_time;
4968 /* make sure we select a new segment */
4970 /* accumulate previous segments */
4971 if (GST_CLOCK_TIME_IS_VALID (stream->segment.stop))
4972 stream->accumulated_base +=
4973 (stream->segment.stop -
4974 stream->segment.start) / ABS (stream->segment.rate);
4976 stream->segment_index = -1;
4981 gst_qtdemux_sync_streams (GstQTDemux * demux)
4985 if (demux->n_streams <= 1)
4988 for (i = 0; i < demux->n_streams; i++) {
4989 QtDemuxStream *stream;
4990 GstClockTime end_time;
4992 stream = demux->streams[i];
4997 /* TODO advance time on subtitle streams here, if any some day */
4999 /* some clips/trailers may have unbalanced streams at the end,
5000 * so send EOS on shorter stream to prevent stalling others */
5002 /* do not mess with EOS if SEGMENT seeking */
5003 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT)
5006 if (demux->pullbased) {
5007 /* loop mode is sample time based */
5008 if (!STREAM_IS_EOS (stream))
5011 /* push mode is byte position based */
5012 if (stream->n_samples &&
5013 stream->samples[stream->n_samples - 1].offset >= demux->offset)
5017 if (stream->sent_eos)
5020 /* only act if some gap */
5021 end_time = stream->segments[stream->n_segments - 1].stop_time;
5022 GST_LOG_OBJECT (demux, "current position: %" GST_TIME_FORMAT
5023 ", stream end: %" GST_TIME_FORMAT,
5024 GST_TIME_ARGS (demux->segment.position), GST_TIME_ARGS (end_time));
5025 if (GST_CLOCK_TIME_IS_VALID (end_time)
5026 && (end_time + 2 * GST_SECOND < demux->segment.position)) {
5029 GST_DEBUG_OBJECT (demux, "sending EOS for stream %s",
5030 GST_PAD_NAME (stream->pad));
5031 stream->sent_eos = TRUE;
5032 event = gst_event_new_eos ();
5033 if (demux->segment_seqnum)
5034 gst_event_set_seqnum (event, demux->segment_seqnum);
5035 gst_pad_push_event (stream->pad, event);
5040 /* EOS and NOT_LINKED need to be combined. This means that we return:
5042 * GST_FLOW_NOT_LINKED: when all pads NOT_LINKED.
5043 * GST_FLOW_EOS: when all pads EOS or NOT_LINKED.
5045 static GstFlowReturn
5046 gst_qtdemux_combine_flows (GstQTDemux * demux, QtDemuxStream * stream,
5049 GST_LOG_OBJECT (demux, "flow return: %s", gst_flow_get_name (ret));
5052 ret = gst_flow_combiner_update_pad_flow (demux->flowcombiner, stream->pad,
5055 ret = gst_flow_combiner_update_flow (demux->flowcombiner, ret);
5057 GST_LOG_OBJECT (demux, "combined flow return: %s", gst_flow_get_name (ret));
5061 /* the input buffer metadata must be writable. Returns NULL when the buffer is
5062 * completely clipped
5064 * Should be used only with raw buffers */
5066 gst_qtdemux_clip_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
5069 guint64 start, stop, cstart, cstop, diff;
5070 GstClockTime pts, duration;
5072 gint num_rate, denom_rate;
5077 osize = size = gst_buffer_get_size (buf);
5080 /* depending on the type, setup the clip parameters */
5081 if (stream->subtype == FOURCC_soun) {
5082 frame_size = stream->bytes_per_frame;
5083 num_rate = GST_SECOND;
5084 denom_rate = (gint) stream->rate;
5086 } else if (stream->subtype == FOURCC_vide) {
5088 num_rate = stream->fps_n;
5089 denom_rate = stream->fps_d;
5094 if (frame_size <= 0)
5095 goto bad_frame_size;
5097 /* we can only clip if we have a valid pts */
5098 pts = GST_BUFFER_PTS (buf);
5099 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (pts)))
5102 duration = GST_BUFFER_DURATION (buf);
5104 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (duration))) {
5106 gst_util_uint64_scale_int (size / frame_size, num_rate, denom_rate);
5110 stop = start + duration;
5112 if (G_UNLIKELY (!gst_segment_clip (&stream->segment,
5113 GST_FORMAT_TIME, start, stop, &cstart, &cstop)))
5116 /* see if some clipping happened */
5117 diff = cstart - start;
5123 /* bring clipped time to samples and to bytes */
5124 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
5127 GST_DEBUG_OBJECT (qtdemux,
5128 "clipping start to %" GST_TIME_FORMAT " %"
5129 G_GUINT64_FORMAT " bytes", GST_TIME_ARGS (cstart), diff);
5135 diff = stop - cstop;
5140 /* bring clipped time to samples and then to bytes */
5141 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
5143 GST_DEBUG_OBJECT (qtdemux,
5144 "clipping stop to %" GST_TIME_FORMAT " %" G_GUINT64_FORMAT
5145 " bytes", GST_TIME_ARGS (cstop), diff);
5150 if (offset != 0 || size != osize)
5151 gst_buffer_resize (buf, offset, size);
5153 GST_BUFFER_DTS (buf) = GST_CLOCK_TIME_NONE;
5154 GST_BUFFER_PTS (buf) = pts;
5155 GST_BUFFER_DURATION (buf) = duration;
5159 /* dropped buffer */
5162 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
5167 GST_DEBUG_OBJECT (qtdemux, "bad frame size");
5172 GST_DEBUG_OBJECT (qtdemux, "no pts on buffer");
5177 GST_DEBUG_OBJECT (qtdemux, "clipped buffer");
5178 gst_buffer_unref (buf);
5184 gst_qtdemux_align_buffer (GstQTDemux * demux,
5185 GstBuffer * buffer, gsize alignment)
5189 gst_buffer_map (buffer, &map, GST_MAP_READ);
5191 if (map.size < sizeof (guintptr)) {
5192 gst_buffer_unmap (buffer, &map);
5196 if (((guintptr) map.data) & (alignment - 1)) {
5197 GstBuffer *new_buffer;
5198 GstAllocationParams params = { 0, alignment - 1, 0, 0, };
5200 new_buffer = gst_buffer_new_allocate (NULL,
5201 gst_buffer_get_size (buffer), ¶ms);
5203 /* Copy data "by hand", so ensure alignment is kept: */
5204 gst_buffer_fill (new_buffer, 0, map.data, map.size);
5206 gst_buffer_copy_into (new_buffer, buffer, GST_BUFFER_COPY_METADATA, 0, -1);
5207 GST_DEBUG_OBJECT (demux,
5208 "We want output aligned on %" G_GSIZE_FORMAT ", reallocated",
5211 gst_buffer_unmap (buffer, &map);
5212 gst_buffer_unref (buffer);
5217 gst_buffer_unmap (buffer, &map);
5221 /* the input buffer metadata must be writable,
5222 * but time/duration etc not yet set and need not be preserved */
5224 gst_qtdemux_process_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
5231 /* not many cases for now */
5232 if (G_UNLIKELY (stream->fourcc == FOURCC_mp4s)) {
5233 /* send a one time dvd clut event */
5234 if (stream->pending_event && stream->pad)
5235 gst_pad_push_event (stream->pad, stream->pending_event);
5236 stream->pending_event = NULL;
5239 if (G_UNLIKELY (stream->subtype != FOURCC_text
5240 && stream->subtype != FOURCC_sbtl &&
5241 stream->subtype != FOURCC_subp)) {
5245 gst_buffer_map (buf, &map, GST_MAP_READ);
5247 /* empty buffer is sent to terminate previous subtitle */
5248 if (map.size <= 2) {
5249 gst_buffer_unmap (buf, &map);
5250 gst_buffer_unref (buf);
5253 if (stream->subtype == FOURCC_subp) {
5254 /* That's all the processing needed for subpictures */
5255 gst_buffer_unmap (buf, &map);
5259 nsize = GST_READ_UINT16_BE (map.data);
5260 nsize = MIN (nsize, map.size - 2);
5262 GST_LOG_OBJECT (qtdemux, "3GPP timed text subtitle: %d/%" G_GSIZE_FORMAT "",
5265 /* takes care of UTF-8 validation or UTF-16 recognition,
5266 * no other encoding expected */
5267 str = gst_tag_freeform_string_to_utf8 ((gchar *) map.data + 2, nsize, NULL);
5268 gst_buffer_unmap (buf, &map);
5270 gst_buffer_unref (buf);
5271 buf = _gst_buffer_new_wrapped (str, strlen (str), g_free);
5273 /* this should not really happen unless the subtitle is corrupted */
5274 gst_buffer_unref (buf);
5278 /* FIXME ? convert optional subsequent style info to markup */
5283 /* Sets a buffer's attributes properly and pushes it downstream.
5284 * Also checks for additional actions and custom processing that may
5285 * need to be done first.
5287 static GstFlowReturn
5288 gst_qtdemux_decorate_and_push_buffer (GstQTDemux * qtdemux,
5289 QtDemuxStream * stream, GstBuffer * buf,
5290 GstClockTime dts, GstClockTime pts, GstClockTime duration,
5291 gboolean keyframe, GstClockTime position, guint64 byte_position)
5293 GstFlowReturn ret = GST_FLOW_OK;
5295 /* offset the timestamps according to the edit list */
5297 if (G_UNLIKELY (stream->fourcc == FOURCC_rtsp)) {
5301 gst_buffer_map (buf, &map, GST_MAP_READ);
5302 url = g_strndup ((gchar *) map.data, map.size);
5303 gst_buffer_unmap (buf, &map);
5304 if (url != NULL && strlen (url) != 0) {
5305 /* we have RTSP redirect now */
5306 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
5307 gst_message_new_element (GST_OBJECT_CAST (qtdemux),
5308 gst_structure_new ("redirect",
5309 "new-location", G_TYPE_STRING, url, NULL)));
5310 qtdemux->posted_redirect = TRUE;
5312 GST_WARNING_OBJECT (qtdemux, "Redirect URI of stream is empty, not "
5318 /* position reporting */
5319 if (qtdemux->segment.rate >= 0) {
5320 qtdemux->segment.position = position;
5321 gst_qtdemux_sync_streams (qtdemux);
5324 if (G_UNLIKELY (!stream->pad)) {
5325 GST_DEBUG_OBJECT (qtdemux, "No output pad for stream, ignoring");
5326 gst_buffer_unref (buf);
5330 /* send out pending buffers */
5331 while (stream->buffers) {
5332 GstBuffer *buffer = (GstBuffer *) stream->buffers->data;
5334 if (G_UNLIKELY (stream->discont)) {
5335 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
5336 GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
5337 stream->discont = FALSE;
5339 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
5342 if (stream->alignment > 1)
5343 buffer = gst_qtdemux_align_buffer (qtdemux, buffer, stream->alignment);
5344 gst_pad_push (stream->pad, buffer);
5346 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
5349 /* we're going to modify the metadata */
5350 buf = gst_buffer_make_writable (buf);
5352 if (G_UNLIKELY (stream->need_process))
5353 buf = gst_qtdemux_process_buffer (qtdemux, stream, buf);
5359 GST_BUFFER_DTS (buf) = dts;
5360 GST_BUFFER_PTS (buf) = pts;
5361 GST_BUFFER_DURATION (buf) = duration;
5362 GST_BUFFER_OFFSET (buf) = -1;
5363 GST_BUFFER_OFFSET_END (buf) = -1;
5365 if (G_UNLIKELY (stream->rgb8_palette))
5366 gst_buffer_append_memory (buf, gst_memory_ref (stream->rgb8_palette));
5368 if (G_UNLIKELY (stream->padding)) {
5369 gst_buffer_resize (buf, stream->padding, -1);
5372 if (G_UNLIKELY (qtdemux->element_index)) {
5373 GstClockTime stream_time;
5376 gst_segment_to_stream_time (&stream->segment, GST_FORMAT_TIME,
5378 if (GST_CLOCK_TIME_IS_VALID (stream_time)) {
5379 GST_LOG_OBJECT (qtdemux,
5380 "adding association %" GST_TIME_FORMAT "-> %"
5381 G_GUINT64_FORMAT, GST_TIME_ARGS (stream_time), byte_position);
5382 gst_index_add_association (qtdemux->element_index,
5384 keyframe ? GST_ASSOCIATION_FLAG_KEY_UNIT :
5385 GST_ASSOCIATION_FLAG_DELTA_UNIT, GST_FORMAT_TIME, stream_time,
5386 GST_FORMAT_BYTES, byte_position, NULL);
5391 if (stream->need_clip)
5392 buf = gst_qtdemux_clip_buffer (qtdemux, stream, buf);
5394 if (G_UNLIKELY (buf == NULL))
5397 if (G_UNLIKELY (stream->discont)) {
5398 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
5399 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
5400 stream->discont = FALSE;
5402 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
5406 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
5407 stream->on_keyframe = FALSE;
5409 stream->on_keyframe = TRUE;
5413 GST_LOG_OBJECT (qtdemux,
5414 "Pushing buffer with dts %" GST_TIME_FORMAT ", pts %" GST_TIME_FORMAT
5415 ", duration %" GST_TIME_FORMAT " on pad %s", GST_TIME_ARGS (dts),
5416 GST_TIME_ARGS (pts), GST_TIME_ARGS (duration),
5417 GST_PAD_NAME (stream->pad));
5419 if (stream->protected && stream->protection_scheme_type == FOURCC_cenc) {
5420 GstStructure *crypto_info;
5421 QtDemuxCencSampleSetInfo *info =
5422 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
5426 while ((event = g_queue_pop_head (&stream->protection_scheme_event_queue))) {
5427 gst_pad_push_event (stream->pad, event);
5430 if (info->crypto_info == NULL) {
5431 GST_DEBUG_OBJECT (qtdemux, "cenc metadata hasn't been parsed yet");
5432 gst_buffer_unref (buf);
5436 index = stream->sample_index - (stream->n_samples - info->crypto_info->len);
5437 if (G_LIKELY (index >= 0 && index < info->crypto_info->len)) {
5438 /* steal structure from array */
5439 crypto_info = g_ptr_array_index (info->crypto_info, index);
5440 g_ptr_array_index (info->crypto_info, index) = NULL;
5441 GST_LOG_OBJECT (qtdemux, "attaching cenc metadata [%u]", index);
5442 if (!crypto_info || !gst_buffer_add_protection_meta (buf, crypto_info))
5443 GST_ERROR_OBJECT (qtdemux, "failed to attach cenc metadata to buffer");
5447 if (stream->alignment > 1)
5448 buf = gst_qtdemux_align_buffer (qtdemux, buf, stream->alignment);
5450 ret = gst_pad_push (stream->pad, buf);
5452 if (GST_CLOCK_TIME_IS_VALID (pts) && GST_CLOCK_TIME_IS_VALID (duration)) {
5453 /* mark position in stream, we'll need this to know when to send GAP event */
5454 stream->segment.position = pts + duration;
5461 static const QtDemuxRandomAccessEntry *
5462 gst_qtdemux_stream_seek_fragment (GstQTDemux * qtdemux, QtDemuxStream * stream,
5463 GstClockTime pos, gboolean after)
5465 QtDemuxRandomAccessEntry *entries = stream->ra_entries;
5466 guint n_entries = stream->n_ra_entries;
5469 /* we assume the table is sorted */
5470 for (i = 0; i < n_entries; ++i) {
5471 if (entries[i].ts > pos)
5475 /* FIXME: maybe save first moof_offset somewhere instead, but for now it's
5476 * probably okay to assume that the index lists the very first fragment */
5483 return &entries[i - 1];
5487 gst_qtdemux_do_fragmented_seek (GstQTDemux * qtdemux)
5489 const QtDemuxRandomAccessEntry *best_entry = NULL;
5492 GST_OBJECT_LOCK (qtdemux);
5494 g_assert (qtdemux->n_streams > 0);
5496 for (i = 0; i < qtdemux->n_streams; i++) {
5497 const QtDemuxRandomAccessEntry *entry;
5498 QtDemuxStream *stream;
5499 gboolean is_audio_or_video;
5501 stream = qtdemux->streams[i];
5503 g_free (stream->samples);
5504 stream->samples = NULL;
5505 stream->n_samples = 0;
5506 stream->stbl_index = -1; /* no samples have yet been parsed */
5507 stream->sample_index = -1;
5509 if (stream->ra_entries == NULL)
5512 if (stream->subtype == FOURCC_vide || stream->subtype == FOURCC_soun)
5513 is_audio_or_video = TRUE;
5515 is_audio_or_video = FALSE;
5518 gst_qtdemux_stream_seek_fragment (qtdemux, stream,
5519 stream->time_position, !is_audio_or_video);
5521 GST_INFO_OBJECT (stream->pad, "%" GST_TIME_FORMAT " at offset "
5522 "%" G_GUINT64_FORMAT, GST_TIME_ARGS (entry->ts), entry->moof_offset);
5524 stream->pending_seek = entry;
5526 /* decide position to jump to just based on audio/video tracks, not subs */
5527 if (!is_audio_or_video)
5530 if (best_entry == NULL || entry->moof_offset < best_entry->moof_offset)
5534 if (best_entry == NULL) {
5535 GST_OBJECT_UNLOCK (qtdemux);
5539 GST_INFO_OBJECT (qtdemux, "seek to %" GST_TIME_FORMAT ", best fragment "
5540 "moof offset: %" G_GUINT64_FORMAT ", ts %" GST_TIME_FORMAT,
5541 GST_TIME_ARGS (qtdemux->streams[0]->time_position),
5542 best_entry->moof_offset, GST_TIME_ARGS (best_entry->ts));
5544 qtdemux->moof_offset = best_entry->moof_offset;
5546 qtdemux_add_fragmented_samples (qtdemux);
5548 GST_OBJECT_UNLOCK (qtdemux);
5552 static GstFlowReturn
5553 gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux)
5555 GstFlowReturn ret = GST_FLOW_OK;
5556 GstBuffer *buf = NULL;
5557 QtDemuxStream *stream;
5558 GstClockTime min_time;
5560 GstClockTime dts = GST_CLOCK_TIME_NONE;
5561 GstClockTime pts = GST_CLOCK_TIME_NONE;
5562 GstClockTime duration = 0;
5563 gboolean keyframe = FALSE;
5564 guint sample_size = 0;
5570 gst_qtdemux_push_pending_newsegment (qtdemux);
5572 if (qtdemux->fragmented_seek_pending) {
5573 GST_INFO_OBJECT (qtdemux, "pending fragmented seek");
5574 gst_qtdemux_do_fragmented_seek (qtdemux);
5575 GST_INFO_OBJECT (qtdemux, "fragmented seek done!");
5576 qtdemux->fragmented_seek_pending = FALSE;
5579 /* Figure out the next stream sample to output, min_time is expressed in
5580 * global time and runs over the edit list segments. */
5581 min_time = G_MAXUINT64;
5583 for (i = 0; i < qtdemux->n_streams; i++) {
5584 GstClockTime position;
5586 stream = qtdemux->streams[i];
5587 position = stream->time_position;
5589 /* position of -1 is EOS */
5590 if (position != GST_CLOCK_TIME_NONE && position < min_time) {
5591 min_time = position;
5596 if (G_UNLIKELY (index == -1)) {
5597 GST_DEBUG_OBJECT (qtdemux, "all streams are EOS");
5601 /* check for segment end */
5602 if (G_UNLIKELY (qtdemux->segment.stop != -1
5603 && ((qtdemux->segment.rate >= 0 && qtdemux->segment.stop <= min_time)
5604 || (qtdemux->segment.rate < 0
5605 && qtdemux->segment.start > min_time))
5606 && qtdemux->streams[index]->on_keyframe)) {
5607 GST_DEBUG_OBJECT (qtdemux, "we reached the end of our segment.");
5608 qtdemux->streams[index]->time_position = GST_CLOCK_TIME_NONE;
5612 /* gap events for subtitle streams */
5613 for (i = 0; i < qtdemux->n_streams; i++) {
5614 stream = qtdemux->streams[i];
5615 if (stream->pad && (stream->subtype == FOURCC_subp
5616 || stream->subtype == FOURCC_text
5617 || stream->subtype == FOURCC_sbtl)) {
5618 /* send one second gap events until the stream catches up */
5619 /* gaps can only be sent after segment is activated (segment.stop is no longer -1) */
5620 while (GST_CLOCK_TIME_IS_VALID (stream->segment.stop) &&
5621 GST_CLOCK_TIME_IS_VALID (stream->segment.position) &&
5622 stream->segment.position + GST_SECOND < min_time) {
5624 gst_event_new_gap (stream->segment.position, GST_SECOND);
5625 gst_pad_push_event (stream->pad, gap);
5626 stream->segment.position += GST_SECOND;
5631 stream = qtdemux->streams[index];
5632 if (stream->new_caps) {
5633 gst_qtdemux_configure_stream (qtdemux, stream);
5634 qtdemux_do_allocation (qtdemux, stream);
5637 /* fetch info for the current sample of this stream */
5638 if (G_UNLIKELY (!gst_qtdemux_prepare_current_sample (qtdemux, stream, &empty,
5639 &offset, &sample_size, &dts, &pts, &duration, &keyframe)))
5642 /* If we're doing a keyframe-only trickmode, only push keyframes on video streams */
5643 if (G_UNLIKELY (qtdemux->
5644 segment.flags & GST_SEGMENT_FLAG_TRICKMODE_KEY_UNITS)) {
5645 if (stream->subtype == FOURCC_vide && !keyframe) {
5646 GST_LOG_OBJECT (qtdemux, "Skipping non-keyframe on stream %d", index);
5651 GST_DEBUG_OBJECT (qtdemux,
5652 "pushing from stream %d, empty %d offset %" G_GUINT64_FORMAT
5653 ", size %d, dts=%" GST_TIME_FORMAT ", pts=%" GST_TIME_FORMAT
5654 ", duration %" GST_TIME_FORMAT, index, empty, offset, sample_size,
5655 GST_TIME_ARGS (dts), GST_TIME_ARGS (pts), GST_TIME_ARGS (duration));
5657 if (G_UNLIKELY (empty)) {
5658 /* empty segment, push a gap and move to the next one */
5659 gst_pad_push_event (stream->pad, gst_event_new_gap (pts, duration));
5660 stream->segment.position = pts + duration;
5664 /* hmm, empty sample, skip and move to next sample */
5665 if (G_UNLIKELY (sample_size <= 0))
5668 /* last pushed sample was out of boundary, goto next sample */
5669 if (G_UNLIKELY (GST_PAD_LAST_FLOW_RETURN (stream->pad) == GST_FLOW_EOS))
5672 if (stream->max_buffer_size == 0 || sample_size <= stream->max_buffer_size) {
5675 GST_DEBUG_OBJECT (qtdemux,
5676 "size %d larger than stream max_buffer_size %d, trimming",
5677 sample_size, stream->max_buffer_size);
5679 MIN (sample_size - stream->offset_in_sample, stream->max_buffer_size);
5682 if (qtdemux->cenc_aux_info_offset > 0) {
5685 GstBuffer *aux_info = NULL;
5687 /* pull the data stored before the sample */
5689 gst_qtdemux_pull_atom (qtdemux, qtdemux->offset,
5690 offset + stream->offset_in_sample - qtdemux->offset, &aux_info);
5691 if (G_UNLIKELY (ret != GST_FLOW_OK))
5693 gst_buffer_map (aux_info, &map, GST_MAP_READ);
5694 GST_DEBUG_OBJECT (qtdemux, "parsing cenc auxiliary info");
5695 gst_byte_reader_init (&br, map.data + 8, map.size);
5696 if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
5697 qtdemux->cenc_aux_info_sizes, qtdemux->cenc_aux_sample_count)) {
5698 GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
5699 gst_buffer_unmap (aux_info, &map);
5700 gst_buffer_unref (aux_info);
5701 ret = GST_FLOW_ERROR;
5704 gst_buffer_unmap (aux_info, &map);
5705 gst_buffer_unref (aux_info);
5708 GST_LOG_OBJECT (qtdemux, "reading %d bytes @ %" G_GUINT64_FORMAT, size,
5711 if (stream->use_allocator) {
5712 /* if we have a per-stream allocator, use it */
5713 buf = gst_buffer_new_allocate (stream->allocator, size, &stream->params);
5716 ret = gst_qtdemux_pull_atom (qtdemux, offset + stream->offset_in_sample,
5718 if (G_UNLIKELY (ret != GST_FLOW_OK))
5721 if (size != sample_size) {
5722 pts += gst_util_uint64_scale_int (GST_SECOND,
5723 stream->offset_in_sample / stream->bytes_per_frame, stream->timescale);
5724 dts += gst_util_uint64_scale_int (GST_SECOND,
5725 stream->offset_in_sample / stream->bytes_per_frame, stream->timescale);
5726 duration = gst_util_uint64_scale_int (GST_SECOND,
5727 size / stream->bytes_per_frame, stream->timescale);
5730 ret = gst_qtdemux_decorate_and_push_buffer (qtdemux, stream, buf,
5731 dts, pts, duration, keyframe, min_time, offset);
5733 if (size != sample_size) {
5734 QtDemuxSample *sample = &stream->samples[stream->sample_index];
5735 QtDemuxSegment *segment = &stream->segments[stream->segment_index];
5737 GstClockTime time_position = QTSTREAMTIME_TO_GSTTIME (stream,
5738 sample->timestamp + stream->offset_in_sample / stream->bytes_per_frame);
5739 if (time_position >= segment->media_start) {
5740 /* inside the segment, update time_position, looks very familiar to
5741 * GStreamer segments, doesn't it? */
5742 stream->time_position = (time_position - segment->media_start) +
5745 /* not yet in segment, time does not yet increment. This means
5746 * that we are still prerolling keyframes to the decoder so it can
5747 * decode the first sample of the segment. */
5748 stream->time_position = segment->time;
5753 ret = gst_qtdemux_combine_flows (qtdemux, stream, ret);
5754 /* ignore unlinked, we will not push on the pad anymore and we will EOS when
5755 * we have no more data for the pad to push */
5756 if (ret == GST_FLOW_EOS)
5759 stream->offset_in_sample += size;
5760 if (stream->offset_in_sample >= sample_size) {
5761 gst_qtdemux_advance_sample (qtdemux, stream);
5766 gst_qtdemux_advance_sample (qtdemux, stream);
5774 GST_DEBUG_OBJECT (qtdemux, "No samples left for any streams - EOS");
5780 GST_DEBUG_OBJECT (qtdemux, "No samples left for stream");
5781 /* EOS will be raised if all are EOS */
5788 gst_qtdemux_loop (GstPad * pad)
5790 GstQTDemux *qtdemux;
5794 qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
5796 cur_offset = qtdemux->offset;
5797 GST_LOG_OBJECT (qtdemux, "loop at position %" G_GUINT64_FORMAT ", state %s",
5798 cur_offset, qt_demux_state_string (qtdemux->state));
5800 switch (qtdemux->state) {
5801 case QTDEMUX_STATE_INITIAL:
5802 case QTDEMUX_STATE_HEADER:
5803 ret = gst_qtdemux_loop_state_header (qtdemux);
5805 case QTDEMUX_STATE_MOVIE:
5806 ret = gst_qtdemux_loop_state_movie (qtdemux);
5807 if (qtdemux->segment.rate < 0 && ret == GST_FLOW_EOS) {
5808 ret = gst_qtdemux_seek_to_previous_keyframe (qtdemux);
5816 /* if something went wrong, pause */
5817 if (ret != GST_FLOW_OK)
5821 gst_object_unref (qtdemux);
5827 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
5828 (NULL), ("streaming stopped, invalid state"));
5829 gst_pad_pause_task (pad);
5830 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
5835 const gchar *reason = gst_flow_get_name (ret);
5837 GST_LOG_OBJECT (qtdemux, "pausing task, reason %s", reason);
5839 gst_pad_pause_task (pad);
5841 /* fatal errors need special actions */
5843 if (ret == GST_FLOW_EOS) {
5844 if (qtdemux->n_streams == 0) {
5845 /* we have no streams, post an error */
5846 gst_qtdemux_post_no_playable_stream_error (qtdemux);
5848 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
5851 if ((stop = qtdemux->segment.stop) == -1)
5852 stop = qtdemux->segment.duration;
5854 if (qtdemux->segment.rate >= 0) {
5855 GstMessage *message;
5858 GST_LOG_OBJECT (qtdemux, "Sending segment done, at end of segment");
5859 message = gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
5860 GST_FORMAT_TIME, stop);
5861 event = gst_event_new_segment_done (GST_FORMAT_TIME, stop);
5862 if (qtdemux->segment_seqnum) {
5863 gst_message_set_seqnum (message, qtdemux->segment_seqnum);
5864 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
5866 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), message);
5867 gst_qtdemux_push_event (qtdemux, event);
5869 GstMessage *message;
5872 /* For Reverse Playback */
5873 GST_LOG_OBJECT (qtdemux, "Sending segment done, at start of segment");
5874 message = gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
5875 GST_FORMAT_TIME, qtdemux->segment.start);
5876 event = gst_event_new_segment_done (GST_FORMAT_TIME,
5877 qtdemux->segment.start);
5878 if (qtdemux->segment_seqnum) {
5879 gst_message_set_seqnum (message, qtdemux->segment_seqnum);
5880 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
5882 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), message);
5883 gst_qtdemux_push_event (qtdemux, event);
5888 GST_LOG_OBJECT (qtdemux, "Sending EOS at end of segment");
5889 event = gst_event_new_eos ();
5890 if (qtdemux->segment_seqnum)
5891 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
5892 gst_qtdemux_push_event (qtdemux, event);
5894 } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
5895 GST_ELEMENT_FLOW_ERROR (qtdemux, ret);
5896 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
5905 * Returns if there are samples to be played.
5908 has_next_entry (GstQTDemux * demux)
5910 QtDemuxStream *stream;
5913 GST_DEBUG_OBJECT (demux, "Checking if there are samples not played yet");
5915 for (i = 0; i < demux->n_streams; i++) {
5916 stream = demux->streams[i];
5918 if (stream->sample_index == -1) {
5919 stream->sample_index = 0;
5920 stream->offset_in_sample = 0;
5923 if (stream->sample_index >= stream->n_samples) {
5924 GST_LOG_OBJECT (demux, "stream %d samples exhausted", i);
5927 GST_DEBUG_OBJECT (demux, "Found a sample");
5931 GST_DEBUG_OBJECT (demux, "There wasn't any next sample");
5938 * Returns the size of the first entry at the current offset.
5939 * If -1, there are none (which means EOS or empty file).
5942 next_entry_size (GstQTDemux * demux)
5944 QtDemuxStream *stream;
5947 guint64 smalloffs = (guint64) - 1;
5948 QtDemuxSample *sample;
5950 GST_LOG_OBJECT (demux, "Finding entry at offset %" G_GUINT64_FORMAT,
5953 for (i = 0; i < demux->n_streams; i++) {
5954 stream = demux->streams[i];
5956 if (stream->sample_index == -1) {
5957 stream->sample_index = 0;
5958 stream->offset_in_sample = 0;
5961 if (stream->sample_index >= stream->n_samples) {
5962 GST_LOG_OBJECT (demux, "stream %d samples exhausted", i);
5966 if (!qtdemux_parse_samples (demux, stream, stream->sample_index)) {
5967 GST_LOG_OBJECT (demux, "Parsing of index %u from stbl atom failed!",
5968 stream->sample_index);
5972 sample = &stream->samples[stream->sample_index];
5974 GST_LOG_OBJECT (demux,
5975 "Checking Stream %d (sample_index:%d / offset:%" G_GUINT64_FORMAT
5976 " / size:%" G_GUINT32_FORMAT ")", i, stream->sample_index,
5977 sample->offset, sample->size);
5979 if (((smalloffs == -1)
5980 || (sample->offset < smalloffs)) && (sample->size)) {
5982 smalloffs = sample->offset;
5986 GST_LOG_OBJECT (demux,
5987 "stream %d offset %" G_GUINT64_FORMAT " demux->offset :%"
5988 G_GUINT64_FORMAT, smallidx, smalloffs, demux->offset);
5993 stream = demux->streams[smallidx];
5994 sample = &stream->samples[stream->sample_index];
5996 if (sample->offset >= demux->offset) {
5997 demux->todrop = sample->offset - demux->offset;
5998 return sample->size + demux->todrop;
6001 GST_DEBUG_OBJECT (demux,
6002 "There wasn't any entry at offset %" G_GUINT64_FORMAT, demux->offset);
6007 gst_qtdemux_post_progress (GstQTDemux * demux, gint num, gint denom)
6009 gint perc = (gint) ((gdouble) num * 100.0 / (gdouble) denom);
6011 gst_element_post_message (GST_ELEMENT_CAST (demux),
6012 gst_message_new_element (GST_OBJECT_CAST (demux),
6013 gst_structure_new ("progress", "percent", G_TYPE_INT, perc, NULL)));
6017 qtdemux_seek_offset (GstQTDemux * demux, guint64 offset)
6022 GST_DEBUG_OBJECT (demux, "Seeking to %" G_GUINT64_FORMAT, offset);
6025 gst_event_new_seek (1.0, GST_FORMAT_BYTES,
6026 GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset,
6027 GST_SEEK_TYPE_NONE, -1);
6029 /* store seqnum to drop flush events, they don't need to reach downstream */
6030 demux->offset_seek_seqnum = gst_event_get_seqnum (event);
6031 res = gst_pad_push_event (demux->sinkpad, event);
6032 demux->offset_seek_seqnum = 0;
6037 /* check for seekable upstream, above and beyond a mere query */
6039 gst_qtdemux_check_seekability (GstQTDemux * demux)
6042 gboolean seekable = FALSE;
6043 gint64 start = -1, stop = -1;
6045 if (demux->upstream_size)
6048 query = gst_query_new_seeking (GST_FORMAT_BYTES);
6049 if (!gst_pad_peer_query (demux->sinkpad, query)) {
6050 GST_DEBUG_OBJECT (demux, "seeking query failed");
6054 gst_query_parse_seeking (query, NULL, &seekable, &start, &stop);
6056 /* try harder to query upstream size if we didn't get it the first time */
6057 if (seekable && stop == -1) {
6058 GST_DEBUG_OBJECT (demux, "doing duration query to fix up unset stop");
6059 gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &stop);
6062 /* if upstream doesn't know the size, it's likely that it's not seekable in
6063 * practice even if it technically may be seekable */
6064 if (seekable && (start != 0 || stop <= start)) {
6065 GST_DEBUG_OBJECT (demux, "seekable but unknown start/stop -> disable");
6070 gst_query_unref (query);
6072 GST_DEBUG_OBJECT (demux, "seekable: %d (%" G_GUINT64_FORMAT " - %"
6073 G_GUINT64_FORMAT ")", seekable, start, stop);
6074 demux->upstream_seekable = seekable;
6075 demux->upstream_size = seekable ? stop : -1;
6079 gst_qtdemux_drop_data (GstQTDemux * demux, gint bytes)
6081 g_return_if_fail (bytes <= demux->todrop);
6083 GST_LOG_OBJECT (demux, "Dropping %d bytes", bytes);
6084 gst_adapter_flush (demux->adapter, bytes);
6085 demux->neededbytes -= bytes;
6086 demux->offset += bytes;
6087 demux->todrop -= bytes;
6091 gst_qtdemux_check_send_pending_segment (GstQTDemux * demux)
6093 if (G_UNLIKELY (demux->pending_newsegment)) {
6096 gst_qtdemux_push_pending_newsegment (demux);
6097 /* clear to send tags on all streams */
6098 for (i = 0; i < demux->n_streams; i++) {
6099 QtDemuxStream *stream;
6100 stream = demux->streams[i];
6101 gst_qtdemux_push_tags (demux, stream);
6102 if (stream->sparse) {
6103 GST_INFO_OBJECT (demux, "Sending gap event on stream %d", i);
6104 gst_pad_push_event (stream->pad,
6105 gst_event_new_gap (stream->segment.position, GST_CLOCK_TIME_NONE));
6112 gst_qtdemux_send_gap_for_segment (GstQTDemux * demux,
6113 QtDemuxStream * stream, gint segment_index, GstClockTime pos)
6115 GstClockTime ts, dur;
6120 stream->segments[segment_index].duration - (pos -
6121 stream->segments[segment_index].time);
6122 gap = gst_event_new_gap (ts, dur);
6123 stream->time_position += dur;
6125 GST_DEBUG_OBJECT (stream->pad, "Pushing gap for empty "
6126 "segment: %" GST_PTR_FORMAT, gap);
6127 gst_pad_push_event (stream->pad, gap);
6131 gst_qtdemux_stream_send_initial_gap_segments (GstQTDemux * demux,
6132 QtDemuxStream * stream)
6136 /* Push any initial gap segments before proceeding to the
6138 for (i = 0; i < stream->n_segments; i++) {
6139 gst_qtdemux_activate_segment (demux, stream, i, stream->time_position);
6141 if (QTSEGMENT_IS_EMPTY (&stream->segments[i])) {
6142 gst_qtdemux_send_gap_for_segment (demux, stream, i,
6143 stream->time_position);
6145 /* Only support empty segment at the beginning followed by
6146 * one non-empty segment, this was checked when parsing the
6147 * edts atom, arriving here is unexpected */
6148 g_assert (i + 1 == stream->n_segments);
6154 static GstFlowReturn
6155 gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent, GstBuffer * inbuf)
6159 demux = GST_QTDEMUX (parent);
6161 GST_DEBUG_OBJECT (demux,
6162 "Received buffer pts:%" GST_TIME_FORMAT " dts:%" GST_TIME_FORMAT
6163 " offset:%" G_GUINT64_FORMAT " size:%" G_GSIZE_FORMAT " demux offset:%"
6164 G_GUINT64_FORMAT, GST_TIME_ARGS (GST_BUFFER_PTS (inbuf)),
6165 GST_TIME_ARGS (GST_BUFFER_DTS (inbuf)), GST_BUFFER_OFFSET (inbuf),
6166 gst_buffer_get_size (inbuf), demux->offset);
6168 if (GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_DISCONT)) {
6169 gboolean is_gap_input = FALSE;
6172 GST_DEBUG_OBJECT (demux, "Got DISCONT, marking all streams as DISCONT");
6174 for (i = 0; i < demux->n_streams; i++) {
6175 demux->streams[i]->discont = TRUE;
6178 /* Check if we can land back on our feet in the case where upstream is
6179 * handling the seeking/pushing of samples with gaps in between (like
6180 * in the case of trick-mode DASH for example) */
6181 if (demux->upstream_format_is_time
6182 && GST_BUFFER_OFFSET (inbuf) != GST_BUFFER_OFFSET_NONE) {
6184 for (i = 0; i < demux->n_streams; i++) {
6186 GST_LOG_OBJECT (demux,
6187 "Stream #%d , checking if offset %" G_GUINT64_FORMAT
6188 " is a sample start", i, GST_BUFFER_OFFSET (inbuf));
6190 gst_qtdemux_find_index_for_given_media_offset_linear (demux,
6191 demux->streams[i], GST_BUFFER_OFFSET (inbuf));
6193 QtDemuxSample *sample = &demux->streams[i]->samples[res];
6194 GST_LOG_OBJECT (demux,
6195 "Checking if sample %d from stream %d is valid (offset:%"
6196 G_GUINT64_FORMAT " size:%" G_GUINT32_FORMAT ")", res, i,
6197 sample->offset, sample->size);
6198 if (sample->offset == GST_BUFFER_OFFSET (inbuf)) {
6199 GST_LOG_OBJECT (demux,
6200 "new buffer corresponds to a valid sample : %" G_GUINT32_FORMAT,
6202 is_gap_input = TRUE;
6203 /* We can go back to standard playback mode */
6204 demux->state = QTDEMUX_STATE_MOVIE;
6205 /* Remember which sample this stream is at */
6206 demux->streams[i]->sample_index = res;
6207 /* Finally update all push-based values to the expected values */
6208 demux->neededbytes = demux->streams[i]->samples[res].size;
6210 demux->offset = GST_BUFFER_OFFSET (inbuf);
6214 if (!is_gap_input) {
6215 /* Reset state if it's a real discont */
6216 demux->neededbytes = 16;
6217 demux->state = QTDEMUX_STATE_INITIAL;
6218 demux->offset = GST_BUFFER_OFFSET (inbuf);
6221 /* Reverse fragmented playback, need to flush all we have before
6222 * consuming a new fragment.
6223 * The samples array have the timestamps calculated by accumulating the
6224 * durations but this won't work for reverse playback of fragments as
6225 * the timestamps of a subsequent fragment should be smaller than the
6226 * previously received one. */
6227 if (!is_gap_input && demux->fragmented && demux->segment.rate < 0) {
6228 gst_qtdemux_process_adapter (demux, TRUE);
6229 for (i = 0; i < demux->n_streams; i++)
6230 gst_qtdemux_stream_flush_samples_data (demux, demux->streams[i]);
6234 gst_adapter_push (demux->adapter, inbuf);
6236 GST_DEBUG_OBJECT (demux,
6237 "pushing in inbuf %p, neededbytes:%u, available:%" G_GSIZE_FORMAT, inbuf,
6238 demux->neededbytes, gst_adapter_available (demux->adapter));
6240 return gst_qtdemux_process_adapter (demux, FALSE);
6243 static GstFlowReturn
6244 gst_qtdemux_process_adapter (GstQTDemux * demux, gboolean force)
6246 GstFlowReturn ret = GST_FLOW_OK;
6248 /* we never really mean to buffer that much */
6249 if (demux->neededbytes == -1) {
6253 while (((gst_adapter_available (demux->adapter)) >= demux->neededbytes) &&
6254 (ret == GST_FLOW_OK || (ret == GST_FLOW_NOT_LINKED && force))) {
6256 #ifndef GST_DISABLE_GST_DEBUG
6258 guint64 discont_offset, distance_from_discont;
6260 discont_offset = gst_adapter_offset_at_discont (demux->adapter);
6261 distance_from_discont =
6262 gst_adapter_distance_from_discont (demux->adapter);
6264 GST_DEBUG_OBJECT (demux,
6265 "state:%s , demux->neededbytes:%d, demux->offset:%" G_GUINT64_FORMAT
6266 " adapter offset :%" G_GUINT64_FORMAT " (+ %" G_GUINT64_FORMAT
6267 " bytes)", qt_demux_state_string (demux->state), demux->neededbytes,
6268 demux->offset, discont_offset, distance_from_discont);
6272 switch (demux->state) {
6273 case QTDEMUX_STATE_INITIAL:{
6278 gst_qtdemux_check_seekability (demux);
6280 data = gst_adapter_map (demux->adapter, demux->neededbytes);
6282 /* get fourcc/length, set neededbytes */
6283 extract_initial_length_and_fourcc ((guint8 *) data, demux->neededbytes,
6285 gst_adapter_unmap (demux->adapter);
6287 GST_DEBUG_OBJECT (demux, "Peeking found [%" GST_FOURCC_FORMAT "] "
6288 "size: %" G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), size);
6290 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
6291 (_("This file is invalid and cannot be played.")),
6292 ("initial atom '%" GST_FOURCC_FORMAT "' has empty length",
6293 GST_FOURCC_ARGS (fourcc)));
6294 ret = GST_FLOW_ERROR;
6297 if (fourcc == FOURCC_mdat) {
6298 gint next_entry = next_entry_size (demux);
6299 if (demux->n_streams > 0 && (next_entry != -1 || !demux->fragmented)) {
6300 /* we have the headers, start playback */
6301 demux->state = QTDEMUX_STATE_MOVIE;
6302 demux->neededbytes = next_entry;
6303 demux->mdatleft = size;
6305 /* no headers yet, try to get them */
6308 guint64 old, target;
6311 old = demux->offset;
6312 target = old + size;
6314 /* try to jump over the atom with a seek */
6315 /* only bother if it seems worth doing so,
6316 * and avoids possible upstream/server problems */
6317 if (demux->upstream_seekable &&
6318 demux->upstream_size > 4 * (1 << 20)) {
6319 res = qtdemux_seek_offset (demux, target);
6321 GST_DEBUG_OBJECT (demux, "skipping seek");
6326 GST_DEBUG_OBJECT (demux, "seek success");
6327 /* remember the offset fo the first mdat so we can seek back to it
6328 * after we have the headers */
6329 if (fourcc == FOURCC_mdat && demux->first_mdat == -1) {
6330 demux->first_mdat = old;
6331 GST_DEBUG_OBJECT (demux, "first mdat at %" G_GUINT64_FORMAT,
6334 /* seek worked, continue reading */
6335 demux->offset = target;
6336 demux->neededbytes = 16;
6337 demux->state = QTDEMUX_STATE_INITIAL;
6339 /* seek failed, need to buffer */
6340 demux->offset = old;
6341 GST_DEBUG_OBJECT (demux, "seek failed/skipped");
6342 /* there may be multiple mdat (or alike) buffers */
6344 if (demux->mdatbuffer)
6345 bs = gst_buffer_get_size (demux->mdatbuffer);
6348 if (size + bs > 10 * (1 << 20))
6350 demux->state = QTDEMUX_STATE_BUFFER_MDAT;
6351 demux->neededbytes = size;
6352 if (!demux->mdatbuffer)
6353 demux->mdatoffset = demux->offset;
6356 } else if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
6357 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
6358 (_("This file is invalid and cannot be played.")),
6359 ("atom %" GST_FOURCC_FORMAT " has bogus size %" G_GUINT64_FORMAT,
6360 GST_FOURCC_ARGS (fourcc), size));
6361 ret = GST_FLOW_ERROR;
6364 /* this means we already started buffering and still no moov header,
6365 * let's continue buffering everything till we get moov */
6366 if (demux->mdatbuffer && !(fourcc == FOURCC_moov
6367 || fourcc == FOURCC_moof))
6369 demux->neededbytes = size;
6370 demux->state = QTDEMUX_STATE_HEADER;
6374 case QTDEMUX_STATE_HEADER:{
6378 GST_DEBUG_OBJECT (demux, "In header");
6380 data = gst_adapter_map (demux->adapter, demux->neededbytes);
6382 /* parse the header */
6383 extract_initial_length_and_fourcc (data, demux->neededbytes, NULL,
6385 if (fourcc == FOURCC_moov) {
6388 /* in usual fragmented setup we could try to scan for more
6389 * and end up at the the moov (after mdat) again */
6390 if (demux->got_moov && demux->n_streams > 0 &&
6392 || demux->last_moov_offset == demux->offset)) {
6393 GST_DEBUG_OBJECT (demux,
6394 "Skipping moov atom as we have (this) one already");
6396 GST_DEBUG_OBJECT (demux, "Parsing [moov]");
6398 if (demux->got_moov && demux->fragmented) {
6399 GST_DEBUG_OBJECT (demux,
6400 "Got a second moov, clean up data from old one");
6401 if (demux->moov_node_compressed) {
6402 g_node_destroy (demux->moov_node_compressed);
6403 if (demux->moov_node)
6404 g_free (demux->moov_node->data);
6406 demux->moov_node_compressed = NULL;
6407 if (demux->moov_node)
6408 g_node_destroy (demux->moov_node);
6409 demux->moov_node = NULL;
6411 /* prepare newsegment to send when streaming actually starts */
6412 if (!demux->pending_newsegment) {
6413 demux->pending_newsegment =
6414 gst_event_new_segment (&demux->segment);
6415 if (demux->segment_seqnum)
6416 gst_event_set_seqnum (demux->pending_newsegment,
6417 demux->segment_seqnum);
6421 demux->last_moov_offset = demux->offset;
6423 qtdemux_parse_moov (demux, data, demux->neededbytes);
6424 qtdemux_node_dump (demux, demux->moov_node);
6425 qtdemux_parse_tree (demux);
6426 qtdemux_prepare_streams (demux);
6427 if (!demux->got_moov)
6428 qtdemux_expose_streams (demux);
6431 for (n = 0; n < demux->n_streams; n++) {
6432 QtDemuxStream *stream = demux->streams[n];
6434 gst_qtdemux_configure_stream (demux, stream);
6438 demux->got_moov = TRUE;
6439 gst_qtdemux_check_send_pending_segment (demux);
6441 /* fragmented streams headers shouldn't contain edts atoms */
6442 if (!demux->fragmented) {
6443 for (n = 0; n < demux->n_streams; n++) {
6444 gst_qtdemux_stream_send_initial_gap_segments (demux,
6449 if (demux->moov_node_compressed) {
6450 g_node_destroy (demux->moov_node_compressed);
6451 g_free (demux->moov_node->data);
6453 demux->moov_node_compressed = NULL;
6454 g_node_destroy (demux->moov_node);
6455 demux->moov_node = NULL;
6456 GST_DEBUG_OBJECT (demux, "Finished parsing the header");
6458 } else if (fourcc == FOURCC_moof) {
6459 if ((demux->got_moov || demux->media_caps) && demux->fragmented) {
6461 GstClockTime prev_pts;
6462 guint64 prev_offset;
6463 guint64 adapter_discont_offset, adapter_discont_dist;
6465 GST_DEBUG_OBJECT (demux, "Parsing [moof]");
6468 * The timestamp of the moof buffer is relevant as some scenarios
6469 * won't have the initial timestamp in the atoms. Whenever a new
6470 * buffer has started, we get that buffer's PTS and use it as a base
6471 * timestamp for the trun entries.
6473 * To keep track of the current buffer timestamp and starting point
6474 * we use gst_adapter_prev_pts that gives us the PTS and the distance
6475 * from the beggining of the buffer, with the distance and demux->offset
6476 * we know if it is still the same buffer or not.
6478 prev_pts = gst_adapter_prev_pts (demux->adapter, &dist);
6479 prev_offset = demux->offset - dist;
6480 if (demux->fragment_start_offset == -1
6481 || prev_offset > demux->fragment_start_offset) {
6482 demux->fragment_start_offset = prev_offset;
6483 demux->fragment_start = prev_pts;
6484 GST_DEBUG_OBJECT (demux,
6485 "New fragment start found at: %" G_GUINT64_FORMAT " : %"
6486 GST_TIME_FORMAT, demux->fragment_start_offset,
6487 GST_TIME_ARGS (demux->fragment_start));
6490 /* We can't use prev_offset() here because this would require
6491 * upstream to set consistent and correct offsets on all buffers
6492 * since the discont. Nothing ever did that in the past and we
6493 * would break backwards compatibility here then.
6494 * Instead take the offset we had at the last discont and count
6495 * the bytes from there. This works with old code as there would
6496 * be no discont between moov and moof, and also works with
6497 * adaptivedemux which correctly sets offset and will set the
6498 * DISCONT flag accordingly when needed.
6500 * We also only do this for upstream TIME segments as otherwise
6501 * there are potential backwards compatibility problems with
6502 * seeking in PUSH mode and upstream providing inconsistent
6504 adapter_discont_offset =
6505 gst_adapter_offset_at_discont (demux->adapter);
6506 adapter_discont_dist =
6507 gst_adapter_distance_from_discont (demux->adapter);
6509 GST_DEBUG_OBJECT (demux,
6510 "demux offset %" G_GUINT64_FORMAT " adapter offset %"
6511 G_GUINT64_FORMAT " (+ %" G_GUINT64_FORMAT " bytes)",
6512 demux->offset, adapter_discont_offset, adapter_discont_dist);
6514 if (demux->upstream_format_is_time) {
6515 demux->moof_offset = adapter_discont_offset;
6516 if (demux->moof_offset != GST_BUFFER_OFFSET_NONE)
6517 demux->moof_offset += adapter_discont_dist;
6518 if (demux->moof_offset == GST_BUFFER_OFFSET_NONE)
6519 demux->moof_offset = demux->offset;
6521 demux->moof_offset = demux->offset;
6524 if (!qtdemux_parse_moof (demux, data, demux->neededbytes,
6525 demux->moof_offset, NULL)) {
6526 gst_adapter_unmap (demux->adapter);
6527 ret = GST_FLOW_ERROR;
6530 /* in MSS we need to expose the pads after the first moof as we won't get a moov */
6531 if (demux->mss_mode && !demux->exposed) {
6532 if (!demux->pending_newsegment) {
6533 GST_DEBUG_OBJECT (demux, "new pending_newsegment");
6534 demux->pending_newsegment =
6535 gst_event_new_segment (&demux->segment);
6536 if (demux->segment_seqnum)
6537 gst_event_set_seqnum (demux->pending_newsegment,
6538 demux->segment_seqnum);
6540 qtdemux_expose_streams (demux);
6543 GST_DEBUG_OBJECT (demux, "Discarding [moof]");
6545 } else if (fourcc == FOURCC_ftyp) {
6546 GST_DEBUG_OBJECT (demux, "Parsing [ftyp]");
6547 qtdemux_parse_ftyp (demux, data, demux->neededbytes);
6548 } else if (fourcc == FOURCC_uuid) {
6549 GST_DEBUG_OBJECT (demux, "Parsing [uuid]");
6550 qtdemux_parse_uuid (demux, data, demux->neededbytes);
6551 } else if (fourcc == FOURCC_sidx) {
6552 GST_DEBUG_OBJECT (demux, "Parsing [sidx]");
6553 qtdemux_parse_sidx (demux, data, demux->neededbytes);
6555 GST_WARNING_OBJECT (demux,
6556 "Unknown fourcc while parsing header : %" GST_FOURCC_FORMAT,
6557 GST_FOURCC_ARGS (fourcc));
6558 /* Let's jump that one and go back to initial state */
6560 gst_adapter_unmap (demux->adapter);
6563 if (demux->mdatbuffer && demux->n_streams) {
6564 gsize remaining_data_size = 0;
6566 /* the mdat was before the header */
6567 GST_DEBUG_OBJECT (demux, "We have n_streams:%d and mdatbuffer:%p",
6568 demux->n_streams, demux->mdatbuffer);
6569 /* restore our adapter/offset view of things with upstream;
6570 * put preceding buffered data ahead of current moov data.
6571 * This should also handle evil mdat, moov, mdat cases and alike */
6572 gst_adapter_flush (demux->adapter, demux->neededbytes);
6574 /* Store any remaining data after the mdat for later usage */
6575 remaining_data_size = gst_adapter_available (demux->adapter);
6576 if (remaining_data_size > 0) {
6577 g_assert (demux->restoredata_buffer == NULL);
6578 demux->restoredata_buffer =
6579 gst_adapter_take_buffer (demux->adapter, remaining_data_size);
6580 demux->restoredata_offset = demux->offset + demux->neededbytes;
6581 GST_DEBUG_OBJECT (demux,
6582 "Stored %" G_GSIZE_FORMAT " post mdat bytes at offset %"
6583 G_GUINT64_FORMAT, remaining_data_size,
6584 demux->restoredata_offset);
6587 gst_adapter_push (demux->adapter, demux->mdatbuffer);
6588 demux->mdatbuffer = NULL;
6589 demux->offset = demux->mdatoffset;
6590 demux->neededbytes = next_entry_size (demux);
6591 demux->state = QTDEMUX_STATE_MOVIE;
6592 demux->mdatleft = gst_adapter_available (demux->adapter);
6594 GST_DEBUG_OBJECT (demux, "Carrying on normally");
6595 gst_adapter_flush (demux->adapter, demux->neededbytes);
6597 /* only go back to the mdat if there are samples to play */
6598 if (demux->got_moov && demux->first_mdat != -1
6599 && has_next_entry (demux)) {
6602 /* we need to seek back */
6603 res = qtdemux_seek_offset (demux, demux->first_mdat);
6605 demux->offset = demux->first_mdat;
6607 GST_DEBUG_OBJECT (demux, "Seek back failed");
6610 demux->offset += demux->neededbytes;
6612 demux->neededbytes = 16;
6613 demux->state = QTDEMUX_STATE_INITIAL;
6618 case QTDEMUX_STATE_BUFFER_MDAT:{
6622 GST_DEBUG_OBJECT (demux, "Got our buffer at offset %" G_GUINT64_FORMAT,
6624 buf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
6625 gst_buffer_extract (buf, 0, fourcc, 4);
6626 GST_DEBUG_OBJECT (demux, "mdatbuffer starts with %" GST_FOURCC_FORMAT,
6627 GST_FOURCC_ARGS (QT_FOURCC (fourcc)));
6628 if (demux->mdatbuffer)
6629 demux->mdatbuffer = gst_buffer_append (demux->mdatbuffer, buf);
6631 demux->mdatbuffer = buf;
6632 demux->offset += demux->neededbytes;
6633 demux->neededbytes = 16;
6634 demux->state = QTDEMUX_STATE_INITIAL;
6635 gst_qtdemux_post_progress (demux, 1, 1);
6639 case QTDEMUX_STATE_MOVIE:{
6640 QtDemuxStream *stream = NULL;
6641 QtDemuxSample *sample;
6643 GstClockTime dts, pts, duration;
6646 GST_DEBUG_OBJECT (demux,
6647 "BEGIN // in MOVIE for offset %" G_GUINT64_FORMAT, demux->offset);
6649 if (demux->fragmented) {
6650 GST_DEBUG_OBJECT (demux, "mdat remaining %" G_GUINT64_FORMAT,
6652 if (G_LIKELY (demux->todrop < demux->mdatleft)) {
6653 /* if needed data starts within this atom,
6654 * then it should not exceed this atom */
6655 if (G_UNLIKELY (demux->neededbytes > demux->mdatleft)) {
6656 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
6657 (_("This file is invalid and cannot be played.")),
6658 ("sample data crosses atom boundary"));
6659 ret = GST_FLOW_ERROR;
6662 demux->mdatleft -= demux->neededbytes;
6664 GST_DEBUG_OBJECT (demux, "data atom emptied; resuming atom scan");
6665 /* so we are dropping more than left in this atom */
6666 gst_qtdemux_drop_data (demux, demux->mdatleft);
6667 demux->mdatleft = 0;
6669 /* need to resume atom parsing so we do not miss any other pieces */
6670 demux->state = QTDEMUX_STATE_INITIAL;
6671 demux->neededbytes = 16;
6673 /* check if there was any stored post mdat data from previous buffers */
6674 if (demux->restoredata_buffer) {
6675 g_assert (gst_adapter_available (demux->adapter) == 0);
6677 gst_adapter_push (demux->adapter, demux->restoredata_buffer);
6678 demux->restoredata_buffer = NULL;
6679 demux->offset = demux->restoredata_offset;
6686 if (demux->todrop) {
6687 if (demux->cenc_aux_info_offset > 0) {
6691 GST_DEBUG_OBJECT (demux, "parsing cenc auxiliary info");
6692 data = gst_adapter_map (demux->adapter, demux->todrop);
6693 gst_byte_reader_init (&br, data + 8, demux->todrop);
6694 if (!qtdemux_parse_cenc_aux_info (demux, demux->streams[0], &br,
6695 demux->cenc_aux_info_sizes, demux->cenc_aux_sample_count)) {
6696 GST_ERROR_OBJECT (demux, "failed to parse cenc auxiliary info");
6697 ret = GST_FLOW_ERROR;
6698 gst_adapter_unmap (demux->adapter);
6699 g_free (demux->cenc_aux_info_sizes);
6700 demux->cenc_aux_info_sizes = NULL;
6703 demux->cenc_aux_info_offset = 0;
6704 g_free (demux->cenc_aux_info_sizes);
6705 demux->cenc_aux_info_sizes = NULL;
6706 gst_adapter_unmap (demux->adapter);
6708 gst_qtdemux_drop_data (demux, demux->todrop);
6712 /* initial newsegment sent here after having added pads,
6713 * possible others in sink_event */
6714 gst_qtdemux_check_send_pending_segment (demux);
6716 /* Figure out which stream this packet belongs to */
6717 for (i = 0; i < demux->n_streams; i++) {
6718 stream = demux->streams[i];
6719 if (stream->sample_index >= stream->n_samples)
6721 GST_LOG_OBJECT (demux,
6722 "Checking stream %d (sample_index:%d / offset:%" G_GUINT64_FORMAT
6723 " / size:%d)", i, stream->sample_index,
6724 stream->samples[stream->sample_index].offset,
6725 stream->samples[stream->sample_index].size);
6727 if (stream->samples[stream->sample_index].offset == demux->offset)
6731 if (G_UNLIKELY (stream == NULL || i == demux->n_streams))
6732 goto unknown_stream;
6734 if (stream->new_caps) {
6735 gst_qtdemux_configure_stream (demux, stream);
6738 /* Put data in a buffer, set timestamps, caps, ... */
6739 sample = &stream->samples[stream->sample_index];
6741 if (G_LIKELY (!(STREAM_IS_EOS (stream)))) {
6742 GST_DEBUG_OBJECT (demux, "stream : %" GST_FOURCC_FORMAT,
6743 GST_FOURCC_ARGS (stream->fourcc));
6745 dts = QTSAMPLE_DTS (stream, sample);
6746 pts = QTSAMPLE_PTS (stream, sample);
6747 duration = QTSAMPLE_DUR_DTS (stream, sample, dts);
6748 keyframe = QTSAMPLE_KEYFRAME (stream, sample);
6750 /* check for segment end */
6751 if (G_UNLIKELY (demux->segment.stop != -1
6752 && demux->segment.stop <= pts && stream->on_keyframe)) {
6753 GST_DEBUG_OBJECT (demux, "we reached the end of our segment.");
6754 stream->time_position = GST_CLOCK_TIME_NONE; /* this means EOS */
6756 /* skip this data, stream is EOS */
6757 gst_adapter_flush (demux->adapter, demux->neededbytes);
6759 /* check if all streams are eos */
6761 for (i = 0; i < demux->n_streams; i++) {
6762 if (!STREAM_IS_EOS (demux->streams[i])) {
6768 if (ret == GST_FLOW_EOS) {
6769 GST_DEBUG_OBJECT (demux, "All streams are EOS, signal upstream");
6776 gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
6778 /* FIXME: should either be an assert or a plain check */
6779 g_return_val_if_fail (outbuf != NULL, GST_FLOW_ERROR);
6781 ret = gst_qtdemux_decorate_and_push_buffer (demux, stream, outbuf,
6782 dts, pts, duration, keyframe, dts, demux->offset);
6786 ret = gst_qtdemux_combine_flows (demux, stream, ret);
6787 if (ret != GST_FLOW_OK && ret != GST_FLOW_NOT_LINKED)
6788 goto non_ok_unlinked_flow;
6790 /* skip this data, stream is EOS */
6791 gst_adapter_flush (demux->adapter, demux->neededbytes);
6794 stream->sample_index++;
6795 stream->offset_in_sample = 0;
6797 /* update current offset and figure out size of next buffer */
6798 GST_LOG_OBJECT (demux, "increasing offset %" G_GUINT64_FORMAT " by %u",
6799 demux->offset, demux->neededbytes);
6800 demux->offset += demux->neededbytes;
6801 GST_LOG_OBJECT (demux, "offset is now %" G_GUINT64_FORMAT,
6804 if ((demux->neededbytes = next_entry_size (demux)) == -1) {
6805 if (demux->fragmented) {
6806 GST_DEBUG_OBJECT (demux, "(temporarily) out of fragmented samples");
6807 /* there may be more to follow, only finish this atom */
6808 demux->todrop = demux->mdatleft;
6809 demux->neededbytes = demux->todrop;
6821 /* when buffering movie data, at least show user something is happening */
6822 if (ret == GST_FLOW_OK && demux->state == QTDEMUX_STATE_BUFFER_MDAT &&
6823 gst_adapter_available (demux->adapter) <= demux->neededbytes) {
6824 gst_qtdemux_post_progress (demux, gst_adapter_available (demux->adapter),
6825 demux->neededbytes);
6832 non_ok_unlinked_flow:
6834 GST_DEBUG_OBJECT (demux, "Stopping, combined return flow %s",
6835 gst_flow_get_name (ret));
6840 GST_ELEMENT_ERROR (demux, STREAM, FAILED, (NULL), ("unknown stream found"));
6841 ret = GST_FLOW_ERROR;
6846 GST_DEBUG_OBJECT (demux, "no next entry, EOS");
6852 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
6853 (NULL), ("qtdemuxer invalid state %d", demux->state));
6854 ret = GST_FLOW_ERROR;
6859 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
6860 (NULL), ("no 'moov' atom within the first 10 MB"));
6861 ret = GST_FLOW_ERROR;
6867 qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent)
6872 query = gst_query_new_scheduling ();
6874 if (!gst_pad_peer_query (sinkpad, query)) {
6875 gst_query_unref (query);
6879 pull_mode = gst_query_has_scheduling_mode_with_flags (query,
6880 GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
6881 gst_query_unref (query);
6886 GST_DEBUG_OBJECT (sinkpad, "activating pull");
6887 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
6891 GST_DEBUG_OBJECT (sinkpad, "activating push");
6892 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
6897 qtdemux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
6898 GstPadMode mode, gboolean active)
6901 GstQTDemux *demux = GST_QTDEMUX (parent);
6904 case GST_PAD_MODE_PUSH:
6905 demux->pullbased = FALSE;
6908 case GST_PAD_MODE_PULL:
6910 demux->pullbased = TRUE;
6911 res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_qtdemux_loop,
6914 res = gst_pad_stop_task (sinkpad);
6926 qtdemux_inflate (void *z_buffer, guint z_length, guint * length)
6932 memset (&z, 0, sizeof (z));
6937 if ((ret = inflateInit (&z)) != Z_OK) {
6938 GST_ERROR ("inflateInit() returned %d", ret);
6942 z.next_in = z_buffer;
6943 z.avail_in = z_length;
6945 buffer = (guint8 *) g_malloc (*length);
6946 z.avail_out = *length;
6947 z.next_out = (Bytef *) buffer;
6949 ret = inflate (&z, Z_NO_FLUSH);
6950 if (ret == Z_STREAM_END) {
6952 } else if (ret != Z_OK) {
6953 GST_WARNING ("inflate() returned %d", ret);
6958 buffer = (guint8 *) g_realloc (buffer, *length);
6959 z.next_out = (Bytef *) (buffer + z.total_out);
6960 z.avail_out += 4096;
6961 } while (z.avail_in > 0);
6963 if (ret != Z_STREAM_END) {
6968 *length = z.total_out;
6975 #endif /* HAVE_ZLIB */
6978 qtdemux_parse_moov (GstQTDemux * qtdemux, const guint8 * buffer, guint length)
6982 qtdemux->moov_node = g_node_new ((guint8 *) buffer);
6984 /* counts as header data */
6985 qtdemux->header_size += length;
6987 GST_DEBUG_OBJECT (qtdemux, "parsing 'moov' atom");
6988 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buffer, length);
6990 cmov = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_cmov);
6997 dcom = qtdemux_tree_get_child_by_type (cmov, FOURCC_dcom);
6998 cmvd = qtdemux_tree_get_child_by_type (cmov, FOURCC_cmvd);
6999 if (dcom == NULL || cmvd == NULL)
7000 goto invalid_compression;
7002 dcom_len = QT_UINT32 (dcom->data);
7004 goto invalid_compression;
7006 method = QT_FOURCC ((guint8 *) dcom->data + 8);
7010 guint uncompressed_length;
7011 guint compressed_length;
7015 cmvd_len = QT_UINT32 ((guint8 *) cmvd->data);
7017 goto invalid_compression;
7019 uncompressed_length = QT_UINT32 ((guint8 *) cmvd->data + 8);
7020 compressed_length = cmvd_len - 12;
7021 GST_LOG ("length = %u", uncompressed_length);
7024 (guint8 *) qtdemux_inflate ((guint8 *) cmvd->data + 12,
7025 compressed_length, &uncompressed_length);
7028 qtdemux->moov_node_compressed = qtdemux->moov_node;
7029 qtdemux->moov_node = g_node_new (buf);
7031 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buf,
7032 uncompressed_length);
7036 #endif /* HAVE_ZLIB */
7038 GST_WARNING_OBJECT (qtdemux, "unknown or unhandled header compression "
7039 "type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (method));
7046 invalid_compression:
7048 GST_ERROR_OBJECT (qtdemux, "invalid compressed header");
7054 qtdemux_parse_container (GstQTDemux * qtdemux, GNode * node, const guint8 * buf,
7057 while (G_UNLIKELY (buf < end)) {
7061 if (G_UNLIKELY (buf + 4 > end)) {
7062 GST_LOG_OBJECT (qtdemux, "buffer overrun");
7065 len = QT_UINT32 (buf);
7066 if (G_UNLIKELY (len == 0)) {
7067 GST_LOG_OBJECT (qtdemux, "empty container");
7070 if (G_UNLIKELY (len < 8)) {
7071 GST_WARNING_OBJECT (qtdemux, "length too short (%d < 8)", len);
7074 if (G_UNLIKELY (len > (end - buf))) {
7075 GST_WARNING_OBJECT (qtdemux, "length too long (%d > %d)", len,
7076 (gint) (end - buf));
7080 child = g_node_new ((guint8 *) buf);
7081 g_node_append (node, child);
7082 GST_LOG_OBJECT (qtdemux, "adding new node of len %d", len);
7083 qtdemux_parse_node (qtdemux, child, buf, len);
7091 qtdemux_parse_theora_extension (GstQTDemux * qtdemux, QtDemuxStream * stream,
7094 int len = QT_UINT32 (xdxt->data);
7095 guint8 *buf = xdxt->data;
7096 guint8 *end = buf + len;
7099 /* skip size and type */
7107 size = QT_UINT32 (buf);
7108 type = QT_FOURCC (buf + 4);
7110 GST_LOG_OBJECT (qtdemux, "%p %p", buf, end);
7112 if (buf + size > end || size <= 0)
7118 GST_WARNING_OBJECT (qtdemux, "have cookie %" GST_FOURCC_FORMAT,
7119 GST_FOURCC_ARGS (type));
7123 buffer = gst_buffer_new_and_alloc (size);
7124 gst_buffer_fill (buffer, 0, buf, size);
7125 stream->buffers = g_slist_append (stream->buffers, buffer);
7126 GST_LOG_OBJECT (qtdemux, "parsing theora header");
7129 buffer = gst_buffer_new_and_alloc (size);
7130 gst_buffer_fill (buffer, 0, buf, size);
7131 stream->buffers = g_slist_append (stream->buffers, buffer);
7132 GST_LOG_OBJECT (qtdemux, "parsing theora comment");
7135 buffer = gst_buffer_new_and_alloc (size);
7136 gst_buffer_fill (buffer, 0, buf, size);
7137 stream->buffers = g_slist_append (stream->buffers, buffer);
7138 GST_LOG_OBJECT (qtdemux, "parsing theora codebook");
7141 GST_WARNING_OBJECT (qtdemux,
7142 "unknown theora cookie %" GST_FOURCC_FORMAT,
7143 GST_FOURCC_ARGS (type));
7152 qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node, const guint8 * buffer,
7156 guint32 node_length = 0;
7157 const QtNodeType *type;
7160 GST_LOG_OBJECT (qtdemux, "qtdemux_parse buffer %p length %u", buffer, length);
7162 if (G_UNLIKELY (length < 8))
7163 goto not_enough_data;
7165 node_length = QT_UINT32 (buffer);
7166 fourcc = QT_FOURCC (buffer + 4);
7168 /* ignore empty nodes */
7169 if (G_UNLIKELY (fourcc == 0 || node_length == 8))
7172 type = qtdemux_type_get (fourcc);
7174 end = buffer + length;
7176 GST_LOG_OBJECT (qtdemux,
7177 "parsing '%" GST_FOURCC_FORMAT "', length=%u, name '%s'",
7178 GST_FOURCC_ARGS (fourcc), node_length, type->name);
7180 if (node_length > length)
7181 goto broken_atom_size;
7183 if (type->flags & QT_FLAG_CONTAINER) {
7184 qtdemux_parse_container (qtdemux, node, buffer + 8, end);
7189 if (node_length < 20) {
7190 GST_LOG_OBJECT (qtdemux, "skipping small stsd box");
7193 GST_DEBUG_OBJECT (qtdemux,
7194 "parsing stsd (sample table, sample description) atom");
7195 /* Skip over 8 byte atom hdr + 1 byte version, 3 bytes flags, 4 byte num_entries */
7196 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
7207 /* also read alac (or whatever) in stead of mp4a in the following,
7208 * since a similar layout is used in other cases as well */
7209 if (fourcc == FOURCC_mp4a)
7211 else if (fourcc == FOURCC_fLaC)
7216 /* There are two things we might encounter here: a true mp4a atom, and
7217 an mp4a entry in an stsd atom. The latter is what we're interested
7218 in, and it looks like an atom, but isn't really one. The true mp4a
7219 atom is short, so we detect it based on length here. */
7220 if (length < min_size) {
7221 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
7222 GST_FOURCC_ARGS (fourcc));
7226 /* 'version' here is the sound sample description version. Types 0 and
7227 1 are documented in the QTFF reference, but type 2 is not: it's
7228 described in Apple header files instead (struct SoundDescriptionV2
7230 version = QT_UINT16 (buffer + 16);
7232 GST_DEBUG_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT " version 0x%08x",
7233 GST_FOURCC_ARGS (fourcc), version);
7235 /* parse any esds descriptors */
7247 GST_WARNING_OBJECT (qtdemux,
7248 "unhandled %" GST_FOURCC_FORMAT " version 0x%08x",
7249 GST_FOURCC_ARGS (fourcc), version);
7254 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
7280 /* codec_data is contained inside these atoms, which all have
7281 * the same format. */
7282 /* video sample description size is 86 bytes without extension.
7283 * node_length have to be bigger than 86 bytes because video sample
7284 * description can include extenstions such as esds, fiel, glbl, etc. */
7285 if (node_length < 86) {
7286 GST_WARNING_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT
7287 " sample description length too short (%u < 86)",
7288 GST_FOURCC_ARGS (fourcc), node_length);
7292 GST_DEBUG_OBJECT (qtdemux, "parsing in %" GST_FOURCC_FORMAT,
7293 GST_FOURCC_ARGS (fourcc));
7295 /* version (2 bytes) : this is set to 0, unless a compressor has changed
7297 * revision level (2 bytes) : must be set to 0. */
7298 version = QT_UINT32 (buffer + 16);
7299 GST_DEBUG_OBJECT (qtdemux, "version %08x", version);
7301 /* compressor name : PASCAL string and informative purposes
7302 * first byte : the number of bytes to be displayed.
7303 * it has to be less than 32 because it is reserved
7304 * space of 32 bytes total including itself. */
7305 str_len = QT_UINT8 (buffer + 50);
7307 GST_DEBUG_OBJECT (qtdemux, "compressorname = %.*s", str_len,
7308 (char *) buffer + 51);
7310 GST_WARNING_OBJECT (qtdemux,
7311 "compressorname length too big (%u > 31)", str_len);
7313 GST_MEMDUMP_OBJECT (qtdemux, "video sample description", buffer,
7315 qtdemux_parse_container (qtdemux, node, buffer + 86, end);
7320 GST_DEBUG_OBJECT (qtdemux, "parsing meta atom");
7321 qtdemux_parse_container (qtdemux, node, buffer + 12, end);
7326 GST_MEMDUMP_OBJECT (qtdemux, "mp4s", buffer, end - buffer);
7327 /* Skip 8 byte header, plus 8 byte version + flags + entry_count */
7328 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
7337 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
7338 GST_FOURCC_ARGS (fourcc));
7342 version = QT_UINT32 (buffer + 12);
7343 GST_DEBUG_OBJECT (qtdemux, "parsing XiTh atom version 0x%08x", version);
7350 GST_DEBUG_OBJECT (qtdemux, "unknown version 0x%08x", version);
7355 if (length < offset) {
7356 GST_WARNING_OBJECT (qtdemux,
7357 "skipping too small %" GST_FOURCC_FORMAT " box",
7358 GST_FOURCC_ARGS (fourcc));
7361 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
7367 qtdemux_parse_container (qtdemux, node, buffer + 0x34, end);
7372 qtdemux_parse_uuid (qtdemux, buffer, end - buffer);
7377 qtdemux_parse_container (qtdemux, node, buffer + 36, end);
7381 if (!strcmp (type->name, "unknown"))
7382 GST_MEMDUMP ("Unknown tag", buffer + 4, end - buffer - 4);
7386 GST_LOG_OBJECT (qtdemux, "parsed '%" GST_FOURCC_FORMAT "'",
7387 GST_FOURCC_ARGS (fourcc));
7393 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
7394 (_("This file is corrupt and cannot be played.")),
7395 ("Not enough data for an atom header, got only %u bytes", length));
7400 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
7401 (_("This file is corrupt and cannot be played.")),
7402 ("Atom '%" GST_FOURCC_FORMAT "' has size of %u bytes, but we have only "
7403 "%u bytes available.", GST_FOURCC_ARGS (fourcc), node_length,
7410 qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc)
7414 guint32 child_fourcc;
7416 for (child = g_node_first_child (node); child;
7417 child = g_node_next_sibling (child)) {
7418 buffer = (guint8 *) child->data;
7420 child_fourcc = QT_FOURCC (buffer + 4);
7422 if (G_UNLIKELY (child_fourcc == fourcc)) {
7430 qtdemux_tree_get_child_by_type_full (GNode * node, guint32 fourcc,
7431 GstByteReader * parser)
7435 guint32 child_fourcc, child_len;
7437 for (child = g_node_first_child (node); child;
7438 child = g_node_next_sibling (child)) {
7439 buffer = (guint8 *) child->data;
7441 child_len = QT_UINT32 (buffer);
7442 child_fourcc = QT_FOURCC (buffer + 4);
7444 if (G_UNLIKELY (child_fourcc == fourcc)) {
7445 if (G_UNLIKELY (child_len < (4 + 4)))
7447 /* FIXME: must verify if atom length < parent atom length */
7448 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
7456 qtdemux_tree_get_sibling_by_type_full (GNode * node, guint32 fourcc,
7457 GstByteReader * parser)
7461 guint32 child_fourcc, child_len;
7463 for (child = g_node_next_sibling (node); child;
7464 child = g_node_next_sibling (child)) {
7465 buffer = (guint8 *) child->data;
7467 child_fourcc = QT_FOURCC (buffer + 4);
7469 if (child_fourcc == fourcc) {
7471 child_len = QT_UINT32 (buffer);
7472 if (G_UNLIKELY (child_len < (4 + 4)))
7474 /* FIXME: must verify if atom length < parent atom length */
7475 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
7484 qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc)
7486 return qtdemux_tree_get_sibling_by_type_full (node, fourcc, NULL);
7490 qtdemux_do_allocation (GstQTDemux * qtdemux, QtDemuxStream * stream)
7492 /* FIXME: This can only reliably work if demuxers have a
7493 * separate streaming thread per srcpad. This should be
7494 * done in a demuxer base class, which integrates parts
7497 * https://bugzilla.gnome.org/show_bug.cgi?id=701856
7502 query = gst_query_new_allocation (stream->caps, FALSE);
7504 if (!gst_pad_peer_query (stream->pad, query)) {
7505 /* not a problem, just debug a little */
7506 GST_DEBUG_OBJECT (qtdemux, "peer ALLOCATION query failed");
7509 if (stream->allocator)
7510 gst_object_unref (stream->allocator);
7512 if (gst_query_get_n_allocation_params (query) > 0) {
7513 /* try the allocator */
7514 gst_query_parse_nth_allocation_param (query, 0, &stream->allocator,
7516 stream->use_allocator = TRUE;
7518 stream->allocator = NULL;
7519 gst_allocation_params_init (&stream->params);
7520 stream->use_allocator = FALSE;
7522 gst_query_unref (query);
7527 gst_qtdemux_configure_protected_caps (GstQTDemux * qtdemux,
7528 QtDemuxStream * stream)
7531 const gchar *selected_system;
7533 g_return_val_if_fail (qtdemux != NULL, FALSE);
7534 g_return_val_if_fail (stream != NULL, FALSE);
7535 g_return_val_if_fail (gst_caps_get_size (stream->caps) == 1, FALSE);
7537 if (stream->protection_scheme_type != FOURCC_cenc) {
7538 GST_ERROR_OBJECT (qtdemux, "unsupported protection scheme");
7541 if (qtdemux->protection_system_ids == NULL) {
7542 GST_ERROR_OBJECT (qtdemux, "stream is protected using cenc, but no "
7543 "cenc protection system information has been found");
7546 g_ptr_array_add (qtdemux->protection_system_ids, NULL);
7547 selected_system = gst_protection_select_system ((const gchar **)
7548 qtdemux->protection_system_ids->pdata);
7549 g_ptr_array_remove_index (qtdemux->protection_system_ids,
7550 qtdemux->protection_system_ids->len - 1);
7551 if (!selected_system) {
7552 GST_ERROR_OBJECT (qtdemux, "stream is protected, but no "
7553 "suitable decryptor element has been found");
7557 s = gst_caps_get_structure (stream->caps, 0);
7558 if (!gst_structure_has_name (s, "application/x-cenc")) {
7559 gst_structure_set (s,
7560 "original-media-type", G_TYPE_STRING, gst_structure_get_name (s),
7561 GST_PROTECTION_SYSTEM_ID_CAPS_FIELD, G_TYPE_STRING, selected_system,
7563 gst_structure_set_name (s, "application/x-cenc");
7569 gst_qtdemux_configure_stream (GstQTDemux * qtdemux, QtDemuxStream * stream)
7571 if (stream->subtype == FOURCC_vide) {
7572 /* fps is calculated base on the duration of the average framerate since
7573 * qt does not have a fixed framerate. */
7574 gboolean fps_available = TRUE;
7576 if ((stream->n_samples == 1) && (stream->first_duration == 0)) {
7581 if (stream->duration == 0 || stream->n_samples < 2) {
7582 stream->fps_n = stream->timescale;
7584 fps_available = FALSE;
7586 GstClockTime avg_duration;
7590 /* duration and n_samples can be updated for fragmented format
7591 * so, framerate of fragmented format is calculated using data in a moof */
7592 if (qtdemux->fragmented && stream->n_samples_moof > 0
7593 && stream->duration_moof > 0) {
7594 n_samples = stream->n_samples_moof;
7595 duration = stream->duration_moof;
7597 n_samples = stream->n_samples;
7598 duration = stream->duration;
7601 /* Calculate a framerate, ignoring the first sample which is sometimes truncated */
7602 /* stream->duration is guint64, timescale, n_samples are guint32 */
7604 gst_util_uint64_scale_round (duration -
7605 stream->first_duration, GST_SECOND,
7606 (guint64) (stream->timescale) * (n_samples - 1));
7608 GST_LOG_OBJECT (qtdemux,
7609 "Calculating avg sample duration based on stream (or moof) duration %"
7611 " minus first sample %u, leaving %d samples gives %"
7612 GST_TIME_FORMAT, duration, stream->first_duration,
7613 n_samples - 1, GST_TIME_ARGS (avg_duration));
7615 gst_video_guess_framerate (avg_duration, &stream->fps_n,
7618 GST_DEBUG_OBJECT (qtdemux,
7619 "Calculating framerate, timescale %u gave fps_n %d fps_d %d",
7620 stream->timescale, stream->fps_n, stream->fps_d);
7625 stream->caps = gst_caps_make_writable (stream->caps);
7627 gst_caps_set_simple (stream->caps,
7628 "width", G_TYPE_INT, stream->width,
7629 "height", G_TYPE_INT, stream->height, NULL);
7631 /* set framerate if calculated framerate is reliable */
7632 if (fps_available) {
7633 gst_caps_set_simple (stream->caps,
7634 "framerate", GST_TYPE_FRACTION, stream->fps_n, stream->fps_d, NULL);
7637 /* calculate pixel-aspect-ratio using display width and height */
7638 GST_DEBUG_OBJECT (qtdemux,
7639 "video size %dx%d, target display size %dx%d", stream->width,
7640 stream->height, stream->display_width, stream->display_height);
7641 /* qt file might have pasp atom */
7642 if (stream->par_w > 0 && stream->par_h > 0) {
7643 GST_DEBUG_OBJECT (qtdemux, "par %d:%d", stream->par_w, stream->par_h);
7644 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
7645 GST_TYPE_FRACTION, stream->par_w, stream->par_h, NULL);
7646 } else if (stream->display_width > 0 && stream->display_height > 0 &&
7647 stream->width > 0 && stream->height > 0) {
7650 /* calculate the pixel aspect ratio using the display and pixel w/h */
7651 n = stream->display_width * stream->height;
7652 d = stream->display_height * stream->width;
7655 GST_DEBUG_OBJECT (qtdemux, "setting PAR to %d/%d", n, d);
7658 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
7659 GST_TYPE_FRACTION, stream->par_w, stream->par_h, NULL);
7662 if (stream->interlace_mode > 0) {
7663 if (stream->interlace_mode == 1) {
7664 gst_caps_set_simple (stream->caps, "interlace-mode", G_TYPE_STRING,
7665 "progressive", NULL);
7666 } else if (stream->interlace_mode == 2) {
7667 gst_caps_set_simple (stream->caps, "interlace-mode", G_TYPE_STRING,
7668 "interleaved", NULL);
7669 if (stream->field_order == 9) {
7670 gst_caps_set_simple (stream->caps, "field-order", G_TYPE_STRING,
7671 "top-field-first", NULL);
7672 } else if (stream->field_order == 14) {
7673 gst_caps_set_simple (stream->caps, "field-order", G_TYPE_STRING,
7674 "bottom-field-first", NULL);
7679 /* Create incomplete colorimetry here if needed */
7680 if (stream->colorimetry.range ||
7681 stream->colorimetry.matrix ||
7682 stream->colorimetry.transfer || stream->colorimetry.primaries) {
7683 gchar *colorimetry =
7684 gst_video_colorimetry_to_string (&stream->colorimetry);
7685 gst_caps_set_simple (stream->caps, "colorimetry", G_TYPE_STRING,
7687 g_free (colorimetry);
7690 if (stream->multiview_mode != GST_VIDEO_MULTIVIEW_MODE_NONE) {
7691 guint par_w = 1, par_h = 1;
7693 if (stream->par_w > 0 && stream->par_h > 0) {
7694 par_w = stream->par_w;
7695 par_h = stream->par_h;
7698 if (gst_video_multiview_guess_half_aspect (stream->multiview_mode,
7699 stream->width, stream->height, par_w, par_h)) {
7700 stream->multiview_flags |= GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT;
7703 gst_caps_set_simple (stream->caps,
7704 "multiview-mode", G_TYPE_STRING,
7705 gst_video_multiview_mode_to_caps_string (stream->multiview_mode),
7706 "multiview-flags", GST_TYPE_VIDEO_MULTIVIEW_FLAGSET,
7707 stream->multiview_flags, GST_FLAG_SET_MASK_EXACT, NULL);
7712 else if (stream->subtype == FOURCC_soun) {
7714 stream->caps = gst_caps_make_writable (stream->caps);
7715 if (stream->rate > 0)
7716 gst_caps_set_simple (stream->caps,
7717 "rate", G_TYPE_INT, (int) stream->rate, NULL);
7718 if (stream->n_channels > 0)
7719 gst_caps_set_simple (stream->caps,
7720 "channels", G_TYPE_INT, stream->n_channels, NULL);
7721 if (stream->n_channels > 2) {
7722 /* FIXME: Need to parse the 'chan' atom to get channel layouts
7723 * correctly; this is just the minimum we can do - assume
7724 * we don't actually have any channel positions. */
7725 gst_caps_set_simple (stream->caps,
7726 "channel-mask", GST_TYPE_BITMASK, G_GUINT64_CONSTANT (0), NULL);
7732 GstCaps *prev_caps = NULL;
7734 GST_PAD_ELEMENT_PRIVATE (stream->pad) = stream;
7735 gst_pad_set_event_function (stream->pad, gst_qtdemux_handle_src_event);
7736 gst_pad_set_query_function (stream->pad, gst_qtdemux_handle_src_query);
7737 gst_pad_set_active (stream->pad, TRUE);
7739 gst_pad_use_fixed_caps (stream->pad);
7741 if (stream->protected) {
7742 if (!gst_qtdemux_configure_protected_caps (qtdemux, stream)) {
7743 GST_ERROR_OBJECT (qtdemux,
7744 "Failed to configure protected stream caps.");
7749 if (stream->new_stream) {
7752 GstStreamFlags stream_flags;
7755 gst_pad_get_sticky_event (qtdemux->sinkpad, GST_EVENT_STREAM_START,
7758 if (gst_event_parse_group_id (event, &qtdemux->group_id))
7759 qtdemux->have_group_id = TRUE;
7761 qtdemux->have_group_id = FALSE;
7762 gst_event_unref (event);
7763 } else if (!qtdemux->have_group_id) {
7764 qtdemux->have_group_id = TRUE;
7765 qtdemux->group_id = gst_util_group_id_next ();
7768 stream->new_stream = FALSE;
7770 gst_pad_create_stream_id_printf (stream->pad,
7771 GST_ELEMENT_CAST (qtdemux), "%03u", stream->track_id);
7772 event = gst_event_new_stream_start (stream_id);
7773 if (qtdemux->have_group_id)
7774 gst_event_set_group_id (event, qtdemux->group_id);
7775 stream_flags = GST_STREAM_FLAG_NONE;
7776 if (stream->disabled)
7777 stream_flags |= GST_STREAM_FLAG_UNSELECT;
7779 stream_flags |= GST_STREAM_FLAG_SPARSE;
7780 gst_event_set_stream_flags (event, stream_flags);
7781 gst_pad_push_event (stream->pad, event);
7785 prev_caps = gst_pad_get_current_caps (stream->pad);
7787 if (!prev_caps || !gst_caps_is_equal_fixed (prev_caps, stream->caps)) {
7788 GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT, stream->caps);
7789 gst_pad_set_caps (stream->pad, stream->caps);
7791 GST_DEBUG_OBJECT (qtdemux, "ignore duplicated caps");
7795 gst_caps_unref (prev_caps);
7796 stream->new_caps = FALSE;
7802 gst_qtdemux_add_stream (GstQTDemux * qtdemux,
7803 QtDemuxStream * stream, GstTagList * list)
7805 gboolean ret = TRUE;
7806 /* consistent default for push based mode */
7807 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
7809 if (stream->subtype == FOURCC_vide) {
7810 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
7813 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
7816 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
7817 gst_object_unref (stream->pad);
7823 qtdemux->n_video_streams++;
7824 } else if (stream->subtype == FOURCC_soun) {
7825 gchar *name = g_strdup_printf ("audio_%u", qtdemux->n_audio_streams);
7828 gst_pad_new_from_static_template (&gst_qtdemux_audiosrc_template, name);
7830 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
7831 gst_object_unref (stream->pad);
7836 qtdemux->n_audio_streams++;
7837 } else if (stream->subtype == FOURCC_strm) {
7838 GST_DEBUG_OBJECT (qtdemux, "stream type, not creating pad");
7839 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
7840 || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt) {
7841 gchar *name = g_strdup_printf ("subtitle_%u", qtdemux->n_sub_streams);
7844 gst_pad_new_from_static_template (&gst_qtdemux_subsrc_template, name);
7846 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
7847 gst_object_unref (stream->pad);
7852 qtdemux->n_sub_streams++;
7853 } else if (stream->caps) {
7854 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
7857 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
7859 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
7860 gst_object_unref (stream->pad);
7865 qtdemux->n_video_streams++;
7867 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
7874 GST_DEBUG_OBJECT (qtdemux, "adding pad %s %p to qtdemux %p",
7875 GST_OBJECT_NAME (stream->pad), stream->pad, qtdemux);
7876 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
7877 gst_flow_combiner_add_pad (qtdemux->flowcombiner, stream->pad);
7879 if (stream->pending_tags)
7880 gst_tag_list_unref (stream->pending_tags);
7881 stream->pending_tags = list;
7883 /* global tags go on each pad anyway */
7884 stream->send_global_tags = TRUE;
7885 /* send upstream GST_EVENT_PROTECTION events that were received before
7886 this source pad was created */
7887 for (l = qtdemux->protection_event_queue.head; l != NULL; l = l->next)
7888 gst_pad_push_event (stream->pad, gst_event_ref (l->data));
7892 gst_tag_list_unref (list);
7896 /* find next atom with @fourcc starting at @offset */
7897 static GstFlowReturn
7898 qtdemux_find_atom (GstQTDemux * qtdemux, guint64 * offset,
7899 guint64 * length, guint32 fourcc)
7905 GST_LOG_OBJECT (qtdemux, "finding fourcc %" GST_FOURCC_FORMAT " at offset %"
7906 G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), *offset);
7912 ret = gst_pad_pull_range (qtdemux->sinkpad, *offset, 16, &buf);
7913 if (G_UNLIKELY (ret != GST_FLOW_OK))
7915 if (G_UNLIKELY (gst_buffer_get_size (buf) != 16)) {
7918 gst_buffer_unref (buf);
7921 gst_buffer_map (buf, &map, GST_MAP_READ);
7922 extract_initial_length_and_fourcc (map.data, 16, length, &lfourcc);
7923 gst_buffer_unmap (buf, &map);
7924 gst_buffer_unref (buf);
7926 if (G_UNLIKELY (*length == 0)) {
7927 GST_DEBUG_OBJECT (qtdemux, "invalid length 0");
7928 ret = GST_FLOW_ERROR;
7932 if (lfourcc == fourcc) {
7933 GST_DEBUG_OBJECT (qtdemux, "found fourcc at offset %" G_GUINT64_FORMAT,
7937 GST_LOG_OBJECT (qtdemux,
7938 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
7939 GST_FOURCC_ARGS (fourcc), *offset);
7948 /* might simply have had last one */
7949 GST_DEBUG_OBJECT (qtdemux, "fourcc not found");
7954 /* should only do something in pull mode */
7955 /* call with OBJECT lock */
7956 static GstFlowReturn
7957 qtdemux_add_fragmented_samples (GstQTDemux * qtdemux)
7959 guint64 length, offset;
7960 GstBuffer *buf = NULL;
7961 GstFlowReturn ret = GST_FLOW_OK;
7962 GstFlowReturn res = GST_FLOW_OK;
7965 offset = qtdemux->moof_offset;
7966 GST_DEBUG_OBJECT (qtdemux, "next moof at offset %" G_GUINT64_FORMAT, offset);
7969 GST_DEBUG_OBJECT (qtdemux, "no next moof");
7970 return GST_FLOW_EOS;
7973 /* best not do pull etc with lock held */
7974 GST_OBJECT_UNLOCK (qtdemux);
7976 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
7977 if (ret != GST_FLOW_OK)
7980 ret = gst_qtdemux_pull_atom (qtdemux, offset, length, &buf);
7981 if (G_UNLIKELY (ret != GST_FLOW_OK))
7983 gst_buffer_map (buf, &map, GST_MAP_READ);
7984 if (!qtdemux_parse_moof (qtdemux, map.data, map.size, offset, NULL)) {
7985 gst_buffer_unmap (buf, &map);
7986 gst_buffer_unref (buf);
7991 gst_buffer_unmap (buf, &map);
7992 gst_buffer_unref (buf);
7996 /* look for next moof */
7997 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
7998 if (G_UNLIKELY (ret != GST_FLOW_OK))
8002 GST_OBJECT_LOCK (qtdemux);
8004 qtdemux->moof_offset = offset;
8010 GST_DEBUG_OBJECT (qtdemux, "failed to parse moof");
8012 res = GST_FLOW_ERROR;
8017 /* maybe upstream temporarily flushing */
8018 if (ret != GST_FLOW_FLUSHING) {
8019 GST_DEBUG_OBJECT (qtdemux, "no next moof");
8022 GST_DEBUG_OBJECT (qtdemux, "upstream WRONG_STATE");
8023 /* resume at current position next time */
8030 /* initialise bytereaders for stbl sub-atoms */
8032 qtdemux_stbl_init (GstQTDemux * qtdemux, QtDemuxStream * stream, GNode * stbl)
8034 stream->stbl_index = -1; /* no samples have yet been parsed */
8035 stream->sample_index = -1;
8037 /* time-to-sample atom */
8038 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stts, &stream->stts))
8041 /* copy atom data into a new buffer for later use */
8042 stream->stts.data = g_memdup (stream->stts.data, stream->stts.size);
8044 /* skip version + flags */
8045 if (!gst_byte_reader_skip (&stream->stts, 1 + 3) ||
8046 !gst_byte_reader_get_uint32_be (&stream->stts, &stream->n_sample_times))
8048 GST_LOG_OBJECT (qtdemux, "%u timestamp blocks", stream->n_sample_times);
8050 /* make sure there's enough data */
8051 if (!qt_atom_parser_has_chunks (&stream->stts, stream->n_sample_times, 8)) {
8052 stream->n_sample_times = gst_byte_reader_get_remaining (&stream->stts) / 8;
8053 GST_LOG_OBJECT (qtdemux, "overriding to %u timestamp blocks",
8054 stream->n_sample_times);
8055 if (!stream->n_sample_times)
8059 /* sync sample atom */
8060 stream->stps_present = FALSE;
8061 if ((stream->stss_present =
8062 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stss,
8063 &stream->stss) ? TRUE : FALSE) == TRUE) {
8064 /* copy atom data into a new buffer for later use */
8065 stream->stss.data = g_memdup (stream->stss.data, stream->stss.size);
8067 /* skip version + flags */
8068 if (!gst_byte_reader_skip (&stream->stss, 1 + 3) ||
8069 !gst_byte_reader_get_uint32_be (&stream->stss, &stream->n_sample_syncs))
8072 if (stream->n_sample_syncs) {
8073 /* make sure there's enough data */
8074 if (!qt_atom_parser_has_chunks (&stream->stss, stream->n_sample_syncs, 4))
8078 /* partial sync sample atom */
8079 if ((stream->stps_present =
8080 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stps,
8081 &stream->stps) ? TRUE : FALSE) == TRUE) {
8082 /* copy atom data into a new buffer for later use */
8083 stream->stps.data = g_memdup (stream->stps.data, stream->stps.size);
8085 /* skip version + flags */
8086 if (!gst_byte_reader_skip (&stream->stps, 1 + 3) ||
8087 !gst_byte_reader_get_uint32_be (&stream->stps,
8088 &stream->n_sample_partial_syncs))
8091 /* if there are no entries, the stss table contains the real
8093 if (stream->n_sample_partial_syncs) {
8094 /* make sure there's enough data */
8095 if (!qt_atom_parser_has_chunks (&stream->stps,
8096 stream->n_sample_partial_syncs, 4))
8103 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsz, &stream->stsz))
8106 /* copy atom data into a new buffer for later use */
8107 stream->stsz.data = g_memdup (stream->stsz.data, stream->stsz.size);
8109 /* skip version + flags */
8110 if (!gst_byte_reader_skip (&stream->stsz, 1 + 3) ||
8111 !gst_byte_reader_get_uint32_be (&stream->stsz, &stream->sample_size))
8114 if (!gst_byte_reader_get_uint32_be (&stream->stsz, &stream->n_samples))
8117 if (!stream->n_samples)
8120 /* sample-to-chunk atom */
8121 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsc, &stream->stsc))
8124 /* copy atom data into a new buffer for later use */
8125 stream->stsc.data = g_memdup (stream->stsc.data, stream->stsc.size);
8127 /* skip version + flags */
8128 if (!gst_byte_reader_skip (&stream->stsc, 1 + 3) ||
8129 !gst_byte_reader_get_uint32_be (&stream->stsc,
8130 &stream->n_samples_per_chunk))
8133 GST_DEBUG_OBJECT (qtdemux, "n_samples_per_chunk %u",
8134 stream->n_samples_per_chunk);
8136 /* make sure there's enough data */
8137 if (!qt_atom_parser_has_chunks (&stream->stsc, stream->n_samples_per_chunk,
8143 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stco, &stream->stco))
8144 stream->co_size = sizeof (guint32);
8145 else if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_co64,
8147 stream->co_size = sizeof (guint64);
8151 /* copy atom data into a new buffer for later use */
8152 stream->stco.data = g_memdup (stream->stco.data, stream->stco.size);
8154 /* skip version + flags */
8155 if (!gst_byte_reader_skip (&stream->stco, 1 + 3))
8158 /* chunks_are_samples == TRUE means treat chunks as samples */
8159 stream->chunks_are_samples = stream->sample_size && !stream->sampled;
8160 if (stream->chunks_are_samples) {
8161 /* treat chunks as samples */
8162 if (!gst_byte_reader_get_uint32_be (&stream->stco, &stream->n_samples))
8165 /* skip number of entries */
8166 if (!gst_byte_reader_skip (&stream->stco, 4))
8169 /* make sure there are enough data in the stsz atom */
8170 if (!stream->sample_size) {
8171 /* different sizes for each sample */
8172 if (!qt_atom_parser_has_chunks (&stream->stsz, stream->n_samples, 4))
8177 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
8178 stream->n_samples, (guint) sizeof (QtDemuxSample),
8179 stream->n_samples * sizeof (QtDemuxSample) / (1024.0 * 1024.0));
8181 if (stream->n_samples >=
8182 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample)) {
8183 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
8184 "be larger than %uMB (broken file?)", stream->n_samples,
8185 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
8189 g_assert (stream->samples == NULL);
8190 stream->samples = g_try_new0 (QtDemuxSample, stream->n_samples);
8191 if (!stream->samples) {
8192 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
8197 /* composition time-to-sample */
8198 if ((stream->ctts_present =
8199 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_ctts,
8200 &stream->ctts) ? TRUE : FALSE) == TRUE) {
8201 GstByteReader cslg = GST_BYTE_READER_INIT (NULL, 0);
8203 /* copy atom data into a new buffer for later use */
8204 stream->ctts.data = g_memdup (stream->ctts.data, stream->ctts.size);
8206 /* skip version + flags */
8207 if (!gst_byte_reader_skip (&stream->ctts, 1 + 3)
8208 || !gst_byte_reader_get_uint32_be (&stream->ctts,
8209 &stream->n_composition_times))
8212 /* make sure there's enough data */
8213 if (!qt_atom_parser_has_chunks (&stream->ctts, stream->n_composition_times,
8217 /* This is optional, if missing we iterate the ctts */
8218 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_cslg, &cslg)) {
8219 if (!gst_byte_reader_skip (&cslg, 1 + 3)
8220 || !gst_byte_reader_get_uint32_be (&cslg, &stream->cslg_shift)) {
8221 g_free ((gpointer) cslg.data);
8225 gint32 cslg_least = 0;
8226 guint num_entries, pos;
8229 pos = gst_byte_reader_get_pos (&stream->ctts);
8230 num_entries = stream->n_composition_times;
8232 stream->cslg_shift = 0;
8234 for (i = 0; i < num_entries; i++) {
8237 gst_byte_reader_skip_unchecked (&stream->ctts, 4);
8238 offset = gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
8240 if (offset < cslg_least)
8241 cslg_least = offset;
8245 stream->cslg_shift = ABS (cslg_least);
8247 stream->cslg_shift = 0;
8249 /* reset the reader so we can generate sample table */
8250 gst_byte_reader_set_pos (&stream->ctts, pos);
8253 /* Ensure the cslg_shift value is consistent so we can use it
8254 * unconditionnally to produce TS and Segment */
8255 stream->cslg_shift = 0;
8262 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8263 (_("This file is corrupt and cannot be played.")), (NULL));
8268 gst_qtdemux_stbl_free (stream);
8269 if (!qtdemux->fragmented) {
8270 /* not quite good */
8271 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
8274 /* may pick up samples elsewhere */
8280 /* collect samples from the next sample to be parsed up to sample @n for @stream
8281 * by reading the info from @stbl
8283 * This code can be executed from both the streaming thread and the seeking
8284 * thread so it takes the object lock to protect itself
8287 qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream, guint32 n)
8290 QtDemuxSample *samples, *first, *cur, *last;
8291 guint32 n_samples_per_chunk;
8294 GST_LOG_OBJECT (qtdemux, "parsing samples for stream fourcc %"
8295 GST_FOURCC_FORMAT ", pad %s", GST_FOURCC_ARGS (stream->fourcc),
8296 stream->pad ? GST_PAD_NAME (stream->pad) : "(NULL)");
8298 n_samples = stream->n_samples;
8301 goto out_of_samples;
8303 GST_OBJECT_LOCK (qtdemux);
8304 if (n <= stream->stbl_index)
8305 goto already_parsed;
8307 GST_DEBUG_OBJECT (qtdemux, "parsing up to sample %u", n);
8309 if (!stream->stsz.data) {
8310 /* so we already parsed and passed all the moov samples;
8311 * onto fragmented ones */
8312 g_assert (qtdemux->fragmented);
8316 /* pointer to the sample table */
8317 samples = stream->samples;
8319 /* starts from -1, moves to the next sample index to parse */
8320 stream->stbl_index++;
8322 /* keep track of the first and last sample to fill */
8323 first = &samples[stream->stbl_index];
8326 if (!stream->chunks_are_samples) {
8327 /* set the sample sizes */
8328 if (stream->sample_size == 0) {
8329 /* different sizes for each sample */
8330 for (cur = first; cur <= last; cur++) {
8331 cur->size = gst_byte_reader_get_uint32_be_unchecked (&stream->stsz);
8332 GST_LOG_OBJECT (qtdemux, "sample %d has size %u",
8333 (guint) (cur - samples), cur->size);
8336 /* samples have the same size */
8337 GST_LOG_OBJECT (qtdemux, "all samples have size %u", stream->sample_size);
8338 for (cur = first; cur <= last; cur++)
8339 cur->size = stream->sample_size;
8343 n_samples_per_chunk = stream->n_samples_per_chunk;
8346 for (i = stream->stsc_index; i < n_samples_per_chunk; i++) {
8349 if (stream->stsc_chunk_index >= stream->last_chunk
8350 || stream->stsc_chunk_index < stream->first_chunk) {
8351 stream->first_chunk =
8352 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
8353 stream->samples_per_chunk =
8354 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
8355 gst_byte_reader_skip_unchecked (&stream->stsc, 4);
8357 /* chunk numbers are counted from 1 it seems */
8358 if (G_UNLIKELY (stream->first_chunk == 0))
8361 --stream->first_chunk;
8363 /* the last chunk of each entry is calculated by taking the first chunk
8364 * of the next entry; except if there is no next, where we fake it with
8366 if (G_UNLIKELY (i == (stream->n_samples_per_chunk - 1))) {
8367 stream->last_chunk = G_MAXUINT32;
8369 stream->last_chunk =
8370 gst_byte_reader_peek_uint32_be_unchecked (&stream->stsc);
8371 if (G_UNLIKELY (stream->last_chunk == 0))
8374 --stream->last_chunk;
8377 GST_LOG_OBJECT (qtdemux,
8378 "entry %d has first_chunk %d, last_chunk %d, samples_per_chunk %d", i,
8379 stream->first_chunk, stream->last_chunk, stream->samples_per_chunk);
8381 if (G_UNLIKELY (stream->last_chunk < stream->first_chunk))
8384 if (stream->last_chunk != G_MAXUINT32) {
8385 if (!qt_atom_parser_peek_sub (&stream->stco,
8386 stream->first_chunk * stream->co_size,
8387 (stream->last_chunk - stream->first_chunk) * stream->co_size,
8392 stream->co_chunk = stream->stco;
8393 if (!gst_byte_reader_skip (&stream->co_chunk,
8394 stream->first_chunk * stream->co_size))
8398 stream->stsc_chunk_index = stream->first_chunk;
8401 last_chunk = stream->last_chunk;
8403 if (stream->chunks_are_samples) {
8404 cur = &samples[stream->stsc_chunk_index];
8406 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
8409 stream->stsc_chunk_index = j;
8414 qt_atom_parser_get_offset_unchecked (&stream->co_chunk,
8417 GST_LOG_OBJECT (qtdemux, "Created entry %d with offset "
8418 "%" G_GUINT64_FORMAT, j, cur->offset);
8420 if (stream->samples_per_frame * stream->bytes_per_frame) {
8422 (stream->samples_per_chunk * stream->n_channels) /
8423 stream->samples_per_frame * stream->bytes_per_frame;
8425 cur->size = stream->samples_per_chunk;
8428 GST_DEBUG_OBJECT (qtdemux,
8429 "keyframe sample %d: timestamp %" GST_TIME_FORMAT ", size %u",
8430 j, GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream,
8431 stream->stco_sample_index)), cur->size);
8433 cur->timestamp = stream->stco_sample_index;
8434 cur->duration = stream->samples_per_chunk;
8435 cur->keyframe = TRUE;
8438 stream->stco_sample_index += stream->samples_per_chunk;
8440 stream->stsc_chunk_index = j;
8442 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
8443 guint32 samples_per_chunk;
8444 guint64 chunk_offset;
8446 if (!stream->stsc_sample_index
8447 && !qt_atom_parser_get_offset (&stream->co_chunk, stream->co_size,
8448 &stream->chunk_offset))
8451 samples_per_chunk = stream->samples_per_chunk;
8452 chunk_offset = stream->chunk_offset;
8454 for (k = stream->stsc_sample_index; k < samples_per_chunk; k++) {
8455 GST_LOG_OBJECT (qtdemux, "creating entry %d with offset %"
8456 G_GUINT64_FORMAT " and size %d",
8457 (guint) (cur - samples), chunk_offset, cur->size);
8459 cur->offset = chunk_offset;
8460 chunk_offset += cur->size;
8463 if (G_UNLIKELY (cur > last)) {
8465 stream->stsc_sample_index = k + 1;
8466 stream->chunk_offset = chunk_offset;
8467 stream->stsc_chunk_index = j;
8471 stream->stsc_sample_index = 0;
8473 stream->stsc_chunk_index = j;
8475 stream->stsc_index++;
8478 if (stream->chunks_are_samples)
8482 guint32 n_sample_times;
8484 n_sample_times = stream->n_sample_times;
8487 for (i = stream->stts_index; i < n_sample_times; i++) {
8488 guint32 stts_samples;
8489 gint32 stts_duration;
8492 if (stream->stts_sample_index >= stream->stts_samples
8493 || !stream->stts_sample_index) {
8495 stream->stts_samples =
8496 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
8497 stream->stts_duration =
8498 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
8500 GST_LOG_OBJECT (qtdemux, "block %d, %u timestamps, duration %u",
8501 i, stream->stts_samples, stream->stts_duration);
8503 stream->stts_sample_index = 0;
8506 stts_samples = stream->stts_samples;
8507 stts_duration = stream->stts_duration;
8508 stts_time = stream->stts_time;
8510 for (j = stream->stts_sample_index; j < stts_samples; j++) {
8511 GST_DEBUG_OBJECT (qtdemux,
8512 "sample %d: index %d, timestamp %" GST_TIME_FORMAT,
8513 (guint) (cur - samples), j,
8514 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stts_time)));
8516 cur->timestamp = stts_time;
8517 cur->duration = stts_duration;
8519 /* avoid 32-bit wrap-around,
8520 * but still mind possible 'negative' duration */
8521 stts_time += (gint64) stts_duration;
8524 if (G_UNLIKELY (cur > last)) {
8526 stream->stts_time = stts_time;
8527 stream->stts_sample_index = j + 1;
8531 stream->stts_sample_index = 0;
8532 stream->stts_time = stts_time;
8533 stream->stts_index++;
8535 /* fill up empty timestamps with the last timestamp, this can happen when
8536 * the last samples do not decode and so we don't have timestamps for them.
8537 * We however look at the last timestamp to estimate the track length so we
8538 * need something in here. */
8539 for (; cur < last; cur++) {
8540 GST_DEBUG_OBJECT (qtdemux,
8541 "fill sample %d: timestamp %" GST_TIME_FORMAT,
8542 (guint) (cur - samples),
8543 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stream->stts_time)));
8544 cur->timestamp = stream->stts_time;
8550 /* sample sync, can be NULL */
8551 if (stream->stss_present == TRUE) {
8552 guint32 n_sample_syncs;
8554 n_sample_syncs = stream->n_sample_syncs;
8556 if (!n_sample_syncs) {
8557 GST_DEBUG_OBJECT (qtdemux, "all samples are keyframes");
8558 stream->all_keyframe = TRUE;
8560 for (i = stream->stss_index; i < n_sample_syncs; i++) {
8561 /* note that the first sample is index 1, not 0 */
8564 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stss);
8566 if (G_LIKELY (index > 0 && index <= n_samples)) {
8568 samples[index].keyframe = TRUE;
8569 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
8570 /* and exit if we have enough samples */
8571 if (G_UNLIKELY (index >= n)) {
8578 stream->stss_index = i;
8581 /* stps marks partial sync frames like open GOP I-Frames */
8582 if (stream->stps_present == TRUE) {
8583 guint32 n_sample_partial_syncs;
8585 n_sample_partial_syncs = stream->n_sample_partial_syncs;
8587 /* if there are no entries, the stss table contains the real
8589 if (n_sample_partial_syncs) {
8590 for (i = stream->stps_index; i < n_sample_partial_syncs; i++) {
8591 /* note that the first sample is index 1, not 0 */
8594 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stps);
8596 if (G_LIKELY (index > 0 && index <= n_samples)) {
8598 samples[index].keyframe = TRUE;
8599 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
8600 /* and exit if we have enough samples */
8601 if (G_UNLIKELY (index >= n)) {
8608 stream->stps_index = i;
8612 /* no stss, all samples are keyframes */
8613 stream->all_keyframe = TRUE;
8614 GST_DEBUG_OBJECT (qtdemux, "setting all keyframes");
8619 /* composition time to sample */
8620 if (stream->ctts_present == TRUE) {
8621 guint32 n_composition_times;
8623 gint32 ctts_soffset;
8625 /* Fill in the pts_offsets */
8627 n_composition_times = stream->n_composition_times;
8629 for (i = stream->ctts_index; i < n_composition_times; i++) {
8630 if (stream->ctts_sample_index >= stream->ctts_count
8631 || !stream->ctts_sample_index) {
8632 stream->ctts_count =
8633 gst_byte_reader_get_uint32_be_unchecked (&stream->ctts);
8634 stream->ctts_soffset =
8635 gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
8636 stream->ctts_sample_index = 0;
8639 ctts_count = stream->ctts_count;
8640 ctts_soffset = stream->ctts_soffset;
8642 for (j = stream->ctts_sample_index; j < ctts_count; j++) {
8643 cur->pts_offset = ctts_soffset;
8646 if (G_UNLIKELY (cur > last)) {
8648 stream->ctts_sample_index = j + 1;
8652 stream->ctts_sample_index = 0;
8653 stream->ctts_index++;
8657 stream->stbl_index = n;
8658 /* if index has been completely parsed, free data that is no-longer needed */
8659 if (n + 1 == stream->n_samples) {
8660 gst_qtdemux_stbl_free (stream);
8661 GST_DEBUG_OBJECT (qtdemux, "parsed all available samples;");
8662 if (qtdemux->pullbased) {
8663 GST_DEBUG_OBJECT (qtdemux, "checking for more samples");
8664 while (n + 1 == stream->n_samples)
8665 if (qtdemux_add_fragmented_samples (qtdemux) != GST_FLOW_OK)
8669 GST_OBJECT_UNLOCK (qtdemux);
8676 GST_LOG_OBJECT (qtdemux,
8677 "Tried to parse up to sample %u but this sample has already been parsed",
8679 /* if fragmented, there may be more */
8680 if (qtdemux->fragmented && n == stream->stbl_index)
8682 GST_OBJECT_UNLOCK (qtdemux);
8688 GST_LOG_OBJECT (qtdemux,
8689 "Tried to parse up to sample %u but there are only %u samples", n + 1,
8691 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8692 (_("This file is corrupt and cannot be played.")), (NULL));
8697 GST_OBJECT_UNLOCK (qtdemux);
8698 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8699 (_("This file is corrupt and cannot be played.")), (NULL));
8704 /* collect all segment info for @stream.
8707 qtdemux_parse_segments (GstQTDemux * qtdemux, QtDemuxStream * stream,
8711 /* accept edts if they contain gaps at start and there is only
8712 * one media segment */
8713 gboolean allow_pushbased_edts = TRUE;
8714 gint media_segments_count = 0;
8716 /* parse and prepare segment info from the edit list */
8717 GST_DEBUG_OBJECT (qtdemux, "looking for edit list container");
8718 stream->n_segments = 0;
8719 stream->segments = NULL;
8720 if ((edts = qtdemux_tree_get_child_by_type (trak, FOURCC_edts))) {
8723 gint i, count, entry_size;
8726 const guint8 *buffer;
8730 GST_DEBUG_OBJECT (qtdemux, "looking for edit list");
8731 if (!(elst = qtdemux_tree_get_child_by_type (edts, FOURCC_elst)))
8734 buffer = elst->data;
8736 size = QT_UINT32 (buffer);
8737 /* version, flags, n_segments */
8739 GST_WARNING_OBJECT (qtdemux, "Invalid edit list");
8742 version = QT_UINT8 (buffer + 8);
8743 entry_size = (version == 1) ? 20 : 12;
8745 n_segments = QT_UINT32 (buffer + 12);
8747 if (size < 16 + n_segments * entry_size) {
8748 GST_WARNING_OBJECT (qtdemux, "Invalid edit list");
8752 /* we might allocate a bit too much, at least allocate 1 segment */
8753 stream->segments = g_new (QtDemuxSegment, MAX (n_segments, 1));
8755 /* segments always start from 0 */
8760 for (i = 0; i < n_segments; i++) {
8763 gboolean time_valid = TRUE;
8764 QtDemuxSegment *segment;
8766 GstClockTime media_start = GST_CLOCK_TIME_NONE;
8769 media_time = QT_UINT64 (buffer + 8);
8770 duration = QT_UINT64 (buffer);
8771 if (media_time == G_MAXUINT64)
8774 media_time = QT_UINT32 (buffer + 4);
8775 duration = QT_UINT32 (buffer);
8776 if (media_time == G_MAXUINT32)
8781 media_start = QTSTREAMTIME_TO_GSTTIME (stream, media_time);
8783 segment = &stream->segments[count++];
8785 /* time and duration expressed in global timescale */
8786 segment->time = stime;
8787 /* add non scaled values so we don't cause roundoff errors */
8788 if (duration || media_start == GST_CLOCK_TIME_NONE) {
8790 stime = QTTIME_TO_GSTTIME (qtdemux, time);
8791 segment->duration = stime - segment->time;
8793 /* zero duration does not imply media_start == media_stop
8794 * but, only specify media_start.*/
8795 stime = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
8796 if (GST_CLOCK_TIME_IS_VALID (stime) && time_valid
8797 && stime >= media_start) {
8798 segment->duration = stime - media_start;
8800 segment->duration = GST_CLOCK_TIME_NONE;
8803 segment->stop_time = stime;
8805 segment->trak_media_start = media_time;
8806 /* media_time expressed in stream timescale */
8808 segment->media_start = media_start;
8809 segment->media_stop = segment->media_start + segment->duration;
8810 media_segments_count++;
8812 segment->media_start = GST_CLOCK_TIME_NONE;
8813 segment->media_stop = GST_CLOCK_TIME_NONE;
8815 rate_int = QT_UINT32 (buffer + ((version == 1) ? 16 : 8));
8817 if (rate_int <= 1) {
8818 /* 0 is not allowed, some programs write 1 instead of the floating point
8820 GST_WARNING_OBJECT (qtdemux, "found suspicious rate %" G_GUINT32_FORMAT,
8824 segment->rate = rate_int / 65536.0;
8827 GST_DEBUG_OBJECT (qtdemux, "created segment %d time %" GST_TIME_FORMAT
8828 ", duration %" GST_TIME_FORMAT ", media_start %" GST_TIME_FORMAT
8829 " (%" G_GUINT64_FORMAT ") , media_stop %" GST_TIME_FORMAT
8830 " stop_time %" GST_TIME_FORMAT " rate %g, (%d) timescale %u",
8831 i, GST_TIME_ARGS (segment->time),
8832 GST_TIME_ARGS (segment->duration),
8833 GST_TIME_ARGS (segment->media_start), media_time,
8834 GST_TIME_ARGS (segment->media_stop),
8835 GST_TIME_ARGS (segment->stop_time), segment->rate, rate_int,
8837 if (segment->stop_time > qtdemux->segment.stop) {
8838 GST_WARNING_OBJECT (qtdemux, "Segment %d "
8839 " extends to %" GST_TIME_FORMAT
8840 " past the end of the file duration %" GST_TIME_FORMAT
8841 " it will be truncated", i, GST_TIME_ARGS (segment->stop_time),
8842 GST_TIME_ARGS (qtdemux->segment.stop));
8843 qtdemux->segment.stop = segment->stop_time;
8846 buffer += entry_size;
8848 GST_DEBUG_OBJECT (qtdemux, "found %d segments", count);
8849 stream->n_segments = count;
8850 if (media_segments_count != 1)
8851 allow_pushbased_edts = FALSE;
8855 /* push based does not handle segments, so act accordingly here,
8856 * and warn if applicable */
8857 if (!qtdemux->pullbased && !allow_pushbased_edts) {
8858 GST_WARNING_OBJECT (qtdemux, "streaming; discarding edit list segments");
8859 /* remove and use default one below, we stream like it anyway */
8860 g_free (stream->segments);
8861 stream->segments = NULL;
8862 stream->n_segments = 0;
8865 /* no segments, create one to play the complete trak */
8866 if (stream->n_segments == 0) {
8867 GstClockTime stream_duration =
8868 QTSTREAMTIME_TO_GSTTIME (stream, stream->duration);
8870 if (stream->segments == NULL)
8871 stream->segments = g_new (QtDemuxSegment, 1);
8873 /* represent unknown our way */
8874 if (stream_duration == 0)
8875 stream_duration = GST_CLOCK_TIME_NONE;
8877 stream->segments[0].time = 0;
8878 stream->segments[0].stop_time = stream_duration;
8879 stream->segments[0].duration = stream_duration;
8880 stream->segments[0].media_start = 0;
8881 stream->segments[0].media_stop = stream_duration;
8882 stream->segments[0].rate = 1.0;
8883 stream->segments[0].trak_media_start = 0;
8885 GST_DEBUG_OBJECT (qtdemux, "created dummy segment %" GST_TIME_FORMAT,
8886 GST_TIME_ARGS (stream_duration));
8887 stream->n_segments = 1;
8888 stream->dummy_segment = TRUE;
8890 GST_DEBUG_OBJECT (qtdemux, "using %d segments", stream->n_segments);
8896 * Parses the stsd atom of a svq3 trak looking for
8897 * the SMI and gama atoms.
8900 qtdemux_parse_svq3_stsd_data (GstQTDemux * qtdemux, GNode * stsd,
8901 guint8 ** gamma, GstBuffer ** seqh)
8903 guint8 *_gamma = NULL;
8904 GstBuffer *_seqh = NULL;
8905 guint8 *stsd_data = stsd->data;
8906 guint32 length = QT_UINT32 (stsd_data);
8910 GST_WARNING_OBJECT (qtdemux, "stsd too short");
8916 version = QT_UINT16 (stsd_data);
8921 while (length > 8) {
8922 guint32 fourcc, size;
8924 size = QT_UINT32 (stsd_data);
8925 fourcc = QT_FOURCC (stsd_data + 4);
8926 data = stsd_data + 8;
8929 GST_WARNING_OBJECT (qtdemux, "Atom of size 0 found, aborting "
8930 "svq3 atom parsing");
8939 GST_WARNING_OBJECT (qtdemux, "Unexpected size %" G_GUINT32_FORMAT
8940 " for gama atom, expected 12", size);
8945 if (size > 16 && QT_FOURCC (data) == FOURCC_SEQH) {
8947 if (_seqh != NULL) {
8948 GST_WARNING_OBJECT (qtdemux, "Unexpected second SEQH SMI atom "
8949 " found, ignoring");
8951 seqh_size = QT_UINT32 (data + 4);
8952 if (seqh_size > 0) {
8953 _seqh = gst_buffer_new_and_alloc (seqh_size);
8954 gst_buffer_fill (_seqh, 0, data + 8, seqh_size);
8961 GST_WARNING_OBJECT (qtdemux, "Unhandled atom %" GST_FOURCC_FORMAT
8962 " in SVQ3 entry in stsd atom", GST_FOURCC_ARGS (fourcc));
8966 if (size <= length) {
8972 GST_WARNING_OBJECT (qtdemux, "SVQ3 entry too short in stsd atom");
8975 GST_WARNING_OBJECT (qtdemux, "Unexpected version for SVQ3 entry %"
8976 G_GUINT16_FORMAT, version);
8987 gst_buffer_unref (_seqh);
8992 qtdemux_get_rtsp_uri_from_hndl (GstQTDemux * qtdemux, GNode * minf)
8999 * Get 'dinf', to get its child 'dref', that might contain a 'hndl'
9000 * atom that might contain a 'data' atom with the rtsp uri.
9001 * This case was reported in bug #597497, some info about
9002 * the hndl atom can be found in TN1195
9004 dinf = qtdemux_tree_get_child_by_type (minf, FOURCC_dinf);
9005 GST_DEBUG_OBJECT (qtdemux, "Trying to obtain rtsp URI for stream trak");
9008 guint32 dref_num_entries = 0;
9009 if (qtdemux_tree_get_child_by_type_full (dinf, FOURCC_dref, &dref) &&
9010 gst_byte_reader_skip (&dref, 4) &&
9011 gst_byte_reader_get_uint32_be (&dref, &dref_num_entries)) {
9014 /* search dref entries for hndl atom */
9015 for (i = 0; i < dref_num_entries; i++) {
9016 guint32 size = 0, type;
9017 guint8 string_len = 0;
9018 if (gst_byte_reader_get_uint32_be (&dref, &size) &&
9019 qt_atom_parser_get_fourcc (&dref, &type)) {
9020 if (type == FOURCC_hndl) {
9021 GST_DEBUG_OBJECT (qtdemux, "Found hndl atom");
9023 /* skip data reference handle bytes and the
9024 * following pascal string and some extra 4
9025 * bytes I have no idea what are */
9026 if (!gst_byte_reader_skip (&dref, 4) ||
9027 !gst_byte_reader_get_uint8 (&dref, &string_len) ||
9028 !gst_byte_reader_skip (&dref, string_len + 4)) {
9029 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl atom");
9033 /* iterate over the atoms to find the data atom */
9034 while (gst_byte_reader_get_remaining (&dref) >= 8) {
9038 if (gst_byte_reader_get_uint32_be (&dref, &atom_size) &&
9039 qt_atom_parser_get_fourcc (&dref, &atom_type)) {
9040 if (atom_type == FOURCC_data) {
9041 const guint8 *uri_aux = NULL;
9043 /* found the data atom that might contain the rtsp uri */
9044 GST_DEBUG_OBJECT (qtdemux, "Found data atom inside "
9045 "hndl atom, interpreting it as an URI");
9046 if (gst_byte_reader_peek_data (&dref, atom_size - 8,
9048 if (g_strstr_len ((gchar *) uri_aux, 7, "rtsp://") != NULL)
9049 uri = g_strndup ((gchar *) uri_aux, atom_size - 8);
9051 GST_WARNING_OBJECT (qtdemux, "Data atom in hndl atom "
9052 "didn't contain a rtsp address");
9054 GST_WARNING_OBJECT (qtdemux, "Failed to get the data "
9059 /* skipping to the next entry */
9060 if (!gst_byte_reader_skip (&dref, atom_size - 8))
9063 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl child "
9070 /* skip to the next entry */
9071 if (!gst_byte_reader_skip (&dref, size - 8))
9074 GST_WARNING_OBJECT (qtdemux, "Error parsing dref atom");
9077 GST_DEBUG_OBJECT (qtdemux, "Finished parsing dref atom");
9083 #define AMR_NB_ALL_MODES 0x81ff
9084 #define AMR_WB_ALL_MODES 0x83ff
9086 qtdemux_parse_amr_bitrate (GstBuffer * buf, gboolean wb)
9088 /* The 'damr' atom is of the form:
9090 * | vendor | decoder_ver | mode_set | mode_change_period | frames/sample |
9091 * 32 b 8 b 16 b 8 b 8 b
9093 * The highest set bit of the first 7 (AMR-NB) or 8 (AMR-WB) bits of mode_set
9094 * represents the highest mode used in the stream (and thus the maximum
9095 * bitrate), with a couple of special cases as seen below.
9098 /* Map of frame type ID -> bitrate */
9099 static const guint nb_bitrates[] = {
9100 4750, 5150, 5900, 6700, 7400, 7950, 10200, 12200
9102 static const guint wb_bitrates[] = {
9103 6600, 8850, 12650, 14250, 15850, 18250, 19850, 23050, 23850
9109 gst_buffer_map (buf, &map, GST_MAP_READ);
9111 if (map.size != 0x11) {
9112 GST_DEBUG ("Atom should have size 0x11, not %" G_GSIZE_FORMAT, map.size);
9116 if (QT_FOURCC (map.data + 4) != FOURCC_damr) {
9117 GST_DEBUG ("Unknown atom in %" GST_FOURCC_FORMAT,
9118 GST_FOURCC_ARGS (QT_UINT32 (map.data + 4)));
9122 mode_set = QT_UINT16 (map.data + 13);
9124 if (mode_set == (wb ? AMR_WB_ALL_MODES : AMR_NB_ALL_MODES))
9125 max_mode = 7 + (wb ? 1 : 0);
9127 /* AMR-NB modes fo from 0-7, and AMR-WB modes go from 0-8 */
9128 max_mode = g_bit_nth_msf ((gulong) mode_set & (wb ? 0x1ff : 0xff), -1);
9130 if (max_mode == -1) {
9131 GST_DEBUG ("No mode indication was found (mode set) = %x",
9136 gst_buffer_unmap (buf, &map);
9137 return wb ? wb_bitrates[max_mode] : nb_bitrates[max_mode];
9140 gst_buffer_unmap (buf, &map);
9145 qtdemux_parse_transformation_matrix (GstQTDemux * qtdemux,
9146 GstByteReader * reader, guint32 * matrix, const gchar * atom)
9149 * 9 values of 32 bits (fixed point 16.16, except 2 5 and 8 that are 2.30)
9155 if (gst_byte_reader_get_remaining (reader) < 36)
9158 matrix[0] = gst_byte_reader_get_uint32_be_unchecked (reader);
9159 matrix[1] = gst_byte_reader_get_uint32_be_unchecked (reader);
9160 matrix[2] = gst_byte_reader_get_uint32_be_unchecked (reader);
9161 matrix[3] = gst_byte_reader_get_uint32_be_unchecked (reader);
9162 matrix[4] = gst_byte_reader_get_uint32_be_unchecked (reader);
9163 matrix[5] = gst_byte_reader_get_uint32_be_unchecked (reader);
9164 matrix[6] = gst_byte_reader_get_uint32_be_unchecked (reader);
9165 matrix[7] = gst_byte_reader_get_uint32_be_unchecked (reader);
9166 matrix[8] = gst_byte_reader_get_uint32_be_unchecked (reader);
9168 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix from atom %s", atom);
9169 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[0] >> 16,
9170 matrix[0] & 0xFFFF, matrix[1] >> 16, matrix[1] & 0xFF, matrix[2] >> 16,
9172 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[3] >> 16,
9173 matrix[3] & 0xFFFF, matrix[4] >> 16, matrix[4] & 0xFF, matrix[5] >> 16,
9175 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[6] >> 16,
9176 matrix[6] & 0xFFFF, matrix[7] >> 16, matrix[7] & 0xFF, matrix[8] >> 16,
9183 qtdemux_inspect_transformation_matrix (GstQTDemux * qtdemux,
9184 QtDemuxStream * stream, guint32 * matrix, GstTagList ** taglist)
9191 * This macro will only compare value abdegh, it expects cfi to have already
9194 #define QTCHECK_MATRIX(m,a,b,d,e) ((m)[0] == (a << 16) && (m)[1] == (b << 16) && \
9195 (m)[3] == (d << 16) && (m)[4] == (e << 16))
9197 /* only handle the cases where the last column has standard values */
9198 if (matrix[2] == 0 && matrix[5] == 0 && matrix[8] == 1 << 30) {
9199 const gchar *rotation_tag = NULL;
9201 /* no rotation needed */
9202 if (QTCHECK_MATRIX (matrix, 1, 0, 0, 1)) {
9204 } else if (QTCHECK_MATRIX (matrix, 0, 1, G_MAXUINT16, 0)) {
9205 rotation_tag = "rotate-90";
9206 } else if (QTCHECK_MATRIX (matrix, G_MAXUINT16, 0, 0, G_MAXUINT16)) {
9207 rotation_tag = "rotate-180";
9208 } else if (QTCHECK_MATRIX (matrix, 0, G_MAXUINT16, 1, 0)) {
9209 rotation_tag = "rotate-270";
9211 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
9214 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix rotation %s",
9216 if (rotation_tag != NULL) {
9217 if (*taglist == NULL)
9218 *taglist = gst_tag_list_new_empty ();
9219 gst_tag_list_add (*taglist, GST_TAG_MERGE_REPLACE,
9220 GST_TAG_IMAGE_ORIENTATION, rotation_tag, NULL);
9223 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
9227 /* Parses the boxes defined in ISO/IEC 14496-12 that enable support for
9228 * protected streams (sinf, frma, schm and schi); if the protection scheme is
9229 * Common Encryption (cenc), the function will also parse the tenc box (defined
9230 * in ISO/IEC 23001-7). @container points to the node that contains these boxes
9231 * (typically an enc[v|a|t|s] sample entry); the function will set
9232 * @original_fmt to the fourcc of the original unencrypted stream format.
9233 * Returns TRUE if successful; FALSE otherwise. */
9235 qtdemux_parse_protection_scheme_info (GstQTDemux * qtdemux,
9236 QtDemuxStream * stream, GNode * container, guint32 * original_fmt)
9243 g_return_val_if_fail (qtdemux != NULL, FALSE);
9244 g_return_val_if_fail (stream != NULL, FALSE);
9245 g_return_val_if_fail (container != NULL, FALSE);
9246 g_return_val_if_fail (original_fmt != NULL, FALSE);
9248 sinf = qtdemux_tree_get_child_by_type (container, FOURCC_sinf);
9249 if (G_UNLIKELY (!sinf)) {
9250 if (stream->protection_scheme_type == FOURCC_cenc) {
9251 GST_ERROR_OBJECT (qtdemux, "sinf box does not contain schi box, which is "
9252 "mandatory for Common Encryption");
9258 frma = qtdemux_tree_get_child_by_type (sinf, FOURCC_frma);
9259 if (G_UNLIKELY (!frma)) {
9260 GST_ERROR_OBJECT (qtdemux, "sinf box does not contain mandatory frma box");
9264 *original_fmt = QT_FOURCC ((const guint8 *) frma->data + 8);
9265 GST_DEBUG_OBJECT (qtdemux, "original stream format: '%" GST_FOURCC_FORMAT "'",
9266 GST_FOURCC_ARGS (*original_fmt));
9268 schm = qtdemux_tree_get_child_by_type (sinf, FOURCC_schm);
9270 GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schm box");
9273 stream->protection_scheme_type = QT_FOURCC ((const guint8 *) schm->data + 12);
9274 stream->protection_scheme_version =
9275 QT_UINT32 ((const guint8 *) schm->data + 16);
9277 GST_DEBUG_OBJECT (qtdemux,
9278 "protection_scheme_type: %" GST_FOURCC_FORMAT ", "
9279 "protection_scheme_version: %#010x",
9280 GST_FOURCC_ARGS (stream->protection_scheme_type),
9281 stream->protection_scheme_version);
9283 schi = qtdemux_tree_get_child_by_type (sinf, FOURCC_schi);
9285 GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schi box");
9288 if (stream->protection_scheme_type == FOURCC_cenc) {
9289 QtDemuxCencSampleSetInfo *info;
9291 const guint8 *tenc_data;
9292 guint32 isEncrypted;
9294 const guint8 *default_kid;
9297 if (G_UNLIKELY (!stream->protection_scheme_info))
9298 stream->protection_scheme_info =
9299 g_malloc0 (sizeof (QtDemuxCencSampleSetInfo));
9301 info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
9303 tenc = qtdemux_tree_get_child_by_type (schi, FOURCC_tenc);
9305 GST_ERROR_OBJECT (qtdemux, "schi box does not contain tenc box, "
9306 "which is mandatory for Common Encryption");
9309 tenc_data = (const guint8 *) tenc->data + 12;
9310 isEncrypted = QT_UINT24 (tenc_data);
9311 iv_size = QT_UINT8 (tenc_data + 3);
9312 default_kid = (tenc_data + 4);
9313 kid_buf = gst_buffer_new_allocate (NULL, 16, NULL);
9314 gst_buffer_fill (kid_buf, 0, default_kid, 16);
9315 if (info->default_properties)
9316 gst_structure_free (info->default_properties);
9317 info->default_properties =
9318 gst_structure_new ("application/x-cenc",
9319 "iv_size", G_TYPE_UINT, iv_size,
9320 "encrypted", G_TYPE_BOOLEAN, (isEncrypted == 1),
9321 "kid", GST_TYPE_BUFFER, kid_buf, NULL);
9322 GST_DEBUG_OBJECT (qtdemux, "default sample properties: "
9323 "is_encrypted=%u, iv_size=%u", isEncrypted, iv_size);
9324 gst_buffer_unref (kid_buf);
9330 * With each track we associate a new QtDemuxStream that contains all the info
9332 * traks that do not decode to something (like strm traks) will not have a pad.
9335 qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
9356 QtDemuxStream *stream = NULL;
9357 gboolean new_stream = FALSE;
9358 gchar *codec = NULL;
9359 const guint8 *stsd_data;
9360 guint16 lang_code; /* quicktime lang code or packed iso code */
9362 guint32 tkhd_flags = 0;
9363 guint8 tkhd_version = 0;
9365 guint value_size, stsd_len, len;
9369 GST_DEBUG_OBJECT (qtdemux, "parse_trak");
9371 if (!qtdemux_tree_get_child_by_type_full (trak, FOURCC_tkhd, &tkhd)
9372 || !gst_byte_reader_get_uint8 (&tkhd, &tkhd_version)
9373 || !gst_byte_reader_get_uint24_be (&tkhd, &tkhd_flags))
9376 /* pick between 64 or 32 bits */
9377 value_size = tkhd_version == 1 ? 8 : 4;
9378 if (!gst_byte_reader_skip (&tkhd, value_size * 2) ||
9379 !gst_byte_reader_get_uint32_be (&tkhd, &track_id))
9382 if (!qtdemux->got_moov) {
9383 if (qtdemux_find_stream (qtdemux, track_id))
9384 goto existing_stream;
9385 stream = _create_stream ();
9386 stream->track_id = track_id;
9389 stream = qtdemux_find_stream (qtdemux, track_id);
9391 GST_WARNING_OBJECT (qtdemux, "Stream not found, going to ignore it");
9395 /* flush samples data from this track from previous moov */
9396 gst_qtdemux_stream_flush_segments_data (qtdemux, stream);
9397 gst_qtdemux_stream_flush_samples_data (qtdemux, stream);
9399 /* need defaults for fragments */
9400 qtdemux_parse_trex (qtdemux, stream, &dummy, &dummy, &dummy);
9402 if (stream->pending_tags == NULL)
9403 stream->pending_tags = gst_tag_list_new_empty ();
9405 if ((tkhd_flags & 1) == 0)
9406 stream->disabled = TRUE;
9408 GST_LOG_OBJECT (qtdemux, "track[tkhd] version/flags/id: 0x%02x/%06x/%u",
9409 tkhd_version, tkhd_flags, stream->track_id);
9411 if (!(mdia = qtdemux_tree_get_child_by_type (trak, FOURCC_mdia)))
9414 if (!(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mdhd))) {
9415 /* be nice for some crooked mjp2 files that use mhdr for mdhd */
9416 if (qtdemux->major_brand != FOURCC_mjp2 ||
9417 !(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mhdr)))
9421 len = QT_UINT32 ((guint8 *) mdhd->data);
9422 version = QT_UINT32 ((guint8 *) mdhd->data + 8);
9423 GST_LOG_OBJECT (qtdemux, "track version/flags: %08x", version);
9424 if (version == 0x01000000) {
9427 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 28);
9428 stream->duration = QT_UINT64 ((guint8 *) mdhd->data + 32);
9429 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 36);
9433 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 20);
9434 stream->duration = QT_UINT32 ((guint8 *) mdhd->data + 24);
9435 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 28);
9438 if (lang_code < 0x400) {
9439 qtdemux_lang_map_qt_code_to_iso (stream->lang_id, lang_code);
9440 } else if (lang_code == 0x7fff) {
9441 stream->lang_id[0] = 0; /* unspecified */
9443 stream->lang_id[0] = 0x60 + ((lang_code >> 10) & 0x1F);
9444 stream->lang_id[1] = 0x60 + ((lang_code >> 5) & 0x1F);
9445 stream->lang_id[2] = 0x60 + (lang_code & 0x1F);
9446 stream->lang_id[3] = 0;
9449 GST_LOG_OBJECT (qtdemux, "track timescale: %" G_GUINT32_FORMAT,
9451 GST_LOG_OBJECT (qtdemux, "track duration: %" G_GUINT64_FORMAT,
9453 GST_LOG_OBJECT (qtdemux, "track language code/id: 0x%04x/%s",
9454 lang_code, stream->lang_id);
9456 if (G_UNLIKELY (stream->timescale == 0 || qtdemux->timescale == 0))
9459 if ((tref = qtdemux_tree_get_child_by_type (trak, FOURCC_tref))) {
9460 /* chapters track reference */
9461 GNode *chap = qtdemux_tree_get_child_by_type (tref, FOURCC_chap);
9463 gsize length = GST_READ_UINT32_BE (chap->data);
9464 if (qtdemux->chapters_track_id)
9465 GST_FIXME_OBJECT (qtdemux, "Multiple CHAP tracks");
9468 qtdemux->chapters_track_id =
9469 GST_READ_UINT32_BE ((gint8 *) chap->data + 8);
9474 /* fragmented files may have bogus duration in moov */
9475 if (!qtdemux->fragmented &&
9476 qtdemux->duration != G_MAXINT64 && stream->duration != G_MAXINT32) {
9477 guint64 tdur1, tdur2;
9479 /* don't overflow */
9480 tdur1 = stream->timescale * (guint64) qtdemux->duration;
9481 tdur2 = qtdemux->timescale * (guint64) stream->duration;
9484 * some of those trailers, nowadays, have prologue images that are
9485 * themselves video tracks as well. I haven't really found a way to
9486 * identify those yet, except for just looking at their duration. */
9487 if (tdur1 != 0 && (tdur2 * 10 / tdur1) < 2) {
9488 GST_WARNING_OBJECT (qtdemux,
9489 "Track shorter than 20%% (%" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT
9490 " vs. %" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT ") of the stream "
9491 "found, assuming preview image or something; skipping track",
9492 stream->duration, stream->timescale, qtdemux->duration,
9493 qtdemux->timescale);
9495 gst_qtdemux_stream_free (qtdemux, stream);
9500 if (!(hdlr = qtdemux_tree_get_child_by_type (mdia, FOURCC_hdlr)))
9503 GST_LOG_OBJECT (qtdemux, "track type: %" GST_FOURCC_FORMAT,
9504 GST_FOURCC_ARGS (QT_FOURCC ((guint8 *) hdlr->data + 12)));
9506 len = QT_UINT32 ((guint8 *) hdlr->data);
9508 stream->subtype = QT_FOURCC ((guint8 *) hdlr->data + 16);
9509 GST_LOG_OBJECT (qtdemux, "track subtype: %" GST_FOURCC_FORMAT,
9510 GST_FOURCC_ARGS (stream->subtype));
9512 if (!(minf = qtdemux_tree_get_child_by_type (mdia, FOURCC_minf)))
9515 if (!(stbl = qtdemux_tree_get_child_by_type (minf, FOURCC_stbl)))
9518 /*parse svmi header if existing */
9519 svmi = qtdemux_tree_get_child_by_type (stbl, FOURCC_svmi);
9521 len = QT_UINT32 ((guint8 *) svmi->data);
9522 version = QT_UINT32 ((guint8 *) svmi->data + 8);
9524 GstVideoMultiviewMode mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
9525 GstVideoMultiviewFlags flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
9526 guint8 frame_type, frame_layout;
9528 /* MPEG-A stereo video */
9529 if (qtdemux->major_brand == FOURCC_ss02)
9530 flags |= GST_VIDEO_MULTIVIEW_FLAGS_MIXED_MONO;
9532 frame_type = QT_UINT8 ((guint8 *) svmi->data + 12);
9533 frame_layout = QT_UINT8 ((guint8 *) svmi->data + 13) & 0x01;
9534 switch (frame_type) {
9536 mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
9539 mode = GST_VIDEO_MULTIVIEW_MODE_ROW_INTERLEAVED;
9542 mode = GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME;
9545 /* mode 3 is primary/secondary view sequence, ie
9546 * left/right views in separate tracks. See section 7.2
9547 * of ISO/IEC 23000-11:2009 */
9548 GST_FIXME_OBJECT (qtdemux,
9549 "Implement stereo video in separate streams");
9552 if ((frame_layout & 0x1) == 0)
9553 flags |= GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
9555 GST_LOG_OBJECT (qtdemux,
9556 "StereoVideo: composition type: %u, is_left_first: %u",
9557 frame_type, frame_layout);
9558 stream->multiview_mode = mode;
9559 stream->multiview_flags = flags;
9564 if (!(stsd = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsd)))
9566 stsd_data = (const guint8 *) stsd->data;
9568 /* stsd should at least have one entry */
9569 stsd_len = QT_UINT32 (stsd_data);
9570 if (stsd_len < 24) {
9571 /* .. but skip stream with empty stsd produced by some Vivotek cameras */
9572 if (stream->subtype == FOURCC_vivo) {
9574 gst_qtdemux_stream_free (qtdemux, stream);
9581 GST_LOG_OBJECT (qtdemux, "stsd len: %d", stsd_len);
9583 /* and that entry should fit within stsd */
9584 len = QT_UINT32 (stsd_data + 16);
9585 if (len > stsd_len + 16)
9588 stream->fourcc = fourcc = QT_FOURCC (stsd_data + 16 + 4);
9589 GST_LOG_OBJECT (qtdemux, "stsd type: %" GST_FOURCC_FORMAT,
9590 GST_FOURCC_ARGS (stream->fourcc));
9591 GST_LOG_OBJECT (qtdemux, "stsd type len: %d", len);
9593 if ((fourcc == FOURCC_drms) || (fourcc == FOURCC_drmi))
9594 goto error_encrypted;
9596 if (fourcc == FOURCC_encv || fourcc == FOURCC_enca) {
9597 GNode *enc = qtdemux_tree_get_child_by_type (stsd, fourcc);
9598 stream->protected = TRUE;
9599 if (!qtdemux_parse_protection_scheme_info (qtdemux, stream, enc, &fourcc))
9600 GST_ERROR_OBJECT (qtdemux, "Failed to parse protection scheme info");
9603 if (stream->subtype == FOURCC_vide) {
9604 guint32 w = 0, h = 0;
9606 gint depth, palette_size, palette_count;
9608 guint32 *palette_data = NULL;
9610 stream->sampled = TRUE;
9612 /* version 1 uses some 64-bit ints */
9613 if (!gst_byte_reader_skip (&tkhd, 20 + value_size))
9616 if (!qtdemux_parse_transformation_matrix (qtdemux, &tkhd, matrix, "tkhd"))
9619 if (!gst_byte_reader_get_uint32_be (&tkhd, &w)
9620 || !gst_byte_reader_get_uint32_be (&tkhd, &h))
9623 stream->display_width = w >> 16;
9624 stream->display_height = h >> 16;
9626 qtdemux_inspect_transformation_matrix (qtdemux, stream, matrix,
9627 &stream->pending_tags);
9633 stream->width = QT_UINT16 (stsd_data + offset + 32);
9634 stream->height = QT_UINT16 (stsd_data + offset + 34);
9635 stream->fps_n = 0; /* this is filled in later */
9636 stream->fps_d = 0; /* this is filled in later */
9637 stream->bits_per_sample = QT_UINT16 (stsd_data + offset + 82);
9638 stream->color_table_id = QT_UINT16 (stsd_data + offset + 84);
9640 /* if color_table_id is 0, ctab atom must follow; however some files
9641 * produced by TMPEGEnc have color_table_id = 0 and no ctab atom, so
9642 * if color table is not present we'll correct the value */
9643 if (stream->color_table_id == 0 &&
9644 (len < 90 || QT_FOURCC (stsd_data + offset + 86) != FOURCC_ctab)) {
9645 stream->color_table_id = -1;
9648 GST_LOG_OBJECT (qtdemux, "width %d, height %d, bps %d, color table id %d",
9649 stream->width, stream->height, stream->bits_per_sample,
9650 stream->color_table_id);
9652 depth = stream->bits_per_sample;
9654 /* more than 32 bits means grayscale */
9655 gray = (depth > 32);
9656 /* low 32 bits specify the depth */
9659 /* different number of palette entries is determined by depth. */
9661 if ((depth == 1) || (depth == 2) || (depth == 4) || (depth == 8))
9662 palette_count = (1 << depth);
9663 palette_size = palette_count * 4;
9665 if (stream->color_table_id) {
9666 switch (palette_count) {
9670 palette_data = g_memdup (ff_qt_default_palette_2, palette_size);
9673 palette_data = g_memdup (ff_qt_default_palette_4, palette_size);
9677 palette_data = g_memdup (ff_qt_grayscale_palette_16, palette_size);
9679 palette_data = g_memdup (ff_qt_default_palette_16, palette_size);
9683 palette_data = g_memdup (ff_qt_grayscale_palette_256, palette_size);
9685 palette_data = g_memdup (ff_qt_default_palette_256, palette_size);
9688 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
9689 (_("The video in this file might not play correctly.")),
9690 ("unsupported palette depth %d", depth));
9694 gint i, j, start, end;
9700 start = QT_UINT32 (stsd_data + offset + 86);
9701 palette_count = QT_UINT16 (stsd_data + offset + 90);
9702 end = QT_UINT16 (stsd_data + offset + 92);
9704 GST_LOG_OBJECT (qtdemux, "start %d, end %d, palette_count %d",
9705 start, end, palette_count);
9712 if (len < 94 + (end - start) * 8)
9715 /* palette is always the same size */
9716 palette_data = g_malloc0 (256 * 4);
9717 palette_size = 256 * 4;
9719 for (j = 0, i = start; i <= end; j++, i++) {
9722 a = QT_UINT16 (stsd_data + offset + 94 + (j * 8));
9723 r = QT_UINT16 (stsd_data + offset + 96 + (j * 8));
9724 g = QT_UINT16 (stsd_data + offset + 98 + (j * 8));
9725 b = QT_UINT16 (stsd_data + offset + 100 + (j * 8));
9727 palette_data[i] = ((a & 0xff00) << 16) | ((r & 0xff00) << 8) |
9728 (g & 0xff00) | (b >> 8);
9733 gst_caps_unref (stream->caps);
9736 qtdemux_video_caps (qtdemux, stream, fourcc, stsd_data, &codec);
9737 if (G_UNLIKELY (!stream->caps)) {
9738 g_free (palette_data);
9739 goto unknown_stream;
9743 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
9744 GST_TAG_VIDEO_CODEC, codec, NULL);
9753 if (stream->rgb8_palette)
9754 gst_memory_unref (stream->rgb8_palette);
9755 stream->rgb8_palette = gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY,
9756 palette_data, palette_size, 0, palette_size, palette_data, g_free);
9758 s = gst_caps_get_structure (stream->caps, 0);
9760 /* non-raw video has a palette_data property. raw video has the palette as
9761 * an extra plane that we append to the output buffers before we push
9763 if (!gst_structure_has_name (s, "video/x-raw")) {
9766 palette = gst_buffer_new ();
9767 gst_buffer_append_memory (palette, stream->rgb8_palette);
9768 stream->rgb8_palette = NULL;
9770 gst_caps_set_simple (stream->caps, "palette_data",
9771 GST_TYPE_BUFFER, palette, NULL);
9772 gst_buffer_unref (palette);
9774 } else if (palette_count != 0) {
9775 GST_ELEMENT_WARNING (qtdemux, STREAM, NOT_IMPLEMENTED,
9776 (NULL), ("Unsupported palette depth %d", depth));
9779 GST_LOG_OBJECT (qtdemux, "frame count: %u",
9780 QT_UINT16 (stsd_data + offset + 48));
9786 /* pick 'the' stsd child */
9787 if (!stream->protected)
9788 mp4v = qtdemux_tree_get_child_by_type (stsd, fourcc);
9790 mp4v = qtdemux_tree_get_child_by_type (stsd, FOURCC_encv);
9793 esds = qtdemux_tree_get_child_by_type (mp4v, FOURCC_esds);
9794 pasp = qtdemux_tree_get_child_by_type (mp4v, FOURCC_pasp);
9795 colr = qtdemux_tree_get_child_by_type (mp4v, FOURCC_colr);
9796 fiel = qtdemux_tree_get_child_by_type (mp4v, FOURCC_fiel);
9800 const guint8 *pasp_data = (const guint8 *) pasp->data;
9801 gint len = QT_UINT32 (pasp_data);
9804 stream->par_w = QT_UINT32 (pasp_data + 8);
9805 stream->par_h = QT_UINT32 (pasp_data + 12);
9816 const guint8 *fiel_data = (const guint8 *) fiel->data;
9817 gint len = QT_UINT32 (fiel_data);
9820 stream->interlace_mode = GST_READ_UINT8 (fiel_data + 8);
9821 stream->field_order = GST_READ_UINT8 (fiel_data + 9);
9826 const guint8 *colr_data = (const guint8 *) colr->data;
9827 gint len = QT_UINT32 (colr_data);
9829 if (len == 19 || len == 18) {
9830 guint32 color_type = GST_READ_UINT32_LE (colr_data + 8);
9832 if (color_type == FOURCC_nclx || color_type == FOURCC_nclc) {
9833 guint16 primaries = GST_READ_UINT16_BE (colr_data + 12);
9834 guint16 transfer_function = GST_READ_UINT16_BE (colr_data + 14);
9835 guint16 matrix = GST_READ_UINT16_BE (colr_data + 16);
9836 gboolean full_range = len == 19 ? colr_data[17] >> 7 : FALSE;
9838 switch (primaries) {
9840 stream->colorimetry.primaries = GST_VIDEO_COLOR_PRIMARIES_BT709;
9843 stream->colorimetry.primaries = GST_VIDEO_COLOR_PRIMARIES_BT470BG;
9846 stream->colorimetry.primaries =
9847 GST_VIDEO_COLOR_PRIMARIES_SMPTE170M;
9850 stream->colorimetry.primaries = GST_VIDEO_COLOR_PRIMARIES_BT2020;
9856 switch (transfer_function) {
9858 stream->colorimetry.transfer = GST_VIDEO_TRANSFER_BT709;
9861 stream->colorimetry.transfer = GST_VIDEO_TRANSFER_SMPTE240M;
9869 stream->colorimetry.matrix = GST_VIDEO_COLOR_MATRIX_BT709;
9872 stream->colorimetry.matrix = GST_VIDEO_COLOR_MATRIX_BT601;
9875 stream->colorimetry.matrix = GST_VIDEO_COLOR_MATRIX_SMPTE240M;
9878 stream->colorimetry.matrix = GST_VIDEO_COLOR_MATRIX_BT2020;
9884 stream->colorimetry.range =
9885 full_range ? GST_VIDEO_COLOR_RANGE_0_255 :
9886 GST_VIDEO_COLOR_RANGE_16_235;
9888 GST_DEBUG_OBJECT (qtdemux, "Unsupported color type");
9891 GST_WARNING_OBJECT (qtdemux, "Invalid colr atom size");
9896 gst_qtdemux_handle_esds (qtdemux, stream, esds, stream->pending_tags);
9903 gint len = QT_UINT32 (stsd_data) - 0x66;
9904 const guint8 *avc_data = stsd_data + 0x66;
9907 while (len >= 0x8) {
9910 if (QT_UINT32 (avc_data) <= len)
9911 size = QT_UINT32 (avc_data) - 0x8;
9916 /* No real data, so break out */
9919 switch (QT_FOURCC (avc_data + 0x4)) {
9922 /* parse, if found */
9925 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
9927 /* First 4 bytes are the length of the atom, the next 4 bytes
9928 * are the fourcc, the next 1 byte is the version, and the
9929 * subsequent bytes are profile_tier_level structure like data. */
9930 gst_codec_utils_h264_caps_set_level_and_profile (stream->caps,
9931 avc_data + 8 + 1, size - 1);
9932 buf = gst_buffer_new_and_alloc (size);
9933 gst_buffer_fill (buf, 0, avc_data + 0x8, size);
9934 gst_caps_set_simple (stream->caps,
9935 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9936 gst_buffer_unref (buf);
9944 GST_DEBUG_OBJECT (qtdemux, "found strf codec_data in stsd");
9946 /* First 4 bytes are the length of the atom, the next 4 bytes
9947 * are the fourcc, next 40 bytes are BITMAPINFOHEADER,
9948 * next 1 byte is the version, and the
9949 * subsequent bytes are sequence parameter set like data. */
9951 size -= 40; /* we'll be skipping BITMAPINFOHEADER */
9953 gst_codec_utils_h264_caps_set_level_and_profile (stream->caps,
9954 avc_data + 8 + 40 + 1, size - 1);
9956 buf = gst_buffer_new_and_alloc (size);
9957 gst_buffer_fill (buf, 0, avc_data + 8 + 40, size);
9958 gst_caps_set_simple (stream->caps,
9959 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9960 gst_buffer_unref (buf);
9966 guint avg_bitrate, max_bitrate;
9968 /* bufferSizeDB, maxBitrate and avgBitrate - 4 bytes each */
9972 max_bitrate = QT_UINT32 (avc_data + 0xc);
9973 avg_bitrate = QT_UINT32 (avc_data + 0x10);
9975 if (!max_bitrate && !avg_bitrate)
9978 /* Some muxers seem to swap the average and maximum bitrates
9979 * (I'm looking at you, YouTube), so we swap for sanity. */
9980 if (max_bitrate > 0 && max_bitrate < avg_bitrate) {
9981 guint temp = avg_bitrate;
9983 avg_bitrate = max_bitrate;
9987 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
9988 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
9989 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
9991 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
9992 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
9993 GST_TAG_BITRATE, avg_bitrate, NULL);
10004 avc_data += size + 8;
10013 gint len = QT_UINT32 (stsd_data) - 0x66;
10014 const guint8 *hevc_data = stsd_data + 0x66;
10017 while (len >= 0x8) {
10020 if (QT_UINT32 (hevc_data) <= len)
10021 size = QT_UINT32 (hevc_data) - 0x8;
10026 /* No real data, so break out */
10029 switch (QT_FOURCC (hevc_data + 0x4)) {
10032 /* parse, if found */
10035 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
10037 /* First 4 bytes are the length of the atom, the next 4 bytes
10038 * are the fourcc, the next 1 byte is the version, and the
10039 * subsequent bytes are sequence parameter set like data. */
10040 gst_codec_utils_h265_caps_set_level_tier_and_profile
10041 (stream->caps, hevc_data + 8 + 1, size - 1);
10043 buf = gst_buffer_new_and_alloc (size);
10044 gst_buffer_fill (buf, 0, hevc_data + 0x8, size);
10045 gst_caps_set_simple (stream->caps,
10046 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10047 gst_buffer_unref (buf);
10054 hevc_data += size + 8;
10067 GST_DEBUG_OBJECT (qtdemux, "found %" GST_FOURCC_FORMAT,
10068 GST_FOURCC_ARGS (fourcc));
10070 /* codec data might be in glbl extension atom */
10072 qtdemux_tree_get_child_by_type (mp4v, FOURCC_glbl) : NULL;
10078 GST_DEBUG_OBJECT (qtdemux, "found glbl data in stsd");
10080 len = QT_UINT32 (data);
10083 buf = gst_buffer_new_and_alloc (len);
10084 gst_buffer_fill (buf, 0, data + 8, len);
10085 gst_caps_set_simple (stream->caps,
10086 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10087 gst_buffer_unref (buf);
10094 /* see annex I of the jpeg2000 spec */
10095 GNode *jp2h, *ihdr, *colr, *mjp2, *field, *prefix, *cmap, *cdef;
10096 const guint8 *data;
10097 const gchar *colorspace = NULL;
10099 guint32 ncomp_map = 0;
10100 gint32 *comp_map = NULL;
10101 guint32 nchan_def = 0;
10102 gint32 *chan_def = NULL;
10104 GST_DEBUG_OBJECT (qtdemux, "found mjp2");
10105 /* some required atoms */
10106 mjp2 = qtdemux_tree_get_child_by_type (stsd, FOURCC_mjp2);
10109 jp2h = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2h);
10113 /* number of components; redundant with info in codestream, but useful
10115 ihdr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_ihdr);
10116 if (!ihdr || QT_UINT32 (ihdr->data) != 22)
10118 ncomp = QT_UINT16 (((guint8 *) ihdr->data) + 16);
10120 colr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_colr);
10123 GST_DEBUG_OBJECT (qtdemux, "found colr");
10124 /* extract colour space info */
10125 if (QT_UINT8 ((guint8 *) colr->data + 8) == 1) {
10126 switch (QT_UINT32 ((guint8 *) colr->data + 11)) {
10128 colorspace = "sRGB";
10131 colorspace = "GRAY";
10134 colorspace = "sYUV";
10142 /* colr is required, and only values 16, 17, and 18 are specified,
10143 so error if we have no colorspace */
10146 /* extract component mapping */
10147 cmap = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cmap);
10149 guint32 cmap_len = 0;
10151 cmap_len = QT_UINT32 (cmap->data);
10152 if (cmap_len >= 8) {
10153 /* normal box, subtract off header */
10155 /* cmap: { u16 cmp; u8 mtyp; u8 pcol; }* */
10156 if (cmap_len % 4 == 0) {
10157 ncomp_map = (cmap_len / 4);
10158 comp_map = g_new0 (gint32, ncomp_map);
10159 for (i = 0; i < ncomp_map; i++) {
10162 cmp = QT_UINT16 (((guint8 *) cmap->data) + 8 + i * 4);
10163 mtyp = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 2);
10164 pcol = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 3);
10165 comp_map[i] = (mtyp << 24) | (pcol << 16) | cmp;
10170 /* extract channel definitions */
10171 cdef = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cdef);
10173 guint32 cdef_len = 0;
10175 cdef_len = QT_UINT32 (cdef->data);
10176 if (cdef_len >= 10) {
10177 /* normal box, subtract off header and len */
10179 /* cdef: u16 n; { u16 cn; u16 typ; u16 asoc; }* */
10180 if (cdef_len % 6 == 0) {
10181 nchan_def = (cdef_len / 6);
10182 chan_def = g_new0 (gint32, nchan_def);
10183 for (i = 0; i < nchan_def; i++)
10185 for (i = 0; i < nchan_def; i++) {
10186 guint16 cn, typ, asoc;
10187 cn = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6);
10188 typ = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 2);
10189 asoc = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 4);
10190 if (cn < nchan_def) {
10193 chan_def[cn] = asoc;
10196 chan_def[cn] = 0; /* alpha */
10199 chan_def[cn] = -typ;
10207 gst_caps_set_simple (stream->caps,
10208 "num-components", G_TYPE_INT, ncomp, NULL);
10209 gst_caps_set_simple (stream->caps,
10210 "colorspace", G_TYPE_STRING, colorspace, NULL);
10213 GValue arr = { 0, };
10214 GValue elt = { 0, };
10216 g_value_init (&arr, GST_TYPE_ARRAY);
10217 g_value_init (&elt, G_TYPE_INT);
10218 for (i = 0; i < ncomp_map; i++) {
10219 g_value_set_int (&elt, comp_map[i]);
10220 gst_value_array_append_value (&arr, &elt);
10222 gst_structure_set_value (gst_caps_get_structure (stream->caps, 0),
10223 "component-map", &arr);
10224 g_value_unset (&elt);
10225 g_value_unset (&arr);
10230 GValue arr = { 0, };
10231 GValue elt = { 0, };
10233 g_value_init (&arr, GST_TYPE_ARRAY);
10234 g_value_init (&elt, G_TYPE_INT);
10235 for (i = 0; i < nchan_def; i++) {
10236 g_value_set_int (&elt, chan_def[i]);
10237 gst_value_array_append_value (&arr, &elt);
10239 gst_structure_set_value (gst_caps_get_structure (stream->caps, 0),
10240 "channel-definitions", &arr);
10241 g_value_unset (&elt);
10242 g_value_unset (&arr);
10246 /* some optional atoms */
10247 field = qtdemux_tree_get_child_by_type (mjp2, FOURCC_fiel);
10248 prefix = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2x);
10250 /* indicate possible fields in caps */
10252 data = (guint8 *) field->data + 8;
10254 gst_caps_set_simple (stream->caps, "fields", G_TYPE_INT,
10255 (gint) * data, NULL);
10257 /* add codec_data if provided */
10262 GST_DEBUG_OBJECT (qtdemux, "found prefix data in stsd");
10263 data = prefix->data;
10264 len = QT_UINT32 (data);
10267 buf = gst_buffer_new_and_alloc (len);
10268 gst_buffer_fill (buf, 0, data + 8, len);
10269 gst_caps_set_simple (stream->caps,
10270 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10271 gst_buffer_unref (buf);
10278 /* https://developer.apple.com/standards/qtff-2001.pdf,
10279 * page 92, "Video Sample Description", under table 3.1 */
10282 const gint compressor_offset = 16 + 4 + 4 * 3 + 2 * 2 + 2 * 4 + 4 + 2;
10283 const gint min_size = compressor_offset + 32 + 2 + 2;
10286 guint16 color_table_id = 0;
10289 GST_DEBUG_OBJECT (qtdemux, "found jpeg");
10291 /* recover information on interlaced/progressive */
10292 jpeg = qtdemux_tree_get_child_by_type (stsd, FOURCC_jpeg);
10296 len = QT_UINT32 (jpeg->data);
10297 GST_DEBUG_OBJECT (qtdemux, "Found jpeg: len %u, need %d", len,
10299 if (len >= min_size) {
10300 gst_byte_reader_init (&br, jpeg->data, len);
10302 gst_byte_reader_skip (&br, compressor_offset + 32 + 2);
10303 gst_byte_reader_get_uint16_le (&br, &color_table_id);
10304 if (color_table_id != 0) {
10305 /* the spec says there can be concatenated chunks in the data, and we want
10306 * to find one called field. Walk through them. */
10307 gint offset = min_size;
10308 while (offset + 8 < len) {
10309 guint32 size = 0, tag;
10310 ok = gst_byte_reader_get_uint32_le (&br, &size);
10311 ok &= gst_byte_reader_get_uint32_le (&br, &tag);
10312 if (!ok || size < 8) {
10313 GST_WARNING_OBJECT (qtdemux,
10314 "Failed to walk optional chunk list");
10317 GST_DEBUG_OBJECT (qtdemux,
10318 "Found optional %4.4s chunk, size %u", (const char *) &tag,
10320 if (tag == FOURCC_fiel) {
10321 guint8 n_fields, ordering;
10322 gst_byte_reader_get_uint8 (&br, &n_fields);
10323 gst_byte_reader_get_uint8 (&br, &ordering);
10324 if (n_fields == 1 || n_fields == 2) {
10325 GST_DEBUG_OBJECT (qtdemux,
10326 "Found fiel tag with %u fields, ordering %u", n_fields,
10329 gst_caps_set_simple (stream->caps, "interlace-mode",
10330 G_TYPE_STRING, "interleaved", NULL);
10332 GST_WARNING_OBJECT (qtdemux,
10333 "Found fiel tag with invalid fields (%u)", n_fields);
10339 GST_DEBUG_OBJECT (qtdemux,
10340 "Color table ID is 0, not trying to get interlacedness");
10343 GST_WARNING_OBJECT (qtdemux,
10344 "Length of jpeg chunk is too small, not trying to get interlacedness");
10353 GstBuffer *seqh = NULL;
10354 guint8 *gamma_data = NULL;
10355 gint len = QT_UINT32 (stsd_data);
10357 qtdemux_parse_svq3_stsd_data (qtdemux, stsd, &gamma_data, &seqh);
10359 gst_caps_set_simple (stream->caps, "applied-gamma", G_TYPE_DOUBLE,
10360 QT_FP32 (gamma_data), NULL);
10363 /* sorry for the bad name, but we don't know what this is, other
10364 * than its own fourcc */
10365 gst_caps_set_simple (stream->caps, "seqh", GST_TYPE_BUFFER, seqh,
10369 GST_DEBUG_OBJECT (qtdemux, "found codec_data in stsd");
10370 buf = gst_buffer_new_and_alloc (len);
10371 gst_buffer_fill (buf, 0, stsd_data, len);
10372 gst_caps_set_simple (stream->caps,
10373 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10374 gst_buffer_unref (buf);
10380 gst_caps_set_simple (stream->caps,
10381 "depth", G_TYPE_INT, QT_UINT16 (stsd_data + offset + 82), NULL);
10386 GNode *xith, *xdxt;
10388 GST_DEBUG_OBJECT (qtdemux, "found XiTh");
10389 xith = qtdemux_tree_get_child_by_type (stsd, FOURCC_XiTh);
10393 xdxt = qtdemux_tree_get_child_by_type (xith, FOURCC_XdxT);
10397 GST_DEBUG_OBJECT (qtdemux, "found XdxT node");
10398 /* collect the headers and store them in a stream list so that we can
10399 * send them out first */
10400 qtdemux_parse_theora_extension (qtdemux, stream, xdxt);
10410 GST_DEBUG_OBJECT (qtdemux, "parse ovc1 header");
10411 ovc1 = qtdemux_tree_get_child_by_type (stsd, FOURCC_ovc1);
10414 ovc1_data = ovc1->data;
10415 ovc1_len = QT_UINT32 (ovc1_data);
10416 if (ovc1_len <= 198) {
10417 GST_WARNING_OBJECT (qtdemux, "Too small ovc1 header, skipping");
10420 buf = gst_buffer_new_and_alloc (ovc1_len - 198);
10421 gst_buffer_fill (buf, 0, ovc1_data + 198, ovc1_len - 198);
10422 gst_caps_set_simple (stream->caps,
10423 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10424 gst_buffer_unref (buf);
10429 gint len = QT_UINT32 (stsd_data) - 0x66;
10430 const guint8 *vc1_data = stsd_data + 0x66;
10436 if (QT_UINT32 (vc1_data) <= len)
10437 size = QT_UINT32 (vc1_data) - 8;
10442 /* No real data, so break out */
10445 switch (QT_FOURCC (vc1_data + 0x4)) {
10446 case GST_MAKE_FOURCC ('d', 'v', 'c', '1'):
10450 GST_DEBUG_OBJECT (qtdemux, "found dvc1 codec_data in stsd");
10451 buf = gst_buffer_new_and_alloc (size);
10452 gst_buffer_fill (buf, 0, vc1_data + 8, size);
10453 gst_caps_set_simple (stream->caps,
10454 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10455 gst_buffer_unref (buf);
10462 vc1_data += size + 8;
10471 GST_INFO_OBJECT (qtdemux,
10472 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
10473 GST_FOURCC_ARGS (fourcc), stream->caps);
10475 } else if (stream->subtype == FOURCC_soun) {
10476 int version, samplesize;
10477 guint16 compression_id;
10478 gboolean amrwb = FALSE;
10481 /* sample description entry (16) + sound sample description v0 (20) */
10485 version = QT_UINT32 (stsd_data + offset);
10486 stream->n_channels = QT_UINT16 (stsd_data + offset + 8);
10487 samplesize = QT_UINT16 (stsd_data + offset + 10);
10488 compression_id = QT_UINT16 (stsd_data + offset + 12);
10489 stream->rate = QT_FP32 (stsd_data + offset + 16);
10491 GST_LOG_OBJECT (qtdemux, "version/rev: %08x", version);
10492 GST_LOG_OBJECT (qtdemux, "vendor: %08x",
10493 QT_UINT32 (stsd_data + offset + 4));
10494 GST_LOG_OBJECT (qtdemux, "n_channels: %d", stream->n_channels);
10495 GST_LOG_OBJECT (qtdemux, "sample_size: %d", samplesize);
10496 GST_LOG_OBJECT (qtdemux, "compression_id: %d", compression_id);
10497 GST_LOG_OBJECT (qtdemux, "packet size: %d",
10498 QT_UINT16 (stsd_data + offset + 14));
10499 GST_LOG_OBJECT (qtdemux, "sample rate: %g", stream->rate);
10501 if (compression_id == 0xfffe)
10502 stream->sampled = TRUE;
10504 /* first assume uncompressed audio */
10505 stream->bytes_per_sample = samplesize / 8;
10506 stream->samples_per_frame = stream->n_channels;
10507 stream->bytes_per_frame = stream->n_channels * stream->bytes_per_sample;
10508 stream->samples_per_packet = stream->samples_per_frame;
10509 stream->bytes_per_packet = stream->bytes_per_sample;
10513 /* Yes, these have to be hard-coded */
10516 stream->samples_per_packet = 6;
10517 stream->bytes_per_packet = 1;
10518 stream->bytes_per_frame = 1 * stream->n_channels;
10519 stream->bytes_per_sample = 1;
10520 stream->samples_per_frame = 6 * stream->n_channels;
10525 stream->samples_per_packet = 3;
10526 stream->bytes_per_packet = 1;
10527 stream->bytes_per_frame = 1 * stream->n_channels;
10528 stream->bytes_per_sample = 1;
10529 stream->samples_per_frame = 3 * stream->n_channels;
10534 stream->samples_per_packet = 64;
10535 stream->bytes_per_packet = 34;
10536 stream->bytes_per_frame = 34 * stream->n_channels;
10537 stream->bytes_per_sample = 2;
10538 stream->samples_per_frame = 64 * stream->n_channels;
10544 stream->samples_per_packet = 1;
10545 stream->bytes_per_packet = 1;
10546 stream->bytes_per_frame = 1 * stream->n_channels;
10547 stream->bytes_per_sample = 1;
10548 stream->samples_per_frame = 1 * stream->n_channels;
10553 stream->samples_per_packet = 160;
10554 stream->bytes_per_packet = 33;
10555 stream->bytes_per_frame = 33 * stream->n_channels;
10556 stream->bytes_per_sample = 2;
10557 stream->samples_per_frame = 160 * stream->n_channels;
10564 if (version == 0x00010000) {
10565 /* sample description entry (16) + sound sample description v1 (20+16) */
10576 /* only parse extra decoding config for non-pcm audio */
10577 stream->samples_per_packet = QT_UINT32 (stsd_data + offset);
10578 stream->bytes_per_packet = QT_UINT32 (stsd_data + offset + 4);
10579 stream->bytes_per_frame = QT_UINT32 (stsd_data + offset + 8);
10580 stream->bytes_per_sample = QT_UINT32 (stsd_data + offset + 12);
10582 GST_LOG_OBJECT (qtdemux, "samples/packet: %d",
10583 stream->samples_per_packet);
10584 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
10585 stream->bytes_per_packet);
10586 GST_LOG_OBJECT (qtdemux, "bytes/frame: %d",
10587 stream->bytes_per_frame);
10588 GST_LOG_OBJECT (qtdemux, "bytes/sample: %d",
10589 stream->bytes_per_sample);
10591 if (!stream->sampled && stream->bytes_per_packet) {
10592 stream->samples_per_frame = (stream->bytes_per_frame /
10593 stream->bytes_per_packet) * stream->samples_per_packet;
10594 GST_LOG_OBJECT (qtdemux, "samples/frame: %d",
10595 stream->samples_per_frame);
10600 } else if (version == 0x00020000) {
10607 /* sample description entry (16) + sound sample description v2 (56) */
10611 qtfp.val = QT_UINT64 (stsd_data + offset + 4);
10612 stream->rate = qtfp.fp;
10613 stream->n_channels = QT_UINT32 (stsd_data + offset + 12);
10615 GST_LOG_OBJECT (qtdemux, "Sound sample description Version 2");
10616 GST_LOG_OBJECT (qtdemux, "sample rate: %g", stream->rate);
10617 GST_LOG_OBJECT (qtdemux, "n_channels: %d", stream->n_channels);
10618 GST_LOG_OBJECT (qtdemux, "bits/channel: %d",
10619 QT_UINT32 (stsd_data + offset + 20));
10620 GST_LOG_OBJECT (qtdemux, "format flags: %X",
10621 QT_UINT32 (stsd_data + offset + 24));
10622 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
10623 QT_UINT32 (stsd_data + offset + 28));
10624 GST_LOG_OBJECT (qtdemux, "LPCM frames/packet: %d",
10625 QT_UINT32 (stsd_data + offset + 32));
10626 } else if (version != 0x00000) {
10627 GST_WARNING_OBJECT (qtdemux, "unknown audio STSD version %08x", version);
10631 gst_caps_unref (stream->caps);
10633 stream->caps = qtdemux_audio_caps (qtdemux, stream, fourcc,
10634 stsd_data + 32, len - 16, &codec);
10642 in24 = qtdemux_tree_get_child_by_type (stsd, FOURCC_in24);
10644 enda = qtdemux_tree_get_child_by_type (in24, FOURCC_enda);
10646 wave = qtdemux_tree_get_child_by_type (in24, FOURCC_wave);
10648 enda = qtdemux_tree_get_child_by_type (wave, FOURCC_enda);
10651 int enda_value = QT_UINT16 ((guint8 *) enda->data + 8);
10652 gst_caps_set_simple (stream->caps,
10653 "format", G_TYPE_STRING, (enda_value) ? "S24LE" : "S24BE", NULL);
10660 const guint8 *owma_data;
10661 const gchar *codec_name = NULL;
10665 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
10666 /* FIXME this should also be gst_riff_strf_auds,
10667 * but the latter one is actually missing bits-per-sample :( */
10672 gint32 nSamplesPerSec;
10673 gint32 nAvgBytesPerSec;
10674 gint16 nBlockAlign;
10675 gint16 wBitsPerSample;
10678 WAVEFORMATEX *wfex;
10680 GST_DEBUG_OBJECT (qtdemux, "parse owma");
10681 owma = qtdemux_tree_get_child_by_type (stsd, FOURCC_owma);
10684 owma_data = owma->data;
10685 owma_len = QT_UINT32 (owma_data);
10686 if (owma_len <= 54) {
10687 GST_WARNING_OBJECT (qtdemux, "Too small owma header, skipping");
10690 wfex = (WAVEFORMATEX *) (owma_data + 36);
10691 buf = gst_buffer_new_and_alloc (owma_len - 54);
10692 gst_buffer_fill (buf, 0, owma_data + 54, owma_len - 54);
10693 if (wfex->wFormatTag == 0x0161) {
10694 codec_name = "Windows Media Audio";
10696 } else if (wfex->wFormatTag == 0x0162) {
10697 codec_name = "Windows Media Audio 9 Pro";
10699 } else if (wfex->wFormatTag == 0x0163) {
10700 codec_name = "Windows Media Audio 9 Lossless";
10701 /* is that correct? gstffmpegcodecmap.c is missing it, but
10702 * fluendo codec seems to support it */
10706 gst_caps_set_simple (stream->caps,
10707 "codec_data", GST_TYPE_BUFFER, buf,
10708 "wmaversion", G_TYPE_INT, version,
10709 "block_align", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->nBlockAlign),
10710 "bitrate", G_TYPE_INT, GST_READ_UINT32_LE (&wfex->nAvgBytesPerSec),
10711 "width", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->wBitsPerSample),
10712 "depth", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->wBitsPerSample),
10714 gst_buffer_unref (buf);
10718 codec = g_strdup (codec_name);
10724 gint len = QT_UINT32 (stsd_data) - offset;
10725 const guint8 *wfex_data = stsd_data + offset;
10726 const gchar *codec_name = NULL;
10728 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
10729 /* FIXME this should also be gst_riff_strf_auds,
10730 * but the latter one is actually missing bits-per-sample :( */
10735 gint32 nSamplesPerSec;
10736 gint32 nAvgBytesPerSec;
10737 gint16 nBlockAlign;
10738 gint16 wBitsPerSample;
10743 /* FIXME: unify with similar wavformatex parsing code above */
10744 GST_DEBUG_OBJECT (qtdemux, "parse wma, looking for wfex");
10750 if (QT_UINT32 (wfex_data) <= len)
10751 size = QT_UINT32 (wfex_data) - 8;
10756 /* No real data, so break out */
10759 switch (QT_FOURCC (wfex_data + 4)) {
10760 case GST_MAKE_FOURCC ('w', 'f', 'e', 'x'):
10762 GST_DEBUG_OBJECT (qtdemux, "found wfex in stsd");
10767 wfex.wFormatTag = GST_READ_UINT16_LE (wfex_data + 8 + 0);
10768 wfex.nChannels = GST_READ_UINT16_LE (wfex_data + 8 + 2);
10769 wfex.nSamplesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 4);
10770 wfex.nAvgBytesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 8);
10771 wfex.nBlockAlign = GST_READ_UINT16_LE (wfex_data + 8 + 12);
10772 wfex.wBitsPerSample = GST_READ_UINT16_LE (wfex_data + 8 + 14);
10773 wfex.cbSize = GST_READ_UINT16_LE (wfex_data + 8 + 16);
10775 GST_LOG_OBJECT (qtdemux, "Found wfex box in stsd:");
10776 GST_LOG_OBJECT (qtdemux, "FormatTag = 0x%04x, Channels = %u, "
10777 "SamplesPerSec = %u, AvgBytesPerSec = %u, BlockAlign = %u, "
10778 "BitsPerSample = %u, Size = %u", wfex.wFormatTag,
10779 wfex.nChannels, wfex.nSamplesPerSec, wfex.nAvgBytesPerSec,
10780 wfex.nBlockAlign, wfex.wBitsPerSample, wfex.cbSize);
10782 if (wfex.wFormatTag == 0x0161) {
10783 codec_name = "Windows Media Audio";
10785 } else if (wfex.wFormatTag == 0x0162) {
10786 codec_name = "Windows Media Audio 9 Pro";
10788 } else if (wfex.wFormatTag == 0x0163) {
10789 codec_name = "Windows Media Audio 9 Lossless";
10790 /* is that correct? gstffmpegcodecmap.c is missing it, but
10791 * fluendo codec seems to support it */
10795 gst_caps_set_simple (stream->caps,
10796 "wmaversion", G_TYPE_INT, version,
10797 "block_align", G_TYPE_INT, wfex.nBlockAlign,
10798 "bitrate", G_TYPE_INT, wfex.nAvgBytesPerSec,
10799 "width", G_TYPE_INT, wfex.wBitsPerSample,
10800 "depth", G_TYPE_INT, wfex.wBitsPerSample, NULL);
10802 if (size > wfex.cbSize) {
10805 buf = gst_buffer_new_and_alloc (size - wfex.cbSize);
10806 gst_buffer_fill (buf, 0, wfex_data + 8 + wfex.cbSize,
10807 size - wfex.cbSize);
10808 gst_caps_set_simple (stream->caps,
10809 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10810 gst_buffer_unref (buf);
10812 GST_WARNING_OBJECT (qtdemux, "no codec data");
10817 codec = g_strdup (codec_name);
10825 wfex_data += size + 8;
10832 const guint8 *opus_data;
10833 guint8 *channel_mapping = NULL;
10836 guint8 channel_mapping_family;
10837 guint8 stream_count;
10838 guint8 coupled_count;
10841 opus = qtdemux_tree_get_child_by_type (stsd, FOURCC_opus);
10842 opus_data = opus->data;
10844 channels = GST_READ_UINT8 (opus_data + 45);
10845 rate = GST_READ_UINT32_LE (opus_data + 48);
10846 channel_mapping_family = GST_READ_UINT8 (opus_data + 54);
10847 stream_count = GST_READ_UINT8 (opus_data + 55);
10848 coupled_count = GST_READ_UINT8 (opus_data + 56);
10850 if (channels > 0) {
10851 channel_mapping = g_malloc (channels * sizeof (guint8));
10852 for (i = 0; i < channels; i++)
10853 channel_mapping[i] = GST_READ_UINT8 (opus_data + i + 57);
10856 stream->caps = gst_codec_utils_opus_create_caps (rate, channels,
10857 channel_mapping_family, stream_count, coupled_count,
10869 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
10870 GST_TAG_AUDIO_CODEC, codec, NULL);
10874 /* some bitrate info may have ended up in caps */
10875 s = gst_caps_get_structure (stream->caps, 0);
10876 gst_structure_get_int (s, "bitrate", &bitrate);
10878 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
10879 GST_TAG_BITRATE, bitrate, NULL);
10882 if (stream->protected && fourcc == FOURCC_mp4a)
10883 mp4a = qtdemux_tree_get_child_by_type (stsd, FOURCC_enca);
10885 mp4a = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4a);
10890 wave = qtdemux_tree_get_child_by_type (mp4a, FOURCC_wave);
10892 esds = qtdemux_tree_get_child_by_type (wave, FOURCC_esds);
10894 esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
10898 /* If the fourcc's bottom 16 bits gives 'sm', then the top
10899 16 bits is a byte-swapped wave-style codec identifier,
10900 and we can find a WAVE header internally to a 'wave' atom here.
10901 This can more clearly be thought of as 'ms' as the top 16 bits, and a
10902 codec id as the bottom 16 bits - but byte-swapped to store in QT (which
10905 if ((fourcc & 0xffff) == (('s' << 8) | 'm')) {
10906 if (len < offset + 20) {
10907 GST_WARNING_OBJECT (qtdemux, "No wave atom in MS-style audio");
10909 guint32 datalen = QT_UINT32 (stsd_data + offset + 16);
10910 const guint8 *data = stsd_data + offset + 16;
10912 GNode *waveheadernode;
10914 wavenode = g_node_new ((guint8 *) data);
10915 if (qtdemux_parse_node (qtdemux, wavenode, data, datalen)) {
10916 const guint8 *waveheader;
10919 waveheadernode = qtdemux_tree_get_child_by_type (wavenode, fourcc);
10920 if (waveheadernode) {
10921 waveheader = (const guint8 *) waveheadernode->data;
10922 headerlen = QT_UINT32 (waveheader);
10924 if (headerlen > 8) {
10925 gst_riff_strf_auds *header = NULL;
10926 GstBuffer *headerbuf;
10932 headerbuf = gst_buffer_new_and_alloc (headerlen);
10933 gst_buffer_fill (headerbuf, 0, waveheader, headerlen);
10935 if (gst_riff_parse_strf_auds (GST_ELEMENT_CAST (qtdemux),
10936 headerbuf, &header, &extra)) {
10937 gst_caps_unref (stream->caps);
10938 /* FIXME: Need to do something with the channel reorder map */
10939 stream->caps = gst_riff_create_audio_caps (header->format, NULL,
10940 header, extra, NULL, NULL, NULL);
10943 gst_buffer_unref (extra);
10948 GST_DEBUG ("Didn't find waveheadernode for this codec");
10950 g_node_destroy (wavenode);
10953 gst_qtdemux_handle_esds (qtdemux, stream, esds, stream->pending_tags);
10957 /* FIXME: what is in the chunk? */
10960 gint len = QT_UINT32 (stsd_data);
10962 /* seems to be always = 116 = 0x74 */
10968 gint len = QT_UINT32 (stsd_data);
10971 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x4C);
10973 gst_buffer_fill (buf, 0, stsd_data + 0x4C, len - 0x4C);
10974 gst_caps_set_simple (stream->caps,
10975 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10976 gst_buffer_unref (buf);
10978 gst_caps_set_simple (stream->caps,
10979 "samplesize", G_TYPE_INT, samplesize, NULL);
10984 GNode *alac, *wave = NULL;
10986 /* apparently, m4a has this atom appended directly in the stsd entry,
10987 * while mov has it in a wave atom */
10988 alac = qtdemux_tree_get_child_by_type (stsd, FOURCC_alac);
10990 /* alac now refers to stsd entry atom */
10991 wave = qtdemux_tree_get_child_by_type (alac, FOURCC_wave);
10993 alac = qtdemux_tree_get_child_by_type (wave, FOURCC_alac);
10995 alac = qtdemux_tree_get_child_by_type (alac, FOURCC_alac);
10998 const guint8 *alac_data = alac->data;
10999 gint len = QT_UINT32 (alac->data);
11003 GST_DEBUG_OBJECT (qtdemux,
11004 "discarding alac atom with unexpected len %d", len);
11006 /* codec-data contains alac atom size and prefix,
11007 * ffmpeg likes it that way, not quite gst-ish though ...*/
11008 buf = gst_buffer_new_and_alloc (len);
11009 gst_buffer_fill (buf, 0, alac->data, len);
11010 gst_caps_set_simple (stream->caps,
11011 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11012 gst_buffer_unref (buf);
11014 stream->bytes_per_frame = QT_UINT32 (alac_data + 12);
11015 stream->n_channels = QT_UINT8 (alac_data + 21);
11016 stream->rate = QT_UINT32 (alac_data + 32);
11019 gst_caps_set_simple (stream->caps,
11020 "samplesize", G_TYPE_INT, samplesize, NULL);
11025 /* The codingname of the sample entry is 'fLaC' */
11026 GNode *flac = qtdemux_tree_get_child_by_type (stsd, FOURCC_fLaC);
11029 /* The 'dfLa' box is added to the sample entry to convey
11030 initializing information for the decoder. */
11031 const GNode *dfla =
11032 qtdemux_tree_get_child_by_type (flac, FOURCC_dfLa);
11035 const guint32 len = QT_UINT32 (dfla->data);
11037 /* Must contain at least dfLa box header (12),
11038 * METADATA_BLOCK_HEADER (4), METADATA_BLOCK_STREAMINFO (34) */
11040 GST_DEBUG_OBJECT (qtdemux,
11041 "discarding dfla atom with unexpected len %d", len);
11043 /* skip dfLa header to get the METADATA_BLOCKs */
11044 const guint8 *metadata_blocks = (guint8 *) dfla->data + 12;
11045 const guint32 metadata_blocks_len = len - 12;
11047 gchar *stream_marker = g_strdup ("fLaC");
11048 GstBuffer *block = gst_buffer_new_wrapped (stream_marker,
11049 strlen (stream_marker));
11052 guint32 remainder = 0;
11053 guint32 block_size = 0;
11054 gboolean is_last = FALSE;
11056 GValue array = G_VALUE_INIT;
11057 GValue value = G_VALUE_INIT;
11059 g_value_init (&array, GST_TYPE_ARRAY);
11060 g_value_init (&value, GST_TYPE_BUFFER);
11062 gst_value_set_buffer (&value, block);
11063 gst_value_array_append_value (&array, &value);
11064 g_value_reset (&value);
11066 gst_buffer_unref (block);
11068 /* check there's at least one METADATA_BLOCK_HEADER's worth
11069 * of data, and we haven't already finished parsing */
11070 while (!is_last && ((index + 3) < metadata_blocks_len)) {
11071 remainder = metadata_blocks_len - index;
11073 /* add the METADATA_BLOCK_HEADER size to the signalled size */
11075 (metadata_blocks[index + 1] << 16) +
11076 (metadata_blocks[index + 2] << 8) +
11077 metadata_blocks[index + 3];
11079 /* be careful not to read off end of box */
11080 if (block_size > remainder) {
11084 is_last = metadata_blocks[index] >> 7;
11086 block = gst_buffer_new_and_alloc (block_size);
11088 gst_buffer_fill (block, 0, &metadata_blocks[index],
11091 gst_value_set_buffer (&value, block);
11092 gst_value_array_append_value (&array, &value);
11093 g_value_reset (&value);
11095 gst_buffer_unref (block);
11097 index += block_size;
11100 /* only append the metadata if we successfully read all of it */
11102 gst_structure_set_value (gst_caps_get_structure (stream->caps,
11103 0), "streamheader", &array);
11105 GST_WARNING_OBJECT (qtdemux,
11106 "discarding all METADATA_BLOCKs due to invalid "
11107 "block_size %d at idx %d, rem %d", block_size, index,
11111 g_value_unset (&value);
11112 g_value_unset (&array);
11114 /* The sample rate obtained from the stsd may not be accurate
11115 * since it cannot represent rates greater than 65535Hz, so
11116 * override that value with the sample rate from the
11117 * METADATA_BLOCK_STREAMINFO block */
11119 (QT_UINT32 (metadata_blocks + 14) >> 12) & 0xFFFFF;
11130 gint len = QT_UINT32 (stsd_data);
11133 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x34);
11136 gst_buffer_fill (buf, 0, stsd_data + 0x34, len - 0x34);
11138 /* If we have enough data, let's try to get the 'damr' atom. See
11139 * the 3GPP container spec (26.244) for more details. */
11140 if ((len - 0x34) > 8 &&
11141 (bitrate = qtdemux_parse_amr_bitrate (buf, amrwb))) {
11142 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
11143 GST_TAG_MAXIMUM_BITRATE, bitrate, NULL);
11146 gst_caps_set_simple (stream->caps,
11147 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11148 gst_buffer_unref (buf);
11154 /* mp4a atom withtout ESDS; Attempt to build codec data from atom */
11155 gint len = QT_UINT32 (stsd_data);
11158 guint16 sound_version = QT_UINT16 (stsd_data + 32);
11160 if (sound_version == 1) {
11161 guint16 channels = QT_UINT16 (stsd_data + 40);
11162 guint32 time_scale = QT_UINT32 (stsd_data + 46);
11163 guint8 codec_data[2];
11165 gint profile = 2; /* FIXME: Can this be determined somehow? There doesn't seem to be anything in mp4a atom that specifis compression */
11167 gint sample_rate_index =
11168 gst_codec_utils_aac_get_index_from_sample_rate (time_scale);
11170 /* build AAC codec data */
11171 codec_data[0] = profile << 3;
11172 codec_data[0] |= ((sample_rate_index >> 1) & 0x7);
11173 codec_data[1] = (sample_rate_index & 0x01) << 7;
11174 codec_data[1] |= (channels & 0xF) << 3;
11176 buf = gst_buffer_new_and_alloc (2);
11177 gst_buffer_fill (buf, 0, codec_data, 2);
11178 gst_caps_set_simple (stream->caps,
11179 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11180 gst_buffer_unref (buf);
11186 GST_INFO_OBJECT (qtdemux,
11187 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
11191 GST_INFO_OBJECT (qtdemux,
11192 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
11193 GST_FOURCC_ARGS (fourcc), stream->caps);
11195 } else if (stream->subtype == FOURCC_strm) {
11196 if (fourcc == FOURCC_rtsp) {
11197 stream->redirect_uri = qtdemux_get_rtsp_uri_from_hndl (qtdemux, minf);
11199 GST_INFO_OBJECT (qtdemux, "unhandled stream type %" GST_FOURCC_FORMAT,
11200 GST_FOURCC_ARGS (fourcc));
11201 goto unknown_stream;
11203 stream->sampled = TRUE;
11204 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
11205 || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt) {
11207 stream->sampled = TRUE;
11208 stream->sparse = TRUE;
11211 qtdemux_sub_caps (qtdemux, stream, fourcc, stsd_data, &codec);
11213 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
11214 GST_TAG_SUBTITLE_CODEC, codec, NULL);
11219 /* hunt for sort-of codec data */
11223 GNode *mp4s = NULL;
11224 GNode *esds = NULL;
11226 /* look for palette in a stsd->mp4s->esds sub-atom */
11227 mp4s = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4s);
11229 esds = qtdemux_tree_get_child_by_type (mp4s, FOURCC_esds);
11230 if (esds == NULL) {
11232 GST_LOG_OBJECT (qtdemux, "Skipping invalid stsd: no esds child");
11236 gst_qtdemux_handle_esds (qtdemux, stream, esds, stream->pending_tags);
11240 GST_INFO_OBJECT (qtdemux,
11241 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
11244 GST_INFO_OBJECT (qtdemux,
11245 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
11246 GST_FOURCC_ARGS (fourcc), stream->caps);
11248 /* everything in 1 sample */
11249 stream->sampled = TRUE;
11252 qtdemux_generic_caps (qtdemux, stream, fourcc, stsd_data, &codec);
11254 if (stream->caps == NULL)
11255 goto unknown_stream;
11258 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
11259 GST_TAG_SUBTITLE_CODEC, codec, NULL);
11265 /* promote to sampled format */
11266 if (stream->fourcc == FOURCC_samr) {
11267 /* force mono 8000 Hz for AMR */
11268 stream->sampled = TRUE;
11269 stream->n_channels = 1;
11270 stream->rate = 8000;
11271 } else if (stream->fourcc == FOURCC_sawb) {
11272 /* force mono 16000 Hz for AMR-WB */
11273 stream->sampled = TRUE;
11274 stream->n_channels = 1;
11275 stream->rate = 16000;
11276 } else if (stream->fourcc == FOURCC_mp4a) {
11277 stream->sampled = TRUE;
11280 /* collect sample information */
11281 if (!qtdemux_stbl_init (qtdemux, stream, stbl))
11282 goto samples_failed;
11284 if (qtdemux->fragmented) {
11287 /* need all moov samples as basis; probably not many if any at all */
11288 /* prevent moof parsing taking of at this time */
11289 offset = qtdemux->moof_offset;
11290 qtdemux->moof_offset = 0;
11291 if (stream->n_samples &&
11292 !qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
11293 qtdemux->moof_offset = offset;
11294 goto samples_failed;
11296 qtdemux->moof_offset = 0;
11297 /* movie duration more reliable in this case (e.g. mehd) */
11298 if (qtdemux->segment.duration &&
11299 GST_CLOCK_TIME_IS_VALID (qtdemux->segment.duration))
11301 GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->segment.duration);
11304 /* configure segments */
11305 if (!qtdemux_parse_segments (qtdemux, stream, trak))
11306 goto segments_failed;
11308 /* add some language tag, if useful */
11309 if (stream->lang_id[0] != '\0' && strcmp (stream->lang_id, "unk") &&
11310 strcmp (stream->lang_id, "und")) {
11311 const gchar *lang_code;
11313 /* convert ISO 639-2 code to ISO 639-1 */
11314 lang_code = gst_tag_get_language_code (stream->lang_id);
11315 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
11316 GST_TAG_LANGUAGE_CODE, (lang_code) ? lang_code : stream->lang_id, NULL);
11319 /* Check for UDTA tags */
11320 if ((udta = qtdemux_tree_get_child_by_type (trak, FOURCC_udta))) {
11321 qtdemux_parse_udta (qtdemux, stream->pending_tags, udta);
11324 /* now we are ready to add the stream */
11325 if (qtdemux->n_streams >= GST_QTDEMUX_MAX_STREAMS)
11326 goto too_many_streams;
11328 if (!qtdemux->got_moov) {
11329 qtdemux->streams[qtdemux->n_streams] = stream;
11330 qtdemux->n_streams++;
11331 GST_DEBUG_OBJECT (qtdemux, "n_streams is now %d", qtdemux->n_streams);
11339 GST_INFO_OBJECT (qtdemux, "skip disabled track");
11341 gst_qtdemux_stream_free (qtdemux, stream);
11346 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
11347 (_("This file is corrupt and cannot be played.")), (NULL));
11349 gst_qtdemux_stream_free (qtdemux, stream);
11354 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT, (NULL), (NULL));
11356 gst_qtdemux_stream_free (qtdemux, stream);
11362 /* we posted an error already */
11363 /* free stbl sub-atoms */
11364 gst_qtdemux_stbl_free (stream);
11366 gst_qtdemux_stream_free (qtdemux, stream);
11371 GST_INFO_OBJECT (qtdemux, "stream with track id %i already exists",
11374 gst_qtdemux_stream_free (qtdemux, stream);
11379 GST_INFO_OBJECT (qtdemux, "unknown subtype %" GST_FOURCC_FORMAT,
11380 GST_FOURCC_ARGS (stream->subtype));
11382 gst_qtdemux_stream_free (qtdemux, stream);
11387 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
11388 (_("This file contains too many streams. Only playing first %d"),
11389 GST_QTDEMUX_MAX_STREAMS), (NULL));
11394 /* If we can estimate the overall bitrate, and don't have information about the
11395 * stream bitrate for exactly one stream, this guesses the stream bitrate as
11396 * the overall bitrate minus the sum of the bitrates of all other streams. This
11397 * should be useful for the common case where we have one audio and one video
11398 * stream and can estimate the bitrate of one, but not the other. */
11400 gst_qtdemux_guess_bitrate (GstQTDemux * qtdemux)
11402 QtDemuxStream *stream = NULL;
11403 gint64 size, sys_bitrate, sum_bitrate = 0;
11404 GstClockTime duration;
11408 if (qtdemux->fragmented)
11411 GST_DEBUG_OBJECT (qtdemux, "Looking for streams with unknown bitrate");
11413 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &size)
11415 GST_DEBUG_OBJECT (qtdemux,
11416 "Size in bytes of the stream not known - bailing");
11420 /* Subtract the header size */
11421 GST_DEBUG_OBJECT (qtdemux, "Total size %" G_GINT64_FORMAT ", header size %u",
11422 size, qtdemux->header_size);
11424 if (size < qtdemux->header_size)
11427 size = size - qtdemux->header_size;
11429 if (!gst_qtdemux_get_duration (qtdemux, &duration)) {
11430 GST_DEBUG_OBJECT (qtdemux, "Stream duration not known - bailing");
11434 for (i = 0; i < qtdemux->n_streams; i++) {
11435 switch (qtdemux->streams[i]->subtype) {
11438 GST_DEBUG_OBJECT (qtdemux, "checking bitrate for %" GST_PTR_FORMAT,
11439 qtdemux->streams[i]->caps);
11440 /* retrieve bitrate, prefer avg then max */
11442 if (qtdemux->streams[i]->pending_tags) {
11443 gst_tag_list_get_uint (qtdemux->streams[i]->pending_tags,
11444 GST_TAG_MAXIMUM_BITRATE, &bitrate);
11445 GST_DEBUG_OBJECT (qtdemux, "max-bitrate: %u", bitrate);
11446 gst_tag_list_get_uint (qtdemux->streams[i]->pending_tags,
11447 GST_TAG_NOMINAL_BITRATE, &bitrate);
11448 GST_DEBUG_OBJECT (qtdemux, "nominal-bitrate: %u", bitrate);
11449 gst_tag_list_get_uint (qtdemux->streams[i]->pending_tags,
11450 GST_TAG_BITRATE, &bitrate);
11451 GST_DEBUG_OBJECT (qtdemux, "bitrate: %u", bitrate);
11454 sum_bitrate += bitrate;
11457 GST_DEBUG_OBJECT (qtdemux,
11458 ">1 stream with unknown bitrate - bailing");
11461 stream = qtdemux->streams[i];
11465 /* For other subtypes, we assume no significant impact on bitrate */
11471 GST_DEBUG_OBJECT (qtdemux, "All stream bitrates are known");
11475 sys_bitrate = gst_util_uint64_scale (size, GST_SECOND * 8, duration);
11477 if (sys_bitrate < sum_bitrate) {
11478 /* This can happen, since sum_bitrate might be derived from maximum
11479 * bitrates and not average bitrates */
11480 GST_DEBUG_OBJECT (qtdemux,
11481 "System bitrate less than sum bitrate - bailing");
11485 bitrate = sys_bitrate - sum_bitrate;
11486 GST_DEBUG_OBJECT (qtdemux, "System bitrate = %" G_GINT64_FORMAT
11487 ", Stream bitrate = %u", sys_bitrate, bitrate);
11489 if (!stream->pending_tags)
11490 stream->pending_tags = gst_tag_list_new_empty ();
11492 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
11493 GST_TAG_BITRATE, bitrate, NULL);
11496 static GstFlowReturn
11497 qtdemux_prepare_streams (GstQTDemux * qtdemux)
11500 GstFlowReturn ret = GST_FLOW_OK;
11502 GST_DEBUG_OBJECT (qtdemux, "prepare streams");
11504 for (i = 0; ret == GST_FLOW_OK && i < qtdemux->n_streams; i++) {
11505 QtDemuxStream *stream = qtdemux->streams[i];
11506 guint32 sample_num = 0;
11508 GST_DEBUG_OBJECT (qtdemux, "stream %d, id %d, fourcc %" GST_FOURCC_FORMAT,
11509 i, stream->track_id, GST_FOURCC_ARGS (stream->fourcc));
11511 if (qtdemux->fragmented) {
11512 /* need all moov samples first */
11513 GST_OBJECT_LOCK (qtdemux);
11514 while (stream->n_samples == 0)
11515 if ((ret = qtdemux_add_fragmented_samples (qtdemux)) != GST_FLOW_OK)
11517 GST_OBJECT_UNLOCK (qtdemux);
11519 /* discard any stray moof */
11520 qtdemux->moof_offset = 0;
11523 /* prepare braking */
11524 if (ret != GST_FLOW_ERROR)
11527 /* in pull mode, we should have parsed some sample info by now;
11528 * and quite some code will not handle no samples.
11529 * in push mode, we'll just have to deal with it */
11530 if (G_UNLIKELY (qtdemux->pullbased && !stream->n_samples)) {
11531 GST_DEBUG_OBJECT (qtdemux, "no samples for stream; discarding");
11532 gst_qtdemux_remove_stream (qtdemux, i);
11537 /* parse the initial sample for use in setting the frame rate cap */
11538 while (sample_num == 0 && sample_num < stream->n_samples) {
11539 if (!qtdemux_parse_samples (qtdemux, stream, sample_num))
11543 if (stream->n_samples > 0 && stream->stbl_index >= 0) {
11544 stream->first_duration = stream->samples[0].duration;
11545 GST_LOG_OBJECT (qtdemux, "stream %d first duration %u",
11546 stream->track_id, stream->first_duration);
11553 static GstFlowReturn
11554 qtdemux_expose_streams (GstQTDemux * qtdemux)
11557 GSList *oldpads = NULL;
11560 GST_DEBUG_OBJECT (qtdemux, "exposing streams");
11562 for (i = 0; i < qtdemux->n_streams; i++) {
11563 QtDemuxStream *stream = qtdemux->streams[i];
11564 GstPad *oldpad = stream->pad;
11567 GST_DEBUG_OBJECT (qtdemux, "stream %d, id %d, fourcc %" GST_FOURCC_FORMAT,
11568 i, stream->track_id, GST_FOURCC_ARGS (stream->fourcc));
11570 if ((stream->subtype == FOURCC_text || stream->subtype == FOURCC_sbtl) &&
11571 stream->track_id == qtdemux->chapters_track_id) {
11572 /* TODO - parse chapters track and expose it as GstToc; For now just ignore it
11573 so that it doesn't look like a subtitle track */
11574 gst_qtdemux_remove_stream (qtdemux, i);
11579 /* now we have all info and can expose */
11580 list = stream->pending_tags;
11581 stream->pending_tags = NULL;
11583 oldpads = g_slist_prepend (oldpads, oldpad);
11584 if (!gst_qtdemux_add_stream (qtdemux, stream, list))
11585 return GST_FLOW_ERROR;
11588 gst_qtdemux_guess_bitrate (qtdemux);
11590 gst_element_no_more_pads (GST_ELEMENT_CAST (qtdemux));
11592 for (iter = oldpads; iter; iter = g_slist_next (iter)) {
11593 GstPad *oldpad = iter->data;
11596 event = gst_event_new_eos ();
11597 if (qtdemux->segment_seqnum)
11598 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
11600 gst_pad_push_event (oldpad, event);
11601 gst_pad_set_active (oldpad, FALSE);
11602 gst_element_remove_pad (GST_ELEMENT (qtdemux), oldpad);
11603 gst_flow_combiner_remove_pad (qtdemux->flowcombiner, oldpad);
11604 gst_object_unref (oldpad);
11607 /* check if we should post a redirect in case there is a single trak
11608 * and it is a redirecting trak */
11609 if (qtdemux->n_streams == 1 && qtdemux->streams[0]->redirect_uri != NULL) {
11612 GST_INFO_OBJECT (qtdemux, "Issuing a redirect due to a single track with "
11613 "an external content");
11614 m = gst_message_new_element (GST_OBJECT_CAST (qtdemux),
11615 gst_structure_new ("redirect",
11616 "new-location", G_TYPE_STRING, qtdemux->streams[0]->redirect_uri,
11618 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), m);
11619 qtdemux->posted_redirect = TRUE;
11622 for (i = 0; i < qtdemux->n_streams; i++) {
11623 QtDemuxStream *stream = qtdemux->streams[i];
11625 qtdemux_do_allocation (qtdemux, stream);
11628 qtdemux->exposed = TRUE;
11629 return GST_FLOW_OK;
11632 /* check if major or compatible brand is 3GP */
11633 static inline gboolean
11634 qtdemux_is_brand_3gp (GstQTDemux * qtdemux, gboolean major)
11637 return ((qtdemux->major_brand & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
11639 } else if (qtdemux->comp_brands != NULL) {
11643 gboolean res = FALSE;
11645 gst_buffer_map (qtdemux->comp_brands, &map, GST_MAP_READ);
11648 while (size >= 4) {
11649 res = res || ((QT_FOURCC (data) & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
11654 gst_buffer_unmap (qtdemux->comp_brands, &map);
11661 /* check if tag is a spec'ed 3GP tag keyword storing a string */
11662 static inline gboolean
11663 qtdemux_is_string_tag_3gp (GstQTDemux * qtdemux, guint32 fourcc)
11665 return fourcc == FOURCC_cprt || fourcc == FOURCC_gnre || fourcc == FOURCC_titl
11666 || fourcc == FOURCC_dscp || fourcc == FOURCC_perf || fourcc == FOURCC_auth
11667 || fourcc == FOURCC_albm;
11671 qtdemux_tag_add_location (GstQTDemux * qtdemux, GstTagList * taglist,
11672 const char *tag, const char *dummy, GNode * node)
11674 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
11678 gdouble longitude, latitude, altitude;
11681 len = QT_UINT32 (node->data);
11688 /* TODO: language code skipped */
11690 name = gst_tag_freeform_string_to_utf8 (data + offset, -1, env_vars);
11693 /* do not alarm in trivial case, but bail out otherwise */
11694 if (*(data + offset) != 0) {
11695 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8, "
11699 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
11700 GST_TAG_GEO_LOCATION_NAME, name, NULL);
11701 offset += strlen (name);
11705 if (len < offset + 2 + 4 + 4 + 4)
11708 /* +1 +1 = skip null-terminator and location role byte */
11710 /* table in spec says unsigned, semantics say negative has meaning ... */
11711 longitude = QT_SFP32 (data + offset);
11714 latitude = QT_SFP32 (data + offset);
11717 altitude = QT_SFP32 (data + offset);
11719 /* one invalid means all are invalid */
11720 if (longitude >= -180.0 && longitude <= 180.0 &&
11721 latitude >= -90.0 && latitude <= 90.0) {
11722 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
11723 GST_TAG_GEO_LOCATION_LATITUDE, latitude,
11724 GST_TAG_GEO_LOCATION_LONGITUDE, longitude,
11725 GST_TAG_GEO_LOCATION_ELEVATION, altitude, NULL);
11728 /* TODO: no GST_TAG_, so astronomical body and additional notes skipped */
11735 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP location");
11742 qtdemux_tag_add_year (GstQTDemux * qtdemux, GstTagList * taglist,
11743 const char *tag, const char *dummy, GNode * node)
11749 len = QT_UINT32 (node->data);
11753 y = QT_UINT16 ((guint8 *) node->data + 12);
11755 GST_DEBUG_OBJECT (qtdemux, "year: %u is not a valid year", y);
11758 GST_DEBUG_OBJECT (qtdemux, "year: %u", y);
11760 date = g_date_new_dmy (1, 1, y);
11761 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, date, NULL);
11762 g_date_free (date);
11766 qtdemux_tag_add_classification (GstQTDemux * qtdemux, GstTagList * taglist,
11767 const char *tag, const char *dummy, GNode * node)
11770 char *tag_str = NULL;
11775 len = QT_UINT32 (node->data);
11780 entity = (guint8 *) node->data + offset;
11781 if (entity[0] == 0 || entity[1] == 0 || entity[2] == 0 || entity[3] == 0) {
11782 GST_DEBUG_OBJECT (qtdemux,
11783 "classification info: %c%c%c%c invalid classification entity",
11784 entity[0], entity[1], entity[2], entity[3]);
11789 table = QT_UINT16 ((guint8 *) node->data + offset);
11791 /* Language code skipped */
11795 /* Tag format: "XXXX://Y[YYYY]/classification info string"
11796 * XXXX: classification entity, fixed length 4 chars.
11797 * Y[YYYY]: classification table, max 5 chars.
11799 tag_str = g_strdup_printf ("----://%u/%s",
11800 table, (char *) node->data + offset);
11802 /* memcpy To be sure we're preserving byte order */
11803 memcpy (tag_str, entity, 4);
11804 GST_DEBUG_OBJECT (qtdemux, "classification info: %s", tag_str);
11806 gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND, tag, tag_str, NULL);
11815 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP classification");
11821 qtdemux_tag_add_str_full (GstQTDemux * qtdemux, GstTagList * taglist,
11822 const char *tag, const char *dummy, GNode * node)
11824 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
11830 gboolean ret = TRUE;
11831 const gchar *charset = NULL;
11833 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
11835 len = QT_UINT32 (data->data);
11836 type = QT_UINT32 ((guint8 *) data->data + 8);
11837 if (type == 0x00000001 && len > 16) {
11838 s = gst_tag_freeform_string_to_utf8 ((char *) data->data + 16, len - 16,
11841 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
11842 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, s, NULL);
11845 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
11849 len = QT_UINT32 (node->data);
11850 type = QT_UINT32 ((guint8 *) node->data + 4);
11851 if ((type >> 24) == 0xa9 && len > 8 + 4) {
11855 /* Type starts with the (C) symbol, so the next data is a list
11856 * of (string size(16), language code(16), string) */
11858 str_len = QT_UINT16 ((guint8 *) node->data + 8);
11859 lang_code = QT_UINT16 ((guint8 *) node->data + 10);
11861 /* the string + fourcc + size + 2 16bit fields,
11862 * means that there are more tags in this atom */
11863 if (len > str_len + 8 + 4) {
11864 /* TODO how to represent the same tag in different languages? */
11865 GST_WARNING_OBJECT (qtdemux, "Ignoring metadata entry with multiple "
11866 "text alternatives, reading only first one");
11870 len = MIN (len, str_len + 8 + 4); /* remove trailing strings that we don't use */
11871 GST_DEBUG_OBJECT (qtdemux, "found international text tag");
11873 if (lang_code < 0x800) { /* MAC encoded string */
11876 } else if (len > 14 && qtdemux_is_string_tag_3gp (qtdemux,
11877 QT_FOURCC ((guint8 *) node->data + 4))) {
11878 guint32 type = QT_UINT32 ((guint8 *) node->data + 8);
11880 /* we go for 3GP style encoding if major brands claims so,
11881 * or if no hope for data be ok UTF-8, and compatible 3GP brand present */
11882 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
11883 (qtdemux_is_brand_3gp (qtdemux, FALSE) &&
11884 ((type & 0x00FFFFFF) == 0x0) && (type >> 24 <= 0xF))) {
11886 /* 16-bit Language code is ignored here as well */
11887 GST_DEBUG_OBJECT (qtdemux, "found 3gpp text tag");
11894 GST_DEBUG_OBJECT (qtdemux, "found normal text tag");
11895 ret = FALSE; /* may have to fallback */
11898 GError *err = NULL;
11900 s = g_convert ((gchar *) node->data + offset, len - offset, "utf8",
11901 charset, NULL, NULL, &err);
11903 GST_DEBUG_OBJECT (qtdemux, "Failed to convert string from charset %s:"
11904 " %s(%d): %s", charset, g_quark_to_string (err->domain), err->code,
11906 g_error_free (err);
11909 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
11910 len - offset, env_vars);
11913 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
11914 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, s, NULL);
11918 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
11925 qtdemux_tag_add_str (GstQTDemux * qtdemux, GstTagList * taglist,
11926 const char *tag, const char *dummy, GNode * node)
11928 qtdemux_tag_add_str_full (qtdemux, taglist, tag, dummy, node);
11932 qtdemux_tag_add_keywords (GstQTDemux * qtdemux, GstTagList * taglist,
11933 const char *tag, const char *dummy, GNode * node)
11935 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
11937 char *s, *t, *k = NULL;
11942 /* first try normal string tag if major brand not 3GP */
11943 if (!qtdemux_is_brand_3gp (qtdemux, TRUE)) {
11944 if (!qtdemux_tag_add_str_full (qtdemux, taglist, tag, dummy, node)) {
11945 /* hm, that did not work, maybe 3gpp storage in non-3gpp major brand;
11946 * let's try it 3gpp way after minor safety check */
11948 if (QT_UINT32 (data) < 15 || !qtdemux_is_brand_3gp (qtdemux, FALSE))
11954 GST_DEBUG_OBJECT (qtdemux, "found 3gpp keyword tag");
11958 len = QT_UINT32 (data);
11962 count = QT_UINT8 (data + 14);
11964 for (; count; count--) {
11967 if (offset + 1 > len)
11969 slen = QT_UINT8 (data + offset);
11971 if (offset + slen > len)
11973 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
11976 GST_DEBUG_OBJECT (qtdemux, "adding keyword %s", GST_STR_NULL (s));
11978 t = g_strjoin (",", k, s, NULL);
11986 GST_DEBUG_OBJECT (qtdemux, "failed to convert keyword to UTF-8");
11993 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (k));
11994 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, k, NULL);
12003 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP keywords");
12009 qtdemux_tag_add_num (GstQTDemux * qtdemux, GstTagList * taglist,
12010 const char *tag1, const char *tag2, GNode * node)
12017 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12019 len = QT_UINT32 (data->data);
12020 type = QT_UINT32 ((guint8 *) data->data + 8);
12021 if (type == 0x00000000 && len >= 22) {
12022 n1 = QT_UINT16 ((guint8 *) data->data + 18);
12023 n2 = QT_UINT16 ((guint8 *) data->data + 20);
12025 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag1, n1);
12026 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, n1, NULL);
12029 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag2, n2);
12030 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag2, n2, NULL);
12037 qtdemux_tag_add_tmpo (GstQTDemux * qtdemux, GstTagList * taglist,
12038 const char *tag1, const char *dummy, GNode * node)
12045 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12047 len = QT_UINT32 (data->data);
12048 type = QT_UINT32 ((guint8 *) data->data + 8);
12049 GST_DEBUG_OBJECT (qtdemux, "have tempo tag, type=%d,len=%d", type, len);
12050 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
12051 if ((type == 0x00000015 || type == 0x0000000f) && len >= 18) {
12052 n1 = QT_UINT16 ((guint8 *) data->data + 16);
12054 /* do not add bpm=0 */
12055 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", n1);
12056 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, (gdouble) n1,
12064 qtdemux_tag_add_uint32 (GstQTDemux * qtdemux, GstTagList * taglist,
12065 const char *tag1, const char *dummy, GNode * node)
12072 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12074 len = QT_UINT32 (data->data);
12075 type = QT_UINT32 ((guint8 *) data->data + 8);
12076 GST_DEBUG_OBJECT (qtdemux, "have %s tag, type=%d,len=%d", tag1, type, len);
12077 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
12078 if ((type == 0x00000015 || type == 0x0000000f) && len >= 20) {
12079 num = QT_UINT32 ((guint8 *) data->data + 16);
12081 /* do not add num=0 */
12082 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", num);
12083 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, num, NULL);
12090 qtdemux_tag_add_covr (GstQTDemux * qtdemux, GstTagList * taglist,
12091 const char *tag1, const char *dummy, GNode * node)
12098 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12100 len = QT_UINT32 (data->data);
12101 type = QT_UINT32 ((guint8 *) data->data + 8);
12102 GST_DEBUG_OBJECT (qtdemux, "have covr tag, type=%d,len=%d", type, len);
12103 if ((type == 0x0000000d || type == 0x0000000e) && len > 16) {
12105 gst_tag_image_data_to_image_sample ((guint8 *) data->data + 16,
12106 len - 16, GST_TAG_IMAGE_TYPE_NONE))) {
12107 GST_DEBUG_OBJECT (qtdemux, "adding tag size %d", len - 16);
12108 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, sample, NULL);
12109 gst_sample_unref (sample);
12116 qtdemux_tag_add_date (GstQTDemux * qtdemux, GstTagList * taglist,
12117 const char *tag, const char *dummy, GNode * node)
12124 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12126 len = QT_UINT32 (data->data);
12127 type = QT_UINT32 ((guint8 *) data->data + 8);
12128 if (type == 0x00000001 && len > 16) {
12129 guint y, m = 1, d = 1;
12132 s = g_strndup ((char *) data->data + 16, len - 16);
12133 GST_DEBUG_OBJECT (qtdemux, "adding date '%s'", s);
12134 ret = sscanf (s, "%u-%u-%u", &y, &m, &d);
12135 if (ret >= 1 && y > 1500 && y < 3000) {
12138 date = g_date_new_dmy (d, m, y);
12139 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, date, NULL);
12140 g_date_free (date);
12142 GST_DEBUG_OBJECT (qtdemux, "could not parse date string '%s'", s);
12150 qtdemux_tag_add_gnre (GstQTDemux * qtdemux, GstTagList * taglist,
12151 const char *tag, const char *dummy, GNode * node)
12155 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12157 /* re-route to normal string tag if major brand says so
12158 * or no data atom and compatible brand suggests so */
12159 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
12160 (qtdemux_is_brand_3gp (qtdemux, FALSE) && !data)) {
12161 qtdemux_tag_add_str (qtdemux, taglist, tag, dummy, node);
12166 guint len, type, n;
12168 len = QT_UINT32 (data->data);
12169 type = QT_UINT32 ((guint8 *) data->data + 8);
12170 if (type == 0x00000000 && len >= 18) {
12171 n = QT_UINT16 ((guint8 *) data->data + 16);
12173 const gchar *genre;
12175 genre = gst_tag_id3_genre_get (n - 1);
12176 if (genre != NULL) {
12177 GST_DEBUG_OBJECT (qtdemux, "adding %d [%s]", n, genre);
12178 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, genre, NULL);
12186 qtdemux_add_double_tag_from_str (GstQTDemux * demux, GstTagList * taglist,
12187 const gchar * tag, guint8 * data, guint32 datasize)
12192 /* make a copy to have \0 at the end */
12193 datacopy = g_strndup ((gchar *) data, datasize);
12195 /* convert the str to double */
12196 if (sscanf (datacopy, "%lf", &value) == 1) {
12197 GST_DEBUG_OBJECT (demux, "adding tag: %s [%s]", tag, datacopy);
12198 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, value, NULL);
12200 GST_WARNING_OBJECT (demux, "Failed to parse double from string: %s",
12208 qtdemux_tag_add_revdns (GstQTDemux * demux, GstTagList * taglist,
12209 const char *tag, const char *tag_bis, GNode * node)
12218 const gchar *meanstr;
12219 const gchar *namestr;
12221 /* checking the whole ---- atom size for consistency */
12222 if (QT_UINT32 (node->data) <= 4 + 12 + 12 + 16) {
12223 GST_WARNING_OBJECT (demux, "Tag ---- atom is too small, ignoring");
12227 mean = qtdemux_tree_get_child_by_type (node, FOURCC_mean);
12229 GST_WARNING_OBJECT (demux, "No 'mean' atom found");
12233 meansize = QT_UINT32 (mean->data);
12234 if (meansize <= 12) {
12235 GST_WARNING_OBJECT (demux, "Small mean atom, ignoring the whole tag");
12238 meanstr = ((gchar *) mean->data) + 12;
12241 name = qtdemux_tree_get_child_by_type (node, FOURCC_name);
12243 GST_WARNING_OBJECT (demux, "'name' atom not found, ignoring tag");
12247 namesize = QT_UINT32 (name->data);
12248 if (namesize <= 12) {
12249 GST_WARNING_OBJECT (demux, "'name' atom is too small, ignoring tag");
12252 namestr = ((gchar *) name->data) + 12;
12260 * uint24 - data type
12264 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12266 GST_WARNING_OBJECT (demux, "No data atom in this tag");
12269 datasize = QT_UINT32 (data->data);
12270 if (datasize <= 16) {
12271 GST_WARNING_OBJECT (demux, "Data atom too small");
12274 datatype = QT_UINT32 (((gchar *) data->data) + 8) & 0xFFFFFF;
12276 if ((strncmp (meanstr, "com.apple.iTunes", meansize) == 0) ||
12277 (strncmp (meanstr, "org.hydrogenaudio.replaygain", meansize) == 0)) {
12278 static const struct
12280 const gchar name[28];
12281 const gchar tag[28];
12284 "replaygain_track_gain", GST_TAG_TRACK_GAIN}, {
12285 "replaygain_track_peak", GST_TAG_TRACK_PEAK}, {
12286 "replaygain_album_gain", GST_TAG_ALBUM_GAIN}, {
12287 "replaygain_album_peak", GST_TAG_ALBUM_PEAK}, {
12288 "MusicBrainz Track Id", GST_TAG_MUSICBRAINZ_TRACKID}, {
12289 "MusicBrainz Artist Id", GST_TAG_MUSICBRAINZ_ARTISTID}, {
12290 "MusicBrainz Album Id", GST_TAG_MUSICBRAINZ_ALBUMID}, {
12291 "MusicBrainz Album Artist Id", GST_TAG_MUSICBRAINZ_ALBUMARTISTID}
12295 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
12296 if (!g_ascii_strncasecmp (tags[i].name, namestr, namesize)) {
12297 switch (gst_tag_get_type (tags[i].tag)) {
12298 case G_TYPE_DOUBLE:
12299 qtdemux_add_double_tag_from_str (demux, taglist, tags[i].tag,
12300 ((guint8 *) data->data) + 16, datasize - 16);
12302 case G_TYPE_STRING:
12303 qtdemux_tag_add_str (demux, taglist, tags[i].tag, NULL, node);
12312 if (i == G_N_ELEMENTS (tags))
12322 #ifndef GST_DISABLE_GST_DEBUG
12324 gchar *namestr_dbg;
12325 gchar *meanstr_dbg;
12327 meanstr_dbg = g_strndup (meanstr, meansize);
12328 namestr_dbg = g_strndup (namestr, namesize);
12330 GST_WARNING_OBJECT (demux, "This tag %s:%s type:%u is not mapped, "
12331 "file a bug at bugzilla.gnome.org", meanstr_dbg, namestr_dbg, datatype);
12333 g_free (namestr_dbg);
12334 g_free (meanstr_dbg);
12341 qtdemux_tag_add_id32 (GstQTDemux * demux, GstTagList * taglist, const char *tag,
12342 const char *tag_bis, GNode * node)
12347 GstTagList *id32_taglist = NULL;
12349 GST_LOG_OBJECT (demux, "parsing ID32");
12352 len = GST_READ_UINT32_BE (data);
12354 /* need at least full box and language tag */
12358 buf = gst_buffer_new_allocate (NULL, len - 14, NULL);
12359 gst_buffer_fill (buf, 0, data + 14, len - 14);
12361 id32_taglist = gst_tag_list_from_id3v2_tag (buf);
12362 if (id32_taglist) {
12363 GST_LOG_OBJECT (demux, "parsing ok");
12364 gst_tag_list_insert (taglist, id32_taglist, GST_TAG_MERGE_KEEP);
12365 gst_tag_list_unref (id32_taglist);
12367 GST_LOG_OBJECT (demux, "parsing failed");
12370 gst_buffer_unref (buf);
12373 typedef void (*GstQTDemuxAddTagFunc) (GstQTDemux * demux, GstTagList * taglist,
12374 const char *tag, const char *tag_bis, GNode * node);
12377 FOURCC_pcst -> if media is a podcast -> bool
12378 FOURCC_cpil -> if media is part of a compilation -> bool
12379 FOURCC_pgap -> if media is part of a gapless context -> bool
12380 FOURCC_tven -> the tv episode id e.g. S01E23 -> str
12383 static const struct
12386 const gchar *gst_tag;
12387 const gchar *gst_tag_bis;
12388 const GstQTDemuxAddTagFunc func;
12391 FOURCC__nam, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
12392 FOURCC_titl, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
12393 FOURCC__grp, GST_TAG_GROUPING, NULL, qtdemux_tag_add_str}, {
12394 FOURCC__wrt, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
12395 FOURCC__ART, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
12396 FOURCC_aART, GST_TAG_ALBUM_ARTIST, NULL, qtdemux_tag_add_str}, {
12397 FOURCC_perf, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
12398 FOURCC_auth, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
12399 FOURCC__alb, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
12400 FOURCC_albm, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
12401 FOURCC_cprt, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
12402 FOURCC__cpy, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
12403 FOURCC__cmt, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
12404 FOURCC__des, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
12405 FOURCC_desc, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
12406 FOURCC_dscp, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
12407 FOURCC__lyr, GST_TAG_LYRICS, NULL, qtdemux_tag_add_str}, {
12408 FOURCC__day, GST_TAG_DATE, NULL, qtdemux_tag_add_date}, {
12409 FOURCC_yrrc, GST_TAG_DATE, NULL, qtdemux_tag_add_year}, {
12410 FOURCC__too, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
12411 FOURCC__inf, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
12412 FOURCC_trkn, GST_TAG_TRACK_NUMBER, GST_TAG_TRACK_COUNT, qtdemux_tag_add_num}, {
12413 FOURCC_disk, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
12414 qtdemux_tag_add_num}, {
12415 FOURCC_disc, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
12416 qtdemux_tag_add_num}, {
12417 FOURCC__gen, GST_TAG_GENRE, NULL, qtdemux_tag_add_str}, {
12418 FOURCC_gnre, GST_TAG_GENRE, NULL, qtdemux_tag_add_gnre}, {
12419 FOURCC_tmpo, GST_TAG_BEATS_PER_MINUTE, NULL, qtdemux_tag_add_tmpo}, {
12420 FOURCC_covr, GST_TAG_PREVIEW_IMAGE, NULL, qtdemux_tag_add_covr}, {
12421 FOURCC_sonm, GST_TAG_TITLE_SORTNAME, NULL, qtdemux_tag_add_str}, {
12422 FOURCC_soal, GST_TAG_ALBUM_SORTNAME, NULL, qtdemux_tag_add_str}, {
12423 FOURCC_soar, GST_TAG_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
12424 FOURCC_soaa, GST_TAG_ALBUM_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
12425 FOURCC_soco, GST_TAG_COMPOSER_SORTNAME, NULL, qtdemux_tag_add_str}, {
12426 FOURCC_sosn, GST_TAG_SHOW_SORTNAME, NULL, qtdemux_tag_add_str}, {
12427 FOURCC_tvsh, GST_TAG_SHOW_NAME, NULL, qtdemux_tag_add_str}, {
12428 FOURCC_tvsn, GST_TAG_SHOW_SEASON_NUMBER, NULL, qtdemux_tag_add_uint32}, {
12429 FOURCC_tves, GST_TAG_SHOW_EPISODE_NUMBER, NULL, qtdemux_tag_add_uint32}, {
12430 FOURCC_kywd, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_keywords}, {
12431 FOURCC_keyw, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_str}, {
12432 FOURCC__enc, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
12433 FOURCC_loci, GST_TAG_GEO_LOCATION_NAME, NULL, qtdemux_tag_add_location}, {
12434 FOURCC_clsf, GST_QT_DEMUX_CLASSIFICATION_TAG, NULL,
12435 qtdemux_tag_add_classification}, {
12436 FOURCC__mak, GST_TAG_DEVICE_MANUFACTURER, NULL, qtdemux_tag_add_str}, {
12437 FOURCC__mod, GST_TAG_DEVICE_MODEL, NULL, qtdemux_tag_add_str}, {
12438 FOURCC__swr, GST_TAG_APPLICATION_NAME, NULL, qtdemux_tag_add_str}, {
12440 /* This is a special case, some tags are stored in this
12441 * 'reverse dns naming', according to:
12442 * http://atomicparsley.sourceforge.net/mpeg-4files.html and
12445 FOURCC_____, "", NULL, qtdemux_tag_add_revdns}, {
12446 /* see http://www.mp4ra.org/specs.html for ID32 in meta box */
12447 FOURCC_ID32, "", NULL, qtdemux_tag_add_id32}
12450 struct _GstQtDemuxTagList
12453 GstTagList *taglist;
12455 typedef struct _GstQtDemuxTagList GstQtDemuxTagList;
12458 qtdemux_tag_add_blob (GNode * node, GstQtDemuxTagList * qtdemuxtaglist)
12464 const gchar *style;
12469 GstQTDemux *demux = qtdemuxtaglist->demux;
12470 GstTagList *taglist = qtdemuxtaglist->taglist;
12473 len = QT_UINT32 (data);
12474 buf = gst_buffer_new_and_alloc (len);
12475 gst_buffer_fill (buf, 0, data, len);
12477 /* heuristic to determine style of tag */
12478 if (QT_FOURCC (data + 4) == FOURCC_____ ||
12479 (len > 8 + 12 && QT_FOURCC (data + 12) == FOURCC_data))
12481 else if (demux->major_brand == FOURCC_qt__)
12482 style = "quicktime";
12483 /* fall back to assuming iso/3gp tag style */
12487 /* santize the name for the caps. */
12488 for (i = 0; i < 4; i++) {
12489 guint8 d = data[4 + i];
12490 if (g_ascii_isalnum (d))
12491 ndata[i] = g_ascii_tolower (d);
12496 media_type = g_strdup_printf ("application/x-gst-qt-%c%c%c%c-tag",
12497 ndata[0], ndata[1], ndata[2], ndata[3]);
12498 GST_DEBUG_OBJECT (demux, "media type %s", media_type);
12500 s = gst_structure_new (media_type, "style", G_TYPE_STRING, style, NULL);
12501 sample = gst_sample_new (buf, NULL, NULL, s);
12502 gst_buffer_unref (buf);
12503 g_free (media_type);
12505 GST_DEBUG_OBJECT (demux, "adding private tag; size %d, info %" GST_PTR_FORMAT,
12508 gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND,
12509 GST_QT_DEMUX_PRIVATE_TAG, sample, NULL);
12511 gst_sample_unref (sample);
12515 qtdemux_parse_udta (GstQTDemux * qtdemux, GstTagList * taglist, GNode * udta)
12522 GstQtDemuxTagList demuxtaglist;
12524 demuxtaglist.demux = qtdemux;
12525 demuxtaglist.taglist = taglist;
12527 meta = qtdemux_tree_get_child_by_type (udta, FOURCC_meta);
12528 if (meta != NULL) {
12529 ilst = qtdemux_tree_get_child_by_type (meta, FOURCC_ilst);
12530 if (ilst == NULL) {
12531 GST_LOG_OBJECT (qtdemux, "no ilst");
12536 GST_LOG_OBJECT (qtdemux, "no meta so using udta itself");
12540 while (i < G_N_ELEMENTS (add_funcs)) {
12541 node = qtdemux_tree_get_child_by_type (ilst, add_funcs[i].fourcc);
12545 len = QT_UINT32 (node->data);
12547 GST_DEBUG_OBJECT (qtdemux, "too small tag atom %" GST_FOURCC_FORMAT,
12548 GST_FOURCC_ARGS (add_funcs[i].fourcc));
12550 add_funcs[i].func (qtdemux, taglist, add_funcs[i].gst_tag,
12551 add_funcs[i].gst_tag_bis, node);
12553 g_node_destroy (node);
12559 /* parsed nodes have been removed, pass along remainder as blob */
12560 g_node_children_foreach (ilst, G_TRAVERSE_ALL,
12561 (GNodeForeachFunc) qtdemux_tag_add_blob, &demuxtaglist);
12563 /* parse up XMP_ node if existing */
12564 xmp_ = qtdemux_tree_get_child_by_type (udta, FOURCC_XMP_);
12565 if (xmp_ != NULL) {
12567 GstTagList *xmptaglist;
12569 buf = _gst_buffer_new_wrapped (((guint8 *) xmp_->data) + 8,
12570 QT_UINT32 ((guint8 *) xmp_->data) - 8, NULL);
12571 xmptaglist = gst_tag_list_from_xmp_buffer (buf);
12572 gst_buffer_unref (buf);
12574 qtdemux_handle_xmp_taglist (qtdemux, taglist, xmptaglist);
12576 GST_DEBUG_OBJECT (qtdemux, "No XMP_ node found");
12582 GstStructure *structure; /* helper for sort function */
12584 guint min_req_bitrate;
12585 guint min_req_qt_version;
12589 qtdemux_redirects_sort_func (gconstpointer a, gconstpointer b)
12591 GstQtReference *ref_a = (GstQtReference *) a;
12592 GstQtReference *ref_b = (GstQtReference *) b;
12594 if (ref_b->min_req_qt_version != ref_a->min_req_qt_version)
12595 return ref_b->min_req_qt_version - ref_a->min_req_qt_version;
12597 /* known bitrates go before unknown; higher bitrates go first */
12598 return ref_b->min_req_bitrate - ref_a->min_req_bitrate;
12601 /* sort the redirects and post a message for the application.
12604 qtdemux_process_redirects (GstQTDemux * qtdemux, GList * references)
12606 GstQtReference *best;
12609 GValue list_val = { 0, };
12612 g_assert (references != NULL);
12614 references = g_list_sort (references, qtdemux_redirects_sort_func);
12616 best = (GstQtReference *) references->data;
12618 g_value_init (&list_val, GST_TYPE_LIST);
12620 for (l = references; l != NULL; l = l->next) {
12621 GstQtReference *ref = (GstQtReference *) l->data;
12622 GValue struct_val = { 0, };
12624 ref->structure = gst_structure_new ("redirect",
12625 "new-location", G_TYPE_STRING, ref->location, NULL);
12627 if (ref->min_req_bitrate > 0) {
12628 gst_structure_set (ref->structure, "minimum-bitrate", G_TYPE_INT,
12629 ref->min_req_bitrate, NULL);
12632 g_value_init (&struct_val, GST_TYPE_STRUCTURE);
12633 g_value_set_boxed (&struct_val, ref->structure);
12634 gst_value_list_append_value (&list_val, &struct_val);
12635 g_value_unset (&struct_val);
12636 /* don't free anything here yet, since we need best->structure below */
12639 g_assert (best != NULL);
12640 s = gst_structure_copy (best->structure);
12642 if (g_list_length (references) > 1) {
12643 gst_structure_set_value (s, "locations", &list_val);
12646 g_value_unset (&list_val);
12648 for (l = references; l != NULL; l = l->next) {
12649 GstQtReference *ref = (GstQtReference *) l->data;
12651 gst_structure_free (ref->structure);
12652 g_free (ref->location);
12655 g_list_free (references);
12657 GST_INFO_OBJECT (qtdemux, "posting redirect message: %" GST_PTR_FORMAT, s);
12658 msg = gst_message_new_element (GST_OBJECT_CAST (qtdemux), s);
12659 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
12660 qtdemux->posted_redirect = TRUE;
12663 /* look for redirect nodes, collect all redirect information and
12667 qtdemux_parse_redirects (GstQTDemux * qtdemux)
12669 GNode *rmra, *rmda, *rdrf;
12671 rmra = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_rmra);
12673 GList *redirects = NULL;
12675 rmda = qtdemux_tree_get_child_by_type (rmra, FOURCC_rmda);
12677 GstQtReference ref = { NULL, NULL, 0, 0 };
12678 GNode *rmdr, *rmvc;
12680 if ((rmdr = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmdr))) {
12681 ref.min_req_bitrate = QT_UINT32 ((guint8 *) rmdr->data + 12);
12682 GST_LOG_OBJECT (qtdemux, "data rate atom, required bitrate = %u",
12683 ref.min_req_bitrate);
12686 if ((rmvc = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmvc))) {
12687 guint32 package = QT_FOURCC ((guint8 *) rmvc->data + 12);
12688 guint version = QT_UINT32 ((guint8 *) rmvc->data + 16);
12690 #ifndef GST_DISABLE_GST_DEBUG
12691 guint bitmask = QT_UINT32 ((guint8 *) rmvc->data + 20);
12693 guint check_type = QT_UINT16 ((guint8 *) rmvc->data + 24);
12695 GST_LOG_OBJECT (qtdemux,
12696 "version check atom [%" GST_FOURCC_FORMAT "], version=0x%08x"
12697 ", mask=%08x, check_type=%u", GST_FOURCC_ARGS (package), version,
12698 bitmask, check_type);
12699 if (package == FOURCC_qtim && check_type == 0) {
12700 ref.min_req_qt_version = version;
12704 rdrf = qtdemux_tree_get_child_by_type (rmda, FOURCC_rdrf);
12710 ref_len = QT_UINT32 ((guint8 *) rdrf->data);
12711 if (ref_len > 20) {
12712 ref_type = QT_FOURCC ((guint8 *) rdrf->data + 12);
12713 ref_data = (guint8 *) rdrf->data + 20;
12714 if (ref_type == FOURCC_alis) {
12715 guint record_len, record_version, fn_len;
12717 if (ref_len > 70) {
12718 /* MacOSX alias record, google for alias-layout.txt */
12719 record_len = QT_UINT16 (ref_data + 4);
12720 record_version = QT_UINT16 (ref_data + 4 + 2);
12721 fn_len = QT_UINT8 (ref_data + 50);
12722 if (record_len > 50 && record_version == 2 && fn_len > 0) {
12723 ref.location = g_strndup ((gchar *) ref_data + 51, fn_len);
12726 GST_WARNING_OBJECT (qtdemux, "Invalid rdrf/alis size (%u < 70)",
12729 } else if (ref_type == FOURCC_url_) {
12730 ref.location = g_strndup ((gchar *) ref_data, ref_len - 8);
12732 GST_DEBUG_OBJECT (qtdemux,
12733 "unknown rdrf reference type %" GST_FOURCC_FORMAT,
12734 GST_FOURCC_ARGS (ref_type));
12736 if (ref.location != NULL) {
12737 GST_INFO_OBJECT (qtdemux, "New location: %s", ref.location);
12739 g_list_prepend (redirects, g_memdup (&ref, sizeof (ref)));
12741 GST_WARNING_OBJECT (qtdemux,
12742 "Failed to extract redirect location from rdrf atom");
12745 GST_WARNING_OBJECT (qtdemux, "Invalid rdrf size (%u < 20)", ref_len);
12749 /* look for others */
12750 rmda = qtdemux_tree_get_sibling_by_type (rmda, FOURCC_rmda);
12753 if (redirects != NULL) {
12754 qtdemux_process_redirects (qtdemux, redirects);
12760 static GstTagList *
12761 qtdemux_add_container_format (GstQTDemux * qtdemux, GstTagList * tags)
12765 if (tags == NULL) {
12766 tags = gst_tag_list_new_empty ();
12767 gst_tag_list_set_scope (tags, GST_TAG_SCOPE_GLOBAL);
12770 if (qtdemux->major_brand == FOURCC_mjp2)
12771 fmt = "Motion JPEG 2000";
12772 else if ((qtdemux->major_brand & 0xffff) == FOURCC_3g__)
12774 else if (qtdemux->major_brand == FOURCC_qt__)
12776 else if (qtdemux->fragmented)
12779 fmt = "ISO MP4/M4A";
12781 GST_LOG_OBJECT (qtdemux, "mapped %" GST_FOURCC_FORMAT " to '%s'",
12782 GST_FOURCC_ARGS (qtdemux->major_brand), fmt);
12784 gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_CONTAINER_FORMAT,
12790 /* we have read the complete moov node now.
12791 * This function parses all of the relevant info, creates the traks and
12792 * prepares all data structures for playback
12795 qtdemux_parse_tree (GstQTDemux * qtdemux)
12801 GstClockTime duration;
12803 guint64 creation_time;
12804 GstDateTime *datetime = NULL;
12807 /* make sure we have a usable taglist */
12808 if (!qtdemux->tag_list) {
12809 qtdemux->tag_list = gst_tag_list_new_empty ();
12810 gst_tag_list_set_scope (qtdemux->tag_list, GST_TAG_SCOPE_GLOBAL);
12812 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
12815 mvhd = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvhd);
12816 if (mvhd == NULL) {
12817 GST_LOG_OBJECT (qtdemux, "No mvhd node found, looking for redirects.");
12818 return qtdemux_parse_redirects (qtdemux);
12821 version = QT_UINT8 ((guint8 *) mvhd->data + 8);
12822 if (version == 1) {
12823 creation_time = QT_UINT64 ((guint8 *) mvhd->data + 12);
12824 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 28);
12825 qtdemux->duration = QT_UINT64 ((guint8 *) mvhd->data + 32);
12826 } else if (version == 0) {
12827 creation_time = QT_UINT32 ((guint8 *) mvhd->data + 12);
12828 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 20);
12829 qtdemux->duration = QT_UINT32 ((guint8 *) mvhd->data + 24);
12831 GST_WARNING_OBJECT (qtdemux, "Unhandled mvhd version %d", version);
12835 /* Moving qt creation time (secs since 1904) to unix time */
12836 if (creation_time != 0) {
12837 /* Try to use epoch first as it should be faster and more commonly found */
12838 if (creation_time >= QTDEMUX_SECONDS_FROM_1904_TO_1970) {
12841 creation_time -= QTDEMUX_SECONDS_FROM_1904_TO_1970;
12842 /* some data cleansing sanity */
12843 g_get_current_time (&now);
12844 if (now.tv_sec + 24 * 3600 < creation_time) {
12845 GST_DEBUG_OBJECT (qtdemux, "discarding bogus future creation time");
12847 datetime = gst_date_time_new_from_unix_epoch_utc (creation_time);
12850 GDateTime *base_dt = g_date_time_new_utc (1904, 1, 1, 0, 0, 0);
12851 GDateTime *dt, *dt_local;
12853 dt = g_date_time_add_seconds (base_dt, creation_time);
12854 dt_local = g_date_time_to_local (dt);
12855 datetime = gst_date_time_new_from_g_date_time (dt_local);
12857 g_date_time_unref (base_dt);
12858 g_date_time_unref (dt);
12862 /* Use KEEP as explicit tags should have a higher priority than mvhd tag */
12863 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_KEEP, GST_TAG_DATE_TIME,
12865 gst_date_time_unref (datetime);
12868 GST_INFO_OBJECT (qtdemux, "timescale: %u", qtdemux->timescale);
12869 GST_INFO_OBJECT (qtdemux, "duration: %" G_GUINT64_FORMAT, qtdemux->duration);
12871 /* check for fragmented file and get some (default) data */
12872 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
12875 GstByteReader mehd_data;
12877 /* let track parsing or anyone know weird stuff might happen ... */
12878 qtdemux->fragmented = TRUE;
12880 /* compensate for total duration */
12881 mehd = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_mehd, &mehd_data);
12883 qtdemux_parse_mehd (qtdemux, &mehd_data);
12886 /* set duration in the segment info */
12887 gst_qtdemux_get_duration (qtdemux, &duration);
12889 qtdemux->segment.duration = duration;
12890 /* also do not exceed duration; stop is set that way post seek anyway,
12891 * and segment activation falls back to duration,
12892 * whereas loop only checks stop, so let's align this here as well */
12893 qtdemux->segment.stop = duration;
12896 /* parse all traks */
12897 trak = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_trak);
12899 qtdemux_parse_trak (qtdemux, trak);
12900 /* iterate all siblings */
12901 trak = qtdemux_tree_get_sibling_by_type (trak, FOURCC_trak);
12904 if (!qtdemux->tag_list) {
12905 GST_DEBUG_OBJECT (qtdemux, "new tag list");
12906 qtdemux->tag_list = gst_tag_list_new_empty ();
12907 gst_tag_list_set_scope (qtdemux->tag_list, GST_TAG_SCOPE_GLOBAL);
12909 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
12913 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_udta);
12915 qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
12917 GST_LOG_OBJECT (qtdemux, "No udta node found.");
12920 /* maybe also some tags in meta box */
12921 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_meta);
12923 GST_DEBUG_OBJECT (qtdemux, "Parsing meta box for tags.");
12924 qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
12926 GST_LOG_OBJECT (qtdemux, "No meta node found.");
12929 /* parse any protection system info */
12930 pssh = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_pssh);
12932 GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
12933 qtdemux_parse_pssh (qtdemux, pssh);
12934 pssh = qtdemux_tree_get_sibling_by_type (pssh, FOURCC_pssh);
12937 qtdemux->tag_list = qtdemux_add_container_format (qtdemux, qtdemux->tag_list);
12942 /* taken from ffmpeg */
12944 read_descr_size (guint8 * ptr, guint8 * end, guint8 ** end_out)
12956 len = (len << 7) | (c & 0x7f);
12964 /* this can change the codec originally present in @list */
12966 gst_qtdemux_handle_esds (GstQTDemux * qtdemux, QtDemuxStream * stream,
12967 GNode * esds, GstTagList * list)
12969 int len = QT_UINT32 (esds->data);
12970 guint8 *ptr = esds->data;
12971 guint8 *end = ptr + len;
12973 guint8 *data_ptr = NULL;
12975 guint8 object_type_id = 0;
12976 const char *codec_name = NULL;
12977 GstCaps *caps = NULL;
12979 GST_MEMDUMP_OBJECT (qtdemux, "esds", ptr, len);
12981 GST_DEBUG_OBJECT (qtdemux, "version/flags = %08x", QT_UINT32 (ptr));
12983 while (ptr + 1 < end) {
12984 tag = QT_UINT8 (ptr);
12985 GST_DEBUG_OBJECT (qtdemux, "tag = %02x", tag);
12987 len = read_descr_size (ptr, end, &ptr);
12988 GST_DEBUG_OBJECT (qtdemux, "len = %d", len);
12990 /* Check the stated amount of data is available for reading */
12991 if (len < 0 || ptr + len > end)
12995 case ES_DESCRIPTOR_TAG:
12996 GST_DEBUG_OBJECT (qtdemux, "ID %04x", QT_UINT16 (ptr));
12997 GST_DEBUG_OBJECT (qtdemux, "priority %04x", QT_UINT8 (ptr + 2));
13000 case DECODER_CONFIG_DESC_TAG:{
13001 guint max_bitrate, avg_bitrate;
13003 object_type_id = QT_UINT8 (ptr);
13004 max_bitrate = QT_UINT32 (ptr + 5);
13005 avg_bitrate = QT_UINT32 (ptr + 9);
13006 GST_DEBUG_OBJECT (qtdemux, "object_type_id %02x", object_type_id);
13007 GST_DEBUG_OBJECT (qtdemux, "stream_type %02x", QT_UINT8 (ptr + 1));
13008 GST_DEBUG_OBJECT (qtdemux, "buffer_size_db %02x", QT_UINT24 (ptr + 2));
13009 GST_DEBUG_OBJECT (qtdemux, "max bitrate %u", max_bitrate);
13010 GST_DEBUG_OBJECT (qtdemux, "avg bitrate %u", avg_bitrate);
13011 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
13012 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
13013 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
13015 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
13016 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
13017 avg_bitrate, NULL);
13022 case DECODER_SPECIFIC_INFO_TAG:
13023 GST_MEMDUMP_OBJECT (qtdemux, "data", ptr, len);
13024 if (object_type_id == 0xe0 && len == 0x40) {
13030 GST_DEBUG_OBJECT (qtdemux,
13031 "Have VOBSUB palette. Creating palette event");
13032 /* move to decConfigDescr data and read palette */
13034 for (i = 0; i < 16; i++) {
13035 clut[i] = QT_UINT32 (data);
13039 s = gst_structure_new ("application/x-gst-dvd", "event",
13040 G_TYPE_STRING, "dvd-spu-clut-change",
13041 "clut00", G_TYPE_INT, clut[0], "clut01", G_TYPE_INT, clut[1],
13042 "clut02", G_TYPE_INT, clut[2], "clut03", G_TYPE_INT, clut[3],
13043 "clut04", G_TYPE_INT, clut[4], "clut05", G_TYPE_INT, clut[5],
13044 "clut06", G_TYPE_INT, clut[6], "clut07", G_TYPE_INT, clut[7],
13045 "clut08", G_TYPE_INT, clut[8], "clut09", G_TYPE_INT, clut[9],
13046 "clut10", G_TYPE_INT, clut[10], "clut11", G_TYPE_INT, clut[11],
13047 "clut12", G_TYPE_INT, clut[12], "clut13", G_TYPE_INT, clut[13],
13048 "clut14", G_TYPE_INT, clut[14], "clut15", G_TYPE_INT, clut[15],
13051 /* store event and trigger custom processing */
13052 stream->pending_event =
13053 gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s);
13055 /* Generic codec_data handler puts it on the caps */
13062 case SL_CONFIG_DESC_TAG:
13063 GST_DEBUG_OBJECT (qtdemux, "data %02x", QT_UINT8 (ptr));
13067 GST_DEBUG_OBJECT (qtdemux, "Unknown/unhandled descriptor tag %02x",
13069 GST_MEMDUMP_OBJECT (qtdemux, "descriptor data", ptr, len);
13075 /* object_type_id in the esds atom in mp4a and mp4v tells us which codec is
13076 * in use, and should also be used to override some other parameters for some
13078 switch (object_type_id) {
13079 case 0x20: /* MPEG-4 */
13080 /* 4 bytes for the visual_object_sequence_start_code and 1 byte for the
13081 * profile_and_level_indication */
13082 if (data_ptr != NULL && data_len >= 5 &&
13083 GST_READ_UINT32_BE (data_ptr) == 0x000001b0) {
13084 gst_codec_utils_mpeg4video_caps_set_level_and_profile (stream->caps,
13085 data_ptr + 4, data_len - 4);
13087 break; /* Nothing special needed here */
13088 case 0x21: /* H.264 */
13089 codec_name = "H.264 / AVC";
13090 caps = gst_caps_new_simple ("video/x-h264",
13091 "stream-format", G_TYPE_STRING, "avc",
13092 "alignment", G_TYPE_STRING, "au", NULL);
13094 case 0x40: /* AAC (any) */
13095 case 0x66: /* AAC Main */
13096 case 0x67: /* AAC LC */
13097 case 0x68: /* AAC SSR */
13098 /* Override channels and rate based on the codec_data, as it's often
13100 /* Only do so for basic setup without HE-AAC extension */
13101 if (data_ptr && data_len == 2) {
13102 guint channels, rate;
13104 channels = gst_codec_utils_aac_get_channels (data_ptr, data_len);
13106 stream->n_channels = channels;
13108 rate = gst_codec_utils_aac_get_sample_rate (data_ptr, data_len);
13110 stream->rate = rate;
13113 /* Set level and profile if possible */
13114 if (data_ptr != NULL && data_len >= 2) {
13115 gst_codec_utils_aac_caps_set_level_and_profile (stream->caps,
13116 data_ptr, data_len);
13118 const gchar *profile_str = NULL;
13121 guint8 *codec_data;
13122 gint rate_idx, profile;
13124 /* No codec_data, let's invent something.
13125 * FIXME: This is wrong for SBR! */
13127 GST_WARNING_OBJECT (qtdemux, "No codec_data for AAC available");
13129 buffer = gst_buffer_new_and_alloc (2);
13130 gst_buffer_map (buffer, &map, GST_MAP_WRITE);
13131 codec_data = map.data;
13134 gst_codec_utils_aac_get_index_from_sample_rate (stream->rate);
13136 switch (object_type_id) {
13138 profile_str = "main";
13142 profile_str = "lc";
13146 profile_str = "ssr";
13154 codec_data[0] = ((profile + 1) << 3) | ((rate_idx & 0xE) >> 1);
13155 codec_data[1] = ((rate_idx & 0x1) << 7) | (stream->n_channels << 3);
13157 gst_buffer_unmap (buffer, &map);
13158 gst_caps_set_simple (stream->caps, "codec_data", GST_TYPE_BUFFER,
13160 gst_buffer_unref (buffer);
13163 gst_caps_set_simple (stream->caps, "profile", G_TYPE_STRING,
13164 profile_str, NULL);
13168 case 0x60: /* MPEG-2, various profiles */
13174 codec_name = "MPEG-2 video";
13175 caps = gst_caps_new_simple ("video/mpeg",
13176 "mpegversion", G_TYPE_INT, 2,
13177 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13179 case 0x69: /* MPEG-2 BC audio */
13180 case 0x6B: /* MPEG-1 audio */
13181 caps = gst_caps_new_simple ("audio/mpeg",
13182 "mpegversion", G_TYPE_INT, 1, "parsed", G_TYPE_BOOLEAN, TRUE, NULL);
13183 codec_name = "MPEG-1 audio";
13185 case 0x6A: /* MPEG-1 */
13186 codec_name = "MPEG-1 video";
13187 caps = gst_caps_new_simple ("video/mpeg",
13188 "mpegversion", G_TYPE_INT, 1,
13189 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13191 case 0x6C: /* MJPEG */
13193 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
13195 codec_name = "Motion-JPEG";
13197 case 0x6D: /* PNG */
13199 gst_caps_new_simple ("image/png", "parsed", G_TYPE_BOOLEAN, TRUE,
13201 codec_name = "PNG still images";
13203 case 0x6E: /* JPEG2000 */
13204 codec_name = "JPEG-2000";
13205 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
13207 case 0xA4: /* Dirac */
13208 codec_name = "Dirac";
13209 caps = gst_caps_new_empty_simple ("video/x-dirac");
13211 case 0xA5: /* AC3 */
13212 codec_name = "AC-3 audio";
13213 caps = gst_caps_new_simple ("audio/x-ac3",
13214 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
13216 case 0xA9: /* AC3 */
13217 codec_name = "DTS audio";
13218 caps = gst_caps_new_simple ("audio/x-dts",
13219 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
13221 case 0xE1: /* QCELP */
13222 /* QCELP, the codec_data is a riff tag (little endian) with
13223 * 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). */
13224 caps = gst_caps_new_empty_simple ("audio/qcelp");
13225 codec_name = "QCELP";
13231 /* If we have a replacement caps, then change our caps for this stream */
13233 gst_caps_unref (stream->caps);
13234 stream->caps = caps;
13237 if (codec_name && list)
13238 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
13239 GST_TAG_AUDIO_CODEC, codec_name, NULL);
13241 /* Add the codec_data attribute to caps, if we have it */
13245 buffer = gst_buffer_new_and_alloc (data_len);
13246 gst_buffer_fill (buffer, 0, data_ptr, data_len);
13248 GST_DEBUG_OBJECT (qtdemux, "setting codec_data from esds");
13249 GST_MEMDUMP_OBJECT (qtdemux, "codec_data from esds", data_ptr, data_len);
13251 gst_caps_set_simple (stream->caps, "codec_data", GST_TYPE_BUFFER,
13253 gst_buffer_unref (buffer);
13258 static inline GstCaps *
13259 _get_unknown_codec_name (const gchar * type, guint32 fourcc)
13263 char *s, fourstr[5];
13265 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
13266 for (i = 0; i < 4; i++) {
13267 if (!g_ascii_isalnum (fourstr[i]))
13270 s = g_strdup_printf ("%s/x-gst-fourcc-%s", type, g_strstrip (fourstr));
13271 caps = gst_caps_new_empty_simple (s);
13276 #define _codec(name) \
13278 if (codec_name) { \
13279 *codec_name = g_strdup (name); \
13284 qtdemux_video_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
13285 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
13287 GstCaps *caps = NULL;
13288 GstVideoFormat format = GST_VIDEO_FORMAT_UNKNOWN;
13291 case GST_MAKE_FOURCC ('p', 'n', 'g', ' '):
13292 _codec ("PNG still images");
13293 caps = gst_caps_new_empty_simple ("image/png");
13296 _codec ("JPEG still images");
13298 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
13301 case GST_MAKE_FOURCC ('m', 'j', 'p', 'a'):
13302 case GST_MAKE_FOURCC ('A', 'V', 'D', 'J'):
13303 case GST_MAKE_FOURCC ('M', 'J', 'P', 'G'):
13304 case GST_MAKE_FOURCC ('d', 'm', 'b', '1'):
13305 _codec ("Motion-JPEG");
13307 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
13310 case GST_MAKE_FOURCC ('m', 'j', 'p', 'b'):
13311 _codec ("Motion-JPEG format B");
13312 caps = gst_caps_new_empty_simple ("video/x-mjpeg-b");
13315 _codec ("JPEG-2000");
13316 /* override to what it should be according to spec, avoid palette_data */
13317 stream->bits_per_sample = 24;
13318 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
13321 _codec ("Sorensen video v.3");
13322 caps = gst_caps_new_simple ("video/x-svq",
13323 "svqversion", G_TYPE_INT, 3, NULL);
13325 case GST_MAKE_FOURCC ('s', 'v', 'q', 'i'):
13326 case GST_MAKE_FOURCC ('S', 'V', 'Q', '1'):
13327 _codec ("Sorensen video v.1");
13328 caps = gst_caps_new_simple ("video/x-svq",
13329 "svqversion", G_TYPE_INT, 1, NULL);
13331 case GST_MAKE_FOURCC ('W', 'R', 'A', 'W'):
13332 caps = gst_caps_new_empty_simple ("video/x-raw");
13333 gst_caps_set_simple (caps, "format", G_TYPE_STRING, "RGB8P", NULL);
13334 _codec ("Windows Raw RGB");
13335 stream->alignment = 32;
13341 bps = QT_UINT16 (stsd_data + 98);
13344 format = GST_VIDEO_FORMAT_RGB15;
13347 format = GST_VIDEO_FORMAT_RGB16;
13350 format = GST_VIDEO_FORMAT_RGB;
13353 format = GST_VIDEO_FORMAT_ARGB;
13361 case GST_MAKE_FOURCC ('y', 'v', '1', '2'):
13362 format = GST_VIDEO_FORMAT_I420;
13364 case GST_MAKE_FOURCC ('y', 'u', 'v', '2'):
13365 case GST_MAKE_FOURCC ('Y', 'u', 'v', '2'):
13366 format = GST_VIDEO_FORMAT_I420;
13369 case GST_MAKE_FOURCC ('2', 'V', 'u', 'y'):
13370 format = GST_VIDEO_FORMAT_UYVY;
13372 case GST_MAKE_FOURCC ('v', '3', '0', '8'):
13373 format = GST_VIDEO_FORMAT_v308;
13375 case GST_MAKE_FOURCC ('v', '2', '1', '6'):
13376 format = GST_VIDEO_FORMAT_v216;
13379 format = GST_VIDEO_FORMAT_v210;
13381 case GST_MAKE_FOURCC ('r', '2', '1', '0'):
13382 format = GST_VIDEO_FORMAT_r210;
13384 /* Packed YUV 4:4:4 10 bit in 32 bits, complex
13385 case GST_MAKE_FOURCC ('v', '4', '1', '0'):
13386 format = GST_VIDEO_FORMAT_v410;
13389 /* Packed YUV 4:4:4:4 8 bit in 32 bits
13390 * but different order than AYUV
13391 case GST_MAKE_FOURCC ('v', '4', '0', '8'):
13392 format = GST_VIDEO_FORMAT_v408;
13395 case GST_MAKE_FOURCC ('m', 'p', 'e', 'g'):
13396 case GST_MAKE_FOURCC ('m', 'p', 'g', '1'):
13397 _codec ("MPEG-1 video");
13398 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
13399 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13401 case GST_MAKE_FOURCC ('h', 'd', 'v', '1'): /* HDV 720p30 */
13402 case GST_MAKE_FOURCC ('h', 'd', 'v', '2'): /* HDV 1080i60 */
13403 case GST_MAKE_FOURCC ('h', 'd', 'v', '3'): /* HDV 1080i50 */
13404 case GST_MAKE_FOURCC ('h', 'd', 'v', '4'): /* HDV 720p24 */
13405 case GST_MAKE_FOURCC ('h', 'd', 'v', '5'): /* HDV 720p25 */
13406 case GST_MAKE_FOURCC ('h', 'd', 'v', '6'): /* HDV 1080p24 */
13407 case GST_MAKE_FOURCC ('h', 'd', 'v', '7'): /* HDV 1080p25 */
13408 case GST_MAKE_FOURCC ('h', 'd', 'v', '8'): /* HDV 1080p30 */
13409 case GST_MAKE_FOURCC ('h', 'd', 'v', '9'): /* HDV 720p60 */
13410 case GST_MAKE_FOURCC ('h', 'd', 'v', 'a'): /* HDV 720p50 */
13411 case GST_MAKE_FOURCC ('m', 'x', '5', 'n'): /* MPEG2 IMX NTSC 525/60 50mb/s produced by FCP */
13412 case GST_MAKE_FOURCC ('m', 'x', '5', 'p'): /* MPEG2 IMX PAL 625/60 50mb/s produced by FCP */
13413 case GST_MAKE_FOURCC ('m', 'x', '4', 'n'): /* MPEG2 IMX NTSC 525/60 40mb/s produced by FCP */
13414 case GST_MAKE_FOURCC ('m', 'x', '4', 'p'): /* MPEG2 IMX PAL 625/60 40mb/s produced by FCP */
13415 case GST_MAKE_FOURCC ('m', 'x', '3', 'n'): /* MPEG2 IMX NTSC 525/60 30mb/s produced by FCP */
13416 case GST_MAKE_FOURCC ('m', 'x', '3', 'p'): /* MPEG2 IMX PAL 625/50 30mb/s produced by FCP */
13417 case GST_MAKE_FOURCC ('x', 'd', 'v', '1'): /* XDCAM HD 720p30 35Mb/s */
13418 case GST_MAKE_FOURCC ('x', 'd', 'v', '2'): /* XDCAM HD 1080i60 35Mb/s */
13419 case GST_MAKE_FOURCC ('x', 'd', 'v', '3'): /* XDCAM HD 1080i50 35Mb/s */
13420 case GST_MAKE_FOURCC ('x', 'd', 'v', '4'): /* XDCAM HD 720p24 35Mb/s */
13421 case GST_MAKE_FOURCC ('x', 'd', 'v', '5'): /* XDCAM HD 720p25 35Mb/s */
13422 case GST_MAKE_FOURCC ('x', 'd', 'v', '6'): /* XDCAM HD 1080p24 35Mb/s */
13423 case GST_MAKE_FOURCC ('x', 'd', 'v', '7'): /* XDCAM HD 1080p25 35Mb/s */
13424 case GST_MAKE_FOURCC ('x', 'd', 'v', '8'): /* XDCAM HD 1080p30 35Mb/s */
13425 case GST_MAKE_FOURCC ('x', 'd', 'v', '9'): /* XDCAM HD 720p60 35Mb/s */
13426 case GST_MAKE_FOURCC ('x', 'd', 'v', 'a'): /* XDCAM HD 720p50 35Mb/s */
13427 case GST_MAKE_FOURCC ('x', 'd', 'v', 'b'): /* XDCAM EX 1080i60 50Mb/s CBR */
13428 case GST_MAKE_FOURCC ('x', 'd', 'v', 'c'): /* XDCAM EX 1080i50 50Mb/s CBR */
13429 case GST_MAKE_FOURCC ('x', 'd', 'v', 'd'): /* XDCAM HD 1080p24 50Mb/s CBR */
13430 case GST_MAKE_FOURCC ('x', 'd', 'v', 'e'): /* XDCAM HD 1080p25 50Mb/s CBR */
13431 case GST_MAKE_FOURCC ('x', 'd', 'v', 'f'): /* XDCAM HD 1080p30 50Mb/s CBR */
13432 case GST_MAKE_FOURCC ('x', 'd', '5', '1'): /* XDCAM HD422 720p30 50Mb/s CBR */
13433 case GST_MAKE_FOURCC ('x', 'd', '5', '4'): /* XDCAM HD422 720p24 50Mb/s CBR */
13434 case GST_MAKE_FOURCC ('x', 'd', '5', '5'): /* XDCAM HD422 720p25 50Mb/s CBR */
13435 case GST_MAKE_FOURCC ('x', 'd', '5', '9'): /* XDCAM HD422 720p60 50Mb/s CBR */
13436 case GST_MAKE_FOURCC ('x', 'd', '5', 'a'): /* XDCAM HD422 720p50 50Mb/s CBR */
13437 case GST_MAKE_FOURCC ('x', 'd', '5', 'b'): /* XDCAM HD422 1080i50 50Mb/s CBR */
13438 case GST_MAKE_FOURCC ('x', 'd', '5', 'c'): /* XDCAM HD422 1080i50 50Mb/s CBR */
13439 case GST_MAKE_FOURCC ('x', 'd', '5', 'd'): /* XDCAM HD422 1080p24 50Mb/s CBR */
13440 case GST_MAKE_FOURCC ('x', 'd', '5', 'e'): /* XDCAM HD422 1080p25 50Mb/s CBR */
13441 case GST_MAKE_FOURCC ('x', 'd', '5', 'f'): /* XDCAM HD422 1080p30 50Mb/s CBR */
13442 case GST_MAKE_FOURCC ('x', 'd', 'h', 'd'): /* XDCAM HD 540p */
13443 case GST_MAKE_FOURCC ('x', 'd', 'h', '2'): /* XDCAM HD422 540p */
13444 case GST_MAKE_FOURCC ('A', 'V', 'm', 'p'): /* AVID IMX PAL */
13445 case GST_MAKE_FOURCC ('m', 'p', 'g', '2'): /* AVID IMX PAL */
13446 case GST_MAKE_FOURCC ('m', 'p', '2', 'v'): /* AVID IMX PAL */
13447 case GST_MAKE_FOURCC ('m', '2', 'v', '1'):
13448 _codec ("MPEG-2 video");
13449 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 2,
13450 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13452 case GST_MAKE_FOURCC ('g', 'i', 'f', ' '):
13453 _codec ("GIF still images");
13454 caps = gst_caps_new_empty_simple ("image/gif");
13457 case GST_MAKE_FOURCC ('H', '2', '6', '3'):
13459 case GST_MAKE_FOURCC ('U', '2', '6', '3'):
13461 /* ffmpeg uses the height/width props, don't know why */
13462 caps = gst_caps_new_simple ("video/x-h263",
13463 "variant", G_TYPE_STRING, "itu", NULL);
13467 _codec ("MPEG-4 video");
13468 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
13469 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13471 case GST_MAKE_FOURCC ('3', 'i', 'v', 'd'):
13472 case GST_MAKE_FOURCC ('3', 'I', 'V', 'D'):
13473 _codec ("Microsoft MPEG-4 4.3"); /* FIXME? */
13474 caps = gst_caps_new_simple ("video/x-msmpeg",
13475 "msmpegversion", G_TYPE_INT, 43, NULL);
13477 case GST_MAKE_FOURCC ('D', 'I', 'V', '3'):
13479 caps = gst_caps_new_simple ("video/x-divx",
13480 "divxversion", G_TYPE_INT, 3, NULL);
13482 case GST_MAKE_FOURCC ('D', 'I', 'V', 'X'):
13483 case GST_MAKE_FOURCC ('d', 'i', 'v', 'x'):
13485 caps = gst_caps_new_simple ("video/x-divx",
13486 "divxversion", G_TYPE_INT, 4, NULL);
13488 case GST_MAKE_FOURCC ('D', 'X', '5', '0'):
13490 caps = gst_caps_new_simple ("video/x-divx",
13491 "divxversion", G_TYPE_INT, 5, NULL);
13494 case GST_MAKE_FOURCC ('F', 'F', 'V', '1'):
13496 caps = gst_caps_new_simple ("video/x-ffv",
13497 "ffvversion", G_TYPE_INT, 1, NULL);
13500 case GST_MAKE_FOURCC ('3', 'I', 'V', '1'):
13501 case GST_MAKE_FOURCC ('3', 'I', 'V', '2'):
13506 case GST_MAKE_FOURCC ('U', 'M', 'P', '4'):
13507 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
13508 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13512 case GST_MAKE_FOURCC ('c', 'v', 'i', 'd'):
13513 _codec ("Cinepak");
13514 caps = gst_caps_new_empty_simple ("video/x-cinepak");
13516 case GST_MAKE_FOURCC ('q', 'd', 'r', 'w'):
13517 _codec ("Apple QuickDraw");
13518 caps = gst_caps_new_empty_simple ("video/x-qdrw");
13520 case GST_MAKE_FOURCC ('r', 'p', 'z', 'a'):
13521 _codec ("Apple video");
13522 caps = gst_caps_new_empty_simple ("video/x-apple-video");
13526 _codec ("H.264 / AVC");
13527 caps = gst_caps_new_simple ("video/x-h264",
13528 "stream-format", G_TYPE_STRING, "avc",
13529 "alignment", G_TYPE_STRING, "au", NULL);
13532 _codec ("H.264 / AVC");
13533 caps = gst_caps_new_simple ("video/x-h264",
13534 "stream-format", G_TYPE_STRING, "avc3",
13535 "alignment", G_TYPE_STRING, "au", NULL);
13539 _codec ("H.265 / HEVC");
13540 caps = gst_caps_new_simple ("video/x-h265",
13541 "stream-format", G_TYPE_STRING, "hvc1",
13542 "alignment", G_TYPE_STRING, "au", NULL);
13545 _codec ("H.265 / HEVC");
13546 caps = gst_caps_new_simple ("video/x-h265",
13547 "stream-format", G_TYPE_STRING, "hev1",
13548 "alignment", G_TYPE_STRING, "au", NULL);
13551 _codec ("Run-length encoding");
13552 caps = gst_caps_new_simple ("video/x-rle",
13553 "layout", G_TYPE_STRING, "quicktime", NULL);
13556 _codec ("Run-length encoding");
13557 caps = gst_caps_new_simple ("video/x-rle",
13558 "layout", G_TYPE_STRING, "microsoft", NULL);
13560 case GST_MAKE_FOURCC ('I', 'V', '3', '2'):
13561 case GST_MAKE_FOURCC ('i', 'v', '3', '2'):
13562 _codec ("Indeo Video 3");
13563 caps = gst_caps_new_simple ("video/x-indeo",
13564 "indeoversion", G_TYPE_INT, 3, NULL);
13566 case GST_MAKE_FOURCC ('I', 'V', '4', '1'):
13567 case GST_MAKE_FOURCC ('i', 'v', '4', '1'):
13568 _codec ("Intel Video 4");
13569 caps = gst_caps_new_simple ("video/x-indeo",
13570 "indeoversion", G_TYPE_INT, 4, NULL);
13574 case GST_MAKE_FOURCC ('d', 'v', 's', 'd'):
13575 case GST_MAKE_FOURCC ('D', 'V', 'S', 'D'):
13576 case GST_MAKE_FOURCC ('d', 'v', 'c', 's'):
13577 case GST_MAKE_FOURCC ('D', 'V', 'C', 'S'):
13578 case GST_MAKE_FOURCC ('d', 'v', '2', '5'):
13579 case GST_MAKE_FOURCC ('d', 'v', 'p', 'p'):
13580 _codec ("DV Video");
13581 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 25,
13582 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13584 case FOURCC_dv5n: /* DVCPRO50 NTSC */
13585 case FOURCC_dv5p: /* DVCPRO50 PAL */
13586 _codec ("DVCPro50 Video");
13587 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 50,
13588 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13590 case GST_MAKE_FOURCC ('d', 'v', 'h', '5'): /* DVCPRO HD 50i produced by FCP */
13591 case GST_MAKE_FOURCC ('d', 'v', 'h', '6'): /* DVCPRO HD 60i produced by FCP */
13592 _codec ("DVCProHD Video");
13593 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 100,
13594 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13596 case GST_MAKE_FOURCC ('s', 'm', 'c', ' '):
13597 _codec ("Apple Graphics (SMC)");
13598 caps = gst_caps_new_empty_simple ("video/x-smc");
13600 case GST_MAKE_FOURCC ('V', 'P', '3', '1'):
13602 caps = gst_caps_new_empty_simple ("video/x-vp3");
13604 case GST_MAKE_FOURCC ('V', 'P', '6', 'F'):
13605 _codec ("VP6 Flash");
13606 caps = gst_caps_new_empty_simple ("video/x-vp6-flash");
13610 caps = gst_caps_new_empty_simple ("video/x-theora");
13611 /* theora uses one byte of padding in the data stream because it does not
13612 * allow 0 sized packets while theora does */
13613 stream->padding = 1;
13617 caps = gst_caps_new_empty_simple ("video/x-dirac");
13619 case GST_MAKE_FOURCC ('t', 'i', 'f', 'f'):
13620 _codec ("TIFF still images");
13621 caps = gst_caps_new_empty_simple ("image/tiff");
13623 case GST_MAKE_FOURCC ('i', 'c', 'o', 'd'):
13624 _codec ("Apple Intermediate Codec");
13625 caps = gst_caps_from_string ("video/x-apple-intermediate-codec");
13627 case GST_MAKE_FOURCC ('A', 'V', 'd', 'n'):
13628 _codec ("AVID DNxHD");
13629 caps = gst_caps_from_string ("video/x-dnxhd");
13632 _codec ("On2 VP8");
13633 caps = gst_caps_from_string ("video/x-vp8");
13636 _codec ("Apple ProRes LT");
13638 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "lt",
13642 _codec ("Apple ProRes HQ");
13644 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "hq",
13648 _codec ("Apple ProRes");
13650 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
13654 _codec ("Apple ProRes Proxy");
13656 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
13660 _codec ("Apple ProRes 4444");
13662 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
13666 _codec ("Apple ProRes 4444 XQ");
13668 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
13674 caps = gst_caps_new_simple ("video/x-wmv",
13675 "wmvversion", G_TYPE_INT, 3, "format", G_TYPE_STRING, "WVC1", NULL);
13677 case GST_MAKE_FOURCC ('k', 'p', 'c', 'd'):
13680 caps = _get_unknown_codec_name ("video", fourcc);
13685 if (format != GST_VIDEO_FORMAT_UNKNOWN) {
13688 gst_video_info_init (&info);
13689 gst_video_info_set_format (&info, format, stream->width, stream->height);
13691 caps = gst_video_info_to_caps (&info);
13692 *codec_name = gst_pb_utils_get_codec_description (caps);
13694 /* enable clipping for raw video streams */
13695 stream->need_clip = TRUE;
13696 stream->alignment = 32;
13703 round_up_pow2 (guint n)
13715 qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
13716 guint32 fourcc, const guint8 * data, int len, gchar ** codec_name)
13719 const GstStructure *s;
13722 GstAudioFormat format = 0;
13725 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
13727 depth = stream->bytes_per_packet * 8;
13730 case GST_MAKE_FOURCC ('N', 'O', 'N', 'E'):
13732 /* 8-bit audio is unsigned */
13734 format = GST_AUDIO_FORMAT_U8;
13735 /* otherwise it's signed and big-endian just like 'twos' */
13737 endian = G_BIG_ENDIAN;
13744 endian = G_LITTLE_ENDIAN;
13747 format = gst_audio_format_build_integer (TRUE, endian, depth, depth);
13749 str = g_strdup_printf ("Raw %d-bit PCM audio", depth);
13753 caps = gst_caps_new_simple ("audio/x-raw",
13754 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
13755 "layout", G_TYPE_STRING, "interleaved", NULL);
13756 stream->alignment = GST_ROUND_UP_8 (depth);
13757 stream->alignment = round_up_pow2 (stream->alignment);
13760 case GST_MAKE_FOURCC ('f', 'l', '6', '4'):
13761 _codec ("Raw 64-bit floating-point audio");
13762 caps = gst_caps_new_simple ("audio/x-raw",
13763 "format", G_TYPE_STRING, "F64BE",
13764 "layout", G_TYPE_STRING, "interleaved", NULL);
13765 stream->alignment = 8;
13767 case GST_MAKE_FOURCC ('f', 'l', '3', '2'):
13768 _codec ("Raw 32-bit floating-point audio");
13769 caps = gst_caps_new_simple ("audio/x-raw",
13770 "format", G_TYPE_STRING, "F32BE",
13771 "layout", G_TYPE_STRING, "interleaved", NULL);
13772 stream->alignment = 4;
13775 _codec ("Raw 24-bit PCM audio");
13776 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
13778 caps = gst_caps_new_simple ("audio/x-raw",
13779 "format", G_TYPE_STRING, "S24BE",
13780 "layout", G_TYPE_STRING, "interleaved", NULL);
13781 stream->alignment = 4;
13783 case GST_MAKE_FOURCC ('i', 'n', '3', '2'):
13784 _codec ("Raw 32-bit PCM audio");
13785 caps = gst_caps_new_simple ("audio/x-raw",
13786 "format", G_TYPE_STRING, "S32BE",
13787 "layout", G_TYPE_STRING, "interleaved", NULL);
13788 stream->alignment = 4;
13791 _codec ("Mu-law audio");
13792 caps = gst_caps_new_empty_simple ("audio/x-mulaw");
13795 _codec ("A-law audio");
13796 caps = gst_caps_new_empty_simple ("audio/x-alaw");
13800 _codec ("Microsoft ADPCM");
13801 /* Microsoft ADPCM-ACM code 2 */
13802 caps = gst_caps_new_simple ("audio/x-adpcm",
13803 "layout", G_TYPE_STRING, "microsoft", NULL);
13807 _codec ("DVI/IMA ADPCM");
13808 caps = gst_caps_new_simple ("audio/x-adpcm",
13809 "layout", G_TYPE_STRING, "dvi", NULL);
13813 _codec ("DVI/Intel IMA ADPCM");
13814 /* FIXME DVI/Intel IMA ADPCM/ACM code 17 */
13815 caps = gst_caps_new_simple ("audio/x-adpcm",
13816 "layout", G_TYPE_STRING, "quicktime", NULL);
13820 /* MPEG layer 3, CBR only (pre QT4.1) */
13822 _codec ("MPEG-1 layer 3");
13823 /* MPEG layer 3, CBR & VBR (QT4.1 and later) */
13824 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 3,
13825 "mpegversion", G_TYPE_INT, 1, NULL);
13827 case GST_MAKE_FOURCC ('.', 'm', 'p', '2'):
13828 _codec ("MPEG-1 layer 2");
13830 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 2,
13831 "mpegversion", G_TYPE_INT, 1, NULL);
13834 case GST_MAKE_FOURCC ('e', 'c', '-', '3'):
13835 _codec ("EAC-3 audio");
13836 caps = gst_caps_new_simple ("audio/x-eac3",
13837 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
13838 stream->sampled = TRUE;
13840 case GST_MAKE_FOURCC ('s', 'a', 'c', '3'): // Nero Recode
13842 _codec ("AC-3 audio");
13843 caps = gst_caps_new_simple ("audio/x-ac3",
13844 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
13845 stream->sampled = TRUE;
13847 case GST_MAKE_FOURCC ('d', 't', 's', 'c'):
13848 case GST_MAKE_FOURCC ('D', 'T', 'S', ' '):
13849 _codec ("DTS audio");
13850 caps = gst_caps_new_simple ("audio/x-dts",
13851 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
13852 stream->sampled = TRUE;
13854 case GST_MAKE_FOURCC ('d', 't', 's', 'h'): // DTS-HD
13855 case GST_MAKE_FOURCC ('d', 't', 's', 'l'): // DTS-HD Lossless
13856 _codec ("DTS-HD audio");
13857 caps = gst_caps_new_simple ("audio/x-dts",
13858 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
13859 stream->sampled = TRUE;
13863 caps = gst_caps_new_simple ("audio/x-mace",
13864 "maceversion", G_TYPE_INT, 3, NULL);
13868 caps = gst_caps_new_simple ("audio/x-mace",
13869 "maceversion", G_TYPE_INT, 6, NULL);
13871 case GST_MAKE_FOURCC ('O', 'g', 'g', 'V'):
13873 caps = gst_caps_new_empty_simple ("application/ogg");
13875 case GST_MAKE_FOURCC ('d', 'v', 'c', 'a'):
13876 _codec ("DV audio");
13877 caps = gst_caps_new_empty_simple ("audio/x-dv");
13880 _codec ("MPEG-4 AAC audio");
13881 caps = gst_caps_new_simple ("audio/mpeg",
13882 "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE,
13883 "stream-format", G_TYPE_STRING, "raw", NULL);
13885 case GST_MAKE_FOURCC ('Q', 'D', 'M', 'C'):
13886 _codec ("QDesign Music");
13887 caps = gst_caps_new_empty_simple ("audio/x-qdm");
13890 _codec ("QDesign Music v.2");
13891 /* FIXME: QDesign music version 2 (no constant) */
13892 if (FALSE && data) {
13893 caps = gst_caps_new_simple ("audio/x-qdm2",
13894 "framesize", G_TYPE_INT, QT_UINT32 (data + 52),
13895 "bitrate", G_TYPE_INT, QT_UINT32 (data + 40),
13896 "blocksize", G_TYPE_INT, QT_UINT32 (data + 44), NULL);
13898 caps = gst_caps_new_empty_simple ("audio/x-qdm2");
13902 _codec ("GSM audio");
13903 caps = gst_caps_new_empty_simple ("audio/x-gsm");
13906 _codec ("AMR audio");
13907 caps = gst_caps_new_empty_simple ("audio/AMR");
13910 _codec ("AMR-WB audio");
13911 caps = gst_caps_new_empty_simple ("audio/AMR-WB");
13914 _codec ("Quicktime IMA ADPCM");
13915 caps = gst_caps_new_simple ("audio/x-adpcm",
13916 "layout", G_TYPE_STRING, "quicktime", NULL);
13919 _codec ("Apple lossless audio");
13920 caps = gst_caps_new_empty_simple ("audio/x-alac");
13923 _codec ("Free Lossless Audio Codec");
13924 caps = gst_caps_new_simple ("audio/x-flac",
13925 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
13927 case GST_MAKE_FOURCC ('Q', 'c', 'l', 'p'):
13928 _codec ("QualComm PureVoice");
13929 caps = gst_caps_from_string ("audio/qcelp");
13934 caps = gst_caps_new_empty_simple ("audio/x-wma");
13938 caps = gst_caps_new_empty_simple ("audio/x-opus");
13940 case GST_MAKE_FOURCC ('l', 'p', 'c', 'm'):
13945 GstAudioFormat format;
13948 FLAG_IS_FLOAT = 0x1,
13949 FLAG_IS_BIG_ENDIAN = 0x2,
13950 FLAG_IS_SIGNED = 0x4,
13951 FLAG_IS_PACKED = 0x8,
13952 FLAG_IS_ALIGNED_HIGH = 0x10,
13953 FLAG_IS_NON_INTERLEAVED = 0x20
13955 _codec ("Raw LPCM audio");
13957 if (data && len >= 56) {
13958 depth = QT_UINT32 (data + 40);
13959 flags = QT_UINT32 (data + 44);
13960 width = QT_UINT32 (data + 48) * 8 / stream->n_channels;
13962 if ((flags & FLAG_IS_FLOAT) == 0) {
13967 format = gst_audio_format_build_integer ((flags & FLAG_IS_SIGNED) ?
13968 TRUE : FALSE, (flags & FLAG_IS_BIG_ENDIAN) ?
13969 G_BIG_ENDIAN : G_LITTLE_ENDIAN, width, depth);
13970 caps = gst_caps_new_simple ("audio/x-raw",
13971 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
13972 "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
13973 "non-interleaved" : "interleaved", NULL);
13974 stream->alignment = GST_ROUND_UP_8 (depth);
13975 stream->alignment = round_up_pow2 (stream->alignment);
13980 if (flags & FLAG_IS_BIG_ENDIAN)
13981 format = GST_AUDIO_FORMAT_F64BE;
13983 format = GST_AUDIO_FORMAT_F64LE;
13985 if (flags & FLAG_IS_BIG_ENDIAN)
13986 format = GST_AUDIO_FORMAT_F32BE;
13988 format = GST_AUDIO_FORMAT_F32LE;
13990 caps = gst_caps_new_simple ("audio/x-raw",
13991 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
13992 "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
13993 "non-interleaved" : "interleaved", NULL);
13994 stream->alignment = width / 8;
13998 case GST_MAKE_FOURCC ('q', 't', 'v', 'r'):
14002 caps = _get_unknown_codec_name ("audio", fourcc);
14008 GstCaps *templ_caps =
14009 gst_static_pad_template_get_caps (&gst_qtdemux_audiosrc_template);
14010 GstCaps *intersection = gst_caps_intersect (caps, templ_caps);
14011 gst_caps_unref (caps);
14012 gst_caps_unref (templ_caps);
14013 caps = intersection;
14016 /* enable clipping for raw audio streams */
14017 s = gst_caps_get_structure (caps, 0);
14018 name = gst_structure_get_name (s);
14019 if (g_str_has_prefix (name, "audio/x-raw")) {
14020 stream->need_clip = TRUE;
14021 stream->max_buffer_size = 4096 * stream->bytes_per_frame;
14022 GST_DEBUG ("setting max buffer size to %d", stream->max_buffer_size);
14028 qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
14029 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
14033 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
14037 _codec ("DVD subtitle");
14038 caps = gst_caps_new_empty_simple ("subpicture/x-dvd");
14039 stream->need_process = TRUE;
14042 _codec ("Quicktime timed text");
14045 _codec ("3GPP timed text");
14047 caps = gst_caps_new_simple ("text/x-raw", "format", G_TYPE_STRING,
14049 /* actual text piece needs to be extracted */
14050 stream->need_process = TRUE;
14053 _codec ("XML subtitles");
14054 caps = gst_caps_new_empty_simple ("application/ttml+xml");
14058 caps = _get_unknown_codec_name ("text", fourcc);
14066 qtdemux_generic_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
14067 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
14073 _codec ("MPEG 1 video");
14074 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
14075 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14085 gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux,
14086 const gchar * system_id)
14090 if (!qtdemux->protection_system_ids)
14091 qtdemux->protection_system_ids =
14092 g_ptr_array_new_with_free_func ((GDestroyNotify) g_free);
14093 /* Check whether we already have an entry for this system ID. */
14094 for (i = 0; i < qtdemux->protection_system_ids->len; ++i) {
14095 const gchar *id = g_ptr_array_index (qtdemux->protection_system_ids, i);
14096 if (g_ascii_strcasecmp (system_id, id) == 0) {
14100 GST_DEBUG_OBJECT (qtdemux, "Adding cenc protection system ID %s", system_id);
14101 g_ptr_array_add (qtdemux->protection_system_ids, g_ascii_strdown (system_id,