2 * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
3 * Copyright (C) <2003> David A. Schleef <ds@schleef.org>
4 * Copyright (C) <2006> Wim Taymans <wim@fluendo.com>
5 * Copyright (C) <2007> Julien Moutte <julien@fluendo.com>
6 * Copyright (C) <2009> Tim-Philipp Müller <tim centricular net>
7 * Copyright (C) <2009> STEricsson <benjamin.gaignard@stericsson.com>
8 * Copyright (C) <2013> Sreerenj Balachandran <sreerenj.balachandran@intel.com>
9 * Copyright (C) <2013> Intel Corporation
10 * Copyright (C) <2014> Centricular Ltd
11 * Copyright (C) <2015> YouView TV Ltd.
12 * Copyright (C) <2016> British Broadcasting Corporation
14 * This library is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU Library General Public
16 * License as published by the Free Software Foundation; either
17 * version 2 of the License, or (at your option) any later version.
19 * This library is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * Library General Public License for more details.
24 * You should have received a copy of the GNU Library General Public
25 * License along with this library; if not, write to the
26 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
27 * Boston, MA 02110-1301, USA.
31 * SECTION:element-qtdemux
33 * Demuxes a .mov file into raw or compressed audio and/or video streams.
35 * This element supports both push and pull-based scheduling, depending on the
36 * capabilities of the upstream elements.
39 * <title>Example launch line</title>
41 * gst-launch-1.0 filesrc location=test.mov ! qtdemux name=demux demux.audio_0 ! queue ! decodebin ! audioconvert ! audioresample ! autoaudiosink demux.video_0 ! queue ! decodebin ! videoconvert ! videoscale ! autovideosink
42 * ]| Play (parse and decode) a .mov file and try to output it to
43 * an automatically detected soundcard and videosink. If the MOV file contains
44 * compressed audio or video data, this will only work if you have the
45 * right decoder elements/plugins installed.
53 #include "gst/gst-i18n-plugin.h"
55 #include <glib/gprintf.h>
56 #include <gst/tag/tag.h>
57 #include <gst/audio/audio.h>
58 #include <gst/video/video.h>
60 #include "qtatomparser.h"
61 #include "qtdemux_types.h"
62 #include "qtdemux_dump.h"
64 #include "descriptors.h"
65 #include "qtdemux_lang.h"
67 #include "qtpalette.h"
69 #include "gst/riff/riff-media.h"
70 #include "gst/riff/riff-read.h"
72 #include <gst/pbutils/pbutils.h>
79 #include <gst/math-compat.h>
85 /* max. size considered 'sane' for non-mdat atoms */
86 #define QTDEMUX_MAX_ATOM_SIZE (25*1024*1024)
88 /* if the sample index is larger than this, something is likely wrong */
89 #define QTDEMUX_MAX_SAMPLE_INDEX_SIZE (50*1024*1024)
91 /* For converting qt creation times to unix epoch times */
92 #define QTDEMUX_SECONDS_PER_DAY (60 * 60 * 24)
93 #define QTDEMUX_LEAP_YEARS_FROM_1904_TO_1970 17
94 #define QTDEMUX_SECONDS_FROM_1904_TO_1970 (((1970 - 1904) * (guint64) 365 + \
95 QTDEMUX_LEAP_YEARS_FROM_1904_TO_1970) * QTDEMUX_SECONDS_PER_DAY)
97 #define STREAM_IS_EOS(s) (s->time_position == GST_CLOCK_TIME_NONE)
99 #define ABSDIFF(x, y) ( (x) > (y) ? ((x) - (y)) : ((y) - (x)) )
101 GST_DEBUG_CATEGORY (qtdemux_debug);
103 typedef struct _QtDemuxSegment QtDemuxSegment;
104 typedef struct _QtDemuxSample QtDemuxSample;
106 typedef struct _QtDemuxCencSampleSetInfo QtDemuxCencSampleSetInfo;
108 struct _QtDemuxSample
111 gint32 pts_offset; /* Add this value to timestamp to get the pts */
113 guint64 timestamp; /* DTS In mov time */
114 guint32 duration; /* In mov time */
115 gboolean keyframe; /* TRUE when this packet is a keyframe */
118 /* Macros for converting to/from timescale */
119 #define QTSTREAMTIME_TO_GSTTIME(stream, value) (gst_util_uint64_scale((value), GST_SECOND, (stream)->timescale))
120 #define GSTTIME_TO_QTSTREAMTIME(stream, value) (gst_util_uint64_scale((value), (stream)->timescale, GST_SECOND))
122 #define QTTIME_TO_GSTTIME(qtdemux, value) (gst_util_uint64_scale((value), GST_SECOND, (qtdemux)->timescale))
123 #define GSTTIME_TO_QTTIME(qtdemux, value) (gst_util_uint64_scale((value), (qtdemux)->timescale, GST_SECOND))
125 /* timestamp is the DTS */
126 #define QTSAMPLE_DTS(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp))
127 /* timestamp + offset is the PTS */
128 #define QTSAMPLE_PTS(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp + (stream)->cslg_shift + (sample)->pts_offset))
129 /* timestamp + duration - dts is the duration */
130 #define QTSAMPLE_DUR_DTS(stream, sample, dts) (QTSTREAMTIME_TO_GSTTIME ((stream), (sample)->timestamp + (sample)->duration) - (dts))
132 #define QTSAMPLE_KEYFRAME(stream,sample) ((stream)->all_keyframe || (sample)->keyframe)
135 * Quicktime has tracks and segments. A track is a continuous piece of
136 * multimedia content. The track is not always played from start to finish but
137 * instead, pieces of the track are 'cut out' and played in sequence. This is
138 * what the segments do.
140 * Inside the track we have keyframes (K) and delta frames. The track has its
141 * own timing, which starts from 0 and extends to end. The position in the track
142 * is called the media_time.
144 * The segments now describe the pieces that should be played from this track
145 * and are basically tuples of media_time/duration/rate entries. We can have
146 * multiple segments and they are all played after one another. An example:
148 * segment 1: media_time: 1 second, duration: 1 second, rate 1
149 * segment 2: media_time: 3 second, duration: 2 second, rate 2
151 * To correctly play back this track, one must play: 1 second of media starting
152 * from media_time 1 followed by 2 seconds of media starting from media_time 3
155 * Each of the segments will be played at a specific time, the first segment at
156 * time 0, the second one after the duration of the first one, etc.. Note that
157 * the time in resulting playback is not identical to the media_time of the
160 * Visually, assuming the track has 4 second of media_time:
163 * .-----------------------------------------------------------.
164 * track: | K.....K.........K........K.......K.......K...........K... |
165 * '-----------------------------------------------------------'
167 * .------------^ ^ .----------^ ^
168 * / .-------------' / .------------------'
170 * .--------------. .--------------.
171 * | segment 1 | | segment 2 |
172 * '--------------' '--------------'
174 * The challenge here is to cut out the right pieces of the track for each of
175 * the playback segments. This fortunately can easily be done with the SEGMENT
176 * events of GStreamer.
178 * For playback of segment 1, we need to provide the decoder with the keyframe
179 * (a), in the above figure, but we must instruct it only to output the decoded
180 * data between second 1 and 2. We do this with a SEGMENT event for 1 to 2, time
181 * position set to the time of the segment: 0.
183 * We then proceed to push data from keyframe (a) to frame (b). The decoder
184 * decodes but clips all before media_time 1.
186 * After finishing a segment, we push out a new SEGMENT event with the clipping
187 * boundaries of the new data.
189 * This is a good usecase for the GStreamer accumulated SEGMENT events.
192 struct _QtDemuxSegment
194 /* global time and duration, all gst time */
196 GstClockTime stop_time;
197 GstClockTime duration;
198 /* media time of trak, all gst time */
199 GstClockTime media_start;
200 GstClockTime media_stop;
202 /* Media start time in trak timescale units */
203 guint32 trak_media_start;
206 #define QTSEGMENT_IS_EMPTY(s) ((s)->media_start == GST_CLOCK_TIME_NONE)
208 /* Used with fragmented MP4 files (mfra atom) */
213 } QtDemuxRandomAccessEntry;
215 struct _QtDemuxStream
225 gboolean new_caps; /* If TRUE, caps need to be generated (by
226 * calling _configure_stream()) This happens
227 * for MSS and fragmented streams */
229 gboolean new_stream; /* signals that a stream_start is required */
230 gboolean on_keyframe; /* if this stream last pushed buffer was a
231 * keyframe. This is important to identify
232 * where to stop pushing buffers after a
233 * segment stop time */
235 /* if the stream has a redirect URI in its headers, we store it here */
242 guint64 duration; /* in timescale units */
246 gchar lang_id[4]; /* ISO 639-2T language code */
250 QtDemuxSample *samples;
251 gboolean all_keyframe; /* TRUE when all samples are keyframes (no stss) */
252 guint32 first_duration; /* duration in timescale of first sample, used for figuring out
254 guint32 n_samples_moof; /* sample count in a moof */
255 guint64 duration_moof; /* duration in timescale of a moof, used for figure out
256 * the framerate of fragmented format stream */
257 guint64 duration_last_moof;
259 guint32 offset_in_sample; /* Offset in the current sample, used for
260 * streams which have got exceedingly big
261 * sample size (such as 24s of raw audio).
262 * Only used when max_buffer_size is non-NULL */
263 guint32 max_buffer_size; /* Maximum allowed size for output buffers.
264 * Currently only set for raw audio streams*/
266 /* if we use chunks or samples */
278 /* Numerator/denominator framerate */
281 GstVideoColorimetry colorimetry;
282 guint16 bits_per_sample;
283 guint16 color_table_id;
284 GstMemory *rgb8_palette;
289 guint samples_per_packet;
290 guint samples_per_frame;
291 guint bytes_per_packet;
292 guint bytes_per_sample;
293 guint bytes_per_frame;
297 gboolean use_allocator;
298 GstAllocator *allocator;
299 GstAllocationParams params;
301 /* when a discontinuity is pending */
304 /* list of buffers to push first */
307 /* if we need to clip this buffer. This is only needed for uncompressed
311 /* buffer needs some custom processing, e.g. subtitles */
312 gboolean need_process;
314 /* current position */
315 guint32 segment_index;
316 guint32 sample_index;
317 GstClockTime time_position; /* in gst time */
318 guint64 accumulated_base;
320 /* the Gst segment we are processing out, used for clipping */
323 /* quicktime segments */
325 QtDemuxSegment *segments;
326 gboolean dummy_segment;
331 GstTagList *pending_tags;
332 gboolean send_global_tags;
334 GstEvent *pending_event;
344 gboolean chunks_are_samples; /* TRUE means treat chunks as samples */
348 GstByteReader co_chunk;
350 guint32 current_chunk;
352 guint32 samples_per_chunk;
353 guint32 stco_sample_index;
355 guint32 sample_size; /* 0 means variable sizes are stored in stsz */
358 guint32 n_samples_per_chunk;
359 guint32 stsc_chunk_index;
360 guint32 stsc_sample_index;
361 guint64 chunk_offset;
364 guint32 stts_samples;
365 guint32 n_sample_times;
366 guint32 stts_sample_index;
368 guint32 stts_duration;
370 gboolean stss_present;
371 guint32 n_sample_syncs;
374 gboolean stps_present;
375 guint32 n_sample_partial_syncs;
377 QtDemuxRandomAccessEntry *ra_entries;
380 const QtDemuxRandomAccessEntry *pending_seek;
383 gboolean ctts_present;
384 guint32 n_composition_times;
386 guint32 ctts_sample_index;
394 gboolean parsed_trex;
395 guint32 def_sample_duration;
396 guint32 def_sample_size;
397 guint32 def_sample_flags;
401 /* stereoscopic video streams */
402 GstVideoMultiviewMode multiview_mode;
403 GstVideoMultiviewFlags multiview_flags;
405 /* protected streams */
407 guint32 protection_scheme_type;
408 guint32 protection_scheme_version;
409 gpointer protection_scheme_info; /* specific to the protection scheme */
410 GQueue protection_scheme_event_queue;
413 /* Contains properties and cryptographic info for a set of samples from a
414 * track protected using Common Encryption (cenc) */
415 struct _QtDemuxCencSampleSetInfo
417 GstStructure *default_properties;
419 /* @crypto_info holds one GstStructure per sample */
420 GPtrArray *crypto_info;
424 qt_demux_state_string (enum QtDemuxState state)
427 case QTDEMUX_STATE_INITIAL:
429 case QTDEMUX_STATE_HEADER:
431 case QTDEMUX_STATE_MOVIE:
433 case QTDEMUX_STATE_BUFFER_MDAT:
434 return "<BUFFER_MDAT>";
440 static GNode *qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc);
441 static GNode *qtdemux_tree_get_child_by_type_full (GNode * node,
442 guint32 fourcc, GstByteReader * parser);
443 static GNode *qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc);
444 static GNode *qtdemux_tree_get_sibling_by_type_full (GNode * node,
445 guint32 fourcc, GstByteReader * parser);
447 static GstFlowReturn qtdemux_add_fragmented_samples (GstQTDemux * qtdemux);
449 static GstStaticPadTemplate gst_qtdemux_sink_template =
450 GST_STATIC_PAD_TEMPLATE ("sink",
453 GST_STATIC_CAPS ("video/quicktime; video/mj2; audio/x-m4a; "
457 static GstStaticPadTemplate gst_qtdemux_videosrc_template =
458 GST_STATIC_PAD_TEMPLATE ("video_%u",
461 GST_STATIC_CAPS_ANY);
463 static GstStaticPadTemplate gst_qtdemux_audiosrc_template =
464 GST_STATIC_PAD_TEMPLATE ("audio_%u",
467 GST_STATIC_CAPS_ANY);
469 static GstStaticPadTemplate gst_qtdemux_subsrc_template =
470 GST_STATIC_PAD_TEMPLATE ("subtitle_%u",
473 GST_STATIC_CAPS_ANY);
475 #define gst_qtdemux_parent_class parent_class
476 G_DEFINE_TYPE (GstQTDemux, gst_qtdemux, GST_TYPE_ELEMENT);
478 static void gst_qtdemux_dispose (GObject * object);
481 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
482 GstClockTime media_time);
484 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
485 QtDemuxStream * str, gint64 media_offset);
488 static void gst_qtdemux_set_index (GstElement * element, GstIndex * index);
489 static GstIndex *gst_qtdemux_get_index (GstElement * element);
491 static GstStateChangeReturn gst_qtdemux_change_state (GstElement * element,
492 GstStateChange transition);
493 static gboolean qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent);
494 static gboolean qtdemux_sink_activate_mode (GstPad * sinkpad,
495 GstObject * parent, GstPadMode mode, gboolean active);
497 static void gst_qtdemux_loop (GstPad * pad);
498 static GstFlowReturn gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent,
500 static gboolean gst_qtdemux_handle_sink_event (GstPad * pad, GstObject * parent,
502 static gboolean gst_qtdemux_setcaps (GstQTDemux * qtdemux, GstCaps * caps);
503 static gboolean gst_qtdemux_configure_stream (GstQTDemux * qtdemux,
504 QtDemuxStream * stream);
505 static GstFlowReturn gst_qtdemux_process_adapter (GstQTDemux * demux,
508 static gboolean qtdemux_parse_moov (GstQTDemux * qtdemux,
509 const guint8 * buffer, guint length);
510 static gboolean qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node,
511 const guint8 * buffer, guint length);
512 static gboolean qtdemux_parse_tree (GstQTDemux * qtdemux);
513 static void qtdemux_parse_udta (GstQTDemux * qtdemux, GstTagList * taglist,
516 static void gst_qtdemux_handle_esds (GstQTDemux * qtdemux,
517 QtDemuxStream * stream, GNode * esds, GstTagList * list);
518 static GstCaps *qtdemux_video_caps (GstQTDemux * qtdemux,
519 QtDemuxStream * stream, guint32 fourcc, const guint8 * stsd_data,
520 gchar ** codec_name);
521 static GstCaps *qtdemux_audio_caps (GstQTDemux * qtdemux,
522 QtDemuxStream * stream, guint32 fourcc, const guint8 * data, int len,
523 gchar ** codec_name);
524 static GstCaps *qtdemux_sub_caps (GstQTDemux * qtdemux,
525 QtDemuxStream * stream, guint32 fourcc, const guint8 * data,
526 gchar ** codec_name);
527 static GstCaps *qtdemux_generic_caps (GstQTDemux * qtdemux,
528 QtDemuxStream * stream, guint32 fourcc, const guint8 * stsd_data,
529 gchar ** codec_name);
531 static gboolean qtdemux_parse_samples (GstQTDemux * qtdemux,
532 QtDemuxStream * stream, guint32 n);
533 static GstFlowReturn qtdemux_expose_streams (GstQTDemux * qtdemux);
534 static void gst_qtdemux_stream_free (GstQTDemux * qtdemux,
535 QtDemuxStream * stream);
536 static void gst_qtdemux_stream_clear (GstQTDemux * qtdemux,
537 QtDemuxStream * stream);
538 static void gst_qtdemux_remove_stream (GstQTDemux * qtdemux, int index);
539 static GstFlowReturn qtdemux_prepare_streams (GstQTDemux * qtdemux);
540 static void qtdemux_do_allocation (GstQTDemux * qtdemux,
541 QtDemuxStream * stream);
542 static gboolean gst_qtdemux_activate_segment (GstQTDemux * qtdemux,
543 QtDemuxStream * stream, guint32 seg_idx, GstClockTime offset);
544 static gboolean gst_qtdemux_stream_update_segment (GstQTDemux * qtdemux,
545 QtDemuxStream * stream, gint seg_idx, GstClockTime offset,
546 GstClockTime * _start, GstClockTime * _stop);
547 static void gst_qtdemux_send_gap_for_segment (GstQTDemux * demux,
548 QtDemuxStream * stream, gint segment_index, GstClockTime pos);
550 static gboolean qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux);
551 static void check_update_duration (GstQTDemux * qtdemux, GstClockTime duration);
553 static gchar *qtdemux_uuid_bytes_to_string (gconstpointer uuid_bytes);
555 static GstStructure *qtdemux_get_cenc_sample_properties (GstQTDemux * qtdemux,
556 QtDemuxStream * stream, guint sample_index);
557 static void gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux,
559 static void qtdemux_gst_structure_free (GstStructure * gststructure);
562 gst_qtdemux_class_init (GstQTDemuxClass * klass)
564 GObjectClass *gobject_class;
565 GstElementClass *gstelement_class;
567 gobject_class = (GObjectClass *) klass;
568 gstelement_class = (GstElementClass *) klass;
570 parent_class = g_type_class_peek_parent (klass);
572 gobject_class->dispose = gst_qtdemux_dispose;
574 gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_qtdemux_change_state);
576 gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_qtdemux_set_index);
577 gstelement_class->get_index = GST_DEBUG_FUNCPTR (gst_qtdemux_get_index);
580 gst_tag_register_musicbrainz_tags ();
582 gst_element_class_add_static_pad_template (gstelement_class,
583 &gst_qtdemux_sink_template);
584 gst_element_class_add_static_pad_template (gstelement_class,
585 &gst_qtdemux_videosrc_template);
586 gst_element_class_add_static_pad_template (gstelement_class,
587 &gst_qtdemux_audiosrc_template);
588 gst_element_class_add_static_pad_template (gstelement_class,
589 &gst_qtdemux_subsrc_template);
590 gst_element_class_set_static_metadata (gstelement_class, "QuickTime demuxer",
592 "Demultiplex a QuickTime file into audio and video streams",
593 "David Schleef <ds@schleef.org>, Wim Taymans <wim@fluendo.com>");
595 GST_DEBUG_CATEGORY_INIT (qtdemux_debug, "qtdemux", 0, "qtdemux plugin");
600 gst_qtdemux_init (GstQTDemux * qtdemux)
603 gst_pad_new_from_static_template (&gst_qtdemux_sink_template, "sink");
604 gst_pad_set_activate_function (qtdemux->sinkpad, qtdemux_sink_activate);
605 gst_pad_set_activatemode_function (qtdemux->sinkpad,
606 qtdemux_sink_activate_mode);
607 gst_pad_set_chain_function (qtdemux->sinkpad, gst_qtdemux_chain);
608 gst_pad_set_event_function (qtdemux->sinkpad, gst_qtdemux_handle_sink_event);
609 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), qtdemux->sinkpad);
611 qtdemux->state = QTDEMUX_STATE_INITIAL;
612 qtdemux->pullbased = FALSE;
613 qtdemux->posted_redirect = FALSE;
614 qtdemux->neededbytes = 16;
616 qtdemux->adapter = gst_adapter_new ();
618 qtdemux->first_mdat = -1;
619 qtdemux->got_moov = FALSE;
620 qtdemux->mdatoffset = -1;
621 qtdemux->mdatbuffer = NULL;
622 qtdemux->restoredata_buffer = NULL;
623 qtdemux->restoredata_offset = -1;
624 qtdemux->fragment_start = -1;
625 qtdemux->fragment_start_offset = -1;
626 qtdemux->media_caps = NULL;
627 qtdemux->exposed = FALSE;
628 qtdemux->mss_mode = FALSE;
629 qtdemux->pending_newsegment = NULL;
630 qtdemux->upstream_format_is_time = FALSE;
631 qtdemux->have_group_id = FALSE;
632 qtdemux->group_id = G_MAXUINT;
633 qtdemux->cenc_aux_info_offset = 0;
634 qtdemux->cenc_aux_info_sizes = NULL;
635 qtdemux->cenc_aux_sample_count = 0;
636 qtdemux->protection_system_ids = NULL;
637 g_queue_init (&qtdemux->protection_event_queue);
638 gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
639 qtdemux->flowcombiner = gst_flow_combiner_new ();
641 GST_OBJECT_FLAG_SET (qtdemux, GST_ELEMENT_FLAG_INDEXABLE);
645 gst_qtdemux_dispose (GObject * object)
647 GstQTDemux *qtdemux = GST_QTDEMUX (object);
649 if (qtdemux->adapter) {
650 g_object_unref (G_OBJECT (qtdemux->adapter));
651 qtdemux->adapter = NULL;
653 gst_flow_combiner_free (qtdemux->flowcombiner);
654 g_queue_foreach (&qtdemux->protection_event_queue, (GFunc) gst_event_unref,
656 g_queue_clear (&qtdemux->protection_event_queue);
658 g_free (qtdemux->cenc_aux_info_sizes);
659 qtdemux->cenc_aux_info_sizes = NULL;
661 G_OBJECT_CLASS (parent_class)->dispose (object);
665 gst_qtdemux_post_no_playable_stream_error (GstQTDemux * qtdemux)
667 if (qtdemux->posted_redirect) {
668 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
669 (_("This file contains no playable streams.")),
670 ("no known streams found, a redirect message has been posted"));
672 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
673 (_("This file contains no playable streams.")),
674 ("no known streams found"));
679 _gst_buffer_new_wrapped (gpointer mem, gsize size, GFreeFunc free_func)
681 return gst_buffer_new_wrapped_full (free_func ? 0 : GST_MEMORY_FLAG_READONLY,
682 mem, size, 0, size, mem, free_func);
686 gst_qtdemux_pull_atom (GstQTDemux * qtdemux, guint64 offset, guint64 size,
693 if (G_UNLIKELY (size == 0)) {
695 GstBuffer *tmp = NULL;
697 ret = gst_qtdemux_pull_atom (qtdemux, offset, sizeof (guint32), &tmp);
698 if (ret != GST_FLOW_OK)
701 gst_buffer_map (tmp, &map, GST_MAP_READ);
702 size = QT_UINT32 (map.data);
703 GST_DEBUG_OBJECT (qtdemux, "size 0x%08" G_GINT64_MODIFIER "x", size);
705 gst_buffer_unmap (tmp, &map);
706 gst_buffer_unref (tmp);
709 /* Sanity check: catch bogus sizes (fuzzed/broken files) */
710 if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
711 if (qtdemux->state != QTDEMUX_STATE_MOVIE && qtdemux->got_moov) {
712 /* we're pulling header but already got most interesting bits,
713 * so never mind the rest (e.g. tags) (that much) */
714 GST_WARNING_OBJECT (qtdemux, "atom has bogus size %" G_GUINT64_FORMAT,
718 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
719 (_("This file is invalid and cannot be played.")),
720 ("atom has bogus size %" G_GUINT64_FORMAT, size));
721 return GST_FLOW_ERROR;
725 flow = gst_pad_pull_range (qtdemux->sinkpad, offset, size, buf);
727 if (G_UNLIKELY (flow != GST_FLOW_OK))
730 bsize = gst_buffer_get_size (*buf);
731 /* Catch short reads - we don't want any partial atoms */
732 if (G_UNLIKELY (bsize < size)) {
733 GST_WARNING_OBJECT (qtdemux,
734 "short read: %" G_GSIZE_FORMAT " < %" G_GUINT64_FORMAT, bsize, size);
735 gst_buffer_unref (*buf);
745 gst_qtdemux_src_convert (GstQTDemux * qtdemux, GstPad * pad,
746 GstFormat src_format, gint64 src_value, GstFormat dest_format,
750 QtDemuxStream *stream = gst_pad_get_element_private (pad);
753 if (stream->subtype != FOURCC_vide) {
758 switch (src_format) {
759 case GST_FORMAT_TIME:
760 switch (dest_format) {
761 case GST_FORMAT_BYTES:{
762 index = gst_qtdemux_find_index_linear (qtdemux, stream, src_value);
768 *dest_value = stream->samples[index].offset;
770 GST_DEBUG_OBJECT (qtdemux, "Format Conversion Time->Offset :%"
771 GST_TIME_FORMAT "->%" G_GUINT64_FORMAT,
772 GST_TIME_ARGS (src_value), *dest_value);
780 case GST_FORMAT_BYTES:
781 switch (dest_format) {
782 case GST_FORMAT_TIME:{
784 gst_qtdemux_find_index_for_given_media_offset_linear (qtdemux,
793 QTSTREAMTIME_TO_GSTTIME (stream,
794 stream->samples[index].timestamp);
795 GST_DEBUG_OBJECT (qtdemux,
796 "Format Conversion Offset->Time :%" G_GUINT64_FORMAT "->%"
797 GST_TIME_FORMAT, src_value, GST_TIME_ARGS (*dest_value));
816 gst_qtdemux_get_duration (GstQTDemux * qtdemux, GstClockTime * duration)
818 gboolean res = FALSE;
820 *duration = GST_CLOCK_TIME_NONE;
822 if (qtdemux->duration != 0 &&
823 qtdemux->duration != G_MAXINT64 && qtdemux->timescale != 0) {
824 *duration = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
827 *duration = GST_CLOCK_TIME_NONE;
834 gst_qtdemux_handle_src_query (GstPad * pad, GstObject * parent,
837 gboolean res = FALSE;
838 GstQTDemux *qtdemux = GST_QTDEMUX (parent);
840 GST_LOG_OBJECT (pad, "%s query", GST_QUERY_TYPE_NAME (query));
842 switch (GST_QUERY_TYPE (query)) {
843 case GST_QUERY_POSITION:{
846 gst_query_parse_position (query, &fmt, NULL);
847 if (fmt == GST_FORMAT_TIME
848 && GST_CLOCK_TIME_IS_VALID (qtdemux->segment.position)) {
849 gst_query_set_position (query, GST_FORMAT_TIME,
850 qtdemux->segment.position);
855 case GST_QUERY_DURATION:{
858 gst_query_parse_duration (query, &fmt, NULL);
859 if (fmt == GST_FORMAT_TIME) {
860 /* First try to query upstream */
861 res = gst_pad_query_default (pad, parent, query);
863 GstClockTime duration;
864 if (gst_qtdemux_get_duration (qtdemux, &duration) && duration > 0) {
865 gst_query_set_duration (query, GST_FORMAT_TIME, duration);
872 case GST_QUERY_CONVERT:{
873 GstFormat src_fmt, dest_fmt;
874 gint64 src_value, dest_value = 0;
876 gst_query_parse_convert (query, &src_fmt, &src_value, &dest_fmt, NULL);
878 res = gst_qtdemux_src_convert (qtdemux, pad,
879 src_fmt, src_value, dest_fmt, &dest_value);
881 gst_query_set_convert (query, src_fmt, src_value, dest_fmt, dest_value);
886 case GST_QUERY_FORMATS:
887 gst_query_set_formats (query, 2, GST_FORMAT_TIME, GST_FORMAT_BYTES);
890 case GST_QUERY_SEEKING:{
894 /* try upstream first */
895 res = gst_pad_query_default (pad, parent, query);
898 gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
899 if (fmt == GST_FORMAT_TIME) {
900 GstClockTime duration;
902 gst_qtdemux_get_duration (qtdemux, &duration);
904 if (!qtdemux->pullbased) {
907 /* we might be able with help from upstream */
909 q = gst_query_new_seeking (GST_FORMAT_BYTES);
910 if (gst_pad_peer_query (qtdemux->sinkpad, q)) {
911 gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL);
912 GST_LOG_OBJECT (qtdemux, "upstream BYTE seekable %d", seekable);
916 gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0, duration);
922 case GST_QUERY_SEGMENT:
927 format = qtdemux->segment.format;
930 gst_segment_to_stream_time (&qtdemux->segment, format,
931 qtdemux->segment.start);
932 if ((stop = qtdemux->segment.stop) == -1)
933 stop = qtdemux->segment.duration;
935 stop = gst_segment_to_stream_time (&qtdemux->segment, format, stop);
937 gst_query_set_segment (query, qtdemux->segment.rate, format, start, stop);
942 res = gst_pad_query_default (pad, parent, query);
950 gst_qtdemux_push_tags (GstQTDemux * qtdemux, QtDemuxStream * stream)
952 if (G_LIKELY (stream->pad)) {
953 GST_DEBUG_OBJECT (qtdemux, "Checking pad %s:%s for tags",
954 GST_DEBUG_PAD_NAME (stream->pad));
956 if (G_UNLIKELY (stream->pending_tags)) {
957 GST_DEBUG_OBJECT (qtdemux, "Sending tags %" GST_PTR_FORMAT,
958 stream->pending_tags);
959 gst_pad_push_event (stream->pad,
960 gst_event_new_tag (stream->pending_tags));
961 stream->pending_tags = NULL;
964 if (G_UNLIKELY (stream->send_global_tags && qtdemux->tag_list)) {
965 GST_DEBUG_OBJECT (qtdemux, "Sending global tags %" GST_PTR_FORMAT,
967 gst_pad_push_event (stream->pad,
968 gst_event_new_tag (gst_tag_list_ref (qtdemux->tag_list)));
969 stream->send_global_tags = FALSE;
974 /* push event on all source pads; takes ownership of the event */
976 gst_qtdemux_push_event (GstQTDemux * qtdemux, GstEvent * event)
979 gboolean has_valid_stream = FALSE;
980 GstEventType etype = GST_EVENT_TYPE (event);
982 GST_DEBUG_OBJECT (qtdemux, "pushing %s event on all source pads",
983 GST_EVENT_TYPE_NAME (event));
985 for (n = 0; n < qtdemux->n_streams; n++) {
987 QtDemuxStream *stream = qtdemux->streams[n];
988 GST_DEBUG_OBJECT (qtdemux, "pushing on pad %i", n);
990 if ((pad = stream->pad)) {
991 has_valid_stream = TRUE;
993 if (etype == GST_EVENT_EOS) {
994 /* let's not send twice */
995 if (stream->sent_eos)
997 stream->sent_eos = TRUE;
1000 gst_pad_push_event (pad, gst_event_ref (event));
1004 gst_event_unref (event);
1006 /* if it is EOS and there are no pads, post an error */
1007 if (!has_valid_stream && etype == GST_EVENT_EOS) {
1008 gst_qtdemux_post_no_playable_stream_error (qtdemux);
1012 /* push a pending newsegment event, if any from the streaming thread */
1014 gst_qtdemux_push_pending_newsegment (GstQTDemux * qtdemux)
1016 if (qtdemux->pending_newsegment) {
1017 gst_qtdemux_push_event (qtdemux, qtdemux->pending_newsegment);
1018 qtdemux->pending_newsegment = NULL;
1028 find_func (QtDemuxSample * s1, gint64 * media_time, gpointer user_data)
1030 if ((gint64) s1->timestamp + s1->pts_offset > *media_time)
1032 if ((gint64) s1->timestamp + s1->pts_offset == *media_time)
1038 /* find the index of the sample that includes the data for @media_time using a
1039 * binary search. Only to be called in optimized cases of linear search below.
1041 * Returns the index of the sample.
1044 gst_qtdemux_find_index (GstQTDemux * qtdemux, QtDemuxStream * str,
1047 QtDemuxSample *result;
1050 /* convert media_time to mov format */
1052 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
1054 result = gst_util_array_binary_search (str->samples, str->stbl_index + 1,
1055 sizeof (QtDemuxSample), (GCompareDataFunc) find_func,
1056 GST_SEARCH_MODE_BEFORE, &media_time, NULL);
1058 if (G_LIKELY (result))
1059 index = result - str->samples;
1068 /* find the index of the sample that includes the data for @media_offset using a
1071 * Returns the index of the sample.
1074 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
1075 QtDemuxStream * str, gint64 media_offset)
1077 QtDemuxSample *result = str->samples;
1080 if (result == NULL || str->n_samples == 0)
1083 if (media_offset == result->offset)
1087 while (index < str->n_samples - 1) {
1088 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
1091 if (media_offset < result->offset)
1102 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
1107 /* find the index of the sample that includes the data for @media_time using a
1108 * linear search, and keeping in mind that not all samples may have been parsed
1109 * yet. If possible, it will delegate to binary search.
1111 * Returns the index of the sample.
1114 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
1115 GstClockTime media_time)
1119 QtDemuxSample *sample;
1121 /* convert media_time to mov format */
1123 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
1125 sample = str->samples;
1126 if (mov_time == sample->timestamp + sample->pts_offset)
1129 /* use faster search if requested time in already parsed range */
1130 sample = str->samples + str->stbl_index;
1131 if (str->stbl_index >= 0 &&
1132 mov_time <= (sample->timestamp + sample->pts_offset))
1133 return gst_qtdemux_find_index (qtdemux, str, media_time);
1135 while (index < str->n_samples - 1) {
1136 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
1139 sample = str->samples + index + 1;
1140 if (mov_time < (sample->timestamp + sample->pts_offset))
1150 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
1155 /* find the index of the keyframe needed to decode the sample at @index
1158 * Returns the index of the keyframe.
1161 gst_qtdemux_find_keyframe (GstQTDemux * qtdemux, QtDemuxStream * str,
1164 guint32 new_index = index;
1166 if (index >= str->n_samples) {
1167 new_index = str->n_samples;
1171 /* all keyframes, return index */
1172 if (str->all_keyframe) {
1177 /* else go back until we have a keyframe */
1179 if (str->samples[new_index].keyframe)
1189 GST_DEBUG_OBJECT (qtdemux, "searching for keyframe index before index %u "
1190 "gave %u", index, new_index);
1195 /* find the segment for @time_position for @stream
1197 * Returns the index of the segment containing @time_position.
1198 * Returns the last segment and sets the @eos variable to TRUE
1199 * if the time is beyond the end. @eos may be NULL
1202 gst_qtdemux_find_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
1203 GstClockTime time_position)
1208 GST_LOG_OBJECT (stream->pad, "finding segment for %" GST_TIME_FORMAT,
1209 GST_TIME_ARGS (time_position));
1212 for (i = 0; i < stream->n_segments; i++) {
1213 QtDemuxSegment *segment = &stream->segments[i];
1215 GST_LOG_OBJECT (stream->pad,
1216 "looking at segment %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT,
1217 GST_TIME_ARGS (segment->time), GST_TIME_ARGS (segment->stop_time));
1219 /* For the last segment we include stop_time in the last segment */
1220 if (i < stream->n_segments - 1) {
1221 if (segment->time <= time_position && time_position < segment->stop_time) {
1222 GST_LOG_OBJECT (stream->pad, "segment %d matches", i);
1227 /* Last segment always matches */
1235 /* move the stream @str to the sample position @index.
1237 * Updates @str->sample_index and marks discontinuity if needed.
1240 gst_qtdemux_move_stream (GstQTDemux * qtdemux, QtDemuxStream * str,
1243 /* no change needed */
1244 if (index == str->sample_index)
1247 GST_DEBUG_OBJECT (qtdemux, "moving to sample %u of %u", index,
1250 /* position changed, we have a discont */
1251 str->sample_index = index;
1252 str->offset_in_sample = 0;
1253 /* Each time we move in the stream we store the position where we are
1255 str->from_sample = index;
1256 str->discont = TRUE;
1260 gst_qtdemux_adjust_seek (GstQTDemux * qtdemux, gint64 desired_time,
1261 gboolean use_sparse, gint64 * key_time, gint64 * key_offset)
1264 gint64 min_byte_offset = -1;
1267 min_offset = desired_time;
1269 /* for each stream, find the index of the sample in the segment
1270 * and move back to the previous keyframe. */
1271 for (n = 0; n < qtdemux->n_streams; n++) {
1273 guint32 index, kindex;
1275 GstClockTime media_start;
1276 GstClockTime media_time;
1277 GstClockTime seg_time;
1278 QtDemuxSegment *seg;
1279 gboolean empty_segment = FALSE;
1281 str = qtdemux->streams[n];
1283 if (str->sparse && !use_sparse)
1286 seg_idx = gst_qtdemux_find_segment (qtdemux, str, desired_time);
1287 GST_DEBUG_OBJECT (qtdemux, "align segment %d", seg_idx);
1289 /* get segment and time in the segment */
1290 seg = &str->segments[seg_idx];
1291 seg_time = (desired_time - seg->time) * seg->rate;
1293 while (QTSEGMENT_IS_EMPTY (seg)) {
1295 empty_segment = TRUE;
1296 GST_DEBUG_OBJECT (str->pad, "Segment %d is empty, moving to next one",
1299 if (seg_idx == str->n_segments)
1301 seg = &str->segments[seg_idx];
1304 if (seg_idx == str->n_segments) {
1305 /* FIXME track shouldn't have the last segment as empty, but if it
1306 * happens we better handle it */
1310 /* get the media time in the segment */
1311 media_start = seg->media_start + seg_time;
1313 /* get the index of the sample with media time */
1314 index = gst_qtdemux_find_index_linear (qtdemux, str, media_start);
1315 GST_DEBUG_OBJECT (qtdemux, "sample for %" GST_TIME_FORMAT " at %u"
1316 " at offset %" G_GUINT64_FORMAT " (empty segment: %d)",
1317 GST_TIME_ARGS (media_start), index, str->samples[index].offset,
1320 if (!empty_segment) {
1321 /* find previous keyframe */
1322 kindex = gst_qtdemux_find_keyframe (qtdemux, str, index);
1324 /* if the keyframe is at a different position, we need to update the
1325 * requested seek time */
1326 if (index != kindex) {
1329 /* get timestamp of keyframe */
1330 media_time = QTSAMPLE_DTS (str, &str->samples[kindex]);
1331 GST_DEBUG_OBJECT (qtdemux,
1332 "keyframe at %u with time %" GST_TIME_FORMAT " at offset %"
1333 G_GUINT64_FORMAT, kindex, GST_TIME_ARGS (media_time),
1334 str->samples[kindex].offset);
1336 /* keyframes in the segment get a chance to change the
1337 * desired_offset. keyframes out of the segment are
1339 if (media_time >= seg->media_start) {
1340 GstClockTime seg_time;
1342 /* this keyframe is inside the segment, convert back to
1344 seg_time = (media_time - seg->media_start) + seg->time;
1345 if (seg_time < min_offset)
1346 min_offset = seg_time;
1351 if (min_byte_offset < 0 || str->samples[index].offset < min_byte_offset)
1352 min_byte_offset = str->samples[index].offset;
1356 *key_time = min_offset;
1358 *key_offset = min_byte_offset;
1362 gst_qtdemux_convert_seek (GstPad * pad, GstFormat * format,
1363 GstSeekType cur_type, gint64 * cur, GstSeekType stop_type, gint64 * stop)
1367 g_return_val_if_fail (format != NULL, FALSE);
1368 g_return_val_if_fail (cur != NULL, FALSE);
1369 g_return_val_if_fail (stop != NULL, FALSE);
1371 if (*format == GST_FORMAT_TIME)
1375 if (cur_type != GST_SEEK_TYPE_NONE)
1376 res = gst_pad_query_convert (pad, *format, *cur, GST_FORMAT_TIME, cur);
1377 if (res && stop_type != GST_SEEK_TYPE_NONE)
1378 res = gst_pad_query_convert (pad, *format, *stop, GST_FORMAT_TIME, stop);
1381 *format = GST_FORMAT_TIME;
1386 /* perform seek in push based mode:
1387 find BYTE position to move to based on time and delegate to upstream
1390 gst_qtdemux_do_push_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1395 GstSeekType cur_type, stop_type;
1396 gint64 cur, stop, key_cur;
1399 gint64 original_stop;
1402 GST_DEBUG_OBJECT (qtdemux, "doing push-based seek");
1404 gst_event_parse_seek (event, &rate, &format, &flags,
1405 &cur_type, &cur, &stop_type, &stop);
1406 seqnum = gst_event_get_seqnum (event);
1408 /* only forward streaming and seeking is possible */
1410 goto unsupported_seek;
1412 /* convert to TIME if needed and possible */
1413 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1417 /* Upstream seek in bytes will have undefined stop, but qtdemux stores
1418 * the original stop position to use when upstream pushes the new segment
1420 original_stop = stop;
1423 /* find reasonable corresponding BYTE position,
1424 * also try to mind about keyframes, since we can not go back a bit for them
1426 gst_qtdemux_adjust_seek (qtdemux, cur, FALSE, &key_cur, &byte_cur);
1431 GST_DEBUG_OBJECT (qtdemux, "Pushing BYTE seek rate %g, "
1432 "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, byte_cur,
1435 GST_OBJECT_LOCK (qtdemux);
1436 qtdemux->seek_offset = byte_cur;
1437 if (!(flags & GST_SEEK_FLAG_KEY_UNIT)) {
1438 qtdemux->push_seek_start = cur;
1440 qtdemux->push_seek_start = key_cur;
1443 if (stop_type == GST_SEEK_TYPE_NONE) {
1444 qtdemux->push_seek_stop = qtdemux->segment.stop;
1446 qtdemux->push_seek_stop = original_stop;
1448 GST_OBJECT_UNLOCK (qtdemux);
1450 /* BYTE seek event */
1451 event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type, byte_cur,
1453 gst_event_set_seqnum (event, seqnum);
1454 res = gst_pad_push_event (qtdemux->sinkpad, event);
1461 GST_DEBUG_OBJECT (qtdemux, "could not determine byte position to seek to, "
1467 GST_DEBUG_OBJECT (qtdemux, "unsupported seek, seek aborted.");
1472 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1477 /* perform the seek.
1479 * We set all segment_indexes in the streams to unknown and
1480 * adjust the time_position to the desired position. this is enough
1481 * to trigger a segment switch in the streaming thread to start
1482 * streaming from the desired position.
1484 * Keyframe seeking is a little more complicated when dealing with
1485 * segments. Ideally we want to move to the previous keyframe in
1486 * the segment but there might not be a keyframe in the segment. In
1487 * fact, none of the segments could contain a keyframe. We take a
1488 * practical approach: seek to the previous keyframe in the segment,
1489 * if there is none, seek to the beginning of the segment.
1491 * Called with STREAM_LOCK
1494 gst_qtdemux_perform_seek (GstQTDemux * qtdemux, GstSegment * segment,
1495 guint32 seqnum, GstSeekFlags flags)
1497 gint64 desired_offset;
1500 desired_offset = segment->position;
1502 GST_DEBUG_OBJECT (qtdemux, "seeking to %" GST_TIME_FORMAT,
1503 GST_TIME_ARGS (desired_offset));
1505 /* may not have enough fragmented info to do this adjustment,
1506 * and we can't scan (and probably should not) at this time with
1507 * possibly flushing upstream */
1508 if ((flags & GST_SEEK_FLAG_KEY_UNIT) && !qtdemux->fragmented) {
1511 gst_qtdemux_adjust_seek (qtdemux, desired_offset, TRUE, &min_offset, NULL);
1512 GST_DEBUG_OBJECT (qtdemux, "keyframe seek, align to %"
1513 GST_TIME_FORMAT, GST_TIME_ARGS (min_offset));
1514 desired_offset = min_offset;
1517 /* and set all streams to the final position */
1518 gst_flow_combiner_reset (qtdemux->flowcombiner);
1519 qtdemux->segment_seqnum = seqnum;
1520 for (n = 0; n < qtdemux->n_streams; n++) {
1521 QtDemuxStream *stream = qtdemux->streams[n];
1523 stream->time_position = desired_offset;
1524 stream->accumulated_base = 0;
1525 stream->sample_index = -1;
1526 stream->offset_in_sample = 0;
1527 stream->segment_index = -1;
1528 stream->sent_eos = FALSE;
1530 if (segment->flags & GST_SEEK_FLAG_FLUSH)
1531 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
1533 segment->position = desired_offset;
1534 segment->time = desired_offset;
1535 if (segment->rate >= 0) {
1536 segment->start = desired_offset;
1538 /* we stop at the end */
1539 if (segment->stop == -1)
1540 segment->stop = segment->duration;
1542 segment->stop = desired_offset;
1545 if (qtdemux->fragmented)
1546 qtdemux->fragmented_seek_pending = TRUE;
1551 /* do a seek in pull based mode */
1553 gst_qtdemux_do_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1558 GstSeekType cur_type, stop_type;
1562 GstSegment seeksegment;
1564 GstEvent *flush_event;
1567 GST_DEBUG_OBJECT (qtdemux, "doing seek with event");
1569 gst_event_parse_seek (event, &rate, &format, &flags,
1570 &cur_type, &cur, &stop_type, &stop);
1571 seqnum = gst_event_get_seqnum (event);
1573 /* we have to have a format as the segment format. Try to convert
1575 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1579 GST_DEBUG_OBJECT (qtdemux, "seek format %s", gst_format_get_name (format));
1581 GST_DEBUG_OBJECT (qtdemux, "doing seek without event");
1585 flush = flags & GST_SEEK_FLAG_FLUSH;
1587 /* stop streaming, either by flushing or by pausing the task */
1589 flush_event = gst_event_new_flush_start ();
1591 gst_event_set_seqnum (flush_event, seqnum);
1592 /* unlock upstream pull_range */
1593 gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event));
1594 /* make sure out loop function exits */
1595 gst_qtdemux_push_event (qtdemux, flush_event);
1597 /* non flushing seek, pause the task */
1598 gst_pad_pause_task (qtdemux->sinkpad);
1601 /* wait for streaming to finish */
1602 GST_PAD_STREAM_LOCK (qtdemux->sinkpad);
1604 /* copy segment, we need this because we still need the old
1605 * segment when we close the current segment. */
1606 memcpy (&seeksegment, &qtdemux->segment, sizeof (GstSegment));
1609 /* configure the segment with the seek variables */
1610 GST_DEBUG_OBJECT (qtdemux, "configuring seek");
1611 gst_segment_do_seek (&seeksegment, rate, format, flags,
1612 cur_type, cur, stop_type, stop, &update);
1615 /* now do the seek, this actually never returns FALSE */
1616 gst_qtdemux_perform_seek (qtdemux, &seeksegment, seqnum, flags);
1618 /* prepare for streaming again */
1620 flush_event = gst_event_new_flush_stop (TRUE);
1622 gst_event_set_seqnum (flush_event, seqnum);
1624 gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event));
1625 gst_qtdemux_push_event (qtdemux, flush_event);
1628 /* commit the new segment */
1629 memcpy (&qtdemux->segment, &seeksegment, sizeof (GstSegment));
1631 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
1632 GstMessage *msg = gst_message_new_segment_start (GST_OBJECT_CAST (qtdemux),
1633 qtdemux->segment.format, qtdemux->segment.position);
1635 gst_message_set_seqnum (msg, seqnum);
1636 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
1639 /* restart streaming, NEWSEGMENT will be sent from the streaming thread. */
1640 gst_pad_start_task (qtdemux->sinkpad, (GstTaskFunction) gst_qtdemux_loop,
1641 qtdemux->sinkpad, NULL);
1643 GST_PAD_STREAM_UNLOCK (qtdemux->sinkpad);
1650 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1656 qtdemux_ensure_index (GstQTDemux * qtdemux)
1660 GST_DEBUG_OBJECT (qtdemux, "collecting all metadata for all streams");
1662 /* Build complete index */
1663 for (i = 0; i < qtdemux->n_streams; i++) {
1664 QtDemuxStream *stream = qtdemux->streams[i];
1666 if (!qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1))
1674 GST_LOG_OBJECT (qtdemux,
1675 "Building complete index of stream %u for seeking failed!", i);
1681 gst_qtdemux_handle_src_event (GstPad * pad, GstObject * parent,
1684 gboolean res = TRUE;
1685 GstQTDemux *qtdemux = GST_QTDEMUX (parent);
1687 switch (GST_EVENT_TYPE (event)) {
1688 case GST_EVENT_SEEK:
1690 #ifndef GST_DISABLE_GST_DEBUG
1691 GstClockTime ts = gst_util_get_timestamp ();
1694 if (qtdemux->upstream_format_is_time && qtdemux->fragmented) {
1695 /* seek should be handled by upstream, we might need to re-download fragments */
1696 GST_DEBUG_OBJECT (qtdemux,
1697 "let upstream handle seek for fragmented playback");
1701 /* Build complete index for seeking;
1702 * if not a fragmented file at least */
1703 if (!qtdemux->fragmented)
1704 if (!qtdemux_ensure_index (qtdemux))
1706 #ifndef GST_DISABLE_GST_DEBUG
1707 ts = gst_util_get_timestamp () - ts;
1708 GST_INFO_OBJECT (qtdemux,
1709 "Time taken to parse index %" GST_TIME_FORMAT, GST_TIME_ARGS (ts));
1712 if (qtdemux->pullbased) {
1713 res = gst_qtdemux_do_seek (qtdemux, pad, event);
1714 } else if (gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (event))) {
1715 GST_DEBUG_OBJECT (qtdemux, "Upstream successfully seeked");
1717 } else if (qtdemux->state == QTDEMUX_STATE_MOVIE && qtdemux->n_streams
1718 && !qtdemux->fragmented) {
1719 res = gst_qtdemux_do_push_seek (qtdemux, pad, event);
1721 GST_DEBUG_OBJECT (qtdemux,
1722 "ignoring seek in push mode in current state");
1725 gst_event_unref (event);
1729 res = gst_pad_event_default (pad, parent, event);
1739 GST_ERROR_OBJECT (qtdemux, "Index failed");
1740 gst_event_unref (event);
1746 /* stream/index return sample that is min/max w.r.t. byte position,
1747 * time is min/max w.r.t. time of samples,
1748 * the latter need not be time of the former sample */
1750 gst_qtdemux_find_sample (GstQTDemux * qtdemux, gint64 byte_pos, gboolean fw,
1751 gboolean set, QtDemuxStream ** _stream, gint * _index, gint64 * _time)
1754 gint64 time, min_time;
1755 QtDemuxStream *stream;
1761 for (n = 0; n < qtdemux->n_streams; ++n) {
1764 gboolean set_sample;
1766 str = qtdemux->streams[n];
1773 i = str->n_samples - 1;
1777 for (; (i >= 0) && (i < str->n_samples); i += inc) {
1778 if (str->samples[i].size == 0)
1781 if (fw && (str->samples[i].offset < byte_pos))
1784 if (!fw && (str->samples[i].offset + str->samples[i].size > byte_pos))
1787 /* move stream to first available sample */
1789 gst_qtdemux_move_stream (qtdemux, str, i);
1793 /* avoid index from sparse streams since they might be far away */
1795 /* determine min/max time */
1796 time = QTSAMPLE_PTS (str, &str->samples[i]);
1797 if (min_time == -1 || (!fw && time > min_time) ||
1798 (fw && time < min_time)) {
1802 /* determine stream with leading sample, to get its position */
1804 (fw && (str->samples[i].offset < stream->samples[index].offset)) ||
1805 (!fw && (str->samples[i].offset > stream->samples[index].offset))) {
1813 /* no sample for this stream, mark eos */
1815 gst_qtdemux_move_stream (qtdemux, str, str->n_samples);
1826 static QtDemuxStream *
1827 _create_stream (void)
1829 QtDemuxStream *stream;
1831 stream = g_new0 (QtDemuxStream, 1);
1832 /* new streams always need a discont */
1833 stream->discont = TRUE;
1834 /* we enable clipping for raw audio/video streams */
1835 stream->need_clip = FALSE;
1836 stream->need_process = FALSE;
1837 stream->segment_index = -1;
1838 stream->time_position = 0;
1839 stream->sample_index = -1;
1840 stream->offset_in_sample = 0;
1841 stream->new_stream = TRUE;
1842 stream->multiview_mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
1843 stream->multiview_flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
1844 stream->protected = FALSE;
1845 stream->protection_scheme_type = 0;
1846 stream->protection_scheme_version = 0;
1847 stream->protection_scheme_info = NULL;
1848 stream->n_samples_moof = 0;
1849 stream->duration_moof = 0;
1850 stream->duration_last_moof = 0;
1851 g_queue_init (&stream->protection_scheme_event_queue);
1856 gst_qtdemux_setcaps (GstQTDemux * demux, GstCaps * caps)
1858 GstStructure *structure;
1859 const gchar *variant;
1860 const GstCaps *mediacaps = NULL;
1862 GST_DEBUG_OBJECT (demux, "Sink set caps: %" GST_PTR_FORMAT, caps);
1864 structure = gst_caps_get_structure (caps, 0);
1865 variant = gst_structure_get_string (structure, "variant");
1867 if (variant && strcmp (variant, "mss-fragmented") == 0) {
1868 QtDemuxStream *stream;
1869 const GValue *value;
1871 demux->fragmented = TRUE;
1872 demux->mss_mode = TRUE;
1874 if (demux->n_streams > 1) {
1875 /* can't do this, we can only renegotiate for another mss format */
1879 value = gst_structure_get_value (structure, "media-caps");
1882 const GValue *timescale_v;
1884 /* TODO update when stream changes during playback */
1886 if (demux->n_streams == 0) {
1887 stream = _create_stream ();
1888 demux->streams[demux->n_streams] = stream;
1889 demux->n_streams = 1;
1891 stream = demux->streams[0];
1894 timescale_v = gst_structure_get_value (structure, "timescale");
1896 stream->timescale = g_value_get_uint64 (timescale_v);
1898 /* default mss timescale */
1899 stream->timescale = 10000000;
1901 demux->timescale = stream->timescale;
1903 mediacaps = gst_value_get_caps (value);
1904 if (!stream->caps || !gst_caps_is_equal_fixed (mediacaps, stream->caps)) {
1905 GST_DEBUG_OBJECT (demux, "We have a new caps %" GST_PTR_FORMAT,
1907 stream->new_caps = TRUE;
1909 gst_caps_replace (&stream->caps, (GstCaps *) mediacaps);
1910 structure = gst_caps_get_structure (mediacaps, 0);
1911 if (g_str_has_prefix (gst_structure_get_name (structure), "video")) {
1912 stream->subtype = FOURCC_vide;
1914 gst_structure_get_int (structure, "width", &stream->width);
1915 gst_structure_get_int (structure, "height", &stream->height);
1916 gst_structure_get_fraction (structure, "framerate", &stream->fps_n,
1918 } else if (g_str_has_prefix (gst_structure_get_name (structure), "audio")) {
1920 stream->subtype = FOURCC_soun;
1921 gst_structure_get_int (structure, "channels", &stream->n_channels);
1922 gst_structure_get_int (structure, "rate", &rate);
1923 stream->rate = rate;
1926 gst_caps_replace (&demux->media_caps, (GstCaps *) mediacaps);
1928 demux->mss_mode = FALSE;
1935 gst_qtdemux_reset (GstQTDemux * qtdemux, gboolean hard)
1939 GST_DEBUG_OBJECT (qtdemux, "Resetting demux");
1940 gst_pad_stop_task (qtdemux->sinkpad);
1942 if (hard || qtdemux->upstream_format_is_time) {
1943 qtdemux->state = QTDEMUX_STATE_INITIAL;
1944 qtdemux->neededbytes = 16;
1945 qtdemux->todrop = 0;
1946 qtdemux->pullbased = FALSE;
1947 qtdemux->posted_redirect = FALSE;
1948 qtdemux->first_mdat = -1;
1949 qtdemux->header_size = 0;
1950 qtdemux->mdatoffset = -1;
1951 qtdemux->restoredata_offset = -1;
1952 if (qtdemux->mdatbuffer)
1953 gst_buffer_unref (qtdemux->mdatbuffer);
1954 if (qtdemux->restoredata_buffer)
1955 gst_buffer_unref (qtdemux->restoredata_buffer);
1956 qtdemux->mdatbuffer = NULL;
1957 qtdemux->restoredata_buffer = NULL;
1958 qtdemux->mdatleft = 0;
1959 if (qtdemux->comp_brands)
1960 gst_buffer_unref (qtdemux->comp_brands);
1961 qtdemux->comp_brands = NULL;
1962 qtdemux->last_moov_offset = -1;
1963 if (qtdemux->moov_node)
1964 g_node_destroy (qtdemux->moov_node);
1965 qtdemux->moov_node = NULL;
1966 qtdemux->moov_node_compressed = NULL;
1967 if (qtdemux->tag_list)
1968 gst_mini_object_unref (GST_MINI_OBJECT_CAST (qtdemux->tag_list));
1969 qtdemux->tag_list = NULL;
1971 if (qtdemux->element_index)
1972 gst_object_unref (qtdemux->element_index);
1973 qtdemux->element_index = NULL;
1975 qtdemux->major_brand = 0;
1976 if (qtdemux->pending_newsegment)
1977 gst_event_unref (qtdemux->pending_newsegment);
1978 qtdemux->pending_newsegment = NULL;
1979 qtdemux->upstream_format_is_time = FALSE;
1980 qtdemux->upstream_seekable = FALSE;
1981 qtdemux->upstream_size = 0;
1983 qtdemux->fragment_start = -1;
1984 qtdemux->fragment_start_offset = -1;
1985 qtdemux->duration = 0;
1986 qtdemux->moof_offset = 0;
1987 qtdemux->chapters_track_id = 0;
1988 qtdemux->have_group_id = FALSE;
1989 qtdemux->group_id = G_MAXUINT;
1991 g_queue_foreach (&qtdemux->protection_event_queue, (GFunc) gst_event_unref,
1993 g_queue_clear (&qtdemux->protection_event_queue);
1995 qtdemux->offset = 0;
1996 gst_adapter_clear (qtdemux->adapter);
1997 gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
1998 qtdemux->segment_seqnum = 0;
2001 for (n = 0; n < qtdemux->n_streams; n++) {
2002 gst_qtdemux_stream_free (qtdemux, qtdemux->streams[n]);
2003 qtdemux->streams[n] = NULL;
2005 qtdemux->n_streams = 0;
2006 qtdemux->n_video_streams = 0;
2007 qtdemux->n_audio_streams = 0;
2008 qtdemux->n_sub_streams = 0;
2009 qtdemux->exposed = FALSE;
2010 qtdemux->fragmented = FALSE;
2011 qtdemux->mss_mode = FALSE;
2012 gst_caps_replace (&qtdemux->media_caps, NULL);
2013 qtdemux->timescale = 0;
2014 qtdemux->got_moov = FALSE;
2015 if (qtdemux->protection_system_ids) {
2016 g_ptr_array_free (qtdemux->protection_system_ids, TRUE);
2017 qtdemux->protection_system_ids = NULL;
2019 } else if (qtdemux->mss_mode) {
2020 gst_flow_combiner_reset (qtdemux->flowcombiner);
2021 for (n = 0; n < qtdemux->n_streams; n++)
2022 gst_qtdemux_stream_clear (qtdemux, qtdemux->streams[n]);
2024 gst_flow_combiner_reset (qtdemux->flowcombiner);
2025 for (n = 0; n < qtdemux->n_streams; n++) {
2026 qtdemux->streams[n]->sent_eos = FALSE;
2027 qtdemux->streams[n]->time_position = 0;
2028 qtdemux->streams[n]->accumulated_base = 0;
2030 if (!qtdemux->pending_newsegment) {
2031 qtdemux->pending_newsegment = gst_event_new_segment (&qtdemux->segment);
2032 if (qtdemux->segment_seqnum)
2033 gst_event_set_seqnum (qtdemux->pending_newsegment,
2034 qtdemux->segment_seqnum);
2040 /* Maps the @segment to the qt edts internal segments and pushes
2041 * the correspnding segment event.
2043 * If it ends up being at a empty segment, a gap will be pushed and the next
2044 * edts segment will be activated in sequence.
2046 * To be used in push-mode only */
2048 gst_qtdemux_map_and_push_segments (GstQTDemux * qtdemux, GstSegment * segment)
2052 for (n = 0; n < qtdemux->n_streams; n++) {
2053 QtDemuxStream *stream = qtdemux->streams[n];
2055 stream->time_position = segment->start;
2057 /* in push mode we should be guaranteed that we will have empty segments
2058 * at the beginning and then one segment after, other scenarios are not
2059 * supported and are discarded when parsing the edts */
2060 for (i = 0; i < stream->n_segments; i++) {
2061 if (stream->segments[i].stop_time > segment->start) {
2062 gst_qtdemux_activate_segment (qtdemux, stream, i,
2063 stream->time_position);
2064 if (QTSEGMENT_IS_EMPTY (&stream->segments[i])) {
2065 /* push the empty segment and move to the next one */
2066 gst_qtdemux_send_gap_for_segment (qtdemux, stream, i,
2067 stream->time_position);
2071 g_assert (i == stream->n_segments - 1);
2078 gst_qtdemux_handle_sink_event (GstPad * sinkpad, GstObject * parent,
2081 GstQTDemux *demux = GST_QTDEMUX (parent);
2082 gboolean res = TRUE;
2084 GST_LOG_OBJECT (demux, "handling %s event", GST_EVENT_TYPE_NAME (event));
2086 switch (GST_EVENT_TYPE (event)) {
2087 case GST_EVENT_SEGMENT:
2090 QtDemuxStream *stream;
2094 /* some debug output */
2095 gst_event_copy_segment (event, &segment);
2096 GST_DEBUG_OBJECT (demux, "received newsegment %" GST_SEGMENT_FORMAT,
2099 /* erase any previously set segment */
2100 gst_event_replace (&demux->pending_newsegment, NULL);
2102 if (segment.format == GST_FORMAT_TIME) {
2103 GST_DEBUG_OBJECT (demux, "new pending_newsegment");
2104 gst_event_replace (&demux->pending_newsegment, event);
2105 demux->upstream_format_is_time = TRUE;
2107 GST_DEBUG_OBJECT (demux, "Not storing upstream newsegment, "
2108 "not in time format");
2110 /* chain will send initial newsegment after pads have been added */
2111 if (demux->state != QTDEMUX_STATE_MOVIE || !demux->n_streams) {
2112 GST_DEBUG_OBJECT (demux, "still starting, eating event");
2117 /* check if this matches a time seek we received previously
2118 * FIXME for backwards compatibility reasons we use the
2119 * seek_offset here to compare. In the future we might want to
2120 * change this to use the seqnum as it uniquely should identify
2121 * the segment that corresponds to the seek. */
2122 GST_DEBUG_OBJECT (demux, "Stored seek offset: %" G_GINT64_FORMAT
2123 ", received segment offset %" G_GINT64_FORMAT,
2124 demux->seek_offset, segment.start);
2125 if (segment.format == GST_FORMAT_BYTES
2126 && demux->seek_offset == segment.start) {
2127 GST_OBJECT_LOCK (demux);
2128 offset = segment.start;
2130 segment.format = GST_FORMAT_TIME;
2131 segment.start = demux->push_seek_start;
2132 segment.stop = demux->push_seek_stop;
2133 GST_DEBUG_OBJECT (demux, "Replaced segment with stored seek "
2134 "segment %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT,
2135 GST_TIME_ARGS (segment.start), GST_TIME_ARGS (segment.stop));
2136 GST_OBJECT_UNLOCK (demux);
2139 /* we only expect a BYTE segment, e.g. following a seek */
2140 if (segment.format == GST_FORMAT_BYTES) {
2141 if (GST_CLOCK_TIME_IS_VALID (segment.start)) {
2142 offset = segment.start;
2144 gst_qtdemux_find_sample (demux, segment.start, TRUE, FALSE, NULL,
2145 NULL, (gint64 *) & segment.start);
2146 if ((gint64) segment.start < 0)
2149 if (GST_CLOCK_TIME_IS_VALID (segment.stop)) {
2150 gst_qtdemux_find_sample (demux, segment.stop, FALSE, FALSE, NULL,
2151 NULL, (gint64 *) & segment.stop);
2152 /* keyframe seeking should already arrange for start >= stop,
2153 * but make sure in other rare cases */
2154 segment.stop = MAX (segment.stop, segment.start);
2156 } else if (segment.format == GST_FORMAT_TIME) {
2157 /* push all data on the adapter before starting this
2159 gst_qtdemux_process_adapter (demux, TRUE);
2161 GST_DEBUG_OBJECT (demux, "unsupported segment format, ignoring");
2165 /* We shouldn't modify upstream driven TIME FORMAT segment */
2166 if (!demux->upstream_format_is_time) {
2167 /* accept upstream's notion of segment and distribute along */
2168 segment.format = GST_FORMAT_TIME;
2169 segment.position = segment.time = segment.start;
2170 segment.duration = demux->segment.duration;
2171 segment.base = gst_segment_to_running_time (&demux->segment,
2172 GST_FORMAT_TIME, demux->segment.position);
2175 gst_segment_copy_into (&segment, &demux->segment);
2176 GST_DEBUG_OBJECT (demux, "Pushing newseg %" GST_SEGMENT_FORMAT, &segment);
2178 /* map segment to internal qt segments and push on each stream */
2179 if (demux->n_streams) {
2180 if (demux->fragmented) {
2181 GstEvent *segment_event = gst_event_new_segment (&segment);
2183 gst_event_replace (&demux->pending_newsegment, NULL);
2184 gst_event_set_seqnum (segment_event, demux->segment_seqnum);
2185 gst_qtdemux_push_event (demux, segment_event);
2187 gst_event_replace (&demux->pending_newsegment, NULL);
2188 gst_qtdemux_map_and_push_segments (demux, &segment);
2192 /* clear leftover in current segment, if any */
2193 gst_adapter_clear (demux->adapter);
2195 /* set up streaming thread */
2196 demux->offset = offset;
2197 if (demux->upstream_format_is_time) {
2198 GST_DEBUG_OBJECT (demux, "Upstream is driving in time format, "
2199 "set values to restart reading from a new atom");
2200 demux->neededbytes = 16;
2203 gst_qtdemux_find_sample (demux, offset, TRUE, TRUE, &stream, &idx,
2206 demux->todrop = stream->samples[idx].offset - offset;
2207 demux->neededbytes = demux->todrop + stream->samples[idx].size;
2209 /* set up for EOS */
2210 demux->neededbytes = -1;
2215 gst_event_unref (event);
2219 case GST_EVENT_FLUSH_START:
2221 if (gst_event_get_seqnum (event) == demux->offset_seek_seqnum) {
2222 gst_event_unref (event);
2227 case GST_EVENT_FLUSH_STOP:
2231 dur = demux->segment.duration;
2232 gst_qtdemux_reset (demux, FALSE);
2233 demux->segment.duration = dur;
2235 if (gst_event_get_seqnum (event) == demux->offset_seek_seqnum) {
2236 gst_event_unref (event);
2242 /* If we are in push mode, and get an EOS before we've seen any streams,
2243 * then error out - we have nowhere to send the EOS */
2244 if (!demux->pullbased) {
2246 gboolean has_valid_stream = FALSE;
2247 for (i = 0; i < demux->n_streams; i++) {
2248 if (demux->streams[i]->pad != NULL) {
2249 has_valid_stream = TRUE;
2253 if (!has_valid_stream)
2254 gst_qtdemux_post_no_playable_stream_error (demux);
2256 GST_DEBUG_OBJECT (demux, "Data still available after EOS: %u",
2257 (guint) gst_adapter_available (demux->adapter));
2258 if (gst_qtdemux_process_adapter (demux, TRUE) != GST_FLOW_OK) {
2264 case GST_EVENT_CAPS:{
2265 GstCaps *caps = NULL;
2267 gst_event_parse_caps (event, &caps);
2268 gst_qtdemux_setcaps (demux, caps);
2270 gst_event_unref (event);
2273 case GST_EVENT_PROTECTION:
2275 const gchar *system_id = NULL;
2277 gst_event_parse_protection (event, &system_id, NULL, NULL);
2278 GST_DEBUG_OBJECT (demux, "Received protection event for system ID %s",
2280 gst_qtdemux_append_protection_system_id (demux, system_id);
2281 /* save the event for later, for source pads that have not been created */
2282 g_queue_push_tail (&demux->protection_event_queue, gst_event_ref (event));
2283 /* send it to all pads that already exist */
2284 gst_qtdemux_push_event (demux, event);
2292 res = gst_pad_event_default (demux->sinkpad, parent, event) & res;
2300 gst_qtdemux_set_index (GstElement * element, GstIndex * index)
2302 GstQTDemux *demux = GST_QTDEMUX (element);
2304 GST_OBJECT_LOCK (demux);
2305 if (demux->element_index)
2306 gst_object_unref (demux->element_index);
2308 demux->element_index = gst_object_ref (index);
2310 demux->element_index = NULL;
2312 GST_OBJECT_UNLOCK (demux);
2313 /* object lock might be taken again */
2315 gst_index_get_writer_id (index, GST_OBJECT (element), &demux->index_id);
2316 GST_DEBUG_OBJECT (demux, "Set index %" GST_PTR_FORMAT "for writer id %d",
2317 demux->element_index, demux->index_id);
2321 gst_qtdemux_get_index (GstElement * element)
2323 GstIndex *result = NULL;
2324 GstQTDemux *demux = GST_QTDEMUX (element);
2326 GST_OBJECT_LOCK (demux);
2327 if (demux->element_index)
2328 result = gst_object_ref (demux->element_index);
2329 GST_OBJECT_UNLOCK (demux);
2331 GST_DEBUG_OBJECT (demux, "Returning index %" GST_PTR_FORMAT, result);
2338 gst_qtdemux_stbl_free (QtDemuxStream * stream)
2340 g_free ((gpointer) stream->stco.data);
2341 stream->stco.data = NULL;
2342 g_free ((gpointer) stream->stsz.data);
2343 stream->stsz.data = NULL;
2344 g_free ((gpointer) stream->stsc.data);
2345 stream->stsc.data = NULL;
2346 g_free ((gpointer) stream->stts.data);
2347 stream->stts.data = NULL;
2348 g_free ((gpointer) stream->stss.data);
2349 stream->stss.data = NULL;
2350 g_free ((gpointer) stream->stps.data);
2351 stream->stps.data = NULL;
2352 g_free ((gpointer) stream->ctts.data);
2353 stream->ctts.data = NULL;
2357 gst_qtdemux_stream_flush_segments_data (GstQTDemux * qtdemux,
2358 QtDemuxStream * stream)
2360 g_free (stream->segments);
2361 stream->segments = NULL;
2362 stream->segment_index = -1;
2363 stream->accumulated_base = 0;
2367 gst_qtdemux_stream_flush_samples_data (GstQTDemux * qtdemux,
2368 QtDemuxStream * stream)
2370 g_free (stream->samples);
2371 stream->samples = NULL;
2372 gst_qtdemux_stbl_free (stream);
2375 g_free (stream->ra_entries);
2376 stream->ra_entries = NULL;
2377 stream->n_ra_entries = 0;
2379 stream->sample_index = -1;
2380 stream->stbl_index = -1;
2381 stream->n_samples = 0;
2382 stream->time_position = 0;
2384 stream->n_samples_moof = 0;
2385 stream->duration_moof = 0;
2386 stream->duration_last_moof = 0;
2390 gst_qtdemux_stream_clear (GstQTDemux * qtdemux, QtDemuxStream * stream)
2392 if (stream->allocator)
2393 gst_object_unref (stream->allocator);
2394 while (stream->buffers) {
2395 gst_buffer_unref (GST_BUFFER_CAST (stream->buffers->data));
2396 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
2398 if (stream->rgb8_palette) {
2399 gst_memory_unref (stream->rgb8_palette);
2400 stream->rgb8_palette = NULL;
2403 if (stream->pending_tags)
2404 gst_tag_list_unref (stream->pending_tags);
2405 stream->pending_tags = NULL;
2406 g_free (stream->redirect_uri);
2407 stream->redirect_uri = NULL;
2408 stream->sent_eos = FALSE;
2409 stream->sparse = FALSE;
2410 stream->protected = FALSE;
2411 if (stream->protection_scheme_info) {
2412 if (stream->protection_scheme_type == FOURCC_cenc) {
2413 QtDemuxCencSampleSetInfo *info =
2414 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
2415 if (info->default_properties)
2416 gst_structure_free (info->default_properties);
2417 if (info->crypto_info)
2418 g_ptr_array_free (info->crypto_info, TRUE);
2420 g_free (stream->protection_scheme_info);
2421 stream->protection_scheme_info = NULL;
2423 stream->protection_scheme_type = 0;
2424 stream->protection_scheme_version = 0;
2425 g_queue_foreach (&stream->protection_scheme_event_queue,
2426 (GFunc) gst_event_unref, NULL);
2427 g_queue_clear (&stream->protection_scheme_event_queue);
2428 gst_qtdemux_stream_flush_segments_data (qtdemux, stream);
2429 gst_qtdemux_stream_flush_samples_data (qtdemux, stream);
2433 gst_qtdemux_stream_free (GstQTDemux * qtdemux, QtDemuxStream * stream)
2435 gst_qtdemux_stream_clear (qtdemux, stream);
2437 gst_caps_unref (stream->caps);
2438 stream->caps = NULL;
2440 gst_element_remove_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
2441 gst_flow_combiner_remove_pad (qtdemux->flowcombiner, stream->pad);
2447 gst_qtdemux_remove_stream (GstQTDemux * qtdemux, int i)
2449 g_assert (i >= 0 && i < qtdemux->n_streams && qtdemux->streams[i] != NULL);
2451 gst_qtdemux_stream_free (qtdemux, qtdemux->streams[i]);
2452 qtdemux->streams[i] = qtdemux->streams[qtdemux->n_streams - 1];
2453 qtdemux->streams[qtdemux->n_streams - 1] = NULL;
2454 qtdemux->n_streams--;
2457 static GstStateChangeReturn
2458 gst_qtdemux_change_state (GstElement * element, GstStateChange transition)
2460 GstQTDemux *qtdemux = GST_QTDEMUX (element);
2461 GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
2463 switch (transition) {
2464 case GST_STATE_CHANGE_PAUSED_TO_READY:
2470 result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
2472 switch (transition) {
2473 case GST_STATE_CHANGE_PAUSED_TO_READY:{
2474 gst_qtdemux_reset (qtdemux, TRUE);
2485 qtdemux_parse_ftyp (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2487 /* counts as header data */
2488 qtdemux->header_size += length;
2490 /* only consider at least a sufficiently complete ftyp atom */
2494 qtdemux->major_brand = QT_FOURCC (buffer + 8);
2495 GST_DEBUG_OBJECT (qtdemux, "major brand: %" GST_FOURCC_FORMAT,
2496 GST_FOURCC_ARGS (qtdemux->major_brand));
2497 if (qtdemux->comp_brands)
2498 gst_buffer_unref (qtdemux->comp_brands);
2499 buf = qtdemux->comp_brands = gst_buffer_new_and_alloc (length - 16);
2500 gst_buffer_fill (buf, 0, buffer + 16, length - 16);
2505 qtdemux_handle_xmp_taglist (GstQTDemux * qtdemux, GstTagList * taglist,
2506 GstTagList * xmptaglist)
2508 /* Strip out bogus fields */
2510 if (gst_tag_list_get_scope (taglist) == GST_TAG_SCOPE_GLOBAL) {
2511 gst_tag_list_remove_tag (xmptaglist, GST_TAG_VIDEO_CODEC);
2512 gst_tag_list_remove_tag (xmptaglist, GST_TAG_AUDIO_CODEC);
2514 gst_tag_list_remove_tag (xmptaglist, GST_TAG_CONTAINER_FORMAT);
2517 GST_DEBUG_OBJECT (qtdemux, "Found XMP tags %" GST_PTR_FORMAT, xmptaglist);
2519 /* prioritize native tags using _KEEP mode */
2520 gst_tag_list_insert (taglist, xmptaglist, GST_TAG_MERGE_KEEP);
2521 gst_tag_list_unref (xmptaglist);
2526 qtdemux_parse_piff (GstQTDemux * qtdemux, const guint8 * buffer, gint length,
2534 QtDemuxStream *stream;
2535 GstStructure *structure;
2536 QtDemuxCencSampleSetInfo *ss_info = NULL;
2537 const gchar *system_id;
2538 gboolean uses_sub_sample_encryption = FALSE;
2540 if (qtdemux->n_streams == 0)
2543 stream = qtdemux->streams[0];
2545 structure = gst_caps_get_structure (stream->caps, 0);
2546 if (!gst_structure_has_name (structure, "application/x-cenc")) {
2547 GST_WARNING_OBJECT (qtdemux,
2548 "Attempting PIFF box parsing on an unencrypted stream.");
2552 gst_structure_get (structure, GST_PROTECTION_SYSTEM_ID_CAPS_FIELD,
2553 G_TYPE_STRING, &system_id, NULL);
2554 gst_qtdemux_append_protection_system_id (qtdemux, system_id);
2556 stream->protected = TRUE;
2557 stream->protection_scheme_type = FOURCC_cenc;
2559 if (!stream->protection_scheme_info)
2560 stream->protection_scheme_info = g_new0 (QtDemuxCencSampleSetInfo, 1);
2562 ss_info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
2564 if (ss_info->default_properties)
2565 gst_structure_free (ss_info->default_properties);
2567 ss_info->default_properties =
2568 gst_structure_new ("application/x-cenc",
2569 "iv_size", G_TYPE_UINT, iv_size, "encrypted", G_TYPE_BOOLEAN, TRUE, NULL);
2571 if (ss_info->crypto_info) {
2572 GST_LOG_OBJECT (qtdemux, "unreffing existing crypto_info");
2573 g_ptr_array_free (ss_info->crypto_info, TRUE);
2574 ss_info->crypto_info = NULL;
2578 gst_byte_reader_init (&br, buffer + offset + 16, length - offset - 16);
2580 if (!gst_byte_reader_get_uint8 (&br, &version)) {
2581 GST_ERROR_OBJECT (qtdemux, "Error getting box's version field");
2585 if (!gst_byte_reader_get_uint24_be (&br, &flags)) {
2586 GST_ERROR_OBJECT (qtdemux, "Error getting box's flags field");
2590 if ((flags & 0x000001)) {
2591 guint32 algorithm_id = 0;
2594 gboolean is_encrypted = TRUE;
2596 if (!gst_byte_reader_get_uint24_le (&br, &algorithm_id)) {
2597 GST_ERROR_OBJECT (qtdemux, "Error getting box's algorithm ID field");
2602 if (algorithm_id == 0) {
2603 is_encrypted = FALSE;
2604 } else if (algorithm_id == 1) {
2605 /* FIXME: maybe store this in properties? */
2606 GST_DEBUG_OBJECT (qtdemux, "AES 128-bits CTR encrypted stream");
2607 } else if (algorithm_id == 2) {
2608 /* FIXME: maybe store this in properties? */
2609 GST_DEBUG_OBJECT (qtdemux, "AES 128-bits CBC encrypted stream");
2612 if (!gst_byte_reader_get_uint8 (&br, &iv_size))
2615 if (!gst_byte_reader_get_data (&br, 16, &kid))
2618 kid_buf = gst_buffer_new_allocate (NULL, 16, NULL);
2619 gst_buffer_fill (kid_buf, 0, kid, 16);
2620 if (ss_info->default_properties)
2621 gst_structure_free (ss_info->default_properties);
2622 ss_info->default_properties =
2623 gst_structure_new ("application/x-cenc",
2624 "iv_size", G_TYPE_UINT, iv_size,
2625 "encrypted", G_TYPE_BOOLEAN, is_encrypted,
2626 "kid", GST_TYPE_BUFFER, kid_buf, NULL);
2627 GST_DEBUG_OBJECT (qtdemux, "default sample properties: "
2628 "is_encrypted=%u, iv_size=%u", is_encrypted, iv_size);
2629 gst_buffer_unref (kid_buf);
2630 } else if ((flags & 0x000002)) {
2631 uses_sub_sample_encryption = TRUE;
2634 if (!gst_byte_reader_get_uint32_be (&br, &qtdemux->cenc_aux_sample_count)) {
2635 GST_ERROR_OBJECT (qtdemux, "Error getting box's sample count field");
2639 ss_info->crypto_info =
2640 g_ptr_array_new_full (qtdemux->cenc_aux_sample_count,
2641 (GDestroyNotify) qtdemux_gst_structure_free);
2643 for (i = 0; i < qtdemux->cenc_aux_sample_count; ++i) {
2644 GstStructure *properties;
2648 properties = qtdemux_get_cenc_sample_properties (qtdemux, stream, i);
2649 if (properties == NULL) {
2650 GST_ERROR_OBJECT (qtdemux, "failed to get properties for sample %u", i);
2654 if (!gst_byte_reader_dup_data (&br, iv_size, &data)) {
2655 GST_ERROR_OBJECT (qtdemux, "IV data not present for sample %u", i);
2656 gst_structure_free (properties);
2659 buf = gst_buffer_new_wrapped (data, iv_size);
2660 gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL);
2661 gst_buffer_unref (buf);
2663 if (uses_sub_sample_encryption) {
2664 guint16 n_subsamples;
2666 if (!gst_byte_reader_get_uint16_be (&br, &n_subsamples)
2667 || n_subsamples == 0) {
2668 GST_ERROR_OBJECT (qtdemux,
2669 "failed to get subsample count for sample %u", i);
2670 gst_structure_free (properties);
2673 GST_LOG_OBJECT (qtdemux, "subsample count: %u", n_subsamples);
2674 if (!gst_byte_reader_dup_data (&br, n_subsamples * 6, &data)) {
2675 GST_ERROR_OBJECT (qtdemux, "failed to get subsample data for sample %u",
2677 gst_structure_free (properties);
2680 buf = gst_buffer_new_wrapped (data, n_subsamples * 6);
2681 gst_structure_set (properties,
2682 "subsample_count", G_TYPE_UINT, n_subsamples,
2683 "subsamples", GST_TYPE_BUFFER, buf, NULL);
2684 gst_buffer_unref (buf);
2686 gst_structure_set (properties, "subsample_count", G_TYPE_UINT, 0, NULL);
2689 g_ptr_array_add (ss_info->crypto_info, properties);
2694 qtdemux_parse_uuid (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2696 static const guint8 xmp_uuid[] = { 0xBE, 0x7A, 0xCF, 0xCB,
2697 0x97, 0xA9, 0x42, 0xE8,
2698 0x9C, 0x71, 0x99, 0x94,
2699 0x91, 0xE3, 0xAF, 0xAC
2701 static const guint8 playready_uuid[] = {
2702 0xd0, 0x8a, 0x4f, 0x18, 0x10, 0xf3, 0x4a, 0x82,
2703 0xb6, 0xc8, 0x32, 0xd8, 0xab, 0xa1, 0x83, 0xd3
2706 static const guint8 piff_sample_encryption_uuid[] = {
2707 0xa2, 0x39, 0x4f, 0x52, 0x5a, 0x9b, 0x4f, 0x14,
2708 0xa2, 0x44, 0x6c, 0x42, 0x7c, 0x64, 0x8d, 0xf4
2713 /* counts as header data */
2714 qtdemux->header_size += length;
2716 offset = (QT_UINT32 (buffer) == 0) ? 16 : 8;
2718 if (length <= offset + 16) {
2719 GST_DEBUG_OBJECT (qtdemux, "uuid atom is too short, skipping");
2723 if (memcmp (buffer + offset, xmp_uuid, 16) == 0) {
2725 GstTagList *taglist;
2727 buf = _gst_buffer_new_wrapped ((guint8 *) buffer + offset + 16,
2728 length - offset - 16, NULL);
2729 taglist = gst_tag_list_from_xmp_buffer (buf);
2730 gst_buffer_unref (buf);
2732 qtdemux_handle_xmp_taglist (qtdemux, qtdemux->tag_list, taglist);
2734 } else if (memcmp (buffer + offset, playready_uuid, 16) == 0) {
2736 const gunichar2 *s_utf16;
2739 len = GST_READ_UINT16_LE (buffer + offset + 0x30);
2740 s_utf16 = (const gunichar2 *) (buffer + offset + 0x32);
2741 contents = g_utf16_to_utf8 (s_utf16, len / 2, NULL, NULL, NULL);
2742 GST_ERROR_OBJECT (qtdemux, "contents: %s", contents);
2746 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT,
2747 (_("Cannot play stream because it is encrypted with PlayReady DRM.")),
2749 } else if (memcmp (buffer + offset, piff_sample_encryption_uuid, 16) == 0) {
2750 qtdemux_parse_piff (qtdemux, buffer, length, offset);
2752 GST_DEBUG_OBJECT (qtdemux, "Ignoring unknown uuid: %08x-%08x-%08x-%08x",
2753 GST_READ_UINT32_LE (buffer + offset),
2754 GST_READ_UINT32_LE (buffer + offset + 4),
2755 GST_READ_UINT32_LE (buffer + offset + 8),
2756 GST_READ_UINT32_LE (buffer + offset + 12));
2761 qtdemux_parse_sidx (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2763 GstSidxParser sidx_parser;
2764 GstIsoffParserResult res;
2767 gst_isoff_qt_sidx_parser_init (&sidx_parser);
2770 gst_isoff_qt_sidx_parser_add_data (&sidx_parser, buffer, length,
2772 GST_DEBUG_OBJECT (qtdemux, "sidx parse result: %d", res);
2773 if (res == GST_ISOFF_QT_PARSER_DONE) {
2774 check_update_duration (qtdemux, sidx_parser.cumulative_pts);
2776 gst_isoff_qt_sidx_parser_clear (&sidx_parser);
2779 /* caller verifies at least 8 bytes in buf */
2781 extract_initial_length_and_fourcc (const guint8 * data, guint size,
2782 guint64 * plength, guint32 * pfourcc)
2787 length = QT_UINT32 (data);
2788 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
2789 fourcc = QT_FOURCC (data + 4);
2790 GST_DEBUG ("atom type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
2793 length = G_MAXUINT64;
2794 } else if (length == 1 && size >= 16) {
2795 /* this means we have an extended size, which is the 64 bit value of
2796 * the next 8 bytes */
2797 length = QT_UINT64 (data + 8);
2798 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
2808 qtdemux_parse_mehd (GstQTDemux * qtdemux, GstByteReader * br)
2810 guint32 version = 0;
2811 GstClockTime duration = 0;
2813 if (!gst_byte_reader_get_uint32_be (br, &version))
2818 if (!gst_byte_reader_get_uint64_be (br, &duration))
2823 if (!gst_byte_reader_get_uint32_be (br, &dur))
2828 GST_INFO_OBJECT (qtdemux, "mehd duration: %" G_GUINT64_FORMAT, duration);
2829 qtdemux->duration = duration;
2835 GST_DEBUG_OBJECT (qtdemux, "parsing mehd failed");
2841 qtdemux_parse_trex (GstQTDemux * qtdemux, QtDemuxStream * stream,
2842 guint32 * ds_duration, guint32 * ds_size, guint32 * ds_flags)
2844 if (!stream->parsed_trex && qtdemux->moov_node) {
2846 GstByteReader trex_data;
2848 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
2850 trex = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_trex,
2853 guint32 id = 0, dur = 0, size = 0, flags = 0, dummy = 0;
2855 /* skip version/flags */
2856 if (!gst_byte_reader_skip (&trex_data, 4))
2858 if (!gst_byte_reader_get_uint32_be (&trex_data, &id))
2860 if (id != stream->track_id)
2862 /* sample description index; ignore */
2863 if (!gst_byte_reader_get_uint32_be (&trex_data, &dummy))
2865 if (!gst_byte_reader_get_uint32_be (&trex_data, &dur))
2867 if (!gst_byte_reader_get_uint32_be (&trex_data, &size))
2869 if (!gst_byte_reader_get_uint32_be (&trex_data, &flags))
2872 GST_DEBUG_OBJECT (qtdemux, "fragment defaults for stream %d; "
2873 "duration %d, size %d, flags 0x%x", stream->track_id,
2876 stream->parsed_trex = TRUE;
2877 stream->def_sample_duration = dur;
2878 stream->def_sample_size = size;
2879 stream->def_sample_flags = flags;
2882 /* iterate all siblings */
2883 trex = qtdemux_tree_get_sibling_by_type_full (trex, FOURCC_trex,
2889 *ds_duration = stream->def_sample_duration;
2890 *ds_size = stream->def_sample_size;
2891 *ds_flags = stream->def_sample_flags;
2893 /* even then, above values are better than random ... */
2894 if (G_UNLIKELY (!stream->parsed_trex)) {
2895 GST_WARNING_OBJECT (qtdemux,
2896 "failed to find fragment defaults for stream %d", stream->track_id);
2903 /* This method should be called whenever a more accurate duration might
2904 * have been found. It will update all relevant variables if/where needed
2907 check_update_duration (GstQTDemux * qtdemux, GstClockTime duration)
2911 GstClockTime prevdur;
2913 movdur = GSTTIME_TO_QTTIME (qtdemux, duration);
2915 if (movdur > qtdemux->duration) {
2916 prevdur = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
2917 GST_DEBUG_OBJECT (qtdemux,
2918 "Updating total duration to %" GST_TIME_FORMAT " was %" GST_TIME_FORMAT,
2919 GST_TIME_ARGS (duration), GST_TIME_ARGS (prevdur));
2920 qtdemux->duration = movdur;
2921 GST_DEBUG_OBJECT (qtdemux,
2922 "qtdemux->segment.duration: %" GST_TIME_FORMAT " .stop: %"
2923 GST_TIME_FORMAT, GST_TIME_ARGS (qtdemux->segment.duration),
2924 GST_TIME_ARGS (qtdemux->segment.stop));
2925 if (qtdemux->segment.duration == prevdur) {
2926 /* If the current segment has duration/stop identical to previous duration
2927 * update them also (because they were set at that point in time with
2928 * the wrong duration */
2929 /* We convert the value *from* the timescale version to avoid rounding errors */
2930 GstClockTime fixeddur = QTTIME_TO_GSTTIME (qtdemux, movdur);
2931 GST_DEBUG_OBJECT (qtdemux, "Updated segment.duration and segment.stop");
2932 qtdemux->segment.duration = fixeddur;
2933 qtdemux->segment.stop = fixeddur;
2936 for (i = 0; i < qtdemux->n_streams; i++) {
2937 QtDemuxStream *stream = qtdemux->streams[i];
2939 movdur = GSTTIME_TO_QTSTREAMTIME (stream, duration);
2940 if (movdur > stream->duration) {
2941 GST_DEBUG_OBJECT (qtdemux,
2942 "Updating stream #%d duration to %" GST_TIME_FORMAT, i,
2943 GST_TIME_ARGS (duration));
2944 stream->duration = movdur;
2945 if (stream->dummy_segment) {
2946 /* Update all dummy values to new duration */
2947 stream->segments[0].stop_time = duration;
2948 stream->segments[0].duration = duration;
2949 stream->segments[0].media_stop = duration;
2951 /* let downstream know we possibly have a new stop time */
2952 if (stream->segment_index != -1) {
2955 if (qtdemux->segment.rate >= 0) {
2956 pos = stream->segment.start;
2958 pos = stream->segment.stop;
2961 gst_qtdemux_stream_update_segment (qtdemux, stream,
2962 stream->segment_index, pos, NULL, NULL);
2971 qtdemux_parse_trun (GstQTDemux * qtdemux, GstByteReader * trun,
2972 QtDemuxStream * stream, guint32 d_sample_duration, guint32 d_sample_size,
2973 guint32 d_sample_flags, gint64 moof_offset, gint64 moof_length,
2974 gint64 * base_offset, gint64 * running_offset, gint64 decode_ts)
2976 GstClockTime gst_ts = GST_CLOCK_TIME_NONE;
2978 gint32 data_offset = 0;
2979 guint32 flags = 0, first_flags = 0, samples_count = 0;
2982 guint entry_size, dur_offset, size_offset, flags_offset = 0, ct_offset = 0;
2983 QtDemuxSample *sample;
2984 gboolean ismv = FALSE;
2985 gint64 initial_offset;
2987 GST_LOG_OBJECT (qtdemux, "parsing trun stream %d; "
2988 "default dur %d, size %d, flags 0x%x, base offset %" G_GINT64_FORMAT ", "
2989 "decode ts %" G_GINT64_FORMAT, stream->track_id, d_sample_duration,
2990 d_sample_size, d_sample_flags, *base_offset, decode_ts);
2992 if (stream->pending_seek && moof_offset < stream->pending_seek->moof_offset) {
2993 GST_INFO_OBJECT (stream->pad, "skipping trun before seek target fragment");
2997 /* presence of stss or not can't really tell us much,
2998 * and flags and so on tend to be marginally reliable in these files */
2999 if (stream->subtype == FOURCC_soun) {
3000 GST_DEBUG_OBJECT (qtdemux,
3001 "sound track in fragmented file; marking all keyframes");
3002 stream->all_keyframe = TRUE;
3005 if (!gst_byte_reader_skip (trun, 1) ||
3006 !gst_byte_reader_get_uint24_be (trun, &flags))
3009 if (!gst_byte_reader_get_uint32_be (trun, &samples_count))
3012 if (flags & TR_DATA_OFFSET) {
3013 /* note this is really signed */
3014 if (!gst_byte_reader_get_int32_be (trun, &data_offset))
3016 GST_LOG_OBJECT (qtdemux, "trun data offset %d", data_offset);
3017 /* default base offset = first byte of moof */
3018 if (*base_offset == -1) {
3019 GST_LOG_OBJECT (qtdemux, "base_offset at moof");
3020 *base_offset = moof_offset;
3022 *running_offset = *base_offset + data_offset;
3024 /* if no offset at all, that would mean data starts at moof start,
3025 * which is a bit wrong and is ismv crappy way, so compensate
3026 * assuming data is in mdat following moof */
3027 if (*base_offset == -1) {
3028 *base_offset = moof_offset + moof_length + 8;
3029 GST_LOG_OBJECT (qtdemux, "base_offset assumed in mdat after moof");
3032 if (*running_offset == -1)
3033 *running_offset = *base_offset;
3036 GST_LOG_OBJECT (qtdemux, "running offset now %" G_GINT64_FORMAT,
3038 GST_LOG_OBJECT (qtdemux, "trun offset %d, flags 0x%x, entries %d",
3039 data_offset, flags, samples_count);
3041 if (flags & TR_FIRST_SAMPLE_FLAGS) {
3042 if (G_UNLIKELY (flags & TR_SAMPLE_FLAGS)) {
3043 GST_DEBUG_OBJECT (qtdemux,
3044 "invalid flags; SAMPLE and FIRST_SAMPLE present, discarding latter");
3045 flags ^= TR_FIRST_SAMPLE_FLAGS;
3047 if (!gst_byte_reader_get_uint32_be (trun, &first_flags))
3049 GST_LOG_OBJECT (qtdemux, "first flags: 0x%x", first_flags);
3053 /* FIXME ? spec says other bits should also be checked to determine
3054 * entry size (and prefix size for that matter) */
3056 dur_offset = size_offset = 0;
3057 if (flags & TR_SAMPLE_DURATION) {
3058 GST_LOG_OBJECT (qtdemux, "entry duration present");
3059 dur_offset = entry_size;
3062 if (flags & TR_SAMPLE_SIZE) {
3063 GST_LOG_OBJECT (qtdemux, "entry size present");
3064 size_offset = entry_size;
3067 if (flags & TR_SAMPLE_FLAGS) {
3068 GST_LOG_OBJECT (qtdemux, "entry flags present");
3069 flags_offset = entry_size;
3072 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
3073 GST_LOG_OBJECT (qtdemux, "entry ct offset present");
3074 ct_offset = entry_size;
3078 if (!qt_atom_parser_has_chunks (trun, samples_count, entry_size))
3080 data = (guint8 *) gst_byte_reader_peek_data_unchecked (trun);
3082 if (stream->n_samples + samples_count >=
3083 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample))
3086 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
3087 stream->n_samples + samples_count, (guint) sizeof (QtDemuxSample),
3088 (stream->n_samples + samples_count) *
3089 sizeof (QtDemuxSample) / (1024.0 * 1024.0));
3091 /* create a new array of samples if it's the first sample parsed */
3092 if (stream->n_samples == 0) {
3093 g_assert (stream->samples == NULL);
3094 stream->samples = g_try_new0 (QtDemuxSample, samples_count);
3095 /* or try to reallocate it with space enough to insert the new samples */
3097 stream->samples = g_try_renew (QtDemuxSample, stream->samples,
3098 stream->n_samples + samples_count);
3099 if (stream->samples == NULL)
3102 if (qtdemux->fragment_start != -1) {
3103 timestamp = GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->fragment_start);
3104 qtdemux->fragment_start = -1;
3106 if (stream->n_samples == 0) {
3107 if (decode_ts > 0) {
3108 timestamp = decode_ts;
3109 } else if (stream->pending_seek != NULL) {
3110 /* if we don't have a timestamp from a tfdt box, we'll use the one
3111 * from the mfra seek table */
3112 GST_INFO_OBJECT (stream->pad, "pending seek ts = %" GST_TIME_FORMAT,
3113 GST_TIME_ARGS (stream->pending_seek->ts));
3115 /* FIXME: this is not fully correct, the timestamp refers to the random
3116 * access sample refered to in the tfra entry, which may not necessarily
3117 * be the first sample in the tfrag/trun (but hopefully/usually is) */
3118 timestamp = GSTTIME_TO_QTSTREAMTIME (stream, stream->pending_seek->ts);
3123 gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
3124 GST_INFO_OBJECT (stream->pad, "first sample ts %" GST_TIME_FORMAT,
3125 GST_TIME_ARGS (gst_ts));
3127 /* subsequent fragments extend stream */
3129 stream->samples[stream->n_samples - 1].timestamp +
3130 stream->samples[stream->n_samples - 1].duration;
3132 /* If this is a GST_FORMAT_BYTES stream and there's a significant
3133 * difference (1 sec.) between decode_ts and timestamp, prefer the
3135 if (!qtdemux->upstream_format_is_time
3136 && ABSDIFF (decode_ts, timestamp) >
3137 MAX (stream->duration_last_moof / 2,
3138 GSTTIME_TO_QTSTREAMTIME (stream, GST_SECOND))) {
3139 GST_INFO_OBJECT (qtdemux,
3140 "decode_ts (%" GST_TIME_FORMAT ") and timestamp (%" GST_TIME_FORMAT
3141 ") are significantly different (more than %" GST_TIME_FORMAT
3142 "), using decode_ts",
3143 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, decode_ts)),
3144 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, timestamp)),
3145 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream,
3146 MAX (stream->duration_last_moof / 2,
3147 GSTTIME_TO_QTSTREAMTIME (stream, GST_SECOND)))));
3148 timestamp = decode_ts;
3151 gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
3152 GST_INFO_OBJECT (qtdemux, "first sample ts %" GST_TIME_FORMAT
3153 " (extends previous samples)", GST_TIME_ARGS (gst_ts));
3157 initial_offset = *running_offset;
3159 sample = stream->samples + stream->n_samples;
3160 for (i = 0; i < samples_count; i++) {
3161 guint32 dur, size, sflags, ct;
3163 /* first read sample data */
3164 if (flags & TR_SAMPLE_DURATION) {
3165 dur = QT_UINT32 (data + dur_offset);
3167 dur = d_sample_duration;
3169 if (flags & TR_SAMPLE_SIZE) {
3170 size = QT_UINT32 (data + size_offset);
3172 size = d_sample_size;
3174 if (flags & TR_FIRST_SAMPLE_FLAGS) {
3176 sflags = first_flags;
3178 sflags = d_sample_flags;
3180 } else if (flags & TR_SAMPLE_FLAGS) {
3181 sflags = QT_UINT32 (data + flags_offset);
3183 sflags = d_sample_flags;
3185 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
3186 ct = QT_UINT32 (data + ct_offset);
3192 /* fill the sample information */
3193 sample->offset = *running_offset;
3194 sample->pts_offset = ct;
3195 sample->size = size;
3196 sample->timestamp = timestamp;
3197 sample->duration = dur;
3198 /* sample-is-difference-sample */
3199 /* ismv seems to use 0x40 for keyframe, 0xc0 for non-keyframe,
3200 * now idea how it relates to bitfield other than massive LE/BE confusion */
3201 sample->keyframe = ismv ? ((sflags & 0xff) == 0x40) : !(sflags & 0x10000);
3202 *running_offset += size;
3204 stream->duration_moof += dur;
3208 /* Update total duration if needed */
3209 check_update_duration (qtdemux, QTSTREAMTIME_TO_GSTTIME (stream, timestamp));
3211 /* Pre-emptively figure out size of mdat based on trun information.
3212 * If the [mdat] atom is effectivelly read, it will be replaced by the actual
3213 * size, else we will still be able to use this when dealing with gap'ed
3215 qtdemux->mdatleft = *running_offset - initial_offset;
3217 stream->n_samples += samples_count;
3218 stream->n_samples_moof += samples_count;
3220 if (stream->pending_seek != NULL)
3221 stream->pending_seek = NULL;
3227 GST_WARNING_OBJECT (qtdemux, "failed to parse trun");
3232 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
3238 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
3239 "be larger than %uMB (broken file?)", stream->n_samples,
3240 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
3245 /* find stream with @id */
3246 static inline QtDemuxStream *
3247 qtdemux_find_stream (GstQTDemux * qtdemux, guint32 id)
3249 QtDemuxStream *stream;
3253 if (G_UNLIKELY (!id)) {
3254 GST_DEBUG_OBJECT (qtdemux, "invalid track id 0");
3258 /* try to get it fast and simple */
3259 if (G_LIKELY (id <= qtdemux->n_streams)) {
3260 stream = qtdemux->streams[id - 1];
3261 if (G_LIKELY (stream->track_id == id))
3265 /* linear search otherwise */
3266 for (i = 0; i < qtdemux->n_streams; i++) {
3267 stream = qtdemux->streams[i];
3268 if (stream->track_id == id)
3271 if (qtdemux->mss_mode) {
3272 /* mss should have only 1 stream anyway */
3273 return qtdemux->streams[0];
3280 qtdemux_parse_mfhd (GstQTDemux * qtdemux, GstByteReader * mfhd,
3281 guint32 * fragment_number)
3283 if (!gst_byte_reader_skip (mfhd, 4))
3285 if (!gst_byte_reader_get_uint32_be (mfhd, fragment_number))
3290 GST_WARNING_OBJECT (qtdemux, "Failed to parse mfhd atom");
3296 qtdemux_parse_tfhd (GstQTDemux * qtdemux, GstByteReader * tfhd,
3297 QtDemuxStream ** stream, guint32 * default_sample_duration,
3298 guint32 * default_sample_size, guint32 * default_sample_flags,
3299 gint64 * base_offset)
3302 guint32 track_id = 0;
3304 if (!gst_byte_reader_skip (tfhd, 1) ||
3305 !gst_byte_reader_get_uint24_be (tfhd, &flags))
3308 if (!gst_byte_reader_get_uint32_be (tfhd, &track_id))
3311 *stream = qtdemux_find_stream (qtdemux, track_id);
3312 if (G_UNLIKELY (!*stream))
3313 goto unknown_stream;
3315 if (flags & TF_DEFAULT_BASE_IS_MOOF)
3316 *base_offset = qtdemux->moof_offset;
3318 if (flags & TF_BASE_DATA_OFFSET)
3319 if (!gst_byte_reader_get_uint64_be (tfhd, (guint64 *) base_offset))
3322 /* obtain stream defaults */
3323 qtdemux_parse_trex (qtdemux, *stream,
3324 default_sample_duration, default_sample_size, default_sample_flags);
3326 /* FIXME: Handle TF_SAMPLE_DESCRIPTION_INDEX properly */
3327 if (flags & TF_SAMPLE_DESCRIPTION_INDEX)
3328 if (!gst_byte_reader_skip (tfhd, 4))
3331 if (flags & TF_DEFAULT_SAMPLE_DURATION)
3332 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_duration))
3335 if (flags & TF_DEFAULT_SAMPLE_SIZE)
3336 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_size))
3339 if (flags & TF_DEFAULT_SAMPLE_FLAGS)
3340 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_flags))
3347 GST_WARNING_OBJECT (qtdemux, "invalid track fragment header");
3352 GST_DEBUG_OBJECT (qtdemux, "unknown stream in tfhd");
3358 qtdemux_parse_tfdt (GstQTDemux * qtdemux, GstByteReader * br,
3359 guint64 * decode_time)
3361 guint32 version = 0;
3363 if (!gst_byte_reader_get_uint32_be (br, &version))
3368 if (!gst_byte_reader_get_uint64_be (br, decode_time))
3371 guint32 dec_time = 0;
3372 if (!gst_byte_reader_get_uint32_be (br, &dec_time))
3374 *decode_time = dec_time;
3377 GST_INFO_OBJECT (qtdemux, "Track fragment decode time: %" G_GUINT64_FORMAT,
3384 GST_DEBUG_OBJECT (qtdemux, "parsing tfdt failed");
3389 /* Returns a pointer to a GstStructure containing the properties of
3390 * the stream sample identified by @sample_index. The caller must unref
3391 * the returned object after use. Returns NULL if unsuccessful. */
3392 static GstStructure *
3393 qtdemux_get_cenc_sample_properties (GstQTDemux * qtdemux,
3394 QtDemuxStream * stream, guint sample_index)
3396 QtDemuxCencSampleSetInfo *info = NULL;
3398 g_return_val_if_fail (stream != NULL, NULL);
3399 g_return_val_if_fail (stream->protected, NULL);
3400 g_return_val_if_fail (stream->protection_scheme_info != NULL, NULL);
3402 info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
3404 /* Currently, cenc properties for groups of samples are not supported, so
3405 * simply return a copy of the default sample properties */
3406 return gst_structure_copy (info->default_properties);
3409 /* Parses the sizes of sample auxiliary information contained within a stream,
3410 * as given in a saiz box. Returns array of sample_count guint8 size values,
3411 * or NULL on failure */
3413 qtdemux_parse_saiz (GstQTDemux * qtdemux, QtDemuxStream * stream,
3414 GstByteReader * br, guint32 * sample_count)
3418 guint8 default_info_size;
3420 g_return_val_if_fail (qtdemux != NULL, NULL);
3421 g_return_val_if_fail (stream != NULL, NULL);
3422 g_return_val_if_fail (br != NULL, NULL);
3423 g_return_val_if_fail (sample_count != NULL, NULL);
3425 if (!gst_byte_reader_get_uint32_be (br, &flags))
3429 /* aux_info_type and aux_info_type_parameter are ignored */
3430 if (!gst_byte_reader_skip (br, 8))
3434 if (!gst_byte_reader_get_uint8 (br, &default_info_size))
3436 GST_DEBUG_OBJECT (qtdemux, "default_info_size: %u", default_info_size);
3438 if (!gst_byte_reader_get_uint32_be (br, sample_count))
3440 GST_DEBUG_OBJECT (qtdemux, "sample_count: %u", *sample_count);
3443 if (default_info_size == 0) {
3444 if (!gst_byte_reader_dup_data (br, *sample_count, &info_sizes)) {
3448 info_sizes = g_new (guint8, *sample_count);
3449 memset (info_sizes, default_info_size, *sample_count);
3455 /* Parses the offset of sample auxiliary information contained within a stream,
3456 * as given in a saio box. Returns TRUE if successful; FALSE otherwise. */
3458 qtdemux_parse_saio (GstQTDemux * qtdemux, QtDemuxStream * stream,
3459 GstByteReader * br, guint32 * info_type, guint32 * info_type_parameter,
3464 guint32 aux_info_type = 0;
3465 guint32 aux_info_type_parameter = 0;
3466 guint32 entry_count;
3469 const guint8 *aux_info_type_data = NULL;
3471 g_return_val_if_fail (qtdemux != NULL, FALSE);
3472 g_return_val_if_fail (stream != NULL, FALSE);
3473 g_return_val_if_fail (br != NULL, FALSE);
3474 g_return_val_if_fail (offset != NULL, FALSE);
3476 if (!gst_byte_reader_get_uint8 (br, &version))
3479 if (!gst_byte_reader_get_uint24_be (br, &flags))
3484 if (!gst_byte_reader_get_data (br, 4, &aux_info_type_data))
3486 aux_info_type = QT_FOURCC (aux_info_type_data);
3488 if (!gst_byte_reader_get_uint32_be (br, &aux_info_type_parameter))
3490 } else if (stream->protected) {
3491 aux_info_type = stream->protection_scheme_type;
3493 aux_info_type = stream->fourcc;
3497 *info_type = aux_info_type;
3498 if (info_type_parameter)
3499 *info_type_parameter = aux_info_type_parameter;
3501 GST_DEBUG_OBJECT (qtdemux, "aux_info_type: '%" GST_FOURCC_FORMAT "', "
3502 "aux_info_type_parameter: %#06x",
3503 GST_FOURCC_ARGS (aux_info_type), aux_info_type_parameter);
3505 if (!gst_byte_reader_get_uint32_be (br, &entry_count))
3508 if (entry_count != 1) {
3509 GST_ERROR_OBJECT (qtdemux, "multiple offsets are not supported");
3514 if (!gst_byte_reader_get_uint32_be (br, &off_32))
3516 *offset = (guint64) off_32;
3518 if (!gst_byte_reader_get_uint64_be (br, &off_64))
3523 GST_DEBUG_OBJECT (qtdemux, "offset: %" G_GUINT64_FORMAT, *offset);
3528 qtdemux_gst_structure_free (GstStructure * gststructure)
3531 gst_structure_free (gststructure);
3535 /* Parses auxiliary information relating to samples protected using Common
3536 * Encryption (cenc); the format of this information is defined in
3537 * ISO/IEC 23001-7. Returns TRUE if successful; FALSE otherwise. */
3539 qtdemux_parse_cenc_aux_info (GstQTDemux * qtdemux, QtDemuxStream * stream,
3540 GstByteReader * br, guint8 * info_sizes, guint32 sample_count)
3542 QtDemuxCencSampleSetInfo *ss_info = NULL;
3546 g_return_val_if_fail (qtdemux != NULL, FALSE);
3547 g_return_val_if_fail (stream != NULL, FALSE);
3548 g_return_val_if_fail (br != NULL, FALSE);
3549 g_return_val_if_fail (stream->protected, FALSE);
3550 g_return_val_if_fail (stream->protection_scheme_info != NULL, FALSE);
3552 ss_info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
3554 if (ss_info->crypto_info) {
3555 GST_LOG_OBJECT (qtdemux, "unreffing existing crypto_info");
3556 g_ptr_array_free (ss_info->crypto_info, TRUE);
3559 ss_info->crypto_info =
3560 g_ptr_array_new_full (sample_count,
3561 (GDestroyNotify) qtdemux_gst_structure_free);
3563 for (i = 0; i < sample_count; ++i) {
3564 GstStructure *properties;
3565 guint16 n_subsamples = 0;
3570 properties = qtdemux_get_cenc_sample_properties (qtdemux, stream, i);
3571 if (properties == NULL) {
3572 GST_ERROR_OBJECT (qtdemux, "failed to get properties for sample %u", i);
3575 if (!gst_structure_get_uint (properties, "iv_size", &iv_size)) {
3576 GST_ERROR_OBJECT (qtdemux, "failed to get iv_size for sample %u", i);
3577 gst_structure_free (properties);
3580 if (!gst_byte_reader_dup_data (br, iv_size, &data)) {
3581 GST_ERROR_OBJECT (qtdemux, "failed to get IV for sample %u", i);
3582 gst_structure_free (properties);
3585 buf = gst_buffer_new_wrapped (data, iv_size);
3586 gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL);
3587 gst_buffer_unref (buf);
3588 size = info_sizes[i];
3589 if (size > iv_size) {
3590 if (!gst_byte_reader_get_uint16_be (br, &n_subsamples)
3591 || !(n_subsamples > 0)) {
3592 gst_structure_free (properties);
3593 GST_ERROR_OBJECT (qtdemux,
3594 "failed to get subsample count for sample %u", i);
3597 GST_LOG_OBJECT (qtdemux, "subsample count: %u", n_subsamples);
3598 if (!gst_byte_reader_dup_data (br, n_subsamples * 6, &data)) {
3599 GST_ERROR_OBJECT (qtdemux, "failed to get subsample data for sample %u",
3601 gst_structure_free (properties);
3604 buf = gst_buffer_new_wrapped (data, n_subsamples * 6);
3606 gst_structure_free (properties);
3609 gst_structure_set (properties,
3610 "subsample_count", G_TYPE_UINT, n_subsamples,
3611 "subsamples", GST_TYPE_BUFFER, buf, NULL);
3612 gst_buffer_unref (buf);
3614 gst_structure_set (properties, "subsample_count", G_TYPE_UINT, 0, NULL);
3616 g_ptr_array_add (ss_info->crypto_info, properties);
3621 /* Converts a UUID in raw byte form to a string representation, as defined in
3622 * RFC 4122. The caller takes ownership of the returned string and is
3623 * responsible for freeing it after use. */
3625 qtdemux_uuid_bytes_to_string (gconstpointer uuid_bytes)
3627 const guint8 *uuid = (const guint8 *) uuid_bytes;
3629 return g_strdup_printf ("%02x%02x%02x%02x-%02x%02x-%02x%02x-"
3630 "%02x%02x-%02x%02x%02x%02x%02x%02x",
3631 uuid[0], uuid[1], uuid[2], uuid[3],
3632 uuid[4], uuid[5], uuid[6], uuid[7],
3633 uuid[8], uuid[9], uuid[10], uuid[11],
3634 uuid[12], uuid[13], uuid[14], uuid[15]);
3637 /* Parses a Protection System Specific Header box (pssh), as defined in the
3638 * Common Encryption (cenc) standard (ISO/IEC 23001-7), which contains
3639 * information needed by a specific content protection system in order to
3640 * decrypt cenc-protected tracks. Returns TRUE if successful; FALSE
3643 qtdemux_parse_pssh (GstQTDemux * qtdemux, GNode * node)
3645 gchar *sysid_string;
3646 guint32 pssh_size = QT_UINT32 (node->data);
3647 GstBuffer *pssh = NULL;
3648 GstEvent *event = NULL;
3649 guint32 parent_box_type;
3652 if (G_UNLIKELY (pssh_size < 32U)) {
3653 GST_ERROR_OBJECT (qtdemux, "invalid box size");
3658 qtdemux_uuid_bytes_to_string ((const guint8 *) node->data + 12);
3660 gst_qtdemux_append_protection_system_id (qtdemux, sysid_string);
3662 pssh = gst_buffer_new_wrapped (g_memdup (node->data, pssh_size), pssh_size);
3663 GST_LOG_OBJECT (qtdemux, "cenc pssh size: %" G_GSIZE_FORMAT,
3664 gst_buffer_get_size (pssh));
3666 parent_box_type = QT_FOURCC ((const guint8 *) node->parent->data + 4);
3668 /* Push an event containing the pssh box onto the queues of all streams. */
3669 event = gst_event_new_protection (sysid_string, pssh,
3670 (parent_box_type == FOURCC_moov) ? "isobmff/moov" : "isobmff/moof");
3671 for (i = 0; i < qtdemux->n_streams; ++i) {
3672 g_queue_push_tail (&qtdemux->streams[i]->protection_scheme_event_queue,
3673 gst_event_ref (event));
3675 g_free (sysid_string);
3676 gst_event_unref (event);
3677 gst_buffer_unref (pssh);
3682 qtdemux_parse_moof (GstQTDemux * qtdemux, const guint8 * buffer, guint length,
3683 guint64 moof_offset, QtDemuxStream * stream)
3685 GNode *moof_node, *traf_node, *tfhd_node, *trun_node, *tfdt_node, *mfhd_node;
3687 GstByteReader mfhd_data, trun_data, tfhd_data, tfdt_data;
3688 GNode *saiz_node, *saio_node, *pssh_node;
3689 GstByteReader saiz_data, saio_data;
3690 guint32 ds_size = 0, ds_duration = 0, ds_flags = 0;
3691 gint64 base_offset, running_offset;
3694 /* NOTE @stream ignored */
3696 moof_node = g_node_new ((guint8 *) buffer);
3697 qtdemux_parse_node (qtdemux, moof_node, buffer, length);
3698 qtdemux_node_dump (qtdemux, moof_node);
3700 /* Get fragment number from mfhd and check it's valid */
3702 qtdemux_tree_get_child_by_type_full (moof_node, FOURCC_mfhd, &mfhd_data);
3703 if (mfhd_node == NULL)
3705 if (!qtdemux_parse_mfhd (qtdemux, &mfhd_data, &frag_num))
3707 GST_DEBUG_OBJECT (qtdemux, "Fragment #%d", frag_num);
3709 /* unknown base_offset to start with */
3710 base_offset = running_offset = -1;
3711 traf_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_traf);
3713 guint64 decode_time = 0;
3715 /* Fragment Header node */
3717 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfhd,
3721 if (!qtdemux_parse_tfhd (qtdemux, &tfhd_data, &stream, &ds_duration,
3722 &ds_size, &ds_flags, &base_offset))
3725 /* The following code assumes at most a single set of sample auxiliary
3726 * data in the fragment (consisting of a saiz box and a corresponding saio
3727 * box); in theory, however, there could be multiple sets of sample
3728 * auxiliary data in a fragment. */
3730 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saiz,
3733 guint32 info_type = 0;
3735 guint32 info_type_parameter = 0;
3737 g_free (qtdemux->cenc_aux_info_sizes);
3739 qtdemux->cenc_aux_info_sizes =
3740 qtdemux_parse_saiz (qtdemux, stream, &saiz_data,
3741 &qtdemux->cenc_aux_sample_count);
3742 if (qtdemux->cenc_aux_info_sizes == NULL) {
3743 GST_ERROR_OBJECT (qtdemux, "failed to parse saiz box");
3747 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saio,
3750 GST_ERROR_OBJECT (qtdemux, "saiz box without a corresponding saio box");
3751 g_free (qtdemux->cenc_aux_info_sizes);
3752 qtdemux->cenc_aux_info_sizes = NULL;
3756 if (G_UNLIKELY (!qtdemux_parse_saio (qtdemux, stream, &saio_data,
3757 &info_type, &info_type_parameter, &offset))) {
3758 GST_ERROR_OBJECT (qtdemux, "failed to parse saio box");
3759 g_free (qtdemux->cenc_aux_info_sizes);
3760 qtdemux->cenc_aux_info_sizes = NULL;
3763 if (base_offset > -1 && base_offset > qtdemux->moof_offset)
3764 offset += (guint64) (base_offset - qtdemux->moof_offset);
3765 if (info_type == FOURCC_cenc && info_type_parameter == 0U) {
3767 if (offset > length) {
3768 GST_DEBUG_OBJECT (qtdemux, "cenc auxiliary info stored out of moof");
3769 qtdemux->cenc_aux_info_offset = offset;
3771 gst_byte_reader_init (&br, buffer + offset, length - offset);
3772 if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
3773 qtdemux->cenc_aux_info_sizes,
3774 qtdemux->cenc_aux_sample_count)) {
3775 GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
3776 g_free (qtdemux->cenc_aux_info_sizes);
3777 qtdemux->cenc_aux_info_sizes = NULL;
3785 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfdt,
3788 /* We'll use decode_time to interpolate timestamps
3789 * in case the input timestamps are missing */
3790 qtdemux_parse_tfdt (qtdemux, &tfdt_data, &decode_time);
3792 GST_DEBUG_OBJECT (qtdemux, "decode time %" G_GINT64_FORMAT
3793 " (%" GST_TIME_FORMAT ")", decode_time,
3794 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, decode_time)));
3796 /* Discard the fragment buffer timestamp info to avoid using it.
3797 * Rely on tfdt instead as it is more accurate than the timestamp
3798 * that is fetched from a manifest/playlist and is usually
3800 qtdemux->fragment_start = -1;
3803 if (G_UNLIKELY (!stream)) {
3804 /* we lost track of offset, we'll need to regain it,
3805 * but can delay complaining until later or avoid doing so altogether */
3809 if (G_UNLIKELY (base_offset < -1))
3812 if (qtdemux->upstream_format_is_time)
3813 gst_qtdemux_stream_flush_samples_data (qtdemux, stream);
3815 /* initialise moof sample data */
3816 stream->n_samples_moof = 0;
3817 stream->duration_last_moof = stream->duration_moof;
3818 stream->duration_moof = 0;
3820 /* Track Run node */
3822 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_trun,
3825 qtdemux_parse_trun (qtdemux, &trun_data, stream,
3826 ds_duration, ds_size, ds_flags, moof_offset, length, &base_offset,
3827 &running_offset, decode_time);
3828 /* iterate all siblings */
3829 trun_node = qtdemux_tree_get_sibling_by_type_full (trun_node, FOURCC_trun,
3833 uuid_node = qtdemux_tree_get_child_by_type (traf_node, FOURCC_uuid);
3835 guint8 *uuid_buffer = (guint8 *) uuid_node->data;
3836 guint32 box_length = QT_UINT32 (uuid_buffer);
3838 qtdemux_parse_uuid (qtdemux, uuid_buffer, box_length);
3841 /* if no new base_offset provided for next traf,
3842 * base is end of current traf */
3843 base_offset = running_offset;
3844 running_offset = -1;
3846 if (stream->n_samples_moof && stream->duration_moof)
3847 stream->new_caps = TRUE;
3850 /* iterate all siblings */
3851 traf_node = qtdemux_tree_get_sibling_by_type (traf_node, FOURCC_traf);
3854 /* parse any protection system info */
3855 pssh_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_pssh);
3857 GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
3858 qtdemux_parse_pssh (qtdemux, pssh_node);
3859 pssh_node = qtdemux_tree_get_sibling_by_type (pssh_node, FOURCC_pssh);
3862 g_node_destroy (moof_node);
3867 GST_DEBUG_OBJECT (qtdemux, "missing tfhd box");
3872 GST_DEBUG_OBJECT (qtdemux, "Missing mfhd box");
3877 GST_DEBUG_OBJECT (qtdemux, "lost offset");
3882 g_node_destroy (moof_node);
3883 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
3884 (_("This file is corrupt and cannot be played.")), (NULL));
3890 /* might be used if some day we actually use mfra & co
3891 * for random access to fragments,
3892 * but that will require quite some modifications and much less relying
3893 * on a sample array */
3897 qtdemux_parse_tfra (GstQTDemux * qtdemux, GNode * tfra_node)
3899 QtDemuxStream *stream;
3900 guint32 ver_flags, track_id, len, num_entries, i;
3901 guint value_size, traf_size, trun_size, sample_size;
3902 guint64 time = 0, moof_offset = 0;
3904 GstBuffer *buf = NULL;
3909 gst_byte_reader_init (&tfra, tfra_node->data, QT_UINT32 (tfra_node->data));
3911 if (!gst_byte_reader_skip (&tfra, 8))
3914 if (!gst_byte_reader_get_uint32_be (&tfra, &ver_flags))
3917 if (!gst_byte_reader_get_uint32_be (&tfra, &track_id)
3918 || !gst_byte_reader_get_uint32_be (&tfra, &len)
3919 || !gst_byte_reader_get_uint32_be (&tfra, &num_entries))
3922 GST_DEBUG_OBJECT (qtdemux, "parsing tfra box for track id %u", track_id);
3924 stream = qtdemux_find_stream (qtdemux, track_id);
3926 goto unknown_trackid;
3928 value_size = ((ver_flags >> 24) == 1) ? sizeof (guint64) : sizeof (guint32);
3929 sample_size = (len & 3) + 1;
3930 trun_size = ((len & 12) >> 2) + 1;
3931 traf_size = ((len & 48) >> 4) + 1;
3933 GST_DEBUG_OBJECT (qtdemux, "%u entries, sizes: value %u, traf %u, trun %u, "
3934 "sample %u", num_entries, value_size, traf_size, trun_size, sample_size);
3936 if (num_entries == 0)
3939 if (!qt_atom_parser_has_chunks (&tfra, num_entries,
3940 value_size + value_size + traf_size + trun_size + sample_size))
3943 g_free (stream->ra_entries);
3944 stream->ra_entries = g_new (QtDemuxRandomAccessEntry, num_entries);
3945 stream->n_ra_entries = num_entries;
3947 for (i = 0; i < num_entries; i++) {
3948 qt_atom_parser_get_offset (&tfra, value_size, &time);
3949 qt_atom_parser_get_offset (&tfra, value_size, &moof_offset);
3950 qt_atom_parser_get_uint_with_size_unchecked (&tfra, traf_size);
3951 qt_atom_parser_get_uint_with_size_unchecked (&tfra, trun_size);
3952 qt_atom_parser_get_uint_with_size_unchecked (&tfra, sample_size);
3954 time = QTSTREAMTIME_TO_GSTTIME (stream, time);
3956 GST_LOG_OBJECT (qtdemux, "fragment time: %" GST_TIME_FORMAT ", "
3957 " moof_offset: %" G_GUINT64_FORMAT, GST_TIME_ARGS (time), moof_offset);
3959 stream->ra_entries[i].ts = time;
3960 stream->ra_entries[i].moof_offset = moof_offset;
3962 /* don't want to go through the entire file and read all moofs at startup */
3964 ret = gst_qtdemux_pull_atom (qtdemux, moof_offset, 0, &buf);
3965 if (ret != GST_FLOW_OK)
3967 qtdemux_parse_moof (qtdemux, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf),
3968 moof_offset, stream);
3969 gst_buffer_unref (buf);
3973 check_update_duration (qtdemux, time);
3980 GST_WARNING_OBJECT (qtdemux, "Couldn't find stream for track %u", track_id);
3985 GST_WARNING_OBJECT (qtdemux, "broken traf box, ignoring");
3990 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
3996 qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux)
3998 GstMapInfo mfro_map = GST_MAP_INFO_INIT;
3999 GstMapInfo mfra_map = GST_MAP_INFO_INIT;
4000 GstBuffer *mfro = NULL, *mfra = NULL;
4002 gboolean ret = FALSE;
4003 GNode *mfra_node, *tfra_node;
4004 guint64 mfra_offset = 0;
4005 guint32 fourcc, mfra_size;
4008 /* query upstream size in bytes */
4009 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &len))
4010 goto size_query_failed;
4012 /* mfro box should be at the very end of the file */
4013 flow = gst_qtdemux_pull_atom (qtdemux, len - 16, 16, &mfro);
4014 if (flow != GST_FLOW_OK)
4017 gst_buffer_map (mfro, &mfro_map, GST_MAP_READ);
4019 fourcc = QT_FOURCC (mfro_map.data + 4);
4020 if (fourcc != FOURCC_mfro)
4023 GST_INFO_OBJECT (qtdemux, "Found mfro box");
4024 if (mfro_map.size < 16)
4025 goto invalid_mfro_size;
4027 mfra_size = QT_UINT32 (mfro_map.data + 12);
4028 if (mfra_size >= len)
4029 goto invalid_mfra_size;
4031 mfra_offset = len - mfra_size;
4033 GST_INFO_OBJECT (qtdemux, "mfra offset: %" G_GUINT64_FORMAT ", size %u",
4034 mfra_offset, mfra_size);
4036 /* now get and parse mfra box */
4037 flow = gst_qtdemux_pull_atom (qtdemux, mfra_offset, mfra_size, &mfra);
4038 if (flow != GST_FLOW_OK)
4041 gst_buffer_map (mfra, &mfra_map, GST_MAP_READ);
4043 mfra_node = g_node_new ((guint8 *) mfra_map.data);
4044 qtdemux_parse_node (qtdemux, mfra_node, mfra_map.data, mfra_map.size);
4046 tfra_node = qtdemux_tree_get_child_by_type (mfra_node, FOURCC_tfra);
4049 qtdemux_parse_tfra (qtdemux, tfra_node);
4050 /* iterate all siblings */
4051 tfra_node = qtdemux_tree_get_sibling_by_type (tfra_node, FOURCC_tfra);
4053 g_node_destroy (mfra_node);
4055 GST_INFO_OBJECT (qtdemux, "parsed movie fragment random access box (mfra)");
4061 if (mfro_map.memory != NULL)
4062 gst_buffer_unmap (mfro, &mfro_map);
4063 gst_buffer_unref (mfro);
4066 if (mfra_map.memory != NULL)
4067 gst_buffer_unmap (mfra, &mfra_map);
4068 gst_buffer_unref (mfra);
4075 GST_WARNING_OBJECT (qtdemux, "could not query upstream size");
4080 GST_WARNING_OBJECT (qtdemux, "mfro size is too small");
4085 GST_WARNING_OBJECT (qtdemux, "mfra_size in mfro box is invalid");
4090 GST_WARNING_OBJECT (qtdemux, "bogus mfra offset or size, broken file");
4096 add_offset (guint64 offset, guint64 advance)
4098 /* Avoid 64-bit overflow by clamping */
4099 if (offset > G_MAXUINT64 - advance)
4101 return offset + advance;
4104 static GstFlowReturn
4105 gst_qtdemux_loop_state_header (GstQTDemux * qtdemux)
4109 GstBuffer *buf = NULL;
4110 GstFlowReturn ret = GST_FLOW_OK;
4111 guint64 cur_offset = qtdemux->offset;
4114 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, 16, &buf);
4115 if (G_UNLIKELY (ret != GST_FLOW_OK))
4117 gst_buffer_map (buf, &map, GST_MAP_READ);
4118 if (G_LIKELY (map.size >= 8))
4119 extract_initial_length_and_fourcc (map.data, map.size, &length, &fourcc);
4120 gst_buffer_unmap (buf, &map);
4121 gst_buffer_unref (buf);
4123 /* maybe we already got most we needed, so only consider this eof */
4124 if (G_UNLIKELY (length == 0)) {
4125 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
4126 (_("Invalid atom size.")),
4127 ("Header atom '%" GST_FOURCC_FORMAT "' has empty length",
4128 GST_FOURCC_ARGS (fourcc)));
4135 /* record for later parsing when needed */
4136 if (!qtdemux->moof_offset) {
4137 qtdemux->moof_offset = qtdemux->offset;
4139 if (qtdemux_pull_mfro_mfra (qtdemux)) {
4142 qtdemux->offset += length; /* skip moof and keep going */
4144 if (qtdemux->got_moov) {
4145 GST_INFO_OBJECT (qtdemux, "moof header, got moov, done with headers");
4156 GST_LOG_OBJECT (qtdemux,
4157 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
4158 GST_FOURCC_ARGS (fourcc), cur_offset);
4159 qtdemux->offset = add_offset (qtdemux->offset, length);
4164 GstBuffer *moov = NULL;
4166 if (qtdemux->got_moov) {
4167 GST_DEBUG_OBJECT (qtdemux, "Skipping moov atom as we have one already");
4168 qtdemux->offset = add_offset (qtdemux->offset, length);
4172 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, length, &moov);
4173 if (ret != GST_FLOW_OK)
4175 gst_buffer_map (moov, &map, GST_MAP_READ);
4177 if (length != map.size) {
4178 /* Some files have a 'moov' atom at the end of the file which contains
4179 * a terminal 'free' atom where the body of the atom is missing.
4180 * Check for, and permit, this special case.
4182 if (map.size >= 8) {
4183 guint8 *final_data = map.data + (map.size - 8);
4184 guint32 final_length = QT_UINT32 (final_data);
4185 guint32 final_fourcc = QT_FOURCC (final_data + 4);
4187 if (final_fourcc == FOURCC_free
4188 && map.size + final_length - 8 == length) {
4189 /* Ok, we've found that special case. Allocate a new buffer with
4190 * that free atom actually present. */
4191 GstBuffer *newmoov = gst_buffer_new_and_alloc (length);
4192 gst_buffer_fill (newmoov, 0, map.data, map.size);
4193 gst_buffer_memset (newmoov, map.size, 0, final_length - 8);
4194 gst_buffer_unmap (moov, &map);
4195 gst_buffer_unref (moov);
4197 gst_buffer_map (moov, &map, GST_MAP_READ);
4202 if (length != map.size) {
4203 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4204 (_("This file is incomplete and cannot be played.")),
4205 ("We got less than expected (received %" G_GSIZE_FORMAT
4206 ", wanted %u, offset %" G_GUINT64_FORMAT ")", map.size,
4207 (guint) length, cur_offset));
4208 gst_buffer_unmap (moov, &map);
4209 gst_buffer_unref (moov);
4210 ret = GST_FLOW_ERROR;
4213 qtdemux->offset += length;
4215 qtdemux_parse_moov (qtdemux, map.data, length);
4216 qtdemux_node_dump (qtdemux, qtdemux->moov_node);
4218 qtdemux_parse_tree (qtdemux);
4219 g_node_destroy (qtdemux->moov_node);
4220 gst_buffer_unmap (moov, &map);
4221 gst_buffer_unref (moov);
4222 qtdemux->moov_node = NULL;
4223 qtdemux->got_moov = TRUE;
4229 GstBuffer *ftyp = NULL;
4231 /* extract major brand; might come in handy for ISO vs QT issues */
4232 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &ftyp);
4233 if (ret != GST_FLOW_OK)
4235 qtdemux->offset += length;
4236 gst_buffer_map (ftyp, &map, GST_MAP_READ);
4237 qtdemux_parse_ftyp (qtdemux, map.data, map.size);
4238 gst_buffer_unmap (ftyp, &map);
4239 gst_buffer_unref (ftyp);
4244 GstBuffer *uuid = NULL;
4246 /* uuid are extension atoms */
4247 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &uuid);
4248 if (ret != GST_FLOW_OK)
4250 qtdemux->offset += length;
4251 gst_buffer_map (uuid, &map, GST_MAP_READ);
4252 qtdemux_parse_uuid (qtdemux, map.data, map.size);
4253 gst_buffer_unmap (uuid, &map);
4254 gst_buffer_unref (uuid);
4259 GstBuffer *sidx = NULL;
4260 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &sidx);
4261 if (ret != GST_FLOW_OK)
4263 qtdemux->offset += length;
4264 gst_buffer_map (sidx, &map, GST_MAP_READ);
4265 qtdemux_parse_sidx (qtdemux, map.data, map.size);
4266 gst_buffer_unmap (sidx, &map);
4267 gst_buffer_unref (sidx);
4272 GstBuffer *unknown = NULL;
4274 GST_LOG_OBJECT (qtdemux,
4275 "unknown %08x '%" GST_FOURCC_FORMAT "' of size %" G_GUINT64_FORMAT
4276 " at %" G_GUINT64_FORMAT, fourcc, GST_FOURCC_ARGS (fourcc), length,
4278 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &unknown);
4279 if (ret != GST_FLOW_OK)
4281 gst_buffer_map (unknown, &map, GST_MAP_READ);
4282 GST_MEMDUMP ("Unknown tag", map.data, map.size);
4283 gst_buffer_unmap (unknown, &map);
4284 gst_buffer_unref (unknown);
4285 qtdemux->offset += length;
4291 if (ret == GST_FLOW_EOS && (qtdemux->got_moov || qtdemux->media_caps)) {
4292 /* digested all data, show what we have */
4293 qtdemux_prepare_streams (qtdemux);
4294 ret = qtdemux_expose_streams (qtdemux);
4296 qtdemux->state = QTDEMUX_STATE_MOVIE;
4297 GST_DEBUG_OBJECT (qtdemux, "switching state to STATE_MOVIE (%d)",
4304 /* Seeks to the previous keyframe of the indexed stream and
4305 * aligns other streams with respect to the keyframe timestamp
4306 * of indexed stream. Only called in case of Reverse Playback
4308 static GstFlowReturn
4309 gst_qtdemux_seek_to_previous_keyframe (GstQTDemux * qtdemux)
4312 guint32 seg_idx = 0, k_index = 0;
4313 guint32 ref_seg_idx, ref_k_index;
4314 GstClockTime k_pos = 0, last_stop = 0;
4315 QtDemuxSegment *seg = NULL;
4316 QtDemuxStream *ref_str = NULL;
4317 guint64 seg_media_start_mov; /* segment media start time in mov format */
4320 /* Now we choose an arbitrary stream, get the previous keyframe timestamp
4321 * and finally align all the other streams on that timestamp with their
4322 * respective keyframes */
4323 for (n = 0; n < qtdemux->n_streams; n++) {
4324 QtDemuxStream *str = qtdemux->streams[n];
4326 /* No candidate yet, take the first stream */
4332 /* So that stream has a segment, we prefer video streams */
4333 if (str->subtype == FOURCC_vide) {
4339 if (G_UNLIKELY (!ref_str)) {
4340 GST_DEBUG_OBJECT (qtdemux, "couldn't find any stream");
4344 if (G_UNLIKELY (!ref_str->from_sample)) {
4345 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of the file");
4349 /* So that stream has been playing from from_sample to to_sample. We will
4350 * get the timestamp of the previous sample and search for a keyframe before
4351 * that. For audio streams we do an arbitrary jump in the past (10 samples) */
4352 if (ref_str->subtype == FOURCC_vide) {
4353 k_index = gst_qtdemux_find_keyframe (qtdemux, ref_str,
4354 ref_str->from_sample - 1);
4356 if (ref_str->from_sample >= 10)
4357 k_index = ref_str->from_sample - 10;
4363 ref_str->samples[k_index].timestamp +
4364 ref_str->samples[k_index].pts_offset;
4366 /* get current segment for that stream */
4367 seg = &ref_str->segments[ref_str->segment_index];
4368 /* Use segment start in original timescale for comparisons */
4369 seg_media_start_mov = seg->trak_media_start;
4371 GST_LOG_OBJECT (qtdemux, "keyframe index %u ts %" G_GUINT64_FORMAT
4372 " seg start %" G_GUINT64_FORMAT " %" GST_TIME_FORMAT "\n",
4373 k_index, target_ts, seg_media_start_mov,
4374 GST_TIME_ARGS (seg->media_start));
4376 /* Crawl back through segments to find the one containing this I frame */
4377 while (target_ts < seg_media_start_mov) {
4378 GST_DEBUG_OBJECT (qtdemux,
4379 "keyframe position (sample %u) is out of segment %u " " target %"
4380 G_GUINT64_FORMAT " seg start %" G_GUINT64_FORMAT, k_index,
4381 ref_str->segment_index, target_ts, seg_media_start_mov);
4383 if (G_UNLIKELY (!ref_str->segment_index)) {
4384 /* Reached first segment, let's consider it's EOS */
4387 ref_str->segment_index--;
4388 seg = &ref_str->segments[ref_str->segment_index];
4389 /* Use segment start in original timescale for comparisons */
4390 seg_media_start_mov = seg->trak_media_start;
4392 /* Calculate time position of the keyframe and where we should stop */
4394 QTSTREAMTIME_TO_GSTTIME (ref_str,
4395 target_ts - seg->trak_media_start) + seg->time;
4397 QTSTREAMTIME_TO_GSTTIME (ref_str,
4398 ref_str->samples[ref_str->from_sample].timestamp -
4399 seg->trak_media_start) + seg->time;
4401 GST_DEBUG_OBJECT (qtdemux, "preferred stream played from sample %u, "
4402 "now going to sample %u (pts %" GST_TIME_FORMAT ")", ref_str->from_sample,
4403 k_index, GST_TIME_ARGS (k_pos));
4405 /* Set last_stop with the keyframe timestamp we pushed of that stream */
4406 qtdemux->segment.position = last_stop;
4407 GST_DEBUG_OBJECT (qtdemux, "last_stop now is %" GST_TIME_FORMAT,
4408 GST_TIME_ARGS (last_stop));
4410 if (G_UNLIKELY (last_stop < qtdemux->segment.start)) {
4411 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of segment");
4415 ref_seg_idx = ref_str->segment_index;
4416 ref_k_index = k_index;
4418 /* Align them all on this */
4419 for (n = 0; n < qtdemux->n_streams; n++) {
4421 GstClockTime seg_time = 0;
4422 QtDemuxStream *str = qtdemux->streams[n];
4424 /* aligning reference stream again might lead to backing up to yet another
4425 * keyframe (due to timestamp rounding issues),
4426 * potentially putting more load on downstream; so let's try to avoid */
4427 if (str == ref_str) {
4428 seg_idx = ref_seg_idx;
4429 seg = &str->segments[seg_idx];
4430 k_index = ref_k_index;
4431 GST_DEBUG_OBJECT (qtdemux, "reference stream %d segment %d, "
4432 "sample at index %d", n, ref_str->segment_index, k_index);
4434 seg_idx = gst_qtdemux_find_segment (qtdemux, str, k_pos);
4435 GST_DEBUG_OBJECT (qtdemux,
4436 "stream %d align segment %d for keyframe pos %" GST_TIME_FORMAT, n,
4437 seg_idx, GST_TIME_ARGS (k_pos));
4439 /* get segment and time in the segment */
4440 seg = &str->segments[seg_idx];
4441 seg_time = k_pos - seg->time;
4443 /* get the media time in the segment.
4444 * No adjustment for empty "filler" segments */
4445 if (seg->media_start != GST_CLOCK_TIME_NONE)
4446 seg_time += seg->media_start;
4448 /* get the index of the sample with media time */
4449 index = gst_qtdemux_find_index_linear (qtdemux, str, seg_time);
4450 GST_DEBUG_OBJECT (qtdemux,
4451 "stream %d sample for %" GST_TIME_FORMAT " at %u", n,
4452 GST_TIME_ARGS (seg_time), index);
4454 /* find previous keyframe */
4455 k_index = gst_qtdemux_find_keyframe (qtdemux, str, index);
4458 /* Remember until where we want to go */
4459 str->to_sample = str->from_sample - 1;
4460 /* Define our time position */
4462 str->samples[k_index].timestamp + str->samples[k_index].pts_offset;
4463 str->time_position = QTSTREAMTIME_TO_GSTTIME (str, target_ts) + seg->time;
4464 if (seg->media_start != GST_CLOCK_TIME_NONE)
4465 str->time_position -= seg->media_start;
4467 /* Now seek back in time */
4468 gst_qtdemux_move_stream (qtdemux, str, k_index);
4469 GST_DEBUG_OBJECT (qtdemux, "stream %d keyframe at %u, time position %"
4470 GST_TIME_FORMAT " playing from sample %u to %u", n, k_index,
4471 GST_TIME_ARGS (str->time_position), str->from_sample, str->to_sample);
4477 return GST_FLOW_EOS;
4481 * Gets the current qt segment start, stop and position for the
4482 * given time offset. This is used in update_segment()
4485 gst_qtdemux_stream_segment_get_boundaries (GstQTDemux * qtdemux,
4486 QtDemuxStream * stream, GstClockTime offset,
4487 GstClockTime * _start, GstClockTime * _stop, GstClockTime * _time)
4489 GstClockTime seg_time;
4490 GstClockTime start, stop, time;
4491 QtDemuxSegment *segment;
4493 segment = &stream->segments[stream->segment_index];
4495 /* get time in this segment */
4496 seg_time = (offset - segment->time) * segment->rate;
4498 GST_LOG_OBJECT (stream->pad, "seg_time %" GST_TIME_FORMAT,
4499 GST_TIME_ARGS (seg_time));
4501 if (G_UNLIKELY (seg_time > segment->duration)) {
4502 GST_LOG_OBJECT (stream->pad,
4503 "seg_time > segment->duration %" GST_TIME_FORMAT,
4504 GST_TIME_ARGS (segment->duration));
4505 seg_time = segment->duration;
4508 /* qtdemux->segment.stop is in outside-time-realm, whereas
4509 * segment->media_stop is in track-time-realm.
4511 * In order to compare the two, we need to bring segment.stop
4512 * into the track-time-realm
4514 * FIXME - does this comment still hold? Don't see any conversion here */
4516 stop = qtdemux->segment.stop;
4517 if (stop == GST_CLOCK_TIME_NONE)
4518 stop = qtdemux->segment.duration;
4519 if (stop == GST_CLOCK_TIME_NONE)
4520 stop = segment->media_stop;
4523 MIN (segment->media_stop, stop - segment->time + segment->media_start);
4525 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
4526 start = segment->time + seg_time;
4528 stop = start - seg_time + segment->duration;
4529 } else if (qtdemux->segment.rate >= 0) {
4530 start = MIN (segment->media_start + seg_time, stop);
4533 if (segment->media_start >= qtdemux->segment.start) {
4534 time = segment->time;
4536 time = segment->time + (qtdemux->segment.start - segment->media_start);
4539 start = MAX (segment->media_start, qtdemux->segment.start);
4540 stop = MIN (segment->media_start + seg_time, stop);
4549 * Updates the qt segment used for the stream and pushes a new segment event
4550 * downstream on this stream's pad.
4553 gst_qtdemux_stream_update_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
4554 gint seg_idx, GstClockTime offset, GstClockTime * _start,
4555 GstClockTime * _stop)
4557 QtDemuxSegment *segment;
4558 GstClockTime start = 0, stop = GST_CLOCK_TIME_NONE, time = 0;
4562 /* update the current segment */
4563 stream->segment_index = seg_idx;
4565 /* get the segment */
4566 segment = &stream->segments[seg_idx];
4568 if (G_UNLIKELY (offset < segment->time)) {
4569 GST_WARNING_OBJECT (stream->pad, "offset < segment->time %" GST_TIME_FORMAT,
4570 GST_TIME_ARGS (segment->time));
4574 /* segment lies beyond total indicated duration */
4575 if (G_UNLIKELY (qtdemux->segment.duration != GST_CLOCK_TIME_NONE &&
4576 segment->time > qtdemux->segment.duration)) {
4577 GST_WARNING_OBJECT (stream->pad, "file duration %" GST_TIME_FORMAT
4578 " < segment->time %" GST_TIME_FORMAT,
4579 GST_TIME_ARGS (qtdemux->segment.duration),
4580 GST_TIME_ARGS (segment->time));
4584 gst_qtdemux_stream_segment_get_boundaries (qtdemux, stream, offset,
4585 &start, &stop, &time);
4587 GST_DEBUG_OBJECT (stream->pad, "new segment %d from %" GST_TIME_FORMAT
4588 " to %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT, seg_idx,
4589 GST_TIME_ARGS (start), GST_TIME_ARGS (stop), GST_TIME_ARGS (time));
4591 /* combine global rate with that of the segment */
4592 rate = segment->rate * qtdemux->segment.rate;
4594 /* Copy flags from main segment */
4595 stream->segment.flags = qtdemux->segment.flags;
4597 /* update the segment values used for clipping */
4598 stream->segment.offset = qtdemux->segment.offset;
4599 stream->segment.base = qtdemux->segment.base + stream->accumulated_base;
4600 stream->segment.applied_rate = qtdemux->segment.applied_rate;
4601 stream->segment.rate = rate;
4602 stream->segment.start = start + QTSTREAMTIME_TO_GSTTIME (stream,
4603 stream->cslg_shift);
4604 stream->segment.stop = stop + QTSTREAMTIME_TO_GSTTIME (stream,
4605 stream->cslg_shift);
4606 stream->segment.time = time;
4607 stream->segment.position = stream->segment.start;
4609 GST_DEBUG_OBJECT (stream->pad, "New segment: %" GST_SEGMENT_FORMAT,
4612 /* now prepare and send the segment */
4614 event = gst_event_new_segment (&stream->segment);
4615 if (qtdemux->segment_seqnum) {
4616 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
4618 gst_pad_push_event (stream->pad, event);
4619 /* assume we can send more data now */
4620 GST_PAD_LAST_FLOW_RETURN (stream->pad) = GST_FLOW_OK;
4621 /* clear to send tags on this pad now */
4622 gst_qtdemux_push_tags (qtdemux, stream);
4633 /* activate the given segment number @seg_idx of @stream at time @offset.
4634 * @offset is an absolute global position over all the segments.
4636 * This will push out a NEWSEGMENT event with the right values and
4637 * position the stream index to the first decodable sample before
4641 gst_qtdemux_activate_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
4642 guint32 seg_idx, GstClockTime offset)
4644 QtDemuxSegment *segment;
4645 guint32 index, kf_index;
4646 GstClockTime start = 0, stop = GST_CLOCK_TIME_NONE;
4648 GST_LOG_OBJECT (stream->pad, "activate segment %d, offset %" GST_TIME_FORMAT,
4649 seg_idx, GST_TIME_ARGS (offset));
4651 if (!gst_qtdemux_stream_update_segment (qtdemux, stream, seg_idx, offset,
4655 segment = &stream->segments[stream->segment_index];
4657 /* in the fragmented case, we pick a fragment that starts before our
4658 * desired position and rely on downstream to wait for a keyframe
4659 * (FIXME: doesn't seem to work so well with ismv and wmv, as no parser; the
4660 * tfra entries tells us which trun/sample the key unit is in, but we don't
4661 * make use of this additional information at the moment) */
4662 if (qtdemux->fragmented) {
4663 stream->to_sample = G_MAXUINT32;
4667 /* We don't need to look for a sample in push-based */
4668 if (!qtdemux->pullbased)
4671 /* and move to the keyframe before the indicated media time of the
4673 if (G_LIKELY (!QTSEGMENT_IS_EMPTY (segment))) {
4674 if (qtdemux->segment.rate >= 0) {
4675 index = gst_qtdemux_find_index_linear (qtdemux, stream, start);
4676 stream->to_sample = G_MAXUINT32;
4677 GST_DEBUG_OBJECT (stream->pad,
4678 "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
4679 GST_TIME_FORMAT, GST_TIME_ARGS (start), index,
4680 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
4682 index = gst_qtdemux_find_index_linear (qtdemux, stream, stop);
4683 stream->to_sample = index;
4684 GST_DEBUG_OBJECT (stream->pad,
4685 "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
4686 GST_TIME_FORMAT, GST_TIME_ARGS (stop), index,
4687 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
4690 GST_DEBUG_OBJECT (stream->pad, "No need to look for keyframe, "
4691 "this is an empty segment");
4695 /* gst_qtdemux_parse_sample () called from gst_qtdemux_find_index_linear ()
4696 * encountered an error and printed a message so we return appropriately */
4700 /* we're at the right spot */
4701 if (index == stream->sample_index) {
4702 GST_DEBUG_OBJECT (stream->pad, "we are at the right index");
4706 /* find keyframe of the target index */
4707 kf_index = gst_qtdemux_find_keyframe (qtdemux, stream, index);
4710 /* indent does stupid stuff with stream->samples[].timestamp */
4712 /* if we move forwards, we don't have to go back to the previous
4713 * keyframe since we already sent that. We can also just jump to
4714 * the keyframe right before the target index if there is one. */
4715 if (index > stream->sample_index) {
4716 /* moving forwards check if we move past a keyframe */
4717 if (kf_index > stream->sample_index) {
4718 GST_DEBUG_OBJECT (stream->pad,
4719 "moving forwards to keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" )", kf_index,
4720 GST_TIME_ARGS (QTSAMPLE_PTS(stream, &stream->samples[kf_index])),
4721 GST_TIME_ARGS (QTSAMPLE_DTS(stream, &stream->samples[kf_index])));
4722 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
4724 GST_DEBUG_OBJECT (stream->pad,
4725 "moving forwards, keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" ) already sent", kf_index,
4726 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[kf_index])),
4727 GST_TIME_ARGS (QTSAMPLE_DTS (stream, &stream->samples[kf_index])));
4730 GST_DEBUG_OBJECT (stream->pad,
4731 "moving backwards to keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" )", kf_index,
4732 GST_TIME_ARGS (QTSAMPLE_PTS(stream, &stream->samples[kf_index])),
4733 GST_TIME_ARGS (QTSAMPLE_DTS(stream, &stream->samples[kf_index])));
4734 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
4742 /* prepare to get the current sample of @stream, getting essential values.
4744 * This function will also prepare and send the segment when needed.
4746 * Return FALSE if the stream is EOS.
4751 gst_qtdemux_prepare_current_sample (GstQTDemux * qtdemux,
4752 QtDemuxStream * stream, gboolean * empty, guint64 * offset, guint * size,
4753 GstClockTime * dts, GstClockTime * pts, GstClockTime * duration,
4754 gboolean * keyframe)
4756 QtDemuxSample *sample;
4757 GstClockTime time_position;
4760 g_return_val_if_fail (stream != NULL, FALSE);
4762 time_position = stream->time_position;
4763 if (G_UNLIKELY (time_position == GST_CLOCK_TIME_NONE))
4766 seg_idx = stream->segment_index;
4767 if (G_UNLIKELY (seg_idx == -1)) {
4768 /* find segment corresponding to time_position if we are looking
4770 seg_idx = gst_qtdemux_find_segment (qtdemux, stream, time_position);
4773 /* different segment, activate it, sample_index will be set. */
4774 if (G_UNLIKELY (stream->segment_index != seg_idx))
4775 gst_qtdemux_activate_segment (qtdemux, stream, seg_idx, time_position);
4777 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (&stream->segments[stream->
4779 QtDemuxSegment *seg = &stream->segments[stream->segment_index];
4781 GST_LOG_OBJECT (qtdemux, "Empty segment activated,"
4782 " prepare empty sample");
4785 *pts = *dts = time_position;
4786 *duration = seg->duration - (time_position - seg->time);
4793 if (stream->sample_index == -1)
4794 stream->sample_index = 0;
4796 GST_LOG_OBJECT (qtdemux, "segment active, index = %u of %u",
4797 stream->sample_index, stream->n_samples);
4799 if (G_UNLIKELY (stream->sample_index >= stream->n_samples)) {
4800 if (!qtdemux->fragmented)
4803 GST_INFO_OBJECT (qtdemux, "out of samples, trying to add more");
4807 GST_OBJECT_LOCK (qtdemux);
4808 flow = qtdemux_add_fragmented_samples (qtdemux);
4809 GST_OBJECT_UNLOCK (qtdemux);
4811 if (flow != GST_FLOW_OK)
4814 while (stream->sample_index >= stream->n_samples);
4817 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
4818 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
4819 stream->sample_index);
4823 /* now get the info for the sample we're at */
4824 sample = &stream->samples[stream->sample_index];
4826 *dts = QTSAMPLE_DTS (stream, sample);
4827 *pts = QTSAMPLE_PTS (stream, sample);
4828 *offset = sample->offset;
4829 *size = sample->size;
4830 *duration = QTSAMPLE_DUR_DTS (stream, sample, *dts);
4831 *keyframe = QTSAMPLE_KEYFRAME (stream, sample);
4838 stream->time_position = GST_CLOCK_TIME_NONE;
4843 /* move to the next sample in @stream.
4845 * Moves to the next segment when needed.
4848 gst_qtdemux_advance_sample (GstQTDemux * qtdemux, QtDemuxStream * stream)
4850 QtDemuxSample *sample;
4851 QtDemuxSegment *segment;
4853 /* get current segment */
4854 segment = &stream->segments[stream->segment_index];
4856 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
4857 GST_DEBUG_OBJECT (qtdemux, "Empty segment, no samples to advance");
4861 if (G_UNLIKELY (stream->sample_index >= stream->to_sample)) {
4862 /* Mark the stream as EOS */
4863 GST_DEBUG_OBJECT (qtdemux,
4864 "reached max allowed sample %u, mark EOS", stream->to_sample);
4865 stream->time_position = GST_CLOCK_TIME_NONE;
4869 /* move to next sample */
4870 stream->sample_index++;
4871 stream->offset_in_sample = 0;
4873 /* reached the last sample, we need the next segment */
4874 if (G_UNLIKELY (stream->sample_index >= stream->n_samples))
4877 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
4878 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
4879 stream->sample_index);
4883 /* get next sample */
4884 sample = &stream->samples[stream->sample_index];
4886 /* see if we are past the segment */
4887 if (G_UNLIKELY (QTSAMPLE_DTS (stream, sample) >= segment->media_stop))
4890 if (QTSAMPLE_DTS (stream, sample) >= segment->media_start) {
4891 /* inside the segment, update time_position, looks very familiar to
4892 * GStreamer segments, doesn't it? */
4893 stream->time_position =
4894 QTSAMPLE_DTS (stream, sample) - segment->media_start + segment->time;
4896 /* not yet in segment, time does not yet increment. This means
4897 * that we are still prerolling keyframes to the decoder so it can
4898 * decode the first sample of the segment. */
4899 stream->time_position = segment->time;
4903 /* move to the next segment */
4906 GST_DEBUG_OBJECT (qtdemux, "segment %d ended ", stream->segment_index);
4908 if (stream->segment_index == stream->n_segments - 1) {
4909 /* are we at the end of the last segment, we're EOS */
4910 stream->time_position = GST_CLOCK_TIME_NONE;
4912 /* else we're only at the end of the current segment */
4913 stream->time_position = segment->stop_time;
4915 /* make sure we select a new segment */
4917 /* accumulate previous segments */
4918 if (GST_CLOCK_TIME_IS_VALID (stream->segment.stop))
4919 stream->accumulated_base +=
4920 (stream->segment.stop -
4921 stream->segment.start) / ABS (stream->segment.rate);
4923 stream->segment_index = -1;
4928 gst_qtdemux_sync_streams (GstQTDemux * demux)
4932 if (demux->n_streams <= 1)
4935 for (i = 0; i < demux->n_streams; i++) {
4936 QtDemuxStream *stream;
4937 GstClockTime end_time;
4939 stream = demux->streams[i];
4944 /* TODO advance time on subtitle streams here, if any some day */
4946 /* some clips/trailers may have unbalanced streams at the end,
4947 * so send EOS on shorter stream to prevent stalling others */
4949 /* do not mess with EOS if SEGMENT seeking */
4950 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT)
4953 if (demux->pullbased) {
4954 /* loop mode is sample time based */
4955 if (!STREAM_IS_EOS (stream))
4958 /* push mode is byte position based */
4959 if (stream->n_samples &&
4960 stream->samples[stream->n_samples - 1].offset >= demux->offset)
4964 if (stream->sent_eos)
4967 /* only act if some gap */
4968 end_time = stream->segments[stream->n_segments - 1].stop_time;
4969 GST_LOG_OBJECT (demux, "current position: %" GST_TIME_FORMAT
4970 ", stream end: %" GST_TIME_FORMAT,
4971 GST_TIME_ARGS (demux->segment.position), GST_TIME_ARGS (end_time));
4972 if (GST_CLOCK_TIME_IS_VALID (end_time)
4973 && (end_time + 2 * GST_SECOND < demux->segment.position)) {
4976 GST_DEBUG_OBJECT (demux, "sending EOS for stream %s",
4977 GST_PAD_NAME (stream->pad));
4978 stream->sent_eos = TRUE;
4979 event = gst_event_new_eos ();
4980 if (demux->segment_seqnum)
4981 gst_event_set_seqnum (event, demux->segment_seqnum);
4982 gst_pad_push_event (stream->pad, event);
4987 /* EOS and NOT_LINKED need to be combined. This means that we return:
4989 * GST_FLOW_NOT_LINKED: when all pads NOT_LINKED.
4990 * GST_FLOW_EOS: when all pads EOS or NOT_LINKED.
4992 static GstFlowReturn
4993 gst_qtdemux_combine_flows (GstQTDemux * demux, QtDemuxStream * stream,
4996 GST_LOG_OBJECT (demux, "flow return: %s", gst_flow_get_name (ret));
4999 ret = gst_flow_combiner_update_pad_flow (demux->flowcombiner, stream->pad,
5002 ret = gst_flow_combiner_update_flow (demux->flowcombiner, ret);
5004 GST_LOG_OBJECT (demux, "combined flow return: %s", gst_flow_get_name (ret));
5008 /* the input buffer metadata must be writable. Returns NULL when the buffer is
5009 * completely clipped
5011 * Should be used only with raw buffers */
5013 gst_qtdemux_clip_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
5016 guint64 start, stop, cstart, cstop, diff;
5017 GstClockTime pts, duration;
5019 gint num_rate, denom_rate;
5024 osize = size = gst_buffer_get_size (buf);
5027 /* depending on the type, setup the clip parameters */
5028 if (stream->subtype == FOURCC_soun) {
5029 frame_size = stream->bytes_per_frame;
5030 num_rate = GST_SECOND;
5031 denom_rate = (gint) stream->rate;
5033 } else if (stream->subtype == FOURCC_vide) {
5035 num_rate = stream->fps_n;
5036 denom_rate = stream->fps_d;
5041 if (frame_size <= 0)
5042 goto bad_frame_size;
5044 /* we can only clip if we have a valid pts */
5045 pts = GST_BUFFER_PTS (buf);
5046 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (pts)))
5049 duration = GST_BUFFER_DURATION (buf);
5051 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (duration))) {
5053 gst_util_uint64_scale_int (size / frame_size, num_rate, denom_rate);
5057 stop = start + duration;
5059 if (G_UNLIKELY (!gst_segment_clip (&stream->segment,
5060 GST_FORMAT_TIME, start, stop, &cstart, &cstop)))
5063 /* see if some clipping happened */
5064 diff = cstart - start;
5070 /* bring clipped time to samples and to bytes */
5071 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
5074 GST_DEBUG_OBJECT (qtdemux,
5075 "clipping start to %" GST_TIME_FORMAT " %"
5076 G_GUINT64_FORMAT " bytes", GST_TIME_ARGS (cstart), diff);
5082 diff = stop - cstop;
5087 /* bring clipped time to samples and then to bytes */
5088 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
5090 GST_DEBUG_OBJECT (qtdemux,
5091 "clipping stop to %" GST_TIME_FORMAT " %" G_GUINT64_FORMAT
5092 " bytes", GST_TIME_ARGS (cstop), diff);
5097 if (offset != 0 || size != osize)
5098 gst_buffer_resize (buf, offset, size);
5100 GST_BUFFER_DTS (buf) = GST_CLOCK_TIME_NONE;
5101 GST_BUFFER_PTS (buf) = pts;
5102 GST_BUFFER_DURATION (buf) = duration;
5106 /* dropped buffer */
5109 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
5114 GST_DEBUG_OBJECT (qtdemux, "bad frame size");
5119 GST_DEBUG_OBJECT (qtdemux, "no pts on buffer");
5124 GST_DEBUG_OBJECT (qtdemux, "clipped buffer");
5125 gst_buffer_unref (buf);
5130 /* the input buffer metadata must be writable,
5131 * but time/duration etc not yet set and need not be preserved */
5133 gst_qtdemux_process_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
5140 /* not many cases for now */
5141 if (G_UNLIKELY (stream->fourcc == FOURCC_mp4s)) {
5142 /* send a one time dvd clut event */
5143 if (stream->pending_event && stream->pad)
5144 gst_pad_push_event (stream->pad, stream->pending_event);
5145 stream->pending_event = NULL;
5148 if (G_UNLIKELY (stream->subtype != FOURCC_text
5149 && stream->subtype != FOURCC_sbtl &&
5150 stream->subtype != FOURCC_subp)) {
5154 gst_buffer_map (buf, &map, GST_MAP_READ);
5156 /* empty buffer is sent to terminate previous subtitle */
5157 if (map.size <= 2) {
5158 gst_buffer_unmap (buf, &map);
5159 gst_buffer_unref (buf);
5162 if (stream->subtype == FOURCC_subp) {
5163 /* That's all the processing needed for subpictures */
5164 gst_buffer_unmap (buf, &map);
5168 nsize = GST_READ_UINT16_BE (map.data);
5169 nsize = MIN (nsize, map.size - 2);
5171 GST_LOG_OBJECT (qtdemux, "3GPP timed text subtitle: %d/%" G_GSIZE_FORMAT "",
5174 /* takes care of UTF-8 validation or UTF-16 recognition,
5175 * no other encoding expected */
5176 str = gst_tag_freeform_string_to_utf8 ((gchar *) map.data + 2, nsize, NULL);
5177 gst_buffer_unmap (buf, &map);
5179 gst_buffer_unref (buf);
5180 buf = _gst_buffer_new_wrapped (str, strlen (str), g_free);
5182 /* this should not really happen unless the subtitle is corrupted */
5183 gst_buffer_unref (buf);
5187 /* FIXME ? convert optional subsequent style info to markup */
5192 /* Sets a buffer's attributes properly and pushes it downstream.
5193 * Also checks for additional actions and custom processing that may
5194 * need to be done first.
5196 static GstFlowReturn
5197 gst_qtdemux_decorate_and_push_buffer (GstQTDemux * qtdemux,
5198 QtDemuxStream * stream, GstBuffer * buf,
5199 GstClockTime dts, GstClockTime pts, GstClockTime duration,
5200 gboolean keyframe, GstClockTime position, guint64 byte_position)
5202 GstFlowReturn ret = GST_FLOW_OK;
5204 /* offset the timestamps according to the edit list */
5206 if (G_UNLIKELY (stream->fourcc == FOURCC_rtsp)) {
5210 gst_buffer_map (buf, &map, GST_MAP_READ);
5211 url = g_strndup ((gchar *) map.data, map.size);
5212 gst_buffer_unmap (buf, &map);
5213 if (url != NULL && strlen (url) != 0) {
5214 /* we have RTSP redirect now */
5215 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
5216 gst_message_new_element (GST_OBJECT_CAST (qtdemux),
5217 gst_structure_new ("redirect",
5218 "new-location", G_TYPE_STRING, url, NULL)));
5219 qtdemux->posted_redirect = TRUE;
5221 GST_WARNING_OBJECT (qtdemux, "Redirect URI of stream is empty, not "
5227 /* position reporting */
5228 if (qtdemux->segment.rate >= 0) {
5229 qtdemux->segment.position = position;
5230 gst_qtdemux_sync_streams (qtdemux);
5233 if (G_UNLIKELY (!stream->pad)) {
5234 GST_DEBUG_OBJECT (qtdemux, "No output pad for stream, ignoring");
5235 gst_buffer_unref (buf);
5239 /* send out pending buffers */
5240 while (stream->buffers) {
5241 GstBuffer *buffer = (GstBuffer *) stream->buffers->data;
5243 if (G_UNLIKELY (stream->discont)) {
5244 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
5245 GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
5246 stream->discont = FALSE;
5248 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
5251 gst_pad_push (stream->pad, buffer);
5253 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
5256 /* we're going to modify the metadata */
5257 buf = gst_buffer_make_writable (buf);
5259 if (G_UNLIKELY (stream->need_process))
5260 buf = gst_qtdemux_process_buffer (qtdemux, stream, buf);
5266 GST_BUFFER_DTS (buf) = dts;
5267 GST_BUFFER_PTS (buf) = pts;
5268 GST_BUFFER_DURATION (buf) = duration;
5269 GST_BUFFER_OFFSET (buf) = -1;
5270 GST_BUFFER_OFFSET_END (buf) = -1;
5272 if (G_UNLIKELY (stream->rgb8_palette))
5273 gst_buffer_append_memory (buf, gst_memory_ref (stream->rgb8_palette));
5275 if (G_UNLIKELY (stream->padding)) {
5276 gst_buffer_resize (buf, stream->padding, -1);
5279 if (G_UNLIKELY (qtdemux->element_index)) {
5280 GstClockTime stream_time;
5283 gst_segment_to_stream_time (&stream->segment, GST_FORMAT_TIME,
5285 if (GST_CLOCK_TIME_IS_VALID (stream_time)) {
5286 GST_LOG_OBJECT (qtdemux,
5287 "adding association %" GST_TIME_FORMAT "-> %"
5288 G_GUINT64_FORMAT, GST_TIME_ARGS (stream_time), byte_position);
5289 gst_index_add_association (qtdemux->element_index,
5291 keyframe ? GST_ASSOCIATION_FLAG_KEY_UNIT :
5292 GST_ASSOCIATION_FLAG_DELTA_UNIT, GST_FORMAT_TIME, stream_time,
5293 GST_FORMAT_BYTES, byte_position, NULL);
5298 if (stream->need_clip)
5299 buf = gst_qtdemux_clip_buffer (qtdemux, stream, buf);
5301 if (G_UNLIKELY (buf == NULL))
5304 if (G_UNLIKELY (stream->discont)) {
5305 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
5306 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
5307 stream->discont = FALSE;
5309 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
5313 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
5314 stream->on_keyframe = FALSE;
5316 stream->on_keyframe = TRUE;
5320 GST_LOG_OBJECT (qtdemux,
5321 "Pushing buffer with dts %" GST_TIME_FORMAT ", pts %" GST_TIME_FORMAT
5322 ", duration %" GST_TIME_FORMAT " on pad %s", GST_TIME_ARGS (dts),
5323 GST_TIME_ARGS (pts), GST_TIME_ARGS (duration),
5324 GST_PAD_NAME (stream->pad));
5326 if (stream->protected && stream->protection_scheme_type == FOURCC_cenc) {
5327 GstStructure *crypto_info;
5328 QtDemuxCencSampleSetInfo *info =
5329 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
5333 while ((event = g_queue_pop_head (&stream->protection_scheme_event_queue))) {
5334 gst_pad_push_event (stream->pad, event);
5337 if (info->crypto_info == NULL) {
5338 GST_DEBUG_OBJECT (qtdemux, "cenc metadata hasn't been parsed yet");
5339 gst_buffer_unref (buf);
5343 index = stream->sample_index - (stream->n_samples - info->crypto_info->len);
5344 if (G_LIKELY (index >= 0 && index < info->crypto_info->len)) {
5345 /* steal structure from array */
5346 crypto_info = g_ptr_array_index (info->crypto_info, index);
5347 g_ptr_array_index (info->crypto_info, index) = NULL;
5348 GST_LOG_OBJECT (qtdemux, "attaching cenc metadata [%u]", index);
5349 if (!crypto_info || !gst_buffer_add_protection_meta (buf, crypto_info))
5350 GST_ERROR_OBJECT (qtdemux, "failed to attach cenc metadata to buffer");
5354 ret = gst_pad_push (stream->pad, buf);
5356 if (GST_CLOCK_TIME_IS_VALID (pts) && GST_CLOCK_TIME_IS_VALID (duration)) {
5357 /* mark position in stream, we'll need this to know when to send GAP event */
5358 stream->segment.position = pts + duration;
5365 static const QtDemuxRandomAccessEntry *
5366 gst_qtdemux_stream_seek_fragment (GstQTDemux * qtdemux, QtDemuxStream * stream,
5367 GstClockTime pos, gboolean after)
5369 QtDemuxRandomAccessEntry *entries = stream->ra_entries;
5370 guint n_entries = stream->n_ra_entries;
5373 /* we assume the table is sorted */
5374 for (i = 0; i < n_entries; ++i) {
5375 if (entries[i].ts > pos)
5379 /* FIXME: maybe save first moof_offset somewhere instead, but for now it's
5380 * probably okay to assume that the index lists the very first fragment */
5387 return &entries[i - 1];
5391 gst_qtdemux_do_fragmented_seek (GstQTDemux * qtdemux)
5393 const QtDemuxRandomAccessEntry *best_entry = NULL;
5396 GST_OBJECT_LOCK (qtdemux);
5398 g_assert (qtdemux->n_streams > 0);
5400 for (i = 0; i < qtdemux->n_streams; i++) {
5401 const QtDemuxRandomAccessEntry *entry;
5402 QtDemuxStream *stream;
5403 gboolean is_audio_or_video;
5405 stream = qtdemux->streams[i];
5407 g_free (stream->samples);
5408 stream->samples = NULL;
5409 stream->n_samples = 0;
5410 stream->stbl_index = -1; /* no samples have yet been parsed */
5411 stream->sample_index = -1;
5413 if (stream->ra_entries == NULL)
5416 if (stream->subtype == FOURCC_vide || stream->subtype == FOURCC_soun)
5417 is_audio_or_video = TRUE;
5419 is_audio_or_video = FALSE;
5422 gst_qtdemux_stream_seek_fragment (qtdemux, stream,
5423 stream->time_position, !is_audio_or_video);
5425 GST_INFO_OBJECT (stream->pad, "%" GST_TIME_FORMAT " at offset "
5426 "%" G_GUINT64_FORMAT, GST_TIME_ARGS (entry->ts), entry->moof_offset);
5428 stream->pending_seek = entry;
5430 /* decide position to jump to just based on audio/video tracks, not subs */
5431 if (!is_audio_or_video)
5434 if (best_entry == NULL || entry->moof_offset < best_entry->moof_offset)
5438 if (best_entry == NULL) {
5439 GST_OBJECT_UNLOCK (qtdemux);
5443 GST_INFO_OBJECT (qtdemux, "seek to %" GST_TIME_FORMAT ", best fragment "
5444 "moof offset: %" G_GUINT64_FORMAT ", ts %" GST_TIME_FORMAT,
5445 GST_TIME_ARGS (qtdemux->streams[0]->time_position),
5446 best_entry->moof_offset, GST_TIME_ARGS (best_entry->ts));
5448 qtdemux->moof_offset = best_entry->moof_offset;
5450 qtdemux_add_fragmented_samples (qtdemux);
5452 GST_OBJECT_UNLOCK (qtdemux);
5456 static GstFlowReturn
5457 gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux)
5459 GstFlowReturn ret = GST_FLOW_OK;
5460 GstBuffer *buf = NULL;
5461 QtDemuxStream *stream;
5462 GstClockTime min_time;
5464 GstClockTime dts = GST_CLOCK_TIME_NONE;
5465 GstClockTime pts = GST_CLOCK_TIME_NONE;
5466 GstClockTime duration = 0;
5467 gboolean keyframe = FALSE;
5468 guint sample_size = 0;
5474 gst_qtdemux_push_pending_newsegment (qtdemux);
5476 if (qtdemux->fragmented_seek_pending) {
5477 GST_INFO_OBJECT (qtdemux, "pending fragmented seek");
5478 gst_qtdemux_do_fragmented_seek (qtdemux);
5479 GST_INFO_OBJECT (qtdemux, "fragmented seek done!");
5480 qtdemux->fragmented_seek_pending = FALSE;
5483 /* Figure out the next stream sample to output, min_time is expressed in
5484 * global time and runs over the edit list segments. */
5485 min_time = G_MAXUINT64;
5487 for (i = 0; i < qtdemux->n_streams; i++) {
5488 GstClockTime position;
5490 stream = qtdemux->streams[i];
5491 position = stream->time_position;
5493 /* position of -1 is EOS */
5494 if (position != GST_CLOCK_TIME_NONE && position < min_time) {
5495 min_time = position;
5500 if (G_UNLIKELY (index == -1)) {
5501 GST_DEBUG_OBJECT (qtdemux, "all streams are EOS");
5505 /* check for segment end */
5506 if (G_UNLIKELY (qtdemux->segment.stop != -1
5507 && ((qtdemux->segment.rate >= 0 && qtdemux->segment.stop <= min_time)
5508 || (qtdemux->segment.rate < 0
5509 && qtdemux->segment.start > min_time))
5510 && qtdemux->streams[index]->on_keyframe)) {
5511 GST_DEBUG_OBJECT (qtdemux, "we reached the end of our segment.");
5512 qtdemux->streams[index]->time_position = GST_CLOCK_TIME_NONE;
5516 /* gap events for subtitle streams */
5517 for (i = 0; i < qtdemux->n_streams; i++) {
5518 stream = qtdemux->streams[i];
5519 if (stream->pad && (stream->subtype == FOURCC_subp
5520 || stream->subtype == FOURCC_text
5521 || stream->subtype == FOURCC_sbtl)) {
5522 /* send one second gap events until the stream catches up */
5523 /* gaps can only be sent after segment is activated (segment.stop is no longer -1) */
5524 while (GST_CLOCK_TIME_IS_VALID (stream->segment.stop) &&
5525 GST_CLOCK_TIME_IS_VALID (stream->segment.position) &&
5526 stream->segment.position + GST_SECOND < min_time) {
5528 gst_event_new_gap (stream->segment.position, GST_SECOND);
5529 gst_pad_push_event (stream->pad, gap);
5530 stream->segment.position += GST_SECOND;
5535 stream = qtdemux->streams[index];
5536 if (stream->new_caps) {
5537 gst_qtdemux_configure_stream (qtdemux, stream);
5538 qtdemux_do_allocation (qtdemux, stream);
5541 /* fetch info for the current sample of this stream */
5542 if (G_UNLIKELY (!gst_qtdemux_prepare_current_sample (qtdemux, stream, &empty,
5543 &offset, &sample_size, &dts, &pts, &duration, &keyframe)))
5546 /* If we're doing a keyframe-only trickmode, only push keyframes on video streams */
5547 if (G_UNLIKELY (qtdemux->
5548 segment.flags & GST_SEGMENT_FLAG_TRICKMODE_KEY_UNITS)) {
5549 if (stream->subtype == FOURCC_vide && !keyframe) {
5550 GST_LOG_OBJECT (qtdemux, "Skipping non-keyframe on stream %d", index);
5555 GST_DEBUG_OBJECT (qtdemux,
5556 "pushing from stream %d, empty %d offset %" G_GUINT64_FORMAT
5557 ", size %d, dts=%" GST_TIME_FORMAT ", pts=%" GST_TIME_FORMAT
5558 ", duration %" GST_TIME_FORMAT, index, empty, offset, sample_size,
5559 GST_TIME_ARGS (dts), GST_TIME_ARGS (pts), GST_TIME_ARGS (duration));
5561 if (G_UNLIKELY (empty)) {
5562 /* empty segment, push a gap and move to the next one */
5563 gst_pad_push_event (stream->pad, gst_event_new_gap (pts, duration));
5564 stream->segment.position = pts + duration;
5568 /* hmm, empty sample, skip and move to next sample */
5569 if (G_UNLIKELY (sample_size <= 0))
5572 /* last pushed sample was out of boundary, goto next sample */
5573 if (G_UNLIKELY (GST_PAD_LAST_FLOW_RETURN (stream->pad) == GST_FLOW_EOS))
5576 if (stream->max_buffer_size == 0 || sample_size <= stream->max_buffer_size) {
5579 GST_DEBUG_OBJECT (qtdemux,
5580 "size %d larger than stream max_buffer_size %d, trimming",
5581 sample_size, stream->max_buffer_size);
5583 MIN (sample_size - stream->offset_in_sample, stream->max_buffer_size);
5586 if (qtdemux->cenc_aux_info_offset > 0) {
5589 GstBuffer *aux_info = NULL;
5591 /* pull the data stored before the sample */
5593 gst_qtdemux_pull_atom (qtdemux, qtdemux->offset,
5594 offset + stream->offset_in_sample - qtdemux->offset, &aux_info);
5595 if (G_UNLIKELY (ret != GST_FLOW_OK))
5597 gst_buffer_map (aux_info, &map, GST_MAP_READ);
5598 GST_DEBUG_OBJECT (qtdemux, "parsing cenc auxiliary info");
5599 gst_byte_reader_init (&br, map.data + 8, map.size);
5600 if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
5601 qtdemux->cenc_aux_info_sizes, qtdemux->cenc_aux_sample_count)) {
5602 GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
5603 gst_buffer_unmap (aux_info, &map);
5604 gst_buffer_unref (aux_info);
5605 ret = GST_FLOW_ERROR;
5608 gst_buffer_unmap (aux_info, &map);
5609 gst_buffer_unref (aux_info);
5612 GST_LOG_OBJECT (qtdemux, "reading %d bytes @ %" G_GUINT64_FORMAT, size,
5615 if (stream->use_allocator) {
5616 /* if we have a per-stream allocator, use it */
5617 buf = gst_buffer_new_allocate (stream->allocator, size, &stream->params);
5620 ret = gst_qtdemux_pull_atom (qtdemux, offset + stream->offset_in_sample,
5622 if (G_UNLIKELY (ret != GST_FLOW_OK))
5625 if (size != sample_size) {
5626 pts += gst_util_uint64_scale_int (GST_SECOND,
5627 stream->offset_in_sample / stream->bytes_per_frame, stream->timescale);
5628 dts += gst_util_uint64_scale_int (GST_SECOND,
5629 stream->offset_in_sample / stream->bytes_per_frame, stream->timescale);
5630 duration = gst_util_uint64_scale_int (GST_SECOND,
5631 size / stream->bytes_per_frame, stream->timescale);
5634 ret = gst_qtdemux_decorate_and_push_buffer (qtdemux, stream, buf,
5635 dts, pts, duration, keyframe, min_time, offset);
5637 if (size != sample_size) {
5638 QtDemuxSample *sample = &stream->samples[stream->sample_index];
5639 QtDemuxSegment *segment = &stream->segments[stream->segment_index];
5641 GstClockTime time_position = QTSTREAMTIME_TO_GSTTIME (stream,
5642 sample->timestamp + stream->offset_in_sample / stream->bytes_per_frame);
5643 if (time_position >= segment->media_start) {
5644 /* inside the segment, update time_position, looks very familiar to
5645 * GStreamer segments, doesn't it? */
5646 stream->time_position = (time_position - segment->media_start) +
5649 /* not yet in segment, time does not yet increment. This means
5650 * that we are still prerolling keyframes to the decoder so it can
5651 * decode the first sample of the segment. */
5652 stream->time_position = segment->time;
5657 ret = gst_qtdemux_combine_flows (qtdemux, stream, ret);
5658 /* ignore unlinked, we will not push on the pad anymore and we will EOS when
5659 * we have no more data for the pad to push */
5660 if (ret == GST_FLOW_EOS)
5663 stream->offset_in_sample += size;
5664 if (stream->offset_in_sample >= sample_size) {
5665 gst_qtdemux_advance_sample (qtdemux, stream);
5670 gst_qtdemux_advance_sample (qtdemux, stream);
5678 GST_DEBUG_OBJECT (qtdemux, "No samples left for any streams - EOS");
5684 GST_DEBUG_OBJECT (qtdemux, "No samples left for stream");
5685 /* EOS will be raised if all are EOS */
5692 gst_qtdemux_loop (GstPad * pad)
5694 GstQTDemux *qtdemux;
5698 qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
5700 cur_offset = qtdemux->offset;
5701 GST_LOG_OBJECT (qtdemux, "loop at position %" G_GUINT64_FORMAT ", state %s",
5702 cur_offset, qt_demux_state_string (qtdemux->state));
5704 switch (qtdemux->state) {
5705 case QTDEMUX_STATE_INITIAL:
5706 case QTDEMUX_STATE_HEADER:
5707 ret = gst_qtdemux_loop_state_header (qtdemux);
5709 case QTDEMUX_STATE_MOVIE:
5710 ret = gst_qtdemux_loop_state_movie (qtdemux);
5711 if (qtdemux->segment.rate < 0 && ret == GST_FLOW_EOS) {
5712 ret = gst_qtdemux_seek_to_previous_keyframe (qtdemux);
5720 /* if something went wrong, pause */
5721 if (ret != GST_FLOW_OK)
5725 gst_object_unref (qtdemux);
5731 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
5732 (NULL), ("streaming stopped, invalid state"));
5733 gst_pad_pause_task (pad);
5734 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
5739 const gchar *reason = gst_flow_get_name (ret);
5741 GST_LOG_OBJECT (qtdemux, "pausing task, reason %s", reason);
5743 gst_pad_pause_task (pad);
5745 /* fatal errors need special actions */
5747 if (ret == GST_FLOW_EOS) {
5748 if (qtdemux->n_streams == 0) {
5749 /* we have no streams, post an error */
5750 gst_qtdemux_post_no_playable_stream_error (qtdemux);
5752 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
5755 if ((stop = qtdemux->segment.stop) == -1)
5756 stop = qtdemux->segment.duration;
5758 if (qtdemux->segment.rate >= 0) {
5759 GstMessage *message;
5762 GST_LOG_OBJECT (qtdemux, "Sending segment done, at end of segment");
5763 message = gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
5764 GST_FORMAT_TIME, stop);
5765 event = gst_event_new_segment_done (GST_FORMAT_TIME, stop);
5766 if (qtdemux->segment_seqnum) {
5767 gst_message_set_seqnum (message, qtdemux->segment_seqnum);
5768 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
5770 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), message);
5771 gst_qtdemux_push_event (qtdemux, event);
5773 GstMessage *message;
5776 /* For Reverse Playback */
5777 GST_LOG_OBJECT (qtdemux, "Sending segment done, at start of segment");
5778 message = gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
5779 GST_FORMAT_TIME, qtdemux->segment.start);
5780 event = gst_event_new_segment_done (GST_FORMAT_TIME,
5781 qtdemux->segment.start);
5782 if (qtdemux->segment_seqnum) {
5783 gst_message_set_seqnum (message, qtdemux->segment_seqnum);
5784 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
5786 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), message);
5787 gst_qtdemux_push_event (qtdemux, event);
5792 GST_LOG_OBJECT (qtdemux, "Sending EOS at end of segment");
5793 event = gst_event_new_eos ();
5794 if (qtdemux->segment_seqnum)
5795 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
5796 gst_qtdemux_push_event (qtdemux, event);
5798 } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
5799 GST_ELEMENT_FLOW_ERROR (qtdemux, ret);
5800 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
5809 * Returns if there are samples to be played.
5812 has_next_entry (GstQTDemux * demux)
5814 QtDemuxStream *stream;
5817 GST_DEBUG_OBJECT (demux, "Checking if there are samples not played yet");
5819 for (i = 0; i < demux->n_streams; i++) {
5820 stream = demux->streams[i];
5822 if (stream->sample_index == -1) {
5823 stream->sample_index = 0;
5824 stream->offset_in_sample = 0;
5827 if (stream->sample_index >= stream->n_samples) {
5828 GST_LOG_OBJECT (demux, "stream %d samples exhausted", i);
5831 GST_DEBUG_OBJECT (demux, "Found a sample");
5835 GST_DEBUG_OBJECT (demux, "There wasn't any next sample");
5842 * Returns the size of the first entry at the current offset.
5843 * If -1, there are none (which means EOS or empty file).
5846 next_entry_size (GstQTDemux * demux)
5848 QtDemuxStream *stream;
5851 guint64 smalloffs = (guint64) - 1;
5852 QtDemuxSample *sample;
5854 GST_LOG_OBJECT (demux, "Finding entry at offset %" G_GUINT64_FORMAT,
5857 for (i = 0; i < demux->n_streams; i++) {
5858 stream = demux->streams[i];
5860 if (stream->sample_index == -1) {
5861 stream->sample_index = 0;
5862 stream->offset_in_sample = 0;
5865 if (stream->sample_index >= stream->n_samples) {
5866 GST_LOG_OBJECT (demux, "stream %d samples exhausted", i);
5870 if (!qtdemux_parse_samples (demux, stream, stream->sample_index)) {
5871 GST_LOG_OBJECT (demux, "Parsing of index %u from stbl atom failed!",
5872 stream->sample_index);
5876 sample = &stream->samples[stream->sample_index];
5878 GST_LOG_OBJECT (demux,
5879 "Checking Stream %d (sample_index:%d / offset:%" G_GUINT64_FORMAT
5880 " / size:%" G_GUINT32_FORMAT ")", i, stream->sample_index,
5881 sample->offset, sample->size);
5883 if (((smalloffs == -1)
5884 || (sample->offset < smalloffs)) && (sample->size)) {
5886 smalloffs = sample->offset;
5890 GST_LOG_OBJECT (demux,
5891 "stream %d offset %" G_GUINT64_FORMAT " demux->offset :%"
5892 G_GUINT64_FORMAT, smallidx, smalloffs, demux->offset);
5897 stream = demux->streams[smallidx];
5898 sample = &stream->samples[stream->sample_index];
5900 if (sample->offset >= demux->offset) {
5901 demux->todrop = sample->offset - demux->offset;
5902 return sample->size + demux->todrop;
5905 GST_DEBUG_OBJECT (demux,
5906 "There wasn't any entry at offset %" G_GUINT64_FORMAT, demux->offset);
5911 gst_qtdemux_post_progress (GstQTDemux * demux, gint num, gint denom)
5913 gint perc = (gint) ((gdouble) num * 100.0 / (gdouble) denom);
5915 gst_element_post_message (GST_ELEMENT_CAST (demux),
5916 gst_message_new_element (GST_OBJECT_CAST (demux),
5917 gst_structure_new ("progress", "percent", G_TYPE_INT, perc, NULL)));
5921 qtdemux_seek_offset (GstQTDemux * demux, guint64 offset)
5926 GST_DEBUG_OBJECT (demux, "Seeking to %" G_GUINT64_FORMAT, offset);
5929 gst_event_new_seek (1.0, GST_FORMAT_BYTES,
5930 GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset,
5931 GST_SEEK_TYPE_NONE, -1);
5933 /* store seqnum to drop flush events, they don't need to reach downstream */
5934 demux->offset_seek_seqnum = gst_event_get_seqnum (event);
5935 res = gst_pad_push_event (demux->sinkpad, event);
5936 demux->offset_seek_seqnum = 0;
5941 /* check for seekable upstream, above and beyond a mere query */
5943 gst_qtdemux_check_seekability (GstQTDemux * demux)
5946 gboolean seekable = FALSE;
5947 gint64 start = -1, stop = -1;
5949 if (demux->upstream_size)
5952 query = gst_query_new_seeking (GST_FORMAT_BYTES);
5953 if (!gst_pad_peer_query (demux->sinkpad, query)) {
5954 GST_DEBUG_OBJECT (demux, "seeking query failed");
5958 gst_query_parse_seeking (query, NULL, &seekable, &start, &stop);
5960 /* try harder to query upstream size if we didn't get it the first time */
5961 if (seekable && stop == -1) {
5962 GST_DEBUG_OBJECT (demux, "doing duration query to fix up unset stop");
5963 gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &stop);
5966 /* if upstream doesn't know the size, it's likely that it's not seekable in
5967 * practice even if it technically may be seekable */
5968 if (seekable && (start != 0 || stop <= start)) {
5969 GST_DEBUG_OBJECT (demux, "seekable but unknown start/stop -> disable");
5974 gst_query_unref (query);
5976 GST_DEBUG_OBJECT (demux, "seekable: %d (%" G_GUINT64_FORMAT " - %"
5977 G_GUINT64_FORMAT ")", seekable, start, stop);
5978 demux->upstream_seekable = seekable;
5979 demux->upstream_size = seekable ? stop : -1;
5983 gst_qtdemux_drop_data (GstQTDemux * demux, gint bytes)
5985 g_return_if_fail (bytes <= demux->todrop);
5987 GST_LOG_OBJECT (demux, "Dropping %d bytes", bytes);
5988 gst_adapter_flush (demux->adapter, bytes);
5989 demux->neededbytes -= bytes;
5990 demux->offset += bytes;
5991 demux->todrop -= bytes;
5995 gst_qtdemux_check_send_pending_segment (GstQTDemux * demux)
5997 if (G_UNLIKELY (demux->pending_newsegment)) {
6000 gst_qtdemux_push_pending_newsegment (demux);
6001 /* clear to send tags on all streams */
6002 for (i = 0; i < demux->n_streams; i++) {
6003 QtDemuxStream *stream;
6004 stream = demux->streams[i];
6005 gst_qtdemux_push_tags (demux, stream);
6006 if (stream->sparse) {
6007 GST_INFO_OBJECT (demux, "Sending gap event on stream %d", i);
6008 gst_pad_push_event (stream->pad,
6009 gst_event_new_gap (stream->segment.position, GST_CLOCK_TIME_NONE));
6016 gst_qtdemux_send_gap_for_segment (GstQTDemux * demux,
6017 QtDemuxStream * stream, gint segment_index, GstClockTime pos)
6019 GstClockTime ts, dur;
6024 stream->segments[segment_index].duration - (pos -
6025 stream->segments[segment_index].time);
6026 gap = gst_event_new_gap (ts, dur);
6027 stream->time_position += dur;
6029 GST_DEBUG_OBJECT (stream->pad, "Pushing gap for empty "
6030 "segment: %" GST_PTR_FORMAT, gap);
6031 gst_pad_push_event (stream->pad, gap);
6035 gst_qtdemux_stream_send_initial_gap_segments (GstQTDemux * demux,
6036 QtDemuxStream * stream)
6040 /* Push any initial gap segments before proceeding to the
6042 for (i = 0; i < stream->n_segments; i++) {
6043 gst_qtdemux_activate_segment (demux, stream, i, stream->time_position);
6045 if (QTSEGMENT_IS_EMPTY (&stream->segments[i])) {
6046 gst_qtdemux_send_gap_for_segment (demux, stream, i,
6047 stream->time_position);
6049 /* Only support empty segment at the beginning followed by
6050 * one non-empty segment, this was checked when parsing the
6051 * edts atom, arriving here is unexpected */
6052 g_assert (i + 1 == stream->n_segments);
6058 static GstFlowReturn
6059 gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent, GstBuffer * inbuf)
6063 demux = GST_QTDEMUX (parent);
6065 GST_DEBUG_OBJECT (demux,
6066 "Received buffer pts:%" GST_TIME_FORMAT " dts:%" GST_TIME_FORMAT
6067 " offset:%" G_GUINT64_FORMAT " size:%" G_GSIZE_FORMAT " demux offset:%"
6068 G_GUINT64_FORMAT, GST_TIME_ARGS (GST_BUFFER_PTS (inbuf)),
6069 GST_TIME_ARGS (GST_BUFFER_DTS (inbuf)), GST_BUFFER_OFFSET (inbuf),
6070 gst_buffer_get_size (inbuf), demux->offset);
6072 if (GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_DISCONT)) {
6073 gboolean is_gap_input = FALSE;
6076 GST_DEBUG_OBJECT (demux, "Got DISCONT, marking all streams as DISCONT");
6078 for (i = 0; i < demux->n_streams; i++) {
6079 demux->streams[i]->discont = TRUE;
6082 /* Check if we can land back on our feet in the case where upstream is
6083 * handling the seeking/pushing of samples with gaps in between (like
6084 * in the case of trick-mode DASH for example) */
6085 if (demux->upstream_format_is_time
6086 && GST_BUFFER_OFFSET (inbuf) != GST_BUFFER_OFFSET_NONE) {
6088 for (i = 0; i < demux->n_streams; i++) {
6090 GST_LOG_OBJECT (demux,
6091 "Stream #%d , checking if offset %" G_GUINT64_FORMAT
6092 " is a sample start", i, GST_BUFFER_OFFSET (inbuf));
6094 gst_qtdemux_find_index_for_given_media_offset_linear (demux,
6095 demux->streams[i], GST_BUFFER_OFFSET (inbuf));
6097 QtDemuxSample *sample = &demux->streams[i]->samples[res];
6098 GST_LOG_OBJECT (demux,
6099 "Checking if sample %d from stream %d is valid (offset:%"
6100 G_GUINT64_FORMAT " size:%" G_GUINT32_FORMAT ")", res, i,
6101 sample->offset, sample->size);
6102 if (sample->offset == GST_BUFFER_OFFSET (inbuf)) {
6103 GST_LOG_OBJECT (demux,
6104 "new buffer corresponds to a valid sample : %" G_GUINT32_FORMAT,
6106 is_gap_input = TRUE;
6107 /* We can go back to standard playback mode */
6108 demux->state = QTDEMUX_STATE_MOVIE;
6109 /* Remember which sample this stream is at */
6110 demux->streams[i]->sample_index = res;
6111 /* Finally update all push-based values to the expected values */
6112 demux->neededbytes = demux->streams[i]->samples[res].size;
6114 demux->offset = GST_BUFFER_OFFSET (inbuf);
6118 if (!is_gap_input) {
6119 /* Reset state if it's a real discont */
6120 demux->neededbytes = 16;
6121 demux->state = QTDEMUX_STATE_INITIAL;
6122 demux->offset = GST_BUFFER_OFFSET (inbuf);
6125 /* Reverse fragmented playback, need to flush all we have before
6126 * consuming a new fragment.
6127 * The samples array have the timestamps calculated by accumulating the
6128 * durations but this won't work for reverse playback of fragments as
6129 * the timestamps of a subsequent fragment should be smaller than the
6130 * previously received one. */
6131 if (!is_gap_input && demux->fragmented && demux->segment.rate < 0) {
6132 gst_qtdemux_process_adapter (demux, TRUE);
6133 for (i = 0; i < demux->n_streams; i++)
6134 gst_qtdemux_stream_flush_samples_data (demux, demux->streams[i]);
6138 gst_adapter_push (demux->adapter, inbuf);
6140 GST_DEBUG_OBJECT (demux,
6141 "pushing in inbuf %p, neededbytes:%u, available:%" G_GSIZE_FORMAT, inbuf,
6142 demux->neededbytes, gst_adapter_available (demux->adapter));
6144 return gst_qtdemux_process_adapter (demux, FALSE);
6147 static GstFlowReturn
6148 gst_qtdemux_process_adapter (GstQTDemux * demux, gboolean force)
6150 GstFlowReturn ret = GST_FLOW_OK;
6152 /* we never really mean to buffer that much */
6153 if (demux->neededbytes == -1) {
6157 while (((gst_adapter_available (demux->adapter)) >= demux->neededbytes) &&
6158 (ret == GST_FLOW_OK || (ret == GST_FLOW_NOT_LINKED && force))) {
6160 #ifndef GST_DISABLE_GST_DEBUG
6162 guint64 discont_offset, distance_from_discont;
6164 discont_offset = gst_adapter_offset_at_discont (demux->adapter);
6165 distance_from_discont =
6166 gst_adapter_distance_from_discont (demux->adapter);
6168 GST_DEBUG_OBJECT (demux,
6169 "state:%s , demux->neededbytes:%d, demux->offset:%" G_GUINT64_FORMAT
6170 " adapter offset :%" G_GUINT64_FORMAT " (+ %" G_GUINT64_FORMAT
6171 " bytes)", qt_demux_state_string (demux->state), demux->neededbytes,
6172 demux->offset, discont_offset, distance_from_discont);
6176 switch (demux->state) {
6177 case QTDEMUX_STATE_INITIAL:{
6182 gst_qtdemux_check_seekability (demux);
6184 data = gst_adapter_map (demux->adapter, demux->neededbytes);
6186 /* get fourcc/length, set neededbytes */
6187 extract_initial_length_and_fourcc ((guint8 *) data, demux->neededbytes,
6189 gst_adapter_unmap (demux->adapter);
6191 GST_DEBUG_OBJECT (demux, "Peeking found [%" GST_FOURCC_FORMAT "] "
6192 "size: %" G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), size);
6194 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
6195 (_("This file is invalid and cannot be played.")),
6196 ("initial atom '%" GST_FOURCC_FORMAT "' has empty length",
6197 GST_FOURCC_ARGS (fourcc)));
6198 ret = GST_FLOW_ERROR;
6201 if (fourcc == FOURCC_mdat) {
6202 gint next_entry = next_entry_size (demux);
6203 if (demux->n_streams > 0 && (next_entry != -1 || !demux->fragmented)) {
6204 /* we have the headers, start playback */
6205 demux->state = QTDEMUX_STATE_MOVIE;
6206 demux->neededbytes = next_entry;
6207 demux->mdatleft = size;
6209 /* no headers yet, try to get them */
6212 guint64 old, target;
6215 old = demux->offset;
6216 target = old + size;
6218 /* try to jump over the atom with a seek */
6219 /* only bother if it seems worth doing so,
6220 * and avoids possible upstream/server problems */
6221 if (demux->upstream_seekable &&
6222 demux->upstream_size > 4 * (1 << 20)) {
6223 res = qtdemux_seek_offset (demux, target);
6225 GST_DEBUG_OBJECT (demux, "skipping seek");
6230 GST_DEBUG_OBJECT (demux, "seek success");
6231 /* remember the offset fo the first mdat so we can seek back to it
6232 * after we have the headers */
6233 if (fourcc == FOURCC_mdat && demux->first_mdat == -1) {
6234 demux->first_mdat = old;
6235 GST_DEBUG_OBJECT (demux, "first mdat at %" G_GUINT64_FORMAT,
6238 /* seek worked, continue reading */
6239 demux->offset = target;
6240 demux->neededbytes = 16;
6241 demux->state = QTDEMUX_STATE_INITIAL;
6243 /* seek failed, need to buffer */
6244 demux->offset = old;
6245 GST_DEBUG_OBJECT (demux, "seek failed/skipped");
6246 /* there may be multiple mdat (or alike) buffers */
6248 if (demux->mdatbuffer)
6249 bs = gst_buffer_get_size (demux->mdatbuffer);
6252 if (size + bs > 10 * (1 << 20))
6254 demux->state = QTDEMUX_STATE_BUFFER_MDAT;
6255 demux->neededbytes = size;
6256 if (!demux->mdatbuffer)
6257 demux->mdatoffset = demux->offset;
6260 } else if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
6261 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
6262 (_("This file is invalid and cannot be played.")),
6263 ("atom %" GST_FOURCC_FORMAT " has bogus size %" G_GUINT64_FORMAT,
6264 GST_FOURCC_ARGS (fourcc), size));
6265 ret = GST_FLOW_ERROR;
6268 /* this means we already started buffering and still no moov header,
6269 * let's continue buffering everything till we get moov */
6270 if (demux->mdatbuffer && !(fourcc == FOURCC_moov
6271 || fourcc == FOURCC_moof))
6273 demux->neededbytes = size;
6274 demux->state = QTDEMUX_STATE_HEADER;
6278 case QTDEMUX_STATE_HEADER:{
6282 GST_DEBUG_OBJECT (demux, "In header");
6284 data = gst_adapter_map (demux->adapter, demux->neededbytes);
6286 /* parse the header */
6287 extract_initial_length_and_fourcc (data, demux->neededbytes, NULL,
6289 if (fourcc == FOURCC_moov) {
6292 /* in usual fragmented setup we could try to scan for more
6293 * and end up at the the moov (after mdat) again */
6294 if (demux->got_moov && demux->n_streams > 0 &&
6296 || demux->last_moov_offset == demux->offset)) {
6297 GST_DEBUG_OBJECT (demux,
6298 "Skipping moov atom as we have (this) one already");
6300 GST_DEBUG_OBJECT (demux, "Parsing [moov]");
6302 if (demux->got_moov && demux->fragmented) {
6303 GST_DEBUG_OBJECT (demux,
6304 "Got a second moov, clean up data from old one");
6305 if (demux->moov_node)
6306 g_node_destroy (demux->moov_node);
6307 demux->moov_node = NULL;
6308 demux->moov_node_compressed = NULL;
6310 /* prepare newsegment to send when streaming actually starts */
6311 if (!demux->pending_newsegment) {
6312 demux->pending_newsegment =
6313 gst_event_new_segment (&demux->segment);
6314 if (demux->segment_seqnum)
6315 gst_event_set_seqnum (demux->pending_newsegment,
6316 demux->segment_seqnum);
6320 demux->last_moov_offset = demux->offset;
6322 qtdemux_parse_moov (demux, data, demux->neededbytes);
6323 qtdemux_node_dump (demux, demux->moov_node);
6324 qtdemux_parse_tree (demux);
6325 qtdemux_prepare_streams (demux);
6326 if (!demux->got_moov)
6327 qtdemux_expose_streams (demux);
6330 for (n = 0; n < demux->n_streams; n++) {
6331 QtDemuxStream *stream = demux->streams[n];
6333 gst_qtdemux_configure_stream (demux, stream);
6337 demux->got_moov = TRUE;
6338 gst_qtdemux_check_send_pending_segment (demux);
6340 /* fragmented streams headers shouldn't contain edts atoms */
6341 if (!demux->fragmented) {
6342 for (n = 0; n < demux->n_streams; n++) {
6343 gst_qtdemux_stream_send_initial_gap_segments (demux,
6348 g_node_destroy (demux->moov_node);
6349 demux->moov_node = NULL;
6350 GST_DEBUG_OBJECT (demux, "Finished parsing the header");
6352 } else if (fourcc == FOURCC_moof) {
6353 if ((demux->got_moov || demux->media_caps) && demux->fragmented) {
6355 GstClockTime prev_pts;
6356 guint64 prev_offset;
6357 guint64 adapter_discont_offset, adapter_discont_dist;
6359 GST_DEBUG_OBJECT (demux, "Parsing [moof]");
6362 * The timestamp of the moof buffer is relevant as some scenarios
6363 * won't have the initial timestamp in the atoms. Whenever a new
6364 * buffer has started, we get that buffer's PTS and use it as a base
6365 * timestamp for the trun entries.
6367 * To keep track of the current buffer timestamp and starting point
6368 * we use gst_adapter_prev_pts that gives us the PTS and the distance
6369 * from the beggining of the buffer, with the distance and demux->offset
6370 * we know if it is still the same buffer or not.
6372 prev_pts = gst_adapter_prev_pts (demux->adapter, &dist);
6373 prev_offset = demux->offset - dist;
6374 if (demux->fragment_start_offset == -1
6375 || prev_offset > demux->fragment_start_offset) {
6376 demux->fragment_start_offset = prev_offset;
6377 demux->fragment_start = prev_pts;
6378 GST_DEBUG_OBJECT (demux,
6379 "New fragment start found at: %" G_GUINT64_FORMAT " : %"
6380 GST_TIME_FORMAT, demux->fragment_start_offset,
6381 GST_TIME_ARGS (demux->fragment_start));
6384 /* We can't use prev_offset() here because this would require
6385 * upstream to set consistent and correct offsets on all buffers
6386 * since the discont. Nothing ever did that in the past and we
6387 * would break backwards compatibility here then.
6388 * Instead take the offset we had at the last discont and count
6389 * the bytes from there. This works with old code as there would
6390 * be no discont between moov and moof, and also works with
6391 * adaptivedemux which correctly sets offset and will set the
6392 * DISCONT flag accordingly when needed.
6394 * We also only do this for upstream TIME segments as otherwise
6395 * there are potential backwards compatibility problems with
6396 * seeking in PUSH mode and upstream providing inconsistent
6398 adapter_discont_offset =
6399 gst_adapter_offset_at_discont (demux->adapter);
6400 adapter_discont_dist =
6401 gst_adapter_distance_from_discont (demux->adapter);
6403 GST_DEBUG_OBJECT (demux,
6404 "demux offset %" G_GUINT64_FORMAT " adapter offset %"
6405 G_GUINT64_FORMAT " (+ %" G_GUINT64_FORMAT " bytes)",
6406 demux->offset, adapter_discont_offset, adapter_discont_dist);
6408 if (demux->upstream_format_is_time) {
6409 demux->moof_offset = adapter_discont_offset;
6410 if (demux->moof_offset != GST_BUFFER_OFFSET_NONE)
6411 demux->moof_offset += adapter_discont_dist;
6412 if (demux->moof_offset == GST_BUFFER_OFFSET_NONE)
6413 demux->moof_offset = demux->offset;
6415 demux->moof_offset = demux->offset;
6418 if (!qtdemux_parse_moof (demux, data, demux->neededbytes,
6419 demux->moof_offset, NULL)) {
6420 gst_adapter_unmap (demux->adapter);
6421 ret = GST_FLOW_ERROR;
6424 /* in MSS we need to expose the pads after the first moof as we won't get a moov */
6425 if (demux->mss_mode && !demux->exposed) {
6426 if (!demux->pending_newsegment) {
6427 GST_DEBUG_OBJECT (demux, "new pending_newsegment");
6428 demux->pending_newsegment =
6429 gst_event_new_segment (&demux->segment);
6430 if (demux->segment_seqnum)
6431 gst_event_set_seqnum (demux->pending_newsegment,
6432 demux->segment_seqnum);
6434 qtdemux_expose_streams (demux);
6437 GST_DEBUG_OBJECT (demux, "Discarding [moof]");
6439 } else if (fourcc == FOURCC_ftyp) {
6440 GST_DEBUG_OBJECT (demux, "Parsing [ftyp]");
6441 qtdemux_parse_ftyp (demux, data, demux->neededbytes);
6442 } else if (fourcc == FOURCC_uuid) {
6443 GST_DEBUG_OBJECT (demux, "Parsing [uuid]");
6444 qtdemux_parse_uuid (demux, data, demux->neededbytes);
6445 } else if (fourcc == FOURCC_sidx) {
6446 GST_DEBUG_OBJECT (demux, "Parsing [sidx]");
6447 qtdemux_parse_sidx (demux, data, demux->neededbytes);
6449 GST_WARNING_OBJECT (demux,
6450 "Unknown fourcc while parsing header : %" GST_FOURCC_FORMAT,
6451 GST_FOURCC_ARGS (fourcc));
6452 /* Let's jump that one and go back to initial state */
6454 gst_adapter_unmap (demux->adapter);
6457 if (demux->mdatbuffer && demux->n_streams) {
6458 gsize remaining_data_size = 0;
6460 /* the mdat was before the header */
6461 GST_DEBUG_OBJECT (demux, "We have n_streams:%d and mdatbuffer:%p",
6462 demux->n_streams, demux->mdatbuffer);
6463 /* restore our adapter/offset view of things with upstream;
6464 * put preceding buffered data ahead of current moov data.
6465 * This should also handle evil mdat, moov, mdat cases and alike */
6466 gst_adapter_flush (demux->adapter, demux->neededbytes);
6468 /* Store any remaining data after the mdat for later usage */
6469 remaining_data_size = gst_adapter_available (demux->adapter);
6470 if (remaining_data_size > 0) {
6471 g_assert (demux->restoredata_buffer == NULL);
6472 demux->restoredata_buffer =
6473 gst_adapter_take_buffer (demux->adapter, remaining_data_size);
6474 demux->restoredata_offset = demux->offset + demux->neededbytes;
6475 GST_DEBUG_OBJECT (demux,
6476 "Stored %" G_GSIZE_FORMAT " post mdat bytes at offset %"
6477 G_GUINT64_FORMAT, remaining_data_size,
6478 demux->restoredata_offset);
6481 gst_adapter_push (demux->adapter, demux->mdatbuffer);
6482 demux->mdatbuffer = NULL;
6483 demux->offset = demux->mdatoffset;
6484 demux->neededbytes = next_entry_size (demux);
6485 demux->state = QTDEMUX_STATE_MOVIE;
6486 demux->mdatleft = gst_adapter_available (demux->adapter);
6488 GST_DEBUG_OBJECT (demux, "Carrying on normally");
6489 gst_adapter_flush (demux->adapter, demux->neededbytes);
6491 /* only go back to the mdat if there are samples to play */
6492 if (demux->got_moov && demux->first_mdat != -1
6493 && has_next_entry (demux)) {
6496 /* we need to seek back */
6497 res = qtdemux_seek_offset (demux, demux->first_mdat);
6499 demux->offset = demux->first_mdat;
6501 GST_DEBUG_OBJECT (demux, "Seek back failed");
6504 demux->offset += demux->neededbytes;
6506 demux->neededbytes = 16;
6507 demux->state = QTDEMUX_STATE_INITIAL;
6512 case QTDEMUX_STATE_BUFFER_MDAT:{
6516 GST_DEBUG_OBJECT (demux, "Got our buffer at offset %" G_GUINT64_FORMAT,
6518 buf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
6519 gst_buffer_extract (buf, 0, fourcc, 4);
6520 GST_DEBUG_OBJECT (demux, "mdatbuffer starts with %" GST_FOURCC_FORMAT,
6521 GST_FOURCC_ARGS (QT_FOURCC (fourcc)));
6522 if (demux->mdatbuffer)
6523 demux->mdatbuffer = gst_buffer_append (demux->mdatbuffer, buf);
6525 demux->mdatbuffer = buf;
6526 demux->offset += demux->neededbytes;
6527 demux->neededbytes = 16;
6528 demux->state = QTDEMUX_STATE_INITIAL;
6529 gst_qtdemux_post_progress (demux, 1, 1);
6533 case QTDEMUX_STATE_MOVIE:{
6534 QtDemuxStream *stream = NULL;
6535 QtDemuxSample *sample;
6537 GstClockTime dts, pts, duration;
6540 GST_DEBUG_OBJECT (demux,
6541 "BEGIN // in MOVIE for offset %" G_GUINT64_FORMAT, demux->offset);
6543 if (demux->fragmented) {
6544 GST_DEBUG_OBJECT (demux, "mdat remaining %" G_GUINT64_FORMAT,
6546 if (G_LIKELY (demux->todrop < demux->mdatleft)) {
6547 /* if needed data starts within this atom,
6548 * then it should not exceed this atom */
6549 if (G_UNLIKELY (demux->neededbytes > demux->mdatleft)) {
6550 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
6551 (_("This file is invalid and cannot be played.")),
6552 ("sample data crosses atom boundary"));
6553 ret = GST_FLOW_ERROR;
6556 demux->mdatleft -= demux->neededbytes;
6558 GST_DEBUG_OBJECT (demux, "data atom emptied; resuming atom scan");
6559 /* so we are dropping more than left in this atom */
6560 gst_qtdemux_drop_data (demux, demux->mdatleft);
6561 demux->mdatleft = 0;
6563 /* need to resume atom parsing so we do not miss any other pieces */
6564 demux->state = QTDEMUX_STATE_INITIAL;
6565 demux->neededbytes = 16;
6567 /* check if there was any stored post mdat data from previous buffers */
6568 if (demux->restoredata_buffer) {
6569 g_assert (gst_adapter_available (demux->adapter) == 0);
6571 gst_adapter_push (demux->adapter, demux->restoredata_buffer);
6572 demux->restoredata_buffer = NULL;
6573 demux->offset = demux->restoredata_offset;
6580 if (demux->todrop) {
6581 if (demux->cenc_aux_info_offset > 0) {
6585 GST_DEBUG_OBJECT (demux, "parsing cenc auxiliary info");
6586 data = gst_adapter_map (demux->adapter, demux->todrop);
6587 gst_byte_reader_init (&br, data + 8, demux->todrop);
6588 if (!qtdemux_parse_cenc_aux_info (demux, demux->streams[0], &br,
6589 demux->cenc_aux_info_sizes, demux->cenc_aux_sample_count)) {
6590 GST_ERROR_OBJECT (demux, "failed to parse cenc auxiliary info");
6591 ret = GST_FLOW_ERROR;
6592 gst_adapter_unmap (demux->adapter);
6593 g_free (demux->cenc_aux_info_sizes);
6594 demux->cenc_aux_info_sizes = NULL;
6597 demux->cenc_aux_info_offset = 0;
6598 g_free (demux->cenc_aux_info_sizes);
6599 demux->cenc_aux_info_sizes = NULL;
6600 gst_adapter_unmap (demux->adapter);
6602 gst_qtdemux_drop_data (demux, demux->todrop);
6606 /* initial newsegment sent here after having added pads,
6607 * possible others in sink_event */
6608 gst_qtdemux_check_send_pending_segment (demux);
6610 /* Figure out which stream this packet belongs to */
6611 for (i = 0; i < demux->n_streams; i++) {
6612 stream = demux->streams[i];
6613 if (stream->sample_index >= stream->n_samples)
6615 GST_LOG_OBJECT (demux,
6616 "Checking stream %d (sample_index:%d / offset:%" G_GUINT64_FORMAT
6617 " / size:%d)", i, stream->sample_index,
6618 stream->samples[stream->sample_index].offset,
6619 stream->samples[stream->sample_index].size);
6621 if (stream->samples[stream->sample_index].offset == demux->offset)
6625 if (G_UNLIKELY (stream == NULL || i == demux->n_streams))
6626 goto unknown_stream;
6628 if (stream->new_caps) {
6629 gst_qtdemux_configure_stream (demux, stream);
6632 /* Put data in a buffer, set timestamps, caps, ... */
6633 sample = &stream->samples[stream->sample_index];
6635 if (G_LIKELY (!(STREAM_IS_EOS (stream)))) {
6636 GST_DEBUG_OBJECT (demux, "stream : %" GST_FOURCC_FORMAT,
6637 GST_FOURCC_ARGS (stream->fourcc));
6639 dts = QTSAMPLE_DTS (stream, sample);
6640 pts = QTSAMPLE_PTS (stream, sample);
6641 duration = QTSAMPLE_DUR_DTS (stream, sample, dts);
6642 keyframe = QTSAMPLE_KEYFRAME (stream, sample);
6644 /* check for segment end */
6645 if (G_UNLIKELY (demux->segment.stop != -1
6646 && demux->segment.stop <= pts && stream->on_keyframe)) {
6647 GST_DEBUG_OBJECT (demux, "we reached the end of our segment.");
6648 stream->time_position = GST_CLOCK_TIME_NONE; /* this means EOS */
6650 /* skip this data, stream is EOS */
6651 gst_adapter_flush (demux->adapter, demux->neededbytes);
6653 /* check if all streams are eos */
6655 for (i = 0; i < demux->n_streams; i++) {
6656 if (!STREAM_IS_EOS (demux->streams[i])) {
6662 if (ret == GST_FLOW_EOS) {
6663 GST_DEBUG_OBJECT (demux, "All streams are EOS, signal upstream");
6670 gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
6672 /* FIXME: should either be an assert or a plain check */
6673 g_return_val_if_fail (outbuf != NULL, GST_FLOW_ERROR);
6675 ret = gst_qtdemux_decorate_and_push_buffer (demux, stream, outbuf,
6676 dts, pts, duration, keyframe, dts, demux->offset);
6680 ret = gst_qtdemux_combine_flows (demux, stream, ret);
6681 if (ret != GST_FLOW_OK && ret != GST_FLOW_NOT_LINKED)
6682 goto non_ok_unlinked_flow;
6684 /* skip this data, stream is EOS */
6685 gst_adapter_flush (demux->adapter, demux->neededbytes);
6688 stream->sample_index++;
6689 stream->offset_in_sample = 0;
6691 /* update current offset and figure out size of next buffer */
6692 GST_LOG_OBJECT (demux, "increasing offset %" G_GUINT64_FORMAT " by %u",
6693 demux->offset, demux->neededbytes);
6694 demux->offset += demux->neededbytes;
6695 GST_LOG_OBJECT (demux, "offset is now %" G_GUINT64_FORMAT,
6698 if ((demux->neededbytes = next_entry_size (demux)) == -1) {
6699 if (demux->fragmented) {
6700 GST_DEBUG_OBJECT (demux, "(temporarily) out of fragmented samples");
6701 /* there may be more to follow, only finish this atom */
6702 demux->todrop = demux->mdatleft;
6703 demux->neededbytes = demux->todrop;
6715 /* when buffering movie data, at least show user something is happening */
6716 if (ret == GST_FLOW_OK && demux->state == QTDEMUX_STATE_BUFFER_MDAT &&
6717 gst_adapter_available (demux->adapter) <= demux->neededbytes) {
6718 gst_qtdemux_post_progress (demux, gst_adapter_available (demux->adapter),
6719 demux->neededbytes);
6726 non_ok_unlinked_flow:
6728 GST_DEBUG_OBJECT (demux, "Stopping, combined return flow %s",
6729 gst_flow_get_name (ret));
6734 GST_ELEMENT_ERROR (demux, STREAM, FAILED, (NULL), ("unknown stream found"));
6735 ret = GST_FLOW_ERROR;
6740 GST_DEBUG_OBJECT (demux, "no next entry, EOS");
6746 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
6747 (NULL), ("qtdemuxer invalid state %d", demux->state));
6748 ret = GST_FLOW_ERROR;
6753 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
6754 (NULL), ("no 'moov' atom within the first 10 MB"));
6755 ret = GST_FLOW_ERROR;
6761 qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent)
6766 query = gst_query_new_scheduling ();
6768 if (!gst_pad_peer_query (sinkpad, query)) {
6769 gst_query_unref (query);
6773 pull_mode = gst_query_has_scheduling_mode_with_flags (query,
6774 GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
6775 gst_query_unref (query);
6780 GST_DEBUG_OBJECT (sinkpad, "activating pull");
6781 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
6785 GST_DEBUG_OBJECT (sinkpad, "activating push");
6786 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
6791 qtdemux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
6792 GstPadMode mode, gboolean active)
6795 GstQTDemux *demux = GST_QTDEMUX (parent);
6798 case GST_PAD_MODE_PUSH:
6799 demux->pullbased = FALSE;
6802 case GST_PAD_MODE_PULL:
6804 demux->pullbased = TRUE;
6805 res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_qtdemux_loop,
6808 res = gst_pad_stop_task (sinkpad);
6820 qtdemux_zalloc (void *opaque, unsigned int items, unsigned int size)
6822 return g_malloc (items * size);
6826 qtdemux_zfree (void *opaque, void *addr)
6832 qtdemux_inflate (void *z_buffer, guint z_length, guint length)
6838 z = g_new0 (z_stream, 1);
6839 z->zalloc = qtdemux_zalloc;
6840 z->zfree = qtdemux_zfree;
6843 z->next_in = z_buffer;
6844 z->avail_in = z_length;
6846 buffer = (guint8 *) g_malloc (length);
6847 ret = inflateInit (z);
6848 while (z->avail_in > 0) {
6849 if (z->avail_out == 0) {
6851 buffer = (guint8 *) g_realloc (buffer, length);
6852 z->next_out = buffer + z->total_out;
6853 z->avail_out = 1024;
6855 ret = inflate (z, Z_SYNC_FLUSH);
6859 if (ret != Z_STREAM_END) {
6860 g_warning ("inflate() returned %d", ret);
6866 #endif /* HAVE_ZLIB */
6869 qtdemux_parse_moov (GstQTDemux * qtdemux, const guint8 * buffer, guint length)
6873 qtdemux->moov_node = g_node_new ((guint8 *) buffer);
6875 /* counts as header data */
6876 qtdemux->header_size += length;
6878 GST_DEBUG_OBJECT (qtdemux, "parsing 'moov' atom");
6879 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buffer, length);
6881 cmov = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_cmov);
6887 dcom = qtdemux_tree_get_child_by_type (cmov, FOURCC_dcom);
6888 cmvd = qtdemux_tree_get_child_by_type (cmov, FOURCC_cmvd);
6889 if (dcom == NULL || cmvd == NULL)
6890 goto invalid_compression;
6892 method = QT_FOURCC ((guint8 *) dcom->data + 8);
6896 guint uncompressed_length;
6897 guint compressed_length;
6900 uncompressed_length = QT_UINT32 ((guint8 *) cmvd->data + 8);
6901 compressed_length = QT_UINT32 ((guint8 *) cmvd->data + 4) - 12;
6902 GST_LOG ("length = %u", uncompressed_length);
6905 (guint8 *) qtdemux_inflate ((guint8 *) cmvd->data + 12,
6906 compressed_length, uncompressed_length);
6908 qtdemux->moov_node_compressed = qtdemux->moov_node;
6909 qtdemux->moov_node = g_node_new (buf);
6911 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buf,
6912 uncompressed_length);
6915 #endif /* HAVE_ZLIB */
6917 GST_WARNING_OBJECT (qtdemux, "unknown or unhandled header compression "
6918 "type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (method));
6925 invalid_compression:
6927 GST_ERROR_OBJECT (qtdemux, "invalid compressed header");
6933 qtdemux_parse_container (GstQTDemux * qtdemux, GNode * node, const guint8 * buf,
6936 while (G_UNLIKELY (buf < end)) {
6940 if (G_UNLIKELY (buf + 4 > end)) {
6941 GST_LOG_OBJECT (qtdemux, "buffer overrun");
6944 len = QT_UINT32 (buf);
6945 if (G_UNLIKELY (len == 0)) {
6946 GST_LOG_OBJECT (qtdemux, "empty container");
6949 if (G_UNLIKELY (len < 8)) {
6950 GST_WARNING_OBJECT (qtdemux, "length too short (%d < 8)", len);
6953 if (G_UNLIKELY (len > (end - buf))) {
6954 GST_WARNING_OBJECT (qtdemux, "length too long (%d > %d)", len,
6955 (gint) (end - buf));
6959 child = g_node_new ((guint8 *) buf);
6960 g_node_append (node, child);
6961 GST_LOG_OBJECT (qtdemux, "adding new node of len %d", len);
6962 qtdemux_parse_node (qtdemux, child, buf, len);
6970 qtdemux_parse_theora_extension (GstQTDemux * qtdemux, QtDemuxStream * stream,
6973 int len = QT_UINT32 (xdxt->data);
6974 guint8 *buf = xdxt->data;
6975 guint8 *end = buf + len;
6978 /* skip size and type */
6986 size = QT_UINT32 (buf);
6987 type = QT_FOURCC (buf + 4);
6989 GST_LOG_OBJECT (qtdemux, "%p %p", buf, end);
6991 if (buf + size > end || size <= 0)
6997 GST_WARNING_OBJECT (qtdemux, "have cookie %" GST_FOURCC_FORMAT,
6998 GST_FOURCC_ARGS (type));
7002 buffer = gst_buffer_new_and_alloc (size);
7003 gst_buffer_fill (buffer, 0, buf, size);
7004 stream->buffers = g_slist_append (stream->buffers, buffer);
7005 GST_LOG_OBJECT (qtdemux, "parsing theora header");
7008 buffer = gst_buffer_new_and_alloc (size);
7009 gst_buffer_fill (buffer, 0, buf, size);
7010 stream->buffers = g_slist_append (stream->buffers, buffer);
7011 GST_LOG_OBJECT (qtdemux, "parsing theora comment");
7014 buffer = gst_buffer_new_and_alloc (size);
7015 gst_buffer_fill (buffer, 0, buf, size);
7016 stream->buffers = g_slist_append (stream->buffers, buffer);
7017 GST_LOG_OBJECT (qtdemux, "parsing theora codebook");
7020 GST_WARNING_OBJECT (qtdemux,
7021 "unknown theora cookie %" GST_FOURCC_FORMAT,
7022 GST_FOURCC_ARGS (type));
7031 qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node, const guint8 * buffer,
7035 guint32 node_length = 0;
7036 const QtNodeType *type;
7039 GST_LOG_OBJECT (qtdemux, "qtdemux_parse buffer %p length %u", buffer, length);
7041 if (G_UNLIKELY (length < 8))
7042 goto not_enough_data;
7044 node_length = QT_UINT32 (buffer);
7045 fourcc = QT_FOURCC (buffer + 4);
7047 /* ignore empty nodes */
7048 if (G_UNLIKELY (fourcc == 0 || node_length == 8))
7051 type = qtdemux_type_get (fourcc);
7053 end = buffer + length;
7055 GST_LOG_OBJECT (qtdemux,
7056 "parsing '%" GST_FOURCC_FORMAT "', length=%u, name '%s'",
7057 GST_FOURCC_ARGS (fourcc), node_length, type->name);
7059 if (node_length > length)
7060 goto broken_atom_size;
7062 if (type->flags & QT_FLAG_CONTAINER) {
7063 qtdemux_parse_container (qtdemux, node, buffer + 8, end);
7068 if (node_length < 20) {
7069 GST_LOG_OBJECT (qtdemux, "skipping small stsd box");
7072 GST_DEBUG_OBJECT (qtdemux,
7073 "parsing stsd (sample table, sample description) atom");
7074 /* Skip over 8 byte atom hdr + 1 byte version, 3 bytes flags, 4 byte num_entries */
7075 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
7086 /* also read alac (or whatever) in stead of mp4a in the following,
7087 * since a similar layout is used in other cases as well */
7088 if (fourcc == FOURCC_mp4a)
7090 else if (fourcc == FOURCC_fLaC)
7095 /* There are two things we might encounter here: a true mp4a atom, and
7096 an mp4a entry in an stsd atom. The latter is what we're interested
7097 in, and it looks like an atom, but isn't really one. The true mp4a
7098 atom is short, so we detect it based on length here. */
7099 if (length < min_size) {
7100 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
7101 GST_FOURCC_ARGS (fourcc));
7105 /* 'version' here is the sound sample description version. Types 0 and
7106 1 are documented in the QTFF reference, but type 2 is not: it's
7107 described in Apple header files instead (struct SoundDescriptionV2
7109 version = QT_UINT16 (buffer + 16);
7111 GST_DEBUG_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT " version 0x%08x",
7112 GST_FOURCC_ARGS (fourcc), version);
7114 /* parse any esds descriptors */
7126 GST_WARNING_OBJECT (qtdemux,
7127 "unhandled %" GST_FOURCC_FORMAT " version 0x%08x",
7128 GST_FOURCC_ARGS (fourcc), version);
7133 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
7150 /* codec_data is contained inside these atoms, which all have
7151 * the same format. */
7153 GST_DEBUG_OBJECT (qtdemux, "parsing in %" GST_FOURCC_FORMAT,
7154 GST_FOURCC_ARGS (fourcc));
7155 version = QT_UINT32 (buffer + 16);
7156 GST_DEBUG_OBJECT (qtdemux, "version %08x", version);
7157 if (1 || version == 0x00000000) {
7158 buf = buffer + 0x32;
7160 /* FIXME Quicktime uses PASCAL string while
7161 * the iso format uses C strings. Check the file
7162 * type before attempting to parse the string here. */
7163 tlen = QT_UINT8 (buf);
7164 GST_DEBUG_OBJECT (qtdemux, "tlen = %d", tlen);
7166 GST_DEBUG_OBJECT (qtdemux, "string = %.*s", tlen, (char *) buf);
7167 /* the string has a reserved space of 32 bytes so skip
7168 * the remaining 31 */
7170 buf += 4; /* and 4 bytes reserved */
7172 GST_MEMDUMP_OBJECT (qtdemux, "mp4v", buf, end - buf);
7174 qtdemux_parse_container (qtdemux, node, buf, end);
7180 GST_MEMDUMP_OBJECT (qtdemux, "H264", buffer, end - buffer);
7181 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
7186 GST_MEMDUMP_OBJECT (qtdemux, "avc1", buffer, end - buffer);
7187 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
7192 GST_MEMDUMP_OBJECT (qtdemux, "avc3", buffer, end - buffer);
7193 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
7198 GST_MEMDUMP_OBJECT (qtdemux, "H265", buffer, end - buffer);
7199 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
7204 GST_MEMDUMP_OBJECT (qtdemux, "hvc1", buffer, end - buffer);
7205 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
7210 GST_MEMDUMP_OBJECT (qtdemux, "hev1", buffer, end - buffer);
7211 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
7216 qtdemux_parse_container (qtdemux, node, buffer + 86, end);
7221 GST_DEBUG_OBJECT (qtdemux, "parsing meta atom");
7222 qtdemux_parse_container (qtdemux, node, buffer + 12, end);
7227 GST_MEMDUMP_OBJECT (qtdemux, "mp4s", buffer, end - buffer);
7228 /* Skip 8 byte header, plus 8 byte version + flags + entry_count */
7229 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
7237 version = QT_UINT32 (buffer + 12);
7238 GST_DEBUG_OBJECT (qtdemux, "parsing XiTh atom version 0x%08x", version);
7245 GST_DEBUG_OBJECT (qtdemux, "unknown version 0x%08x", version);
7250 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
7255 qtdemux_parse_container (qtdemux, node, buffer + 0x34, end);
7260 qtdemux_parse_uuid (qtdemux, buffer, end - buffer);
7265 qtdemux_parse_container (qtdemux, node, buffer + 86, end);
7270 qtdemux_parse_container (qtdemux, node, buffer + 36, end);
7274 if (!strcmp (type->name, "unknown"))
7275 GST_MEMDUMP ("Unknown tag", buffer + 4, end - buffer - 4);
7279 GST_LOG_OBJECT (qtdemux, "parsed '%" GST_FOURCC_FORMAT "'",
7280 GST_FOURCC_ARGS (fourcc));
7286 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
7287 (_("This file is corrupt and cannot be played.")),
7288 ("Not enough data for an atom header, got only %u bytes", length));
7293 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
7294 (_("This file is corrupt and cannot be played.")),
7295 ("Atom '%" GST_FOURCC_FORMAT "' has size of %u bytes, but we have only "
7296 "%u bytes available.", GST_FOURCC_ARGS (fourcc), node_length,
7303 qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc)
7307 guint32 child_fourcc;
7309 for (child = g_node_first_child (node); child;
7310 child = g_node_next_sibling (child)) {
7311 buffer = (guint8 *) child->data;
7313 child_fourcc = QT_FOURCC (buffer + 4);
7315 if (G_UNLIKELY (child_fourcc == fourcc)) {
7323 qtdemux_tree_get_child_by_type_full (GNode * node, guint32 fourcc,
7324 GstByteReader * parser)
7328 guint32 child_fourcc, child_len;
7330 for (child = g_node_first_child (node); child;
7331 child = g_node_next_sibling (child)) {
7332 buffer = (guint8 *) child->data;
7334 child_len = QT_UINT32 (buffer);
7335 child_fourcc = QT_FOURCC (buffer + 4);
7337 if (G_UNLIKELY (child_fourcc == fourcc)) {
7338 if (G_UNLIKELY (child_len < (4 + 4)))
7340 /* FIXME: must verify if atom length < parent atom length */
7341 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
7349 qtdemux_tree_get_sibling_by_type_full (GNode * node, guint32 fourcc,
7350 GstByteReader * parser)
7354 guint32 child_fourcc, child_len;
7356 for (child = g_node_next_sibling (node); child;
7357 child = g_node_next_sibling (child)) {
7358 buffer = (guint8 *) child->data;
7360 child_fourcc = QT_FOURCC (buffer + 4);
7362 if (child_fourcc == fourcc) {
7364 child_len = QT_UINT32 (buffer);
7365 if (G_UNLIKELY (child_len < (4 + 4)))
7367 /* FIXME: must verify if atom length < parent atom length */
7368 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
7377 qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc)
7379 return qtdemux_tree_get_sibling_by_type_full (node, fourcc, NULL);
7383 qtdemux_do_allocation (GstQTDemux * qtdemux, QtDemuxStream * stream)
7385 /* FIXME: This can only reliably work if demuxers have a
7386 * separate streaming thread per srcpad. This should be
7387 * done in a demuxer base class, which integrates parts
7390 * https://bugzilla.gnome.org/show_bug.cgi?id=701856
7395 query = gst_query_new_allocation (stream->caps, FALSE);
7397 if (!gst_pad_peer_query (stream->pad, query)) {
7398 /* not a problem, just debug a little */
7399 GST_DEBUG_OBJECT (qtdemux, "peer ALLOCATION query failed");
7402 if (stream->allocator)
7403 gst_object_unref (stream->allocator);
7405 if (gst_query_get_n_allocation_params (query) > 0) {
7406 /* try the allocator */
7407 gst_query_parse_nth_allocation_param (query, 0, &stream->allocator,
7409 stream->use_allocator = TRUE;
7411 stream->allocator = NULL;
7412 gst_allocation_params_init (&stream->params);
7413 stream->use_allocator = FALSE;
7415 gst_query_unref (query);
7420 gst_qtdemux_configure_protected_caps (GstQTDemux * qtdemux,
7421 QtDemuxStream * stream)
7424 const gchar *selected_system;
7426 g_return_val_if_fail (qtdemux != NULL, FALSE);
7427 g_return_val_if_fail (stream != NULL, FALSE);
7428 g_return_val_if_fail (gst_caps_get_size (stream->caps) == 1, FALSE);
7430 if (stream->protection_scheme_type != FOURCC_cenc) {
7431 GST_ERROR_OBJECT (qtdemux, "unsupported protection scheme");
7434 if (qtdemux->protection_system_ids == NULL) {
7435 GST_ERROR_OBJECT (qtdemux, "stream is protected using cenc, but no "
7436 "cenc protection system information has been found");
7439 g_ptr_array_add (qtdemux->protection_system_ids, NULL);
7440 selected_system = gst_protection_select_system ((const gchar **)
7441 qtdemux->protection_system_ids->pdata);
7442 g_ptr_array_remove_index (qtdemux->protection_system_ids,
7443 qtdemux->protection_system_ids->len - 1);
7444 if (!selected_system) {
7445 GST_ERROR_OBJECT (qtdemux, "stream is protected, but no "
7446 "suitable decryptor element has been found");
7450 s = gst_caps_get_structure (stream->caps, 0);
7451 if (!gst_structure_has_name (s, "application/x-cenc")) {
7452 gst_structure_set (s,
7453 "original-media-type", G_TYPE_STRING, gst_structure_get_name (s),
7454 GST_PROTECTION_SYSTEM_ID_CAPS_FIELD, G_TYPE_STRING, selected_system,
7456 gst_structure_set_name (s, "application/x-cenc");
7462 gst_qtdemux_configure_stream (GstQTDemux * qtdemux, QtDemuxStream * stream)
7464 if (stream->subtype == FOURCC_vide) {
7465 /* fps is calculated base on the duration of the average framerate since
7466 * qt does not have a fixed framerate. */
7467 gboolean fps_available = TRUE;
7469 if ((stream->n_samples == 1) && (stream->first_duration == 0)) {
7474 if (stream->duration == 0 || stream->n_samples < 2) {
7475 stream->fps_n = stream->timescale;
7477 fps_available = FALSE;
7479 GstClockTime avg_duration;
7483 /* duration and n_samples can be updated for fragmented format
7484 * so, framerate of fragmented format is calculated using data in a moof */
7485 if (qtdemux->fragmented && stream->n_samples_moof > 0
7486 && stream->duration_moof > 0) {
7487 n_samples = stream->n_samples_moof;
7488 duration = stream->duration_moof;
7490 n_samples = stream->n_samples;
7491 duration = stream->duration;
7494 /* Calculate a framerate, ignoring the first sample which is sometimes truncated */
7495 /* stream->duration is guint64, timescale, n_samples are guint32 */
7497 gst_util_uint64_scale_round (duration -
7498 stream->first_duration, GST_SECOND,
7499 (guint64) (stream->timescale) * (n_samples - 1));
7501 GST_LOG_OBJECT (qtdemux,
7502 "Calculating avg sample duration based on stream (or moof) duration %"
7504 " minus first sample %u, leaving %d samples gives %"
7505 GST_TIME_FORMAT, duration, stream->first_duration,
7506 n_samples - 1, GST_TIME_ARGS (avg_duration));
7508 gst_video_guess_framerate (avg_duration, &stream->fps_n,
7511 GST_DEBUG_OBJECT (qtdemux,
7512 "Calculating framerate, timescale %u gave fps_n %d fps_d %d",
7513 stream->timescale, stream->fps_n, stream->fps_d);
7518 stream->caps = gst_caps_make_writable (stream->caps);
7520 gst_caps_set_simple (stream->caps,
7521 "width", G_TYPE_INT, stream->width,
7522 "height", G_TYPE_INT, stream->height, NULL);
7524 /* set framerate if calculated framerate is reliable */
7525 if (fps_available) {
7526 gst_caps_set_simple (stream->caps,
7527 "framerate", GST_TYPE_FRACTION, stream->fps_n, stream->fps_d, NULL);
7530 /* calculate pixel-aspect-ratio using display width and height */
7531 GST_DEBUG_OBJECT (qtdemux,
7532 "video size %dx%d, target display size %dx%d", stream->width,
7533 stream->height, stream->display_width, stream->display_height);
7534 /* qt file might have pasp atom */
7535 if (stream->par_w > 0 && stream->par_h > 0) {
7536 GST_DEBUG_OBJECT (qtdemux, "par %d:%d", stream->par_w, stream->par_h);
7537 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
7538 GST_TYPE_FRACTION, stream->par_w, stream->par_h, NULL);
7539 } else if (stream->display_width > 0 && stream->display_height > 0 &&
7540 stream->width > 0 && stream->height > 0) {
7543 /* calculate the pixel aspect ratio using the display and pixel w/h */
7544 n = stream->display_width * stream->height;
7545 d = stream->display_height * stream->width;
7548 GST_DEBUG_OBJECT (qtdemux, "setting PAR to %d/%d", n, d);
7551 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
7552 GST_TYPE_FRACTION, stream->par_w, stream->par_h, NULL);
7555 /* Create incomplete colorimetry here if needed */
7556 if (stream->colorimetry.range ||
7557 stream->colorimetry.matrix ||
7558 stream->colorimetry.transfer || stream->colorimetry.primaries) {
7559 gchar *colorimetry =
7560 gst_video_colorimetry_to_string (&stream->colorimetry);
7561 gst_caps_set_simple (stream->caps, "colorimetry", G_TYPE_STRING,
7563 g_free (colorimetry);
7566 if (stream->multiview_mode != GST_VIDEO_MULTIVIEW_MODE_NONE) {
7567 guint par_w = 1, par_h = 1;
7569 if (stream->par_w > 0 && stream->par_h > 0) {
7570 par_w = stream->par_w;
7571 par_h = stream->par_h;
7574 if (gst_video_multiview_guess_half_aspect (stream->multiview_mode,
7575 stream->width, stream->height, par_w, par_h)) {
7576 stream->multiview_flags |= GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT;
7579 gst_caps_set_simple (stream->caps,
7580 "multiview-mode", G_TYPE_STRING,
7581 gst_video_multiview_mode_to_caps_string (stream->multiview_mode),
7582 "multiview-flags", GST_TYPE_VIDEO_MULTIVIEW_FLAGSET,
7583 stream->multiview_flags, GST_FLAG_SET_MASK_EXACT, NULL);
7588 else if (stream->subtype == FOURCC_soun) {
7590 stream->caps = gst_caps_make_writable (stream->caps);
7591 if (stream->rate > 0)
7592 gst_caps_set_simple (stream->caps,
7593 "rate", G_TYPE_INT, (int) stream->rate, NULL);
7594 if (stream->n_channels > 0)
7595 gst_caps_set_simple (stream->caps,
7596 "channels", G_TYPE_INT, stream->n_channels, NULL);
7597 if (stream->n_channels > 2) {
7598 /* FIXME: Need to parse the 'chan' atom to get channel layouts
7599 * correctly; this is just the minimum we can do - assume
7600 * we don't actually have any channel positions. */
7601 gst_caps_set_simple (stream->caps,
7602 "channel-mask", GST_TYPE_BITMASK, G_GUINT64_CONSTANT (0), NULL);
7608 GstCaps *prev_caps = NULL;
7610 GST_PAD_ELEMENT_PRIVATE (stream->pad) = stream;
7611 gst_pad_set_event_function (stream->pad, gst_qtdemux_handle_src_event);
7612 gst_pad_set_query_function (stream->pad, gst_qtdemux_handle_src_query);
7613 gst_pad_set_active (stream->pad, TRUE);
7615 gst_pad_use_fixed_caps (stream->pad);
7617 if (stream->protected) {
7618 if (!gst_qtdemux_configure_protected_caps (qtdemux, stream)) {
7619 GST_ERROR_OBJECT (qtdemux,
7620 "Failed to configure protected stream caps.");
7625 if (stream->new_stream) {
7628 GstStreamFlags stream_flags;
7631 gst_pad_get_sticky_event (qtdemux->sinkpad, GST_EVENT_STREAM_START,
7634 if (gst_event_parse_group_id (event, &qtdemux->group_id))
7635 qtdemux->have_group_id = TRUE;
7637 qtdemux->have_group_id = FALSE;
7638 gst_event_unref (event);
7639 } else if (!qtdemux->have_group_id) {
7640 qtdemux->have_group_id = TRUE;
7641 qtdemux->group_id = gst_util_group_id_next ();
7644 stream->new_stream = FALSE;
7646 gst_pad_create_stream_id_printf (stream->pad,
7647 GST_ELEMENT_CAST (qtdemux), "%03u", stream->track_id);
7648 event = gst_event_new_stream_start (stream_id);
7649 if (qtdemux->have_group_id)
7650 gst_event_set_group_id (event, qtdemux->group_id);
7651 stream_flags = GST_STREAM_FLAG_NONE;
7652 if (stream->disabled)
7653 stream_flags |= GST_STREAM_FLAG_UNSELECT;
7655 stream_flags |= GST_STREAM_FLAG_SPARSE;
7656 gst_event_set_stream_flags (event, stream_flags);
7657 gst_pad_push_event (stream->pad, event);
7661 prev_caps = gst_pad_get_current_caps (stream->pad);
7663 if (!prev_caps || !gst_caps_is_equal_fixed (prev_caps, stream->caps)) {
7664 GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT, stream->caps);
7665 gst_pad_set_caps (stream->pad, stream->caps);
7667 GST_DEBUG_OBJECT (qtdemux, "ignore duplicated caps");
7671 gst_caps_unref (prev_caps);
7672 stream->new_caps = FALSE;
7678 gst_qtdemux_add_stream (GstQTDemux * qtdemux,
7679 QtDemuxStream * stream, GstTagList * list)
7681 gboolean ret = TRUE;
7682 /* consistent default for push based mode */
7683 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
7685 if (stream->subtype == FOURCC_vide) {
7686 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
7689 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
7692 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
7693 gst_object_unref (stream->pad);
7699 qtdemux->n_video_streams++;
7700 } else if (stream->subtype == FOURCC_soun) {
7701 gchar *name = g_strdup_printf ("audio_%u", qtdemux->n_audio_streams);
7704 gst_pad_new_from_static_template (&gst_qtdemux_audiosrc_template, name);
7706 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
7707 gst_object_unref (stream->pad);
7712 qtdemux->n_audio_streams++;
7713 } else if (stream->subtype == FOURCC_strm) {
7714 GST_DEBUG_OBJECT (qtdemux, "stream type, not creating pad");
7715 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
7716 || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt) {
7717 gchar *name = g_strdup_printf ("subtitle_%u", qtdemux->n_sub_streams);
7720 gst_pad_new_from_static_template (&gst_qtdemux_subsrc_template, name);
7722 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
7723 gst_object_unref (stream->pad);
7728 qtdemux->n_sub_streams++;
7729 } else if (stream->caps) {
7730 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
7733 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
7735 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
7736 gst_object_unref (stream->pad);
7741 qtdemux->n_video_streams++;
7743 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
7750 GST_DEBUG_OBJECT (qtdemux, "adding pad %s %p to qtdemux %p",
7751 GST_OBJECT_NAME (stream->pad), stream->pad, qtdemux);
7752 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
7753 gst_flow_combiner_add_pad (qtdemux->flowcombiner, stream->pad);
7755 if (stream->pending_tags)
7756 gst_tag_list_unref (stream->pending_tags);
7757 stream->pending_tags = list;
7759 /* global tags go on each pad anyway */
7760 stream->send_global_tags = TRUE;
7761 /* send upstream GST_EVENT_PROTECTION events that were received before
7762 this source pad was created */
7763 for (l = qtdemux->protection_event_queue.head; l != NULL; l = l->next)
7764 gst_pad_push_event (stream->pad, gst_event_ref (l->data));
7768 gst_tag_list_unref (list);
7772 /* find next atom with @fourcc starting at @offset */
7773 static GstFlowReturn
7774 qtdemux_find_atom (GstQTDemux * qtdemux, guint64 * offset,
7775 guint64 * length, guint32 fourcc)
7781 GST_LOG_OBJECT (qtdemux, "finding fourcc %" GST_FOURCC_FORMAT " at offset %"
7782 G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), *offset);
7788 ret = gst_pad_pull_range (qtdemux->sinkpad, *offset, 16, &buf);
7789 if (G_UNLIKELY (ret != GST_FLOW_OK))
7791 if (G_UNLIKELY (gst_buffer_get_size (buf) != 16)) {
7794 gst_buffer_unref (buf);
7797 gst_buffer_map (buf, &map, GST_MAP_READ);
7798 extract_initial_length_and_fourcc (map.data, 16, length, &lfourcc);
7799 gst_buffer_unmap (buf, &map);
7800 gst_buffer_unref (buf);
7802 if (G_UNLIKELY (*length == 0)) {
7803 GST_DEBUG_OBJECT (qtdemux, "invalid length 0");
7804 ret = GST_FLOW_ERROR;
7808 if (lfourcc == fourcc) {
7809 GST_DEBUG_OBJECT (qtdemux, "found fourcc at offset %" G_GUINT64_FORMAT,
7813 GST_LOG_OBJECT (qtdemux,
7814 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
7815 GST_FOURCC_ARGS (fourcc), *offset);
7824 /* might simply have had last one */
7825 GST_DEBUG_OBJECT (qtdemux, "fourcc not found");
7830 /* should only do something in pull mode */
7831 /* call with OBJECT lock */
7832 static GstFlowReturn
7833 qtdemux_add_fragmented_samples (GstQTDemux * qtdemux)
7835 guint64 length, offset;
7836 GstBuffer *buf = NULL;
7837 GstFlowReturn ret = GST_FLOW_OK;
7838 GstFlowReturn res = GST_FLOW_OK;
7841 offset = qtdemux->moof_offset;
7842 GST_DEBUG_OBJECT (qtdemux, "next moof at offset %" G_GUINT64_FORMAT, offset);
7845 GST_DEBUG_OBJECT (qtdemux, "no next moof");
7846 return GST_FLOW_EOS;
7849 /* best not do pull etc with lock held */
7850 GST_OBJECT_UNLOCK (qtdemux);
7852 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
7853 if (ret != GST_FLOW_OK)
7856 ret = gst_qtdemux_pull_atom (qtdemux, offset, length, &buf);
7857 if (G_UNLIKELY (ret != GST_FLOW_OK))
7859 gst_buffer_map (buf, &map, GST_MAP_READ);
7860 if (!qtdemux_parse_moof (qtdemux, map.data, map.size, offset, NULL)) {
7861 gst_buffer_unmap (buf, &map);
7862 gst_buffer_unref (buf);
7867 gst_buffer_unmap (buf, &map);
7868 gst_buffer_unref (buf);
7872 /* look for next moof */
7873 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
7874 if (G_UNLIKELY (ret != GST_FLOW_OK))
7878 GST_OBJECT_LOCK (qtdemux);
7880 qtdemux->moof_offset = offset;
7886 GST_DEBUG_OBJECT (qtdemux, "failed to parse moof");
7888 res = GST_FLOW_ERROR;
7893 /* maybe upstream temporarily flushing */
7894 if (ret != GST_FLOW_FLUSHING) {
7895 GST_DEBUG_OBJECT (qtdemux, "no next moof");
7898 GST_DEBUG_OBJECT (qtdemux, "upstream WRONG_STATE");
7899 /* resume at current position next time */
7906 /* initialise bytereaders for stbl sub-atoms */
7908 qtdemux_stbl_init (GstQTDemux * qtdemux, QtDemuxStream * stream, GNode * stbl)
7910 stream->stbl_index = -1; /* no samples have yet been parsed */
7911 stream->sample_index = -1;
7913 /* time-to-sample atom */
7914 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stts, &stream->stts))
7917 /* copy atom data into a new buffer for later use */
7918 stream->stts.data = g_memdup (stream->stts.data, stream->stts.size);
7920 /* skip version + flags */
7921 if (!gst_byte_reader_skip (&stream->stts, 1 + 3) ||
7922 !gst_byte_reader_get_uint32_be (&stream->stts, &stream->n_sample_times))
7924 GST_LOG_OBJECT (qtdemux, "%u timestamp blocks", stream->n_sample_times);
7926 /* make sure there's enough data */
7927 if (!qt_atom_parser_has_chunks (&stream->stts, stream->n_sample_times, 8)) {
7928 stream->n_sample_times = gst_byte_reader_get_remaining (&stream->stts) / 8;
7929 GST_LOG_OBJECT (qtdemux, "overriding to %u timestamp blocks",
7930 stream->n_sample_times);
7931 if (!stream->n_sample_times)
7935 /* sync sample atom */
7936 stream->stps_present = FALSE;
7937 if ((stream->stss_present =
7938 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stss,
7939 &stream->stss) ? TRUE : FALSE) == TRUE) {
7940 /* copy atom data into a new buffer for later use */
7941 stream->stss.data = g_memdup (stream->stss.data, stream->stss.size);
7943 /* skip version + flags */
7944 if (!gst_byte_reader_skip (&stream->stss, 1 + 3) ||
7945 !gst_byte_reader_get_uint32_be (&stream->stss, &stream->n_sample_syncs))
7948 if (stream->n_sample_syncs) {
7949 /* make sure there's enough data */
7950 if (!qt_atom_parser_has_chunks (&stream->stss, stream->n_sample_syncs, 4))
7954 /* partial sync sample atom */
7955 if ((stream->stps_present =
7956 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stps,
7957 &stream->stps) ? TRUE : FALSE) == TRUE) {
7958 /* copy atom data into a new buffer for later use */
7959 stream->stps.data = g_memdup (stream->stps.data, stream->stps.size);
7961 /* skip version + flags */
7962 if (!gst_byte_reader_skip (&stream->stps, 1 + 3) ||
7963 !gst_byte_reader_get_uint32_be (&stream->stps,
7964 &stream->n_sample_partial_syncs))
7967 /* if there are no entries, the stss table contains the real
7969 if (stream->n_sample_partial_syncs) {
7970 /* make sure there's enough data */
7971 if (!qt_atom_parser_has_chunks (&stream->stps,
7972 stream->n_sample_partial_syncs, 4))
7979 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsz, &stream->stsz))
7982 /* copy atom data into a new buffer for later use */
7983 stream->stsz.data = g_memdup (stream->stsz.data, stream->stsz.size);
7985 /* skip version + flags */
7986 if (!gst_byte_reader_skip (&stream->stsz, 1 + 3) ||
7987 !gst_byte_reader_get_uint32_be (&stream->stsz, &stream->sample_size))
7990 if (!gst_byte_reader_get_uint32_be (&stream->stsz, &stream->n_samples))
7993 if (!stream->n_samples)
7996 /* sample-to-chunk atom */
7997 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsc, &stream->stsc))
8000 /* copy atom data into a new buffer for later use */
8001 stream->stsc.data = g_memdup (stream->stsc.data, stream->stsc.size);
8003 /* skip version + flags */
8004 if (!gst_byte_reader_skip (&stream->stsc, 1 + 3) ||
8005 !gst_byte_reader_get_uint32_be (&stream->stsc,
8006 &stream->n_samples_per_chunk))
8009 GST_DEBUG_OBJECT (qtdemux, "n_samples_per_chunk %u",
8010 stream->n_samples_per_chunk);
8012 /* make sure there's enough data */
8013 if (!qt_atom_parser_has_chunks (&stream->stsc, stream->n_samples_per_chunk,
8019 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stco, &stream->stco))
8020 stream->co_size = sizeof (guint32);
8021 else if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_co64,
8023 stream->co_size = sizeof (guint64);
8027 /* copy atom data into a new buffer for later use */
8028 stream->stco.data = g_memdup (stream->stco.data, stream->stco.size);
8030 /* skip version + flags */
8031 if (!gst_byte_reader_skip (&stream->stco, 1 + 3))
8034 /* chunks_are_samples == TRUE means treat chunks as samples */
8035 stream->chunks_are_samples = stream->sample_size && !stream->sampled;
8036 if (stream->chunks_are_samples) {
8037 /* treat chunks as samples */
8038 if (!gst_byte_reader_get_uint32_be (&stream->stco, &stream->n_samples))
8041 /* skip number of entries */
8042 if (!gst_byte_reader_skip (&stream->stco, 4))
8045 /* make sure there are enough data in the stsz atom */
8046 if (!stream->sample_size) {
8047 /* different sizes for each sample */
8048 if (!qt_atom_parser_has_chunks (&stream->stsz, stream->n_samples, 4))
8053 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
8054 stream->n_samples, (guint) sizeof (QtDemuxSample),
8055 stream->n_samples * sizeof (QtDemuxSample) / (1024.0 * 1024.0));
8057 if (stream->n_samples >=
8058 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample)) {
8059 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
8060 "be larger than %uMB (broken file?)", stream->n_samples,
8061 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
8065 g_assert (stream->samples == NULL);
8066 stream->samples = g_try_new0 (QtDemuxSample, stream->n_samples);
8067 if (!stream->samples) {
8068 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
8073 /* composition time-to-sample */
8074 if ((stream->ctts_present =
8075 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_ctts,
8076 &stream->ctts) ? TRUE : FALSE) == TRUE) {
8077 GstByteReader cslg = GST_BYTE_READER_INIT (NULL, 0);
8079 /* copy atom data into a new buffer for later use */
8080 stream->ctts.data = g_memdup (stream->ctts.data, stream->ctts.size);
8082 /* skip version + flags */
8083 if (!gst_byte_reader_skip (&stream->ctts, 1 + 3)
8084 || !gst_byte_reader_get_uint32_be (&stream->ctts,
8085 &stream->n_composition_times))
8088 /* make sure there's enough data */
8089 if (!qt_atom_parser_has_chunks (&stream->ctts, stream->n_composition_times,
8093 /* This is optional, if missing we iterate the ctts */
8094 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_cslg, &cslg)) {
8095 if (!gst_byte_reader_skip (&cslg, 1 + 3)
8096 || !gst_byte_reader_get_uint32_be (&cslg, &stream->cslg_shift)) {
8097 g_free ((gpointer) cslg.data);
8101 gint32 cslg_least = 0;
8102 guint num_entries, pos;
8105 pos = gst_byte_reader_get_pos (&stream->ctts);
8106 num_entries = stream->n_composition_times;
8108 stream->cslg_shift = 0;
8110 for (i = 0; i < num_entries; i++) {
8113 gst_byte_reader_skip_unchecked (&stream->ctts, 4);
8114 offset = gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
8116 if (offset < cslg_least)
8117 cslg_least = offset;
8121 stream->cslg_shift = ABS (cslg_least);
8123 stream->cslg_shift = 0;
8125 /* reset the reader so we can generate sample table */
8126 gst_byte_reader_set_pos (&stream->ctts, pos);
8129 /* Ensure the cslg_shift value is consistent so we can use it
8130 * unconditionnally to produce TS and Segment */
8131 stream->cslg_shift = 0;
8138 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8139 (_("This file is corrupt and cannot be played.")), (NULL));
8144 gst_qtdemux_stbl_free (stream);
8145 if (!qtdemux->fragmented) {
8146 /* not quite good */
8147 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
8150 /* may pick up samples elsewhere */
8156 /* collect samples from the next sample to be parsed up to sample @n for @stream
8157 * by reading the info from @stbl
8159 * This code can be executed from both the streaming thread and the seeking
8160 * thread so it takes the object lock to protect itself
8163 qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream, guint32 n)
8166 QtDemuxSample *samples, *first, *cur, *last;
8167 guint32 n_samples_per_chunk;
8170 GST_LOG_OBJECT (qtdemux, "parsing samples for stream fourcc %"
8171 GST_FOURCC_FORMAT ", pad %s", GST_FOURCC_ARGS (stream->fourcc),
8172 stream->pad ? GST_PAD_NAME (stream->pad) : "(NULL)");
8174 n_samples = stream->n_samples;
8177 goto out_of_samples;
8179 GST_OBJECT_LOCK (qtdemux);
8180 if (n <= stream->stbl_index)
8181 goto already_parsed;
8183 GST_DEBUG_OBJECT (qtdemux, "parsing up to sample %u", n);
8185 if (!stream->stsz.data) {
8186 /* so we already parsed and passed all the moov samples;
8187 * onto fragmented ones */
8188 g_assert (qtdemux->fragmented);
8192 /* pointer to the sample table */
8193 samples = stream->samples;
8195 /* starts from -1, moves to the next sample index to parse */
8196 stream->stbl_index++;
8198 /* keep track of the first and last sample to fill */
8199 first = &samples[stream->stbl_index];
8202 if (!stream->chunks_are_samples) {
8203 /* set the sample sizes */
8204 if (stream->sample_size == 0) {
8205 /* different sizes for each sample */
8206 for (cur = first; cur <= last; cur++) {
8207 cur->size = gst_byte_reader_get_uint32_be_unchecked (&stream->stsz);
8208 GST_LOG_OBJECT (qtdemux, "sample %d has size %u",
8209 (guint) (cur - samples), cur->size);
8212 /* samples have the same size */
8213 GST_LOG_OBJECT (qtdemux, "all samples have size %u", stream->sample_size);
8214 for (cur = first; cur <= last; cur++)
8215 cur->size = stream->sample_size;
8219 n_samples_per_chunk = stream->n_samples_per_chunk;
8222 for (i = stream->stsc_index; i < n_samples_per_chunk; i++) {
8225 if (stream->stsc_chunk_index >= stream->last_chunk
8226 || stream->stsc_chunk_index < stream->first_chunk) {
8227 stream->first_chunk =
8228 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
8229 stream->samples_per_chunk =
8230 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
8231 gst_byte_reader_skip_unchecked (&stream->stsc, 4);
8233 /* chunk numbers are counted from 1 it seems */
8234 if (G_UNLIKELY (stream->first_chunk == 0))
8237 --stream->first_chunk;
8239 /* the last chunk of each entry is calculated by taking the first chunk
8240 * of the next entry; except if there is no next, where we fake it with
8242 if (G_UNLIKELY (i == (stream->n_samples_per_chunk - 1))) {
8243 stream->last_chunk = G_MAXUINT32;
8245 stream->last_chunk =
8246 gst_byte_reader_peek_uint32_be_unchecked (&stream->stsc);
8247 if (G_UNLIKELY (stream->last_chunk == 0))
8250 --stream->last_chunk;
8253 GST_LOG_OBJECT (qtdemux,
8254 "entry %d has first_chunk %d, last_chunk %d, samples_per_chunk %d", i,
8255 stream->first_chunk, stream->last_chunk, stream->samples_per_chunk);
8257 if (G_UNLIKELY (stream->last_chunk < stream->first_chunk))
8260 if (stream->last_chunk != G_MAXUINT32) {
8261 if (!qt_atom_parser_peek_sub (&stream->stco,
8262 stream->first_chunk * stream->co_size,
8263 (stream->last_chunk - stream->first_chunk) * stream->co_size,
8268 stream->co_chunk = stream->stco;
8269 if (!gst_byte_reader_skip (&stream->co_chunk,
8270 stream->first_chunk * stream->co_size))
8274 stream->stsc_chunk_index = stream->first_chunk;
8277 last_chunk = stream->last_chunk;
8279 if (stream->chunks_are_samples) {
8280 cur = &samples[stream->stsc_chunk_index];
8282 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
8285 stream->stsc_chunk_index = j;
8290 qt_atom_parser_get_offset_unchecked (&stream->co_chunk,
8293 GST_LOG_OBJECT (qtdemux, "Created entry %d with offset "
8294 "%" G_GUINT64_FORMAT, j, cur->offset);
8296 if (stream->samples_per_frame * stream->bytes_per_frame) {
8298 (stream->samples_per_chunk * stream->n_channels) /
8299 stream->samples_per_frame * stream->bytes_per_frame;
8301 cur->size = stream->samples_per_chunk;
8304 GST_DEBUG_OBJECT (qtdemux,
8305 "keyframe sample %d: timestamp %" GST_TIME_FORMAT ", size %u",
8306 j, GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream,
8307 stream->stco_sample_index)), cur->size);
8309 cur->timestamp = stream->stco_sample_index;
8310 cur->duration = stream->samples_per_chunk;
8311 cur->keyframe = TRUE;
8314 stream->stco_sample_index += stream->samples_per_chunk;
8316 stream->stsc_chunk_index = j;
8318 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
8319 guint32 samples_per_chunk;
8320 guint64 chunk_offset;
8322 if (!stream->stsc_sample_index
8323 && !qt_atom_parser_get_offset (&stream->co_chunk, stream->co_size,
8324 &stream->chunk_offset))
8327 samples_per_chunk = stream->samples_per_chunk;
8328 chunk_offset = stream->chunk_offset;
8330 for (k = stream->stsc_sample_index; k < samples_per_chunk; k++) {
8331 GST_LOG_OBJECT (qtdemux, "creating entry %d with offset %"
8332 G_GUINT64_FORMAT " and size %d",
8333 (guint) (cur - samples), chunk_offset, cur->size);
8335 cur->offset = chunk_offset;
8336 chunk_offset += cur->size;
8339 if (G_UNLIKELY (cur > last)) {
8341 stream->stsc_sample_index = k + 1;
8342 stream->chunk_offset = chunk_offset;
8343 stream->stsc_chunk_index = j;
8347 stream->stsc_sample_index = 0;
8349 stream->stsc_chunk_index = j;
8351 stream->stsc_index++;
8354 if (stream->chunks_are_samples)
8358 guint32 n_sample_times;
8360 n_sample_times = stream->n_sample_times;
8363 for (i = stream->stts_index; i < n_sample_times; i++) {
8364 guint32 stts_samples;
8365 gint32 stts_duration;
8368 if (stream->stts_sample_index >= stream->stts_samples
8369 || !stream->stts_sample_index) {
8371 stream->stts_samples =
8372 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
8373 stream->stts_duration =
8374 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
8376 GST_LOG_OBJECT (qtdemux, "block %d, %u timestamps, duration %u",
8377 i, stream->stts_samples, stream->stts_duration);
8379 stream->stts_sample_index = 0;
8382 stts_samples = stream->stts_samples;
8383 stts_duration = stream->stts_duration;
8384 stts_time = stream->stts_time;
8386 for (j = stream->stts_sample_index; j < stts_samples; j++) {
8387 GST_DEBUG_OBJECT (qtdemux,
8388 "sample %d: index %d, timestamp %" GST_TIME_FORMAT,
8389 (guint) (cur - samples), j,
8390 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stts_time)));
8392 cur->timestamp = stts_time;
8393 cur->duration = stts_duration;
8395 /* avoid 32-bit wrap-around,
8396 * but still mind possible 'negative' duration */
8397 stts_time += (gint64) stts_duration;
8400 if (G_UNLIKELY (cur > last)) {
8402 stream->stts_time = stts_time;
8403 stream->stts_sample_index = j + 1;
8407 stream->stts_sample_index = 0;
8408 stream->stts_time = stts_time;
8409 stream->stts_index++;
8411 /* fill up empty timestamps with the last timestamp, this can happen when
8412 * the last samples do not decode and so we don't have timestamps for them.
8413 * We however look at the last timestamp to estimate the track length so we
8414 * need something in here. */
8415 for (; cur < last; cur++) {
8416 GST_DEBUG_OBJECT (qtdemux,
8417 "fill sample %d: timestamp %" GST_TIME_FORMAT,
8418 (guint) (cur - samples),
8419 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stream->stts_time)));
8420 cur->timestamp = stream->stts_time;
8426 /* sample sync, can be NULL */
8427 if (stream->stss_present == TRUE) {
8428 guint32 n_sample_syncs;
8430 n_sample_syncs = stream->n_sample_syncs;
8432 if (!n_sample_syncs) {
8433 GST_DEBUG_OBJECT (qtdemux, "all samples are keyframes");
8434 stream->all_keyframe = TRUE;
8436 for (i = stream->stss_index; i < n_sample_syncs; i++) {
8437 /* note that the first sample is index 1, not 0 */
8440 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stss);
8442 if (G_LIKELY (index > 0 && index <= n_samples)) {
8444 samples[index].keyframe = TRUE;
8445 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
8446 /* and exit if we have enough samples */
8447 if (G_UNLIKELY (index >= n)) {
8454 stream->stss_index = i;
8457 /* stps marks partial sync frames like open GOP I-Frames */
8458 if (stream->stps_present == TRUE) {
8459 guint32 n_sample_partial_syncs;
8461 n_sample_partial_syncs = stream->n_sample_partial_syncs;
8463 /* if there are no entries, the stss table contains the real
8465 if (n_sample_partial_syncs) {
8466 for (i = stream->stps_index; i < n_sample_partial_syncs; i++) {
8467 /* note that the first sample is index 1, not 0 */
8470 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stps);
8472 if (G_LIKELY (index > 0 && index <= n_samples)) {
8474 samples[index].keyframe = TRUE;
8475 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
8476 /* and exit if we have enough samples */
8477 if (G_UNLIKELY (index >= n)) {
8484 stream->stps_index = i;
8488 /* no stss, all samples are keyframes */
8489 stream->all_keyframe = TRUE;
8490 GST_DEBUG_OBJECT (qtdemux, "setting all keyframes");
8495 /* composition time to sample */
8496 if (stream->ctts_present == TRUE) {
8497 guint32 n_composition_times;
8499 gint32 ctts_soffset;
8501 /* Fill in the pts_offsets */
8503 n_composition_times = stream->n_composition_times;
8505 for (i = stream->ctts_index; i < n_composition_times; i++) {
8506 if (stream->ctts_sample_index >= stream->ctts_count
8507 || !stream->ctts_sample_index) {
8508 stream->ctts_count =
8509 gst_byte_reader_get_uint32_be_unchecked (&stream->ctts);
8510 stream->ctts_soffset =
8511 gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
8512 stream->ctts_sample_index = 0;
8515 ctts_count = stream->ctts_count;
8516 ctts_soffset = stream->ctts_soffset;
8518 for (j = stream->ctts_sample_index; j < ctts_count; j++) {
8519 cur->pts_offset = ctts_soffset;
8522 if (G_UNLIKELY (cur > last)) {
8524 stream->ctts_sample_index = j + 1;
8528 stream->ctts_sample_index = 0;
8529 stream->ctts_index++;
8533 stream->stbl_index = n;
8534 /* if index has been completely parsed, free data that is no-longer needed */
8535 if (n + 1 == stream->n_samples) {
8536 gst_qtdemux_stbl_free (stream);
8537 GST_DEBUG_OBJECT (qtdemux, "parsed all available samples;");
8538 if (qtdemux->pullbased) {
8539 GST_DEBUG_OBJECT (qtdemux, "checking for more samples");
8540 while (n + 1 == stream->n_samples)
8541 if (qtdemux_add_fragmented_samples (qtdemux) != GST_FLOW_OK)
8545 GST_OBJECT_UNLOCK (qtdemux);
8552 GST_LOG_OBJECT (qtdemux,
8553 "Tried to parse up to sample %u but this sample has already been parsed",
8555 /* if fragmented, there may be more */
8556 if (qtdemux->fragmented && n == stream->stbl_index)
8558 GST_OBJECT_UNLOCK (qtdemux);
8564 GST_LOG_OBJECT (qtdemux,
8565 "Tried to parse up to sample %u but there are only %u samples", n + 1,
8567 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8568 (_("This file is corrupt and cannot be played.")), (NULL));
8573 GST_OBJECT_UNLOCK (qtdemux);
8574 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8575 (_("This file is corrupt and cannot be played.")), (NULL));
8580 /* collect all segment info for @stream.
8583 qtdemux_parse_segments (GstQTDemux * qtdemux, QtDemuxStream * stream,
8587 /* accept edts if they contain gaps at start and there is only
8588 * one media segment */
8589 gboolean allow_pushbased_edts = TRUE;
8590 gint media_segments_count = 0;
8592 /* parse and prepare segment info from the edit list */
8593 GST_DEBUG_OBJECT (qtdemux, "looking for edit list container");
8594 stream->n_segments = 0;
8595 stream->segments = NULL;
8596 if ((edts = qtdemux_tree_get_child_by_type (trak, FOURCC_edts))) {
8599 gint i, count, entry_size;
8605 GST_DEBUG_OBJECT (qtdemux, "looking for edit list");
8606 if (!(elst = qtdemux_tree_get_child_by_type (edts, FOURCC_elst)))
8609 buffer = elst->data;
8611 version = QT_UINT8 (buffer + 8);
8612 entry_size = (version == 1) ? 20 : 12;
8614 n_segments = QT_UINT32 (buffer + 12);
8616 /* we might allocate a bit too much, at least allocate 1 segment */
8617 stream->segments = g_new (QtDemuxSegment, MAX (n_segments, 1));
8619 /* segments always start from 0 */
8623 for (i = 0; i < n_segments; i++) {
8626 gboolean time_valid = TRUE;
8627 QtDemuxSegment *segment;
8629 GstClockTime media_start = GST_CLOCK_TIME_NONE;
8632 media_time = QT_UINT64 (buffer + 24 + i * entry_size);
8633 duration = QT_UINT64 (buffer + 16 + i * entry_size);
8634 if (media_time == G_MAXUINT64)
8637 media_time = QT_UINT32 (buffer + 20 + i * entry_size);
8638 duration = QT_UINT32 (buffer + 16 + i * entry_size);
8639 if (media_time == G_MAXUINT32)
8644 media_start = QTSTREAMTIME_TO_GSTTIME (stream, media_time);
8646 segment = &stream->segments[count++];
8648 /* time and duration expressed in global timescale */
8649 segment->time = stime;
8650 /* add non scaled values so we don't cause roundoff errors */
8651 if (duration || media_start == GST_CLOCK_TIME_NONE) {
8653 stime = QTTIME_TO_GSTTIME (qtdemux, time);
8654 segment->duration = stime - segment->time;
8656 /* zero duration does not imply media_start == media_stop
8657 * but, only specify media_start.*/
8658 stime = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
8659 if (GST_CLOCK_TIME_IS_VALID (stime) && time_valid
8660 && stime >= media_start) {
8661 segment->duration = stime - media_start;
8663 segment->duration = GST_CLOCK_TIME_NONE;
8666 segment->stop_time = stime;
8668 segment->trak_media_start = media_time;
8669 /* media_time expressed in stream timescale */
8671 segment->media_start = media_start;
8672 segment->media_stop = segment->media_start + segment->duration;
8673 media_segments_count++;
8675 segment->media_start = GST_CLOCK_TIME_NONE;
8676 segment->media_stop = GST_CLOCK_TIME_NONE;
8679 QT_UINT32 (buffer + ((version == 1) ? 32 : 24) + i * entry_size);
8681 if (rate_int <= 1) {
8682 /* 0 is not allowed, some programs write 1 instead of the floating point
8684 GST_WARNING_OBJECT (qtdemux, "found suspicious rate %" G_GUINT32_FORMAT,
8688 segment->rate = rate_int / 65536.0;
8691 GST_DEBUG_OBJECT (qtdemux, "created segment %d time %" GST_TIME_FORMAT
8692 ", duration %" GST_TIME_FORMAT ", media_start %" GST_TIME_FORMAT
8693 " (%" G_GUINT64_FORMAT ") , media_stop %" GST_TIME_FORMAT
8694 " stop_time %" GST_TIME_FORMAT " rate %g, (%d) timescale %u",
8695 i, GST_TIME_ARGS (segment->time),
8696 GST_TIME_ARGS (segment->duration),
8697 GST_TIME_ARGS (segment->media_start), media_time,
8698 GST_TIME_ARGS (segment->media_stop),
8699 GST_TIME_ARGS (segment->stop_time), segment->rate, rate_int,
8701 if (segment->stop_time > qtdemux->segment.stop) {
8702 GST_WARNING_OBJECT (qtdemux, "Segment %d "
8703 " extends to %" GST_TIME_FORMAT
8704 " past the end of the file duration %" GST_TIME_FORMAT
8705 " it will be truncated", i, GST_TIME_ARGS (segment->stop_time),
8706 GST_TIME_ARGS (qtdemux->segment.stop));
8707 qtdemux->segment.stop = segment->stop_time;
8710 GST_DEBUG_OBJECT (qtdemux, "found %d segments", count);
8711 stream->n_segments = count;
8712 if (media_segments_count != 1)
8713 allow_pushbased_edts = FALSE;
8717 /* push based does not handle segments, so act accordingly here,
8718 * and warn if applicable */
8719 if (!qtdemux->pullbased && !allow_pushbased_edts) {
8720 GST_WARNING_OBJECT (qtdemux, "streaming; discarding edit list segments");
8721 /* remove and use default one below, we stream like it anyway */
8722 g_free (stream->segments);
8723 stream->segments = NULL;
8724 stream->n_segments = 0;
8727 /* no segments, create one to play the complete trak */
8728 if (stream->n_segments == 0) {
8729 GstClockTime stream_duration =
8730 QTSTREAMTIME_TO_GSTTIME (stream, stream->duration);
8732 if (stream->segments == NULL)
8733 stream->segments = g_new (QtDemuxSegment, 1);
8735 /* represent unknown our way */
8736 if (stream_duration == 0)
8737 stream_duration = GST_CLOCK_TIME_NONE;
8739 stream->segments[0].time = 0;
8740 stream->segments[0].stop_time = stream_duration;
8741 stream->segments[0].duration = stream_duration;
8742 stream->segments[0].media_start = 0;
8743 stream->segments[0].media_stop = stream_duration;
8744 stream->segments[0].rate = 1.0;
8745 stream->segments[0].trak_media_start = 0;
8747 GST_DEBUG_OBJECT (qtdemux, "created dummy segment %" GST_TIME_FORMAT,
8748 GST_TIME_ARGS (stream_duration));
8749 stream->n_segments = 1;
8750 stream->dummy_segment = TRUE;
8752 GST_DEBUG_OBJECT (qtdemux, "using %d segments", stream->n_segments);
8758 * Parses the stsd atom of a svq3 trak looking for
8759 * the SMI and gama atoms.
8762 qtdemux_parse_svq3_stsd_data (GstQTDemux * qtdemux, GNode * stsd,
8763 guint8 ** gamma, GstBuffer ** seqh)
8765 guint8 *_gamma = NULL;
8766 GstBuffer *_seqh = NULL;
8767 guint8 *stsd_data = stsd->data;
8768 guint32 length = QT_UINT32 (stsd_data);
8772 GST_WARNING_OBJECT (qtdemux, "stsd too short");
8778 version = QT_UINT16 (stsd_data);
8783 while (length > 8) {
8784 guint32 fourcc, size;
8786 size = QT_UINT32 (stsd_data);
8787 fourcc = QT_FOURCC (stsd_data + 4);
8788 data = stsd_data + 8;
8791 GST_WARNING_OBJECT (qtdemux, "Atom of size 0 found, aborting "
8792 "svq3 atom parsing");
8801 GST_WARNING_OBJECT (qtdemux, "Unexpected size %" G_GUINT32_FORMAT
8802 " for gama atom, expected 12", size);
8807 if (size > 16 && QT_FOURCC (data) == FOURCC_SEQH) {
8809 if (_seqh != NULL) {
8810 GST_WARNING_OBJECT (qtdemux, "Unexpected second SEQH SMI atom "
8811 " found, ignoring");
8813 seqh_size = QT_UINT32 (data + 4);
8814 if (seqh_size > 0) {
8815 _seqh = gst_buffer_new_and_alloc (seqh_size);
8816 gst_buffer_fill (_seqh, 0, data + 8, seqh_size);
8823 GST_WARNING_OBJECT (qtdemux, "Unhandled atom %" GST_FOURCC_FORMAT
8824 " in SVQ3 entry in stsd atom", GST_FOURCC_ARGS (fourcc));
8828 if (size <= length) {
8834 GST_WARNING_OBJECT (qtdemux, "SVQ3 entry too short in stsd atom");
8837 GST_WARNING_OBJECT (qtdemux, "Unexpected version for SVQ3 entry %"
8838 G_GUINT16_FORMAT, version);
8849 gst_buffer_unref (_seqh);
8854 qtdemux_get_rtsp_uri_from_hndl (GstQTDemux * qtdemux, GNode * minf)
8861 * Get 'dinf', to get its child 'dref', that might contain a 'hndl'
8862 * atom that might contain a 'data' atom with the rtsp uri.
8863 * This case was reported in bug #597497, some info about
8864 * the hndl atom can be found in TN1195
8866 dinf = qtdemux_tree_get_child_by_type (minf, FOURCC_dinf);
8867 GST_DEBUG_OBJECT (qtdemux, "Trying to obtain rtsp URI for stream trak");
8870 guint32 dref_num_entries = 0;
8871 if (qtdemux_tree_get_child_by_type_full (dinf, FOURCC_dref, &dref) &&
8872 gst_byte_reader_skip (&dref, 4) &&
8873 gst_byte_reader_get_uint32_be (&dref, &dref_num_entries)) {
8876 /* search dref entries for hndl atom */
8877 for (i = 0; i < dref_num_entries; i++) {
8878 guint32 size = 0, type;
8879 guint8 string_len = 0;
8880 if (gst_byte_reader_get_uint32_be (&dref, &size) &&
8881 qt_atom_parser_get_fourcc (&dref, &type)) {
8882 if (type == FOURCC_hndl) {
8883 GST_DEBUG_OBJECT (qtdemux, "Found hndl atom");
8885 /* skip data reference handle bytes and the
8886 * following pascal string and some extra 4
8887 * bytes I have no idea what are */
8888 if (!gst_byte_reader_skip (&dref, 4) ||
8889 !gst_byte_reader_get_uint8 (&dref, &string_len) ||
8890 !gst_byte_reader_skip (&dref, string_len + 4)) {
8891 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl atom");
8895 /* iterate over the atoms to find the data atom */
8896 while (gst_byte_reader_get_remaining (&dref) >= 8) {
8900 if (gst_byte_reader_get_uint32_be (&dref, &atom_size) &&
8901 qt_atom_parser_get_fourcc (&dref, &atom_type)) {
8902 if (atom_type == FOURCC_data) {
8903 const guint8 *uri_aux = NULL;
8905 /* found the data atom that might contain the rtsp uri */
8906 GST_DEBUG_OBJECT (qtdemux, "Found data atom inside "
8907 "hndl atom, interpreting it as an URI");
8908 if (gst_byte_reader_peek_data (&dref, atom_size - 8,
8910 if (g_strstr_len ((gchar *) uri_aux, 7, "rtsp://") != NULL)
8911 uri = g_strndup ((gchar *) uri_aux, atom_size - 8);
8913 GST_WARNING_OBJECT (qtdemux, "Data atom in hndl atom "
8914 "didn't contain a rtsp address");
8916 GST_WARNING_OBJECT (qtdemux, "Failed to get the data "
8921 /* skipping to the next entry */
8922 if (!gst_byte_reader_skip (&dref, atom_size - 8))
8925 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl child "
8932 /* skip to the next entry */
8933 if (!gst_byte_reader_skip (&dref, size - 8))
8936 GST_WARNING_OBJECT (qtdemux, "Error parsing dref atom");
8939 GST_DEBUG_OBJECT (qtdemux, "Finished parsing dref atom");
8945 #define AMR_NB_ALL_MODES 0x81ff
8946 #define AMR_WB_ALL_MODES 0x83ff
8948 qtdemux_parse_amr_bitrate (GstBuffer * buf, gboolean wb)
8950 /* The 'damr' atom is of the form:
8952 * | vendor | decoder_ver | mode_set | mode_change_period | frames/sample |
8953 * 32 b 8 b 16 b 8 b 8 b
8955 * The highest set bit of the first 7 (AMR-NB) or 8 (AMR-WB) bits of mode_set
8956 * represents the highest mode used in the stream (and thus the maximum
8957 * bitrate), with a couple of special cases as seen below.
8960 /* Map of frame type ID -> bitrate */
8961 static const guint nb_bitrates[] = {
8962 4750, 5150, 5900, 6700, 7400, 7950, 10200, 12200
8964 static const guint wb_bitrates[] = {
8965 6600, 8850, 12650, 14250, 15850, 18250, 19850, 23050, 23850
8971 gst_buffer_map (buf, &map, GST_MAP_READ);
8973 if (map.size != 0x11) {
8974 GST_DEBUG ("Atom should have size 0x11, not %" G_GSIZE_FORMAT, map.size);
8978 if (QT_FOURCC (map.data + 4) != FOURCC_damr) {
8979 GST_DEBUG ("Unknown atom in %" GST_FOURCC_FORMAT,
8980 GST_FOURCC_ARGS (QT_UINT32 (map.data + 4)));
8984 mode_set = QT_UINT16 (map.data + 13);
8986 if (mode_set == (wb ? AMR_WB_ALL_MODES : AMR_NB_ALL_MODES))
8987 max_mode = 7 + (wb ? 1 : 0);
8989 /* AMR-NB modes fo from 0-7, and AMR-WB modes go from 0-8 */
8990 max_mode = g_bit_nth_msf ((gulong) mode_set & (wb ? 0x1ff : 0xff), -1);
8992 if (max_mode == -1) {
8993 GST_DEBUG ("No mode indication was found (mode set) = %x",
8998 gst_buffer_unmap (buf, &map);
8999 return wb ? wb_bitrates[max_mode] : nb_bitrates[max_mode];
9002 gst_buffer_unmap (buf, &map);
9007 qtdemux_parse_transformation_matrix (GstQTDemux * qtdemux,
9008 GstByteReader * reader, guint32 * matrix, const gchar * atom)
9011 * 9 values of 32 bits (fixed point 16.16, except 2 5 and 8 that are 2.30)
9017 if (gst_byte_reader_get_remaining (reader) < 36)
9020 matrix[0] = gst_byte_reader_get_uint32_be_unchecked (reader);
9021 matrix[1] = gst_byte_reader_get_uint32_be_unchecked (reader);
9022 matrix[2] = gst_byte_reader_get_uint32_be_unchecked (reader);
9023 matrix[3] = gst_byte_reader_get_uint32_be_unchecked (reader);
9024 matrix[4] = gst_byte_reader_get_uint32_be_unchecked (reader);
9025 matrix[5] = gst_byte_reader_get_uint32_be_unchecked (reader);
9026 matrix[6] = gst_byte_reader_get_uint32_be_unchecked (reader);
9027 matrix[7] = gst_byte_reader_get_uint32_be_unchecked (reader);
9028 matrix[8] = gst_byte_reader_get_uint32_be_unchecked (reader);
9030 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix from atom %s", atom);
9031 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[0] >> 16,
9032 matrix[0] & 0xFFFF, matrix[1] >> 16, matrix[1] & 0xFF, matrix[2] >> 16,
9034 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[3] >> 16,
9035 matrix[3] & 0xFFFF, matrix[4] >> 16, matrix[4] & 0xFF, matrix[5] >> 16,
9037 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[6] >> 16,
9038 matrix[6] & 0xFFFF, matrix[7] >> 16, matrix[7] & 0xFF, matrix[8] >> 16,
9045 qtdemux_inspect_transformation_matrix (GstQTDemux * qtdemux,
9046 QtDemuxStream * stream, guint32 * matrix, GstTagList ** taglist)
9053 * This macro will only compare value abdegh, it expects cfi to have already
9056 #define QTCHECK_MATRIX(m,a,b,d,e) ((m)[0] == (a << 16) && (m)[1] == (b << 16) && \
9057 (m)[3] == (d << 16) && (m)[4] == (e << 16))
9059 /* only handle the cases where the last column has standard values */
9060 if (matrix[2] == 0 && matrix[5] == 0 && matrix[8] == 1 << 30) {
9061 const gchar *rotation_tag = NULL;
9063 /* no rotation needed */
9064 if (QTCHECK_MATRIX (matrix, 1, 0, 0, 1)) {
9066 } else if (QTCHECK_MATRIX (matrix, 0, 1, G_MAXUINT16, 0)) {
9067 rotation_tag = "rotate-90";
9068 } else if (QTCHECK_MATRIX (matrix, G_MAXUINT16, 0, 0, G_MAXUINT16)) {
9069 rotation_tag = "rotate-180";
9070 } else if (QTCHECK_MATRIX (matrix, 0, G_MAXUINT16, 1, 0)) {
9071 rotation_tag = "rotate-270";
9073 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
9076 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix rotation %s",
9078 if (rotation_tag != NULL) {
9079 if (*taglist == NULL)
9080 *taglist = gst_tag_list_new_empty ();
9081 gst_tag_list_add (*taglist, GST_TAG_MERGE_REPLACE,
9082 GST_TAG_IMAGE_ORIENTATION, rotation_tag, NULL);
9085 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
9089 /* Parses the boxes defined in ISO/IEC 14496-12 that enable support for
9090 * protected streams (sinf, frma, schm and schi); if the protection scheme is
9091 * Common Encryption (cenc), the function will also parse the tenc box (defined
9092 * in ISO/IEC 23001-7). @container points to the node that contains these boxes
9093 * (typically an enc[v|a|t|s] sample entry); the function will set
9094 * @original_fmt to the fourcc of the original unencrypted stream format.
9095 * Returns TRUE if successful; FALSE otherwise. */
9097 qtdemux_parse_protection_scheme_info (GstQTDemux * qtdemux,
9098 QtDemuxStream * stream, GNode * container, guint32 * original_fmt)
9105 g_return_val_if_fail (qtdemux != NULL, FALSE);
9106 g_return_val_if_fail (stream != NULL, FALSE);
9107 g_return_val_if_fail (container != NULL, FALSE);
9108 g_return_val_if_fail (original_fmt != NULL, FALSE);
9110 sinf = qtdemux_tree_get_child_by_type (container, FOURCC_sinf);
9111 if (G_UNLIKELY (!sinf)) {
9112 if (stream->protection_scheme_type == FOURCC_cenc) {
9113 GST_ERROR_OBJECT (qtdemux, "sinf box does not contain schi box, which is "
9114 "mandatory for Common Encryption");
9120 frma = qtdemux_tree_get_child_by_type (sinf, FOURCC_frma);
9121 if (G_UNLIKELY (!frma)) {
9122 GST_ERROR_OBJECT (qtdemux, "sinf box does not contain mandatory frma box");
9126 *original_fmt = QT_FOURCC ((const guint8 *) frma->data + 8);
9127 GST_DEBUG_OBJECT (qtdemux, "original stream format: '%" GST_FOURCC_FORMAT "'",
9128 GST_FOURCC_ARGS (*original_fmt));
9130 schm = qtdemux_tree_get_child_by_type (sinf, FOURCC_schm);
9132 GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schm box");
9135 stream->protection_scheme_type = QT_FOURCC ((const guint8 *) schm->data + 12);
9136 stream->protection_scheme_version =
9137 QT_UINT32 ((const guint8 *) schm->data + 16);
9139 GST_DEBUG_OBJECT (qtdemux,
9140 "protection_scheme_type: %" GST_FOURCC_FORMAT ", "
9141 "protection_scheme_version: %#010x",
9142 GST_FOURCC_ARGS (stream->protection_scheme_type),
9143 stream->protection_scheme_version);
9145 schi = qtdemux_tree_get_child_by_type (sinf, FOURCC_schi);
9147 GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schi box");
9150 if (stream->protection_scheme_type == FOURCC_cenc) {
9151 QtDemuxCencSampleSetInfo *info;
9153 const guint8 *tenc_data;
9154 guint32 isEncrypted;
9156 const guint8 *default_kid;
9159 if (G_UNLIKELY (!stream->protection_scheme_info))
9160 stream->protection_scheme_info =
9161 g_malloc0 (sizeof (QtDemuxCencSampleSetInfo));
9163 info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
9165 tenc = qtdemux_tree_get_child_by_type (schi, FOURCC_tenc);
9167 GST_ERROR_OBJECT (qtdemux, "schi box does not contain tenc box, "
9168 "which is mandatory for Common Encryption");
9171 tenc_data = (const guint8 *) tenc->data + 12;
9172 isEncrypted = QT_UINT24 (tenc_data);
9173 iv_size = QT_UINT8 (tenc_data + 3);
9174 default_kid = (tenc_data + 4);
9175 kid_buf = gst_buffer_new_allocate (NULL, 16, NULL);
9176 gst_buffer_fill (kid_buf, 0, default_kid, 16);
9177 if (info->default_properties)
9178 gst_structure_free (info->default_properties);
9179 info->default_properties =
9180 gst_structure_new ("application/x-cenc",
9181 "iv_size", G_TYPE_UINT, iv_size,
9182 "encrypted", G_TYPE_BOOLEAN, (isEncrypted == 1),
9183 "kid", GST_TYPE_BUFFER, kid_buf, NULL);
9184 GST_DEBUG_OBJECT (qtdemux, "default sample properties: "
9185 "is_encrypted=%u, iv_size=%u", isEncrypted, iv_size);
9186 gst_buffer_unref (kid_buf);
9192 * With each track we associate a new QtDemuxStream that contains all the info
9194 * traks that do not decode to something (like strm traks) will not have a pad.
9197 qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
9217 QtDemuxStream *stream = NULL;
9218 gboolean new_stream = FALSE;
9219 gchar *codec = NULL;
9220 const guint8 *stsd_data;
9221 guint16 lang_code; /* quicktime lang code or packed iso code */
9223 guint32 tkhd_flags = 0;
9224 guint8 tkhd_version = 0;
9226 guint value_size, stsd_len, len;
9230 GST_DEBUG_OBJECT (qtdemux, "parse_trak");
9232 if (!qtdemux_tree_get_child_by_type_full (trak, FOURCC_tkhd, &tkhd)
9233 || !gst_byte_reader_get_uint8 (&tkhd, &tkhd_version)
9234 || !gst_byte_reader_get_uint24_be (&tkhd, &tkhd_flags))
9237 /* pick between 64 or 32 bits */
9238 value_size = tkhd_version == 1 ? 8 : 4;
9239 if (!gst_byte_reader_skip (&tkhd, value_size * 2) ||
9240 !gst_byte_reader_get_uint32_be (&tkhd, &track_id))
9243 if (!qtdemux->got_moov) {
9244 if (qtdemux_find_stream (qtdemux, track_id))
9245 goto existing_stream;
9246 stream = _create_stream ();
9247 stream->track_id = track_id;
9250 stream = qtdemux_find_stream (qtdemux, track_id);
9252 GST_WARNING_OBJECT (qtdemux, "Stream not found, going to ignore it");
9256 /* flush samples data from this track from previous moov */
9257 gst_qtdemux_stream_flush_segments_data (qtdemux, stream);
9258 gst_qtdemux_stream_flush_samples_data (qtdemux, stream);
9260 /* need defaults for fragments */
9261 qtdemux_parse_trex (qtdemux, stream, &dummy, &dummy, &dummy);
9263 if (stream->pending_tags == NULL)
9264 stream->pending_tags = gst_tag_list_new_empty ();
9266 if ((tkhd_flags & 1) == 0)
9267 stream->disabled = TRUE;
9269 GST_LOG_OBJECT (qtdemux, "track[tkhd] version/flags/id: 0x%02x/%06x/%u",
9270 tkhd_version, tkhd_flags, stream->track_id);
9272 if (!(mdia = qtdemux_tree_get_child_by_type (trak, FOURCC_mdia)))
9275 if (!(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mdhd))) {
9276 /* be nice for some crooked mjp2 files that use mhdr for mdhd */
9277 if (qtdemux->major_brand != FOURCC_mjp2 ||
9278 !(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mhdr)))
9282 len = QT_UINT32 ((guint8 *) mdhd->data);
9283 version = QT_UINT32 ((guint8 *) mdhd->data + 8);
9284 GST_LOG_OBJECT (qtdemux, "track version/flags: %08x", version);
9285 if (version == 0x01000000) {
9288 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 28);
9289 stream->duration = QT_UINT64 ((guint8 *) mdhd->data + 32);
9290 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 36);
9294 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 20);
9295 stream->duration = QT_UINT32 ((guint8 *) mdhd->data + 24);
9296 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 28);
9299 if (lang_code < 0x400) {
9300 qtdemux_lang_map_qt_code_to_iso (stream->lang_id, lang_code);
9301 } else if (lang_code == 0x7fff) {
9302 stream->lang_id[0] = 0; /* unspecified */
9304 stream->lang_id[0] = 0x60 + ((lang_code >> 10) & 0x1F);
9305 stream->lang_id[1] = 0x60 + ((lang_code >> 5) & 0x1F);
9306 stream->lang_id[2] = 0x60 + (lang_code & 0x1F);
9307 stream->lang_id[3] = 0;
9310 GST_LOG_OBJECT (qtdemux, "track timescale: %" G_GUINT32_FORMAT,
9312 GST_LOG_OBJECT (qtdemux, "track duration: %" G_GUINT64_FORMAT,
9314 GST_LOG_OBJECT (qtdemux, "track language code/id: 0x%04x/%s",
9315 lang_code, stream->lang_id);
9317 if (G_UNLIKELY (stream->timescale == 0 || qtdemux->timescale == 0))
9320 if ((tref = qtdemux_tree_get_child_by_type (trak, FOURCC_tref))) {
9321 /* chapters track reference */
9322 GNode *chap = qtdemux_tree_get_child_by_type (tref, FOURCC_chap);
9324 gsize length = GST_READ_UINT32_BE (chap->data);
9325 if (qtdemux->chapters_track_id)
9326 GST_FIXME_OBJECT (qtdemux, "Multiple CHAP tracks");
9329 qtdemux->chapters_track_id =
9330 GST_READ_UINT32_BE ((gint8 *) chap->data + 8);
9335 /* fragmented files may have bogus duration in moov */
9336 if (!qtdemux->fragmented &&
9337 qtdemux->duration != G_MAXINT64 && stream->duration != G_MAXINT32) {
9338 guint64 tdur1, tdur2;
9340 /* don't overflow */
9341 tdur1 = stream->timescale * (guint64) qtdemux->duration;
9342 tdur2 = qtdemux->timescale * (guint64) stream->duration;
9345 * some of those trailers, nowadays, have prologue images that are
9346 * themselves video tracks as well. I haven't really found a way to
9347 * identify those yet, except for just looking at their duration. */
9348 if (tdur1 != 0 && (tdur2 * 10 / tdur1) < 2) {
9349 GST_WARNING_OBJECT (qtdemux,
9350 "Track shorter than 20%% (%" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT
9351 " vs. %" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT ") of the stream "
9352 "found, assuming preview image or something; skipping track",
9353 stream->duration, stream->timescale, qtdemux->duration,
9354 qtdemux->timescale);
9356 gst_qtdemux_stream_free (qtdemux, stream);
9361 if (!(hdlr = qtdemux_tree_get_child_by_type (mdia, FOURCC_hdlr)))
9364 GST_LOG_OBJECT (qtdemux, "track type: %" GST_FOURCC_FORMAT,
9365 GST_FOURCC_ARGS (QT_FOURCC ((guint8 *) hdlr->data + 12)));
9367 len = QT_UINT32 ((guint8 *) hdlr->data);
9369 stream->subtype = QT_FOURCC ((guint8 *) hdlr->data + 16);
9370 GST_LOG_OBJECT (qtdemux, "track subtype: %" GST_FOURCC_FORMAT,
9371 GST_FOURCC_ARGS (stream->subtype));
9373 if (!(minf = qtdemux_tree_get_child_by_type (mdia, FOURCC_minf)))
9376 if (!(stbl = qtdemux_tree_get_child_by_type (minf, FOURCC_stbl)))
9379 /*parse svmi header if existing */
9380 svmi = qtdemux_tree_get_child_by_type (stbl, FOURCC_svmi);
9382 len = QT_UINT32 ((guint8 *) svmi->data);
9383 version = QT_UINT32 ((guint8 *) svmi->data + 8);
9385 GstVideoMultiviewMode mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
9386 GstVideoMultiviewFlags flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
9387 guint8 frame_type, frame_layout;
9389 /* MPEG-A stereo video */
9390 if (qtdemux->major_brand == FOURCC_ss02)
9391 flags |= GST_VIDEO_MULTIVIEW_FLAGS_MIXED_MONO;
9393 frame_type = QT_UINT8 ((guint8 *) svmi->data + 12);
9394 frame_layout = QT_UINT8 ((guint8 *) svmi->data + 13) & 0x01;
9395 switch (frame_type) {
9397 mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
9400 mode = GST_VIDEO_MULTIVIEW_MODE_ROW_INTERLEAVED;
9403 mode = GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME;
9406 /* mode 3 is primary/secondary view sequence, ie
9407 * left/right views in separate tracks. See section 7.2
9408 * of ISO/IEC 23000-11:2009 */
9409 GST_FIXME_OBJECT (qtdemux,
9410 "Implement stereo video in separate streams");
9413 if ((frame_layout & 0x1) == 0)
9414 flags |= GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
9416 GST_LOG_OBJECT (qtdemux,
9417 "StereoVideo: composition type: %u, is_left_first: %u",
9418 frame_type, frame_layout);
9419 stream->multiview_mode = mode;
9420 stream->multiview_flags = flags;
9425 if (!(stsd = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsd)))
9427 stsd_data = (const guint8 *) stsd->data;
9429 /* stsd should at least have one entry */
9430 stsd_len = QT_UINT32 (stsd_data);
9431 if (stsd_len < 24) {
9432 /* .. but skip stream with empty stsd produced by some Vivotek cameras */
9433 if (stream->subtype == FOURCC_vivo) {
9435 gst_qtdemux_stream_free (qtdemux, stream);
9442 GST_LOG_OBJECT (qtdemux, "stsd len: %d", stsd_len);
9444 /* and that entry should fit within stsd */
9445 len = QT_UINT32 (stsd_data + 16);
9446 if (len > stsd_len + 16)
9449 stream->fourcc = fourcc = QT_FOURCC (stsd_data + 16 + 4);
9450 GST_LOG_OBJECT (qtdemux, "stsd type: %" GST_FOURCC_FORMAT,
9451 GST_FOURCC_ARGS (stream->fourcc));
9452 GST_LOG_OBJECT (qtdemux, "stsd type len: %d", len);
9454 if ((fourcc == FOURCC_drms) || (fourcc == FOURCC_drmi))
9455 goto error_encrypted;
9457 if (fourcc == FOURCC_encv || fourcc == FOURCC_enca) {
9458 GNode *enc = qtdemux_tree_get_child_by_type (stsd, fourcc);
9459 stream->protected = TRUE;
9460 if (!qtdemux_parse_protection_scheme_info (qtdemux, stream, enc, &fourcc))
9461 GST_ERROR_OBJECT (qtdemux, "Failed to parse protection scheme info");
9464 if (stream->subtype == FOURCC_vide) {
9465 guint32 w = 0, h = 0;
9467 gint depth, palette_size, palette_count;
9469 guint32 *palette_data = NULL;
9471 stream->sampled = TRUE;
9473 /* version 1 uses some 64-bit ints */
9474 if (!gst_byte_reader_skip (&tkhd, 20 + value_size))
9477 if (!qtdemux_parse_transformation_matrix (qtdemux, &tkhd, matrix, "tkhd"))
9480 if (!gst_byte_reader_get_uint32_be (&tkhd, &w)
9481 || !gst_byte_reader_get_uint32_be (&tkhd, &h))
9484 stream->display_width = w >> 16;
9485 stream->display_height = h >> 16;
9487 qtdemux_inspect_transformation_matrix (qtdemux, stream, matrix,
9488 &stream->pending_tags);
9494 stream->width = QT_UINT16 (stsd_data + offset + 32);
9495 stream->height = QT_UINT16 (stsd_data + offset + 34);
9496 stream->fps_n = 0; /* this is filled in later */
9497 stream->fps_d = 0; /* this is filled in later */
9498 stream->bits_per_sample = QT_UINT16 (stsd_data + offset + 82);
9499 stream->color_table_id = QT_UINT16 (stsd_data + offset + 84);
9501 /* if color_table_id is 0, ctab atom must follow; however some files
9502 * produced by TMPEGEnc have color_table_id = 0 and no ctab atom, so
9503 * if color table is not present we'll correct the value */
9504 if (stream->color_table_id == 0 &&
9505 (len < 90 || QT_FOURCC (stsd_data + offset + 86) != FOURCC_ctab)) {
9506 stream->color_table_id = -1;
9509 GST_LOG_OBJECT (qtdemux, "width %d, height %d, bps %d, color table id %d",
9510 stream->width, stream->height, stream->bits_per_sample,
9511 stream->color_table_id);
9513 depth = stream->bits_per_sample;
9515 /* more than 32 bits means grayscale */
9516 gray = (depth > 32);
9517 /* low 32 bits specify the depth */
9520 /* different number of palette entries is determined by depth. */
9522 if ((depth == 1) || (depth == 2) || (depth == 4) || (depth == 8))
9523 palette_count = (1 << depth);
9524 palette_size = palette_count * 4;
9526 if (stream->color_table_id) {
9527 switch (palette_count) {
9531 palette_data = g_memdup (ff_qt_default_palette_2, palette_size);
9534 palette_data = g_memdup (ff_qt_default_palette_4, palette_size);
9538 palette_data = g_memdup (ff_qt_grayscale_palette_16, palette_size);
9540 palette_data = g_memdup (ff_qt_default_palette_16, palette_size);
9544 palette_data = g_memdup (ff_qt_grayscale_palette_256, palette_size);
9546 palette_data = g_memdup (ff_qt_default_palette_256, palette_size);
9549 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
9550 (_("The video in this file might not play correctly.")),
9551 ("unsupported palette depth %d", depth));
9555 gint i, j, start, end;
9561 start = QT_UINT32 (stsd_data + offset + 86);
9562 palette_count = QT_UINT16 (stsd_data + offset + 90);
9563 end = QT_UINT16 (stsd_data + offset + 92);
9565 GST_LOG_OBJECT (qtdemux, "start %d, end %d, palette_count %d",
9566 start, end, palette_count);
9573 if (len < 94 + (end - start) * 8)
9576 /* palette is always the same size */
9577 palette_data = g_malloc0 (256 * 4);
9578 palette_size = 256 * 4;
9580 for (j = 0, i = start; i <= end; j++, i++) {
9583 a = QT_UINT16 (stsd_data + offset + 94 + (j * 8));
9584 r = QT_UINT16 (stsd_data + offset + 96 + (j * 8));
9585 g = QT_UINT16 (stsd_data + offset + 98 + (j * 8));
9586 b = QT_UINT16 (stsd_data + offset + 100 + (j * 8));
9588 palette_data[i] = ((a & 0xff00) << 16) | ((r & 0xff00) << 8) |
9589 (g & 0xff00) | (b >> 8);
9594 gst_caps_unref (stream->caps);
9597 qtdemux_video_caps (qtdemux, stream, fourcc, stsd_data, &codec);
9598 if (G_UNLIKELY (!stream->caps)) {
9599 g_free (palette_data);
9600 goto unknown_stream;
9604 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
9605 GST_TAG_VIDEO_CODEC, codec, NULL);
9614 if (stream->rgb8_palette)
9615 gst_memory_unref (stream->rgb8_palette);
9616 stream->rgb8_palette = gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY,
9617 palette_data, palette_size, 0, palette_size, palette_data, g_free);
9619 s = gst_caps_get_structure (stream->caps, 0);
9621 /* non-raw video has a palette_data property. raw video has the palette as
9622 * an extra plane that we append to the output buffers before we push
9624 if (!gst_structure_has_name (s, "video/x-raw")) {
9627 palette = gst_buffer_new ();
9628 gst_buffer_append_memory (palette, stream->rgb8_palette);
9629 stream->rgb8_palette = NULL;
9631 gst_caps_set_simple (stream->caps, "palette_data",
9632 GST_TYPE_BUFFER, palette, NULL);
9633 gst_buffer_unref (palette);
9635 } else if (palette_count != 0) {
9636 GST_ELEMENT_WARNING (qtdemux, STREAM, NOT_IMPLEMENTED,
9637 (NULL), ("Unsupported palette depth %d", depth));
9640 GST_LOG_OBJECT (qtdemux, "frame count: %u",
9641 QT_UINT16 (stsd_data + offset + 48));
9646 /* pick 'the' stsd child */
9647 if (!stream->protected)
9648 mp4v = qtdemux_tree_get_child_by_type (stsd, fourcc);
9650 mp4v = qtdemux_tree_get_child_by_type (stsd, FOURCC_encv);
9653 esds = qtdemux_tree_get_child_by_type (mp4v, FOURCC_esds);
9654 pasp = qtdemux_tree_get_child_by_type (mp4v, FOURCC_pasp);
9655 colr = qtdemux_tree_get_child_by_type (mp4v, FOURCC_colr);
9659 const guint8 *pasp_data = (const guint8 *) pasp->data;
9661 stream->par_w = QT_UINT32 (pasp_data + 8);
9662 stream->par_h = QT_UINT32 (pasp_data + 12);
9669 const guint8 *colr_data = (const guint8 *) colr->data;
9670 gint len = QT_UINT32 (colr_data);
9672 if (len == 19 || len == 18) {
9673 guint32 color_type = GST_READ_UINT32_LE (colr_data + 8);
9675 if (color_type == FOURCC_nclx || color_type == FOURCC_nclc) {
9676 guint16 primaries = GST_READ_UINT16_BE (colr_data + 12);
9677 guint16 transfer_function = GST_READ_UINT16_BE (colr_data + 14);
9678 guint16 matrix = GST_READ_UINT16_BE (colr_data + 16);
9679 gboolean full_range = len == 19 ? colr_data[17] >> 7 : FALSE;
9681 switch (primaries) {
9683 stream->colorimetry.primaries = GST_VIDEO_COLOR_PRIMARIES_BT709;
9686 stream->colorimetry.primaries = GST_VIDEO_COLOR_PRIMARIES_BT470BG;
9689 stream->colorimetry.primaries =
9690 GST_VIDEO_COLOR_PRIMARIES_SMPTE170M;
9693 stream->colorimetry.primaries = GST_VIDEO_COLOR_PRIMARIES_BT2020;
9699 switch (transfer_function) {
9701 stream->colorimetry.transfer = GST_VIDEO_TRANSFER_BT709;
9704 stream->colorimetry.transfer = GST_VIDEO_TRANSFER_SMPTE240M;
9712 stream->colorimetry.matrix = GST_VIDEO_COLOR_MATRIX_BT709;
9715 stream->colorimetry.matrix = GST_VIDEO_COLOR_MATRIX_BT601;
9718 stream->colorimetry.matrix = GST_VIDEO_COLOR_MATRIX_SMPTE240M;
9721 stream->colorimetry.matrix = GST_VIDEO_COLOR_MATRIX_BT2020;
9727 stream->colorimetry.range =
9728 full_range ? GST_VIDEO_COLOR_RANGE_0_255 :
9729 GST_VIDEO_COLOR_RANGE_16_235;
9731 GST_DEBUG_OBJECT (qtdemux, "Unsupported color type");
9734 GST_WARNING_OBJECT (qtdemux, "Invalid colr atom size");
9739 gst_qtdemux_handle_esds (qtdemux, stream, esds, stream->pending_tags);
9746 gint len = QT_UINT32 (stsd_data) - 0x66;
9747 const guint8 *avc_data = stsd_data + 0x66;
9750 while (len >= 0x8) {
9753 if (QT_UINT32 (avc_data) <= len)
9754 size = QT_UINT32 (avc_data) - 0x8;
9759 /* No real data, so break out */
9762 switch (QT_FOURCC (avc_data + 0x4)) {
9765 /* parse, if found */
9768 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
9770 /* First 4 bytes are the length of the atom, the next 4 bytes
9771 * are the fourcc, the next 1 byte is the version, and the
9772 * subsequent bytes are profile_tier_level structure like data. */
9773 gst_codec_utils_h264_caps_set_level_and_profile (stream->caps,
9774 avc_data + 8 + 1, size - 1);
9775 buf = gst_buffer_new_and_alloc (size);
9776 gst_buffer_fill (buf, 0, avc_data + 0x8, size);
9777 gst_caps_set_simple (stream->caps,
9778 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9779 gst_buffer_unref (buf);
9787 GST_DEBUG_OBJECT (qtdemux, "found strf codec_data in stsd");
9789 /* First 4 bytes are the length of the atom, the next 4 bytes
9790 * are the fourcc, next 40 bytes are BITMAPINFOHEADER,
9791 * next 1 byte is the version, and the
9792 * subsequent bytes are sequence parameter set like data. */
9794 size -= 40; /* we'll be skipping BITMAPINFOHEADER */
9796 gst_codec_utils_h264_caps_set_level_and_profile (stream->caps,
9797 avc_data + 8 + 40 + 1, size - 1);
9799 buf = gst_buffer_new_and_alloc (size);
9800 gst_buffer_fill (buf, 0, avc_data + 8 + 40, size);
9801 gst_caps_set_simple (stream->caps,
9802 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9803 gst_buffer_unref (buf);
9809 guint avg_bitrate, max_bitrate;
9811 /* bufferSizeDB, maxBitrate and avgBitrate - 4 bytes each */
9815 max_bitrate = QT_UINT32 (avc_data + 0xc);
9816 avg_bitrate = QT_UINT32 (avc_data + 0x10);
9818 if (!max_bitrate && !avg_bitrate)
9821 /* Some muxers seem to swap the average and maximum bitrates
9822 * (I'm looking at you, YouTube), so we swap for sanity. */
9823 if (max_bitrate > 0 && max_bitrate < avg_bitrate) {
9824 guint temp = avg_bitrate;
9826 avg_bitrate = max_bitrate;
9830 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
9831 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
9832 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
9834 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
9835 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
9836 GST_TAG_BITRATE, avg_bitrate, NULL);
9847 avc_data += size + 8;
9856 gint len = QT_UINT32 (stsd_data) - 0x66;
9857 const guint8 *hevc_data = stsd_data + 0x66;
9860 while (len >= 0x8) {
9863 if (QT_UINT32 (hevc_data) <= len)
9864 size = QT_UINT32 (hevc_data) - 0x8;
9869 /* No real data, so break out */
9872 switch (QT_FOURCC (hevc_data + 0x4)) {
9875 /* parse, if found */
9878 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
9880 /* First 4 bytes are the length of the atom, the next 4 bytes
9881 * are the fourcc, the next 1 byte is the version, and the
9882 * subsequent bytes are sequence parameter set like data. */
9883 gst_codec_utils_h265_caps_set_level_tier_and_profile
9884 (stream->caps, hevc_data + 8 + 1, size - 1);
9886 buf = gst_buffer_new_and_alloc (size);
9887 gst_buffer_fill (buf, 0, hevc_data + 0x8, size);
9888 gst_caps_set_simple (stream->caps,
9889 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9890 gst_buffer_unref (buf);
9897 hevc_data += size + 8;
9908 GST_DEBUG_OBJECT (qtdemux, "found %" GST_FOURCC_FORMAT,
9909 GST_FOURCC_ARGS (fourcc));
9911 /* codec data might be in glbl extension atom */
9913 qtdemux_tree_get_child_by_type (mp4v, FOURCC_glbl) : NULL;
9919 GST_DEBUG_OBJECT (qtdemux, "found glbl data in stsd");
9921 len = QT_UINT32 (data);
9924 buf = gst_buffer_new_and_alloc (len);
9925 gst_buffer_fill (buf, 0, data + 8, len);
9926 gst_caps_set_simple (stream->caps,
9927 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9928 gst_buffer_unref (buf);
9935 /* see annex I of the jpeg2000 spec */
9936 GNode *jp2h, *ihdr, *colr, *mjp2, *field, *prefix, *cmap, *cdef;
9938 const gchar *colorspace = NULL;
9940 guint32 ncomp_map = 0;
9941 gint32 *comp_map = NULL;
9942 guint32 nchan_def = 0;
9943 gint32 *chan_def = NULL;
9945 GST_DEBUG_OBJECT (qtdemux, "found mjp2");
9946 /* some required atoms */
9947 mjp2 = qtdemux_tree_get_child_by_type (stsd, FOURCC_mjp2);
9950 jp2h = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2h);
9954 /* number of components; redundant with info in codestream, but useful
9956 ihdr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_ihdr);
9957 if (!ihdr || QT_UINT32 (ihdr->data) != 22)
9959 ncomp = QT_UINT16 (((guint8 *) ihdr->data) + 16);
9961 colr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_colr);
9964 GST_DEBUG_OBJECT (qtdemux, "found colr");
9965 /* extract colour space info */
9966 if (QT_UINT8 ((guint8 *) colr->data + 8) == 1) {
9967 switch (QT_UINT32 ((guint8 *) colr->data + 11)) {
9969 colorspace = "sRGB";
9972 colorspace = "GRAY";
9975 colorspace = "sYUV";
9983 /* colr is required, and only values 16, 17, and 18 are specified,
9984 so error if we have no colorspace */
9987 /* extract component mapping */
9988 cmap = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cmap);
9990 guint32 cmap_len = 0;
9992 cmap_len = QT_UINT32 (cmap->data);
9993 if (cmap_len >= 8) {
9994 /* normal box, subtract off header */
9996 /* cmap: { u16 cmp; u8 mtyp; u8 pcol; }* */
9997 if (cmap_len % 4 == 0) {
9998 ncomp_map = (cmap_len / 4);
9999 comp_map = g_new0 (gint32, ncomp_map);
10000 for (i = 0; i < ncomp_map; i++) {
10003 cmp = QT_UINT16 (((guint8 *) cmap->data) + 8 + i * 4);
10004 mtyp = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 2);
10005 pcol = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 3);
10006 comp_map[i] = (mtyp << 24) | (pcol << 16) | cmp;
10011 /* extract channel definitions */
10012 cdef = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cdef);
10014 guint32 cdef_len = 0;
10016 cdef_len = QT_UINT32 (cdef->data);
10017 if (cdef_len >= 10) {
10018 /* normal box, subtract off header and len */
10020 /* cdef: u16 n; { u16 cn; u16 typ; u16 asoc; }* */
10021 if (cdef_len % 6 == 0) {
10022 nchan_def = (cdef_len / 6);
10023 chan_def = g_new0 (gint32, nchan_def);
10024 for (i = 0; i < nchan_def; i++)
10026 for (i = 0; i < nchan_def; i++) {
10027 guint16 cn, typ, asoc;
10028 cn = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6);
10029 typ = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 2);
10030 asoc = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 4);
10031 if (cn < nchan_def) {
10034 chan_def[cn] = asoc;
10037 chan_def[cn] = 0; /* alpha */
10040 chan_def[cn] = -typ;
10048 gst_caps_set_simple (stream->caps,
10049 "num-components", G_TYPE_INT, ncomp, NULL);
10050 gst_caps_set_simple (stream->caps,
10051 "colorspace", G_TYPE_STRING, colorspace, NULL);
10054 GValue arr = { 0, };
10055 GValue elt = { 0, };
10057 g_value_init (&arr, GST_TYPE_ARRAY);
10058 g_value_init (&elt, G_TYPE_INT);
10059 for (i = 0; i < ncomp_map; i++) {
10060 g_value_set_int (&elt, comp_map[i]);
10061 gst_value_array_append_value (&arr, &elt);
10063 gst_structure_set_value (gst_caps_get_structure (stream->caps, 0),
10064 "component-map", &arr);
10065 g_value_unset (&elt);
10066 g_value_unset (&arr);
10071 GValue arr = { 0, };
10072 GValue elt = { 0, };
10074 g_value_init (&arr, GST_TYPE_ARRAY);
10075 g_value_init (&elt, G_TYPE_INT);
10076 for (i = 0; i < nchan_def; i++) {
10077 g_value_set_int (&elt, chan_def[i]);
10078 gst_value_array_append_value (&arr, &elt);
10080 gst_structure_set_value (gst_caps_get_structure (stream->caps, 0),
10081 "channel-definitions", &arr);
10082 g_value_unset (&elt);
10083 g_value_unset (&arr);
10087 /* some optional atoms */
10088 field = qtdemux_tree_get_child_by_type (mjp2, FOURCC_fiel);
10089 prefix = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2x);
10091 /* indicate possible fields in caps */
10093 data = (guint8 *) field->data + 8;
10095 gst_caps_set_simple (stream->caps, "fields", G_TYPE_INT,
10096 (gint) * data, NULL);
10098 /* add codec_data if provided */
10103 GST_DEBUG_OBJECT (qtdemux, "found prefix data in stsd");
10104 data = prefix->data;
10105 len = QT_UINT32 (data);
10108 buf = gst_buffer_new_and_alloc (len);
10109 gst_buffer_fill (buf, 0, data + 8, len);
10110 gst_caps_set_simple (stream->caps,
10111 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10112 gst_buffer_unref (buf);
10119 /* https://developer.apple.com/standards/qtff-2001.pdf,
10120 * page 92, "Video Sample Description", under table 3.1 */
10123 const off_t compressor_offset =
10124 16 + 4 + 4 * 3 + 2 * 2 + 2 * 4 + 4 + 2;
10125 const off_t min_size = compressor_offset + 32 + 2 + 2;
10128 guint16 color_table_id = 0;
10131 GST_DEBUG_OBJECT (qtdemux, "found jpeg");
10133 /* recover information on interlaced/progressive */
10134 jpeg = qtdemux_tree_get_child_by_type (stsd, FOURCC_jpeg);
10138 len = QT_UINT32 (jpeg->data);
10139 GST_DEBUG_OBJECT (qtdemux, "Found jpeg: len %u, need %lu", len,
10141 if (len >= min_size) {
10142 gst_byte_reader_init (&br, jpeg->data, len);
10144 gst_byte_reader_skip (&br, compressor_offset + 32 + 2);
10145 gst_byte_reader_get_uint16_le (&br, &color_table_id);
10146 if (color_table_id != 0) {
10147 /* the spec says there can be concatenated chunks in the data, and we want
10148 * to find one called field. Walk through them. */
10149 off_t offset = min_size;
10150 while (offset + 8 < len) {
10152 ok = gst_byte_reader_get_uint32_le (&br, &size);
10153 ok &= gst_byte_reader_get_uint32_le (&br, &tag);
10154 if (!ok || size < 8) {
10155 GST_WARNING_OBJECT (qtdemux,
10156 "Failed to walk optional chunk list");
10159 GST_DEBUG_OBJECT (qtdemux,
10160 "Found optional %4.4s chunk, size %u", (const char *) &tag,
10162 if (tag == FOURCC_fiel) {
10163 guint8 n_fields, ordering;
10164 gst_byte_reader_get_uint8 (&br, &n_fields);
10165 gst_byte_reader_get_uint8 (&br, &ordering);
10166 if (n_fields == 1 || n_fields == 2) {
10167 GST_DEBUG_OBJECT (qtdemux,
10168 "Found fiel tag with %u fields, ordering %u", n_fields,
10171 gst_caps_set_simple (stream->caps, "interlace-mode",
10172 G_TYPE_STRING, "interleaved", NULL);
10174 GST_WARNING_OBJECT (qtdemux,
10175 "Found fiel tag with invalid fields (%u)", n_fields);
10181 GST_DEBUG_OBJECT (qtdemux,
10182 "Color table ID is 0, not trying to get interlacedness");
10185 GST_WARNING_OBJECT (qtdemux,
10186 "Length of jpeg chunk is too small, not trying to get interlacedness");
10195 GstBuffer *seqh = NULL;
10196 guint8 *gamma_data = NULL;
10197 gint len = QT_UINT32 (stsd_data);
10199 qtdemux_parse_svq3_stsd_data (qtdemux, stsd, &gamma_data, &seqh);
10201 gst_caps_set_simple (stream->caps, "applied-gamma", G_TYPE_DOUBLE,
10202 QT_FP32 (gamma_data), NULL);
10205 /* sorry for the bad name, but we don't know what this is, other
10206 * than its own fourcc */
10207 gst_caps_set_simple (stream->caps, "seqh", GST_TYPE_BUFFER, seqh,
10211 GST_DEBUG_OBJECT (qtdemux, "found codec_data in stsd");
10212 buf = gst_buffer_new_and_alloc (len);
10213 gst_buffer_fill (buf, 0, stsd_data, len);
10214 gst_caps_set_simple (stream->caps,
10215 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10216 gst_buffer_unref (buf);
10222 gst_caps_set_simple (stream->caps,
10223 "depth", G_TYPE_INT, QT_UINT16 (stsd_data + offset + 82), NULL);
10228 GNode *xith, *xdxt;
10230 GST_DEBUG_OBJECT (qtdemux, "found XiTh");
10231 xith = qtdemux_tree_get_child_by_type (stsd, FOURCC_XiTh);
10235 xdxt = qtdemux_tree_get_child_by_type (xith, FOURCC_XdxT);
10239 GST_DEBUG_OBJECT (qtdemux, "found XdxT node");
10240 /* collect the headers and store them in a stream list so that we can
10241 * send them out first */
10242 qtdemux_parse_theora_extension (qtdemux, stream, xdxt);
10252 GST_DEBUG_OBJECT (qtdemux, "parse ovc1 header");
10253 ovc1 = qtdemux_tree_get_child_by_type (stsd, FOURCC_ovc1);
10256 ovc1_data = ovc1->data;
10257 ovc1_len = QT_UINT32 (ovc1_data);
10258 if (ovc1_len <= 198) {
10259 GST_WARNING_OBJECT (qtdemux, "Too small ovc1 header, skipping");
10262 buf = gst_buffer_new_and_alloc (ovc1_len - 198);
10263 gst_buffer_fill (buf, 0, ovc1_data + 198, ovc1_len - 198);
10264 gst_caps_set_simple (stream->caps,
10265 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10266 gst_buffer_unref (buf);
10271 gint len = QT_UINT32 (stsd_data) - 0x66;
10272 const guint8 *vc1_data = stsd_data + 0x66;
10278 if (QT_UINT32 (vc1_data) <= len)
10279 size = QT_UINT32 (vc1_data) - 8;
10284 /* No real data, so break out */
10287 switch (QT_FOURCC (vc1_data + 0x4)) {
10288 case GST_MAKE_FOURCC ('d', 'v', 'c', '1'):
10292 GST_DEBUG_OBJECT (qtdemux, "found dvc1 codec_data in stsd");
10293 buf = gst_buffer_new_and_alloc (size);
10294 gst_buffer_fill (buf, 0, vc1_data + 8, size);
10295 gst_caps_set_simple (stream->caps,
10296 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10297 gst_buffer_unref (buf);
10304 vc1_data += size + 8;
10313 GST_INFO_OBJECT (qtdemux,
10314 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
10315 GST_FOURCC_ARGS (fourcc), stream->caps);
10317 } else if (stream->subtype == FOURCC_soun) {
10318 int version, samplesize;
10319 guint16 compression_id;
10320 gboolean amrwb = FALSE;
10323 /* sample description entry (16) + sound sample description v0 (20) */
10327 version = QT_UINT32 (stsd_data + offset);
10328 stream->n_channels = QT_UINT16 (stsd_data + offset + 8);
10329 samplesize = QT_UINT16 (stsd_data + offset + 10);
10330 compression_id = QT_UINT16 (stsd_data + offset + 12);
10331 stream->rate = QT_FP32 (stsd_data + offset + 16);
10333 GST_LOG_OBJECT (qtdemux, "version/rev: %08x", version);
10334 GST_LOG_OBJECT (qtdemux, "vendor: %08x",
10335 QT_UINT32 (stsd_data + offset + 4));
10336 GST_LOG_OBJECT (qtdemux, "n_channels: %d", stream->n_channels);
10337 GST_LOG_OBJECT (qtdemux, "sample_size: %d", samplesize);
10338 GST_LOG_OBJECT (qtdemux, "compression_id: %d", compression_id);
10339 GST_LOG_OBJECT (qtdemux, "packet size: %d",
10340 QT_UINT16 (stsd_data + offset + 14));
10341 GST_LOG_OBJECT (qtdemux, "sample rate: %g", stream->rate);
10343 if (compression_id == 0xfffe)
10344 stream->sampled = TRUE;
10346 /* first assume uncompressed audio */
10347 stream->bytes_per_sample = samplesize / 8;
10348 stream->samples_per_frame = stream->n_channels;
10349 stream->bytes_per_frame = stream->n_channels * stream->bytes_per_sample;
10350 stream->samples_per_packet = stream->samples_per_frame;
10351 stream->bytes_per_packet = stream->bytes_per_sample;
10355 /* Yes, these have to be hard-coded */
10358 stream->samples_per_packet = 6;
10359 stream->bytes_per_packet = 1;
10360 stream->bytes_per_frame = 1 * stream->n_channels;
10361 stream->bytes_per_sample = 1;
10362 stream->samples_per_frame = 6 * stream->n_channels;
10367 stream->samples_per_packet = 3;
10368 stream->bytes_per_packet = 1;
10369 stream->bytes_per_frame = 1 * stream->n_channels;
10370 stream->bytes_per_sample = 1;
10371 stream->samples_per_frame = 3 * stream->n_channels;
10376 stream->samples_per_packet = 64;
10377 stream->bytes_per_packet = 34;
10378 stream->bytes_per_frame = 34 * stream->n_channels;
10379 stream->bytes_per_sample = 2;
10380 stream->samples_per_frame = 64 * stream->n_channels;
10386 stream->samples_per_packet = 1;
10387 stream->bytes_per_packet = 1;
10388 stream->bytes_per_frame = 1 * stream->n_channels;
10389 stream->bytes_per_sample = 1;
10390 stream->samples_per_frame = 1 * stream->n_channels;
10395 stream->samples_per_packet = 160;
10396 stream->bytes_per_packet = 33;
10397 stream->bytes_per_frame = 33 * stream->n_channels;
10398 stream->bytes_per_sample = 2;
10399 stream->samples_per_frame = 160 * stream->n_channels;
10406 if (version == 0x00010000) {
10407 /* sample description entry (16) + sound sample description v1 (20+16) */
10418 /* only parse extra decoding config for non-pcm audio */
10419 stream->samples_per_packet = QT_UINT32 (stsd_data + offset);
10420 stream->bytes_per_packet = QT_UINT32 (stsd_data + offset + 4);
10421 stream->bytes_per_frame = QT_UINT32 (stsd_data + offset + 8);
10422 stream->bytes_per_sample = QT_UINT32 (stsd_data + offset + 12);
10424 GST_LOG_OBJECT (qtdemux, "samples/packet: %d",
10425 stream->samples_per_packet);
10426 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
10427 stream->bytes_per_packet);
10428 GST_LOG_OBJECT (qtdemux, "bytes/frame: %d",
10429 stream->bytes_per_frame);
10430 GST_LOG_OBJECT (qtdemux, "bytes/sample: %d",
10431 stream->bytes_per_sample);
10433 if (!stream->sampled && stream->bytes_per_packet) {
10434 stream->samples_per_frame = (stream->bytes_per_frame /
10435 stream->bytes_per_packet) * stream->samples_per_packet;
10436 GST_LOG_OBJECT (qtdemux, "samples/frame: %d",
10437 stream->samples_per_frame);
10442 } else if (version == 0x00020000) {
10449 /* sample description entry (16) + sound sample description v2 (56) */
10453 qtfp.val = QT_UINT64 (stsd_data + offset + 4);
10454 stream->rate = qtfp.fp;
10455 stream->n_channels = QT_UINT32 (stsd_data + offset + 12);
10457 GST_LOG_OBJECT (qtdemux, "Sound sample description Version 2");
10458 GST_LOG_OBJECT (qtdemux, "sample rate: %g", stream->rate);
10459 GST_LOG_OBJECT (qtdemux, "n_channels: %d", stream->n_channels);
10460 GST_LOG_OBJECT (qtdemux, "bits/channel: %d",
10461 QT_UINT32 (stsd_data + offset + 20));
10462 GST_LOG_OBJECT (qtdemux, "format flags: %X",
10463 QT_UINT32 (stsd_data + offset + 24));
10464 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
10465 QT_UINT32 (stsd_data + offset + 28));
10466 GST_LOG_OBJECT (qtdemux, "LPCM frames/packet: %d",
10467 QT_UINT32 (stsd_data + offset + 32));
10468 } else if (version != 0x00000) {
10469 GST_WARNING_OBJECT (qtdemux, "unknown audio STSD version %08x", version);
10473 gst_caps_unref (stream->caps);
10475 stream->caps = qtdemux_audio_caps (qtdemux, stream, fourcc,
10476 stsd_data + 32, len - 16, &codec);
10484 in24 = qtdemux_tree_get_child_by_type (stsd, FOURCC_in24);
10486 enda = qtdemux_tree_get_child_by_type (in24, FOURCC_enda);
10488 wave = qtdemux_tree_get_child_by_type (in24, FOURCC_wave);
10490 enda = qtdemux_tree_get_child_by_type (wave, FOURCC_enda);
10493 int enda_value = QT_UINT16 ((guint8 *) enda->data + 8);
10494 gst_caps_set_simple (stream->caps,
10495 "format", G_TYPE_STRING, (enda_value) ? "S24LE" : "S24BE", NULL);
10502 const guint8 *owma_data;
10503 const gchar *codec_name = NULL;
10507 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
10508 /* FIXME this should also be gst_riff_strf_auds,
10509 * but the latter one is actually missing bits-per-sample :( */
10514 gint32 nSamplesPerSec;
10515 gint32 nAvgBytesPerSec;
10516 gint16 nBlockAlign;
10517 gint16 wBitsPerSample;
10520 WAVEFORMATEX *wfex;
10522 GST_DEBUG_OBJECT (qtdemux, "parse owma");
10523 owma = qtdemux_tree_get_child_by_type (stsd, FOURCC_owma);
10526 owma_data = owma->data;
10527 owma_len = QT_UINT32 (owma_data);
10528 if (owma_len <= 54) {
10529 GST_WARNING_OBJECT (qtdemux, "Too small owma header, skipping");
10532 wfex = (WAVEFORMATEX *) (owma_data + 36);
10533 buf = gst_buffer_new_and_alloc (owma_len - 54);
10534 gst_buffer_fill (buf, 0, owma_data + 54, owma_len - 54);
10535 if (wfex->wFormatTag == 0x0161) {
10536 codec_name = "Windows Media Audio";
10538 } else if (wfex->wFormatTag == 0x0162) {
10539 codec_name = "Windows Media Audio 9 Pro";
10541 } else if (wfex->wFormatTag == 0x0163) {
10542 codec_name = "Windows Media Audio 9 Lossless";
10543 /* is that correct? gstffmpegcodecmap.c is missing it, but
10544 * fluendo codec seems to support it */
10548 gst_caps_set_simple (stream->caps,
10549 "codec_data", GST_TYPE_BUFFER, buf,
10550 "wmaversion", G_TYPE_INT, version,
10551 "block_align", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->nBlockAlign),
10552 "bitrate", G_TYPE_INT, GST_READ_UINT32_LE (&wfex->nAvgBytesPerSec),
10553 "width", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->wBitsPerSample),
10554 "depth", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->wBitsPerSample),
10556 gst_buffer_unref (buf);
10560 codec = g_strdup (codec_name);
10566 gint len = QT_UINT32 (stsd_data) - offset;
10567 const guint8 *wfex_data = stsd_data + offset;
10568 const gchar *codec_name = NULL;
10570 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
10571 /* FIXME this should also be gst_riff_strf_auds,
10572 * but the latter one is actually missing bits-per-sample :( */
10577 gint32 nSamplesPerSec;
10578 gint32 nAvgBytesPerSec;
10579 gint16 nBlockAlign;
10580 gint16 wBitsPerSample;
10585 /* FIXME: unify with similar wavformatex parsing code above */
10586 GST_DEBUG_OBJECT (qtdemux, "parse wma, looking for wfex");
10592 if (QT_UINT32 (wfex_data) <= len)
10593 size = QT_UINT32 (wfex_data) - 8;
10598 /* No real data, so break out */
10601 switch (QT_FOURCC (wfex_data + 4)) {
10602 case GST_MAKE_FOURCC ('w', 'f', 'e', 'x'):
10604 GST_DEBUG_OBJECT (qtdemux, "found wfex in stsd");
10609 wfex.wFormatTag = GST_READ_UINT16_LE (wfex_data + 8 + 0);
10610 wfex.nChannels = GST_READ_UINT16_LE (wfex_data + 8 + 2);
10611 wfex.nSamplesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 4);
10612 wfex.nAvgBytesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 8);
10613 wfex.nBlockAlign = GST_READ_UINT16_LE (wfex_data + 8 + 12);
10614 wfex.wBitsPerSample = GST_READ_UINT16_LE (wfex_data + 8 + 14);
10615 wfex.cbSize = GST_READ_UINT16_LE (wfex_data + 8 + 16);
10617 GST_LOG_OBJECT (qtdemux, "Found wfex box in stsd:");
10618 GST_LOG_OBJECT (qtdemux, "FormatTag = 0x%04x, Channels = %u, "
10619 "SamplesPerSec = %u, AvgBytesPerSec = %u, BlockAlign = %u, "
10620 "BitsPerSample = %u, Size = %u", wfex.wFormatTag,
10621 wfex.nChannels, wfex.nSamplesPerSec, wfex.nAvgBytesPerSec,
10622 wfex.nBlockAlign, wfex.wBitsPerSample, wfex.cbSize);
10624 if (wfex.wFormatTag == 0x0161) {
10625 codec_name = "Windows Media Audio";
10627 } else if (wfex.wFormatTag == 0x0162) {
10628 codec_name = "Windows Media Audio 9 Pro";
10630 } else if (wfex.wFormatTag == 0x0163) {
10631 codec_name = "Windows Media Audio 9 Lossless";
10632 /* is that correct? gstffmpegcodecmap.c is missing it, but
10633 * fluendo codec seems to support it */
10637 gst_caps_set_simple (stream->caps,
10638 "wmaversion", G_TYPE_INT, version,
10639 "block_align", G_TYPE_INT, wfex.nBlockAlign,
10640 "bitrate", G_TYPE_INT, wfex.nAvgBytesPerSec,
10641 "width", G_TYPE_INT, wfex.wBitsPerSample,
10642 "depth", G_TYPE_INT, wfex.wBitsPerSample, NULL);
10644 if (size > wfex.cbSize) {
10647 buf = gst_buffer_new_and_alloc (size - wfex.cbSize);
10648 gst_buffer_fill (buf, 0, wfex_data + 8 + wfex.cbSize,
10649 size - wfex.cbSize);
10650 gst_caps_set_simple (stream->caps,
10651 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10652 gst_buffer_unref (buf);
10654 GST_WARNING_OBJECT (qtdemux, "no codec data");
10659 codec = g_strdup (codec_name);
10667 wfex_data += size + 8;
10674 const guint8 *opus_data;
10675 guint8 *channel_mapping = NULL;
10678 guint8 channel_mapping_family;
10679 guint8 stream_count;
10680 guint8 coupled_count;
10683 opus = qtdemux_tree_get_child_by_type (stsd, FOURCC_opus);
10684 opus_data = opus->data;
10686 channels = GST_READ_UINT8 (opus_data + 45);
10687 rate = GST_READ_UINT32_LE (opus_data + 48);
10688 channel_mapping_family = GST_READ_UINT8 (opus_data + 54);
10689 stream_count = GST_READ_UINT8 (opus_data + 55);
10690 coupled_count = GST_READ_UINT8 (opus_data + 56);
10692 if (channels > 0) {
10693 channel_mapping = g_malloc (channels * sizeof (guint8));
10694 for (i = 0; i < channels; i++)
10695 channel_mapping[i] = GST_READ_UINT8 (opus_data + i + 57);
10698 stream->caps = gst_codec_utils_opus_create_caps (rate, channels,
10699 channel_mapping_family, stream_count, coupled_count,
10711 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
10712 GST_TAG_AUDIO_CODEC, codec, NULL);
10716 /* some bitrate info may have ended up in caps */
10717 s = gst_caps_get_structure (stream->caps, 0);
10718 gst_structure_get_int (s, "bitrate", &bitrate);
10720 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
10721 GST_TAG_BITRATE, bitrate, NULL);
10724 if (stream->protected && fourcc == FOURCC_mp4a)
10725 mp4a = qtdemux_tree_get_child_by_type (stsd, FOURCC_enca);
10727 mp4a = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4a);
10732 wave = qtdemux_tree_get_child_by_type (mp4a, FOURCC_wave);
10734 esds = qtdemux_tree_get_child_by_type (wave, FOURCC_esds);
10736 esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
10740 /* If the fourcc's bottom 16 bits gives 'sm', then the top
10741 16 bits is a byte-swapped wave-style codec identifier,
10742 and we can find a WAVE header internally to a 'wave' atom here.
10743 This can more clearly be thought of as 'ms' as the top 16 bits, and a
10744 codec id as the bottom 16 bits - but byte-swapped to store in QT (which
10747 if ((fourcc & 0xffff) == (('s' << 8) | 'm')) {
10748 if (len < offset + 20) {
10749 GST_WARNING_OBJECT (qtdemux, "No wave atom in MS-style audio");
10751 guint32 datalen = QT_UINT32 (stsd_data + offset + 16);
10752 const guint8 *data = stsd_data + offset + 16;
10754 GNode *waveheadernode;
10756 wavenode = g_node_new ((guint8 *) data);
10757 if (qtdemux_parse_node (qtdemux, wavenode, data, datalen)) {
10758 const guint8 *waveheader;
10761 waveheadernode = qtdemux_tree_get_child_by_type (wavenode, fourcc);
10762 if (waveheadernode) {
10763 waveheader = (const guint8 *) waveheadernode->data;
10764 headerlen = QT_UINT32 (waveheader);
10766 if (headerlen > 8) {
10767 gst_riff_strf_auds *header = NULL;
10768 GstBuffer *headerbuf;
10774 headerbuf = gst_buffer_new_and_alloc (headerlen);
10775 gst_buffer_fill (headerbuf, 0, waveheader, headerlen);
10777 if (gst_riff_parse_strf_auds (GST_ELEMENT_CAST (qtdemux),
10778 headerbuf, &header, &extra)) {
10779 gst_caps_unref (stream->caps);
10780 /* FIXME: Need to do something with the channel reorder map */
10781 stream->caps = gst_riff_create_audio_caps (header->format, NULL,
10782 header, extra, NULL, NULL, NULL);
10785 gst_buffer_unref (extra);
10790 GST_DEBUG ("Didn't find waveheadernode for this codec");
10792 g_node_destroy (wavenode);
10795 gst_qtdemux_handle_esds (qtdemux, stream, esds, stream->pending_tags);
10799 /* FIXME: what is in the chunk? */
10802 gint len = QT_UINT32 (stsd_data);
10804 /* seems to be always = 116 = 0x74 */
10810 gint len = QT_UINT32 (stsd_data);
10813 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x4C);
10815 gst_buffer_fill (buf, 0, stsd_data + 0x4C, len - 0x4C);
10816 gst_caps_set_simple (stream->caps,
10817 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10818 gst_buffer_unref (buf);
10820 gst_caps_set_simple (stream->caps,
10821 "samplesize", G_TYPE_INT, samplesize, NULL);
10826 GNode *alac, *wave = NULL;
10828 /* apparently, m4a has this atom appended directly in the stsd entry,
10829 * while mov has it in a wave atom */
10830 alac = qtdemux_tree_get_child_by_type (stsd, FOURCC_alac);
10832 /* alac now refers to stsd entry atom */
10833 wave = qtdemux_tree_get_child_by_type (alac, FOURCC_wave);
10835 alac = qtdemux_tree_get_child_by_type (wave, FOURCC_alac);
10837 alac = qtdemux_tree_get_child_by_type (alac, FOURCC_alac);
10840 const guint8 *alac_data = alac->data;
10841 gint len = QT_UINT32 (alac->data);
10845 GST_DEBUG_OBJECT (qtdemux,
10846 "discarding alac atom with unexpected len %d", len);
10848 /* codec-data contains alac atom size and prefix,
10849 * ffmpeg likes it that way, not quite gst-ish though ...*/
10850 buf = gst_buffer_new_and_alloc (len);
10851 gst_buffer_fill (buf, 0, alac->data, len);
10852 gst_caps_set_simple (stream->caps,
10853 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10854 gst_buffer_unref (buf);
10856 stream->bytes_per_frame = QT_UINT32 (alac_data + 12);
10857 stream->n_channels = QT_UINT8 (alac_data + 21);
10858 stream->rate = QT_UINT32 (alac_data + 32);
10861 gst_caps_set_simple (stream->caps,
10862 "samplesize", G_TYPE_INT, samplesize, NULL);
10867 /* The codingname of the sample entry is 'fLaC' */
10868 GNode *flac = qtdemux_tree_get_child_by_type (stsd, FOURCC_fLaC);
10871 /* The 'dfLa' box is added to the sample entry to convey
10872 initializing information for the decoder. */
10873 const GNode *dfla =
10874 qtdemux_tree_get_child_by_type (flac, FOURCC_dfLa);
10877 const guint32 len = QT_UINT32 (dfla->data);
10879 /* Must contain at least dfLa box header (12),
10880 * METADATA_BLOCK_HEADER (4), METADATA_BLOCK_STREAMINFO (34) */
10882 GST_DEBUG_OBJECT (qtdemux,
10883 "discarding dfla atom with unexpected len %d", len);
10885 /* skip dfLa header to get the METADATA_BLOCKs */
10886 const guint8 *metadata_blocks = (guint8 *) dfla->data + 12;
10887 const guint32 metadata_blocks_len = len - 12;
10889 gchar *stream_marker = g_strdup ("fLaC");
10890 GstBuffer *block = gst_buffer_new_wrapped (stream_marker,
10891 strlen (stream_marker));
10894 gboolean is_last = FALSE;
10896 GValue array = G_VALUE_INIT;
10897 GValue value = G_VALUE_INIT;
10899 g_value_init (&array, GST_TYPE_ARRAY);
10900 g_value_init (&value, GST_TYPE_BUFFER);
10902 gst_value_set_buffer (&value, block);
10903 gst_value_array_append_value (&array, &value);
10904 g_value_reset (&value);
10906 gst_buffer_unref (block);
10908 while (is_last == FALSE && index < metadata_blocks_len) {
10909 /* add the METADATA_BLOCK_HEADER size to the signalled size */
10910 const guint block_size = 4 +
10911 (metadata_blocks[index + 1] << 16) +
10912 (metadata_blocks[index + 2] << 8) +
10913 metadata_blocks[index + 3];
10915 is_last = metadata_blocks[index] >> 7;
10917 block = gst_buffer_new_and_alloc (block_size);
10919 gst_buffer_fill (block, 0, &metadata_blocks[index],
10922 gst_value_set_buffer (&value, block);
10923 gst_value_array_append_value (&array, &value);
10924 g_value_reset (&value);
10926 gst_buffer_unref (block);
10928 index += block_size;
10931 gst_structure_set_value (gst_caps_get_structure (stream->caps,
10932 0), "streamheader", &array);
10934 g_value_unset (&value);
10935 g_value_unset (&array);
10937 /* The sample rate obtained from the stsd may not be accurate
10938 * since it cannot represent rates greater than 65535Hz, so
10939 * override that value with the sample rate from the
10940 * METADATA_BLOCK_STREAMINFO block */
10942 (QT_UINT32 (metadata_blocks + 14) >> 12) & 0xFFFFF;
10953 gint len = QT_UINT32 (stsd_data);
10956 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x34);
10959 gst_buffer_fill (buf, 0, stsd_data + 0x34, len - 0x34);
10961 /* If we have enough data, let's try to get the 'damr' atom. See
10962 * the 3GPP container spec (26.244) for more details. */
10963 if ((len - 0x34) > 8 &&
10964 (bitrate = qtdemux_parse_amr_bitrate (buf, amrwb))) {
10965 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
10966 GST_TAG_MAXIMUM_BITRATE, bitrate, NULL);
10969 gst_caps_set_simple (stream->caps,
10970 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10971 gst_buffer_unref (buf);
10977 /* mp4a atom withtout ESDS; Attempt to build codec data from atom */
10978 gint len = QT_UINT32 (stsd_data);
10981 guint16 sound_version = QT_UINT16 (stsd_data + 32);
10983 if (sound_version == 1) {
10984 guint16 channels = QT_UINT16 (stsd_data + 40);
10985 guint32 time_scale = QT_UINT32 (stsd_data + 46);
10986 guint8 codec_data[2];
10988 gint profile = 2; /* FIXME: Can this be determined somehow? There doesn't seem to be anything in mp4a atom that specifis compression */
10990 gint sample_rate_index =
10991 gst_codec_utils_aac_get_index_from_sample_rate (time_scale);
10993 /* build AAC codec data */
10994 codec_data[0] = profile << 3;
10995 codec_data[0] |= ((sample_rate_index >> 1) & 0x7);
10996 codec_data[1] = (sample_rate_index & 0x01) << 7;
10997 codec_data[1] |= (channels & 0xF) << 3;
10999 buf = gst_buffer_new_and_alloc (2);
11000 gst_buffer_fill (buf, 0, codec_data, 2);
11001 gst_caps_set_simple (stream->caps,
11002 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11003 gst_buffer_unref (buf);
11009 GST_INFO_OBJECT (qtdemux,
11010 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
11014 GST_INFO_OBJECT (qtdemux,
11015 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
11016 GST_FOURCC_ARGS (fourcc), stream->caps);
11018 } else if (stream->subtype == FOURCC_strm) {
11019 if (fourcc == FOURCC_rtsp) {
11020 stream->redirect_uri = qtdemux_get_rtsp_uri_from_hndl (qtdemux, minf);
11022 GST_INFO_OBJECT (qtdemux, "unhandled stream type %" GST_FOURCC_FORMAT,
11023 GST_FOURCC_ARGS (fourcc));
11024 goto unknown_stream;
11026 stream->sampled = TRUE;
11027 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
11028 || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt) {
11030 stream->sampled = TRUE;
11031 stream->sparse = TRUE;
11034 qtdemux_sub_caps (qtdemux, stream, fourcc, stsd_data, &codec);
11036 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
11037 GST_TAG_SUBTITLE_CODEC, codec, NULL);
11042 /* hunt for sort-of codec data */
11046 GNode *mp4s = NULL;
11047 GNode *esds = NULL;
11049 /* look for palette in a stsd->mp4s->esds sub-atom */
11050 mp4s = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4s);
11052 esds = qtdemux_tree_get_child_by_type (mp4s, FOURCC_esds);
11053 if (esds == NULL) {
11055 GST_LOG_OBJECT (qtdemux, "Skipping invalid stsd: no esds child");
11059 gst_qtdemux_handle_esds (qtdemux, stream, esds, stream->pending_tags);
11063 GST_INFO_OBJECT (qtdemux,
11064 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
11067 GST_INFO_OBJECT (qtdemux,
11068 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
11069 GST_FOURCC_ARGS (fourcc), stream->caps);
11071 /* everything in 1 sample */
11072 stream->sampled = TRUE;
11075 qtdemux_generic_caps (qtdemux, stream, fourcc, stsd_data, &codec);
11077 if (stream->caps == NULL)
11078 goto unknown_stream;
11081 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
11082 GST_TAG_SUBTITLE_CODEC, codec, NULL);
11088 /* promote to sampled format */
11089 if (stream->fourcc == FOURCC_samr) {
11090 /* force mono 8000 Hz for AMR */
11091 stream->sampled = TRUE;
11092 stream->n_channels = 1;
11093 stream->rate = 8000;
11094 } else if (stream->fourcc == FOURCC_sawb) {
11095 /* force mono 16000 Hz for AMR-WB */
11096 stream->sampled = TRUE;
11097 stream->n_channels = 1;
11098 stream->rate = 16000;
11099 } else if (stream->fourcc == FOURCC_mp4a) {
11100 stream->sampled = TRUE;
11103 /* collect sample information */
11104 if (!qtdemux_stbl_init (qtdemux, stream, stbl))
11105 goto samples_failed;
11107 if (qtdemux->fragmented) {
11110 /* need all moov samples as basis; probably not many if any at all */
11111 /* prevent moof parsing taking of at this time */
11112 offset = qtdemux->moof_offset;
11113 qtdemux->moof_offset = 0;
11114 if (stream->n_samples &&
11115 !qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
11116 qtdemux->moof_offset = offset;
11117 goto samples_failed;
11119 qtdemux->moof_offset = 0;
11120 /* movie duration more reliable in this case (e.g. mehd) */
11121 if (qtdemux->segment.duration &&
11122 GST_CLOCK_TIME_IS_VALID (qtdemux->segment.duration))
11124 GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->segment.duration);
11127 /* configure segments */
11128 if (!qtdemux_parse_segments (qtdemux, stream, trak))
11129 goto segments_failed;
11131 /* add some language tag, if useful */
11132 if (stream->lang_id[0] != '\0' && strcmp (stream->lang_id, "unk") &&
11133 strcmp (stream->lang_id, "und")) {
11134 const gchar *lang_code;
11136 /* convert ISO 639-2 code to ISO 639-1 */
11137 lang_code = gst_tag_get_language_code (stream->lang_id);
11138 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
11139 GST_TAG_LANGUAGE_CODE, (lang_code) ? lang_code : stream->lang_id, NULL);
11142 /* Check for UDTA tags */
11143 if ((udta = qtdemux_tree_get_child_by_type (trak, FOURCC_udta))) {
11144 qtdemux_parse_udta (qtdemux, stream->pending_tags, udta);
11147 /* now we are ready to add the stream */
11148 if (qtdemux->n_streams >= GST_QTDEMUX_MAX_STREAMS)
11149 goto too_many_streams;
11151 if (!qtdemux->got_moov) {
11152 qtdemux->streams[qtdemux->n_streams] = stream;
11153 qtdemux->n_streams++;
11154 GST_DEBUG_OBJECT (qtdemux, "n_streams is now %d", qtdemux->n_streams);
11162 GST_INFO_OBJECT (qtdemux, "skip disabled track");
11164 gst_qtdemux_stream_free (qtdemux, stream);
11169 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
11170 (_("This file is corrupt and cannot be played.")), (NULL));
11172 gst_qtdemux_stream_free (qtdemux, stream);
11177 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT, (NULL), (NULL));
11179 gst_qtdemux_stream_free (qtdemux, stream);
11185 /* we posted an error already */
11186 /* free stbl sub-atoms */
11187 gst_qtdemux_stbl_free (stream);
11189 gst_qtdemux_stream_free (qtdemux, stream);
11194 GST_INFO_OBJECT (qtdemux, "stream with track id %i already exists",
11197 gst_qtdemux_stream_free (qtdemux, stream);
11202 GST_INFO_OBJECT (qtdemux, "unknown subtype %" GST_FOURCC_FORMAT,
11203 GST_FOURCC_ARGS (stream->subtype));
11205 gst_qtdemux_stream_free (qtdemux, stream);
11210 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
11211 (_("This file contains too many streams. Only playing first %d"),
11212 GST_QTDEMUX_MAX_STREAMS), (NULL));
11217 /* If we can estimate the overall bitrate, and don't have information about the
11218 * stream bitrate for exactly one stream, this guesses the stream bitrate as
11219 * the overall bitrate minus the sum of the bitrates of all other streams. This
11220 * should be useful for the common case where we have one audio and one video
11221 * stream and can estimate the bitrate of one, but not the other. */
11223 gst_qtdemux_guess_bitrate (GstQTDemux * qtdemux)
11225 QtDemuxStream *stream = NULL;
11226 gint64 size, sys_bitrate, sum_bitrate = 0;
11227 GstClockTime duration;
11231 if (qtdemux->fragmented)
11234 GST_DEBUG_OBJECT (qtdemux, "Looking for streams with unknown bitrate");
11236 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &size)
11238 GST_DEBUG_OBJECT (qtdemux,
11239 "Size in bytes of the stream not known - bailing");
11243 /* Subtract the header size */
11244 GST_DEBUG_OBJECT (qtdemux, "Total size %" G_GINT64_FORMAT ", header size %u",
11245 size, qtdemux->header_size);
11247 if (size < qtdemux->header_size)
11250 size = size - qtdemux->header_size;
11252 if (!gst_qtdemux_get_duration (qtdemux, &duration)) {
11253 GST_DEBUG_OBJECT (qtdemux, "Stream duration not known - bailing");
11257 for (i = 0; i < qtdemux->n_streams; i++) {
11258 switch (qtdemux->streams[i]->subtype) {
11261 GST_DEBUG_OBJECT (qtdemux, "checking bitrate for %" GST_PTR_FORMAT,
11262 qtdemux->streams[i]->caps);
11263 /* retrieve bitrate, prefer avg then max */
11265 if (qtdemux->streams[i]->pending_tags) {
11266 gst_tag_list_get_uint (qtdemux->streams[i]->pending_tags,
11267 GST_TAG_MAXIMUM_BITRATE, &bitrate);
11268 GST_DEBUG_OBJECT (qtdemux, "max-bitrate: %u", bitrate);
11269 gst_tag_list_get_uint (qtdemux->streams[i]->pending_tags,
11270 GST_TAG_NOMINAL_BITRATE, &bitrate);
11271 GST_DEBUG_OBJECT (qtdemux, "nominal-bitrate: %u", bitrate);
11272 gst_tag_list_get_uint (qtdemux->streams[i]->pending_tags,
11273 GST_TAG_BITRATE, &bitrate);
11274 GST_DEBUG_OBJECT (qtdemux, "bitrate: %u", bitrate);
11277 sum_bitrate += bitrate;
11280 GST_DEBUG_OBJECT (qtdemux,
11281 ">1 stream with unknown bitrate - bailing");
11284 stream = qtdemux->streams[i];
11288 /* For other subtypes, we assume no significant impact on bitrate */
11294 GST_DEBUG_OBJECT (qtdemux, "All stream bitrates are known");
11298 sys_bitrate = gst_util_uint64_scale (size, GST_SECOND * 8, duration);
11300 if (sys_bitrate < sum_bitrate) {
11301 /* This can happen, since sum_bitrate might be derived from maximum
11302 * bitrates and not average bitrates */
11303 GST_DEBUG_OBJECT (qtdemux,
11304 "System bitrate less than sum bitrate - bailing");
11308 bitrate = sys_bitrate - sum_bitrate;
11309 GST_DEBUG_OBJECT (qtdemux, "System bitrate = %" G_GINT64_FORMAT
11310 ", Stream bitrate = %u", sys_bitrate, bitrate);
11312 if (!stream->pending_tags)
11313 stream->pending_tags = gst_tag_list_new_empty ();
11315 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
11316 GST_TAG_BITRATE, bitrate, NULL);
11319 static GstFlowReturn
11320 qtdemux_prepare_streams (GstQTDemux * qtdemux)
11323 GstFlowReturn ret = GST_FLOW_OK;
11325 GST_DEBUG_OBJECT (qtdemux, "prepare streams");
11327 for (i = 0; ret == GST_FLOW_OK && i < qtdemux->n_streams; i++) {
11328 QtDemuxStream *stream = qtdemux->streams[i];
11329 guint32 sample_num = 0;
11331 GST_DEBUG_OBJECT (qtdemux, "stream %d, id %d, fourcc %" GST_FOURCC_FORMAT,
11332 i, stream->track_id, GST_FOURCC_ARGS (stream->fourcc));
11334 if (qtdemux->fragmented) {
11335 /* need all moov samples first */
11336 GST_OBJECT_LOCK (qtdemux);
11337 while (stream->n_samples == 0)
11338 if ((ret = qtdemux_add_fragmented_samples (qtdemux)) != GST_FLOW_OK)
11340 GST_OBJECT_UNLOCK (qtdemux);
11342 /* discard any stray moof */
11343 qtdemux->moof_offset = 0;
11346 /* prepare braking */
11347 if (ret != GST_FLOW_ERROR)
11350 /* in pull mode, we should have parsed some sample info by now;
11351 * and quite some code will not handle no samples.
11352 * in push mode, we'll just have to deal with it */
11353 if (G_UNLIKELY (qtdemux->pullbased && !stream->n_samples)) {
11354 GST_DEBUG_OBJECT (qtdemux, "no samples for stream; discarding");
11355 gst_qtdemux_remove_stream (qtdemux, i);
11360 /* parse the initial sample for use in setting the frame rate cap */
11361 while (sample_num == 0 && sample_num < stream->n_samples) {
11362 if (!qtdemux_parse_samples (qtdemux, stream, sample_num))
11366 if (stream->n_samples > 0 && stream->stbl_index >= 0) {
11367 stream->first_duration = stream->samples[0].duration;
11368 GST_LOG_OBJECT (qtdemux, "stream %d first duration %u",
11369 stream->track_id, stream->first_duration);
11376 static GstFlowReturn
11377 qtdemux_expose_streams (GstQTDemux * qtdemux)
11380 GstFlowReturn ret = GST_FLOW_OK;
11381 GSList *oldpads = NULL;
11384 GST_DEBUG_OBJECT (qtdemux, "exposing streams");
11386 for (i = 0; ret == GST_FLOW_OK && i < qtdemux->n_streams; i++) {
11387 QtDemuxStream *stream = qtdemux->streams[i];
11388 GstPad *oldpad = stream->pad;
11391 GST_DEBUG_OBJECT (qtdemux, "stream %d, id %d, fourcc %" GST_FOURCC_FORMAT,
11392 i, stream->track_id, GST_FOURCC_ARGS (stream->fourcc));
11394 if ((stream->subtype == FOURCC_text || stream->subtype == FOURCC_sbtl) &&
11395 stream->track_id == qtdemux->chapters_track_id) {
11396 /* TODO - parse chapters track and expose it as GstToc; For now just ignore it
11397 so that it doesn't look like a subtitle track */
11398 gst_qtdemux_remove_stream (qtdemux, i);
11403 /* now we have all info and can expose */
11404 list = stream->pending_tags;
11405 stream->pending_tags = NULL;
11407 oldpads = g_slist_prepend (oldpads, oldpad);
11408 if (!gst_qtdemux_add_stream (qtdemux, stream, list))
11409 return GST_FLOW_ERROR;
11412 gst_qtdemux_guess_bitrate (qtdemux);
11414 gst_element_no_more_pads (GST_ELEMENT_CAST (qtdemux));
11416 for (iter = oldpads; iter; iter = g_slist_next (iter)) {
11417 GstPad *oldpad = iter->data;
11420 event = gst_event_new_eos ();
11421 if (qtdemux->segment_seqnum)
11422 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
11424 gst_pad_push_event (oldpad, event);
11425 gst_pad_set_active (oldpad, FALSE);
11426 gst_element_remove_pad (GST_ELEMENT (qtdemux), oldpad);
11427 gst_flow_combiner_remove_pad (qtdemux->flowcombiner, oldpad);
11428 gst_object_unref (oldpad);
11431 /* check if we should post a redirect in case there is a single trak
11432 * and it is a redirecting trak */
11433 if (qtdemux->n_streams == 1 && qtdemux->streams[0]->redirect_uri != NULL) {
11436 GST_INFO_OBJECT (qtdemux, "Issuing a redirect due to a single track with "
11437 "an external content");
11438 m = gst_message_new_element (GST_OBJECT_CAST (qtdemux),
11439 gst_structure_new ("redirect",
11440 "new-location", G_TYPE_STRING, qtdemux->streams[0]->redirect_uri,
11442 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), m);
11443 qtdemux->posted_redirect = TRUE;
11446 for (i = 0; i < qtdemux->n_streams; i++) {
11447 QtDemuxStream *stream = qtdemux->streams[i];
11449 qtdemux_do_allocation (qtdemux, stream);
11452 qtdemux->exposed = TRUE;
11456 /* check if major or compatible brand is 3GP */
11457 static inline gboolean
11458 qtdemux_is_brand_3gp (GstQTDemux * qtdemux, gboolean major)
11461 return ((qtdemux->major_brand & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
11463 } else if (qtdemux->comp_brands != NULL) {
11467 gboolean res = FALSE;
11469 gst_buffer_map (qtdemux->comp_brands, &map, GST_MAP_READ);
11472 while (size >= 4) {
11473 res = res || ((QT_FOURCC (data) & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
11478 gst_buffer_unmap (qtdemux->comp_brands, &map);
11485 /* check if tag is a spec'ed 3GP tag keyword storing a string */
11486 static inline gboolean
11487 qtdemux_is_string_tag_3gp (GstQTDemux * qtdemux, guint32 fourcc)
11489 return fourcc == FOURCC_cprt || fourcc == FOURCC_gnre || fourcc == FOURCC_titl
11490 || fourcc == FOURCC_dscp || fourcc == FOURCC_perf || fourcc == FOURCC_auth
11491 || fourcc == FOURCC_albm;
11495 qtdemux_tag_add_location (GstQTDemux * qtdemux, GstTagList * taglist,
11496 const char *tag, const char *dummy, GNode * node)
11498 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
11502 gdouble longitude, latitude, altitude;
11505 len = QT_UINT32 (node->data);
11512 /* TODO: language code skipped */
11514 name = gst_tag_freeform_string_to_utf8 (data + offset, -1, env_vars);
11517 /* do not alarm in trivial case, but bail out otherwise */
11518 if (*(data + offset) != 0) {
11519 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8, "
11523 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
11524 GST_TAG_GEO_LOCATION_NAME, name, NULL);
11525 offset += strlen (name);
11529 if (len < offset + 2 + 4 + 4 + 4)
11532 /* +1 +1 = skip null-terminator and location role byte */
11534 /* table in spec says unsigned, semantics say negative has meaning ... */
11535 longitude = QT_SFP32 (data + offset);
11538 latitude = QT_SFP32 (data + offset);
11541 altitude = QT_SFP32 (data + offset);
11543 /* one invalid means all are invalid */
11544 if (longitude >= -180.0 && longitude <= 180.0 &&
11545 latitude >= -90.0 && latitude <= 90.0) {
11546 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
11547 GST_TAG_GEO_LOCATION_LATITUDE, latitude,
11548 GST_TAG_GEO_LOCATION_LONGITUDE, longitude,
11549 GST_TAG_GEO_LOCATION_ELEVATION, altitude, NULL);
11552 /* TODO: no GST_TAG_, so astronomical body and additional notes skipped */
11559 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP location");
11566 qtdemux_tag_add_year (GstQTDemux * qtdemux, GstTagList * taglist,
11567 const char *tag, const char *dummy, GNode * node)
11573 len = QT_UINT32 (node->data);
11577 y = QT_UINT16 ((guint8 *) node->data + 12);
11579 GST_DEBUG_OBJECT (qtdemux, "year: %u is not a valid year", y);
11582 GST_DEBUG_OBJECT (qtdemux, "year: %u", y);
11584 date = g_date_new_dmy (1, 1, y);
11585 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, date, NULL);
11586 g_date_free (date);
11590 qtdemux_tag_add_classification (GstQTDemux * qtdemux, GstTagList * taglist,
11591 const char *tag, const char *dummy, GNode * node)
11594 char *tag_str = NULL;
11599 len = QT_UINT32 (node->data);
11604 entity = (guint8 *) node->data + offset;
11605 if (entity[0] == 0 || entity[1] == 0 || entity[2] == 0 || entity[3] == 0) {
11606 GST_DEBUG_OBJECT (qtdemux,
11607 "classification info: %c%c%c%c invalid classification entity",
11608 entity[0], entity[1], entity[2], entity[3]);
11613 table = QT_UINT16 ((guint8 *) node->data + offset);
11615 /* Language code skipped */
11619 /* Tag format: "XXXX://Y[YYYY]/classification info string"
11620 * XXXX: classification entity, fixed length 4 chars.
11621 * Y[YYYY]: classification table, max 5 chars.
11623 tag_str = g_strdup_printf ("----://%u/%s",
11624 table, (char *) node->data + offset);
11626 /* memcpy To be sure we're preserving byte order */
11627 memcpy (tag_str, entity, 4);
11628 GST_DEBUG_OBJECT (qtdemux, "classification info: %s", tag_str);
11630 gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND, tag, tag_str, NULL);
11639 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP classification");
11645 qtdemux_tag_add_str_full (GstQTDemux * qtdemux, GstTagList * taglist,
11646 const char *tag, const char *dummy, GNode * node)
11648 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
11654 gboolean ret = TRUE;
11655 const gchar *charset = NULL;
11657 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
11659 len = QT_UINT32 (data->data);
11660 type = QT_UINT32 ((guint8 *) data->data + 8);
11661 if (type == 0x00000001 && len > 16) {
11662 s = gst_tag_freeform_string_to_utf8 ((char *) data->data + 16, len - 16,
11665 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
11666 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, s, NULL);
11669 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
11673 len = QT_UINT32 (node->data);
11674 type = QT_UINT32 ((guint8 *) node->data + 4);
11675 if ((type >> 24) == 0xa9) {
11679 /* Type starts with the (C) symbol, so the next data is a list
11680 * of (string size(16), language code(16), string) */
11682 str_len = QT_UINT16 ((guint8 *) node->data + 8);
11683 lang_code = QT_UINT16 ((guint8 *) node->data + 10);
11685 /* the string + fourcc + size + 2 16bit fields,
11686 * means that there are more tags in this atom */
11687 if (len > str_len + 8 + 4) {
11688 /* TODO how to represent the same tag in different languages? */
11689 GST_WARNING_OBJECT (qtdemux, "Ignoring metadata entry with multiple "
11690 "text alternatives, reading only first one");
11694 len = str_len + 8 + 4; /* remove trailing strings that we don't use */
11695 GST_DEBUG_OBJECT (qtdemux, "found international text tag");
11697 if (lang_code < 0x800) { /* MAC encoded string */
11700 } else if (len > 14 && qtdemux_is_string_tag_3gp (qtdemux,
11701 QT_FOURCC ((guint8 *) node->data + 4))) {
11702 guint32 type = QT_UINT32 ((guint8 *) node->data + 8);
11704 /* we go for 3GP style encoding if major brands claims so,
11705 * or if no hope for data be ok UTF-8, and compatible 3GP brand present */
11706 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
11707 (qtdemux_is_brand_3gp (qtdemux, FALSE) &&
11708 ((type & 0x00FFFFFF) == 0x0) && (type >> 24 <= 0xF))) {
11710 /* 16-bit Language code is ignored here as well */
11711 GST_DEBUG_OBJECT (qtdemux, "found 3gpp text tag");
11718 GST_DEBUG_OBJECT (qtdemux, "found normal text tag");
11719 ret = FALSE; /* may have to fallback */
11722 GError *err = NULL;
11724 s = g_convert ((gchar *) node->data + offset, len - offset, "utf8",
11725 charset, NULL, NULL, &err);
11727 GST_DEBUG_OBJECT (qtdemux, "Failed to convert string from charset %s:"
11728 " %s(%d): %s", charset, g_quark_to_string (err->domain), err->code,
11730 g_error_free (err);
11733 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
11734 len - offset, env_vars);
11737 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
11738 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, s, NULL);
11742 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
11749 qtdemux_tag_add_str (GstQTDemux * qtdemux, GstTagList * taglist,
11750 const char *tag, const char *dummy, GNode * node)
11752 qtdemux_tag_add_str_full (qtdemux, taglist, tag, dummy, node);
11756 qtdemux_tag_add_keywords (GstQTDemux * qtdemux, GstTagList * taglist,
11757 const char *tag, const char *dummy, GNode * node)
11759 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
11761 char *s, *t, *k = NULL;
11766 /* first try normal string tag if major brand not 3GP */
11767 if (!qtdemux_is_brand_3gp (qtdemux, TRUE)) {
11768 if (!qtdemux_tag_add_str_full (qtdemux, taglist, tag, dummy, node)) {
11769 /* hm, that did not work, maybe 3gpp storage in non-3gpp major brand;
11770 * let's try it 3gpp way after minor safety check */
11772 if (QT_UINT32 (data) < 15 || !qtdemux_is_brand_3gp (qtdemux, FALSE))
11778 GST_DEBUG_OBJECT (qtdemux, "found 3gpp keyword tag");
11782 len = QT_UINT32 (data);
11786 count = QT_UINT8 (data + 14);
11788 for (; count; count--) {
11791 if (offset + 1 > len)
11793 slen = QT_UINT8 (data + offset);
11795 if (offset + slen > len)
11797 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
11800 GST_DEBUG_OBJECT (qtdemux, "adding keyword %s", GST_STR_NULL (s));
11802 t = g_strjoin (",", k, s, NULL);
11810 GST_DEBUG_OBJECT (qtdemux, "failed to convert keyword to UTF-8");
11817 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (k));
11818 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, k, NULL);
11827 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP keywords");
11833 qtdemux_tag_add_num (GstQTDemux * qtdemux, GstTagList * taglist,
11834 const char *tag1, const char *tag2, GNode * node)
11841 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
11843 len = QT_UINT32 (data->data);
11844 type = QT_UINT32 ((guint8 *) data->data + 8);
11845 if (type == 0x00000000 && len >= 22) {
11846 n1 = QT_UINT16 ((guint8 *) data->data + 18);
11847 n2 = QT_UINT16 ((guint8 *) data->data + 20);
11849 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag1, n1);
11850 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, n1, NULL);
11853 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag2, n2);
11854 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag2, n2, NULL);
11861 qtdemux_tag_add_tmpo (GstQTDemux * qtdemux, GstTagList * taglist,
11862 const char *tag1, const char *dummy, GNode * node)
11869 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
11871 len = QT_UINT32 (data->data);
11872 type = QT_UINT32 ((guint8 *) data->data + 8);
11873 GST_DEBUG_OBJECT (qtdemux, "have tempo tag, type=%d,len=%d", type, len);
11874 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
11875 if ((type == 0x00000015 || type == 0x0000000f) && len >= 18) {
11876 n1 = QT_UINT16 ((guint8 *) data->data + 16);
11878 /* do not add bpm=0 */
11879 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", n1);
11880 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, (gdouble) n1,
11888 qtdemux_tag_add_uint32 (GstQTDemux * qtdemux, GstTagList * taglist,
11889 const char *tag1, const char *dummy, GNode * node)
11896 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
11898 len = QT_UINT32 (data->data);
11899 type = QT_UINT32 ((guint8 *) data->data + 8);
11900 GST_DEBUG_OBJECT (qtdemux, "have %s tag, type=%d,len=%d", tag1, type, len);
11901 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
11902 if ((type == 0x00000015 || type == 0x0000000f) && len >= 20) {
11903 num = QT_UINT32 ((guint8 *) data->data + 16);
11905 /* do not add num=0 */
11906 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", num);
11907 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, num, NULL);
11914 qtdemux_tag_add_covr (GstQTDemux * qtdemux, GstTagList * taglist,
11915 const char *tag1, const char *dummy, GNode * node)
11922 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
11924 len = QT_UINT32 (data->data);
11925 type = QT_UINT32 ((guint8 *) data->data + 8);
11926 GST_DEBUG_OBJECT (qtdemux, "have covr tag, type=%d,len=%d", type, len);
11927 if ((type == 0x0000000d || type == 0x0000000e) && len > 16) {
11929 gst_tag_image_data_to_image_sample ((guint8 *) data->data + 16,
11930 len - 16, GST_TAG_IMAGE_TYPE_NONE))) {
11931 GST_DEBUG_OBJECT (qtdemux, "adding tag size %d", len - 16);
11932 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, sample, NULL);
11933 gst_sample_unref (sample);
11940 qtdemux_tag_add_date (GstQTDemux * qtdemux, GstTagList * taglist,
11941 const char *tag, const char *dummy, GNode * node)
11948 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
11950 len = QT_UINT32 (data->data);
11951 type = QT_UINT32 ((guint8 *) data->data + 8);
11952 if (type == 0x00000001 && len > 16) {
11953 guint y, m = 1, d = 1;
11956 s = g_strndup ((char *) data->data + 16, len - 16);
11957 GST_DEBUG_OBJECT (qtdemux, "adding date '%s'", s);
11958 ret = sscanf (s, "%u-%u-%u", &y, &m, &d);
11959 if (ret >= 1 && y > 1500 && y < 3000) {
11962 date = g_date_new_dmy (d, m, y);
11963 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, date, NULL);
11964 g_date_free (date);
11966 GST_DEBUG_OBJECT (qtdemux, "could not parse date string '%s'", s);
11974 qtdemux_tag_add_gnre (GstQTDemux * qtdemux, GstTagList * taglist,
11975 const char *tag, const char *dummy, GNode * node)
11979 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
11981 /* re-route to normal string tag if major brand says so
11982 * or no data atom and compatible brand suggests so */
11983 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
11984 (qtdemux_is_brand_3gp (qtdemux, FALSE) && !data)) {
11985 qtdemux_tag_add_str (qtdemux, taglist, tag, dummy, node);
11990 guint len, type, n;
11992 len = QT_UINT32 (data->data);
11993 type = QT_UINT32 ((guint8 *) data->data + 8);
11994 if (type == 0x00000000 && len >= 18) {
11995 n = QT_UINT16 ((guint8 *) data->data + 16);
11997 const gchar *genre;
11999 genre = gst_tag_id3_genre_get (n - 1);
12000 if (genre != NULL) {
12001 GST_DEBUG_OBJECT (qtdemux, "adding %d [%s]", n, genre);
12002 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, genre, NULL);
12010 qtdemux_add_double_tag_from_str (GstQTDemux * demux, GstTagList * taglist,
12011 const gchar * tag, guint8 * data, guint32 datasize)
12016 /* make a copy to have \0 at the end */
12017 datacopy = g_strndup ((gchar *) data, datasize);
12019 /* convert the str to double */
12020 if (sscanf (datacopy, "%lf", &value) == 1) {
12021 GST_DEBUG_OBJECT (demux, "adding tag: %s [%s]", tag, datacopy);
12022 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, value, NULL);
12024 GST_WARNING_OBJECT (demux, "Failed to parse double from string: %s",
12032 qtdemux_tag_add_revdns (GstQTDemux * demux, GstTagList * taglist,
12033 const char *tag, const char *tag_bis, GNode * node)
12042 const gchar *meanstr;
12043 const gchar *namestr;
12045 /* checking the whole ---- atom size for consistency */
12046 if (QT_UINT32 (node->data) <= 4 + 12 + 12 + 16) {
12047 GST_WARNING_OBJECT (demux, "Tag ---- atom is too small, ignoring");
12051 mean = qtdemux_tree_get_child_by_type (node, FOURCC_mean);
12053 GST_WARNING_OBJECT (demux, "No 'mean' atom found");
12057 meansize = QT_UINT32 (mean->data);
12058 if (meansize <= 12) {
12059 GST_WARNING_OBJECT (demux, "Small mean atom, ignoring the whole tag");
12062 meanstr = ((gchar *) mean->data) + 12;
12065 name = qtdemux_tree_get_child_by_type (node, FOURCC_name);
12067 GST_WARNING_OBJECT (demux, "'name' atom not found, ignoring tag");
12071 namesize = QT_UINT32 (name->data);
12072 if (namesize <= 12) {
12073 GST_WARNING_OBJECT (demux, "'name' atom is too small, ignoring tag");
12076 namestr = ((gchar *) name->data) + 12;
12084 * uint24 - data type
12088 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12090 GST_WARNING_OBJECT (demux, "No data atom in this tag");
12093 datasize = QT_UINT32 (data->data);
12094 if (datasize <= 16) {
12095 GST_WARNING_OBJECT (demux, "Data atom too small");
12098 datatype = QT_UINT32 (((gchar *) data->data) + 8) & 0xFFFFFF;
12100 if ((strncmp (meanstr, "com.apple.iTunes", meansize) == 0) ||
12101 (strncmp (meanstr, "org.hydrogenaudio.replaygain", meansize) == 0)) {
12102 static const struct
12104 const gchar name[28];
12105 const gchar tag[28];
12108 "replaygain_track_gain", GST_TAG_TRACK_GAIN}, {
12109 "replaygain_track_peak", GST_TAG_TRACK_PEAK}, {
12110 "replaygain_album_gain", GST_TAG_ALBUM_GAIN}, {
12111 "replaygain_album_peak", GST_TAG_ALBUM_PEAK}, {
12112 "MusicBrainz Track Id", GST_TAG_MUSICBRAINZ_TRACKID}, {
12113 "MusicBrainz Artist Id", GST_TAG_MUSICBRAINZ_ARTISTID}, {
12114 "MusicBrainz Album Id", GST_TAG_MUSICBRAINZ_ALBUMID}, {
12115 "MusicBrainz Album Artist Id", GST_TAG_MUSICBRAINZ_ALBUMARTISTID}
12119 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
12120 if (!g_ascii_strncasecmp (tags[i].name, namestr, namesize)) {
12121 switch (gst_tag_get_type (tags[i].tag)) {
12122 case G_TYPE_DOUBLE:
12123 qtdemux_add_double_tag_from_str (demux, taglist, tags[i].tag,
12124 ((guint8 *) data->data) + 16, datasize - 16);
12126 case G_TYPE_STRING:
12127 qtdemux_tag_add_str (demux, taglist, tags[i].tag, NULL, node);
12136 if (i == G_N_ELEMENTS (tags))
12146 #ifndef GST_DISABLE_GST_DEBUG
12148 gchar *namestr_dbg;
12149 gchar *meanstr_dbg;
12151 meanstr_dbg = g_strndup (meanstr, meansize);
12152 namestr_dbg = g_strndup (namestr, namesize);
12154 GST_WARNING_OBJECT (demux, "This tag %s:%s type:%u is not mapped, "
12155 "file a bug at bugzilla.gnome.org", meanstr_dbg, namestr_dbg, datatype);
12157 g_free (namestr_dbg);
12158 g_free (meanstr_dbg);
12165 qtdemux_tag_add_id32 (GstQTDemux * demux, GstTagList * taglist, const char *tag,
12166 const char *tag_bis, GNode * node)
12171 GstTagList *id32_taglist = NULL;
12173 GST_LOG_OBJECT (demux, "parsing ID32");
12176 len = GST_READ_UINT32_BE (data);
12178 /* need at least full box and language tag */
12182 buf = gst_buffer_new_allocate (NULL, len - 14, NULL);
12183 gst_buffer_fill (buf, 0, data + 14, len - 14);
12185 id32_taglist = gst_tag_list_from_id3v2_tag (buf);
12186 if (id32_taglist) {
12187 GST_LOG_OBJECT (demux, "parsing ok");
12188 gst_tag_list_insert (taglist, id32_taglist, GST_TAG_MERGE_KEEP);
12189 gst_tag_list_unref (id32_taglist);
12191 GST_LOG_OBJECT (demux, "parsing failed");
12194 gst_buffer_unref (buf);
12197 typedef void (*GstQTDemuxAddTagFunc) (GstQTDemux * demux, GstTagList * taglist,
12198 const char *tag, const char *tag_bis, GNode * node);
12201 FOURCC_pcst -> if media is a podcast -> bool
12202 FOURCC_cpil -> if media is part of a compilation -> bool
12203 FOURCC_pgap -> if media is part of a gapless context -> bool
12204 FOURCC_tven -> the tv episode id e.g. S01E23 -> str
12207 static const struct
12210 const gchar *gst_tag;
12211 const gchar *gst_tag_bis;
12212 const GstQTDemuxAddTagFunc func;
12215 FOURCC__nam, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
12216 FOURCC_titl, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
12217 FOURCC__grp, GST_TAG_GROUPING, NULL, qtdemux_tag_add_str}, {
12218 FOURCC__wrt, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
12219 FOURCC__ART, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
12220 FOURCC_aART, GST_TAG_ALBUM_ARTIST, NULL, qtdemux_tag_add_str}, {
12221 FOURCC_perf, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
12222 FOURCC_auth, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
12223 FOURCC__alb, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
12224 FOURCC_albm, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
12225 FOURCC_cprt, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
12226 FOURCC__cpy, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
12227 FOURCC__cmt, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
12228 FOURCC__des, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
12229 FOURCC_desc, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
12230 FOURCC_dscp, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
12231 FOURCC__lyr, GST_TAG_LYRICS, NULL, qtdemux_tag_add_str}, {
12232 FOURCC__day, GST_TAG_DATE, NULL, qtdemux_tag_add_date}, {
12233 FOURCC_yrrc, GST_TAG_DATE, NULL, qtdemux_tag_add_year}, {
12234 FOURCC__too, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
12235 FOURCC__inf, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
12236 FOURCC_trkn, GST_TAG_TRACK_NUMBER, GST_TAG_TRACK_COUNT, qtdemux_tag_add_num}, {
12237 FOURCC_disk, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
12238 qtdemux_tag_add_num}, {
12239 FOURCC_disc, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
12240 qtdemux_tag_add_num}, {
12241 FOURCC__gen, GST_TAG_GENRE, NULL, qtdemux_tag_add_str}, {
12242 FOURCC_gnre, GST_TAG_GENRE, NULL, qtdemux_tag_add_gnre}, {
12243 FOURCC_tmpo, GST_TAG_BEATS_PER_MINUTE, NULL, qtdemux_tag_add_tmpo}, {
12244 FOURCC_covr, GST_TAG_PREVIEW_IMAGE, NULL, qtdemux_tag_add_covr}, {
12245 FOURCC_sonm, GST_TAG_TITLE_SORTNAME, NULL, qtdemux_tag_add_str}, {
12246 FOURCC_soal, GST_TAG_ALBUM_SORTNAME, NULL, qtdemux_tag_add_str}, {
12247 FOURCC_soar, GST_TAG_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
12248 FOURCC_soaa, GST_TAG_ALBUM_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
12249 FOURCC_soco, GST_TAG_COMPOSER_SORTNAME, NULL, qtdemux_tag_add_str}, {
12250 FOURCC_sosn, GST_TAG_SHOW_SORTNAME, NULL, qtdemux_tag_add_str}, {
12251 FOURCC_tvsh, GST_TAG_SHOW_NAME, NULL, qtdemux_tag_add_str}, {
12252 FOURCC_tvsn, GST_TAG_SHOW_SEASON_NUMBER, NULL, qtdemux_tag_add_uint32}, {
12253 FOURCC_tves, GST_TAG_SHOW_EPISODE_NUMBER, NULL, qtdemux_tag_add_uint32}, {
12254 FOURCC_kywd, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_keywords}, {
12255 FOURCC_keyw, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_str}, {
12256 FOURCC__enc, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
12257 FOURCC_loci, GST_TAG_GEO_LOCATION_NAME, NULL, qtdemux_tag_add_location}, {
12258 FOURCC_clsf, GST_QT_DEMUX_CLASSIFICATION_TAG, NULL,
12259 qtdemux_tag_add_classification}, {
12260 FOURCC__mak, GST_TAG_DEVICE_MANUFACTURER, NULL, qtdemux_tag_add_str}, {
12261 FOURCC__mod, GST_TAG_DEVICE_MODEL, NULL, qtdemux_tag_add_str}, {
12262 FOURCC__swr, GST_TAG_APPLICATION_NAME, NULL, qtdemux_tag_add_str}, {
12264 /* This is a special case, some tags are stored in this
12265 * 'reverse dns naming', according to:
12266 * http://atomicparsley.sourceforge.net/mpeg-4files.html and
12269 FOURCC_____, "", NULL, qtdemux_tag_add_revdns}, {
12270 /* see http://www.mp4ra.org/specs.html for ID32 in meta box */
12271 FOURCC_ID32, "", NULL, qtdemux_tag_add_id32}
12274 struct _GstQtDemuxTagList
12277 GstTagList *taglist;
12279 typedef struct _GstQtDemuxTagList GstQtDemuxTagList;
12282 qtdemux_tag_add_blob (GNode * node, GstQtDemuxTagList * qtdemuxtaglist)
12288 const gchar *style;
12293 GstQTDemux *demux = qtdemuxtaglist->demux;
12294 GstTagList *taglist = qtdemuxtaglist->taglist;
12297 len = QT_UINT32 (data);
12298 buf = gst_buffer_new_and_alloc (len);
12299 gst_buffer_fill (buf, 0, data, len);
12301 /* heuristic to determine style of tag */
12302 if (QT_FOURCC (data + 4) == FOURCC_____ ||
12303 (len > 8 + 12 && QT_FOURCC (data + 12) == FOURCC_data))
12305 else if (demux->major_brand == FOURCC_qt__)
12306 style = "quicktime";
12307 /* fall back to assuming iso/3gp tag style */
12311 /* santize the name for the caps. */
12312 for (i = 0; i < 4; i++) {
12313 guint8 d = data[4 + i];
12314 if (g_ascii_isalnum (d))
12315 ndata[i] = g_ascii_tolower (d);
12320 media_type = g_strdup_printf ("application/x-gst-qt-%c%c%c%c-tag",
12321 ndata[0], ndata[1], ndata[2], ndata[3]);
12322 GST_DEBUG_OBJECT (demux, "media type %s", media_type);
12324 s = gst_structure_new (media_type, "style", G_TYPE_STRING, style, NULL);
12325 sample = gst_sample_new (buf, NULL, NULL, s);
12326 gst_buffer_unref (buf);
12327 g_free (media_type);
12329 GST_DEBUG_OBJECT (demux, "adding private tag; size %d, info %" GST_PTR_FORMAT,
12332 gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND,
12333 GST_QT_DEMUX_PRIVATE_TAG, sample, NULL);
12335 gst_sample_unref (sample);
12339 qtdemux_parse_udta (GstQTDemux * qtdemux, GstTagList * taglist, GNode * udta)
12346 GstQtDemuxTagList demuxtaglist;
12348 demuxtaglist.demux = qtdemux;
12349 demuxtaglist.taglist = taglist;
12351 meta = qtdemux_tree_get_child_by_type (udta, FOURCC_meta);
12352 if (meta != NULL) {
12353 ilst = qtdemux_tree_get_child_by_type (meta, FOURCC_ilst);
12354 if (ilst == NULL) {
12355 GST_LOG_OBJECT (qtdemux, "no ilst");
12360 GST_LOG_OBJECT (qtdemux, "no meta so using udta itself");
12364 while (i < G_N_ELEMENTS (add_funcs)) {
12365 node = qtdemux_tree_get_child_by_type (ilst, add_funcs[i].fourcc);
12369 len = QT_UINT32 (node->data);
12371 GST_DEBUG_OBJECT (qtdemux, "too small tag atom %" GST_FOURCC_FORMAT,
12372 GST_FOURCC_ARGS (add_funcs[i].fourcc));
12374 add_funcs[i].func (qtdemux, taglist, add_funcs[i].gst_tag,
12375 add_funcs[i].gst_tag_bis, node);
12377 g_node_destroy (node);
12383 /* parsed nodes have been removed, pass along remainder as blob */
12384 g_node_children_foreach (ilst, G_TRAVERSE_ALL,
12385 (GNodeForeachFunc) qtdemux_tag_add_blob, &demuxtaglist);
12387 /* parse up XMP_ node if existing */
12388 xmp_ = qtdemux_tree_get_child_by_type (udta, FOURCC_XMP_);
12389 if (xmp_ != NULL) {
12391 GstTagList *xmptaglist;
12393 buf = _gst_buffer_new_wrapped (((guint8 *) xmp_->data) + 8,
12394 QT_UINT32 ((guint8 *) xmp_->data) - 8, NULL);
12395 xmptaglist = gst_tag_list_from_xmp_buffer (buf);
12396 gst_buffer_unref (buf);
12398 qtdemux_handle_xmp_taglist (qtdemux, taglist, xmptaglist);
12400 GST_DEBUG_OBJECT (qtdemux, "No XMP_ node found");
12406 GstStructure *structure; /* helper for sort function */
12408 guint min_req_bitrate;
12409 guint min_req_qt_version;
12413 qtdemux_redirects_sort_func (gconstpointer a, gconstpointer b)
12415 GstQtReference *ref_a = (GstQtReference *) a;
12416 GstQtReference *ref_b = (GstQtReference *) b;
12418 if (ref_b->min_req_qt_version != ref_a->min_req_qt_version)
12419 return ref_b->min_req_qt_version - ref_a->min_req_qt_version;
12421 /* known bitrates go before unknown; higher bitrates go first */
12422 return ref_b->min_req_bitrate - ref_a->min_req_bitrate;
12425 /* sort the redirects and post a message for the application.
12428 qtdemux_process_redirects (GstQTDemux * qtdemux, GList * references)
12430 GstQtReference *best;
12433 GValue list_val = { 0, };
12436 g_assert (references != NULL);
12438 references = g_list_sort (references, qtdemux_redirects_sort_func);
12440 best = (GstQtReference *) references->data;
12442 g_value_init (&list_val, GST_TYPE_LIST);
12444 for (l = references; l != NULL; l = l->next) {
12445 GstQtReference *ref = (GstQtReference *) l->data;
12446 GValue struct_val = { 0, };
12448 ref->structure = gst_structure_new ("redirect",
12449 "new-location", G_TYPE_STRING, ref->location, NULL);
12451 if (ref->min_req_bitrate > 0) {
12452 gst_structure_set (ref->structure, "minimum-bitrate", G_TYPE_INT,
12453 ref->min_req_bitrate, NULL);
12456 g_value_init (&struct_val, GST_TYPE_STRUCTURE);
12457 g_value_set_boxed (&struct_val, ref->structure);
12458 gst_value_list_append_value (&list_val, &struct_val);
12459 g_value_unset (&struct_val);
12460 /* don't free anything here yet, since we need best->structure below */
12463 g_assert (best != NULL);
12464 s = gst_structure_copy (best->structure);
12466 if (g_list_length (references) > 1) {
12467 gst_structure_set_value (s, "locations", &list_val);
12470 g_value_unset (&list_val);
12472 for (l = references; l != NULL; l = l->next) {
12473 GstQtReference *ref = (GstQtReference *) l->data;
12475 gst_structure_free (ref->structure);
12476 g_free (ref->location);
12479 g_list_free (references);
12481 GST_INFO_OBJECT (qtdemux, "posting redirect message: %" GST_PTR_FORMAT, s);
12482 msg = gst_message_new_element (GST_OBJECT_CAST (qtdemux), s);
12483 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
12484 qtdemux->posted_redirect = TRUE;
12487 /* look for redirect nodes, collect all redirect information and
12491 qtdemux_parse_redirects (GstQTDemux * qtdemux)
12493 GNode *rmra, *rmda, *rdrf;
12495 rmra = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_rmra);
12497 GList *redirects = NULL;
12499 rmda = qtdemux_tree_get_child_by_type (rmra, FOURCC_rmda);
12501 GstQtReference ref = { NULL, NULL, 0, 0 };
12502 GNode *rmdr, *rmvc;
12504 if ((rmdr = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmdr))) {
12505 ref.min_req_bitrate = QT_UINT32 ((guint8 *) rmdr->data + 12);
12506 GST_LOG_OBJECT (qtdemux, "data rate atom, required bitrate = %u",
12507 ref.min_req_bitrate);
12510 if ((rmvc = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmvc))) {
12511 guint32 package = QT_FOURCC ((guint8 *) rmvc->data + 12);
12512 guint version = QT_UINT32 ((guint8 *) rmvc->data + 16);
12514 #ifndef GST_DISABLE_GST_DEBUG
12515 guint bitmask = QT_UINT32 ((guint8 *) rmvc->data + 20);
12517 guint check_type = QT_UINT16 ((guint8 *) rmvc->data + 24);
12519 GST_LOG_OBJECT (qtdemux,
12520 "version check atom [%" GST_FOURCC_FORMAT "], version=0x%08x"
12521 ", mask=%08x, check_type=%u", GST_FOURCC_ARGS (package), version,
12522 bitmask, check_type);
12523 if (package == FOURCC_qtim && check_type == 0) {
12524 ref.min_req_qt_version = version;
12528 rdrf = qtdemux_tree_get_child_by_type (rmda, FOURCC_rdrf);
12534 ref_len = QT_UINT32 ((guint8 *) rdrf->data);
12535 if (ref_len > 20) {
12536 ref_type = QT_FOURCC ((guint8 *) rdrf->data + 12);
12537 ref_data = (guint8 *) rdrf->data + 20;
12538 if (ref_type == FOURCC_alis) {
12539 guint record_len, record_version, fn_len;
12541 if (ref_len > 70) {
12542 /* MacOSX alias record, google for alias-layout.txt */
12543 record_len = QT_UINT16 (ref_data + 4);
12544 record_version = QT_UINT16 (ref_data + 4 + 2);
12545 fn_len = QT_UINT8 (ref_data + 50);
12546 if (record_len > 50 && record_version == 2 && fn_len > 0) {
12547 ref.location = g_strndup ((gchar *) ref_data + 51, fn_len);
12550 GST_WARNING_OBJECT (qtdemux, "Invalid rdrf/alis size (%u < 70)",
12553 } else if (ref_type == FOURCC_url_) {
12554 ref.location = g_strndup ((gchar *) ref_data, ref_len - 8);
12556 GST_DEBUG_OBJECT (qtdemux,
12557 "unknown rdrf reference type %" GST_FOURCC_FORMAT,
12558 GST_FOURCC_ARGS (ref_type));
12560 if (ref.location != NULL) {
12561 GST_INFO_OBJECT (qtdemux, "New location: %s", ref.location);
12563 g_list_prepend (redirects, g_memdup (&ref, sizeof (ref)));
12565 GST_WARNING_OBJECT (qtdemux,
12566 "Failed to extract redirect location from rdrf atom");
12569 GST_WARNING_OBJECT (qtdemux, "Invalid rdrf size (%u < 20)", ref_len);
12573 /* look for others */
12574 rmda = qtdemux_tree_get_sibling_by_type (rmda, FOURCC_rmda);
12577 if (redirects != NULL) {
12578 qtdemux_process_redirects (qtdemux, redirects);
12584 static GstTagList *
12585 qtdemux_add_container_format (GstQTDemux * qtdemux, GstTagList * tags)
12589 if (tags == NULL) {
12590 tags = gst_tag_list_new_empty ();
12591 gst_tag_list_set_scope (tags, GST_TAG_SCOPE_GLOBAL);
12594 if (qtdemux->major_brand == FOURCC_mjp2)
12595 fmt = "Motion JPEG 2000";
12596 else if ((qtdemux->major_brand & 0xffff) == FOURCC_3g__)
12598 else if (qtdemux->major_brand == FOURCC_qt__)
12600 else if (qtdemux->fragmented)
12603 fmt = "ISO MP4/M4A";
12605 GST_LOG_OBJECT (qtdemux, "mapped %" GST_FOURCC_FORMAT " to '%s'",
12606 GST_FOURCC_ARGS (qtdemux->major_brand), fmt);
12608 gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_CONTAINER_FORMAT,
12614 /* we have read the complete moov node now.
12615 * This function parses all of the relevant info, creates the traks and
12616 * prepares all data structures for playback
12619 qtdemux_parse_tree (GstQTDemux * qtdemux)
12625 GstClockTime duration;
12627 guint64 creation_time;
12628 GstDateTime *datetime = NULL;
12631 /* make sure we have a usable taglist */
12632 if (!qtdemux->tag_list) {
12633 qtdemux->tag_list = gst_tag_list_new_empty ();
12634 gst_tag_list_set_scope (qtdemux->tag_list, GST_TAG_SCOPE_GLOBAL);
12636 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
12639 mvhd = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvhd);
12640 if (mvhd == NULL) {
12641 GST_LOG_OBJECT (qtdemux, "No mvhd node found, looking for redirects.");
12642 return qtdemux_parse_redirects (qtdemux);
12645 version = QT_UINT8 ((guint8 *) mvhd->data + 8);
12646 if (version == 1) {
12647 creation_time = QT_UINT64 ((guint8 *) mvhd->data + 12);
12648 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 28);
12649 qtdemux->duration = QT_UINT64 ((guint8 *) mvhd->data + 32);
12650 } else if (version == 0) {
12651 creation_time = QT_UINT32 ((guint8 *) mvhd->data + 12);
12652 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 20);
12653 qtdemux->duration = QT_UINT32 ((guint8 *) mvhd->data + 24);
12655 GST_WARNING_OBJECT (qtdemux, "Unhandled mvhd version %d", version);
12659 /* Moving qt creation time (secs since 1904) to unix time */
12660 if (creation_time != 0) {
12661 /* Try to use epoch first as it should be faster and more commonly found */
12662 if (creation_time >= QTDEMUX_SECONDS_FROM_1904_TO_1970) {
12665 creation_time -= QTDEMUX_SECONDS_FROM_1904_TO_1970;
12666 /* some data cleansing sanity */
12667 g_get_current_time (&now);
12668 if (now.tv_sec + 24 * 3600 < creation_time) {
12669 GST_DEBUG_OBJECT (qtdemux, "discarding bogus future creation time");
12671 datetime = gst_date_time_new_from_unix_epoch_utc (creation_time);
12674 GDateTime *base_dt = g_date_time_new_utc (1904, 1, 1, 0, 0, 0);
12675 GDateTime *dt, *dt_local;
12677 dt = g_date_time_add_seconds (base_dt, creation_time);
12678 dt_local = g_date_time_to_local (dt);
12679 datetime = gst_date_time_new_from_g_date_time (dt_local);
12681 g_date_time_unref (base_dt);
12682 g_date_time_unref (dt);
12686 /* Use KEEP as explicit tags should have a higher priority than mvhd tag */
12687 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_KEEP, GST_TAG_DATE_TIME,
12689 gst_date_time_unref (datetime);
12692 GST_INFO_OBJECT (qtdemux, "timescale: %u", qtdemux->timescale);
12693 GST_INFO_OBJECT (qtdemux, "duration: %" G_GUINT64_FORMAT, qtdemux->duration);
12695 /* check for fragmented file and get some (default) data */
12696 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
12699 GstByteReader mehd_data;
12701 /* let track parsing or anyone know weird stuff might happen ... */
12702 qtdemux->fragmented = TRUE;
12704 /* compensate for total duration */
12705 mehd = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_mehd, &mehd_data);
12707 qtdemux_parse_mehd (qtdemux, &mehd_data);
12710 /* set duration in the segment info */
12711 gst_qtdemux_get_duration (qtdemux, &duration);
12713 qtdemux->segment.duration = duration;
12714 /* also do not exceed duration; stop is set that way post seek anyway,
12715 * and segment activation falls back to duration,
12716 * whereas loop only checks stop, so let's align this here as well */
12717 qtdemux->segment.stop = duration;
12720 /* parse all traks */
12721 trak = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_trak);
12723 qtdemux_parse_trak (qtdemux, trak);
12724 /* iterate all siblings */
12725 trak = qtdemux_tree_get_sibling_by_type (trak, FOURCC_trak);
12728 if (!qtdemux->tag_list) {
12729 GST_DEBUG_OBJECT (qtdemux, "new tag list");
12730 qtdemux->tag_list = gst_tag_list_new_empty ();
12731 gst_tag_list_set_scope (qtdemux->tag_list, GST_TAG_SCOPE_GLOBAL);
12733 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
12737 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_udta);
12739 qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
12741 GST_LOG_OBJECT (qtdemux, "No udta node found.");
12744 /* maybe also some tags in meta box */
12745 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_meta);
12747 GST_DEBUG_OBJECT (qtdemux, "Parsing meta box for tags.");
12748 qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
12750 GST_LOG_OBJECT (qtdemux, "No meta node found.");
12753 /* parse any protection system info */
12754 pssh = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_pssh);
12756 GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
12757 qtdemux_parse_pssh (qtdemux, pssh);
12758 pssh = qtdemux_tree_get_sibling_by_type (pssh, FOURCC_pssh);
12761 qtdemux->tag_list = qtdemux_add_container_format (qtdemux, qtdemux->tag_list);
12766 /* taken from ffmpeg */
12768 read_descr_size (guint8 * ptr, guint8 * end, guint8 ** end_out)
12780 len = (len << 7) | (c & 0x7f);
12788 /* this can change the codec originally present in @list */
12790 gst_qtdemux_handle_esds (GstQTDemux * qtdemux, QtDemuxStream * stream,
12791 GNode * esds, GstTagList * list)
12793 int len = QT_UINT32 (esds->data);
12794 guint8 *ptr = esds->data;
12795 guint8 *end = ptr + len;
12797 guint8 *data_ptr = NULL;
12799 guint8 object_type_id = 0;
12800 const char *codec_name = NULL;
12801 GstCaps *caps = NULL;
12803 GST_MEMDUMP_OBJECT (qtdemux, "esds", ptr, len);
12805 GST_DEBUG_OBJECT (qtdemux, "version/flags = %08x", QT_UINT32 (ptr));
12807 while (ptr + 1 < end) {
12808 tag = QT_UINT8 (ptr);
12809 GST_DEBUG_OBJECT (qtdemux, "tag = %02x", tag);
12811 len = read_descr_size (ptr, end, &ptr);
12812 GST_DEBUG_OBJECT (qtdemux, "len = %d", len);
12814 /* Check the stated amount of data is available for reading */
12815 if (len < 0 || ptr + len > end)
12819 case ES_DESCRIPTOR_TAG:
12820 GST_DEBUG_OBJECT (qtdemux, "ID %04x", QT_UINT16 (ptr));
12821 GST_DEBUG_OBJECT (qtdemux, "priority %04x", QT_UINT8 (ptr + 2));
12824 case DECODER_CONFIG_DESC_TAG:{
12825 guint max_bitrate, avg_bitrate;
12827 object_type_id = QT_UINT8 (ptr);
12828 max_bitrate = QT_UINT32 (ptr + 5);
12829 avg_bitrate = QT_UINT32 (ptr + 9);
12830 GST_DEBUG_OBJECT (qtdemux, "object_type_id %02x", object_type_id);
12831 GST_DEBUG_OBJECT (qtdemux, "stream_type %02x", QT_UINT8 (ptr + 1));
12832 GST_DEBUG_OBJECT (qtdemux, "buffer_size_db %02x", QT_UINT24 (ptr + 2));
12833 GST_DEBUG_OBJECT (qtdemux, "max bitrate %u", max_bitrate);
12834 GST_DEBUG_OBJECT (qtdemux, "avg bitrate %u", avg_bitrate);
12835 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
12836 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
12837 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
12839 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
12840 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
12841 avg_bitrate, NULL);
12846 case DECODER_SPECIFIC_INFO_TAG:
12847 GST_MEMDUMP_OBJECT (qtdemux, "data", ptr, len);
12848 if (object_type_id == 0xe0 && len == 0x40) {
12854 GST_DEBUG_OBJECT (qtdemux,
12855 "Have VOBSUB palette. Creating palette event");
12856 /* move to decConfigDescr data and read palette */
12858 for (i = 0; i < 16; i++) {
12859 clut[i] = QT_UINT32 (data);
12863 s = gst_structure_new ("application/x-gst-dvd", "event",
12864 G_TYPE_STRING, "dvd-spu-clut-change",
12865 "clut00", G_TYPE_INT, clut[0], "clut01", G_TYPE_INT, clut[1],
12866 "clut02", G_TYPE_INT, clut[2], "clut03", G_TYPE_INT, clut[3],
12867 "clut04", G_TYPE_INT, clut[4], "clut05", G_TYPE_INT, clut[5],
12868 "clut06", G_TYPE_INT, clut[6], "clut07", G_TYPE_INT, clut[7],
12869 "clut08", G_TYPE_INT, clut[8], "clut09", G_TYPE_INT, clut[9],
12870 "clut10", G_TYPE_INT, clut[10], "clut11", G_TYPE_INT, clut[11],
12871 "clut12", G_TYPE_INT, clut[12], "clut13", G_TYPE_INT, clut[13],
12872 "clut14", G_TYPE_INT, clut[14], "clut15", G_TYPE_INT, clut[15],
12875 /* store event and trigger custom processing */
12876 stream->pending_event =
12877 gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s);
12879 /* Generic codec_data handler puts it on the caps */
12886 case SL_CONFIG_DESC_TAG:
12887 GST_DEBUG_OBJECT (qtdemux, "data %02x", QT_UINT8 (ptr));
12891 GST_DEBUG_OBJECT (qtdemux, "Unknown/unhandled descriptor tag %02x",
12893 GST_MEMDUMP_OBJECT (qtdemux, "descriptor data", ptr, len);
12899 /* object_type_id in the esds atom in mp4a and mp4v tells us which codec is
12900 * in use, and should also be used to override some other parameters for some
12902 switch (object_type_id) {
12903 case 0x20: /* MPEG-4 */
12904 /* 4 bytes for the visual_object_sequence_start_code and 1 byte for the
12905 * profile_and_level_indication */
12906 if (data_ptr != NULL && data_len >= 5 &&
12907 GST_READ_UINT32_BE (data_ptr) == 0x000001b0) {
12908 gst_codec_utils_mpeg4video_caps_set_level_and_profile (stream->caps,
12909 data_ptr + 4, data_len - 4);
12911 break; /* Nothing special needed here */
12912 case 0x21: /* H.264 */
12913 codec_name = "H.264 / AVC";
12914 caps = gst_caps_new_simple ("video/x-h264",
12915 "stream-format", G_TYPE_STRING, "avc",
12916 "alignment", G_TYPE_STRING, "au", NULL);
12918 case 0x40: /* AAC (any) */
12919 case 0x66: /* AAC Main */
12920 case 0x67: /* AAC LC */
12921 case 0x68: /* AAC SSR */
12922 /* Override channels and rate based on the codec_data, as it's often
12924 /* Only do so for basic setup without HE-AAC extension */
12925 if (data_ptr && data_len == 2) {
12926 guint channels, rate;
12928 channels = gst_codec_utils_aac_get_channels (data_ptr, data_len);
12930 stream->n_channels = channels;
12932 rate = gst_codec_utils_aac_get_sample_rate (data_ptr, data_len);
12934 stream->rate = rate;
12937 /* Set level and profile if possible */
12938 if (data_ptr != NULL && data_len >= 2) {
12939 gst_codec_utils_aac_caps_set_level_and_profile (stream->caps,
12940 data_ptr, data_len);
12942 const gchar *profile_str = NULL;
12945 guint8 *codec_data;
12946 gint rate_idx, profile;
12948 /* No codec_data, let's invent something.
12949 * FIXME: This is wrong for SBR! */
12951 GST_WARNING_OBJECT (qtdemux, "No codec_data for AAC available");
12953 buffer = gst_buffer_new_and_alloc (2);
12954 gst_buffer_map (buffer, &map, GST_MAP_WRITE);
12955 codec_data = map.data;
12958 gst_codec_utils_aac_get_index_from_sample_rate (stream->rate);
12960 switch (object_type_id) {
12962 profile_str = "main";
12966 profile_str = "lc";
12970 profile_str = "ssr";
12978 codec_data[0] = ((profile + 1) << 3) | ((rate_idx & 0xE) >> 1);
12979 codec_data[1] = ((rate_idx & 0x1) << 7) | (stream->n_channels << 3);
12981 gst_buffer_unmap (buffer, &map);
12982 gst_caps_set_simple (stream->caps, "codec_data", GST_TYPE_BUFFER,
12984 gst_buffer_unref (buffer);
12987 gst_caps_set_simple (stream->caps, "profile", G_TYPE_STRING,
12988 profile_str, NULL);
12992 case 0x60: /* MPEG-2, various profiles */
12998 codec_name = "MPEG-2 video";
12999 caps = gst_caps_new_simple ("video/mpeg",
13000 "mpegversion", G_TYPE_INT, 2,
13001 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13003 case 0x69: /* MPEG-2 BC audio */
13004 case 0x6B: /* MPEG-1 audio */
13005 caps = gst_caps_new_simple ("audio/mpeg",
13006 "mpegversion", G_TYPE_INT, 1, "parsed", G_TYPE_BOOLEAN, TRUE, NULL);
13007 codec_name = "MPEG-1 audio";
13009 case 0x6A: /* MPEG-1 */
13010 codec_name = "MPEG-1 video";
13011 caps = gst_caps_new_simple ("video/mpeg",
13012 "mpegversion", G_TYPE_INT, 1,
13013 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13015 case 0x6C: /* MJPEG */
13017 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
13019 codec_name = "Motion-JPEG";
13021 case 0x6D: /* PNG */
13023 gst_caps_new_simple ("image/png", "parsed", G_TYPE_BOOLEAN, TRUE,
13025 codec_name = "PNG still images";
13027 case 0x6E: /* JPEG2000 */
13028 codec_name = "JPEG-2000";
13029 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
13031 case 0xA4: /* Dirac */
13032 codec_name = "Dirac";
13033 caps = gst_caps_new_empty_simple ("video/x-dirac");
13035 case 0xA5: /* AC3 */
13036 codec_name = "AC-3 audio";
13037 caps = gst_caps_new_simple ("audio/x-ac3",
13038 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
13040 case 0xA9: /* AC3 */
13041 codec_name = "DTS audio";
13042 caps = gst_caps_new_simple ("audio/x-dts",
13043 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
13045 case 0xE1: /* QCELP */
13046 /* QCELP, the codec_data is a riff tag (little endian) with
13047 * 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). */
13048 caps = gst_caps_new_empty_simple ("audio/qcelp");
13049 codec_name = "QCELP";
13055 /* If we have a replacement caps, then change our caps for this stream */
13057 gst_caps_unref (stream->caps);
13058 stream->caps = caps;
13061 if (codec_name && list)
13062 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
13063 GST_TAG_AUDIO_CODEC, codec_name, NULL);
13065 /* Add the codec_data attribute to caps, if we have it */
13069 buffer = gst_buffer_new_and_alloc (data_len);
13070 gst_buffer_fill (buffer, 0, data_ptr, data_len);
13072 GST_DEBUG_OBJECT (qtdemux, "setting codec_data from esds");
13073 GST_MEMDUMP_OBJECT (qtdemux, "codec_data from esds", data_ptr, data_len);
13075 gst_caps_set_simple (stream->caps, "codec_data", GST_TYPE_BUFFER,
13077 gst_buffer_unref (buffer);
13082 #define _codec(name) \
13084 if (codec_name) { \
13085 *codec_name = g_strdup (name); \
13090 qtdemux_video_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
13091 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
13093 GstCaps *caps = NULL;
13094 GstVideoFormat format = GST_VIDEO_FORMAT_UNKNOWN;
13097 case GST_MAKE_FOURCC ('p', 'n', 'g', ' '):
13098 _codec ("PNG still images");
13099 caps = gst_caps_new_empty_simple ("image/png");
13102 _codec ("JPEG still images");
13104 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
13107 case GST_MAKE_FOURCC ('m', 'j', 'p', 'a'):
13108 case GST_MAKE_FOURCC ('A', 'V', 'D', 'J'):
13109 case GST_MAKE_FOURCC ('M', 'J', 'P', 'G'):
13110 case GST_MAKE_FOURCC ('d', 'm', 'b', '1'):
13111 _codec ("Motion-JPEG");
13113 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
13116 case GST_MAKE_FOURCC ('m', 'j', 'p', 'b'):
13117 _codec ("Motion-JPEG format B");
13118 caps = gst_caps_new_empty_simple ("video/x-mjpeg-b");
13121 _codec ("JPEG-2000");
13122 /* override to what it should be according to spec, avoid palette_data */
13123 stream->bits_per_sample = 24;
13124 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
13127 _codec ("Sorensen video v.3");
13128 caps = gst_caps_new_simple ("video/x-svq",
13129 "svqversion", G_TYPE_INT, 3, NULL);
13131 case GST_MAKE_FOURCC ('s', 'v', 'q', 'i'):
13132 case GST_MAKE_FOURCC ('S', 'V', 'Q', '1'):
13133 _codec ("Sorensen video v.1");
13134 caps = gst_caps_new_simple ("video/x-svq",
13135 "svqversion", G_TYPE_INT, 1, NULL);
13137 case GST_MAKE_FOURCC ('W', 'R', 'A', 'W'):
13138 caps = gst_caps_new_empty_simple ("video/x-raw");
13139 gst_caps_set_simple (caps, "format", G_TYPE_STRING, "RGB8P", NULL);
13140 _codec ("Windows Raw RGB");
13146 bps = QT_UINT16 (stsd_data + 98);
13149 format = GST_VIDEO_FORMAT_RGB15;
13152 format = GST_VIDEO_FORMAT_RGB16;
13155 format = GST_VIDEO_FORMAT_RGB;
13158 format = GST_VIDEO_FORMAT_ARGB;
13166 case GST_MAKE_FOURCC ('y', 'v', '1', '2'):
13167 format = GST_VIDEO_FORMAT_I420;
13169 case GST_MAKE_FOURCC ('y', 'u', 'v', '2'):
13170 case GST_MAKE_FOURCC ('Y', 'u', 'v', '2'):
13171 format = GST_VIDEO_FORMAT_I420;
13174 case GST_MAKE_FOURCC ('2', 'V', 'u', 'y'):
13175 format = GST_VIDEO_FORMAT_UYVY;
13177 case GST_MAKE_FOURCC ('v', '3', '0', '8'):
13178 format = GST_VIDEO_FORMAT_v308;
13180 case GST_MAKE_FOURCC ('v', '2', '1', '6'):
13181 format = GST_VIDEO_FORMAT_v216;
13184 format = GST_VIDEO_FORMAT_v210;
13186 case GST_MAKE_FOURCC ('r', '2', '1', '0'):
13187 format = GST_VIDEO_FORMAT_r210;
13189 /* Packed YUV 4:4:4 10 bit in 32 bits, complex
13190 case GST_MAKE_FOURCC ('v', '4', '1', '0'):
13191 format = GST_VIDEO_FORMAT_v410;
13194 /* Packed YUV 4:4:4:4 8 bit in 32 bits
13195 * but different order than AYUV
13196 case GST_MAKE_FOURCC ('v', '4', '0', '8'):
13197 format = GST_VIDEO_FORMAT_v408;
13200 case GST_MAKE_FOURCC ('m', 'p', 'e', 'g'):
13201 case GST_MAKE_FOURCC ('m', 'p', 'g', '1'):
13202 _codec ("MPEG-1 video");
13203 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
13204 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13206 case GST_MAKE_FOURCC ('h', 'd', 'v', '1'): /* HDV 720p30 */
13207 case GST_MAKE_FOURCC ('h', 'd', 'v', '2'): /* HDV 1080i60 */
13208 case GST_MAKE_FOURCC ('h', 'd', 'v', '3'): /* HDV 1080i50 */
13209 case GST_MAKE_FOURCC ('h', 'd', 'v', '4'): /* HDV 720p24 */
13210 case GST_MAKE_FOURCC ('h', 'd', 'v', '5'): /* HDV 720p25 */
13211 case GST_MAKE_FOURCC ('h', 'd', 'v', '6'): /* HDV 1080p24 */
13212 case GST_MAKE_FOURCC ('h', 'd', 'v', '7'): /* HDV 1080p25 */
13213 case GST_MAKE_FOURCC ('h', 'd', 'v', '8'): /* HDV 1080p30 */
13214 case GST_MAKE_FOURCC ('h', 'd', 'v', '9'): /* HDV 720p60 */
13215 case GST_MAKE_FOURCC ('h', 'd', 'v', 'a'): /* HDV 720p50 */
13216 case GST_MAKE_FOURCC ('m', 'x', '5', 'n'): /* MPEG2 IMX NTSC 525/60 50mb/s produced by FCP */
13217 case GST_MAKE_FOURCC ('m', 'x', '5', 'p'): /* MPEG2 IMX PAL 625/60 50mb/s produced by FCP */
13218 case GST_MAKE_FOURCC ('m', 'x', '4', 'n'): /* MPEG2 IMX NTSC 525/60 40mb/s produced by FCP */
13219 case GST_MAKE_FOURCC ('m', 'x', '4', 'p'): /* MPEG2 IMX PAL 625/60 40mb/s produced by FCP */
13220 case GST_MAKE_FOURCC ('m', 'x', '3', 'n'): /* MPEG2 IMX NTSC 525/60 30mb/s produced by FCP */
13221 case GST_MAKE_FOURCC ('m', 'x', '3', 'p'): /* MPEG2 IMX PAL 625/50 30mb/s produced by FCP */
13222 case GST_MAKE_FOURCC ('x', 'd', 'v', '1'): /* XDCAM HD 720p30 35Mb/s */
13223 case GST_MAKE_FOURCC ('x', 'd', 'v', '2'): /* XDCAM HD 1080i60 35Mb/s */
13224 case GST_MAKE_FOURCC ('x', 'd', 'v', '3'): /* XDCAM HD 1080i50 35Mb/s */
13225 case GST_MAKE_FOURCC ('x', 'd', 'v', '4'): /* XDCAM HD 720p24 35Mb/s */
13226 case GST_MAKE_FOURCC ('x', 'd', 'v', '5'): /* XDCAM HD 720p25 35Mb/s */
13227 case GST_MAKE_FOURCC ('x', 'd', 'v', '6'): /* XDCAM HD 1080p24 35Mb/s */
13228 case GST_MAKE_FOURCC ('x', 'd', 'v', '7'): /* XDCAM HD 1080p25 35Mb/s */
13229 case GST_MAKE_FOURCC ('x', 'd', 'v', '8'): /* XDCAM HD 1080p30 35Mb/s */
13230 case GST_MAKE_FOURCC ('x', 'd', 'v', '9'): /* XDCAM HD 720p60 35Mb/s */
13231 case GST_MAKE_FOURCC ('x', 'd', 'v', 'a'): /* XDCAM HD 720p50 35Mb/s */
13232 case GST_MAKE_FOURCC ('x', 'd', 'v', 'b'): /* XDCAM EX 1080i60 50Mb/s CBR */
13233 case GST_MAKE_FOURCC ('x', 'd', 'v', 'c'): /* XDCAM EX 1080i50 50Mb/s CBR */
13234 case GST_MAKE_FOURCC ('x', 'd', 'v', 'd'): /* XDCAM HD 1080p24 50Mb/s CBR */
13235 case GST_MAKE_FOURCC ('x', 'd', 'v', 'e'): /* XDCAM HD 1080p25 50Mb/s CBR */
13236 case GST_MAKE_FOURCC ('x', 'd', 'v', 'f'): /* XDCAM HD 1080p30 50Mb/s CBR */
13237 case GST_MAKE_FOURCC ('x', 'd', '5', '1'): /* XDCAM HD422 720p30 50Mb/s CBR */
13238 case GST_MAKE_FOURCC ('x', 'd', '5', '4'): /* XDCAM HD422 720p24 50Mb/s CBR */
13239 case GST_MAKE_FOURCC ('x', 'd', '5', '5'): /* XDCAM HD422 720p25 50Mb/s CBR */
13240 case GST_MAKE_FOURCC ('x', 'd', '5', '9'): /* XDCAM HD422 720p60 50Mb/s CBR */
13241 case GST_MAKE_FOURCC ('x', 'd', '5', 'a'): /* XDCAM HD422 720p50 50Mb/s CBR */
13242 case GST_MAKE_FOURCC ('x', 'd', '5', 'b'): /* XDCAM HD422 1080i50 50Mb/s CBR */
13243 case GST_MAKE_FOURCC ('x', 'd', '5', 'c'): /* XDCAM HD422 1080i50 50Mb/s CBR */
13244 case GST_MAKE_FOURCC ('x', 'd', '5', 'd'): /* XDCAM HD422 1080p24 50Mb/s CBR */
13245 case GST_MAKE_FOURCC ('x', 'd', '5', 'e'): /* XDCAM HD422 1080p25 50Mb/s CBR */
13246 case GST_MAKE_FOURCC ('x', 'd', '5', 'f'): /* XDCAM HD422 1080p30 50Mb/s CBR */
13247 case GST_MAKE_FOURCC ('x', 'd', 'h', 'd'): /* XDCAM HD 540p */
13248 case GST_MAKE_FOURCC ('x', 'd', 'h', '2'): /* XDCAM HD422 540p */
13249 case GST_MAKE_FOURCC ('A', 'V', 'm', 'p'): /* AVID IMX PAL */
13250 case GST_MAKE_FOURCC ('m', 'p', 'g', '2'): /* AVID IMX PAL */
13251 case GST_MAKE_FOURCC ('m', 'p', '2', 'v'): /* AVID IMX PAL */
13252 _codec ("MPEG-2 video");
13253 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 2,
13254 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13256 case GST_MAKE_FOURCC ('g', 'i', 'f', ' '):
13257 _codec ("GIF still images");
13258 caps = gst_caps_new_empty_simple ("image/gif");
13261 case GST_MAKE_FOURCC ('H', '2', '6', '3'):
13263 case GST_MAKE_FOURCC ('U', '2', '6', '3'):
13265 /* ffmpeg uses the height/width props, don't know why */
13266 caps = gst_caps_new_simple ("video/x-h263",
13267 "variant", G_TYPE_STRING, "itu", NULL);
13271 _codec ("MPEG-4 video");
13272 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
13273 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13275 case GST_MAKE_FOURCC ('3', 'i', 'v', 'd'):
13276 case GST_MAKE_FOURCC ('3', 'I', 'V', 'D'):
13277 _codec ("Microsoft MPEG-4 4.3"); /* FIXME? */
13278 caps = gst_caps_new_simple ("video/x-msmpeg",
13279 "msmpegversion", G_TYPE_INT, 43, NULL);
13281 case GST_MAKE_FOURCC ('D', 'I', 'V', '3'):
13283 caps = gst_caps_new_simple ("video/x-divx",
13284 "divxversion", G_TYPE_INT, 3, NULL);
13286 case GST_MAKE_FOURCC ('D', 'I', 'V', 'X'):
13287 case GST_MAKE_FOURCC ('d', 'i', 'v', 'x'):
13289 caps = gst_caps_new_simple ("video/x-divx",
13290 "divxversion", G_TYPE_INT, 4, NULL);
13292 case GST_MAKE_FOURCC ('D', 'X', '5', '0'):
13294 caps = gst_caps_new_simple ("video/x-divx",
13295 "divxversion", G_TYPE_INT, 5, NULL);
13298 case GST_MAKE_FOURCC ('F', 'F', 'V', '1'):
13300 caps = gst_caps_new_simple ("video/x-ffv",
13301 "ffvversion", G_TYPE_INT, 1, NULL);
13304 case GST_MAKE_FOURCC ('3', 'I', 'V', '1'):
13305 case GST_MAKE_FOURCC ('3', 'I', 'V', '2'):
13306 case GST_MAKE_FOURCC ('X', 'V', 'I', 'D'):
13307 case GST_MAKE_FOURCC ('x', 'v', 'i', 'd'):
13309 case GST_MAKE_FOURCC ('U', 'M', 'P', '4'):
13310 caps = gst_caps_new_simple ("video/mpeg",
13311 "mpegversion", G_TYPE_INT, 4, NULL);
13315 case GST_MAKE_FOURCC ('c', 'v', 'i', 'd'):
13316 _codec ("Cinepak");
13317 caps = gst_caps_new_empty_simple ("video/x-cinepak");
13319 case GST_MAKE_FOURCC ('q', 'd', 'r', 'w'):
13320 _codec ("Apple QuickDraw");
13321 caps = gst_caps_new_empty_simple ("video/x-qdrw");
13323 case GST_MAKE_FOURCC ('r', 'p', 'z', 'a'):
13324 _codec ("Apple video");
13325 caps = gst_caps_new_empty_simple ("video/x-apple-video");
13329 _codec ("H.264 / AVC");
13330 caps = gst_caps_new_simple ("video/x-h264",
13331 "stream-format", G_TYPE_STRING, "avc",
13332 "alignment", G_TYPE_STRING, "au", NULL);
13335 _codec ("H.264 / AVC");
13336 caps = gst_caps_new_simple ("video/x-h264",
13337 "stream-format", G_TYPE_STRING, "avc3",
13338 "alignment", G_TYPE_STRING, "au", NULL);
13342 _codec ("H.265 / HEVC");
13343 caps = gst_caps_new_simple ("video/x-h265",
13344 "stream-format", G_TYPE_STRING, "hvc1",
13345 "alignment", G_TYPE_STRING, "au", NULL);
13348 _codec ("H.265 / HEVC");
13349 caps = gst_caps_new_simple ("video/x-h265",
13350 "stream-format", G_TYPE_STRING, "hev1",
13351 "alignment", G_TYPE_STRING, "au", NULL);
13354 _codec ("Run-length encoding");
13355 caps = gst_caps_new_simple ("video/x-rle",
13356 "layout", G_TYPE_STRING, "quicktime", NULL);
13359 _codec ("Run-length encoding");
13360 caps = gst_caps_new_simple ("video/x-rle",
13361 "layout", G_TYPE_STRING, "microsoft", NULL);
13363 case GST_MAKE_FOURCC ('I', 'V', '3', '2'):
13364 case GST_MAKE_FOURCC ('i', 'v', '3', '2'):
13365 _codec ("Indeo Video 3");
13366 caps = gst_caps_new_simple ("video/x-indeo",
13367 "indeoversion", G_TYPE_INT, 3, NULL);
13369 case GST_MAKE_FOURCC ('I', 'V', '4', '1'):
13370 case GST_MAKE_FOURCC ('i', 'v', '4', '1'):
13371 _codec ("Intel Video 4");
13372 caps = gst_caps_new_simple ("video/x-indeo",
13373 "indeoversion", G_TYPE_INT, 4, NULL);
13377 case GST_MAKE_FOURCC ('d', 'v', 's', 'd'):
13378 case GST_MAKE_FOURCC ('D', 'V', 'S', 'D'):
13379 case GST_MAKE_FOURCC ('d', 'v', 'c', 's'):
13380 case GST_MAKE_FOURCC ('D', 'V', 'C', 'S'):
13381 case GST_MAKE_FOURCC ('d', 'v', '2', '5'):
13382 case GST_MAKE_FOURCC ('d', 'v', 'p', 'p'):
13383 _codec ("DV Video");
13384 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 25,
13385 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13387 case FOURCC_dv5n: /* DVCPRO50 NTSC */
13388 case FOURCC_dv5p: /* DVCPRO50 PAL */
13389 _codec ("DVCPro50 Video");
13390 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 50,
13391 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13393 case GST_MAKE_FOURCC ('d', 'v', 'h', '5'): /* DVCPRO HD 50i produced by FCP */
13394 case GST_MAKE_FOURCC ('d', 'v', 'h', '6'): /* DVCPRO HD 60i produced by FCP */
13395 _codec ("DVCProHD Video");
13396 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 100,
13397 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13399 case GST_MAKE_FOURCC ('s', 'm', 'c', ' '):
13400 _codec ("Apple Graphics (SMC)");
13401 caps = gst_caps_new_empty_simple ("video/x-smc");
13403 case GST_MAKE_FOURCC ('V', 'P', '3', '1'):
13405 caps = gst_caps_new_empty_simple ("video/x-vp3");
13407 case GST_MAKE_FOURCC ('V', 'P', '6', 'F'):
13408 _codec ("VP6 Flash");
13409 caps = gst_caps_new_empty_simple ("video/x-vp6-flash");
13413 caps = gst_caps_new_empty_simple ("video/x-theora");
13414 /* theora uses one byte of padding in the data stream because it does not
13415 * allow 0 sized packets while theora does */
13416 stream->padding = 1;
13420 caps = gst_caps_new_empty_simple ("video/x-dirac");
13422 case GST_MAKE_FOURCC ('t', 'i', 'f', 'f'):
13423 _codec ("TIFF still images");
13424 caps = gst_caps_new_empty_simple ("image/tiff");
13426 case GST_MAKE_FOURCC ('i', 'c', 'o', 'd'):
13427 _codec ("Apple Intermediate Codec");
13428 caps = gst_caps_from_string ("video/x-apple-intermediate-codec");
13430 case GST_MAKE_FOURCC ('A', 'V', 'd', 'n'):
13431 _codec ("AVID DNxHD");
13432 caps = gst_caps_from_string ("video/x-dnxhd");
13435 _codec ("On2 VP8");
13436 caps = gst_caps_from_string ("video/x-vp8");
13439 _codec ("Apple ProRes LT");
13441 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "lt",
13445 _codec ("Apple ProRes HQ");
13447 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "hq",
13451 _codec ("Apple ProRes");
13453 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
13457 _codec ("Apple ProRes Proxy");
13459 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
13463 _codec ("Apple ProRes 4444");
13465 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
13469 _codec ("Apple ProRes 4444 XQ");
13471 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
13477 caps = gst_caps_new_simple ("video/x-wmv",
13478 "wmvversion", G_TYPE_INT, 3, "format", G_TYPE_STRING, "WVC1", NULL);
13480 case GST_MAKE_FOURCC ('k', 'p', 'c', 'd'):
13483 char *s, fourstr[5];
13485 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
13486 s = g_strdup_printf ("video/x-gst-fourcc-%s", g_strstrip (fourstr));
13487 caps = gst_caps_new_empty_simple (s);
13493 if (format != GST_VIDEO_FORMAT_UNKNOWN) {
13496 gst_video_info_init (&info);
13497 gst_video_info_set_format (&info, format, stream->width, stream->height);
13499 caps = gst_video_info_to_caps (&info);
13500 *codec_name = gst_pb_utils_get_codec_description (caps);
13502 /* enable clipping for raw video streams */
13503 stream->need_clip = TRUE;
13510 qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
13511 guint32 fourcc, const guint8 * data, int len, gchar ** codec_name)
13514 const GstStructure *s;
13517 GstAudioFormat format = 0;
13520 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
13522 depth = stream->bytes_per_packet * 8;
13525 case GST_MAKE_FOURCC ('N', 'O', 'N', 'E'):
13527 /* 8-bit audio is unsigned */
13529 format = GST_AUDIO_FORMAT_U8;
13530 /* otherwise it's signed and big-endian just like 'twos' */
13532 endian = G_BIG_ENDIAN;
13539 endian = G_LITTLE_ENDIAN;
13542 format = gst_audio_format_build_integer (TRUE, endian, depth, depth);
13544 str = g_strdup_printf ("Raw %d-bit PCM audio", depth);
13548 caps = gst_caps_new_simple ("audio/x-raw",
13549 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
13550 "layout", G_TYPE_STRING, "interleaved", NULL);
13553 case GST_MAKE_FOURCC ('f', 'l', '6', '4'):
13554 _codec ("Raw 64-bit floating-point audio");
13555 caps = gst_caps_new_simple ("audio/x-raw",
13556 "format", G_TYPE_STRING, "F64BE",
13557 "layout", G_TYPE_STRING, "interleaved", NULL);
13559 case GST_MAKE_FOURCC ('f', 'l', '3', '2'):
13560 _codec ("Raw 32-bit floating-point audio");
13561 caps = gst_caps_new_simple ("audio/x-raw",
13562 "format", G_TYPE_STRING, "F32BE",
13563 "layout", G_TYPE_STRING, "interleaved", NULL);
13566 _codec ("Raw 24-bit PCM audio");
13567 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
13569 caps = gst_caps_new_simple ("audio/x-raw",
13570 "format", G_TYPE_STRING, "S24BE",
13571 "layout", G_TYPE_STRING, "interleaved", NULL);
13573 case GST_MAKE_FOURCC ('i', 'n', '3', '2'):
13574 _codec ("Raw 32-bit PCM audio");
13575 caps = gst_caps_new_simple ("audio/x-raw",
13576 "format", G_TYPE_STRING, "S32BE",
13577 "layout", G_TYPE_STRING, "interleaved", NULL);
13580 _codec ("Mu-law audio");
13581 caps = gst_caps_new_empty_simple ("audio/x-mulaw");
13584 _codec ("A-law audio");
13585 caps = gst_caps_new_empty_simple ("audio/x-alaw");
13589 _codec ("Microsoft ADPCM");
13590 /* Microsoft ADPCM-ACM code 2 */
13591 caps = gst_caps_new_simple ("audio/x-adpcm",
13592 "layout", G_TYPE_STRING, "microsoft", NULL);
13596 _codec ("DVI/IMA ADPCM");
13597 caps = gst_caps_new_simple ("audio/x-adpcm",
13598 "layout", G_TYPE_STRING, "dvi", NULL);
13602 _codec ("DVI/Intel IMA ADPCM");
13603 /* FIXME DVI/Intel IMA ADPCM/ACM code 17 */
13604 caps = gst_caps_new_simple ("audio/x-adpcm",
13605 "layout", G_TYPE_STRING, "quicktime", NULL);
13609 /* MPEG layer 3, CBR only (pre QT4.1) */
13611 _codec ("MPEG-1 layer 3");
13612 /* MPEG layer 3, CBR & VBR (QT4.1 and later) */
13613 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 3,
13614 "mpegversion", G_TYPE_INT, 1, NULL);
13617 case GST_MAKE_FOURCC ('e', 'c', '-', '3'):
13618 _codec ("EAC-3 audio");
13619 caps = gst_caps_new_simple ("audio/x-eac3",
13620 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
13621 stream->sampled = TRUE;
13623 case GST_MAKE_FOURCC ('s', 'a', 'c', '3'): // Nero Recode
13625 _codec ("AC-3 audio");
13626 caps = gst_caps_new_simple ("audio/x-ac3",
13627 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
13628 stream->sampled = TRUE;
13630 case GST_MAKE_FOURCC ('d', 't', 's', 'c'):
13631 case GST_MAKE_FOURCC ('D', 'T', 'S', ' '):
13632 _codec ("DTS audio");
13633 caps = gst_caps_new_simple ("audio/x-dts",
13634 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
13635 stream->sampled = TRUE;
13637 case GST_MAKE_FOURCC ('d', 't', 's', 'h'): // DTS-HD
13638 case GST_MAKE_FOURCC ('d', 't', 's', 'l'): // DTS-HD Lossless
13639 _codec ("DTS-HD audio");
13640 caps = gst_caps_new_simple ("audio/x-dts",
13641 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
13642 stream->sampled = TRUE;
13646 caps = gst_caps_new_simple ("audio/x-mace",
13647 "maceversion", G_TYPE_INT, 3, NULL);
13651 caps = gst_caps_new_simple ("audio/x-mace",
13652 "maceversion", G_TYPE_INT, 6, NULL);
13654 case GST_MAKE_FOURCC ('O', 'g', 'g', 'V'):
13656 caps = gst_caps_new_empty_simple ("application/ogg");
13658 case GST_MAKE_FOURCC ('d', 'v', 'c', 'a'):
13659 _codec ("DV audio");
13660 caps = gst_caps_new_empty_simple ("audio/x-dv");
13663 _codec ("MPEG-4 AAC audio");
13664 caps = gst_caps_new_simple ("audio/mpeg",
13665 "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE,
13666 "stream-format", G_TYPE_STRING, "raw", NULL);
13668 case GST_MAKE_FOURCC ('Q', 'D', 'M', 'C'):
13669 _codec ("QDesign Music");
13670 caps = gst_caps_new_empty_simple ("audio/x-qdm");
13673 _codec ("QDesign Music v.2");
13674 /* FIXME: QDesign music version 2 (no constant) */
13675 if (FALSE && data) {
13676 caps = gst_caps_new_simple ("audio/x-qdm2",
13677 "framesize", G_TYPE_INT, QT_UINT32 (data + 52),
13678 "bitrate", G_TYPE_INT, QT_UINT32 (data + 40),
13679 "blocksize", G_TYPE_INT, QT_UINT32 (data + 44), NULL);
13681 caps = gst_caps_new_empty_simple ("audio/x-qdm2");
13685 _codec ("GSM audio");
13686 caps = gst_caps_new_empty_simple ("audio/x-gsm");
13689 _codec ("AMR audio");
13690 caps = gst_caps_new_empty_simple ("audio/AMR");
13693 _codec ("AMR-WB audio");
13694 caps = gst_caps_new_empty_simple ("audio/AMR-WB");
13697 _codec ("Quicktime IMA ADPCM");
13698 caps = gst_caps_new_simple ("audio/x-adpcm",
13699 "layout", G_TYPE_STRING, "quicktime", NULL);
13702 _codec ("Apple lossless audio");
13703 caps = gst_caps_new_empty_simple ("audio/x-alac");
13706 _codec ("Free Lossless Audio Codec");
13707 caps = gst_caps_new_simple ("audio/x-flac",
13708 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
13710 case GST_MAKE_FOURCC ('Q', 'c', 'l', 'p'):
13711 _codec ("QualComm PureVoice");
13712 caps = gst_caps_from_string ("audio/qcelp");
13717 caps = gst_caps_new_empty_simple ("audio/x-wma");
13721 caps = gst_caps_new_empty_simple ("audio/x-opus");
13723 case GST_MAKE_FOURCC ('l', 'p', 'c', 'm'):
13728 GstAudioFormat format;
13731 FLAG_IS_FLOAT = 0x1,
13732 FLAG_IS_BIG_ENDIAN = 0x2,
13733 FLAG_IS_SIGNED = 0x4,
13734 FLAG_IS_PACKED = 0x8,
13735 FLAG_IS_ALIGNED_HIGH = 0x10,
13736 FLAG_IS_NON_INTERLEAVED = 0x20
13738 _codec ("Raw LPCM audio");
13740 if (data && len >= 56) {
13741 depth = QT_UINT32 (data + 40);
13742 flags = QT_UINT32 (data + 44);
13743 width = QT_UINT32 (data + 48) * 8 / stream->n_channels;
13745 if ((flags & FLAG_IS_FLOAT) == 0) {
13750 format = gst_audio_format_build_integer ((flags & FLAG_IS_SIGNED) ?
13751 TRUE : FALSE, (flags & FLAG_IS_BIG_ENDIAN) ?
13752 G_BIG_ENDIAN : G_LITTLE_ENDIAN, width, 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, (flags & FLAG_IS_NON_INTERLEAVED) ?
13756 "non-interleaved" : "interleaved", NULL);
13761 if (flags & FLAG_IS_BIG_ENDIAN)
13762 format = GST_AUDIO_FORMAT_F64BE;
13764 format = GST_AUDIO_FORMAT_F64LE;
13766 if (flags & FLAG_IS_BIG_ENDIAN)
13767 format = GST_AUDIO_FORMAT_F32BE;
13769 format = GST_AUDIO_FORMAT_F32LE;
13771 caps = gst_caps_new_simple ("audio/x-raw",
13772 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
13773 "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
13774 "non-interleaved" : "interleaved", NULL);
13778 case GST_MAKE_FOURCC ('q', 't', 'v', 'r'):
13782 char *s, fourstr[5];
13784 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
13785 s = g_strdup_printf ("audio/x-gst-fourcc-%s", g_strstrip (fourstr));
13786 caps = gst_caps_new_empty_simple (s);
13793 GstCaps *templ_caps =
13794 gst_static_pad_template_get_caps (&gst_qtdemux_audiosrc_template);
13795 GstCaps *intersection = gst_caps_intersect (caps, templ_caps);
13796 gst_caps_unref (caps);
13797 gst_caps_unref (templ_caps);
13798 caps = intersection;
13801 /* enable clipping for raw audio streams */
13802 s = gst_caps_get_structure (caps, 0);
13803 name = gst_structure_get_name (s);
13804 if (g_str_has_prefix (name, "audio/x-raw")) {
13805 stream->need_clip = TRUE;
13806 stream->max_buffer_size = 4096 * stream->bytes_per_frame;
13807 GST_DEBUG ("setting max buffer size to %d", stream->max_buffer_size);
13813 qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
13814 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
13818 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
13822 _codec ("DVD subtitle");
13823 caps = gst_caps_new_empty_simple ("subpicture/x-dvd");
13824 stream->need_process = TRUE;
13827 _codec ("Quicktime timed text");
13830 _codec ("3GPP timed text");
13832 caps = gst_caps_new_simple ("text/x-raw", "format", G_TYPE_STRING,
13834 /* actual text piece needs to be extracted */
13835 stream->need_process = TRUE;
13838 _codec ("XML subtitles");
13839 caps = gst_caps_new_empty_simple ("application/ttml+xml");
13843 char *s, fourstr[5];
13845 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
13846 s = g_strdup_printf ("text/x-gst-fourcc-%s", g_strstrip (fourstr));
13847 caps = gst_caps_new_empty_simple (s);
13856 qtdemux_generic_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
13857 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
13863 _codec ("MPEG 1 video");
13864 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
13865 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13875 gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux,
13876 const gchar * system_id)
13880 if (!qtdemux->protection_system_ids)
13881 qtdemux->protection_system_ids =
13882 g_ptr_array_new_with_free_func ((GDestroyNotify) g_free);
13883 /* Check whether we already have an entry for this system ID. */
13884 for (i = 0; i < qtdemux->protection_system_ids->len; ++i) {
13885 const gchar *id = g_ptr_array_index (qtdemux->protection_system_ids, i);
13886 if (g_ascii_strcasecmp (system_id, id) == 0) {
13890 GST_DEBUG_OBJECT (qtdemux, "Adding cenc protection system ID %s", system_id);
13891 g_ptr_array_add (qtdemux->protection_system_ids, g_ascii_strdown (system_id,