2 * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
3 * Copyright (C) <2003> David A. Schleef <ds@schleef.org>
4 * Copyright (C) <2006> Wim Taymans <wim@fluendo.com>
5 * Copyright (C) <2007> Julien Moutte <julien@fluendo.com>
6 * Copyright (C) <2009> Tim-Philipp Müller <tim centricular net>
7 * Copyright (C) <2009> STEricsson <benjamin.gaignard@stericsson.com>
8 * Copyright (C) <2013> Sreerenj Balachandran <sreerenj.balachandran@intel.com>
9 * Copyright (C) <2013> Intel Corporation
10 * Copyright (C) <2014> Centricular Ltd
11 * Copyright (C) <2015> YouView TV Ltd.
13 * This library is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU Library General Public
15 * License as published by the Free Software Foundation; either
16 * version 2 of the License, or (at your option) any later version.
18 * This library is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * Library General Public License for more details.
23 * You should have received a copy of the GNU Library General Public
24 * License along with this library; if not, write to the
25 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
26 * Boston, MA 02110-1301, USA.
30 * SECTION:element-qtdemux
32 * Demuxes a .mov file into raw or compressed audio and/or video streams.
34 * This element supports both push and pull-based scheduling, depending on the
35 * capabilities of the upstream elements.
38 * <title>Example launch line</title>
40 * gst-launch-1.0 filesrc location=test.mov ! qtdemux name=demux demux.audio_0 ! queue ! decodebin ! audioconvert ! audioresample ! autoaudiosink demux.video_0 ! queue ! decodebin ! videoconvert ! videoscale ! autovideosink
41 * ]| Play (parse and decode) a .mov file and try to output it to
42 * an automatically detected soundcard and videosink. If the MOV file contains
43 * compressed audio or video data, this will only work if you have the
44 * right decoder elements/plugins installed.
52 #include "gst/gst-i18n-plugin.h"
54 #include <glib/gprintf.h>
55 #include <gst/tag/tag.h>
56 #include <gst/audio/audio.h>
57 #include <gst/video/video.h>
59 #include "qtatomparser.h"
60 #include "qtdemux_types.h"
61 #include "qtdemux_dump.h"
63 #include "descriptors.h"
64 #include "qtdemux_lang.h"
66 #include "qtpalette.h"
68 #include "gst/riff/riff-media.h"
69 #include "gst/riff/riff-read.h"
71 #include <gst/pbutils/pbutils.h>
78 #include <gst/math-compat.h>
84 /* max. size considered 'sane' for non-mdat atoms */
85 #define QTDEMUX_MAX_ATOM_SIZE (25*1024*1024)
87 /* if the sample index is larger than this, something is likely wrong */
88 #define QTDEMUX_MAX_SAMPLE_INDEX_SIZE (50*1024*1024)
90 /* For converting qt creation times to unix epoch times */
91 #define QTDEMUX_SECONDS_PER_DAY (60 * 60 * 24)
92 #define QTDEMUX_LEAP_YEARS_FROM_1904_TO_1970 17
93 #define QTDEMUX_SECONDS_FROM_1904_TO_1970 (((1970 - 1904) * (guint64) 365 + \
94 QTDEMUX_LEAP_YEARS_FROM_1904_TO_1970) * QTDEMUX_SECONDS_PER_DAY)
96 #define STREAM_IS_EOS(s) (s->time_position == GST_CLOCK_TIME_NONE)
98 GST_DEBUG_CATEGORY (qtdemux_debug);
100 /*typedef struct _QtNode QtNode; */
101 typedef struct _QtDemuxSegment QtDemuxSegment;
102 typedef struct _QtDemuxSample QtDemuxSample;
104 typedef struct _QtDemuxCencSampleSetInfo QtDemuxCencSampleSetInfo;
113 struct _QtDemuxSample
116 gint32 pts_offset; /* Add this value to timestamp to get the pts */
118 guint64 timestamp; /* DTS In mov time */
119 guint32 duration; /* In mov time */
120 gboolean keyframe; /* TRUE when this packet is a keyframe */
123 /* Macros for converting to/from timescale */
124 #define QTSTREAMTIME_TO_GSTTIME(stream, value) (gst_util_uint64_scale((value), GST_SECOND, (stream)->timescale))
125 #define GSTTIME_TO_QTSTREAMTIME(stream, value) (gst_util_uint64_scale((value), (stream)->timescale, GST_SECOND))
127 #define QTTIME_TO_GSTTIME(qtdemux, value) (gst_util_uint64_scale((value), GST_SECOND, (qtdemux)->timescale))
128 #define GSTTIME_TO_QTTIME(qtdemux, value) (gst_util_uint64_scale((value), (qtdemux)->timescale, GST_SECOND))
130 /* timestamp is the DTS */
131 #define QTSAMPLE_DTS(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp))
132 /* timestamp + offset is the PTS */
133 #define QTSAMPLE_PTS(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp + (stream)->cslg_shift + (sample)->pts_offset))
134 /* timestamp + duration - dts is the duration */
135 #define QTSAMPLE_DUR_DTS(stream, sample, dts) (QTSTREAMTIME_TO_GSTTIME ((stream), (sample)->timestamp + (sample)->duration) - (dts))
137 #define QTSAMPLE_KEYFRAME(stream,sample) ((stream)->all_keyframe || (sample)->keyframe)
140 * Quicktime has tracks and segments. A track is a continuous piece of
141 * multimedia content. The track is not always played from start to finish but
142 * instead, pieces of the track are 'cut out' and played in sequence. This is
143 * what the segments do.
145 * Inside the track we have keyframes (K) and delta frames. The track has its
146 * own timing, which starts from 0 and extends to end. The position in the track
147 * is called the media_time.
149 * The segments now describe the pieces that should be played from this track
150 * and are basically tuples of media_time/duration/rate entries. We can have
151 * multiple segments and they are all played after one another. An example:
153 * segment 1: media_time: 1 second, duration: 1 second, rate 1
154 * segment 2: media_time: 3 second, duration: 2 second, rate 2
156 * To correctly play back this track, one must play: 1 second of media starting
157 * from media_time 1 followed by 2 seconds of media starting from media_time 3
160 * Each of the segments will be played at a specific time, the first segment at
161 * time 0, the second one after the duration of the first one, etc.. Note that
162 * the time in resulting playback is not identical to the media_time of the
165 * Visually, assuming the track has 4 second of media_time:
168 * .-----------------------------------------------------------.
169 * track: | K.....K.........K........K.......K.......K...........K... |
170 * '-----------------------------------------------------------'
172 * .------------^ ^ .----------^ ^
173 * / .-------------' / .------------------'
175 * .--------------. .--------------.
176 * | segment 1 | | segment 2 |
177 * '--------------' '--------------'
179 * The challenge here is to cut out the right pieces of the track for each of
180 * the playback segments. This fortunately can easily be done with the SEGMENT
181 * events of GStreamer.
183 * For playback of segment 1, we need to provide the decoder with the keyframe
184 * (a), in the above figure, but we must instruct it only to output the decoded
185 * data between second 1 and 2. We do this with a SEGMENT event for 1 to 2, time
186 * position set to the time of the segment: 0.
188 * We then proceed to push data from keyframe (a) to frame (b). The decoder
189 * decodes but clips all before media_time 1.
191 * After finishing a segment, we push out a new SEGMENT event with the clipping
192 * boundaries of the new data.
194 * This is a good usecase for the GStreamer accumulated SEGMENT events.
197 struct _QtDemuxSegment
199 /* global time and duration, all gst time */
201 GstClockTime stop_time;
202 GstClockTime duration;
203 /* media time of trak, all gst time */
204 GstClockTime media_start;
205 GstClockTime media_stop;
207 /* Media start time in trak timescale units */
208 guint32 trak_media_start;
211 #define QTSEGMENT_IS_EMPTY(s) ((s)->media_start == GST_CLOCK_TIME_NONE)
213 /* Used with fragmented MP4 files (mfra atom) */
218 } QtDemuxRandomAccessEntry;
220 struct _QtDemuxStream
231 gboolean new_stream; /* signals that a stream_start is required */
232 gboolean on_keyframe; /* if this stream last pushed buffer was a
233 * keyframe. This is important to identify
234 * where to stop pushing buffers after a
235 * segment stop time */
237 /* if the stream has a redirect URI in its headers, we store it here */
244 guint64 duration; /* in timescale */
248 gchar lang_id[4]; /* ISO 639-2T language code */
252 QtDemuxSample *samples;
253 gboolean all_keyframe; /* TRUE when all samples are keyframes (no stss) */
254 guint32 first_duration; /* duration in timescale of first sample, used for figuring out
255 the framerate, in timescale units */
256 guint32 n_samples_moof; /* sample count in a moof */
257 guint64 duration_moof; /* duration in timescale of a moof, used for figure out
258 * the framerate of fragmented format stream */
259 guint32 offset_in_sample;
260 guint32 max_buffer_size;
262 /* if we use chunks or samples */
274 /* Numerator/denominator framerate */
277 guint16 bits_per_sample;
278 guint16 color_table_id;
279 GstMemory *rgb8_palette;
284 guint samples_per_packet;
285 guint samples_per_frame;
286 guint bytes_per_packet;
287 guint bytes_per_sample;
288 guint bytes_per_frame;
292 gboolean use_allocator;
293 GstAllocator *allocator;
294 GstAllocationParams params;
296 /* when a discontinuity is pending */
299 /* list of buffers to push first */
302 /* if we need to clip this buffer. This is only needed for uncompressed
306 /* buffer needs some custom processing, e.g. subtitles */
307 gboolean need_process;
309 /* current position */
310 guint32 segment_index;
311 guint32 sample_index;
312 GstClockTime time_position; /* in gst time */
313 guint64 accumulated_base;
315 /* the Gst segment we are processing out, used for clipping */
317 guint32 segment_seqnum; /* segment event seqnum obtained from seek */
319 /* quicktime segments */
321 QtDemuxSegment *segments;
322 gboolean dummy_segment;
327 GstTagList *pending_tags;
328 gboolean send_global_tags;
330 GstEvent *pending_event;
340 gboolean chunks_are_samples; /* TRUE means treat chunks as samples */
344 GstByteReader co_chunk;
346 guint32 current_chunk;
348 guint32 samples_per_chunk;
349 guint32 stco_sample_index;
351 guint32 sample_size; /* 0 means variable sizes are stored in stsz */
354 guint32 n_samples_per_chunk;
355 guint32 stsc_chunk_index;
356 guint32 stsc_sample_index;
357 guint64 chunk_offset;
360 guint32 stts_samples;
361 guint32 n_sample_times;
362 guint32 stts_sample_index;
364 guint32 stts_duration;
366 gboolean stss_present;
367 guint32 n_sample_syncs;
370 gboolean stps_present;
371 guint32 n_sample_partial_syncs;
373 QtDemuxRandomAccessEntry *ra_entries;
376 const QtDemuxRandomAccessEntry *pending_seek;
379 gboolean ctts_present;
380 guint32 n_composition_times;
382 guint32 ctts_sample_index;
390 gboolean parsed_trex;
391 guint32 def_sample_duration;
392 guint32 def_sample_size;
393 guint32 def_sample_flags;
397 /* stereoscopic video streams */
398 GstVideoMultiviewMode multiview_mode;
399 GstVideoMultiviewFlags multiview_flags;
401 /* protected streams */
403 guint32 protection_scheme_type;
404 guint32 protection_scheme_version;
405 gpointer protection_scheme_info; /* specific to the protection scheme */
406 GQueue protection_scheme_event_queue;
409 /* Contains properties and cryptographic info for a set of samples from a
410 * track protected using Common Encryption (cenc) */
411 struct _QtDemuxCencSampleSetInfo
413 GstStructure *default_properties;
415 /* @crypto_info holds one GstStructure per sample */
416 GPtrArray *crypto_info;
421 QTDEMUX_STATE_INITIAL, /* Initial state (haven't got the header yet) */
422 QTDEMUX_STATE_HEADER, /* Parsing the header */
423 QTDEMUX_STATE_MOVIE, /* Parsing/Playing the media data */
424 QTDEMUX_STATE_BUFFER_MDAT /* Buffering the mdat atom */
427 static GNode *qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc);
428 static GNode *qtdemux_tree_get_child_by_type_full (GNode * node,
429 guint32 fourcc, GstByteReader * parser);
430 static GNode *qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc);
431 static GNode *qtdemux_tree_get_sibling_by_type_full (GNode * node,
432 guint32 fourcc, GstByteReader * parser);
434 static GstFlowReturn qtdemux_add_fragmented_samples (GstQTDemux * qtdemux);
436 static GstStaticPadTemplate gst_qtdemux_sink_template =
437 GST_STATIC_PAD_TEMPLATE ("sink",
440 GST_STATIC_CAPS ("video/quicktime; video/mj2; audio/x-m4a; "
444 static GstStaticPadTemplate gst_qtdemux_videosrc_template =
445 GST_STATIC_PAD_TEMPLATE ("video_%u",
448 GST_STATIC_CAPS_ANY);
450 static GstStaticPadTemplate gst_qtdemux_audiosrc_template =
451 GST_STATIC_PAD_TEMPLATE ("audio_%u",
454 GST_STATIC_CAPS_ANY);
456 static GstStaticPadTemplate gst_qtdemux_subsrc_template =
457 GST_STATIC_PAD_TEMPLATE ("subtitle_%u",
460 GST_STATIC_CAPS_ANY);
462 #define gst_qtdemux_parent_class parent_class
463 G_DEFINE_TYPE (GstQTDemux, gst_qtdemux, GST_TYPE_ELEMENT);
465 static void gst_qtdemux_dispose (GObject * object);
468 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
469 GstClockTime media_time);
471 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
472 QtDemuxStream * str, gint64 media_offset);
475 static void gst_qtdemux_set_index (GstElement * element, GstIndex * index);
476 static GstIndex *gst_qtdemux_get_index (GstElement * element);
478 static GstStateChangeReturn gst_qtdemux_change_state (GstElement * element,
479 GstStateChange transition);
480 static gboolean qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent);
481 static gboolean qtdemux_sink_activate_mode (GstPad * sinkpad,
482 GstObject * parent, GstPadMode mode, gboolean active);
484 static void gst_qtdemux_loop (GstPad * pad);
485 static GstFlowReturn gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent,
487 static gboolean gst_qtdemux_handle_sink_event (GstPad * pad, GstObject * parent,
489 static gboolean gst_qtdemux_setcaps (GstQTDemux * qtdemux, GstCaps * caps);
490 static gboolean gst_qtdemux_configure_stream (GstQTDemux * qtdemux,
491 QtDemuxStream * stream);
492 static GstFlowReturn gst_qtdemux_process_adapter (GstQTDemux * demux,
495 static gboolean qtdemux_parse_moov (GstQTDemux * qtdemux,
496 const guint8 * buffer, guint length);
497 static gboolean qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node,
498 const guint8 * buffer, guint length);
499 static gboolean qtdemux_parse_tree (GstQTDemux * qtdemux);
500 static void qtdemux_parse_udta (GstQTDemux * qtdemux, GstTagList * taglist,
503 static void gst_qtdemux_handle_esds (GstQTDemux * qtdemux,
504 QtDemuxStream * stream, GNode * esds, GstTagList * list);
505 static GstCaps *qtdemux_video_caps (GstQTDemux * qtdemux,
506 QtDemuxStream * stream, guint32 fourcc, const guint8 * stsd_data,
507 gchar ** codec_name);
508 static GstCaps *qtdemux_audio_caps (GstQTDemux * qtdemux,
509 QtDemuxStream * stream, guint32 fourcc, const guint8 * data, int len,
510 gchar ** codec_name);
511 static GstCaps *qtdemux_sub_caps (GstQTDemux * qtdemux,
512 QtDemuxStream * stream, guint32 fourcc, const guint8 * data,
513 gchar ** codec_name);
514 static GstCaps *qtdemux_generic_caps (GstQTDemux * qtdemux,
515 QtDemuxStream * stream, guint32 fourcc, const guint8 * stsd_data,
516 gchar ** codec_name);
518 static gboolean qtdemux_parse_samples (GstQTDemux * qtdemux,
519 QtDemuxStream * stream, guint32 n);
520 static GstFlowReturn qtdemux_expose_streams (GstQTDemux * qtdemux);
521 static void gst_qtdemux_stream_free (GstQTDemux * qtdemux,
522 QtDemuxStream * stream);
523 static void gst_qtdemux_stream_clear (GstQTDemux * qtdemux,
524 QtDemuxStream * stream);
525 static void gst_qtdemux_remove_stream (GstQTDemux * qtdemux, int index);
526 static GstFlowReturn qtdemux_prepare_streams (GstQTDemux * qtdemux);
527 static void qtdemux_do_allocation (GstQTDemux * qtdemux,
528 QtDemuxStream * stream);
530 static gboolean qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux);
531 static void check_update_duration (GstQTDemux * qtdemux, GstClockTime duration);
533 static void gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux,
537 gst_qtdemux_class_init (GstQTDemuxClass * klass)
539 GObjectClass *gobject_class;
540 GstElementClass *gstelement_class;
542 gobject_class = (GObjectClass *) klass;
543 gstelement_class = (GstElementClass *) klass;
545 parent_class = g_type_class_peek_parent (klass);
547 gobject_class->dispose = gst_qtdemux_dispose;
549 gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_qtdemux_change_state);
551 gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_qtdemux_set_index);
552 gstelement_class->get_index = GST_DEBUG_FUNCPTR (gst_qtdemux_get_index);
555 gst_tag_register_musicbrainz_tags ();
557 gst_element_class_add_pad_template (gstelement_class,
558 gst_static_pad_template_get (&gst_qtdemux_sink_template));
559 gst_element_class_add_pad_template (gstelement_class,
560 gst_static_pad_template_get (&gst_qtdemux_videosrc_template));
561 gst_element_class_add_pad_template (gstelement_class,
562 gst_static_pad_template_get (&gst_qtdemux_audiosrc_template));
563 gst_element_class_add_pad_template (gstelement_class,
564 gst_static_pad_template_get (&gst_qtdemux_subsrc_template));
565 gst_element_class_set_static_metadata (gstelement_class, "QuickTime demuxer",
567 "Demultiplex a QuickTime file into audio and video streams",
568 "David Schleef <ds@schleef.org>, Wim Taymans <wim@fluendo.com>");
570 GST_DEBUG_CATEGORY_INIT (qtdemux_debug, "qtdemux", 0, "qtdemux plugin");
575 gst_qtdemux_init (GstQTDemux * qtdemux)
578 gst_pad_new_from_static_template (&gst_qtdemux_sink_template, "sink");
579 gst_pad_set_activate_function (qtdemux->sinkpad, qtdemux_sink_activate);
580 gst_pad_set_activatemode_function (qtdemux->sinkpad,
581 qtdemux_sink_activate_mode);
582 gst_pad_set_chain_function (qtdemux->sinkpad, gst_qtdemux_chain);
583 gst_pad_set_event_function (qtdemux->sinkpad, gst_qtdemux_handle_sink_event);
584 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), qtdemux->sinkpad);
586 qtdemux->state = QTDEMUX_STATE_INITIAL;
587 qtdemux->pullbased = FALSE;
588 qtdemux->posted_redirect = FALSE;
589 qtdemux->pending_configure = FALSE;
590 qtdemux->neededbytes = 16;
592 qtdemux->adapter = gst_adapter_new ();
594 qtdemux->first_mdat = -1;
595 qtdemux->got_moov = FALSE;
596 qtdemux->mdatoffset = -1;
597 qtdemux->mdatbuffer = NULL;
598 qtdemux->restoredata_buffer = NULL;
599 qtdemux->restoredata_offset = -1;
600 qtdemux->fragment_start = -1;
601 qtdemux->fragment_start_offset = -1;
602 qtdemux->media_caps = NULL;
603 qtdemux->exposed = FALSE;
604 qtdemux->mss_mode = FALSE;
605 qtdemux->pending_newsegment = NULL;
606 qtdemux->upstream_format_is_time = FALSE;
607 qtdemux->have_group_id = FALSE;
608 qtdemux->group_id = G_MAXUINT;
609 qtdemux->cenc_aux_info_offset = 0;
610 qtdemux->cenc_aux_info_sizes = NULL;
611 qtdemux->cenc_aux_sample_count = 0;
612 qtdemux->protection_system_ids = NULL;
613 g_queue_init (&qtdemux->protection_event_queue);
614 gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
615 qtdemux->flowcombiner = gst_flow_combiner_new ();
617 GST_OBJECT_FLAG_SET (qtdemux, GST_ELEMENT_FLAG_INDEXABLE);
621 gst_qtdemux_dispose (GObject * object)
623 GstQTDemux *qtdemux = GST_QTDEMUX (object);
625 if (qtdemux->adapter) {
626 g_object_unref (G_OBJECT (qtdemux->adapter));
627 qtdemux->adapter = NULL;
629 gst_flow_combiner_free (qtdemux->flowcombiner);
630 g_queue_foreach (&qtdemux->protection_event_queue, (GFunc) gst_event_unref,
632 g_queue_clear (&qtdemux->protection_event_queue);
634 g_free (qtdemux->cenc_aux_info_sizes);
635 qtdemux->cenc_aux_info_sizes = NULL;
637 G_OBJECT_CLASS (parent_class)->dispose (object);
641 gst_qtdemux_post_no_playable_stream_error (GstQTDemux * qtdemux)
643 if (qtdemux->posted_redirect) {
644 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
645 (_("This file contains no playable streams.")),
646 ("no known streams found, a redirect message has been posted"));
648 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
649 (_("This file contains no playable streams.")),
650 ("no known streams found"));
655 _gst_buffer_new_wrapped (gpointer mem, gsize size, GFreeFunc free_func)
657 return gst_buffer_new_wrapped_full (free_func ? 0 : GST_MEMORY_FLAG_READONLY,
658 mem, size, 0, size, mem, free_func);
662 gst_qtdemux_pull_atom (GstQTDemux * qtdemux, guint64 offset, guint64 size,
669 if (G_UNLIKELY (size == 0)) {
671 GstBuffer *tmp = NULL;
673 ret = gst_qtdemux_pull_atom (qtdemux, offset, sizeof (guint32), &tmp);
674 if (ret != GST_FLOW_OK)
677 gst_buffer_map (tmp, &map, GST_MAP_READ);
678 size = QT_UINT32 (map.data);
679 GST_DEBUG_OBJECT (qtdemux, "size 0x%08" G_GINT64_MODIFIER "x", size);
681 gst_buffer_unmap (tmp, &map);
682 gst_buffer_unref (tmp);
685 /* Sanity check: catch bogus sizes (fuzzed/broken files) */
686 if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
687 if (qtdemux->state != QTDEMUX_STATE_MOVIE && qtdemux->got_moov) {
688 /* we're pulling header but already got most interesting bits,
689 * so never mind the rest (e.g. tags) (that much) */
690 GST_WARNING_OBJECT (qtdemux, "atom has bogus size %" G_GUINT64_FORMAT,
694 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
695 (_("This file is invalid and cannot be played.")),
696 ("atom has bogus size %" G_GUINT64_FORMAT, size));
697 return GST_FLOW_ERROR;
701 flow = gst_pad_pull_range (qtdemux->sinkpad, offset, size, buf);
703 if (G_UNLIKELY (flow != GST_FLOW_OK))
706 bsize = gst_buffer_get_size (*buf);
707 /* Catch short reads - we don't want any partial atoms */
708 if (G_UNLIKELY (bsize < size)) {
709 GST_WARNING_OBJECT (qtdemux,
710 "short read: %" G_GSIZE_FORMAT " < %" G_GUINT64_FORMAT, bsize, size);
711 gst_buffer_unref (*buf);
721 gst_qtdemux_src_convert (GstPad * pad, GstFormat src_format, gint64 src_value,
722 GstFormat dest_format, gint64 * dest_value)
725 QtDemuxStream *stream = gst_pad_get_element_private (pad);
726 GstQTDemux *qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
729 if (stream->subtype != FOURCC_vide) {
734 switch (src_format) {
735 case GST_FORMAT_TIME:
736 switch (dest_format) {
737 case GST_FORMAT_BYTES:{
738 index = gst_qtdemux_find_index_linear (qtdemux, stream, src_value);
742 *dest_value = stream->samples[index].offset;
744 GST_DEBUG_OBJECT (qtdemux, "Format Conversion Time->Offset :%"
745 GST_TIME_FORMAT "->%" G_GUINT64_FORMAT,
746 GST_TIME_ARGS (src_value), *dest_value);
754 case GST_FORMAT_BYTES:
755 switch (dest_format) {
756 case GST_FORMAT_TIME:{
758 gst_qtdemux_find_index_for_given_media_offset_linear (qtdemux,
765 QTSTREAMTIME_TO_GSTTIME (stream,
766 stream->samples[index].timestamp);
767 GST_DEBUG_OBJECT (qtdemux,
768 "Format Conversion Offset->Time :%" G_GUINT64_FORMAT "->%"
769 GST_TIME_FORMAT, src_value, GST_TIME_ARGS (*dest_value));
782 gst_object_unref (qtdemux);
789 gst_qtdemux_get_duration (GstQTDemux * qtdemux, GstClockTime * duration)
793 *duration = GST_CLOCK_TIME_NONE;
795 if (qtdemux->duration != 0) {
796 if (qtdemux->duration != G_MAXINT64 && qtdemux->timescale != 0) {
797 *duration = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
804 gst_qtdemux_handle_src_query (GstPad * pad, GstObject * parent,
807 gboolean res = FALSE;
808 GstQTDemux *qtdemux = GST_QTDEMUX (parent);
810 GST_LOG_OBJECT (pad, "%s query", GST_QUERY_TYPE_NAME (query));
812 switch (GST_QUERY_TYPE (query)) {
813 case GST_QUERY_POSITION:{
816 gst_query_parse_position (query, &fmt, NULL);
817 if (fmt == GST_FORMAT_TIME
818 && GST_CLOCK_TIME_IS_VALID (qtdemux->segment.position)) {
819 gst_query_set_position (query, GST_FORMAT_TIME,
820 qtdemux->segment.position);
825 case GST_QUERY_DURATION:{
828 gst_query_parse_duration (query, &fmt, NULL);
829 if (fmt == GST_FORMAT_TIME) {
830 /* First try to query upstream */
831 res = gst_pad_query_default (pad, parent, query);
834 if (gst_qtdemux_get_duration (qtdemux, &duration) && duration > 0) {
835 gst_query_set_duration (query, GST_FORMAT_TIME, duration);
842 case GST_QUERY_CONVERT:{
843 GstFormat src_fmt, dest_fmt;
844 gint64 src_value, dest_value = 0;
846 gst_query_parse_convert (query, &src_fmt, &src_value, &dest_fmt, NULL);
848 res = gst_qtdemux_src_convert (pad,
849 src_fmt, src_value, dest_fmt, &dest_value);
851 gst_query_set_convert (query, src_fmt, src_value, dest_fmt, dest_value);
856 case GST_QUERY_FORMATS:
857 gst_query_set_formats (query, 2, GST_FORMAT_TIME, GST_FORMAT_BYTES);
860 case GST_QUERY_SEEKING:{
864 /* try upstream first */
865 res = gst_pad_query_default (pad, parent, query);
868 gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
869 if (fmt == GST_FORMAT_TIME) {
870 GstClockTime duration = GST_CLOCK_TIME_NONE;
872 gst_qtdemux_get_duration (qtdemux, &duration);
874 if (!qtdemux->pullbased) {
877 /* we might be able with help from upstream */
879 q = gst_query_new_seeking (GST_FORMAT_BYTES);
880 if (gst_pad_peer_query (qtdemux->sinkpad, q)) {
881 gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL);
882 GST_LOG_OBJECT (qtdemux, "upstream BYTE seekable %d", seekable);
886 gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0, duration);
892 case GST_QUERY_SEGMENT:
897 format = qtdemux->segment.format;
900 gst_segment_to_stream_time (&qtdemux->segment, format,
901 qtdemux->segment.start);
902 if ((stop = qtdemux->segment.stop) == -1)
903 stop = qtdemux->segment.duration;
905 stop = gst_segment_to_stream_time (&qtdemux->segment, format, stop);
907 gst_query_set_segment (query, qtdemux->segment.rate, format, start, stop);
912 res = gst_pad_query_default (pad, parent, query);
920 gst_qtdemux_push_tags (GstQTDemux * qtdemux, QtDemuxStream * stream)
922 if (G_LIKELY (stream->pad)) {
923 GST_DEBUG_OBJECT (qtdemux, "Checking pad %s:%s for tags",
924 GST_DEBUG_PAD_NAME (stream->pad));
926 if (G_UNLIKELY (stream->pending_tags)) {
927 GST_DEBUG_OBJECT (qtdemux, "Sending tags %" GST_PTR_FORMAT,
928 stream->pending_tags);
929 gst_pad_push_event (stream->pad,
930 gst_event_new_tag (stream->pending_tags));
931 stream->pending_tags = NULL;
934 if (G_UNLIKELY (stream->send_global_tags && qtdemux->tag_list)) {
935 GST_DEBUG_OBJECT (qtdemux, "Sending global tags %" GST_PTR_FORMAT,
937 gst_pad_push_event (stream->pad,
938 gst_event_new_tag (gst_tag_list_ref (qtdemux->tag_list)));
939 stream->send_global_tags = FALSE;
944 /* push event on all source pads; takes ownership of the event */
946 gst_qtdemux_push_event (GstQTDemux * qtdemux, GstEvent * event)
949 gboolean has_valid_stream = FALSE;
950 GstEventType etype = GST_EVENT_TYPE (event);
952 GST_DEBUG_OBJECT (qtdemux, "pushing %s event on all source pads",
953 GST_EVENT_TYPE_NAME (event));
955 for (n = 0; n < qtdemux->n_streams; n++) {
957 QtDemuxStream *stream = qtdemux->streams[n];
958 GST_DEBUG_OBJECT (qtdemux, "pushing on pad %i", n);
960 if ((pad = stream->pad)) {
961 has_valid_stream = TRUE;
963 if (etype == GST_EVENT_EOS) {
964 /* let's not send twice */
965 if (stream->sent_eos)
967 stream->sent_eos = TRUE;
970 gst_pad_push_event (pad, gst_event_ref (event));
974 gst_event_unref (event);
976 /* if it is EOS and there are no pads, post an error */
977 if (!has_valid_stream && etype == GST_EVENT_EOS) {
978 gst_qtdemux_post_no_playable_stream_error (qtdemux);
982 /* push a pending newsegment event, if any from the streaming thread */
984 gst_qtdemux_push_pending_newsegment (GstQTDemux * qtdemux)
986 if (qtdemux->pending_newsegment) {
987 gst_qtdemux_push_event (qtdemux, qtdemux->pending_newsegment);
988 qtdemux->pending_newsegment = NULL;
998 find_func (QtDemuxSample * s1, gint64 * media_time, gpointer user_data)
1000 if ((gint64) s1->timestamp + s1->pts_offset > *media_time)
1002 if ((gint64) s1->timestamp + s1->pts_offset == *media_time)
1008 /* find the index of the sample that includes the data for @media_time using a
1009 * binary search. Only to be called in optimized cases of linear search below.
1011 * Returns the index of the sample.
1014 gst_qtdemux_find_index (GstQTDemux * qtdemux, QtDemuxStream * str,
1017 QtDemuxSample *result;
1020 /* convert media_time to mov format */
1022 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
1024 result = gst_util_array_binary_search (str->samples, str->stbl_index + 1,
1025 sizeof (QtDemuxSample), (GCompareDataFunc) find_func,
1026 GST_SEARCH_MODE_BEFORE, &media_time, NULL);
1028 if (G_LIKELY (result))
1029 index = result - str->samples;
1038 /* find the index of the sample that includes the data for @media_offset using a
1041 * Returns the index of the sample.
1044 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
1045 QtDemuxStream * str, gint64 media_offset)
1047 QtDemuxSample *result = str->samples;
1050 if (result == NULL || str->n_samples == 0)
1053 if (media_offset == result->offset)
1057 while (index < str->n_samples - 1) {
1058 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
1061 if (media_offset < result->offset)
1072 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
1077 /* find the index of the sample that includes the data for @media_time using a
1078 * linear search, and keeping in mind that not all samples may have been parsed
1079 * yet. If possible, it will delegate to binary search.
1081 * Returns the index of the sample.
1084 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
1085 GstClockTime media_time)
1089 QtDemuxSample *sample;
1091 /* convert media_time to mov format */
1093 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
1095 sample = str->samples;
1096 if (mov_time == sample->timestamp + sample->pts_offset)
1099 /* use faster search if requested time in already parsed range */
1100 sample = str->samples + str->stbl_index;
1101 if (str->stbl_index >= 0 &&
1102 mov_time <= (sample->timestamp + sample->pts_offset))
1103 return gst_qtdemux_find_index (qtdemux, str, media_time);
1105 while (index < str->n_samples - 1) {
1106 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
1109 sample = str->samples + index + 1;
1110 if (mov_time < (sample->timestamp + sample->pts_offset))
1120 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
1125 /* find the index of the keyframe needed to decode the sample at @index
1128 * Returns the index of the keyframe.
1131 gst_qtdemux_find_keyframe (GstQTDemux * qtdemux, QtDemuxStream * str,
1134 guint32 new_index = index;
1136 if (index >= str->n_samples) {
1137 new_index = str->n_samples;
1141 /* all keyframes, return index */
1142 if (str->all_keyframe) {
1147 /* else go back until we have a keyframe */
1149 if (str->samples[new_index].keyframe)
1159 GST_DEBUG_OBJECT (qtdemux, "searching for keyframe index before index %u "
1160 "gave %u", index, new_index);
1165 /* find the segment for @time_position for @stream
1167 * Returns the index of the segment containing @time_position.
1168 * Returns the last segment and sets the @eos variable to TRUE
1169 * if the time is beyond the end. @eos may be NULL
1172 gst_qtdemux_find_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
1173 GstClockTime time_position)
1178 GST_LOG_OBJECT (stream->pad, "finding segment for %" GST_TIME_FORMAT,
1179 GST_TIME_ARGS (time_position));
1182 for (i = 0; i < stream->n_segments; i++) {
1183 QtDemuxSegment *segment = &stream->segments[i];
1185 GST_LOG_OBJECT (stream->pad,
1186 "looking at segment %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT,
1187 GST_TIME_ARGS (segment->time), GST_TIME_ARGS (segment->stop_time));
1189 /* For the last segment we include stop_time in the last segment */
1190 if (i < stream->n_segments - 1) {
1191 if (segment->time <= time_position && time_position < segment->stop_time) {
1192 GST_LOG_OBJECT (stream->pad, "segment %d matches", i);
1197 /* Last segment always matches */
1205 /* move the stream @str to the sample position @index.
1207 * Updates @str->sample_index and marks discontinuity if needed.
1210 gst_qtdemux_move_stream (GstQTDemux * qtdemux, QtDemuxStream * str,
1213 /* no change needed */
1214 if (index == str->sample_index)
1217 GST_DEBUG_OBJECT (qtdemux, "moving to sample %u of %u", index,
1220 /* position changed, we have a discont */
1221 str->sample_index = index;
1222 str->offset_in_sample = 0;
1223 /* Each time we move in the stream we store the position where we are
1225 str->from_sample = index;
1226 str->discont = TRUE;
1230 gst_qtdemux_adjust_seek (GstQTDemux * qtdemux, gint64 desired_time,
1231 gboolean use_sparse, gint64 * key_time, gint64 * key_offset)
1234 gint64 min_byte_offset = -1;
1237 min_offset = desired_time;
1239 /* for each stream, find the index of the sample in the segment
1240 * and move back to the previous keyframe. */
1241 for (n = 0; n < qtdemux->n_streams; n++) {
1243 guint32 index, kindex;
1245 GstClockTime media_start;
1246 GstClockTime media_time;
1247 GstClockTime seg_time;
1248 QtDemuxSegment *seg;
1249 gboolean empty_segment = FALSE;
1251 str = qtdemux->streams[n];
1253 if (str->sparse && !use_sparse)
1256 seg_idx = gst_qtdemux_find_segment (qtdemux, str, desired_time);
1257 GST_DEBUG_OBJECT (qtdemux, "align segment %d", seg_idx);
1259 /* get segment and time in the segment */
1260 seg = &str->segments[seg_idx];
1261 seg_time = desired_time - seg->time;
1263 while (QTSEGMENT_IS_EMPTY (seg)) {
1265 empty_segment = TRUE;
1266 GST_DEBUG_OBJECT (str->pad, "Segment %d is empty, moving to next one",
1269 if (seg_idx == str->n_segments)
1271 seg = &str->segments[seg_idx];
1274 if (seg_idx == str->n_segments) {
1275 /* FIXME track shouldn't have the last segment as empty, but if it
1276 * happens we better handle it */
1280 /* get the media time in the segment */
1281 media_start = seg->media_start + seg_time;
1283 /* get the index of the sample with media time */
1284 index = gst_qtdemux_find_index_linear (qtdemux, str, media_start);
1285 GST_DEBUG_OBJECT (qtdemux, "sample for %" GST_TIME_FORMAT " at %u"
1286 " at offset %" G_GUINT64_FORMAT " (empty segment: %d)",
1287 GST_TIME_ARGS (media_start), index, str->samples[index].offset,
1290 if (!empty_segment) {
1291 /* find previous keyframe */
1292 kindex = gst_qtdemux_find_keyframe (qtdemux, str, index);
1294 /* if the keyframe is at a different position, we need to update the
1295 * requested seek time */
1296 if (index != kindex) {
1299 /* get timestamp of keyframe */
1300 media_time = QTSAMPLE_DTS (str, &str->samples[kindex]);
1301 GST_DEBUG_OBJECT (qtdemux,
1302 "keyframe at %u with time %" GST_TIME_FORMAT " at offset %"
1303 G_GUINT64_FORMAT, kindex, GST_TIME_ARGS (media_time),
1304 str->samples[kindex].offset);
1306 /* keyframes in the segment get a chance to change the
1307 * desired_offset. keyframes out of the segment are
1309 if (media_time >= seg->media_start) {
1310 GstClockTime seg_time;
1312 /* this keyframe is inside the segment, convert back to
1314 seg_time = (media_time - seg->media_start) + seg->time;
1315 if (seg_time < min_offset)
1316 min_offset = seg_time;
1321 if (min_byte_offset < 0 || str->samples[index].offset < min_byte_offset)
1322 min_byte_offset = str->samples[index].offset;
1326 *key_time = min_offset;
1328 *key_offset = min_byte_offset;
1332 gst_qtdemux_convert_seek (GstPad * pad, GstFormat * format,
1333 GstSeekType cur_type, gint64 * cur, GstSeekType stop_type, gint64 * stop)
1337 g_return_val_if_fail (format != NULL, FALSE);
1338 g_return_val_if_fail (cur != NULL, FALSE);
1339 g_return_val_if_fail (stop != NULL, FALSE);
1341 if (*format == GST_FORMAT_TIME)
1345 if (cur_type != GST_SEEK_TYPE_NONE)
1346 res = gst_pad_query_convert (pad, *format, *cur, GST_FORMAT_TIME, cur);
1347 if (res && stop_type != GST_SEEK_TYPE_NONE)
1348 res = gst_pad_query_convert (pad, *format, *stop, GST_FORMAT_TIME, stop);
1351 *format = GST_FORMAT_TIME;
1356 /* perform seek in push based mode:
1357 find BYTE position to move to based on time and delegate to upstream
1360 gst_qtdemux_do_push_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1365 GstSeekType cur_type, stop_type;
1366 gint64 cur, stop, key_cur;
1369 gint64 original_stop;
1372 GST_DEBUG_OBJECT (qtdemux, "doing push-based seek");
1374 gst_event_parse_seek (event, &rate, &format, &flags,
1375 &cur_type, &cur, &stop_type, &stop);
1376 seqnum = gst_event_get_seqnum (event);
1378 /* only forward streaming and seeking is possible */
1380 goto unsupported_seek;
1382 /* convert to TIME if needed and possible */
1383 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1387 /* Upstream seek in bytes will have undefined stop, but qtdemux stores
1388 * the original stop position to use when upstream pushes the new segment
1390 original_stop = stop;
1393 /* find reasonable corresponding BYTE position,
1394 * also try to mind about keyframes, since we can not go back a bit for them
1396 gst_qtdemux_adjust_seek (qtdemux, cur, FALSE, &key_cur, &byte_cur);
1401 GST_DEBUG_OBJECT (qtdemux, "Pushing BYTE seek rate %g, "
1402 "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, byte_cur,
1405 GST_OBJECT_LOCK (qtdemux);
1406 qtdemux->seek_offset = byte_cur;
1407 if (!(flags & GST_SEEK_FLAG_KEY_UNIT)) {
1408 qtdemux->push_seek_start = cur;
1410 qtdemux->push_seek_start = key_cur;
1413 if (stop_type == GST_SEEK_TYPE_NONE) {
1414 qtdemux->push_seek_stop = qtdemux->segment.stop;
1416 qtdemux->push_seek_stop = original_stop;
1418 GST_OBJECT_UNLOCK (qtdemux);
1420 /* BYTE seek event */
1421 event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type, byte_cur,
1423 gst_event_set_seqnum (event, seqnum);
1424 res = gst_pad_push_event (qtdemux->sinkpad, event);
1431 GST_DEBUG_OBJECT (qtdemux, "could not determine byte position to seek to, "
1437 GST_DEBUG_OBJECT (qtdemux, "unsupported seek, seek aborted.");
1442 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1447 /* perform the seek.
1449 * We set all segment_indexes in the streams to unknown and
1450 * adjust the time_position to the desired position. this is enough
1451 * to trigger a segment switch in the streaming thread to start
1452 * streaming from the desired position.
1454 * Keyframe seeking is a little more complicated when dealing with
1455 * segments. Ideally we want to move to the previous keyframe in
1456 * the segment but there might not be a keyframe in the segment. In
1457 * fact, none of the segments could contain a keyframe. We take a
1458 * practical approach: seek to the previous keyframe in the segment,
1459 * if there is none, seek to the beginning of the segment.
1461 * Called with STREAM_LOCK
1464 gst_qtdemux_perform_seek (GstQTDemux * qtdemux, GstSegment * segment,
1465 guint32 seqnum, GstSeekFlags flags)
1467 gint64 desired_offset;
1470 desired_offset = segment->position;
1472 GST_DEBUG_OBJECT (qtdemux, "seeking to %" GST_TIME_FORMAT,
1473 GST_TIME_ARGS (desired_offset));
1475 /* may not have enough fragmented info to do this adjustment,
1476 * and we can't scan (and probably should not) at this time with
1477 * possibly flushing upstream */
1478 if ((flags & GST_SEEK_FLAG_KEY_UNIT) && !qtdemux->fragmented) {
1481 gst_qtdemux_adjust_seek (qtdemux, desired_offset, TRUE, &min_offset, NULL);
1482 GST_DEBUG_OBJECT (qtdemux, "keyframe seek, align to %"
1483 GST_TIME_FORMAT, GST_TIME_ARGS (min_offset));
1484 desired_offset = min_offset;
1487 /* and set all streams to the final position */
1488 gst_flow_combiner_reset (qtdemux->flowcombiner);
1489 for (n = 0; n < qtdemux->n_streams; n++) {
1490 QtDemuxStream *stream = qtdemux->streams[n];
1492 stream->time_position = desired_offset;
1493 stream->accumulated_base = 0;
1494 stream->sample_index = -1;
1495 stream->offset_in_sample = 0;
1496 stream->segment_index = -1;
1497 stream->sent_eos = FALSE;
1498 stream->segment_seqnum = seqnum;
1500 if (segment->flags & GST_SEEK_FLAG_FLUSH)
1501 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
1503 segment->position = desired_offset;
1504 segment->time = desired_offset;
1505 if (segment->rate >= 0) {
1506 segment->start = desired_offset;
1508 /* we stop at the end */
1509 if (segment->stop == -1)
1510 segment->stop = segment->duration;
1512 segment->stop = desired_offset;
1515 if (qtdemux->fragmented)
1516 qtdemux->fragmented_seek_pending = TRUE;
1521 /* do a seek in pull based mode */
1523 gst_qtdemux_do_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1528 GstSeekType cur_type, stop_type;
1532 GstSegment seeksegment;
1534 GstEvent *flush_event;
1537 GST_DEBUG_OBJECT (qtdemux, "doing seek with event");
1539 gst_event_parse_seek (event, &rate, &format, &flags,
1540 &cur_type, &cur, &stop_type, &stop);
1541 seqnum = gst_event_get_seqnum (event);
1543 /* we have to have a format as the segment format. Try to convert
1545 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1549 GST_DEBUG_OBJECT (qtdemux, "seek format %s", gst_format_get_name (format));
1551 GST_DEBUG_OBJECT (qtdemux, "doing seek without event");
1555 flush = flags & GST_SEEK_FLAG_FLUSH;
1557 /* stop streaming, either by flushing or by pausing the task */
1559 flush_event = gst_event_new_flush_start ();
1561 gst_event_set_seqnum (flush_event, seqnum);
1562 /* unlock upstream pull_range */
1563 gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event));
1564 /* make sure out loop function exits */
1565 gst_qtdemux_push_event (qtdemux, flush_event);
1567 /* non flushing seek, pause the task */
1568 gst_pad_pause_task (qtdemux->sinkpad);
1571 /* wait for streaming to finish */
1572 GST_PAD_STREAM_LOCK (qtdemux->sinkpad);
1574 /* copy segment, we need this because we still need the old
1575 * segment when we close the current segment. */
1576 memcpy (&seeksegment, &qtdemux->segment, sizeof (GstSegment));
1579 /* configure the segment with the seek variables */
1580 GST_DEBUG_OBJECT (qtdemux, "configuring seek");
1581 gst_segment_do_seek (&seeksegment, rate, format, flags,
1582 cur_type, cur, stop_type, stop, &update);
1585 /* now do the seek, this actually never returns FALSE */
1586 gst_qtdemux_perform_seek (qtdemux, &seeksegment, seqnum, flags);
1588 /* prepare for streaming again */
1590 flush_event = gst_event_new_flush_stop (TRUE);
1592 gst_event_set_seqnum (flush_event, seqnum);
1594 gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event));
1595 gst_qtdemux_push_event (qtdemux, flush_event);
1598 /* commit the new segment */
1599 memcpy (&qtdemux->segment, &seeksegment, sizeof (GstSegment));
1601 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
1602 GstMessage *msg = gst_message_new_segment_start (GST_OBJECT_CAST (qtdemux),
1603 qtdemux->segment.format, qtdemux->segment.position);
1605 gst_message_set_seqnum (msg, seqnum);
1606 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
1609 /* restart streaming, NEWSEGMENT will be sent from the streaming thread. */
1610 gst_pad_start_task (qtdemux->sinkpad, (GstTaskFunction) gst_qtdemux_loop,
1611 qtdemux->sinkpad, NULL);
1613 GST_PAD_STREAM_UNLOCK (qtdemux->sinkpad);
1620 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1626 qtdemux_ensure_index (GstQTDemux * qtdemux)
1630 GST_DEBUG_OBJECT (qtdemux, "collecting all metadata for all streams");
1632 /* Build complete index */
1633 for (i = 0; i < qtdemux->n_streams; i++) {
1634 QtDemuxStream *stream = qtdemux->streams[i];
1636 if (!qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1))
1644 GST_LOG_OBJECT (qtdemux,
1645 "Building complete index of stream %u for seeking failed!", i);
1651 gst_qtdemux_handle_src_event (GstPad * pad, GstObject * parent,
1654 gboolean res = TRUE;
1655 GstQTDemux *qtdemux = GST_QTDEMUX (parent);
1657 switch (GST_EVENT_TYPE (event)) {
1658 case GST_EVENT_SEEK:
1660 #ifndef GST_DISABLE_GST_DEBUG
1661 GstClockTime ts = gst_util_get_timestamp ();
1664 if (qtdemux->upstream_format_is_time && qtdemux->fragmented) {
1665 /* seek should be handled by upstream, we might need to re-download fragments */
1666 GST_DEBUG_OBJECT (qtdemux,
1667 "let upstream handle seek for fragmented playback");
1671 /* Build complete index for seeking;
1672 * if not a fragmented file at least */
1673 if (!qtdemux->fragmented)
1674 if (!qtdemux_ensure_index (qtdemux))
1676 #ifndef GST_DISABLE_GST_DEBUG
1677 ts = gst_util_get_timestamp () - ts;
1678 GST_INFO_OBJECT (qtdemux,
1679 "Time taken to parse index %" GST_TIME_FORMAT, GST_TIME_ARGS (ts));
1682 if (qtdemux->pullbased) {
1683 res = gst_qtdemux_do_seek (qtdemux, pad, event);
1684 } else if (gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (event))) {
1685 GST_DEBUG_OBJECT (qtdemux, "Upstream successfully seeked");
1687 } else if (qtdemux->state == QTDEMUX_STATE_MOVIE && qtdemux->n_streams
1688 && !qtdemux->fragmented) {
1689 res = gst_qtdemux_do_push_seek (qtdemux, pad, event);
1691 GST_DEBUG_OBJECT (qtdemux,
1692 "ignoring seek in push mode in current state");
1695 gst_event_unref (event);
1698 case GST_EVENT_NAVIGATION:
1700 gst_event_unref (event);
1704 res = gst_pad_event_default (pad, parent, event);
1714 GST_ERROR_OBJECT (qtdemux, "Index failed");
1715 gst_event_unref (event);
1721 /* stream/index return sample that is min/max w.r.t. byte position,
1722 * time is min/max w.r.t. time of samples,
1723 * the latter need not be time of the former sample */
1725 gst_qtdemux_find_sample (GstQTDemux * qtdemux, gint64 byte_pos, gboolean fw,
1726 gboolean set, QtDemuxStream ** _stream, gint * _index, gint64 * _time)
1729 gint64 time, min_time;
1730 QtDemuxStream *stream;
1736 for (n = 0; n < qtdemux->n_streams; ++n) {
1739 gboolean set_sample;
1741 str = qtdemux->streams[n];
1748 i = str->n_samples - 1;
1752 for (; (i >= 0) && (i < str->n_samples); i += inc) {
1753 if (str->samples[i].size == 0)
1756 if (fw && (str->samples[i].offset < byte_pos))
1759 if (!fw && (str->samples[i].offset + str->samples[i].size > byte_pos))
1762 /* move stream to first available sample */
1764 gst_qtdemux_move_stream (qtdemux, str, i);
1768 /* avoid index from sparse streams since they might be far away */
1770 /* determine min/max time */
1771 time = QTSAMPLE_PTS (str, &str->samples[i]);
1772 if (min_time == -1 || (!fw && time > min_time) ||
1773 (fw && time < min_time)) {
1777 /* determine stream with leading sample, to get its position */
1779 (fw && (str->samples[i].offset < stream->samples[index].offset)) ||
1780 (!fw && (str->samples[i].offset > stream->samples[index].offset))) {
1788 /* no sample for this stream, mark eos */
1790 gst_qtdemux_move_stream (qtdemux, str, str->n_samples);
1801 static QtDemuxStream *
1802 _create_stream (void)
1804 QtDemuxStream *stream;
1806 stream = g_new0 (QtDemuxStream, 1);
1807 /* new streams always need a discont */
1808 stream->discont = TRUE;
1809 /* we enable clipping for raw audio/video streams */
1810 stream->need_clip = FALSE;
1811 stream->need_process = FALSE;
1812 stream->segment_index = -1;
1813 stream->time_position = 0;
1814 stream->sample_index = -1;
1815 stream->offset_in_sample = 0;
1816 stream->new_stream = TRUE;
1817 stream->multiview_mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
1818 stream->multiview_flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
1819 stream->protected = FALSE;
1820 stream->protection_scheme_type = 0;
1821 stream->protection_scheme_version = 0;
1822 stream->protection_scheme_info = NULL;
1823 stream->n_samples_moof = 0;
1824 stream->duration_moof = 0;
1825 g_queue_init (&stream->protection_scheme_event_queue);
1830 gst_qtdemux_setcaps (GstQTDemux * demux, GstCaps * caps)
1832 GstStructure *structure;
1833 const gchar *variant;
1834 const GstCaps *mediacaps = NULL;
1836 GST_DEBUG_OBJECT (demux, "Sink set caps: %" GST_PTR_FORMAT, caps);
1838 structure = gst_caps_get_structure (caps, 0);
1839 variant = gst_structure_get_string (structure, "variant");
1841 if (variant && strcmp (variant, "mss-fragmented") == 0) {
1842 QtDemuxStream *stream;
1843 const GValue *value;
1845 demux->fragmented = TRUE;
1846 demux->mss_mode = TRUE;
1848 if (demux->n_streams > 1) {
1849 /* can't do this, we can only renegotiate for another mss format */
1853 value = gst_structure_get_value (structure, "media-caps");
1856 const GValue *timescale_v;
1858 /* TODO update when stream changes during playback */
1860 if (demux->n_streams == 0) {
1861 stream = _create_stream ();
1862 demux->streams[demux->n_streams] = stream;
1863 demux->n_streams = 1;
1865 stream = demux->streams[0];
1868 timescale_v = gst_structure_get_value (structure, "timescale");
1870 stream->timescale = g_value_get_uint64 (timescale_v);
1872 /* default mss timescale */
1873 stream->timescale = 10000000;
1875 demux->timescale = stream->timescale;
1877 mediacaps = gst_value_get_caps (value);
1878 if (!stream->caps || !gst_caps_is_equal_fixed (mediacaps, stream->caps)) {
1879 GST_DEBUG_OBJECT (demux, "We have a new caps %" GST_PTR_FORMAT,
1881 stream->new_caps = TRUE;
1883 gst_caps_replace (&stream->caps, (GstCaps *) mediacaps);
1884 structure = gst_caps_get_structure (mediacaps, 0);
1885 if (g_str_has_prefix (gst_structure_get_name (structure), "video")) {
1886 stream->subtype = FOURCC_vide;
1888 gst_structure_get_int (structure, "width", &stream->width);
1889 gst_structure_get_int (structure, "height", &stream->height);
1890 gst_structure_get_fraction (structure, "framerate", &stream->fps_n,
1892 } else if (g_str_has_prefix (gst_structure_get_name (structure), "audio")) {
1894 stream->subtype = FOURCC_soun;
1895 gst_structure_get_int (structure, "channels", &stream->n_channels);
1896 gst_structure_get_int (structure, "rate", &rate);
1897 stream->rate = rate;
1900 gst_caps_replace (&demux->media_caps, (GstCaps *) mediacaps);
1902 demux->mss_mode = FALSE;
1909 gst_qtdemux_reset (GstQTDemux * qtdemux, gboolean hard)
1913 GST_DEBUG_OBJECT (qtdemux, "Resetting demux");
1914 gst_pad_stop_task (qtdemux->sinkpad);
1916 if (hard || qtdemux->upstream_format_is_time) {
1917 qtdemux->state = QTDEMUX_STATE_INITIAL;
1918 qtdemux->neededbytes = 16;
1919 qtdemux->todrop = 0;
1920 qtdemux->pullbased = FALSE;
1921 qtdemux->posted_redirect = FALSE;
1922 qtdemux->first_mdat = -1;
1923 qtdemux->header_size = 0;
1924 qtdemux->mdatoffset = -1;
1925 qtdemux->restoredata_offset = -1;
1926 if (qtdemux->mdatbuffer)
1927 gst_buffer_unref (qtdemux->mdatbuffer);
1928 if (qtdemux->restoredata_buffer)
1929 gst_buffer_unref (qtdemux->restoredata_buffer);
1930 qtdemux->mdatbuffer = NULL;
1931 qtdemux->restoredata_buffer = NULL;
1932 qtdemux->mdatleft = 0;
1933 if (qtdemux->comp_brands)
1934 gst_buffer_unref (qtdemux->comp_brands);
1935 qtdemux->comp_brands = NULL;
1936 qtdemux->last_moov_offset = -1;
1937 if (qtdemux->moov_node)
1938 g_node_destroy (qtdemux->moov_node);
1939 qtdemux->moov_node = NULL;
1940 qtdemux->moov_node_compressed = NULL;
1941 if (qtdemux->tag_list)
1942 gst_mini_object_unref (GST_MINI_OBJECT_CAST (qtdemux->tag_list));
1943 qtdemux->tag_list = NULL;
1945 if (qtdemux->element_index)
1946 gst_object_unref (qtdemux->element_index);
1947 qtdemux->element_index = NULL;
1949 qtdemux->major_brand = 0;
1950 if (qtdemux->pending_newsegment)
1951 gst_event_unref (qtdemux->pending_newsegment);
1952 qtdemux->pending_newsegment = NULL;
1953 qtdemux->upstream_format_is_time = FALSE;
1954 qtdemux->upstream_seekable = FALSE;
1955 qtdemux->upstream_size = 0;
1957 qtdemux->fragment_start = -1;
1958 qtdemux->fragment_start_offset = -1;
1959 qtdemux->duration = 0;
1960 qtdemux->moof_offset = 0;
1961 qtdemux->chapters_track_id = 0;
1962 qtdemux->have_group_id = FALSE;
1963 qtdemux->group_id = G_MAXUINT;
1965 if (qtdemux->protection_system_ids) {
1966 g_ptr_array_free (qtdemux->protection_system_ids, TRUE);
1967 qtdemux->protection_system_ids = NULL;
1969 g_queue_foreach (&qtdemux->protection_event_queue, (GFunc) gst_event_unref,
1971 g_queue_clear (&qtdemux->protection_event_queue);
1973 qtdemux->offset = 0;
1974 gst_adapter_clear (qtdemux->adapter);
1975 gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
1978 for (n = 0; n < qtdemux->n_streams; n++) {
1979 gst_qtdemux_stream_free (qtdemux, qtdemux->streams[n]);
1980 qtdemux->streams[n] = NULL;
1982 qtdemux->n_streams = 0;
1983 qtdemux->n_video_streams = 0;
1984 qtdemux->n_audio_streams = 0;
1985 qtdemux->n_sub_streams = 0;
1986 qtdemux->exposed = FALSE;
1987 qtdemux->fragmented = FALSE;
1988 qtdemux->mss_mode = FALSE;
1989 gst_caps_replace (&qtdemux->media_caps, NULL);
1990 qtdemux->timescale = 0;
1991 qtdemux->got_moov = FALSE;
1992 qtdemux->pending_configure = FALSE;
1993 } else if (qtdemux->mss_mode) {
1994 gst_flow_combiner_reset (qtdemux->flowcombiner);
1995 for (n = 0; n < qtdemux->n_streams; n++)
1996 gst_qtdemux_stream_clear (qtdemux, qtdemux->streams[n]);
1998 gst_flow_combiner_reset (qtdemux->flowcombiner);
1999 for (n = 0; n < qtdemux->n_streams; n++) {
2000 qtdemux->streams[n]->sent_eos = FALSE;
2001 qtdemux->streams[n]->segment_seqnum = 0;
2002 qtdemux->streams[n]->time_position = 0;
2003 qtdemux->streams[n]->accumulated_base = 0;
2005 if (!qtdemux->pending_newsegment) {
2006 qtdemux->pending_newsegment = gst_event_new_segment (&qtdemux->segment);
2012 gst_qtdemux_handle_sink_event (GstPad * sinkpad, GstObject * parent,
2015 GstQTDemux *demux = GST_QTDEMUX (parent);
2016 gboolean res = TRUE;
2018 GST_LOG_OBJECT (demux, "handling %s event", GST_EVENT_TYPE_NAME (event));
2020 switch (GST_EVENT_TYPE (event)) {
2021 case GST_EVENT_SEGMENT:
2024 QtDemuxStream *stream;
2027 GstEvent *segment_event;
2029 /* some debug output */
2030 gst_event_copy_segment (event, &segment);
2031 GST_DEBUG_OBJECT (demux, "received newsegment %" GST_SEGMENT_FORMAT,
2034 if (segment.format == GST_FORMAT_TIME) {
2035 GST_DEBUG_OBJECT (demux, "new pending_newsegment");
2036 gst_event_replace (&demux->pending_newsegment, event);
2037 demux->upstream_format_is_time = TRUE;
2039 GST_DEBUG_OBJECT (demux, "Not storing upstream newsegment, "
2040 "not in time format");
2042 /* chain will send initial newsegment after pads have been added */
2043 if (demux->state != QTDEMUX_STATE_MOVIE || !demux->n_streams) {
2044 GST_DEBUG_OBJECT (demux, "still starting, eating event");
2049 /* check if this matches a time seek we received previously
2050 * FIXME for backwards compatibility reasons we use the
2051 * seek_offset here to compare. In the future we might want to
2052 * change this to use the seqnum as it uniquely should identify
2053 * the segment that corresponds to the seek. */
2054 GST_DEBUG_OBJECT (demux, "Stored seek offset: %" G_GINT64_FORMAT
2055 ", received segment offset %" G_GINT64_FORMAT,
2056 demux->seek_offset, segment.start);
2057 if (segment.format == GST_FORMAT_BYTES
2058 && demux->seek_offset == segment.start) {
2059 GST_OBJECT_LOCK (demux);
2060 offset = segment.start;
2062 segment.format = GST_FORMAT_TIME;
2063 segment.start = demux->push_seek_start;
2064 segment.stop = demux->push_seek_stop;
2065 GST_DEBUG_OBJECT (demux, "Replaced segment with stored seek "
2066 "segment %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT,
2067 GST_TIME_ARGS (segment.start), GST_TIME_ARGS (segment.stop));
2068 GST_OBJECT_UNLOCK (demux);
2071 /* we only expect a BYTE segment, e.g. following a seek */
2072 if (segment.format == GST_FORMAT_BYTES) {
2073 if (GST_CLOCK_TIME_IS_VALID (segment.start)) {
2074 offset = segment.start;
2076 gst_qtdemux_find_sample (demux, segment.start, TRUE, FALSE, NULL,
2077 NULL, (gint64 *) & segment.start);
2078 if ((gint64) segment.start < 0)
2081 if (GST_CLOCK_TIME_IS_VALID (segment.stop)) {
2082 gst_qtdemux_find_sample (demux, segment.stop, FALSE, FALSE, NULL,
2083 NULL, (gint64 *) & segment.stop);
2084 /* keyframe seeking should already arrange for start >= stop,
2085 * but make sure in other rare cases */
2086 segment.stop = MAX (segment.stop, segment.start);
2088 } else if (segment.format == GST_FORMAT_TIME) {
2089 /* push all data on the adapter before starting this
2091 gst_qtdemux_process_adapter (demux, TRUE);
2093 GST_DEBUG_OBJECT (demux, "unsupported segment format, ignoring");
2097 /* accept upstream's notion of segment and distribute along */
2098 segment.format = GST_FORMAT_TIME;
2099 segment.position = segment.time = segment.start;
2100 segment.duration = demux->segment.duration;
2101 segment.base = gst_segment_to_running_time (&demux->segment,
2102 GST_FORMAT_TIME, demux->segment.position);
2104 gst_segment_copy_into (&segment, &demux->segment);
2105 GST_DEBUG_OBJECT (demux, "Pushing newseg %" GST_SEGMENT_FORMAT, &segment);
2106 segment_event = gst_event_new_segment (&segment);
2107 gst_event_set_seqnum (segment_event, gst_event_get_seqnum (event));
2108 gst_qtdemux_push_event (demux, segment_event);
2110 /* clear leftover in current segment, if any */
2111 gst_adapter_clear (demux->adapter);
2113 /* set up streaming thread */
2114 demux->offset = offset;
2115 if (demux->upstream_format_is_time) {
2116 GST_DEBUG_OBJECT (demux, "Upstream is driving in time format, "
2117 "set values to restart reading from a new atom");
2118 demux->neededbytes = 16;
2121 gst_qtdemux_find_sample (demux, offset, TRUE, TRUE, &stream, &idx,
2124 demux->todrop = stream->samples[idx].offset - offset;
2125 demux->neededbytes = demux->todrop + stream->samples[idx].size;
2127 /* set up for EOS */
2128 demux->neededbytes = -1;
2133 gst_event_unref (event);
2137 case GST_EVENT_FLUSH_START:
2139 if (gst_event_get_seqnum (event) == demux->offset_seek_seqnum) {
2140 gst_event_unref (event);
2145 case GST_EVENT_FLUSH_STOP:
2149 dur = demux->segment.duration;
2150 gst_qtdemux_reset (demux, FALSE);
2151 demux->segment.duration = dur;
2153 if (gst_event_get_seqnum (event) == demux->offset_seek_seqnum) {
2154 gst_event_unref (event);
2160 /* If we are in push mode, and get an EOS before we've seen any streams,
2161 * then error out - we have nowhere to send the EOS */
2162 if (!demux->pullbased) {
2164 gboolean has_valid_stream = FALSE;
2165 for (i = 0; i < demux->n_streams; i++) {
2166 if (demux->streams[i]->pad != NULL) {
2167 has_valid_stream = TRUE;
2171 if (!has_valid_stream)
2172 gst_qtdemux_post_no_playable_stream_error (demux);
2174 GST_DEBUG_OBJECT (demux, "Data still available after EOS: %u",
2175 (guint) gst_adapter_available (demux->adapter));
2176 if (gst_qtdemux_process_adapter (demux, TRUE) != GST_FLOW_OK) {
2182 case GST_EVENT_CAPS:{
2183 GstCaps *caps = NULL;
2185 gst_event_parse_caps (event, &caps);
2186 gst_qtdemux_setcaps (demux, caps);
2188 gst_event_unref (event);
2191 case GST_EVENT_PROTECTION:
2193 const gchar *system_id = NULL;
2195 gst_event_parse_protection (event, &system_id, NULL, NULL);
2196 GST_DEBUG_OBJECT (demux, "Received protection event for system ID %s",
2198 gst_qtdemux_append_protection_system_id (demux, system_id);
2199 /* save the event for later, for source pads that have not been created */
2200 g_queue_push_tail (&demux->protection_event_queue, gst_event_ref (event));
2201 /* send it to all pads that already exist */
2202 gst_qtdemux_push_event (demux, event);
2210 res = gst_pad_event_default (demux->sinkpad, parent, event) & res;
2218 gst_qtdemux_set_index (GstElement * element, GstIndex * index)
2220 GstQTDemux *demux = GST_QTDEMUX (element);
2222 GST_OBJECT_LOCK (demux);
2223 if (demux->element_index)
2224 gst_object_unref (demux->element_index);
2226 demux->element_index = gst_object_ref (index);
2228 demux->element_index = NULL;
2230 GST_OBJECT_UNLOCK (demux);
2231 /* object lock might be taken again */
2233 gst_index_get_writer_id (index, GST_OBJECT (element), &demux->index_id);
2234 GST_DEBUG_OBJECT (demux, "Set index %" GST_PTR_FORMAT "for writer id %d",
2235 demux->element_index, demux->index_id);
2239 gst_qtdemux_get_index (GstElement * element)
2241 GstIndex *result = NULL;
2242 GstQTDemux *demux = GST_QTDEMUX (element);
2244 GST_OBJECT_LOCK (demux);
2245 if (demux->element_index)
2246 result = gst_object_ref (demux->element_index);
2247 GST_OBJECT_UNLOCK (demux);
2249 GST_DEBUG_OBJECT (demux, "Returning index %" GST_PTR_FORMAT, result);
2256 gst_qtdemux_stbl_free (QtDemuxStream * stream)
2258 g_free ((gpointer) stream->stco.data);
2259 stream->stco.data = NULL;
2260 g_free ((gpointer) stream->stsz.data);
2261 stream->stsz.data = NULL;
2262 g_free ((gpointer) stream->stsc.data);
2263 stream->stsc.data = NULL;
2264 g_free ((gpointer) stream->stts.data);
2265 stream->stts.data = NULL;
2266 g_free ((gpointer) stream->stss.data);
2267 stream->stss.data = NULL;
2268 g_free ((gpointer) stream->stps.data);
2269 stream->stps.data = NULL;
2270 g_free ((gpointer) stream->ctts.data);
2271 stream->ctts.data = NULL;
2275 gst_qtdemux_stream_flush_segments_data (GstQTDemux * qtdemux,
2276 QtDemuxStream * stream)
2278 g_free (stream->segments);
2279 stream->segments = NULL;
2280 stream->segment_index = -1;
2281 stream->accumulated_base = 0;
2285 gst_qtdemux_stream_flush_samples_data (GstQTDemux * qtdemux,
2286 QtDemuxStream * stream)
2288 g_free (stream->samples);
2289 stream->samples = NULL;
2290 gst_qtdemux_stbl_free (stream);
2293 g_free (stream->ra_entries);
2294 stream->ra_entries = NULL;
2295 stream->n_ra_entries = 0;
2297 stream->sample_index = -1;
2298 stream->stbl_index = -1;
2299 stream->n_samples = 0;
2300 stream->time_position = 0;
2302 stream->n_samples_moof = 0;
2303 stream->duration_moof = 0;
2307 gst_qtdemux_stream_clear (GstQTDemux * qtdemux, QtDemuxStream * stream)
2309 if (stream->allocator)
2310 gst_object_unref (stream->allocator);
2311 while (stream->buffers) {
2312 gst_buffer_unref (GST_BUFFER_CAST (stream->buffers->data));
2313 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
2315 if (stream->rgb8_palette) {
2316 gst_memory_unref (stream->rgb8_palette);
2317 stream->rgb8_palette = NULL;
2320 if (stream->pending_tags)
2321 gst_tag_list_unref (stream->pending_tags);
2322 stream->pending_tags = NULL;
2323 g_free (stream->redirect_uri);
2324 stream->redirect_uri = NULL;
2325 stream->sent_eos = FALSE;
2326 stream->sparse = FALSE;
2327 stream->protected = FALSE;
2328 if (stream->protection_scheme_info) {
2329 if (stream->protection_scheme_type == FOURCC_cenc) {
2330 QtDemuxCencSampleSetInfo *info =
2331 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
2332 if (info->default_properties)
2333 gst_structure_free (info->default_properties);
2334 if (info->crypto_info)
2335 g_ptr_array_free (info->crypto_info, TRUE);
2337 g_free (stream->protection_scheme_info);
2338 stream->protection_scheme_info = NULL;
2340 stream->protection_scheme_type = 0;
2341 stream->protection_scheme_version = 0;
2342 g_queue_foreach (&stream->protection_scheme_event_queue,
2343 (GFunc) gst_event_unref, NULL);
2344 g_queue_clear (&stream->protection_scheme_event_queue);
2345 gst_qtdemux_stream_flush_segments_data (qtdemux, stream);
2346 gst_qtdemux_stream_flush_samples_data (qtdemux, stream);
2350 gst_qtdemux_stream_free (GstQTDemux * qtdemux, QtDemuxStream * stream)
2352 gst_qtdemux_stream_clear (qtdemux, stream);
2354 gst_caps_unref (stream->caps);
2355 stream->caps = NULL;
2357 gst_element_remove_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
2358 gst_flow_combiner_remove_pad (qtdemux->flowcombiner, stream->pad);
2364 gst_qtdemux_remove_stream (GstQTDemux * qtdemux, int i)
2366 g_assert (i >= 0 && i < qtdemux->n_streams && qtdemux->streams[i] != NULL);
2368 gst_qtdemux_stream_free (qtdemux, qtdemux->streams[i]);
2369 qtdemux->streams[i] = qtdemux->streams[qtdemux->n_streams - 1];
2370 qtdemux->streams[qtdemux->n_streams - 1] = NULL;
2371 qtdemux->n_streams--;
2374 static GstStateChangeReturn
2375 gst_qtdemux_change_state (GstElement * element, GstStateChange transition)
2377 GstQTDemux *qtdemux = GST_QTDEMUX (element);
2378 GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
2380 switch (transition) {
2381 case GST_STATE_CHANGE_PAUSED_TO_READY:
2387 result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
2389 switch (transition) {
2390 case GST_STATE_CHANGE_PAUSED_TO_READY:{
2391 gst_qtdemux_reset (qtdemux, TRUE);
2402 qtdemux_parse_ftyp (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2404 /* counts as header data */
2405 qtdemux->header_size += length;
2407 /* only consider at least a sufficiently complete ftyp atom */
2411 qtdemux->major_brand = QT_FOURCC (buffer + 8);
2412 GST_DEBUG_OBJECT (qtdemux, "major brand: %" GST_FOURCC_FORMAT,
2413 GST_FOURCC_ARGS (qtdemux->major_brand));
2414 if (qtdemux->comp_brands)
2415 gst_buffer_unref (qtdemux->comp_brands);
2416 buf = qtdemux->comp_brands = gst_buffer_new_and_alloc (length - 16);
2417 gst_buffer_fill (buf, 0, buffer + 16, length - 16);
2422 qtdemux_handle_xmp_taglist (GstQTDemux * qtdemux, GstTagList * taglist,
2423 GstTagList * xmptaglist)
2425 /* Strip out bogus fields */
2427 if (gst_tag_list_get_scope (taglist) == GST_TAG_SCOPE_GLOBAL) {
2428 gst_tag_list_remove_tag (xmptaglist, GST_TAG_VIDEO_CODEC);
2429 gst_tag_list_remove_tag (xmptaglist, GST_TAG_AUDIO_CODEC);
2431 gst_tag_list_remove_tag (xmptaglist, GST_TAG_CONTAINER_FORMAT);
2434 GST_DEBUG_OBJECT (qtdemux, "Found XMP tags %" GST_PTR_FORMAT, xmptaglist);
2436 /* prioritize native tags using _KEEP mode */
2437 gst_tag_list_insert (taglist, xmptaglist, GST_TAG_MERGE_KEEP);
2438 gst_tag_list_unref (xmptaglist);
2443 qtdemux_parse_uuid (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2445 static const guint8 xmp_uuid[] = { 0xBE, 0x7A, 0xCF, 0xCB,
2446 0x97, 0xA9, 0x42, 0xE8,
2447 0x9C, 0x71, 0x99, 0x94,
2448 0x91, 0xE3, 0xAF, 0xAC
2450 static const guint8 playready_uuid[] = {
2451 0xd0, 0x8a, 0x4f, 0x18, 0x10, 0xf3, 0x4a, 0x82,
2452 0xb6, 0xc8, 0x32, 0xd8, 0xab, 0xa1, 0x83, 0xd3
2456 /* counts as header data */
2457 qtdemux->header_size += length;
2459 offset = (QT_UINT32 (buffer) == 0) ? 16 : 8;
2461 if (length <= offset + 16) {
2462 GST_DEBUG_OBJECT (qtdemux, "uuid atom is too short, skipping");
2466 if (memcmp (buffer + offset, xmp_uuid, 16) == 0) {
2468 GstTagList *taglist;
2470 buf = _gst_buffer_new_wrapped ((guint8 *) buffer + offset + 16,
2471 length - offset - 16, NULL);
2472 taglist = gst_tag_list_from_xmp_buffer (buf);
2473 gst_buffer_unref (buf);
2475 qtdemux_handle_xmp_taglist (qtdemux, qtdemux->tag_list, taglist);
2477 } else if (memcmp (buffer + offset, playready_uuid, 16) == 0) {
2479 const gunichar2 *s_utf16;
2482 len = GST_READ_UINT16_LE (buffer + offset + 0x30);
2483 s_utf16 = (const gunichar2 *) (buffer + offset + 0x32);
2484 contents = g_utf16_to_utf8 (s_utf16, len / 2, NULL, NULL, NULL);
2485 GST_ERROR_OBJECT (qtdemux, "contents: %s", contents);
2489 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT,
2490 (_("Cannot play stream because it is encrypted with PlayReady DRM.")),
2493 GST_DEBUG_OBJECT (qtdemux, "Ignoring unknown uuid: %08x-%08x-%08x-%08x",
2494 GST_READ_UINT32_LE (buffer + offset),
2495 GST_READ_UINT32_LE (buffer + offset + 4),
2496 GST_READ_UINT32_LE (buffer + offset + 8),
2497 GST_READ_UINT32_LE (buffer + offset + 12));
2502 qtdemux_parse_sidx (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2504 GstSidxParser sidx_parser;
2505 GstIsoffParserResult res;
2508 gst_isoff_qt_sidx_parser_init (&sidx_parser);
2511 gst_isoff_qt_sidx_parser_add_data (&sidx_parser, buffer, length,
2513 GST_DEBUG_OBJECT (qtdemux, "sidx parse result: %d", res);
2514 if (res == GST_ISOFF_QT_PARSER_DONE) {
2515 check_update_duration (qtdemux, sidx_parser.cumulative_pts);
2517 gst_isoff_qt_sidx_parser_clear (&sidx_parser);
2520 /* caller verifies at least 8 bytes in buf */
2522 extract_initial_length_and_fourcc (const guint8 * data, guint size,
2523 guint64 * plength, guint32 * pfourcc)
2528 length = QT_UINT32 (data);
2529 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
2530 fourcc = QT_FOURCC (data + 4);
2531 GST_DEBUG ("atom type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
2534 length = G_MAXUINT64;
2535 } else if (length == 1 && size >= 16) {
2536 /* this means we have an extended size, which is the 64 bit value of
2537 * the next 8 bytes */
2538 length = QT_UINT64 (data + 8);
2539 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
2549 qtdemux_parse_mehd (GstQTDemux * qtdemux, GstByteReader * br)
2551 guint32 version = 0;
2552 GstClockTime duration = 0;
2554 if (!gst_byte_reader_get_uint32_be (br, &version))
2559 if (!gst_byte_reader_get_uint64_be (br, &duration))
2564 if (!gst_byte_reader_get_uint32_be (br, &dur))
2569 GST_INFO_OBJECT (qtdemux, "mehd duration: %" G_GUINT64_FORMAT, duration);
2570 qtdemux->duration = duration;
2576 GST_DEBUG_OBJECT (qtdemux, "parsing mehd failed");
2582 qtdemux_parse_trex (GstQTDemux * qtdemux, QtDemuxStream * stream,
2583 guint32 * ds_duration, guint32 * ds_size, guint32 * ds_flags)
2585 if (!stream->parsed_trex && qtdemux->moov_node) {
2587 GstByteReader trex_data;
2589 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
2591 trex = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_trex,
2594 guint32 id = 0, dur = 0, size = 0, flags = 0, dummy = 0;
2596 /* skip version/flags */
2597 if (!gst_byte_reader_skip (&trex_data, 4))
2599 if (!gst_byte_reader_get_uint32_be (&trex_data, &id))
2601 if (id != stream->track_id)
2603 /* sample description index; ignore */
2604 if (!gst_byte_reader_get_uint32_be (&trex_data, &dummy))
2606 if (!gst_byte_reader_get_uint32_be (&trex_data, &dur))
2608 if (!gst_byte_reader_get_uint32_be (&trex_data, &size))
2610 if (!gst_byte_reader_get_uint32_be (&trex_data, &flags))
2613 GST_DEBUG_OBJECT (qtdemux, "fragment defaults for stream %d; "
2614 "duration %d, size %d, flags 0x%x", stream->track_id,
2617 stream->parsed_trex = TRUE;
2618 stream->def_sample_duration = dur;
2619 stream->def_sample_size = size;
2620 stream->def_sample_flags = flags;
2623 /* iterate all siblings */
2624 trex = qtdemux_tree_get_sibling_by_type_full (trex, FOURCC_trex,
2630 *ds_duration = stream->def_sample_duration;
2631 *ds_size = stream->def_sample_size;
2632 *ds_flags = stream->def_sample_flags;
2634 /* even then, above values are better than random ... */
2635 if (G_UNLIKELY (!stream->parsed_trex)) {
2636 GST_WARNING_OBJECT (qtdemux,
2637 "failed to find fragment defaults for stream %d", stream->track_id);
2644 /* This method should be called whenever a more accurate duration might
2645 * have been found. It will update all relevant variables if/where needed
2648 check_update_duration (GstQTDemux * qtdemux, GstClockTime duration)
2652 GstClockTime prevdur;
2654 movdur = GSTTIME_TO_QTTIME (qtdemux, duration);
2656 if (movdur > qtdemux->duration) {
2657 prevdur = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
2658 GST_DEBUG_OBJECT (qtdemux,
2659 "Updating total duration to %" GST_TIME_FORMAT " was %" GST_TIME_FORMAT,
2660 GST_TIME_ARGS (duration), GST_TIME_ARGS (prevdur));
2661 qtdemux->duration = movdur;
2662 GST_DEBUG_OBJECT (qtdemux,
2663 "qtdemux->segment.duration: %" GST_TIME_FORMAT " .stop: %"
2664 GST_TIME_FORMAT, GST_TIME_ARGS (qtdemux->segment.duration),
2665 GST_TIME_ARGS (qtdemux->segment.stop));
2666 if (qtdemux->segment.duration == prevdur) {
2667 /* If the current segment has duration/stop identical to previous duration
2668 * update them also (because they were set at that point in time with
2669 * the wrong duration */
2670 /* We convert the value *from* the timescale version to avoid rounding errors */
2671 GstClockTime fixeddur = QTTIME_TO_GSTTIME (qtdemux, movdur);
2672 GST_DEBUG_OBJECT (qtdemux, "Updated segment.duration and segment.stop");
2673 qtdemux->segment.duration = fixeddur;
2674 qtdemux->segment.stop = fixeddur;
2677 for (i = 0; i < qtdemux->n_streams; i++) {
2678 QtDemuxStream *stream = qtdemux->streams[i];
2680 movdur = GSTTIME_TO_QTSTREAMTIME (stream, duration);
2681 if (movdur > stream->duration) {
2682 GST_DEBUG_OBJECT (qtdemux,
2683 "Updating stream #%d duration to %" GST_TIME_FORMAT, i,
2684 GST_TIME_ARGS (duration));
2685 stream->duration = movdur;
2686 if (stream->dummy_segment) {
2687 /* Update all dummy values to new duration */
2688 stream->segments[0].stop_time = duration;
2689 stream->segments[0].duration = duration;
2690 stream->segments[0].media_stop = duration;
2698 qtdemux_parse_trun (GstQTDemux * qtdemux, GstByteReader * trun,
2699 QtDemuxStream * stream, guint32 d_sample_duration, guint32 d_sample_size,
2700 guint32 d_sample_flags, gint64 moof_offset, gint64 moof_length,
2701 gint64 * base_offset, gint64 * running_offset, gint64 decode_ts)
2703 GstClockTime gst_ts = GST_CLOCK_TIME_NONE;
2705 gint32 data_offset = 0;
2706 guint32 flags = 0, first_flags = 0, samples_count = 0;
2709 guint entry_size, dur_offset, size_offset, flags_offset = 0, ct_offset = 0;
2710 QtDemuxSample *sample;
2711 gboolean ismv = FALSE;
2713 GST_LOG_OBJECT (qtdemux, "parsing trun stream %d; "
2714 "default dur %d, size %d, flags 0x%x, base offset %" G_GINT64_FORMAT ", "
2715 "decode ts %" G_GINT64_FORMAT, stream->track_id, d_sample_duration,
2716 d_sample_size, d_sample_flags, *base_offset, decode_ts);
2718 if (stream->pending_seek && moof_offset < stream->pending_seek->moof_offset) {
2719 GST_INFO_OBJECT (stream->pad, "skipping trun before seek target fragment");
2723 /* presence of stss or not can't really tell us much,
2724 * and flags and so on tend to be marginally reliable in these files */
2725 if (stream->subtype == FOURCC_soun) {
2726 GST_DEBUG_OBJECT (qtdemux,
2727 "sound track in fragmented file; marking all keyframes");
2728 stream->all_keyframe = TRUE;
2731 if (!gst_byte_reader_skip (trun, 1) ||
2732 !gst_byte_reader_get_uint24_be (trun, &flags))
2735 if (!gst_byte_reader_get_uint32_be (trun, &samples_count))
2738 if (flags & TR_DATA_OFFSET) {
2739 /* note this is really signed */
2740 if (!gst_byte_reader_get_int32_be (trun, &data_offset))
2742 GST_LOG_OBJECT (qtdemux, "trun data offset %d", data_offset);
2743 /* default base offset = first byte of moof */
2744 if (*base_offset == -1) {
2745 GST_LOG_OBJECT (qtdemux, "base_offset at moof");
2746 *base_offset = moof_offset;
2748 *running_offset = *base_offset + data_offset;
2750 /* if no offset at all, that would mean data starts at moof start,
2751 * which is a bit wrong and is ismv crappy way, so compensate
2752 * assuming data is in mdat following moof */
2753 if (*base_offset == -1) {
2754 *base_offset = moof_offset + moof_length + 8;
2755 GST_LOG_OBJECT (qtdemux, "base_offset assumed in mdat after moof");
2758 if (*running_offset == -1)
2759 *running_offset = *base_offset;
2762 GST_LOG_OBJECT (qtdemux, "running offset now %" G_GINT64_FORMAT,
2764 GST_LOG_OBJECT (qtdemux, "trun offset %d, flags 0x%x, entries %d",
2765 data_offset, flags, samples_count);
2767 if (flags & TR_FIRST_SAMPLE_FLAGS) {
2768 if (G_UNLIKELY (flags & TR_SAMPLE_FLAGS)) {
2769 GST_DEBUG_OBJECT (qtdemux,
2770 "invalid flags; SAMPLE and FIRST_SAMPLE present, discarding latter");
2771 flags ^= TR_FIRST_SAMPLE_FLAGS;
2773 if (!gst_byte_reader_get_uint32_be (trun, &first_flags))
2775 GST_LOG_OBJECT (qtdemux, "first flags: 0x%x", first_flags);
2779 /* FIXME ? spec says other bits should also be checked to determine
2780 * entry size (and prefix size for that matter) */
2782 dur_offset = size_offset = 0;
2783 if (flags & TR_SAMPLE_DURATION) {
2784 GST_LOG_OBJECT (qtdemux, "entry duration present");
2785 dur_offset = entry_size;
2788 if (flags & TR_SAMPLE_SIZE) {
2789 GST_LOG_OBJECT (qtdemux, "entry size present");
2790 size_offset = entry_size;
2793 if (flags & TR_SAMPLE_FLAGS) {
2794 GST_LOG_OBJECT (qtdemux, "entry flags present");
2795 flags_offset = entry_size;
2798 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
2799 GST_LOG_OBJECT (qtdemux, "entry ct offset present");
2800 ct_offset = entry_size;
2804 if (!qt_atom_parser_has_chunks (trun, samples_count, entry_size))
2806 data = (guint8 *) gst_byte_reader_peek_data_unchecked (trun);
2808 if (stream->n_samples + samples_count >=
2809 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample))
2812 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
2813 stream->n_samples + samples_count, (guint) sizeof (QtDemuxSample),
2814 (stream->n_samples + samples_count) *
2815 sizeof (QtDemuxSample) / (1024.0 * 1024.0));
2817 /* create a new array of samples if it's the first sample parsed */
2818 if (stream->n_samples == 0) {
2819 g_assert (stream->samples == NULL);
2820 stream->samples = g_try_new0 (QtDemuxSample, samples_count);
2821 /* or try to reallocate it with space enough to insert the new samples */
2823 stream->samples = g_try_renew (QtDemuxSample, stream->samples,
2824 stream->n_samples + samples_count);
2825 if (stream->samples == NULL)
2828 if (qtdemux->fragment_start != -1) {
2829 timestamp = GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->fragment_start);
2830 qtdemux->fragment_start = -1;
2832 if (stream->n_samples == 0) {
2833 if (decode_ts > 0) {
2834 timestamp = decode_ts;
2835 } else if (stream->pending_seek != NULL) {
2836 /* if we don't have a timestamp from a tfdt box, we'll use the one
2837 * from the mfra seek table */
2838 GST_INFO_OBJECT (stream->pad, "pending seek ts = %" GST_TIME_FORMAT,
2839 GST_TIME_ARGS (stream->pending_seek->ts));
2841 /* FIXME: this is not fully correct, the timestamp refers to the random
2842 * access sample refered to in the tfra entry, which may not necessarily
2843 * be the first sample in the tfrag/trun (but hopefully/usually is) */
2844 timestamp = GSTTIME_TO_QTSTREAMTIME (stream, stream->pending_seek->ts);
2849 gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
2850 GST_INFO_OBJECT (stream->pad, "first sample ts %" GST_TIME_FORMAT,
2851 GST_TIME_ARGS (gst_ts));
2853 /* subsequent fragments extend stream */
2855 stream->samples[stream->n_samples - 1].timestamp +
2856 stream->samples[stream->n_samples - 1].duration;
2858 gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
2859 GST_INFO_OBJECT (qtdemux, "first sample ts %" GST_TIME_FORMAT
2860 " (extends previous samples)", GST_TIME_ARGS (gst_ts));
2864 sample = stream->samples + stream->n_samples;
2865 for (i = 0; i < samples_count; i++) {
2866 guint32 dur, size, sflags, ct;
2868 /* first read sample data */
2869 if (flags & TR_SAMPLE_DURATION) {
2870 dur = QT_UINT32 (data + dur_offset);
2872 dur = d_sample_duration;
2874 if (flags & TR_SAMPLE_SIZE) {
2875 size = QT_UINT32 (data + size_offset);
2877 size = d_sample_size;
2879 if (flags & TR_FIRST_SAMPLE_FLAGS) {
2881 sflags = first_flags;
2883 sflags = d_sample_flags;
2885 } else if (flags & TR_SAMPLE_FLAGS) {
2886 sflags = QT_UINT32 (data + flags_offset);
2888 sflags = d_sample_flags;
2890 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
2891 ct = QT_UINT32 (data + ct_offset);
2897 /* fill the sample information */
2898 sample->offset = *running_offset;
2899 sample->pts_offset = ct;
2900 sample->size = size;
2901 sample->timestamp = timestamp;
2902 sample->duration = dur;
2903 /* sample-is-difference-sample */
2904 /* ismv seems to use 0x40 for keyframe, 0xc0 for non-keyframe,
2905 * now idea how it relates to bitfield other than massive LE/BE confusion */
2906 sample->keyframe = ismv ? ((sflags & 0xff) == 0x40) : !(sflags & 0x10000);
2907 *running_offset += size;
2909 stream->duration_moof += dur;
2913 /* Update total duration if needed */
2914 check_update_duration (qtdemux, QTSTREAMTIME_TO_GSTTIME (stream, timestamp));
2916 stream->n_samples += samples_count;
2917 stream->n_samples_moof += samples_count;
2919 if (stream->pending_seek != NULL)
2920 stream->pending_seek = NULL;
2926 GST_WARNING_OBJECT (qtdemux, "failed to parse trun");
2931 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
2937 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
2938 "be larger than %uMB (broken file?)", stream->n_samples,
2939 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
2944 /* find stream with @id */
2945 static inline QtDemuxStream *
2946 qtdemux_find_stream (GstQTDemux * qtdemux, guint32 id)
2948 QtDemuxStream *stream;
2952 if (G_UNLIKELY (!id)) {
2953 GST_DEBUG_OBJECT (qtdemux, "invalid track id 0");
2957 /* try to get it fast and simple */
2958 if (G_LIKELY (id <= qtdemux->n_streams)) {
2959 stream = qtdemux->streams[id - 1];
2960 if (G_LIKELY (stream->track_id == id))
2964 /* linear search otherwise */
2965 for (i = 0; i < qtdemux->n_streams; i++) {
2966 stream = qtdemux->streams[i];
2967 if (stream->track_id == id)
2970 if (qtdemux->mss_mode) {
2971 /* mss should have only 1 stream anyway */
2972 return qtdemux->streams[0];
2979 qtdemux_parse_mfhd (GstQTDemux * qtdemux, GstByteReader * mfhd,
2980 guint32 * fragment_number)
2982 if (!gst_byte_reader_skip (mfhd, 4))
2984 if (!gst_byte_reader_get_uint32_be (mfhd, fragment_number))
2989 GST_WARNING_OBJECT (qtdemux, "Failed to parse mfhd atom");
2995 qtdemux_parse_tfhd (GstQTDemux * qtdemux, GstByteReader * tfhd,
2996 QtDemuxStream ** stream, guint32 * default_sample_duration,
2997 guint32 * default_sample_size, guint32 * default_sample_flags,
2998 gint64 * base_offset)
3001 guint32 track_id = 0;
3003 if (!gst_byte_reader_skip (tfhd, 1) ||
3004 !gst_byte_reader_get_uint24_be (tfhd, &flags))
3007 if (!gst_byte_reader_get_uint32_be (tfhd, &track_id))
3010 *stream = qtdemux_find_stream (qtdemux, track_id);
3011 if (G_UNLIKELY (!*stream))
3012 goto unknown_stream;
3014 if (flags & TF_DEFAULT_BASE_IS_MOOF)
3015 *base_offset = qtdemux->moof_offset;
3017 if (flags & TF_BASE_DATA_OFFSET)
3018 if (!gst_byte_reader_get_uint64_be (tfhd, (guint64 *) base_offset))
3021 /* obtain stream defaults */
3022 qtdemux_parse_trex (qtdemux, *stream,
3023 default_sample_duration, default_sample_size, default_sample_flags);
3025 /* FIXME: Handle TF_SAMPLE_DESCRIPTION_INDEX properly */
3026 if (flags & TF_SAMPLE_DESCRIPTION_INDEX)
3027 if (!gst_byte_reader_skip (tfhd, 4))
3030 if (flags & TF_DEFAULT_SAMPLE_DURATION)
3031 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_duration))
3034 if (flags & TF_DEFAULT_SAMPLE_SIZE)
3035 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_size))
3038 if (flags & TF_DEFAULT_SAMPLE_FLAGS)
3039 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_flags))
3046 GST_WARNING_OBJECT (qtdemux, "invalid track fragment header");
3051 GST_DEBUG_OBJECT (qtdemux, "unknown stream in tfhd");
3057 qtdemux_parse_tfdt (GstQTDemux * qtdemux, GstByteReader * br,
3058 guint64 * decode_time)
3060 guint32 version = 0;
3062 if (!gst_byte_reader_get_uint32_be (br, &version))
3067 if (!gst_byte_reader_get_uint64_be (br, decode_time))
3070 guint32 dec_time = 0;
3071 if (!gst_byte_reader_get_uint32_be (br, &dec_time))
3073 *decode_time = dec_time;
3076 GST_INFO_OBJECT (qtdemux, "Track fragment decode time: %" G_GUINT64_FORMAT,
3083 GST_DEBUG_OBJECT (qtdemux, "parsing tfdt failed");
3088 /* Returns a pointer to a GstStructure containing the properties of
3089 * the stream sample identified by @sample_index. The caller must unref
3090 * the returned object after use. Returns NULL if unsuccessful. */
3091 static GstStructure *
3092 qtdemux_get_cenc_sample_properties (GstQTDemux * qtdemux,
3093 QtDemuxStream * stream, guint sample_index)
3095 QtDemuxCencSampleSetInfo *info = NULL;
3097 g_return_val_if_fail (stream != NULL, NULL);
3098 g_return_val_if_fail (stream->protected, NULL);
3099 g_return_val_if_fail (stream->protection_scheme_info != NULL, NULL);
3101 info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
3103 /* Currently, cenc properties for groups of samples are not supported, so
3104 * simply return a copy of the default sample properties */
3105 return gst_structure_copy (info->default_properties);
3108 /* Parses the sizes of sample auxiliary information contained within a stream,
3109 * as given in a saiz box. Returns array of sample_count guint8 size values,
3110 * or NULL on failure */
3112 qtdemux_parse_saiz (GstQTDemux * qtdemux, QtDemuxStream * stream,
3113 GstByteReader * br, guint32 * sample_count)
3117 guint8 default_info_size;
3119 g_return_val_if_fail (qtdemux != NULL, NULL);
3120 g_return_val_if_fail (stream != NULL, NULL);
3121 g_return_val_if_fail (br != NULL, NULL);
3122 g_return_val_if_fail (sample_count != NULL, NULL);
3124 if (!gst_byte_reader_get_uint32_be (br, &flags))
3128 /* aux_info_type and aux_info_type_parameter are ignored */
3129 if (!gst_byte_reader_skip (br, 8))
3133 if (!gst_byte_reader_get_uint8 (br, &default_info_size))
3135 GST_DEBUG_OBJECT (qtdemux, "default_info_size: %u", default_info_size);
3137 if (!gst_byte_reader_get_uint32_be (br, sample_count))
3139 GST_DEBUG_OBJECT (qtdemux, "sample_count: %u", *sample_count);
3142 if (default_info_size == 0) {
3143 if (!gst_byte_reader_dup_data (br, *sample_count, &info_sizes)) {
3147 info_sizes = g_new (guint8, *sample_count);
3148 memset (info_sizes, default_info_size, *sample_count);
3154 /* Parses the offset of sample auxiliary information contained within a stream,
3155 * as given in a saio box. Returns TRUE if successful; FALSE otherwise. */
3157 qtdemux_parse_saio (GstQTDemux * qtdemux, QtDemuxStream * stream,
3158 GstByteReader * br, guint32 * info_type, guint32 * info_type_parameter,
3163 guint32 aux_info_type = 0;
3164 guint32 aux_info_type_parameter = 0;
3165 guint32 entry_count;
3169 g_return_val_if_fail (qtdemux != NULL, FALSE);
3170 g_return_val_if_fail (stream != NULL, FALSE);
3171 g_return_val_if_fail (br != NULL, FALSE);
3172 g_return_val_if_fail (offset != NULL, FALSE);
3174 if (!gst_byte_reader_get_uint8 (br, &version))
3177 if (!gst_byte_reader_get_uint24_be (br, &flags))
3181 if (!gst_byte_reader_get_uint32_be (br, &aux_info_type))
3183 if (!gst_byte_reader_get_uint32_be (br, &aux_info_type_parameter))
3185 } else if (stream->protected) {
3186 aux_info_type = stream->protection_scheme_type;
3188 aux_info_type = stream->fourcc;
3192 *info_type = aux_info_type;
3193 if (info_type_parameter)
3194 *info_type_parameter = aux_info_type_parameter;
3196 GST_DEBUG_OBJECT (qtdemux, "aux_info_type: '%" GST_FOURCC_FORMAT "', "
3197 "aux_info_type_parameter: %#06x",
3198 GST_FOURCC_ARGS (aux_info_type), aux_info_type_parameter);
3200 if (!gst_byte_reader_get_uint32_be (br, &entry_count))
3203 if (entry_count != 1) {
3204 GST_ERROR_OBJECT (qtdemux, "multiple offsets are not supported");
3209 if (!gst_byte_reader_get_uint32_be (br, &off_32))
3211 *offset = (guint64) off_32;
3213 if (!gst_byte_reader_get_uint64_be (br, &off_64))
3218 GST_DEBUG_OBJECT (qtdemux, "offset: %" G_GUINT64_FORMAT, *offset);
3223 qtdemux_gst_structure_free (GstStructure * gststructure)
3226 gst_structure_free (gststructure);
3230 /* Parses auxiliary information relating to samples protected using Common
3231 * Encryption (cenc); the format of this information is defined in
3232 * ISO/IEC 23001-7. Returns TRUE if successful; FALSE otherwise. */
3234 qtdemux_parse_cenc_aux_info (GstQTDemux * qtdemux, QtDemuxStream * stream,
3235 GstByteReader * br, guint8 * info_sizes, guint32 sample_count)
3237 QtDemuxCencSampleSetInfo *ss_info = NULL;
3241 g_return_val_if_fail (qtdemux != NULL, FALSE);
3242 g_return_val_if_fail (stream != NULL, FALSE);
3243 g_return_val_if_fail (br != NULL, FALSE);
3244 g_return_val_if_fail (stream->protected, FALSE);
3245 g_return_val_if_fail (stream->protection_scheme_info != NULL, FALSE);
3247 ss_info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
3249 if (ss_info->crypto_info) {
3250 GST_LOG_OBJECT (qtdemux, "unreffing existing crypto_info");
3251 g_ptr_array_free (ss_info->crypto_info, TRUE);
3254 ss_info->crypto_info =
3255 g_ptr_array_new_full (sample_count,
3256 (GDestroyNotify) qtdemux_gst_structure_free);
3258 for (i = 0; i < sample_count; ++i) {
3259 GstStructure *properties;
3260 guint16 n_subsamples = 0;
3265 properties = qtdemux_get_cenc_sample_properties (qtdemux, stream, i);
3266 if (properties == NULL) {
3267 GST_ERROR_OBJECT (qtdemux, "failed to get properties for sample %u", i);
3270 if (!gst_structure_get_uint (properties, "iv_size", &iv_size)) {
3271 GST_ERROR_OBJECT (qtdemux, "failed to get iv_size for sample %u", i);
3272 gst_structure_free (properties);
3275 if (!gst_byte_reader_dup_data (br, iv_size, &data)) {
3276 GST_ERROR_OBJECT (qtdemux, "failed to get IV for sample %u", i);
3277 gst_structure_free (properties);
3280 buf = gst_buffer_new_wrapped (data, iv_size);
3281 gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL);
3282 size = info_sizes[i];
3283 if (size > iv_size) {
3284 if (!gst_byte_reader_get_uint16_be (br, &n_subsamples)
3285 || !(n_subsamples > 0)) {
3286 gst_structure_free (properties);
3287 GST_ERROR_OBJECT (qtdemux,
3288 "failed to get subsample count for sample %u", i);
3291 GST_LOG_OBJECT (qtdemux, "subsample count: %u", n_subsamples);
3292 if (!gst_byte_reader_dup_data (br, n_subsamples * 6, &data)) {
3293 GST_ERROR_OBJECT (qtdemux, "failed to get subsample data for sample %u",
3295 gst_structure_free (properties);
3298 buf = gst_buffer_new_wrapped (data, n_subsamples * 6);
3300 gst_structure_free (properties);
3303 gst_structure_set (properties,
3304 "subsample_count", G_TYPE_UINT, n_subsamples,
3305 "subsamples", GST_TYPE_BUFFER, buf, NULL);
3307 gst_structure_set (properties, "subsample_count", G_TYPE_UINT, 0, NULL);
3309 g_ptr_array_add (ss_info->crypto_info, properties);
3314 /* Converts a UUID in raw byte form to a string representation, as defined in
3315 * RFC 4122. The caller takes ownership of the returned string and is
3316 * responsible for freeing it after use. */
3318 qtdemux_uuid_bytes_to_string (gconstpointer uuid_bytes)
3320 const guint8 *uuid = (const guint8 *) uuid_bytes;
3322 return g_strdup_printf ("%02x%02x%02x%02x-%02x%02x-%02x%02x-"
3323 "%02x%02x-%02x%02x%02x%02x%02x%02x",
3324 uuid[0], uuid[1], uuid[2], uuid[3],
3325 uuid[4], uuid[5], uuid[6], uuid[7],
3326 uuid[8], uuid[9], uuid[10], uuid[11],
3327 uuid[12], uuid[13], uuid[14], uuid[15]);
3330 /* Parses a Protection System Specific Header box (pssh), as defined in the
3331 * Common Encryption (cenc) standard (ISO/IEC 23001-7), which contains
3332 * information needed by a specific content protection system in order to
3333 * decrypt cenc-protected tracks. Returns TRUE if successful; FALSE
3336 qtdemux_parse_pssh (GstQTDemux * qtdemux, GNode * node)
3338 gchar *sysid_string;
3339 guint32 pssh_size = QT_UINT32 (node->data);
3340 GstBuffer *pssh = NULL;
3341 GstEvent *event = NULL;
3342 guint32 parent_box_type;
3345 if (G_UNLIKELY (pssh_size < 32U)) {
3346 GST_ERROR_OBJECT (qtdemux, "invalid box size");
3351 qtdemux_uuid_bytes_to_string ((const guint8 *) node->data + 12);
3353 gst_qtdemux_append_protection_system_id (qtdemux, sysid_string);
3355 pssh = gst_buffer_new_wrapped (g_memdup (node->data, pssh_size), pssh_size);
3356 GST_LOG_OBJECT (qtdemux, "cenc pssh size: %" G_GSIZE_FORMAT,
3357 gst_buffer_get_size (pssh));
3359 parent_box_type = QT_FOURCC ((const guint8 *) node->parent->data + 4);
3361 /* Push an event containing the pssh box onto the queues of all streams. */
3362 event = gst_event_new_protection (sysid_string, pssh,
3363 (parent_box_type == FOURCC_moov) ? "isobmff/moov" : "isobmff/moof");
3364 for (i = 0; i < qtdemux->n_streams; ++i) {
3365 g_queue_push_tail (&qtdemux->streams[i]->protection_scheme_event_queue,
3366 gst_event_ref (event));
3368 g_free (sysid_string);
3369 gst_event_unref (event);
3370 gst_buffer_unref (pssh);
3375 qtdemux_parse_moof (GstQTDemux * qtdemux, const guint8 * buffer, guint length,
3376 guint64 moof_offset, QtDemuxStream * stream)
3378 GNode *moof_node, *traf_node, *tfhd_node, *trun_node, *tfdt_node, *mfhd_node;
3379 GstByteReader mfhd_data, trun_data, tfhd_data, tfdt_data;
3380 GNode *saiz_node, *saio_node, *pssh_node;
3381 GstByteReader saiz_data, saio_data;
3382 guint32 ds_size = 0, ds_duration = 0, ds_flags = 0;
3383 gint64 base_offset, running_offset;
3386 /* NOTE @stream ignored */
3388 moof_node = g_node_new ((guint8 *) buffer);
3389 qtdemux_parse_node (qtdemux, moof_node, buffer, length);
3390 qtdemux_node_dump (qtdemux, moof_node);
3392 /* Get fragment number from mfhd and check it's valid */
3394 qtdemux_tree_get_child_by_type_full (moof_node, FOURCC_mfhd, &mfhd_data);
3395 if (mfhd_node == NULL)
3397 if (!qtdemux_parse_mfhd (qtdemux, &mfhd_data, &frag_num))
3399 GST_DEBUG_OBJECT (qtdemux, "Fragment #%d", frag_num);
3401 /* unknown base_offset to start with */
3402 base_offset = running_offset = -1;
3403 traf_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_traf);
3405 guint64 decode_time = 0;
3407 /* Fragment Header node */
3409 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfhd,
3413 if (!qtdemux_parse_tfhd (qtdemux, &tfhd_data, &stream, &ds_duration,
3414 &ds_size, &ds_flags, &base_offset))
3417 /* The following code assumes at most a single set of sample auxiliary
3418 * data in the fragment (consisting of a saiz box and a corresponding saio
3419 * box); in theory, however, there could be multiple sets of sample
3420 * auxiliary data in a fragment. */
3422 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saiz,
3425 guint32 info_type = 0;
3427 guint32 info_type_parameter = 0;
3429 g_free (qtdemux->cenc_aux_info_sizes);
3431 qtdemux->cenc_aux_info_sizes =
3432 qtdemux_parse_saiz (qtdemux, stream, &saiz_data,
3433 &qtdemux->cenc_aux_sample_count);
3434 if (qtdemux->cenc_aux_info_sizes == NULL) {
3435 GST_ERROR_OBJECT (qtdemux, "failed to parse saiz box");
3439 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saio,
3442 GST_ERROR_OBJECT (qtdemux, "saiz box without a corresponding saio box");
3443 g_free (qtdemux->cenc_aux_info_sizes);
3444 qtdemux->cenc_aux_info_sizes = NULL;
3448 if (G_UNLIKELY (!qtdemux_parse_saio (qtdemux, stream, &saio_data,
3449 &info_type, &info_type_parameter, &offset))) {
3450 GST_ERROR_OBJECT (qtdemux, "failed to parse saio box");
3451 g_free (qtdemux->cenc_aux_info_sizes);
3452 qtdemux->cenc_aux_info_sizes = NULL;
3455 if (base_offset > qtdemux->moof_offset)
3456 offset += (guint64) (base_offset - qtdemux->moof_offset);
3457 if (info_type == FOURCC_cenc && info_type_parameter == 0U) {
3459 if (offset > length) {
3460 GST_DEBUG_OBJECT (qtdemux, "cenc auxiliary info stored out of moof");
3461 qtdemux->cenc_aux_info_offset = offset;
3463 gst_byte_reader_init (&br, buffer + offset, length - offset);
3464 if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
3465 qtdemux->cenc_aux_info_sizes,
3466 qtdemux->cenc_aux_sample_count)) {
3467 GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
3468 g_free (qtdemux->cenc_aux_info_sizes);
3469 qtdemux->cenc_aux_info_sizes = NULL;
3477 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfdt,
3480 GstClockTime decode_time_ts;
3482 /* We'll use decode_time to interpolate timestamps
3483 * in case the input timestamps are missing */
3484 qtdemux_parse_tfdt (qtdemux, &tfdt_data, &decode_time);
3486 decode_time_ts = QTSTREAMTIME_TO_GSTTIME (stream, decode_time);
3488 GST_DEBUG_OBJECT (qtdemux, "decode time %" G_GINT64_FORMAT
3489 " (%" GST_TIME_FORMAT ")", decode_time,
3490 GST_TIME_ARGS (decode_time_ts));
3492 /* Discard the fragment buffer timestamp info to avoid using it.
3493 * Rely on tfdt instead as it is more accurate than the timestamp
3494 * that is fetched from a manifest/playlist and is usually
3496 qtdemux->fragment_start = -1;
3499 if (G_UNLIKELY (!stream)) {
3500 /* we lost track of offset, we'll need to regain it,
3501 * but can delay complaining until later or avoid doing so altogether */
3505 if (G_UNLIKELY (base_offset < -1))
3508 if (qtdemux->upstream_format_is_time)
3509 gst_qtdemux_stream_flush_samples_data (qtdemux, stream);
3511 /* initialise moof sample data */
3512 stream->n_samples_moof = 0;
3513 stream->duration_moof = 0;
3515 /* Track Run node */
3517 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_trun,
3520 qtdemux_parse_trun (qtdemux, &trun_data, stream,
3521 ds_duration, ds_size, ds_flags, moof_offset, length, &base_offset,
3522 &running_offset, decode_time);
3523 /* iterate all siblings */
3524 trun_node = qtdemux_tree_get_sibling_by_type_full (trun_node, FOURCC_trun,
3527 /* if no new base_offset provided for next traf,
3528 * base is end of current traf */
3529 base_offset = running_offset;
3530 running_offset = -1;
3532 if (stream->n_samples_moof && stream->duration_moof)
3533 stream->new_caps = TRUE;
3536 /* iterate all siblings */
3537 traf_node = qtdemux_tree_get_sibling_by_type (traf_node, FOURCC_traf);
3540 /* parse any protection system info */
3541 pssh_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_pssh);
3543 GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
3544 qtdemux_parse_pssh (qtdemux, pssh_node);
3545 pssh_node = qtdemux_tree_get_sibling_by_type (pssh_node, FOURCC_pssh);
3548 g_node_destroy (moof_node);
3553 GST_DEBUG_OBJECT (qtdemux, "missing tfhd box");
3558 GST_DEBUG_OBJECT (qtdemux, "Missing mfhd box");
3563 GST_DEBUG_OBJECT (qtdemux, "lost offset");
3568 g_node_destroy (moof_node);
3569 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
3570 (_("This file is corrupt and cannot be played.")), (NULL));
3576 /* might be used if some day we actually use mfra & co
3577 * for random access to fragments,
3578 * but that will require quite some modifications and much less relying
3579 * on a sample array */
3583 qtdemux_parse_tfra (GstQTDemux * qtdemux, GNode * tfra_node)
3585 QtDemuxStream *stream;
3586 guint32 ver_flags, track_id, len, num_entries, i;
3587 guint value_size, traf_size, trun_size, sample_size;
3588 guint64 time = 0, moof_offset = 0;
3590 GstBuffer *buf = NULL;
3595 gst_byte_reader_init (&tfra, tfra_node->data, QT_UINT32 (tfra_node->data));
3597 if (!gst_byte_reader_skip (&tfra, 8))
3600 if (!gst_byte_reader_get_uint32_be (&tfra, &ver_flags))
3603 if (!gst_byte_reader_get_uint32_be (&tfra, &track_id)
3604 || !gst_byte_reader_get_uint32_be (&tfra, &len)
3605 || !gst_byte_reader_get_uint32_be (&tfra, &num_entries))
3608 GST_DEBUG_OBJECT (qtdemux, "parsing tfra box for track id %u", track_id);
3610 stream = qtdemux_find_stream (qtdemux, track_id);
3612 goto unknown_trackid;
3614 value_size = ((ver_flags >> 24) == 1) ? sizeof (guint64) : sizeof (guint32);
3615 sample_size = (len & 3) + 1;
3616 trun_size = ((len & 12) >> 2) + 1;
3617 traf_size = ((len & 48) >> 4) + 1;
3619 GST_DEBUG_OBJECT (qtdemux, "%u entries, sizes: value %u, traf %u, trun %u, "
3620 "sample %u", num_entries, value_size, traf_size, trun_size, sample_size);
3622 if (num_entries == 0)
3625 if (!qt_atom_parser_has_chunks (&tfra, num_entries,
3626 value_size + value_size + traf_size + trun_size + sample_size))
3629 g_free (stream->ra_entries);
3630 stream->ra_entries = g_new (QtDemuxRandomAccessEntry, num_entries);
3631 stream->n_ra_entries = num_entries;
3633 for (i = 0; i < num_entries; i++) {
3634 qt_atom_parser_get_offset (&tfra, value_size, &time);
3635 qt_atom_parser_get_offset (&tfra, value_size, &moof_offset);
3636 qt_atom_parser_get_uint_with_size_unchecked (&tfra, traf_size);
3637 qt_atom_parser_get_uint_with_size_unchecked (&tfra, trun_size);
3638 qt_atom_parser_get_uint_with_size_unchecked (&tfra, sample_size);
3640 time = QTSTREAMTIME_TO_GSTTIME (stream, time);
3642 GST_LOG_OBJECT (qtdemux, "fragment time: %" GST_TIME_FORMAT ", "
3643 " moof_offset: %" G_GUINT64_FORMAT, GST_TIME_ARGS (time), moof_offset);
3645 stream->ra_entries[i].ts = time;
3646 stream->ra_entries[i].moof_offset = moof_offset;
3648 /* don't want to go through the entire file and read all moofs at startup */
3650 ret = gst_qtdemux_pull_atom (qtdemux, moof_offset, 0, &buf);
3651 if (ret != GST_FLOW_OK)
3653 qtdemux_parse_moof (qtdemux, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf),
3654 moof_offset, stream);
3655 gst_buffer_unref (buf);
3659 check_update_duration (qtdemux, time);
3666 GST_WARNING_OBJECT (qtdemux, "Couldn't find stream for track %u", track_id);
3671 GST_WARNING_OBJECT (qtdemux, "broken traf box, ignoring");
3676 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
3682 qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux)
3684 GstMapInfo mfro_map = GST_MAP_INFO_INIT;
3685 GstMapInfo mfra_map = GST_MAP_INFO_INIT;
3686 GstBuffer *mfro = NULL, *mfra = NULL;
3688 gboolean ret = FALSE;
3689 GNode *mfra_node, *tfra_node;
3690 guint64 mfra_offset = 0;
3691 guint32 fourcc, mfra_size;
3694 /* query upstream size in bytes */
3695 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &len))
3696 goto size_query_failed;
3698 /* mfro box should be at the very end of the file */
3699 flow = gst_qtdemux_pull_atom (qtdemux, len - 16, 16, &mfro);
3700 if (flow != GST_FLOW_OK)
3703 gst_buffer_map (mfro, &mfro_map, GST_MAP_READ);
3705 fourcc = QT_FOURCC (mfro_map.data + 4);
3706 if (fourcc != FOURCC_mfro)
3709 GST_INFO_OBJECT (qtdemux, "Found mfro box");
3710 if (mfro_map.size < 16)
3711 goto invalid_mfro_size;
3713 mfra_size = QT_UINT32 (mfro_map.data + 12);
3714 if (mfra_size >= len)
3715 goto invalid_mfra_size;
3717 mfra_offset = len - mfra_size;
3719 GST_INFO_OBJECT (qtdemux, "mfra offset: %" G_GUINT64_FORMAT ", size %u",
3720 mfra_offset, mfra_size);
3722 /* now get and parse mfra box */
3723 flow = gst_qtdemux_pull_atom (qtdemux, mfra_offset, mfra_size, &mfra);
3724 if (flow != GST_FLOW_OK)
3727 gst_buffer_map (mfra, &mfra_map, GST_MAP_READ);
3729 mfra_node = g_node_new ((guint8 *) mfra_map.data);
3730 qtdemux_parse_node (qtdemux, mfra_node, mfra_map.data, mfra_map.size);
3732 tfra_node = qtdemux_tree_get_child_by_type (mfra_node, FOURCC_tfra);
3735 qtdemux_parse_tfra (qtdemux, tfra_node);
3736 /* iterate all siblings */
3737 tfra_node = qtdemux_tree_get_sibling_by_type (tfra_node, FOURCC_tfra);
3739 g_node_destroy (mfra_node);
3741 GST_INFO_OBJECT (qtdemux, "parsed movie fragment random access box (mfra)");
3747 if (mfro_map.memory != NULL)
3748 gst_buffer_unmap (mfro, &mfro_map);
3749 gst_buffer_unref (mfro);
3752 if (mfra_map.memory != NULL)
3753 gst_buffer_unmap (mfra, &mfra_map);
3754 gst_buffer_unref (mfra);
3761 GST_WARNING_OBJECT (qtdemux, "could not query upstream size");
3766 GST_WARNING_OBJECT (qtdemux, "mfro size is too small");
3771 GST_WARNING_OBJECT (qtdemux, "mfra_size in mfro box is invalid");
3776 GST_WARNING_OBJECT (qtdemux, "bogus mfra offset or size, broken file");
3782 add_offset (guint64 offset, guint64 advance)
3784 /* Avoid 64-bit overflow by clamping */
3785 if (offset > G_MAXUINT64 - advance)
3787 return offset + advance;
3790 static GstFlowReturn
3791 gst_qtdemux_loop_state_header (GstQTDemux * qtdemux)
3795 GstBuffer *buf = NULL;
3796 GstFlowReturn ret = GST_FLOW_OK;
3797 guint64 cur_offset = qtdemux->offset;
3800 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, 16, &buf);
3801 if (G_UNLIKELY (ret != GST_FLOW_OK))
3803 gst_buffer_map (buf, &map, GST_MAP_READ);
3804 if (G_LIKELY (map.size >= 8))
3805 extract_initial_length_and_fourcc (map.data, map.size, &length, &fourcc);
3806 gst_buffer_unmap (buf, &map);
3807 gst_buffer_unref (buf);
3809 /* maybe we already got most we needed, so only consider this eof */
3810 if (G_UNLIKELY (length == 0)) {
3811 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
3812 (_("Invalid atom size.")),
3813 ("Header atom '%" GST_FOURCC_FORMAT "' has empty length",
3814 GST_FOURCC_ARGS (fourcc)));
3821 /* record for later parsing when needed */
3822 if (!qtdemux->moof_offset) {
3823 qtdemux->moof_offset = qtdemux->offset;
3825 if (qtdemux_pull_mfro_mfra (qtdemux)) {
3828 qtdemux->offset += length; /* skip moof and keep going */
3830 if (qtdemux->got_moov) {
3831 GST_INFO_OBJECT (qtdemux, "moof header, got moov, done with headers");
3842 GST_LOG_OBJECT (qtdemux,
3843 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
3844 GST_FOURCC_ARGS (fourcc), cur_offset);
3845 qtdemux->offset = add_offset (qtdemux->offset, length);
3850 GstBuffer *moov = NULL;
3852 if (qtdemux->got_moov) {
3853 GST_DEBUG_OBJECT (qtdemux, "Skipping moov atom as we have one already");
3854 qtdemux->offset = add_offset (qtdemux->offset, length);
3858 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, length, &moov);
3859 if (ret != GST_FLOW_OK)
3861 gst_buffer_map (moov, &map, GST_MAP_READ);
3863 if (length != map.size) {
3864 /* Some files have a 'moov' atom at the end of the file which contains
3865 * a terminal 'free' atom where the body of the atom is missing.
3866 * Check for, and permit, this special case.
3868 if (map.size >= 8) {
3869 guint8 *final_data = map.data + (map.size - 8);
3870 guint32 final_length = QT_UINT32 (final_data);
3871 guint32 final_fourcc = QT_FOURCC (final_data + 4);
3873 if (final_fourcc == FOURCC_free
3874 && map.size + final_length - 8 == length) {
3875 /* Ok, we've found that special case. Allocate a new buffer with
3876 * that free atom actually present. */
3877 GstBuffer *newmoov = gst_buffer_new_and_alloc (length);
3878 gst_buffer_fill (newmoov, 0, map.data, map.size);
3879 gst_buffer_memset (newmoov, map.size, 0, final_length - 8);
3880 gst_buffer_unmap (moov, &map);
3881 gst_buffer_unref (moov);
3883 gst_buffer_map (moov, &map, GST_MAP_READ);
3888 if (length != map.size) {
3889 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
3890 (_("This file is incomplete and cannot be played.")),
3891 ("We got less than expected (received %" G_GSIZE_FORMAT
3892 ", wanted %u, offset %" G_GUINT64_FORMAT ")", map.size,
3893 (guint) length, cur_offset));
3894 gst_buffer_unmap (moov, &map);
3895 gst_buffer_unref (moov);
3896 ret = GST_FLOW_ERROR;
3899 qtdemux->offset += length;
3901 qtdemux_parse_moov (qtdemux, map.data, length);
3902 qtdemux_node_dump (qtdemux, qtdemux->moov_node);
3904 qtdemux_parse_tree (qtdemux);
3905 g_node_destroy (qtdemux->moov_node);
3906 gst_buffer_unmap (moov, &map);
3907 gst_buffer_unref (moov);
3908 qtdemux->moov_node = NULL;
3909 qtdemux->got_moov = TRUE;
3915 GstBuffer *ftyp = NULL;
3917 /* extract major brand; might come in handy for ISO vs QT issues */
3918 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &ftyp);
3919 if (ret != GST_FLOW_OK)
3921 qtdemux->offset += length;
3922 gst_buffer_map (ftyp, &map, GST_MAP_READ);
3923 qtdemux_parse_ftyp (qtdemux, map.data, map.size);
3924 gst_buffer_unmap (ftyp, &map);
3925 gst_buffer_unref (ftyp);
3930 GstBuffer *uuid = NULL;
3932 /* uuid are extension atoms */
3933 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &uuid);
3934 if (ret != GST_FLOW_OK)
3936 qtdemux->offset += length;
3937 gst_buffer_map (uuid, &map, GST_MAP_READ);
3938 qtdemux_parse_uuid (qtdemux, map.data, map.size);
3939 gst_buffer_unmap (uuid, &map);
3940 gst_buffer_unref (uuid);
3945 GstBuffer *sidx = NULL;
3946 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &sidx);
3947 if (ret != GST_FLOW_OK)
3949 qtdemux->offset += length;
3950 gst_buffer_map (sidx, &map, GST_MAP_READ);
3951 qtdemux_parse_sidx (qtdemux, map.data, map.size);
3952 gst_buffer_unmap (sidx, &map);
3953 gst_buffer_unref (sidx);
3958 GstBuffer *unknown = NULL;
3960 GST_LOG_OBJECT (qtdemux,
3961 "unknown %08x '%" GST_FOURCC_FORMAT "' of size %" G_GUINT64_FORMAT
3962 " at %" G_GUINT64_FORMAT, fourcc, GST_FOURCC_ARGS (fourcc), length,
3964 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &unknown);
3965 if (ret != GST_FLOW_OK)
3967 gst_buffer_map (unknown, &map, GST_MAP_READ);
3968 GST_MEMDUMP ("Unknown tag", map.data, map.size);
3969 gst_buffer_unmap (unknown, &map);
3970 gst_buffer_unref (unknown);
3971 qtdemux->offset += length;
3977 if (ret == GST_FLOW_EOS && (qtdemux->got_moov || qtdemux->media_caps)) {
3978 /* digested all data, show what we have */
3979 qtdemux_prepare_streams (qtdemux);
3980 ret = qtdemux_expose_streams (qtdemux);
3982 qtdemux->state = QTDEMUX_STATE_MOVIE;
3983 GST_DEBUG_OBJECT (qtdemux, "switching state to STATE_MOVIE (%d)",
3990 /* Seeks to the previous keyframe of the indexed stream and
3991 * aligns other streams with respect to the keyframe timestamp
3992 * of indexed stream. Only called in case of Reverse Playback
3994 static GstFlowReturn
3995 gst_qtdemux_seek_to_previous_keyframe (GstQTDemux * qtdemux)
3998 guint32 seg_idx = 0, k_index = 0;
3999 guint32 ref_seg_idx, ref_k_index;
4000 GstClockTime k_pos = 0, last_stop = 0;
4001 QtDemuxSegment *seg = NULL;
4002 QtDemuxStream *ref_str = NULL;
4003 guint64 seg_media_start_mov; /* segment media start time in mov format */
4006 /* Now we choose an arbitrary stream, get the previous keyframe timestamp
4007 * and finally align all the other streams on that timestamp with their
4008 * respective keyframes */
4009 for (n = 0; n < qtdemux->n_streams; n++) {
4010 QtDemuxStream *str = qtdemux->streams[n];
4012 /* No candidate yet, take the first stream */
4018 /* So that stream has a segment, we prefer video streams */
4019 if (str->subtype == FOURCC_vide) {
4025 if (G_UNLIKELY (!ref_str)) {
4026 GST_DEBUG_OBJECT (qtdemux, "couldn't find any stream");
4030 if (G_UNLIKELY (!ref_str->from_sample)) {
4031 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of the file");
4035 /* So that stream has been playing from from_sample to to_sample. We will
4036 * get the timestamp of the previous sample and search for a keyframe before
4037 * that. For audio streams we do an arbitrary jump in the past (10 samples) */
4038 if (ref_str->subtype == FOURCC_vide) {
4039 k_index = gst_qtdemux_find_keyframe (qtdemux, ref_str,
4040 ref_str->from_sample - 1);
4042 if (ref_str->from_sample >= 10)
4043 k_index = ref_str->from_sample - 10;
4049 ref_str->samples[k_index].timestamp +
4050 ref_str->samples[k_index].pts_offset;
4052 /* get current segment for that stream */
4053 seg = &ref_str->segments[ref_str->segment_index];
4054 /* Use segment start in original timescale for comparisons */
4055 seg_media_start_mov = seg->trak_media_start;
4057 GST_LOG_OBJECT (qtdemux, "keyframe index %u ts %" G_GUINT64_FORMAT
4058 " seg start %" G_GUINT64_FORMAT " %" GST_TIME_FORMAT "\n",
4059 k_index, target_ts, seg_media_start_mov,
4060 GST_TIME_ARGS (seg->media_start));
4062 /* Crawl back through segments to find the one containing this I frame */
4063 while (target_ts < seg_media_start_mov) {
4064 GST_DEBUG_OBJECT (qtdemux,
4065 "keyframe position (sample %u) is out of segment %u " " target %"
4066 G_GUINT64_FORMAT " seg start %" G_GUINT64_FORMAT, k_index,
4067 ref_str->segment_index, target_ts, seg_media_start_mov);
4069 if (G_UNLIKELY (!ref_str->segment_index)) {
4070 /* Reached first segment, let's consider it's EOS */
4073 ref_str->segment_index--;
4074 seg = &ref_str->segments[ref_str->segment_index];
4075 /* Use segment start in original timescale for comparisons */
4076 seg_media_start_mov = seg->trak_media_start;
4078 /* Calculate time position of the keyframe and where we should stop */
4080 QTSTREAMTIME_TO_GSTTIME (ref_str,
4081 target_ts - seg->trak_media_start) + seg->time;
4083 QTSTREAMTIME_TO_GSTTIME (ref_str,
4084 ref_str->samples[ref_str->from_sample].timestamp -
4085 seg->trak_media_start) + seg->time;
4087 GST_DEBUG_OBJECT (qtdemux, "preferred stream played from sample %u, "
4088 "now going to sample %u (pts %" GST_TIME_FORMAT ")", ref_str->from_sample,
4089 k_index, GST_TIME_ARGS (k_pos));
4091 /* Set last_stop with the keyframe timestamp we pushed of that stream */
4092 qtdemux->segment.position = last_stop;
4093 GST_DEBUG_OBJECT (qtdemux, "last_stop now is %" GST_TIME_FORMAT,
4094 GST_TIME_ARGS (last_stop));
4096 if (G_UNLIKELY (last_stop < qtdemux->segment.start)) {
4097 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of segment");
4101 ref_seg_idx = ref_str->segment_index;
4102 ref_k_index = k_index;
4104 /* Align them all on this */
4105 for (n = 0; n < qtdemux->n_streams; n++) {
4107 GstClockTime seg_time = 0;
4108 QtDemuxStream *str = qtdemux->streams[n];
4110 /* aligning reference stream again might lead to backing up to yet another
4111 * keyframe (due to timestamp rounding issues),
4112 * potentially putting more load on downstream; so let's try to avoid */
4113 if (str == ref_str) {
4114 seg_idx = ref_seg_idx;
4115 seg = &str->segments[seg_idx];
4116 k_index = ref_k_index;
4117 GST_DEBUG_OBJECT (qtdemux, "reference stream %d segment %d, "
4118 "sample at index %d", n, ref_str->segment_index, k_index);
4120 seg_idx = gst_qtdemux_find_segment (qtdemux, str, k_pos);
4121 GST_DEBUG_OBJECT (qtdemux,
4122 "stream %d align segment %d for keyframe pos %" GST_TIME_FORMAT, n,
4123 seg_idx, GST_TIME_ARGS (k_pos));
4125 /* get segment and time in the segment */
4126 seg = &str->segments[seg_idx];
4127 seg_time = k_pos - seg->time;
4129 /* get the media time in the segment.
4130 * No adjustment for empty "filler" segments */
4131 if (seg->media_start != GST_CLOCK_TIME_NONE)
4132 seg_time += seg->media_start;
4134 /* get the index of the sample with media time */
4135 index = gst_qtdemux_find_index_linear (qtdemux, str, seg_time);
4136 GST_DEBUG_OBJECT (qtdemux,
4137 "stream %d sample for %" GST_TIME_FORMAT " at %u", n,
4138 GST_TIME_ARGS (seg_time), index);
4140 /* find previous keyframe */
4141 k_index = gst_qtdemux_find_keyframe (qtdemux, str, index);
4144 /* Remember until where we want to go */
4145 str->to_sample = str->from_sample - 1;
4146 /* Define our time position */
4148 str->samples[k_index].timestamp + str->samples[k_index].pts_offset;
4149 str->time_position = QTSTREAMTIME_TO_GSTTIME (str, target_ts) + seg->time;
4150 if (seg->media_start != GST_CLOCK_TIME_NONE)
4151 str->time_position -= seg->media_start;
4153 /* Now seek back in time */
4154 gst_qtdemux_move_stream (qtdemux, str, k_index);
4155 GST_DEBUG_OBJECT (qtdemux, "stream %d keyframe at %u, time position %"
4156 GST_TIME_FORMAT " playing from sample %u to %u", n, k_index,
4157 GST_TIME_ARGS (str->time_position), str->from_sample, str->to_sample);
4163 return GST_FLOW_EOS;
4166 /* activate the given segment number @seg_idx of @stream at time @offset.
4167 * @offset is an absolute global position over all the segments.
4169 * This will push out a NEWSEGMENT event with the right values and
4170 * position the stream index to the first decodable sample before
4174 gst_qtdemux_activate_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
4175 guint32 seg_idx, GstClockTime offset)
4178 QtDemuxSegment *segment;
4179 guint32 index, kf_index;
4180 GstClockTime seg_time;
4181 GstClockTime start, stop, time;
4184 GST_LOG_OBJECT (stream->pad, "activate segment %d, offset %" GST_TIME_FORMAT,
4185 seg_idx, GST_TIME_ARGS (offset));
4187 /* update the current segment */
4188 stream->segment_index = seg_idx;
4190 /* get the segment */
4191 segment = &stream->segments[seg_idx];
4193 if (G_UNLIKELY (offset < segment->time)) {
4194 GST_WARNING_OBJECT (stream->pad, "offset < segment->time %" GST_TIME_FORMAT,
4195 GST_TIME_ARGS (segment->time));
4199 /* segment lies beyond total indicated duration */
4200 if (G_UNLIKELY (qtdemux->segment.duration != GST_CLOCK_TIME_NONE &&
4201 segment->time > qtdemux->segment.duration)) {
4202 GST_WARNING_OBJECT (stream->pad, "file duration %" GST_TIME_FORMAT
4203 " < segment->time %" GST_TIME_FORMAT,
4204 GST_TIME_ARGS (qtdemux->segment.duration),
4205 GST_TIME_ARGS (segment->time));
4209 /* get time in this segment */
4210 seg_time = offset - segment->time;
4212 GST_LOG_OBJECT (stream->pad, "seg_time %" GST_TIME_FORMAT,
4213 GST_TIME_ARGS (seg_time));
4215 if (G_UNLIKELY (seg_time > segment->duration)) {
4216 GST_LOG_OBJECT (stream->pad,
4217 "seg_time > segment->duration %" GST_TIME_FORMAT,
4218 GST_TIME_ARGS (segment->duration));
4219 seg_time = segment->duration;
4222 /* qtdemux->segment.stop is in outside-time-realm, whereas
4223 * segment->media_stop is in track-time-realm.
4225 * In order to compare the two, we need to bring segment.stop
4226 * into the track-time-realm */
4228 stop = qtdemux->segment.stop;
4229 if (stop == GST_CLOCK_TIME_NONE)
4230 stop = qtdemux->segment.duration;
4231 if (stop == GST_CLOCK_TIME_NONE)
4232 stop = segment->media_stop;
4235 MIN (segment->media_stop, stop - segment->time + segment->media_start);
4237 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
4238 start = segment->time + seg_time;
4240 stop = start - seg_time + segment->duration;
4241 } else if (qtdemux->segment.rate >= 0) {
4242 start = MIN (segment->media_start + seg_time, stop);
4245 if (segment->media_start >= qtdemux->segment.start) {
4246 time = segment->time;
4248 time = segment->time + (qtdemux->segment.start - segment->media_start);
4251 start = MAX (segment->media_start, qtdemux->segment.start);
4252 stop = MIN (segment->media_start + seg_time, stop);
4255 GST_DEBUG_OBJECT (stream->pad, "new segment %d from %" GST_TIME_FORMAT
4256 " to %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT, seg_idx,
4257 GST_TIME_ARGS (start), GST_TIME_ARGS (stop), GST_TIME_ARGS (time));
4259 /* combine global rate with that of the segment */
4260 rate = segment->rate * qtdemux->segment.rate;
4262 /* Copy flags from main segment */
4263 stream->segment.flags = qtdemux->segment.flags;
4265 /* update the segment values used for clipping */
4266 stream->segment.offset = qtdemux->segment.offset;
4267 stream->segment.base = qtdemux->segment.base + stream->accumulated_base;
4268 stream->segment.applied_rate = qtdemux->segment.applied_rate;
4269 stream->segment.rate = rate;
4270 stream->segment.start = start + QTSTREAMTIME_TO_GSTTIME (stream,
4271 stream->cslg_shift);
4272 stream->segment.stop = stop + QTSTREAMTIME_TO_GSTTIME (stream,
4273 stream->cslg_shift);
4274 stream->segment.time = time;
4275 stream->segment.position = stream->segment.start;
4277 GST_DEBUG_OBJECT (stream->pad, "New segment: %" GST_SEGMENT_FORMAT,
4280 /* now prepare and send the segment */
4282 event = gst_event_new_segment (&stream->segment);
4283 if (stream->segment_seqnum) {
4284 gst_event_set_seqnum (event, stream->segment_seqnum);
4286 gst_pad_push_event (stream->pad, event);
4287 /* assume we can send more data now */
4288 GST_PAD_LAST_FLOW_RETURN (stream->pad) = GST_FLOW_OK;
4289 /* clear to send tags on this pad now */
4290 gst_qtdemux_push_tags (qtdemux, stream);
4293 /* in the fragmented case, we pick a fragment that starts before our
4294 * desired position and rely on downstream to wait for a keyframe
4295 * (FIXME: doesn't seem to work so well with ismv and wmv, as no parser; the
4296 * tfra entries tells us which trun/sample the key unit is in, but we don't
4297 * make use of this additional information at the moment) */
4298 if (qtdemux->fragmented) {
4299 stream->to_sample = G_MAXUINT32;
4303 /* We don't need to look for a sample in push-based */
4304 if (!qtdemux->pullbased)
4307 /* and move to the keyframe before the indicated media time of the
4309 if (G_LIKELY (!QTSEGMENT_IS_EMPTY (segment))) {
4310 if (qtdemux->segment.rate >= 0) {
4311 index = gst_qtdemux_find_index_linear (qtdemux, stream, start);
4312 stream->to_sample = G_MAXUINT32;
4313 GST_DEBUG_OBJECT (stream->pad,
4314 "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
4315 GST_TIME_FORMAT, GST_TIME_ARGS (start), index,
4316 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
4318 index = gst_qtdemux_find_index_linear (qtdemux, stream, stop);
4319 stream->to_sample = index;
4320 GST_DEBUG_OBJECT (stream->pad,
4321 "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
4322 GST_TIME_FORMAT, GST_TIME_ARGS (stop), index,
4323 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
4326 GST_DEBUG_OBJECT (stream->pad, "No need to look for keyframe, "
4327 "this is an empty segment");
4331 /* gst_qtdemux_parse_sample () called from gst_qtdemux_find_index_linear ()
4332 * encountered an error and printed a message so we return appropriately */
4336 /* we're at the right spot */
4337 if (index == stream->sample_index) {
4338 GST_DEBUG_OBJECT (stream->pad, "we are at the right index");
4342 /* find keyframe of the target index */
4343 kf_index = gst_qtdemux_find_keyframe (qtdemux, stream, index);
4346 /* indent does stupid stuff with stream->samples[].timestamp */
4348 /* if we move forwards, we don't have to go back to the previous
4349 * keyframe since we already sent that. We can also just jump to
4350 * the keyframe right before the target index if there is one. */
4351 if (index > stream->sample_index) {
4352 /* moving forwards check if we move past a keyframe */
4353 if (kf_index > stream->sample_index) {
4354 GST_DEBUG_OBJECT (stream->pad,
4355 "moving forwards to keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" )", kf_index,
4356 GST_TIME_ARGS (QTSAMPLE_PTS(stream, &stream->samples[kf_index])),
4357 GST_TIME_ARGS (QTSAMPLE_DTS(stream, &stream->samples[kf_index])));
4358 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
4360 GST_DEBUG_OBJECT (stream->pad,
4361 "moving forwards, keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" ) already sent", kf_index,
4362 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[kf_index])),
4363 GST_TIME_ARGS (QTSAMPLE_DTS (stream, &stream->samples[kf_index])));
4366 GST_DEBUG_OBJECT (stream->pad,
4367 "moving backwards to keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" )", kf_index,
4368 GST_TIME_ARGS (QTSAMPLE_PTS(stream, &stream->samples[kf_index])),
4369 GST_TIME_ARGS (QTSAMPLE_DTS(stream, &stream->samples[kf_index])));
4370 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
4378 /* prepare to get the current sample of @stream, getting essential values.
4380 * This function will also prepare and send the segment when needed.
4382 * Return FALSE if the stream is EOS.
4387 gst_qtdemux_prepare_current_sample (GstQTDemux * qtdemux,
4388 QtDemuxStream * stream, gboolean * empty, guint64 * offset, guint * size,
4389 GstClockTime * dts, GstClockTime * pts, GstClockTime * duration,
4390 gboolean * keyframe)
4392 QtDemuxSample *sample;
4393 GstClockTime time_position;
4396 g_return_val_if_fail (stream != NULL, FALSE);
4398 time_position = stream->time_position;
4399 if (G_UNLIKELY (time_position == GST_CLOCK_TIME_NONE))
4402 seg_idx = stream->segment_index;
4403 if (G_UNLIKELY (seg_idx == -1)) {
4404 /* find segment corresponding to time_position if we are looking
4406 seg_idx = gst_qtdemux_find_segment (qtdemux, stream, time_position);
4409 /* different segment, activate it, sample_index will be set. */
4410 if (G_UNLIKELY (stream->segment_index != seg_idx))
4411 gst_qtdemux_activate_segment (qtdemux, stream, seg_idx, time_position);
4413 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (&stream->segments[stream->
4415 QtDemuxSegment *seg = &stream->segments[stream->segment_index];
4417 GST_LOG_OBJECT (qtdemux, "Empty segment activated,"
4418 " prepare empty sample");
4421 *pts = *dts = time_position;
4422 *duration = seg->duration - (time_position - seg->time);
4429 if (stream->sample_index == -1)
4430 stream->sample_index = 0;
4432 GST_LOG_OBJECT (qtdemux, "segment active, index = %u of %u",
4433 stream->sample_index, stream->n_samples);
4435 if (G_UNLIKELY (stream->sample_index >= stream->n_samples)) {
4436 if (!qtdemux->fragmented)
4439 GST_INFO_OBJECT (qtdemux, "out of samples, trying to add more");
4443 GST_OBJECT_LOCK (qtdemux);
4444 flow = qtdemux_add_fragmented_samples (qtdemux);
4445 GST_OBJECT_UNLOCK (qtdemux);
4447 if (flow != GST_FLOW_OK)
4450 while (stream->sample_index >= stream->n_samples);
4453 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
4454 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
4455 stream->sample_index);
4459 /* now get the info for the sample we're at */
4460 sample = &stream->samples[stream->sample_index];
4462 *dts = QTSAMPLE_DTS (stream, sample);
4463 *pts = QTSAMPLE_PTS (stream, sample);
4464 *offset = sample->offset;
4465 *size = sample->size;
4466 *duration = QTSAMPLE_DUR_DTS (stream, sample, *dts);
4467 *keyframe = QTSAMPLE_KEYFRAME (stream, sample);
4474 stream->time_position = GST_CLOCK_TIME_NONE;
4479 /* move to the next sample in @stream.
4481 * Moves to the next segment when needed.
4484 gst_qtdemux_advance_sample (GstQTDemux * qtdemux, QtDemuxStream * stream)
4486 QtDemuxSample *sample;
4487 QtDemuxSegment *segment;
4489 /* get current segment */
4490 segment = &stream->segments[stream->segment_index];
4492 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
4493 GST_DEBUG_OBJECT (qtdemux, "Empty segment, no samples to advance");
4497 if (G_UNLIKELY (stream->sample_index >= stream->to_sample)) {
4498 /* Mark the stream as EOS */
4499 GST_DEBUG_OBJECT (qtdemux,
4500 "reached max allowed sample %u, mark EOS", stream->to_sample);
4501 stream->time_position = GST_CLOCK_TIME_NONE;
4505 /* move to next sample */
4506 stream->sample_index++;
4507 stream->offset_in_sample = 0;
4509 /* reached the last sample, we need the next segment */
4510 if (G_UNLIKELY (stream->sample_index >= stream->n_samples))
4513 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
4514 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
4515 stream->sample_index);
4519 /* get next sample */
4520 sample = &stream->samples[stream->sample_index];
4522 /* see if we are past the segment */
4523 if (G_UNLIKELY (QTSAMPLE_DTS (stream, sample) >= segment->media_stop))
4526 if (QTSAMPLE_DTS (stream, sample) >= segment->media_start) {
4527 /* inside the segment, update time_position, looks very familiar to
4528 * GStreamer segments, doesn't it? */
4529 stream->time_position =
4530 QTSAMPLE_DTS (stream, sample) - segment->media_start + segment->time;
4532 /* not yet in segment, time does not yet increment. This means
4533 * that we are still prerolling keyframes to the decoder so it can
4534 * decode the first sample of the segment. */
4535 stream->time_position = segment->time;
4539 /* move to the next segment */
4542 GST_DEBUG_OBJECT (qtdemux, "segment %d ended ", stream->segment_index);
4544 if (stream->segment_index == stream->n_segments - 1) {
4545 /* are we at the end of the last segment, we're EOS */
4546 stream->time_position = GST_CLOCK_TIME_NONE;
4548 /* else we're only at the end of the current segment */
4549 stream->time_position = segment->stop_time;
4551 /* make sure we select a new segment */
4553 /* accumulate previous segments */
4554 if (GST_CLOCK_TIME_IS_VALID (stream->segment.stop))
4555 stream->accumulated_base +=
4556 (stream->segment.stop -
4557 stream->segment.start) / ABS (stream->segment.rate);
4559 stream->segment_index = -1;
4564 gst_qtdemux_sync_streams (GstQTDemux * demux)
4568 if (demux->n_streams <= 1)
4571 for (i = 0; i < demux->n_streams; i++) {
4572 QtDemuxStream *stream;
4573 GstClockTime end_time;
4575 stream = demux->streams[i];
4580 /* TODO advance time on subtitle streams here, if any some day */
4582 /* some clips/trailers may have unbalanced streams at the end,
4583 * so send EOS on shorter stream to prevent stalling others */
4585 /* do not mess with EOS if SEGMENT seeking */
4586 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT)
4589 if (demux->pullbased) {
4590 /* loop mode is sample time based */
4591 if (!STREAM_IS_EOS (stream))
4594 /* push mode is byte position based */
4595 if (stream->n_samples &&
4596 stream->samples[stream->n_samples - 1].offset >= demux->offset)
4600 if (stream->sent_eos)
4603 /* only act if some gap */
4604 end_time = stream->segments[stream->n_segments - 1].stop_time;
4605 GST_LOG_OBJECT (demux, "current position: %" GST_TIME_FORMAT
4606 ", stream end: %" GST_TIME_FORMAT,
4607 GST_TIME_ARGS (demux->segment.position), GST_TIME_ARGS (end_time));
4608 if (GST_CLOCK_TIME_IS_VALID (end_time)
4609 && (end_time + 2 * GST_SECOND < demux->segment.position)) {
4610 GST_DEBUG_OBJECT (demux, "sending EOS for stream %s",
4611 GST_PAD_NAME (stream->pad));
4612 stream->sent_eos = TRUE;
4613 gst_pad_push_event (stream->pad, gst_event_new_eos ());
4618 /* EOS and NOT_LINKED need to be combined. This means that we return:
4620 * GST_FLOW_NOT_LINKED: when all pads NOT_LINKED.
4621 * GST_FLOW_EOS: when all pads EOS or NOT_LINKED.
4623 static GstFlowReturn
4624 gst_qtdemux_combine_flows (GstQTDemux * demux, QtDemuxStream * stream,
4627 GST_LOG_OBJECT (demux, "flow return: %s", gst_flow_get_name (ret));
4630 ret = gst_flow_combiner_update_pad_flow (demux->flowcombiner, stream->pad,
4633 ret = gst_flow_combiner_update_flow (demux->flowcombiner, ret);
4635 GST_LOG_OBJECT (demux, "combined flow return: %s", gst_flow_get_name (ret));
4639 /* the input buffer metadata must be writable. Returns NULL when the buffer is
4640 * completely clipped
4642 * Should be used only with raw buffers */
4644 gst_qtdemux_clip_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
4647 guint64 start, stop, cstart, cstop, diff;
4648 GstClockTime pts, duration;
4650 gint num_rate, denom_rate;
4655 osize = size = gst_buffer_get_size (buf);
4658 /* depending on the type, setup the clip parameters */
4659 if (stream->subtype == FOURCC_soun) {
4660 frame_size = stream->bytes_per_frame;
4661 num_rate = GST_SECOND;
4662 denom_rate = (gint) stream->rate;
4664 } else if (stream->subtype == FOURCC_vide) {
4666 num_rate = stream->fps_n;
4667 denom_rate = stream->fps_d;
4672 if (frame_size <= 0)
4673 goto bad_frame_size;
4675 /* we can only clip if we have a valid pts */
4676 pts = GST_BUFFER_PTS (buf);
4677 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (pts)))
4680 duration = GST_BUFFER_DURATION (buf);
4682 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (duration))) {
4684 gst_util_uint64_scale_int (size / frame_size, num_rate, denom_rate);
4688 stop = start + duration;
4690 if (G_UNLIKELY (!gst_segment_clip (&stream->segment,
4691 GST_FORMAT_TIME, start, stop, &cstart, &cstop)))
4694 /* see if some clipping happened */
4695 diff = cstart - start;
4701 /* bring clipped time to samples and to bytes */
4702 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
4705 GST_DEBUG_OBJECT (qtdemux,
4706 "clipping start to %" GST_TIME_FORMAT " %"
4707 G_GUINT64_FORMAT " bytes", GST_TIME_ARGS (cstart), diff);
4713 diff = stop - cstop;
4718 /* bring clipped time to samples and then to bytes */
4719 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
4721 GST_DEBUG_OBJECT (qtdemux,
4722 "clipping stop to %" GST_TIME_FORMAT " %" G_GUINT64_FORMAT
4723 " bytes", GST_TIME_ARGS (cstop), diff);
4728 if (offset != 0 || size != osize)
4729 gst_buffer_resize (buf, offset, size);
4731 GST_BUFFER_DTS (buf) = GST_CLOCK_TIME_NONE;
4732 GST_BUFFER_PTS (buf) = pts;
4733 GST_BUFFER_DURATION (buf) = duration;
4737 /* dropped buffer */
4740 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
4745 GST_DEBUG_OBJECT (qtdemux, "bad frame size");
4750 GST_DEBUG_OBJECT (qtdemux, "no pts on buffer");
4755 GST_DEBUG_OBJECT (qtdemux, "clipped buffer");
4756 gst_buffer_unref (buf);
4761 /* the input buffer metadata must be writable,
4762 * but time/duration etc not yet set and need not be preserved */
4764 gst_qtdemux_process_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
4771 /* not many cases for now */
4772 if (G_UNLIKELY (stream->fourcc == FOURCC_mp4s)) {
4773 /* send a one time dvd clut event */
4774 if (stream->pending_event && stream->pad)
4775 gst_pad_push_event (stream->pad, stream->pending_event);
4776 stream->pending_event = NULL;
4779 if (G_UNLIKELY (stream->subtype != FOURCC_text
4780 && stream->subtype != FOURCC_sbtl &&
4781 stream->subtype != FOURCC_subp)) {
4785 gst_buffer_map (buf, &map, GST_MAP_READ);
4787 /* empty buffer is sent to terminate previous subtitle */
4788 if (map.size <= 2) {
4789 gst_buffer_unmap (buf, &map);
4790 gst_buffer_unref (buf);
4793 if (stream->subtype == FOURCC_subp) {
4794 /* That's all the processing needed for subpictures */
4795 gst_buffer_unmap (buf, &map);
4799 nsize = GST_READ_UINT16_BE (map.data);
4800 nsize = MIN (nsize, map.size - 2);
4802 GST_LOG_OBJECT (qtdemux, "3GPP timed text subtitle: %d/%" G_GSIZE_FORMAT "",
4805 /* takes care of UTF-8 validation or UTF-16 recognition,
4806 * no other encoding expected */
4807 str = gst_tag_freeform_string_to_utf8 ((gchar *) map.data + 2, nsize, NULL);
4808 gst_buffer_unmap (buf, &map);
4810 gst_buffer_unref (buf);
4811 buf = _gst_buffer_new_wrapped (str, strlen (str), g_free);
4813 /* this should not really happen unless the subtitle is corrupted */
4814 gst_buffer_unref (buf);
4818 /* FIXME ? convert optional subsequent style info to markup */
4823 /* Sets a buffer's attributes properly and pushes it downstream.
4824 * Also checks for additional actions and custom processing that may
4825 * need to be done first.
4827 static GstFlowReturn
4828 gst_qtdemux_decorate_and_push_buffer (GstQTDemux * qtdemux,
4829 QtDemuxStream * stream, GstBuffer * buf,
4830 GstClockTime dts, GstClockTime pts, GstClockTime duration,
4831 gboolean keyframe, GstClockTime position, guint64 byte_position)
4833 GstFlowReturn ret = GST_FLOW_OK;
4835 /* offset the timestamps according to the edit list */
4837 if (G_UNLIKELY (stream->fourcc == FOURCC_rtsp)) {
4841 gst_buffer_map (buf, &map, GST_MAP_READ);
4842 url = g_strndup ((gchar *) map.data, map.size);
4843 gst_buffer_unmap (buf, &map);
4844 if (url != NULL && strlen (url) != 0) {
4845 /* we have RTSP redirect now */
4846 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
4847 gst_message_new_element (GST_OBJECT_CAST (qtdemux),
4848 gst_structure_new ("redirect",
4849 "new-location", G_TYPE_STRING, url, NULL)));
4850 qtdemux->posted_redirect = TRUE;
4852 GST_WARNING_OBJECT (qtdemux, "Redirect URI of stream is empty, not "
4858 /* position reporting */
4859 if (qtdemux->segment.rate >= 0) {
4860 qtdemux->segment.position = position;
4861 gst_qtdemux_sync_streams (qtdemux);
4864 if (G_UNLIKELY (!stream->pad)) {
4865 GST_DEBUG_OBJECT (qtdemux, "No output pad for stream, ignoring");
4866 gst_buffer_unref (buf);
4870 /* send out pending buffers */
4871 while (stream->buffers) {
4872 GstBuffer *buffer = (GstBuffer *) stream->buffers->data;
4874 if (G_UNLIKELY (stream->discont)) {
4875 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
4876 GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
4877 stream->discont = FALSE;
4879 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
4882 gst_pad_push (stream->pad, buffer);
4884 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
4887 /* we're going to modify the metadata */
4888 buf = gst_buffer_make_writable (buf);
4890 if (G_UNLIKELY (stream->need_process))
4891 buf = gst_qtdemux_process_buffer (qtdemux, stream, buf);
4897 GST_BUFFER_DTS (buf) = dts;
4898 GST_BUFFER_PTS (buf) = pts;
4899 GST_BUFFER_DURATION (buf) = duration;
4900 GST_BUFFER_OFFSET (buf) = -1;
4901 GST_BUFFER_OFFSET_END (buf) = -1;
4903 if (G_UNLIKELY (stream->rgb8_palette))
4904 gst_buffer_append_memory (buf, gst_memory_ref (stream->rgb8_palette));
4906 if (G_UNLIKELY (stream->padding)) {
4907 gst_buffer_resize (buf, stream->padding, -1);
4910 if (G_UNLIKELY (qtdemux->element_index)) {
4911 GstClockTime stream_time;
4914 gst_segment_to_stream_time (&stream->segment, GST_FORMAT_TIME,
4916 if (GST_CLOCK_TIME_IS_VALID (stream_time)) {
4917 GST_LOG_OBJECT (qtdemux,
4918 "adding association %" GST_TIME_FORMAT "-> %"
4919 G_GUINT64_FORMAT, GST_TIME_ARGS (stream_time), byte_position);
4920 gst_index_add_association (qtdemux->element_index,
4922 keyframe ? GST_ASSOCIATION_FLAG_KEY_UNIT :
4923 GST_ASSOCIATION_FLAG_DELTA_UNIT, GST_FORMAT_TIME, stream_time,
4924 GST_FORMAT_BYTES, byte_position, NULL);
4929 if (stream->need_clip)
4930 buf = gst_qtdemux_clip_buffer (qtdemux, stream, buf);
4932 if (G_UNLIKELY (buf == NULL))
4935 if (G_UNLIKELY (stream->discont)) {
4936 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
4937 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
4938 stream->discont = FALSE;
4940 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
4944 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
4945 stream->on_keyframe = FALSE;
4947 stream->on_keyframe = TRUE;
4951 GST_LOG_OBJECT (qtdemux,
4952 "Pushing buffer with dts %" GST_TIME_FORMAT ", pts %" GST_TIME_FORMAT
4953 ", duration %" GST_TIME_FORMAT " on pad %s", GST_TIME_ARGS (dts),
4954 GST_TIME_ARGS (pts), GST_TIME_ARGS (duration),
4955 GST_PAD_NAME (stream->pad));
4957 if (stream->protected && stream->protection_scheme_type == FOURCC_cenc) {
4958 GstStructure *crypto_info;
4959 QtDemuxCencSampleSetInfo *info =
4960 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
4964 while ((event = g_queue_pop_head (&stream->protection_scheme_event_queue))) {
4965 gst_pad_push_event (stream->pad, event);
4968 index = stream->sample_index - (stream->n_samples - info->crypto_info->len);
4969 if (G_LIKELY (index >= 0 && index < info->crypto_info->len)) {
4970 /* steal structure from array */
4971 crypto_info = g_ptr_array_index (info->crypto_info, index);
4972 g_ptr_array_index (info->crypto_info, index) = NULL;
4973 GST_LOG_OBJECT (qtdemux, "attaching cenc metadata [%u]", index);
4974 if (!crypto_info || !gst_buffer_add_protection_meta (buf, crypto_info))
4975 GST_ERROR_OBJECT (qtdemux, "failed to attach cenc metadata to buffer");
4979 ret = gst_pad_push (stream->pad, buf);
4981 if (GST_CLOCK_TIME_IS_VALID (pts) && GST_CLOCK_TIME_IS_VALID (duration)) {
4982 /* mark position in stream, we'll need this to know when to send GAP event */
4983 stream->segment.position = pts + duration;
4990 static const QtDemuxRandomAccessEntry *
4991 gst_qtdemux_stream_seek_fragment (GstQTDemux * qtdemux, QtDemuxStream * stream,
4992 GstClockTime pos, gboolean after)
4994 QtDemuxRandomAccessEntry *entries = stream->ra_entries;
4995 guint n_entries = stream->n_ra_entries;
4998 /* we assume the table is sorted */
4999 for (i = 0; i < n_entries; ++i) {
5000 if (entries[i].ts > pos)
5004 /* FIXME: maybe save first moof_offset somewhere instead, but for now it's
5005 * probably okay to assume that the index lists the very first fragment */
5012 return &entries[i - 1];
5016 gst_qtdemux_do_fragmented_seek (GstQTDemux * qtdemux)
5018 const QtDemuxRandomAccessEntry *best_entry = NULL;
5021 GST_OBJECT_LOCK (qtdemux);
5023 g_assert (qtdemux->n_streams > 0);
5025 for (i = 0; i < qtdemux->n_streams; i++) {
5026 const QtDemuxRandomAccessEntry *entry;
5027 QtDemuxStream *stream;
5028 gboolean is_audio_or_video;
5030 stream = qtdemux->streams[i];
5032 g_free (stream->samples);
5033 stream->samples = NULL;
5034 stream->n_samples = 0;
5035 stream->stbl_index = -1; /* no samples have yet been parsed */
5036 stream->sample_index = -1;
5038 if (stream->ra_entries == NULL)
5041 if (stream->subtype == FOURCC_vide || stream->subtype == FOURCC_soun)
5042 is_audio_or_video = TRUE;
5044 is_audio_or_video = FALSE;
5047 gst_qtdemux_stream_seek_fragment (qtdemux, stream,
5048 stream->time_position, !is_audio_or_video);
5050 GST_INFO_OBJECT (stream->pad, "%" GST_TIME_FORMAT " at offset "
5051 "%" G_GUINT64_FORMAT, GST_TIME_ARGS (entry->ts), entry->moof_offset);
5053 stream->pending_seek = entry;
5055 /* decide position to jump to just based on audio/video tracks, not subs */
5056 if (!is_audio_or_video)
5059 if (best_entry == NULL || entry->moof_offset < best_entry->moof_offset)
5063 if (best_entry == NULL) {
5064 GST_OBJECT_UNLOCK (qtdemux);
5068 GST_INFO_OBJECT (qtdemux, "seek to %" GST_TIME_FORMAT ", best fragment "
5069 "moof offset: %" G_GUINT64_FORMAT ", ts %" GST_TIME_FORMAT,
5070 GST_TIME_ARGS (qtdemux->streams[0]->time_position),
5071 best_entry->moof_offset, GST_TIME_ARGS (best_entry->ts));
5073 qtdemux->moof_offset = best_entry->moof_offset;
5075 qtdemux_add_fragmented_samples (qtdemux);
5077 GST_OBJECT_UNLOCK (qtdemux);
5081 static GstFlowReturn
5082 gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux)
5084 GstFlowReturn ret = GST_FLOW_OK;
5085 GstBuffer *buf = NULL;
5086 QtDemuxStream *stream;
5087 GstClockTime min_time;
5089 GstClockTime dts = GST_CLOCK_TIME_NONE;
5090 GstClockTime pts = GST_CLOCK_TIME_NONE;
5091 GstClockTime duration = 0;
5092 gboolean keyframe = FALSE;
5093 guint sample_size = 0;
5099 gst_qtdemux_push_pending_newsegment (qtdemux);
5101 if (qtdemux->fragmented_seek_pending) {
5102 GST_INFO_OBJECT (qtdemux, "pending fragmented seek");
5103 gst_qtdemux_do_fragmented_seek (qtdemux);
5104 GST_INFO_OBJECT (qtdemux, "fragmented seek done!");
5105 qtdemux->fragmented_seek_pending = FALSE;
5108 /* Figure out the next stream sample to output, min_time is expressed in
5109 * global time and runs over the edit list segments. */
5110 min_time = G_MAXUINT64;
5112 for (i = 0; i < qtdemux->n_streams; i++) {
5113 GstClockTime position;
5115 stream = qtdemux->streams[i];
5116 position = stream->time_position;
5118 /* position of -1 is EOS */
5119 if (position != GST_CLOCK_TIME_NONE && position < min_time) {
5120 min_time = position;
5125 if (G_UNLIKELY (index == -1)) {
5126 GST_DEBUG_OBJECT (qtdemux, "all streams are EOS");
5130 /* check for segment end */
5131 if (G_UNLIKELY (qtdemux->segment.stop != -1
5132 && ((qtdemux->segment.rate >= 0 && qtdemux->segment.stop <= min_time)
5133 || (qtdemux->segment.rate < 0
5134 && qtdemux->segment.start > min_time))
5135 && qtdemux->streams[index]->on_keyframe)) {
5136 GST_DEBUG_OBJECT (qtdemux, "we reached the end of our segment.");
5137 qtdemux->streams[index]->time_position = GST_CLOCK_TIME_NONE;
5141 /* gap events for subtitle streams */
5142 for (i = 0; i < qtdemux->n_streams; i++) {
5143 stream = qtdemux->streams[i];
5144 if (stream->pad && (stream->subtype == FOURCC_subp
5145 || stream->subtype == FOURCC_text
5146 || stream->subtype == FOURCC_sbtl)) {
5147 /* send one second gap events until the stream catches up */
5148 /* gaps can only be sent after segment is activated (segment.stop is no longer -1) */
5149 while (GST_CLOCK_TIME_IS_VALID (stream->segment.stop) &&
5150 GST_CLOCK_TIME_IS_VALID (stream->segment.position) &&
5151 stream->segment.position + GST_SECOND < min_time) {
5153 gst_event_new_gap (stream->segment.position, GST_SECOND);
5154 gst_pad_push_event (stream->pad, gap);
5155 stream->segment.position += GST_SECOND;
5160 stream = qtdemux->streams[index];
5161 if (stream->new_caps) {
5162 gst_qtdemux_configure_stream (qtdemux, stream);
5163 qtdemux_do_allocation (qtdemux, stream);
5166 /* fetch info for the current sample of this stream */
5167 if (G_UNLIKELY (!gst_qtdemux_prepare_current_sample (qtdemux, stream, &empty,
5168 &offset, &sample_size, &dts, &pts, &duration, &keyframe)))
5171 /* If we're doing a keyframe-only trickmode, only push keyframes on video streams */
5172 if (G_UNLIKELY (qtdemux->
5173 segment.flags & GST_SEGMENT_FLAG_TRICKMODE_KEY_UNITS)) {
5174 if (stream->subtype == FOURCC_vide && !keyframe) {
5175 GST_LOG_OBJECT (qtdemux, "Skipping non-keyframe on stream %d", index);
5180 GST_DEBUG_OBJECT (qtdemux,
5181 "pushing from stream %d, empty %d offset %" G_GUINT64_FORMAT
5182 ", size %d, dts=%" GST_TIME_FORMAT ", pts=%" GST_TIME_FORMAT
5183 ", duration %" GST_TIME_FORMAT, index, empty, offset, sample_size,
5184 GST_TIME_ARGS (dts), GST_TIME_ARGS (pts), GST_TIME_ARGS (duration));
5186 if (G_UNLIKELY (empty)) {
5187 /* empty segment, push a gap and move to the next one */
5188 gst_pad_push_event (stream->pad, gst_event_new_gap (pts, duration));
5189 stream->segment.position = pts + duration;
5193 /* hmm, empty sample, skip and move to next sample */
5194 if (G_UNLIKELY (sample_size <= 0))
5197 /* last pushed sample was out of boundary, goto next sample */
5198 if (G_UNLIKELY (GST_PAD_LAST_FLOW_RETURN (stream->pad) == GST_FLOW_EOS))
5201 if (stream->max_buffer_size == 0 || sample_size <= stream->max_buffer_size) {
5204 GST_DEBUG_OBJECT (qtdemux,
5205 "size %d larger than stream max_buffer_size %d, trimming",
5206 sample_size, stream->max_buffer_size);
5208 MIN (sample_size - stream->offset_in_sample, stream->max_buffer_size);
5211 GST_LOG_OBJECT (qtdemux, "reading %d bytes @ %" G_GUINT64_FORMAT, size,
5214 if (stream->use_allocator) {
5215 /* if we have a per-stream allocator, use it */
5216 buf = gst_buffer_new_allocate (stream->allocator, size, &stream->params);
5219 ret = gst_qtdemux_pull_atom (qtdemux, offset + stream->offset_in_sample,
5221 if (G_UNLIKELY (ret != GST_FLOW_OK))
5224 if (size != sample_size) {
5225 pts += gst_util_uint64_scale_int (GST_SECOND,
5226 stream->offset_in_sample / stream->bytes_per_frame, stream->timescale);
5227 dts += gst_util_uint64_scale_int (GST_SECOND,
5228 stream->offset_in_sample / stream->bytes_per_frame, stream->timescale);
5229 duration = gst_util_uint64_scale_int (GST_SECOND,
5230 size / stream->bytes_per_frame, stream->timescale);
5233 ret = gst_qtdemux_decorate_and_push_buffer (qtdemux, stream, buf,
5234 dts, pts, duration, keyframe, min_time, offset);
5236 if (size != sample_size) {
5237 QtDemuxSample *sample = &stream->samples[stream->sample_index];
5238 QtDemuxSegment *segment = &stream->segments[stream->segment_index];
5240 GstClockTime time_position = QTSTREAMTIME_TO_GSTTIME (stream,
5241 sample->timestamp + stream->offset_in_sample / stream->bytes_per_frame);
5242 if (time_position >= segment->media_start) {
5243 /* inside the segment, update time_position, looks very familiar to
5244 * GStreamer segments, doesn't it? */
5245 stream->time_position = (time_position - segment->media_start) +
5248 /* not yet in segment, time does not yet increment. This means
5249 * that we are still prerolling keyframes to the decoder so it can
5250 * decode the first sample of the segment. */
5251 stream->time_position = segment->time;
5256 ret = gst_qtdemux_combine_flows (qtdemux, stream, ret);
5257 /* ignore unlinked, we will not push on the pad anymore and we will EOS when
5258 * we have no more data for the pad to push */
5259 if (ret == GST_FLOW_EOS)
5262 stream->offset_in_sample += size;
5263 if (stream->offset_in_sample >= sample_size) {
5264 gst_qtdemux_advance_sample (qtdemux, stream);
5269 gst_qtdemux_advance_sample (qtdemux, stream);
5277 GST_DEBUG_OBJECT (qtdemux, "No samples left for any streams - EOS");
5283 GST_DEBUG_OBJECT (qtdemux, "No samples left for stream");
5284 /* EOS will be raised if all are EOS */
5291 gst_qtdemux_loop (GstPad * pad)
5293 GstQTDemux *qtdemux;
5297 qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
5299 cur_offset = qtdemux->offset;
5300 GST_LOG_OBJECT (qtdemux, "loop at position %" G_GUINT64_FORMAT ", state %d",
5301 cur_offset, qtdemux->state);
5303 switch (qtdemux->state) {
5304 case QTDEMUX_STATE_INITIAL:
5305 case QTDEMUX_STATE_HEADER:
5306 ret = gst_qtdemux_loop_state_header (qtdemux);
5308 case QTDEMUX_STATE_MOVIE:
5309 ret = gst_qtdemux_loop_state_movie (qtdemux);
5310 if (qtdemux->segment.rate < 0 && ret == GST_FLOW_EOS) {
5311 ret = gst_qtdemux_seek_to_previous_keyframe (qtdemux);
5319 /* if something went wrong, pause */
5320 if (ret != GST_FLOW_OK)
5324 gst_object_unref (qtdemux);
5330 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
5331 (NULL), ("streaming stopped, invalid state"));
5332 gst_pad_pause_task (pad);
5333 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
5338 const gchar *reason = gst_flow_get_name (ret);
5340 GST_LOG_OBJECT (qtdemux, "pausing task, reason %s", reason);
5342 gst_pad_pause_task (pad);
5344 /* fatal errors need special actions */
5346 if (ret == GST_FLOW_EOS) {
5347 if (qtdemux->n_streams == 0) {
5348 /* we have no streams, post an error */
5349 gst_qtdemux_post_no_playable_stream_error (qtdemux);
5351 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
5354 if ((stop = qtdemux->segment.stop) == -1)
5355 stop = qtdemux->segment.duration;
5357 if (qtdemux->segment.rate >= 0) {
5358 GST_LOG_OBJECT (qtdemux, "Sending segment done, at end of segment");
5359 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
5360 gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
5361 GST_FORMAT_TIME, stop));
5362 gst_qtdemux_push_event (qtdemux,
5363 gst_event_new_segment_done (GST_FORMAT_TIME, stop));
5365 /* For Reverse Playback */
5366 GST_LOG_OBJECT (qtdemux, "Sending segment done, at start of segment");
5367 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
5368 gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
5369 GST_FORMAT_TIME, qtdemux->segment.start));
5370 gst_qtdemux_push_event (qtdemux,
5371 gst_event_new_segment_done (GST_FORMAT_TIME,
5372 qtdemux->segment.start));
5375 GST_LOG_OBJECT (qtdemux, "Sending EOS at end of segment");
5376 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
5378 } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
5379 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
5380 (NULL), ("streaming stopped, reason %s", reason));
5381 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
5390 * Returns if there are samples to be played.
5393 has_next_entry (GstQTDemux * demux)
5395 QtDemuxStream *stream;
5398 GST_DEBUG_OBJECT (demux, "Checking if there are samples not played yet");
5400 for (i = 0; i < demux->n_streams; i++) {
5401 stream = demux->streams[i];
5403 if (stream->sample_index == -1) {
5404 stream->sample_index = 0;
5405 stream->offset_in_sample = 0;
5408 if (stream->sample_index >= stream->n_samples) {
5409 GST_LOG_OBJECT (demux, "stream %d samples exhausted", i);
5412 GST_DEBUG_OBJECT (demux, "Found a sample");
5416 GST_DEBUG_OBJECT (demux, "There wasn't any next sample");
5423 * Returns the size of the first entry at the current offset.
5424 * If -1, there are none (which means EOS or empty file).
5427 next_entry_size (GstQTDemux * demux)
5429 QtDemuxStream *stream;
5432 guint64 smalloffs = (guint64) - 1;
5433 QtDemuxSample *sample;
5435 GST_LOG_OBJECT (demux, "Finding entry at offset %" G_GUINT64_FORMAT,
5438 for (i = 0; i < demux->n_streams; i++) {
5439 stream = demux->streams[i];
5441 if (stream->sample_index == -1) {
5442 stream->sample_index = 0;
5443 stream->offset_in_sample = 0;
5446 if (stream->sample_index >= stream->n_samples) {
5447 GST_LOG_OBJECT (demux, "stream %d samples exhausted", i);
5451 if (!qtdemux_parse_samples (demux, stream, stream->sample_index)) {
5452 GST_LOG_OBJECT (demux, "Parsing of index %u from stbl atom failed!",
5453 stream->sample_index);
5457 sample = &stream->samples[stream->sample_index];
5459 GST_LOG_OBJECT (demux,
5460 "Checking Stream %d (sample_index:%d / offset:%" G_GUINT64_FORMAT
5461 " / size:%" G_GUINT32_FORMAT ")", i, stream->sample_index,
5462 sample->offset, sample->size);
5464 if (((smalloffs == -1)
5465 || (sample->offset < smalloffs)) && (sample->size)) {
5467 smalloffs = sample->offset;
5471 GST_LOG_OBJECT (demux,
5472 "stream %d offset %" G_GUINT64_FORMAT " demux->offset :%"
5473 G_GUINT64_FORMAT, smallidx, smalloffs, demux->offset);
5478 stream = demux->streams[smallidx];
5479 sample = &stream->samples[stream->sample_index];
5481 if (sample->offset >= demux->offset) {
5482 demux->todrop = sample->offset - demux->offset;
5483 return sample->size + demux->todrop;
5486 GST_DEBUG_OBJECT (demux,
5487 "There wasn't any entry at offset %" G_GUINT64_FORMAT, demux->offset);
5492 gst_qtdemux_post_progress (GstQTDemux * demux, gint num, gint denom)
5494 gint perc = (gint) ((gdouble) num * 100.0 / (gdouble) denom);
5496 gst_element_post_message (GST_ELEMENT_CAST (demux),
5497 gst_message_new_element (GST_OBJECT_CAST (demux),
5498 gst_structure_new ("progress", "percent", G_TYPE_INT, perc, NULL)));
5502 qtdemux_seek_offset (GstQTDemux * demux, guint64 offset)
5507 GST_DEBUG_OBJECT (demux, "Seeking to %" G_GUINT64_FORMAT, offset);
5510 gst_event_new_seek (1.0, GST_FORMAT_BYTES,
5511 GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset,
5512 GST_SEEK_TYPE_NONE, -1);
5514 /* store seqnum to drop flush events, they don't need to reach downstream */
5515 demux->offset_seek_seqnum = gst_event_get_seqnum (event);
5516 res = gst_pad_push_event (demux->sinkpad, event);
5517 demux->offset_seek_seqnum = 0;
5522 /* check for seekable upstream, above and beyond a mere query */
5524 gst_qtdemux_check_seekability (GstQTDemux * demux)
5527 gboolean seekable = FALSE;
5528 gint64 start = -1, stop = -1;
5530 if (demux->upstream_size)
5533 query = gst_query_new_seeking (GST_FORMAT_BYTES);
5534 if (!gst_pad_peer_query (demux->sinkpad, query)) {
5535 GST_DEBUG_OBJECT (demux, "seeking query failed");
5539 gst_query_parse_seeking (query, NULL, &seekable, &start, &stop);
5541 /* try harder to query upstream size if we didn't get it the first time */
5542 if (seekable && stop == -1) {
5543 GST_DEBUG_OBJECT (demux, "doing duration query to fix up unset stop");
5544 gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &stop);
5547 /* if upstream doesn't know the size, it's likely that it's not seekable in
5548 * practice even if it technically may be seekable */
5549 if (seekable && (start != 0 || stop <= start)) {
5550 GST_DEBUG_OBJECT (demux, "seekable but unknown start/stop -> disable");
5555 gst_query_unref (query);
5557 GST_DEBUG_OBJECT (demux, "seekable: %d (%" G_GUINT64_FORMAT " - %"
5558 G_GUINT64_FORMAT ")", seekable, start, stop);
5559 demux->upstream_seekable = seekable;
5560 demux->upstream_size = seekable ? stop : -1;
5564 gst_qtdemux_drop_data (GstQTDemux * demux, gint bytes)
5566 g_return_if_fail (bytes <= demux->todrop);
5568 GST_LOG_OBJECT (demux, "Dropping %d bytes", bytes);
5569 gst_adapter_flush (demux->adapter, bytes);
5570 demux->neededbytes -= bytes;
5571 demux->offset += bytes;
5572 demux->todrop -= bytes;
5576 gst_qtdemux_check_send_pending_segment (GstQTDemux * demux)
5578 if (G_UNLIKELY (demux->pending_newsegment)) {
5581 gst_qtdemux_push_pending_newsegment (demux);
5582 /* clear to send tags on all streams */
5583 for (i = 0; i < demux->n_streams; i++) {
5584 QtDemuxStream *stream;
5585 stream = demux->streams[i];
5586 gst_qtdemux_push_tags (demux, stream);
5587 if (stream->sparse) {
5588 GST_INFO_OBJECT (demux, "Sending gap event on stream %d", i);
5589 gst_pad_push_event (stream->pad,
5590 gst_event_new_gap (stream->segment.position, GST_CLOCK_TIME_NONE));
5597 gst_qtdemux_stream_send_initial_gap_segments (GstQTDemux * demux,
5598 QtDemuxStream * stream)
5602 /* Push any initial gap segments before proceeding to the
5604 for (i = 0; i < stream->n_segments; i++) {
5605 gst_qtdemux_activate_segment (demux, stream, i, stream->time_position);
5607 if (QTSEGMENT_IS_EMPTY (&stream->segments[i])) {
5608 GstClockTime ts, dur;
5611 ts = stream->time_position;
5613 stream->segments[i].duration - (stream->time_position -
5614 stream->segments[i].time);
5615 gap = gst_event_new_gap (ts, dur);
5616 stream->time_position += dur;
5618 GST_DEBUG_OBJECT (stream->pad, "Pushing gap for empty "
5619 "segment: %" GST_PTR_FORMAT, gap);
5620 gst_pad_push_event (stream->pad, gap);
5622 /* Only support empty segment at the beginning followed by
5623 * one non-empty segment, this was checked when parsing the
5624 * edts atom, arriving here is unexpected */
5625 g_assert (i + 1 == stream->n_segments);
5631 static GstFlowReturn
5632 gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent, GstBuffer * inbuf)
5636 demux = GST_QTDEMUX (parent);
5638 if (GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_DISCONT)) {
5641 GST_DEBUG_OBJECT (demux, "Got DISCONT, marking all streams as DISCONT");
5643 for (i = 0; i < demux->n_streams; i++) {
5644 demux->streams[i]->discont = TRUE;
5647 /* Reverse fragmented playback, need to flush all we have before
5648 * consuming a new fragment.
5649 * The samples array have the timestamps calculated by accumulating the
5650 * durations but this won't work for reverse playback of fragments as
5651 * the timestamps of a subsequent fragment should be smaller than the
5652 * previously received one. */
5653 if (demux->fragmented && demux->segment.rate < 0) {
5654 gst_qtdemux_process_adapter (demux, TRUE);
5655 for (i = 0; i < demux->n_streams; i++)
5656 gst_qtdemux_stream_flush_samples_data (demux, demux->streams[i]);
5660 gst_adapter_push (demux->adapter, inbuf);
5662 GST_DEBUG_OBJECT (demux,
5663 "pushing in inbuf %p, neededbytes:%u, available:%" G_GSIZE_FORMAT, inbuf,
5664 demux->neededbytes, gst_adapter_available (demux->adapter));
5666 return gst_qtdemux_process_adapter (demux, FALSE);
5669 static GstFlowReturn
5670 gst_qtdemux_process_adapter (GstQTDemux * demux, gboolean force)
5672 GstFlowReturn ret = GST_FLOW_OK;
5674 /* we never really mean to buffer that much */
5675 if (demux->neededbytes == -1) {
5679 while (((gst_adapter_available (demux->adapter)) >= demux->neededbytes) &&
5680 (ret == GST_FLOW_OK || (ret == GST_FLOW_NOT_LINKED && force))) {
5682 GST_DEBUG_OBJECT (demux,
5683 "state:%d , demux->neededbytes:%d, demux->offset:%" G_GUINT64_FORMAT,
5684 demux->state, demux->neededbytes, demux->offset);
5686 switch (demux->state) {
5687 case QTDEMUX_STATE_INITIAL:{
5692 gst_qtdemux_check_seekability (demux);
5694 data = gst_adapter_map (demux->adapter, demux->neededbytes);
5696 /* get fourcc/length, set neededbytes */
5697 extract_initial_length_and_fourcc ((guint8 *) data, demux->neededbytes,
5699 gst_adapter_unmap (demux->adapter);
5701 GST_DEBUG_OBJECT (demux, "Peeking found [%" GST_FOURCC_FORMAT "] "
5702 "size: %" G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), size);
5704 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
5705 (_("This file is invalid and cannot be played.")),
5706 ("initial atom '%" GST_FOURCC_FORMAT "' has empty length",
5707 GST_FOURCC_ARGS (fourcc)));
5708 ret = GST_FLOW_ERROR;
5711 if (fourcc == FOURCC_mdat) {
5712 gint next_entry = next_entry_size (demux);
5713 if (demux->n_streams > 0 && (next_entry != -1 || !demux->fragmented)) {
5714 /* we have the headers, start playback */
5715 demux->state = QTDEMUX_STATE_MOVIE;
5716 demux->neededbytes = next_entry;
5717 demux->mdatleft = size;
5719 /* no headers yet, try to get them */
5722 guint64 old, target;
5725 old = demux->offset;
5726 target = old + size;
5728 /* try to jump over the atom with a seek */
5729 /* only bother if it seems worth doing so,
5730 * and avoids possible upstream/server problems */
5731 if (demux->upstream_seekable &&
5732 demux->upstream_size > 4 * (1 << 20)) {
5733 res = qtdemux_seek_offset (demux, target);
5735 GST_DEBUG_OBJECT (demux, "skipping seek");
5740 GST_DEBUG_OBJECT (demux, "seek success");
5741 /* remember the offset fo the first mdat so we can seek back to it
5742 * after we have the headers */
5743 if (fourcc == FOURCC_mdat && demux->first_mdat == -1) {
5744 demux->first_mdat = old;
5745 GST_DEBUG_OBJECT (demux, "first mdat at %" G_GUINT64_FORMAT,
5748 /* seek worked, continue reading */
5749 demux->offset = target;
5750 demux->neededbytes = 16;
5751 demux->state = QTDEMUX_STATE_INITIAL;
5753 /* seek failed, need to buffer */
5754 demux->offset = old;
5755 GST_DEBUG_OBJECT (demux, "seek failed/skipped");
5756 /* there may be multiple mdat (or alike) buffers */
5758 if (demux->mdatbuffer)
5759 bs = gst_buffer_get_size (demux->mdatbuffer);
5762 if (size + bs > 10 * (1 << 20))
5764 demux->state = QTDEMUX_STATE_BUFFER_MDAT;
5765 demux->neededbytes = size;
5766 if (!demux->mdatbuffer)
5767 demux->mdatoffset = demux->offset;
5770 } else if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
5771 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
5772 (_("This file is invalid and cannot be played.")),
5773 ("atom %" GST_FOURCC_FORMAT " has bogus size %" G_GUINT64_FORMAT,
5774 GST_FOURCC_ARGS (fourcc), size));
5775 ret = GST_FLOW_ERROR;
5778 /* this means we already started buffering and still no moov header,
5779 * let's continue buffering everything till we get moov */
5780 if (demux->mdatbuffer && !(fourcc == FOURCC_moov
5781 || fourcc == FOURCC_moof))
5783 demux->neededbytes = size;
5784 demux->state = QTDEMUX_STATE_HEADER;
5788 case QTDEMUX_STATE_HEADER:{
5792 GST_DEBUG_OBJECT (demux, "In header");
5794 data = gst_adapter_map (demux->adapter, demux->neededbytes);
5796 /* parse the header */
5797 extract_initial_length_and_fourcc (data, demux->neededbytes, NULL,
5799 if (fourcc == FOURCC_moov) {
5801 gboolean got_samples = FALSE;
5803 /* in usual fragmented setup we could try to scan for more
5804 * and end up at the the moov (after mdat) again */
5805 if (demux->got_moov && demux->n_streams > 0 &&
5807 || demux->last_moov_offset == demux->offset)) {
5808 GST_DEBUG_OBJECT (demux,
5809 "Skipping moov atom as we have (this) one already");
5811 GST_DEBUG_OBJECT (demux, "Parsing [moov]");
5813 if (demux->got_moov && demux->fragmented) {
5814 GST_DEBUG_OBJECT (demux,
5815 "Got a second moov, clean up data from old one");
5816 if (demux->moov_node)
5817 g_node_destroy (demux->moov_node);
5818 demux->moov_node = NULL;
5819 demux->moov_node_compressed = NULL;
5821 /* prepare newsegment to send when streaming actually starts */
5822 if (!demux->pending_newsegment)
5823 demux->pending_newsegment =
5824 gst_event_new_segment (&demux->segment);
5827 demux->last_moov_offset = demux->offset;
5829 qtdemux_parse_moov (demux, data, demux->neededbytes);
5830 qtdemux_node_dump (demux, demux->moov_node);
5831 qtdemux_parse_tree (demux);
5832 qtdemux_prepare_streams (demux);
5834 for (n = 0; n < demux->n_streams; n++) {
5835 QtDemuxStream *stream = demux->streams[n];
5836 got_samples |= stream->stbl_index >= 0;
5838 if (!demux->fragmented || got_samples) {
5839 if (!demux->got_moov) {
5840 qtdemux_expose_streams (demux);
5842 for (n = 0; n < demux->n_streams; n++) {
5843 QtDemuxStream *stream = demux->streams[n];
5844 gst_qtdemux_configure_stream (demux, stream);
5847 gst_qtdemux_check_send_pending_segment (demux);
5848 demux->pending_configure = FALSE;
5850 demux->pending_configure = TRUE;
5853 demux->got_moov = TRUE;
5855 /* fragmented streams headers shouldn't contain edts atoms */
5856 if (!demux->fragmented) {
5857 for (n = 0; n < demux->n_streams; n++) {
5858 gst_qtdemux_stream_send_initial_gap_segments (demux,
5863 g_node_destroy (demux->moov_node);
5864 demux->moov_node = NULL;
5865 GST_DEBUG_OBJECT (demux, "Finished parsing the header");
5867 } else if (fourcc == FOURCC_moof) {
5868 if ((demux->got_moov || demux->media_caps) && demux->fragmented) {
5870 GstClockTime prev_pts;
5871 guint64 prev_offset;
5874 GST_DEBUG_OBJECT (demux, "Parsing [moof]");
5877 * The timestamp of the moof buffer is relevant as some scenarios
5878 * won't have the initial timestamp in the atoms. Whenever a new
5879 * buffer has started, we get that buffer's PTS and use it as a base
5880 * timestamp for the trun entries.
5882 * To keep track of the current buffer timestamp and starting point
5883 * we use gst_adapter_prev_pts that gives us the PTS and the distance
5884 * from the beggining of the buffer, with the distance and demux->offset
5885 * we know if it is still the same buffer or not.
5887 prev_pts = gst_adapter_prev_pts (demux->adapter, &dist);
5888 prev_offset = demux->offset - dist;
5889 if (demux->fragment_start_offset == -1
5890 || prev_offset > demux->fragment_start_offset) {
5891 demux->fragment_start_offset = prev_offset;
5892 demux->fragment_start = prev_pts;
5893 GST_DEBUG_OBJECT (demux,
5894 "New fragment start found at: %" G_GUINT64_FORMAT " : %"
5895 GST_TIME_FORMAT, demux->fragment_start_offset,
5896 GST_TIME_ARGS (demux->fragment_start));
5899 demux->moof_offset = demux->offset;
5900 if (!qtdemux_parse_moof (demux, data, demux->neededbytes,
5901 demux->offset, NULL)) {
5902 gst_adapter_unmap (demux->adapter);
5903 ret = GST_FLOW_ERROR;
5906 /* in MSS we need to expose the pads after the first moof as we won't get a moov
5907 * Also, fragmented format need to be exposed if a moov have no valid sample data */
5908 if (demux->mss_mode || demux->pending_configure) {
5909 if (!demux->exposed) {
5910 if (!demux->pending_newsegment) {
5912 gst_segment_init (&segment, GST_FORMAT_TIME);
5913 GST_DEBUG_OBJECT (demux, "new pending_newsegment");
5914 demux->pending_newsegment = gst_event_new_segment (&segment);
5916 qtdemux_expose_streams (demux);
5918 for (n = 0; n < demux->n_streams; n++) {
5919 QtDemuxStream *stream = demux->streams[n];
5920 gst_qtdemux_configure_stream (demux, stream);
5923 gst_qtdemux_check_send_pending_segment (demux);
5924 demux->pending_configure = FALSE;
5927 GST_DEBUG_OBJECT (demux, "Discarding [moof]");
5929 } else if (fourcc == FOURCC_ftyp) {
5930 GST_DEBUG_OBJECT (demux, "Parsing [ftyp]");
5931 qtdemux_parse_ftyp (demux, data, demux->neededbytes);
5932 } else if (fourcc == FOURCC_uuid) {
5933 GST_DEBUG_OBJECT (demux, "Parsing [uuid]");
5934 qtdemux_parse_uuid (demux, data, demux->neededbytes);
5935 } else if (fourcc == FOURCC_sidx) {
5936 GST_DEBUG_OBJECT (demux, "Parsing [sidx]");
5937 qtdemux_parse_sidx (demux, data, demux->neededbytes);
5939 GST_WARNING_OBJECT (demux,
5940 "Unknown fourcc while parsing header : %" GST_FOURCC_FORMAT,
5941 GST_FOURCC_ARGS (fourcc));
5942 /* Let's jump that one and go back to initial state */
5944 gst_adapter_unmap (demux->adapter);
5947 if (demux->mdatbuffer && demux->n_streams) {
5948 gsize remaining_data_size = 0;
5950 /* the mdat was before the header */
5951 GST_DEBUG_OBJECT (demux, "We have n_streams:%d and mdatbuffer:%p",
5952 demux->n_streams, demux->mdatbuffer);
5953 /* restore our adapter/offset view of things with upstream;
5954 * put preceding buffered data ahead of current moov data.
5955 * This should also handle evil mdat, moov, mdat cases and alike */
5956 gst_adapter_flush (demux->adapter, demux->neededbytes);
5958 /* Store any remaining data after the mdat for later usage */
5959 remaining_data_size = gst_adapter_available (demux->adapter);
5960 if (remaining_data_size > 0) {
5961 g_assert (demux->restoredata_buffer == NULL);
5962 demux->restoredata_buffer =
5963 gst_adapter_take_buffer (demux->adapter, remaining_data_size);
5964 demux->restoredata_offset = demux->offset + demux->neededbytes;
5965 GST_DEBUG_OBJECT (demux,
5966 "Stored %" G_GSIZE_FORMAT " post mdat bytes at offset %"
5967 G_GUINT64_FORMAT, remaining_data_size,
5968 demux->restoredata_offset);
5971 gst_adapter_push (demux->adapter, demux->mdatbuffer);
5972 demux->mdatbuffer = NULL;
5973 demux->offset = demux->mdatoffset;
5974 demux->neededbytes = next_entry_size (demux);
5975 demux->state = QTDEMUX_STATE_MOVIE;
5976 demux->mdatleft = gst_adapter_available (demux->adapter);
5978 GST_DEBUG_OBJECT (demux, "Carrying on normally");
5979 gst_adapter_flush (demux->adapter, demux->neededbytes);
5981 /* only go back to the mdat if there are samples to play */
5982 if (demux->got_moov && demux->first_mdat != -1
5983 && has_next_entry (demux)) {
5986 /* we need to seek back */
5987 res = qtdemux_seek_offset (demux, demux->first_mdat);
5989 demux->offset = demux->first_mdat;
5991 GST_DEBUG_OBJECT (demux, "Seek back failed");
5994 demux->offset += demux->neededbytes;
5996 demux->neededbytes = 16;
5997 demux->state = QTDEMUX_STATE_INITIAL;
6002 case QTDEMUX_STATE_BUFFER_MDAT:{
6006 GST_DEBUG_OBJECT (demux, "Got our buffer at offset %" G_GUINT64_FORMAT,
6008 buf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
6009 gst_buffer_extract (buf, 0, fourcc, 4);
6010 GST_DEBUG_OBJECT (demux, "mdatbuffer starts with %" GST_FOURCC_FORMAT,
6011 GST_FOURCC_ARGS (QT_FOURCC (fourcc)));
6012 if (demux->mdatbuffer)
6013 demux->mdatbuffer = gst_buffer_append (demux->mdatbuffer, buf);
6015 demux->mdatbuffer = buf;
6016 demux->offset += demux->neededbytes;
6017 demux->neededbytes = 16;
6018 demux->state = QTDEMUX_STATE_INITIAL;
6019 gst_qtdemux_post_progress (demux, 1, 1);
6023 case QTDEMUX_STATE_MOVIE:{
6024 QtDemuxStream *stream = NULL;
6025 QtDemuxSample *sample;
6027 GstClockTime dts, pts, duration;
6030 GST_DEBUG_OBJECT (demux,
6031 "BEGIN // in MOVIE for offset %" G_GUINT64_FORMAT, demux->offset);
6033 if (demux->fragmented) {
6034 GST_DEBUG_OBJECT (demux, "mdat remaining %" G_GUINT64_FORMAT,
6036 if (G_LIKELY (demux->todrop < demux->mdatleft)) {
6037 /* if needed data starts within this atom,
6038 * then it should not exceed this atom */
6039 if (G_UNLIKELY (demux->neededbytes > demux->mdatleft)) {
6040 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
6041 (_("This file is invalid and cannot be played.")),
6042 ("sample data crosses atom boundary"));
6043 ret = GST_FLOW_ERROR;
6046 demux->mdatleft -= demux->neededbytes;
6048 GST_DEBUG_OBJECT (demux, "data atom emptied; resuming atom scan");
6049 /* so we are dropping more than left in this atom */
6050 gst_qtdemux_drop_data (demux, demux->mdatleft);
6051 demux->mdatleft = 0;
6053 /* need to resume atom parsing so we do not miss any other pieces */
6054 demux->state = QTDEMUX_STATE_INITIAL;
6055 demux->neededbytes = 16;
6057 /* check if there was any stored post mdat data from previous buffers */
6058 if (demux->restoredata_buffer) {
6059 g_assert (gst_adapter_available (demux->adapter) == 0);
6061 gst_adapter_push (demux->adapter, demux->restoredata_buffer);
6062 demux->restoredata_buffer = NULL;
6063 demux->offset = demux->restoredata_offset;
6070 if (demux->todrop) {
6071 if (demux->cenc_aux_info_offset > 0) {
6075 GST_DEBUG_OBJECT (demux, "parsing cenc auxiliary info");
6076 data = gst_adapter_map (demux->adapter, demux->todrop);
6077 gst_byte_reader_init (&br, data + 8, demux->todrop);
6078 if (!qtdemux_parse_cenc_aux_info (demux, demux->streams[0], &br,
6079 demux->cenc_aux_info_sizes, demux->cenc_aux_sample_count)) {
6080 GST_ERROR_OBJECT (demux, "failed to parse cenc auxiliary info");
6081 ret = GST_FLOW_ERROR;
6082 gst_adapter_unmap (demux->adapter);
6083 g_free (demux->cenc_aux_info_sizes);
6084 demux->cenc_aux_info_sizes = NULL;
6087 demux->cenc_aux_info_offset = 0;
6088 g_free (demux->cenc_aux_info_sizes);
6089 demux->cenc_aux_info_sizes = NULL;
6090 gst_adapter_unmap (demux->adapter);
6092 gst_qtdemux_drop_data (demux, demux->todrop);
6096 /* initial newsegment sent here after having added pads,
6097 * possible others in sink_event */
6098 gst_qtdemux_check_send_pending_segment (demux);
6100 /* Figure out which stream this packet belongs to */
6101 for (i = 0; i < demux->n_streams; i++) {
6102 stream = demux->streams[i];
6103 if (stream->sample_index >= stream->n_samples)
6105 GST_LOG_OBJECT (demux,
6106 "Checking stream %d (sample_index:%d / offset:%" G_GUINT64_FORMAT
6107 " / size:%d)", i, stream->sample_index,
6108 stream->samples[stream->sample_index].offset,
6109 stream->samples[stream->sample_index].size);
6111 if (stream->samples[stream->sample_index].offset == demux->offset)
6115 if (G_UNLIKELY (stream == NULL || i == demux->n_streams))
6116 goto unknown_stream;
6118 if (stream->new_caps) {
6119 gst_qtdemux_configure_stream (demux, stream);
6122 /* Put data in a buffer, set timestamps, caps, ... */
6123 sample = &stream->samples[stream->sample_index];
6125 if (G_LIKELY (!(STREAM_IS_EOS (stream)))) {
6126 GST_DEBUG_OBJECT (demux, "stream : %" GST_FOURCC_FORMAT,
6127 GST_FOURCC_ARGS (stream->fourcc));
6129 dts = QTSAMPLE_DTS (stream, sample);
6130 pts = QTSAMPLE_PTS (stream, sample);
6131 duration = QTSAMPLE_DUR_DTS (stream, sample, dts);
6132 keyframe = QTSAMPLE_KEYFRAME (stream, sample);
6134 /* check for segment end */
6135 if (G_UNLIKELY (demux->segment.stop != -1
6136 && demux->segment.stop <= pts && stream->on_keyframe)) {
6137 GST_DEBUG_OBJECT (demux, "we reached the end of our segment.");
6138 stream->time_position = GST_CLOCK_TIME_NONE; /* this means EOS */
6140 /* skip this data, stream is EOS */
6141 gst_adapter_flush (demux->adapter, demux->neededbytes);
6143 /* check if all streams are eos */
6145 for (i = 0; i < demux->n_streams; i++) {
6146 if (!STREAM_IS_EOS (demux->streams[i])) {
6152 if (ret == GST_FLOW_EOS) {
6153 GST_DEBUG_OBJECT (demux, "All streams are EOS, signal upstream");
6160 gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
6162 /* FIXME: should either be an assert or a plain check */
6163 g_return_val_if_fail (outbuf != NULL, GST_FLOW_ERROR);
6165 ret = gst_qtdemux_decorate_and_push_buffer (demux, stream, outbuf,
6166 dts, pts, duration, keyframe, dts, demux->offset);
6170 ret = gst_qtdemux_combine_flows (demux, stream, ret);
6171 if (ret != GST_FLOW_OK && ret != GST_FLOW_NOT_LINKED)
6172 goto non_ok_unlinked_flow;
6174 /* skip this data, stream is EOS */
6175 gst_adapter_flush (demux->adapter, demux->neededbytes);
6178 stream->sample_index++;
6179 stream->offset_in_sample = 0;
6181 /* update current offset and figure out size of next buffer */
6182 GST_LOG_OBJECT (demux, "increasing offset %" G_GUINT64_FORMAT " by %u",
6183 demux->offset, demux->neededbytes);
6184 demux->offset += demux->neededbytes;
6185 GST_LOG_OBJECT (demux, "offset is now %" G_GUINT64_FORMAT,
6188 if ((demux->neededbytes = next_entry_size (demux)) == -1) {
6189 if (demux->fragmented) {
6190 GST_DEBUG_OBJECT (demux, "(temporarily) out of fragmented samples");
6191 /* there may be more to follow, only finish this atom */
6192 demux->todrop = demux->mdatleft;
6193 demux->neededbytes = demux->todrop;
6205 /* when buffering movie data, at least show user something is happening */
6206 if (ret == GST_FLOW_OK && demux->state == QTDEMUX_STATE_BUFFER_MDAT &&
6207 gst_adapter_available (demux->adapter) <= demux->neededbytes) {
6208 gst_qtdemux_post_progress (demux, gst_adapter_available (demux->adapter),
6209 demux->neededbytes);
6216 non_ok_unlinked_flow:
6218 GST_DEBUG_OBJECT (demux, "Stopping, combined return flow %s",
6219 gst_flow_get_name (ret));
6224 GST_ELEMENT_ERROR (demux, STREAM, FAILED, (NULL), ("unknown stream found"));
6225 ret = GST_FLOW_ERROR;
6230 GST_DEBUG_OBJECT (demux, "no next entry, EOS");
6236 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
6237 (NULL), ("qtdemuxer invalid state %d", demux->state));
6238 ret = GST_FLOW_ERROR;
6243 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
6244 (NULL), ("no 'moov' atom within the first 10 MB"));
6245 ret = GST_FLOW_ERROR;
6251 qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent)
6256 query = gst_query_new_scheduling ();
6258 if (!gst_pad_peer_query (sinkpad, query)) {
6259 gst_query_unref (query);
6263 pull_mode = gst_query_has_scheduling_mode_with_flags (query,
6264 GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
6265 gst_query_unref (query);
6270 GST_DEBUG_OBJECT (sinkpad, "activating pull");
6271 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
6275 GST_DEBUG_OBJECT (sinkpad, "activating push");
6276 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
6281 qtdemux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
6282 GstPadMode mode, gboolean active)
6285 GstQTDemux *demux = GST_QTDEMUX (parent);
6288 case GST_PAD_MODE_PUSH:
6289 demux->pullbased = FALSE;
6292 case GST_PAD_MODE_PULL:
6294 demux->pullbased = TRUE;
6295 res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_qtdemux_loop,
6298 res = gst_pad_stop_task (sinkpad);
6310 qtdemux_zalloc (void *opaque, unsigned int items, unsigned int size)
6312 return g_malloc (items * size);
6316 qtdemux_zfree (void *opaque, void *addr)
6322 qtdemux_inflate (void *z_buffer, guint z_length, guint length)
6328 z = g_new0 (z_stream, 1);
6329 z->zalloc = qtdemux_zalloc;
6330 z->zfree = qtdemux_zfree;
6333 z->next_in = z_buffer;
6334 z->avail_in = z_length;
6336 buffer = (guint8 *) g_malloc (length);
6337 ret = inflateInit (z);
6338 while (z->avail_in > 0) {
6339 if (z->avail_out == 0) {
6341 buffer = (guint8 *) g_realloc (buffer, length);
6342 z->next_out = buffer + z->total_out;
6343 z->avail_out = 1024;
6345 ret = inflate (z, Z_SYNC_FLUSH);
6349 if (ret != Z_STREAM_END) {
6350 g_warning ("inflate() returned %d", ret);
6356 #endif /* HAVE_ZLIB */
6359 qtdemux_parse_moov (GstQTDemux * qtdemux, const guint8 * buffer, guint length)
6363 qtdemux->moov_node = g_node_new ((guint8 *) buffer);
6365 /* counts as header data */
6366 qtdemux->header_size += length;
6368 GST_DEBUG_OBJECT (qtdemux, "parsing 'moov' atom");
6369 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buffer, length);
6371 cmov = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_cmov);
6377 dcom = qtdemux_tree_get_child_by_type (cmov, FOURCC_dcom);
6378 cmvd = qtdemux_tree_get_child_by_type (cmov, FOURCC_cmvd);
6379 if (dcom == NULL || cmvd == NULL)
6380 goto invalid_compression;
6382 method = QT_FOURCC ((guint8 *) dcom->data + 8);
6386 guint uncompressed_length;
6387 guint compressed_length;
6390 uncompressed_length = QT_UINT32 ((guint8 *) cmvd->data + 8);
6391 compressed_length = QT_UINT32 ((guint8 *) cmvd->data + 4) - 12;
6392 GST_LOG ("length = %u", uncompressed_length);
6395 (guint8 *) qtdemux_inflate ((guint8 *) cmvd->data + 12,
6396 compressed_length, uncompressed_length);
6398 qtdemux->moov_node_compressed = qtdemux->moov_node;
6399 qtdemux->moov_node = g_node_new (buf);
6401 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buf,
6402 uncompressed_length);
6405 #endif /* HAVE_ZLIB */
6407 GST_WARNING_OBJECT (qtdemux, "unknown or unhandled header compression "
6408 "type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (method));
6415 invalid_compression:
6417 GST_ERROR_OBJECT (qtdemux, "invalid compressed header");
6423 qtdemux_parse_container (GstQTDemux * qtdemux, GNode * node, const guint8 * buf,
6426 while (G_UNLIKELY (buf < end)) {
6430 if (G_UNLIKELY (buf + 4 > end)) {
6431 GST_LOG_OBJECT (qtdemux, "buffer overrun");
6434 len = QT_UINT32 (buf);
6435 if (G_UNLIKELY (len == 0)) {
6436 GST_LOG_OBJECT (qtdemux, "empty container");
6439 if (G_UNLIKELY (len < 8)) {
6440 GST_WARNING_OBJECT (qtdemux, "length too short (%d < 8)", len);
6443 if (G_UNLIKELY (len > (end - buf))) {
6444 GST_WARNING_OBJECT (qtdemux, "length too long (%d > %d)", len,
6445 (gint) (end - buf));
6449 child = g_node_new ((guint8 *) buf);
6450 g_node_append (node, child);
6451 GST_LOG_OBJECT (qtdemux, "adding new node of len %d", len);
6452 qtdemux_parse_node (qtdemux, child, buf, len);
6460 qtdemux_parse_theora_extension (GstQTDemux * qtdemux, QtDemuxStream * stream,
6463 int len = QT_UINT32 (xdxt->data);
6464 guint8 *buf = xdxt->data;
6465 guint8 *end = buf + len;
6468 /* skip size and type */
6476 size = QT_UINT32 (buf);
6477 type = QT_FOURCC (buf + 4);
6479 GST_LOG_OBJECT (qtdemux, "%p %p", buf, end);
6481 if (buf + size > end || size <= 0)
6487 GST_WARNING_OBJECT (qtdemux, "have cookie %" GST_FOURCC_FORMAT,
6488 GST_FOURCC_ARGS (type));
6492 buffer = gst_buffer_new_and_alloc (size);
6493 gst_buffer_fill (buffer, 0, buf, size);
6494 stream->buffers = g_slist_append (stream->buffers, buffer);
6495 GST_LOG_OBJECT (qtdemux, "parsing theora header");
6498 buffer = gst_buffer_new_and_alloc (size);
6499 gst_buffer_fill (buffer, 0, buf, size);
6500 stream->buffers = g_slist_append (stream->buffers, buffer);
6501 GST_LOG_OBJECT (qtdemux, "parsing theora comment");
6504 buffer = gst_buffer_new_and_alloc (size);
6505 gst_buffer_fill (buffer, 0, buf, size);
6506 stream->buffers = g_slist_append (stream->buffers, buffer);
6507 GST_LOG_OBJECT (qtdemux, "parsing theora codebook");
6510 GST_WARNING_OBJECT (qtdemux,
6511 "unknown theora cookie %" GST_FOURCC_FORMAT,
6512 GST_FOURCC_ARGS (type));
6521 qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node, const guint8 * buffer,
6525 guint32 node_length = 0;
6526 const QtNodeType *type;
6529 GST_LOG_OBJECT (qtdemux, "qtdemux_parse buffer %p length %u", buffer, length);
6531 if (G_UNLIKELY (length < 8))
6532 goto not_enough_data;
6534 node_length = QT_UINT32 (buffer);
6535 fourcc = QT_FOURCC (buffer + 4);
6537 /* ignore empty nodes */
6538 if (G_UNLIKELY (fourcc == 0 || node_length == 8))
6541 type = qtdemux_type_get (fourcc);
6543 end = buffer + length;
6545 GST_LOG_OBJECT (qtdemux,
6546 "parsing '%" GST_FOURCC_FORMAT "', length=%u, name '%s'",
6547 GST_FOURCC_ARGS (fourcc), node_length, type->name);
6549 if (node_length > length)
6550 goto broken_atom_size;
6552 if (type->flags & QT_FLAG_CONTAINER) {
6553 qtdemux_parse_container (qtdemux, node, buffer + 8, end);
6558 if (node_length < 20) {
6559 GST_LOG_OBJECT (qtdemux, "skipping small stsd box");
6562 GST_DEBUG_OBJECT (qtdemux,
6563 "parsing stsd (sample table, sample description) atom");
6564 /* Skip over 8 byte atom hdr + 1 byte version, 3 bytes flags, 4 byte num_entries */
6565 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
6575 /* also read alac (or whatever) in stead of mp4a in the following,
6576 * since a similar layout is used in other cases as well */
6577 if (fourcc == FOURCC_mp4a)
6582 /* There are two things we might encounter here: a true mp4a atom, and
6583 an mp4a entry in an stsd atom. The latter is what we're interested
6584 in, and it looks like an atom, but isn't really one. The true mp4a
6585 atom is short, so we detect it based on length here. */
6586 if (length < min_size) {
6587 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
6588 GST_FOURCC_ARGS (fourcc));
6592 /* 'version' here is the sound sample description version. Types 0 and
6593 1 are documented in the QTFF reference, but type 2 is not: it's
6594 described in Apple header files instead (struct SoundDescriptionV2
6596 version = QT_UINT16 (buffer + 16);
6598 GST_DEBUG_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT " version 0x%08x",
6599 GST_FOURCC_ARGS (fourcc), version);
6601 /* parse any esds descriptors */
6613 GST_WARNING_OBJECT (qtdemux,
6614 "unhandled %" GST_FOURCC_FORMAT " version 0x%08x",
6615 GST_FOURCC_ARGS (fourcc), version);
6620 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
6637 /* codec_data is contained inside these atoms, which all have
6638 * the same format. */
6640 GST_DEBUG_OBJECT (qtdemux, "parsing in %" GST_FOURCC_FORMAT,
6641 GST_FOURCC_ARGS (fourcc));
6642 version = QT_UINT32 (buffer + 16);
6643 GST_DEBUG_OBJECT (qtdemux, "version %08x", version);
6644 if (1 || version == 0x00000000) {
6645 buf = buffer + 0x32;
6647 /* FIXME Quicktime uses PASCAL string while
6648 * the iso format uses C strings. Check the file
6649 * type before attempting to parse the string here. */
6650 tlen = QT_UINT8 (buf);
6651 GST_DEBUG_OBJECT (qtdemux, "tlen = %d", tlen);
6653 GST_DEBUG_OBJECT (qtdemux, "string = %.*s", tlen, (char *) buf);
6654 /* the string has a reserved space of 32 bytes so skip
6655 * the remaining 31 */
6657 buf += 4; /* and 4 bytes reserved */
6659 GST_MEMDUMP_OBJECT (qtdemux, "mp4v", buf, end - buf);
6661 qtdemux_parse_container (qtdemux, node, buf, end);
6667 GST_MEMDUMP_OBJECT (qtdemux, "H264", buffer, end - buffer);
6668 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
6673 GST_MEMDUMP_OBJECT (qtdemux, "avc1", buffer, end - buffer);
6674 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
6679 GST_MEMDUMP_OBJECT (qtdemux, "avc3", buffer, end - buffer);
6680 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
6685 GST_MEMDUMP_OBJECT (qtdemux, "H265", buffer, end - buffer);
6686 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
6691 GST_MEMDUMP_OBJECT (qtdemux, "hvc1", buffer, end - buffer);
6692 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
6697 GST_MEMDUMP_OBJECT (qtdemux, "hev1", buffer, end - buffer);
6698 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
6703 qtdemux_parse_container (qtdemux, node, buffer + 86, end);
6708 GST_DEBUG_OBJECT (qtdemux, "parsing meta atom");
6709 qtdemux_parse_container (qtdemux, node, buffer + 12, end);
6714 GST_MEMDUMP_OBJECT (qtdemux, "mp4s", buffer, end - buffer);
6715 /* Skip 8 byte header, plus 8 byte version + flags + entry_count */
6716 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
6724 version = QT_UINT32 (buffer + 12);
6725 GST_DEBUG_OBJECT (qtdemux, "parsing XiTh atom version 0x%08x", version);
6732 GST_DEBUG_OBJECT (qtdemux, "unknown version 0x%08x", version);
6737 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
6742 qtdemux_parse_container (qtdemux, node, buffer + 0x34, end);
6747 qtdemux_parse_uuid (qtdemux, buffer, end - buffer);
6752 qtdemux_parse_container (qtdemux, node, buffer + 86, end);
6757 qtdemux_parse_container (qtdemux, node, buffer + 36, end);
6761 if (!strcmp (type->name, "unknown"))
6762 GST_MEMDUMP ("Unknown tag", buffer + 4, end - buffer - 4);
6766 GST_LOG_OBJECT (qtdemux, "parsed '%" GST_FOURCC_FORMAT "'",
6767 GST_FOURCC_ARGS (fourcc));
6773 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
6774 (_("This file is corrupt and cannot be played.")),
6775 ("Not enough data for an atom header, got only %u bytes", length));
6780 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
6781 (_("This file is corrupt and cannot be played.")),
6782 ("Atom '%" GST_FOURCC_FORMAT "' has size of %u bytes, but we have only "
6783 "%u bytes available.", GST_FOURCC_ARGS (fourcc), node_length,
6790 qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc)
6794 guint32 child_fourcc;
6796 for (child = g_node_first_child (node); child;
6797 child = g_node_next_sibling (child)) {
6798 buffer = (guint8 *) child->data;
6800 child_fourcc = QT_FOURCC (buffer + 4);
6802 if (G_UNLIKELY (child_fourcc == fourcc)) {
6810 qtdemux_tree_get_child_by_type_full (GNode * node, guint32 fourcc,
6811 GstByteReader * parser)
6815 guint32 child_fourcc, child_len;
6817 for (child = g_node_first_child (node); child;
6818 child = g_node_next_sibling (child)) {
6819 buffer = (guint8 *) child->data;
6821 child_len = QT_UINT32 (buffer);
6822 child_fourcc = QT_FOURCC (buffer + 4);
6824 if (G_UNLIKELY (child_fourcc == fourcc)) {
6825 if (G_UNLIKELY (child_len < (4 + 4)))
6827 /* FIXME: must verify if atom length < parent atom length */
6828 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
6836 qtdemux_tree_get_sibling_by_type_full (GNode * node, guint32 fourcc,
6837 GstByteReader * parser)
6841 guint32 child_fourcc, child_len;
6843 for (child = g_node_next_sibling (node); child;
6844 child = g_node_next_sibling (child)) {
6845 buffer = (guint8 *) child->data;
6847 child_fourcc = QT_FOURCC (buffer + 4);
6849 if (child_fourcc == fourcc) {
6851 child_len = QT_UINT32 (buffer);
6852 if (G_UNLIKELY (child_len < (4 + 4)))
6854 /* FIXME: must verify if atom length < parent atom length */
6855 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
6864 qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc)
6866 return qtdemux_tree_get_sibling_by_type_full (node, fourcc, NULL);
6870 qtdemux_do_allocation (GstQTDemux * qtdemux, QtDemuxStream * stream)
6872 /* FIXME: This can only reliably work if demuxers have a
6873 * separate streaming thread per srcpad. This should be
6874 * done in a demuxer base class, which integrates parts
6877 * https://bugzilla.gnome.org/show_bug.cgi?id=701856
6882 query = gst_query_new_allocation (stream->caps, FALSE);
6884 if (!gst_pad_peer_query (stream->pad, query)) {
6885 /* not a problem, just debug a little */
6886 GST_DEBUG_OBJECT (qtdemux, "peer ALLOCATION query failed");
6889 if (stream->allocator)
6890 gst_object_unref (stream->allocator);
6892 if (gst_query_get_n_allocation_params (query) > 0) {
6893 /* try the allocator */
6894 gst_query_parse_nth_allocation_param (query, 0, &stream->allocator,
6896 stream->use_allocator = TRUE;
6898 stream->allocator = NULL;
6899 gst_allocation_params_init (&stream->params);
6900 stream->use_allocator = FALSE;
6902 gst_query_unref (query);
6907 gst_qtdemux_configure_protected_caps (GstQTDemux * qtdemux,
6908 QtDemuxStream * stream)
6911 const gchar *selected_system;
6913 g_return_val_if_fail (qtdemux != NULL, FALSE);
6914 g_return_val_if_fail (stream != NULL, FALSE);
6915 g_return_val_if_fail (gst_caps_get_size (stream->caps) == 1, FALSE);
6917 if (stream->protection_scheme_type != FOURCC_cenc) {
6918 GST_ERROR_OBJECT (qtdemux, "unsupported protection scheme");
6921 if (qtdemux->protection_system_ids == NULL) {
6922 GST_ERROR_OBJECT (qtdemux, "stream is protected using cenc, but no "
6923 "cenc protection system information has been found");
6926 g_ptr_array_add (qtdemux->protection_system_ids, NULL);
6927 selected_system = gst_protection_select_system ((const gchar **)
6928 qtdemux->protection_system_ids->pdata);
6929 g_ptr_array_remove_index (qtdemux->protection_system_ids,
6930 qtdemux->protection_system_ids->len - 1);
6931 if (!selected_system) {
6932 GST_ERROR_OBJECT (qtdemux, "stream is protected, but no "
6933 "suitable decryptor element has been found");
6937 s = gst_caps_get_structure (stream->caps, 0);
6938 if (!gst_structure_has_name (s, "application/x-cenc")) {
6939 gst_structure_set (s,
6940 "original-media-type", G_TYPE_STRING, gst_structure_get_name (s),
6941 GST_PROTECTION_SYSTEM_ID_CAPS_FIELD, G_TYPE_STRING, selected_system,
6943 gst_structure_set_name (s, "application/x-cenc");
6949 gst_qtdemux_configure_stream (GstQTDemux * qtdemux, QtDemuxStream * stream)
6951 if (stream->subtype == FOURCC_vide) {
6952 /* fps is calculated base on the duration of the average framerate since
6953 * qt does not have a fixed framerate. */
6954 if ((stream->n_samples == 1) && (stream->first_duration == 0)) {
6959 if (stream->duration == 0 || stream->n_samples < 2) {
6960 stream->fps_n = stream->timescale;
6963 GstClockTime avg_duration;
6967 /* duration and n_samples can be updated for fragmented format
6968 * so, framerate of fragmented format is calculated using data in a moof */
6969 if (qtdemux->fragmented && stream->n_samples_moof > 0
6970 && stream->duration_moof > 0) {
6971 n_samples = stream->n_samples_moof;
6972 duration = stream->duration_moof;
6974 n_samples = stream->n_samples;
6975 duration = stream->duration;
6978 /* Calculate a framerate, ignoring the first sample which is sometimes truncated */
6979 /* stream->duration is guint64, timescale, n_samples are guint32 */
6981 gst_util_uint64_scale_round (duration -
6982 stream->first_duration, GST_SECOND,
6983 (guint64) (stream->timescale) * (n_samples - 1));
6985 GST_LOG_OBJECT (qtdemux,
6986 "Calculating avg sample duration based on stream (or moof) duration %"
6988 " minus first sample %u, leaving %d samples gives %"
6989 GST_TIME_FORMAT, duration, stream->first_duration,
6990 n_samples - 1, GST_TIME_ARGS (avg_duration));
6992 gst_video_guess_framerate (avg_duration, &stream->fps_n,
6995 GST_DEBUG_OBJECT (qtdemux,
6996 "Calculating framerate, timescale %u gave fps_n %d fps_d %d",
6997 stream->timescale, stream->fps_n, stream->fps_d);
7001 stream->caps = gst_caps_make_writable (stream->caps);
7003 gst_caps_set_simple (stream->caps,
7004 "width", G_TYPE_INT, stream->width,
7005 "height", G_TYPE_INT, stream->height,
7006 "framerate", GST_TYPE_FRACTION, stream->fps_n, stream->fps_d, NULL);
7008 /* calculate pixel-aspect-ratio using display width and height */
7009 GST_DEBUG_OBJECT (qtdemux,
7010 "video size %dx%d, target display size %dx%d", stream->width,
7011 stream->height, stream->display_width, stream->display_height);
7012 /* qt file might have pasp atom */
7013 if (stream->par_w > 0 && stream->par_h > 0) {
7014 GST_DEBUG_OBJECT (qtdemux, "par %d:%d", stream->par_w, stream->par_h);
7015 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
7016 GST_TYPE_FRACTION, stream->par_w, stream->par_h, NULL);
7017 } else if (stream->display_width > 0 && stream->display_height > 0 &&
7018 stream->width > 0 && stream->height > 0) {
7021 /* calculate the pixel aspect ratio using the display and pixel w/h */
7022 n = stream->display_width * stream->height;
7023 d = stream->display_height * stream->width;
7026 GST_DEBUG_OBJECT (qtdemux, "setting PAR to %d/%d", n, d);
7029 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
7030 GST_TYPE_FRACTION, stream->par_w, stream->par_h, NULL);
7033 if (stream->multiview_mode != GST_VIDEO_MULTIVIEW_MODE_NONE) {
7034 guint par_w = 1, par_h = 1;
7036 if (stream->par_w > 0 && stream->par_h > 0) {
7037 par_w = stream->par_w;
7038 par_h = stream->par_h;
7041 if (gst_video_multiview_guess_half_aspect (stream->multiview_mode,
7042 stream->width, stream->height, par_w, par_h)) {
7043 stream->multiview_flags |= GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT;
7046 gst_caps_set_simple (stream->caps,
7047 "multiview-mode", G_TYPE_STRING,
7048 gst_video_multiview_mode_to_caps_string (stream->multiview_mode),
7049 "multiview-flags", GST_TYPE_VIDEO_MULTIVIEW_FLAGSET,
7050 stream->multiview_flags, GST_FLAG_SET_MASK_EXACT, NULL);
7055 else if (stream->subtype == FOURCC_soun) {
7057 stream->caps = gst_caps_make_writable (stream->caps);
7058 if (stream->rate > 0)
7059 gst_caps_set_simple (stream->caps,
7060 "rate", G_TYPE_INT, (int) stream->rate, NULL);
7061 if (stream->n_channels > 0)
7062 gst_caps_set_simple (stream->caps,
7063 "channels", G_TYPE_INT, stream->n_channels, NULL);
7064 if (stream->n_channels > 2) {
7065 /* FIXME: Need to parse the 'chan' atom to get channel layouts
7066 * correctly; this is just the minimum we can do - assume
7067 * we don't actually have any channel positions. */
7068 gst_caps_set_simple (stream->caps,
7069 "channel-mask", GST_TYPE_BITMASK, G_GUINT64_CONSTANT (0), NULL);
7075 GST_PAD_ELEMENT_PRIVATE (stream->pad) = stream;
7076 gst_pad_set_event_function (stream->pad, gst_qtdemux_handle_src_event);
7077 gst_pad_set_query_function (stream->pad, gst_qtdemux_handle_src_query);
7078 gst_pad_set_active (stream->pad, TRUE);
7080 gst_pad_use_fixed_caps (stream->pad);
7082 if (stream->protected) {
7083 if (!gst_qtdemux_configure_protected_caps (qtdemux, stream)) {
7084 GST_ERROR_OBJECT (qtdemux,
7085 "Failed to configure protected stream caps.");
7090 GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT, stream->caps);
7091 if (stream->new_stream) {
7094 GstStreamFlags stream_flags;
7097 gst_pad_get_sticky_event (qtdemux->sinkpad, GST_EVENT_STREAM_START,
7100 if (gst_event_parse_group_id (event, &qtdemux->group_id))
7101 qtdemux->have_group_id = TRUE;
7103 qtdemux->have_group_id = FALSE;
7104 gst_event_unref (event);
7105 } else if (!qtdemux->have_group_id) {
7106 qtdemux->have_group_id = TRUE;
7107 qtdemux->group_id = gst_util_group_id_next ();
7110 stream->new_stream = FALSE;
7112 gst_pad_create_stream_id_printf (stream->pad,
7113 GST_ELEMENT_CAST (qtdemux), "%03u", stream->track_id);
7114 event = gst_event_new_stream_start (stream_id);
7115 if (qtdemux->have_group_id)
7116 gst_event_set_group_id (event, qtdemux->group_id);
7117 stream_flags = GST_STREAM_FLAG_NONE;
7118 if (stream->disabled)
7119 stream_flags |= GST_STREAM_FLAG_UNSELECT;
7121 stream_flags |= GST_STREAM_FLAG_SPARSE;
7122 gst_event_set_stream_flags (event, stream_flags);
7123 gst_pad_push_event (stream->pad, event);
7126 gst_pad_set_caps (stream->pad, stream->caps);
7127 stream->new_caps = FALSE;
7133 gst_qtdemux_add_stream (GstQTDemux * qtdemux,
7134 QtDemuxStream * stream, GstTagList * list)
7136 /* consistent default for push based mode */
7137 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
7139 if (stream->subtype == FOURCC_vide) {
7140 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
7143 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
7146 gst_qtdemux_configure_stream (qtdemux, stream);
7147 qtdemux->n_video_streams++;
7148 } else if (stream->subtype == FOURCC_soun) {
7149 gchar *name = g_strdup_printf ("audio_%u", qtdemux->n_audio_streams);
7152 gst_pad_new_from_static_template (&gst_qtdemux_audiosrc_template, name);
7154 gst_qtdemux_configure_stream (qtdemux, stream);
7155 qtdemux->n_audio_streams++;
7156 } else if (stream->subtype == FOURCC_strm) {
7157 GST_DEBUG_OBJECT (qtdemux, "stream type, not creating pad");
7158 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
7159 || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt) {
7160 gchar *name = g_strdup_printf ("subtitle_%u", qtdemux->n_sub_streams);
7163 gst_pad_new_from_static_template (&gst_qtdemux_subsrc_template, name);
7165 gst_qtdemux_configure_stream (qtdemux, stream);
7166 qtdemux->n_sub_streams++;
7167 } else if (stream->caps) {
7168 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
7171 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
7173 gst_qtdemux_configure_stream (qtdemux, stream);
7174 qtdemux->n_video_streams++;
7176 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
7183 GST_DEBUG_OBJECT (qtdemux, "adding pad %s %p to qtdemux %p",
7184 GST_OBJECT_NAME (stream->pad), stream->pad, qtdemux);
7185 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
7186 gst_flow_combiner_add_pad (qtdemux->flowcombiner, stream->pad);
7188 if (stream->pending_tags)
7189 gst_tag_list_unref (stream->pending_tags);
7190 stream->pending_tags = list;
7192 /* global tags go on each pad anyway */
7193 stream->send_global_tags = TRUE;
7194 /* send upstream GST_EVENT_PROTECTION events that were received before
7195 this source pad was created */
7196 for (l = qtdemux->protection_event_queue.head; l != NULL; l = l->next)
7197 gst_pad_push_event (stream->pad, gst_event_ref (l->data));
7201 gst_tag_list_unref (list);
7205 /* find next atom with @fourcc starting at @offset */
7206 static GstFlowReturn
7207 qtdemux_find_atom (GstQTDemux * qtdemux, guint64 * offset,
7208 guint64 * length, guint32 fourcc)
7214 GST_LOG_OBJECT (qtdemux, "finding fourcc %" GST_FOURCC_FORMAT " at offset %"
7215 G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), *offset);
7221 ret = gst_pad_pull_range (qtdemux->sinkpad, *offset, 16, &buf);
7222 if (G_UNLIKELY (ret != GST_FLOW_OK))
7224 if (G_UNLIKELY (gst_buffer_get_size (buf) != 16)) {
7227 gst_buffer_unref (buf);
7230 gst_buffer_map (buf, &map, GST_MAP_READ);
7231 extract_initial_length_and_fourcc (map.data, 16, length, &lfourcc);
7232 gst_buffer_unmap (buf, &map);
7233 gst_buffer_unref (buf);
7235 if (G_UNLIKELY (*length == 0)) {
7236 GST_DEBUG_OBJECT (qtdemux, "invalid length 0");
7237 ret = GST_FLOW_ERROR;
7241 if (lfourcc == fourcc) {
7242 GST_DEBUG_OBJECT (qtdemux, "found fourcc at offset %" G_GUINT64_FORMAT,
7246 GST_LOG_OBJECT (qtdemux,
7247 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
7248 GST_FOURCC_ARGS (fourcc), *offset);
7257 /* might simply have had last one */
7258 GST_DEBUG_OBJECT (qtdemux, "fourcc not found");
7263 /* should only do something in pull mode */
7264 /* call with OBJECT lock */
7265 static GstFlowReturn
7266 qtdemux_add_fragmented_samples (GstQTDemux * qtdemux)
7268 guint64 length, offset;
7269 GstBuffer *buf = NULL;
7270 GstFlowReturn ret = GST_FLOW_OK;
7271 GstFlowReturn res = GST_FLOW_OK;
7274 offset = qtdemux->moof_offset;
7275 GST_DEBUG_OBJECT (qtdemux, "next moof at offset %" G_GUINT64_FORMAT, offset);
7278 GST_DEBUG_OBJECT (qtdemux, "no next moof");
7279 return GST_FLOW_EOS;
7282 /* best not do pull etc with lock held */
7283 GST_OBJECT_UNLOCK (qtdemux);
7285 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
7286 if (ret != GST_FLOW_OK)
7289 ret = gst_qtdemux_pull_atom (qtdemux, offset, length, &buf);
7290 if (G_UNLIKELY (ret != GST_FLOW_OK))
7292 gst_buffer_map (buf, &map, GST_MAP_READ);
7293 if (!qtdemux_parse_moof (qtdemux, map.data, map.size, offset, NULL)) {
7294 gst_buffer_unmap (buf, &map);
7295 gst_buffer_unref (buf);
7300 gst_buffer_unmap (buf, &map);
7301 gst_buffer_unref (buf);
7305 /* look for next moof */
7306 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
7307 if (G_UNLIKELY (ret != GST_FLOW_OK))
7311 GST_OBJECT_LOCK (qtdemux);
7313 qtdemux->moof_offset = offset;
7319 GST_DEBUG_OBJECT (qtdemux, "failed to parse moof");
7321 res = GST_FLOW_ERROR;
7326 /* maybe upstream temporarily flushing */
7327 if (ret != GST_FLOW_FLUSHING) {
7328 GST_DEBUG_OBJECT (qtdemux, "no next moof");
7331 GST_DEBUG_OBJECT (qtdemux, "upstream WRONG_STATE");
7332 /* resume at current position next time */
7339 /* initialise bytereaders for stbl sub-atoms */
7341 qtdemux_stbl_init (GstQTDemux * qtdemux, QtDemuxStream * stream, GNode * stbl)
7343 stream->stbl_index = -1; /* no samples have yet been parsed */
7344 stream->sample_index = -1;
7346 /* time-to-sample atom */
7347 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stts, &stream->stts))
7350 /* copy atom data into a new buffer for later use */
7351 stream->stts.data = g_memdup (stream->stts.data, stream->stts.size);
7353 /* skip version + flags */
7354 if (!gst_byte_reader_skip (&stream->stts, 1 + 3) ||
7355 !gst_byte_reader_get_uint32_be (&stream->stts, &stream->n_sample_times))
7357 GST_LOG_OBJECT (qtdemux, "%u timestamp blocks", stream->n_sample_times);
7359 /* make sure there's enough data */
7360 if (!qt_atom_parser_has_chunks (&stream->stts, stream->n_sample_times, 8)) {
7361 stream->n_sample_times = gst_byte_reader_get_remaining (&stream->stts) / 8;
7362 GST_LOG_OBJECT (qtdemux, "overriding to %u timestamp blocks",
7363 stream->n_sample_times);
7364 if (!stream->n_sample_times)
7368 /* sync sample atom */
7369 stream->stps_present = FALSE;
7370 if ((stream->stss_present =
7371 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stss,
7372 &stream->stss) ? TRUE : FALSE) == TRUE) {
7373 /* copy atom data into a new buffer for later use */
7374 stream->stss.data = g_memdup (stream->stss.data, stream->stss.size);
7376 /* skip version + flags */
7377 if (!gst_byte_reader_skip (&stream->stss, 1 + 3) ||
7378 !gst_byte_reader_get_uint32_be (&stream->stss, &stream->n_sample_syncs))
7381 if (stream->n_sample_syncs) {
7382 /* make sure there's enough data */
7383 if (!qt_atom_parser_has_chunks (&stream->stss, stream->n_sample_syncs, 4))
7387 /* partial sync sample atom */
7388 if ((stream->stps_present =
7389 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stps,
7390 &stream->stps) ? TRUE : FALSE) == TRUE) {
7391 /* copy atom data into a new buffer for later use */
7392 stream->stps.data = g_memdup (stream->stps.data, stream->stps.size);
7394 /* skip version + flags */
7395 if (!gst_byte_reader_skip (&stream->stps, 1 + 3) ||
7396 !gst_byte_reader_get_uint32_be (&stream->stps,
7397 &stream->n_sample_partial_syncs))
7400 /* if there are no entries, the stss table contains the real
7402 if (stream->n_sample_partial_syncs) {
7403 /* make sure there's enough data */
7404 if (!qt_atom_parser_has_chunks (&stream->stps,
7405 stream->n_sample_partial_syncs, 4))
7412 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsz, &stream->stsz))
7415 /* copy atom data into a new buffer for later use */
7416 stream->stsz.data = g_memdup (stream->stsz.data, stream->stsz.size);
7418 /* skip version + flags */
7419 if (!gst_byte_reader_skip (&stream->stsz, 1 + 3) ||
7420 !gst_byte_reader_get_uint32_be (&stream->stsz, &stream->sample_size))
7423 if (!gst_byte_reader_get_uint32_be (&stream->stsz, &stream->n_samples))
7426 if (!stream->n_samples)
7429 /* sample-to-chunk atom */
7430 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsc, &stream->stsc))
7433 /* copy atom data into a new buffer for later use */
7434 stream->stsc.data = g_memdup (stream->stsc.data, stream->stsc.size);
7436 /* skip version + flags */
7437 if (!gst_byte_reader_skip (&stream->stsc, 1 + 3) ||
7438 !gst_byte_reader_get_uint32_be (&stream->stsc,
7439 &stream->n_samples_per_chunk))
7442 GST_DEBUG_OBJECT (qtdemux, "n_samples_per_chunk %u",
7443 stream->n_samples_per_chunk);
7445 /* make sure there's enough data */
7446 if (!qt_atom_parser_has_chunks (&stream->stsc, stream->n_samples_per_chunk,
7452 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stco, &stream->stco))
7453 stream->co_size = sizeof (guint32);
7454 else if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_co64,
7456 stream->co_size = sizeof (guint64);
7460 /* copy atom data into a new buffer for later use */
7461 stream->stco.data = g_memdup (stream->stco.data, stream->stco.size);
7463 /* skip version + flags */
7464 if (!gst_byte_reader_skip (&stream->stco, 1 + 3))
7467 /* chunks_are_samples == TRUE means treat chunks as samples */
7468 stream->chunks_are_samples = stream->sample_size && !stream->sampled;
7469 if (stream->chunks_are_samples) {
7470 /* treat chunks as samples */
7471 if (!gst_byte_reader_get_uint32_be (&stream->stco, &stream->n_samples))
7474 /* skip number of entries */
7475 if (!gst_byte_reader_skip (&stream->stco, 4))
7478 /* make sure there are enough data in the stsz atom */
7479 if (!stream->sample_size) {
7480 /* different sizes for each sample */
7481 if (!qt_atom_parser_has_chunks (&stream->stsz, stream->n_samples, 4))
7486 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
7487 stream->n_samples, (guint) sizeof (QtDemuxSample),
7488 stream->n_samples * sizeof (QtDemuxSample) / (1024.0 * 1024.0));
7490 if (stream->n_samples >=
7491 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample)) {
7492 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
7493 "be larger than %uMB (broken file?)", stream->n_samples,
7494 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
7498 g_assert (stream->samples == NULL);
7499 stream->samples = g_try_new0 (QtDemuxSample, stream->n_samples);
7500 if (!stream->samples) {
7501 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
7506 /* composition time-to-sample */
7507 if ((stream->ctts_present =
7508 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_ctts,
7509 &stream->ctts) ? TRUE : FALSE) == TRUE) {
7510 GstByteReader cslg = GST_BYTE_READER_INIT (NULL, 0);
7512 /* copy atom data into a new buffer for later use */
7513 stream->ctts.data = g_memdup (stream->ctts.data, stream->ctts.size);
7515 /* skip version + flags */
7516 if (!gst_byte_reader_skip (&stream->ctts, 1 + 3)
7517 || !gst_byte_reader_get_uint32_be (&stream->ctts,
7518 &stream->n_composition_times))
7521 /* make sure there's enough data */
7522 if (!qt_atom_parser_has_chunks (&stream->ctts, stream->n_composition_times,
7526 /* This is optional, if missing we iterate the ctts */
7527 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_cslg, &cslg)) {
7528 if (!gst_byte_reader_skip (&cslg, 1 + 3)
7529 || !gst_byte_reader_get_uint32_be (&cslg, &stream->cslg_shift)) {
7530 g_free ((gpointer) cslg.data);
7534 gint32 cslg_least = 0;
7535 guint num_entries, pos;
7538 pos = gst_byte_reader_get_pos (&stream->ctts);
7539 num_entries = stream->n_composition_times;
7541 stream->cslg_shift = 0;
7543 for (i = 0; i < num_entries; i++) {
7546 gst_byte_reader_skip_unchecked (&stream->ctts, 4);
7547 offset = gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
7549 if (offset < cslg_least)
7550 cslg_least = offset;
7554 stream->cslg_shift = ABS (cslg_least);
7556 stream->cslg_shift = 0;
7558 /* reset the reader so we can generate sample table */
7559 gst_byte_reader_set_pos (&stream->ctts, pos);
7562 /* Ensure the cslg_shift value is consistent so we can use it
7563 * unconditionnally to produce TS and Segment */
7564 stream->cslg_shift = 0;
7571 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
7572 (_("This file is corrupt and cannot be played.")), (NULL));
7577 gst_qtdemux_stbl_free (stream);
7578 if (!qtdemux->fragmented) {
7579 /* not quite good */
7580 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
7583 /* may pick up samples elsewhere */
7589 /* collect samples from the next sample to be parsed up to sample @n for @stream
7590 * by reading the info from @stbl
7592 * This code can be executed from both the streaming thread and the seeking
7593 * thread so it takes the object lock to protect itself
7596 qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream, guint32 n)
7599 QtDemuxSample *samples, *first, *cur, *last;
7600 guint32 n_samples_per_chunk;
7603 GST_LOG_OBJECT (qtdemux, "parsing samples for stream fourcc %"
7604 GST_FOURCC_FORMAT ", pad %s", GST_FOURCC_ARGS (stream->fourcc),
7605 stream->pad ? GST_PAD_NAME (stream->pad) : "(NULL)");
7607 n_samples = stream->n_samples;
7610 goto out_of_samples;
7612 GST_OBJECT_LOCK (qtdemux);
7613 if (n <= stream->stbl_index)
7614 goto already_parsed;
7616 GST_DEBUG_OBJECT (qtdemux, "parsing up to sample %u", n);
7618 if (!stream->stsz.data) {
7619 /* so we already parsed and passed all the moov samples;
7620 * onto fragmented ones */
7621 g_assert (qtdemux->fragmented);
7625 /* pointer to the sample table */
7626 samples = stream->samples;
7628 /* starts from -1, moves to the next sample index to parse */
7629 stream->stbl_index++;
7631 /* keep track of the first and last sample to fill */
7632 first = &samples[stream->stbl_index];
7635 if (!stream->chunks_are_samples) {
7636 /* set the sample sizes */
7637 if (stream->sample_size == 0) {
7638 /* different sizes for each sample */
7639 for (cur = first; cur <= last; cur++) {
7640 cur->size = gst_byte_reader_get_uint32_be_unchecked (&stream->stsz);
7641 GST_LOG_OBJECT (qtdemux, "sample %d has size %u",
7642 (guint) (cur - samples), cur->size);
7645 /* samples have the same size */
7646 GST_LOG_OBJECT (qtdemux, "all samples have size %u", stream->sample_size);
7647 for (cur = first; cur <= last; cur++)
7648 cur->size = stream->sample_size;
7652 n_samples_per_chunk = stream->n_samples_per_chunk;
7655 for (i = stream->stsc_index; i < n_samples_per_chunk; i++) {
7658 if (stream->stsc_chunk_index >= stream->last_chunk
7659 || stream->stsc_chunk_index < stream->first_chunk) {
7660 stream->first_chunk =
7661 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
7662 stream->samples_per_chunk =
7663 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
7664 gst_byte_reader_skip_unchecked (&stream->stsc, 4);
7666 /* chunk numbers are counted from 1 it seems */
7667 if (G_UNLIKELY (stream->first_chunk == 0))
7670 --stream->first_chunk;
7672 /* the last chunk of each entry is calculated by taking the first chunk
7673 * of the next entry; except if there is no next, where we fake it with
7675 if (G_UNLIKELY (i == (stream->n_samples_per_chunk - 1))) {
7676 stream->last_chunk = G_MAXUINT32;
7678 stream->last_chunk =
7679 gst_byte_reader_peek_uint32_be_unchecked (&stream->stsc);
7680 if (G_UNLIKELY (stream->last_chunk == 0))
7683 --stream->last_chunk;
7686 GST_LOG_OBJECT (qtdemux,
7687 "entry %d has first_chunk %d, last_chunk %d, samples_per_chunk %d", i,
7688 stream->first_chunk, stream->last_chunk, stream->samples_per_chunk);
7690 if (G_UNLIKELY (stream->last_chunk < stream->first_chunk))
7693 if (stream->last_chunk != G_MAXUINT32) {
7694 if (!qt_atom_parser_peek_sub (&stream->stco,
7695 stream->first_chunk * stream->co_size,
7696 (stream->last_chunk - stream->first_chunk) * stream->co_size,
7701 stream->co_chunk = stream->stco;
7702 if (!gst_byte_reader_skip (&stream->co_chunk,
7703 stream->first_chunk * stream->co_size))
7707 stream->stsc_chunk_index = stream->first_chunk;
7710 last_chunk = stream->last_chunk;
7712 if (stream->chunks_are_samples) {
7713 cur = &samples[stream->stsc_chunk_index];
7715 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
7718 stream->stsc_chunk_index = j;
7723 qt_atom_parser_get_offset_unchecked (&stream->co_chunk,
7726 GST_LOG_OBJECT (qtdemux, "Created entry %d with offset "
7727 "%" G_GUINT64_FORMAT, j, cur->offset);
7729 if (stream->samples_per_frame * stream->bytes_per_frame) {
7731 (stream->samples_per_chunk * stream->n_channels) /
7732 stream->samples_per_frame * stream->bytes_per_frame;
7734 cur->size = stream->samples_per_chunk;
7737 GST_DEBUG_OBJECT (qtdemux,
7738 "keyframe sample %d: timestamp %" GST_TIME_FORMAT ", size %u",
7739 j, GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream,
7740 stream->stco_sample_index)), cur->size);
7742 cur->timestamp = stream->stco_sample_index;
7743 cur->duration = stream->samples_per_chunk;
7744 cur->keyframe = TRUE;
7747 stream->stco_sample_index += stream->samples_per_chunk;
7749 stream->stsc_chunk_index = j;
7751 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
7752 guint32 samples_per_chunk;
7753 guint64 chunk_offset;
7755 if (!stream->stsc_sample_index
7756 && !qt_atom_parser_get_offset (&stream->co_chunk, stream->co_size,
7757 &stream->chunk_offset))
7760 samples_per_chunk = stream->samples_per_chunk;
7761 chunk_offset = stream->chunk_offset;
7763 for (k = stream->stsc_sample_index; k < samples_per_chunk; k++) {
7764 GST_LOG_OBJECT (qtdemux, "creating entry %d with offset %"
7765 G_GUINT64_FORMAT " and size %d",
7766 (guint) (cur - samples), chunk_offset, cur->size);
7768 cur->offset = chunk_offset;
7769 chunk_offset += cur->size;
7772 if (G_UNLIKELY (cur > last)) {
7774 stream->stsc_sample_index = k + 1;
7775 stream->chunk_offset = chunk_offset;
7776 stream->stsc_chunk_index = j;
7780 stream->stsc_sample_index = 0;
7782 stream->stsc_chunk_index = j;
7784 stream->stsc_index++;
7787 if (stream->chunks_are_samples)
7791 guint32 n_sample_times;
7793 n_sample_times = stream->n_sample_times;
7796 for (i = stream->stts_index; i < n_sample_times; i++) {
7797 guint32 stts_samples;
7798 gint32 stts_duration;
7801 if (stream->stts_sample_index >= stream->stts_samples
7802 || !stream->stts_sample_index) {
7804 stream->stts_samples =
7805 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
7806 stream->stts_duration =
7807 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
7809 GST_LOG_OBJECT (qtdemux, "block %d, %u timestamps, duration %u",
7810 i, stream->stts_samples, stream->stts_duration);
7812 stream->stts_sample_index = 0;
7815 stts_samples = stream->stts_samples;
7816 stts_duration = stream->stts_duration;
7817 stts_time = stream->stts_time;
7819 for (j = stream->stts_sample_index; j < stts_samples; j++) {
7820 GST_DEBUG_OBJECT (qtdemux,
7821 "sample %d: index %d, timestamp %" GST_TIME_FORMAT,
7822 (guint) (cur - samples), j,
7823 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stts_time)));
7825 cur->timestamp = stts_time;
7826 cur->duration = stts_duration;
7828 /* avoid 32-bit wrap-around,
7829 * but still mind possible 'negative' duration */
7830 stts_time += (gint64) stts_duration;
7833 if (G_UNLIKELY (cur > last)) {
7835 stream->stts_time = stts_time;
7836 stream->stts_sample_index = j + 1;
7840 stream->stts_sample_index = 0;
7841 stream->stts_time = stts_time;
7842 stream->stts_index++;
7844 /* fill up empty timestamps with the last timestamp, this can happen when
7845 * the last samples do not decode and so we don't have timestamps for them.
7846 * We however look at the last timestamp to estimate the track length so we
7847 * need something in here. */
7848 for (; cur < last; cur++) {
7849 GST_DEBUG_OBJECT (qtdemux,
7850 "fill sample %d: timestamp %" GST_TIME_FORMAT,
7851 (guint) (cur - samples),
7852 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stream->stts_time)));
7853 cur->timestamp = stream->stts_time;
7859 /* sample sync, can be NULL */
7860 if (stream->stss_present == TRUE) {
7861 guint32 n_sample_syncs;
7863 n_sample_syncs = stream->n_sample_syncs;
7865 if (!n_sample_syncs) {
7866 GST_DEBUG_OBJECT (qtdemux, "all samples are keyframes");
7867 stream->all_keyframe = TRUE;
7869 for (i = stream->stss_index; i < n_sample_syncs; i++) {
7870 /* note that the first sample is index 1, not 0 */
7873 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stss);
7875 if (G_LIKELY (index > 0 && index <= n_samples)) {
7877 samples[index].keyframe = TRUE;
7878 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
7879 /* and exit if we have enough samples */
7880 if (G_UNLIKELY (index >= n)) {
7887 stream->stss_index = i;
7890 /* stps marks partial sync frames like open GOP I-Frames */
7891 if (stream->stps_present == TRUE) {
7892 guint32 n_sample_partial_syncs;
7894 n_sample_partial_syncs = stream->n_sample_partial_syncs;
7896 /* if there are no entries, the stss table contains the real
7898 if (n_sample_partial_syncs) {
7899 for (i = stream->stps_index; i < n_sample_partial_syncs; i++) {
7900 /* note that the first sample is index 1, not 0 */
7903 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stps);
7905 if (G_LIKELY (index > 0 && index <= n_samples)) {
7907 samples[index].keyframe = TRUE;
7908 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
7909 /* and exit if we have enough samples */
7910 if (G_UNLIKELY (index >= n)) {
7917 stream->stps_index = i;
7921 /* no stss, all samples are keyframes */
7922 stream->all_keyframe = TRUE;
7923 GST_DEBUG_OBJECT (qtdemux, "setting all keyframes");
7928 /* composition time to sample */
7929 if (stream->ctts_present == TRUE) {
7930 guint32 n_composition_times;
7932 gint32 ctts_soffset;
7934 /* Fill in the pts_offsets */
7936 n_composition_times = stream->n_composition_times;
7938 for (i = stream->ctts_index; i < n_composition_times; i++) {
7939 if (stream->ctts_sample_index >= stream->ctts_count
7940 || !stream->ctts_sample_index) {
7941 stream->ctts_count =
7942 gst_byte_reader_get_uint32_be_unchecked (&stream->ctts);
7943 stream->ctts_soffset =
7944 gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
7945 stream->ctts_sample_index = 0;
7948 ctts_count = stream->ctts_count;
7949 ctts_soffset = stream->ctts_soffset;
7951 for (j = stream->ctts_sample_index; j < ctts_count; j++) {
7952 cur->pts_offset = ctts_soffset;
7955 if (G_UNLIKELY (cur > last)) {
7957 stream->ctts_sample_index = j + 1;
7961 stream->ctts_sample_index = 0;
7962 stream->ctts_index++;
7966 stream->stbl_index = n;
7967 /* if index has been completely parsed, free data that is no-longer needed */
7968 if (n + 1 == stream->n_samples) {
7969 gst_qtdemux_stbl_free (stream);
7970 GST_DEBUG_OBJECT (qtdemux, "parsed all available samples;");
7971 if (qtdemux->pullbased) {
7972 GST_DEBUG_OBJECT (qtdemux, "checking for more samples");
7973 while (n + 1 == stream->n_samples)
7974 if (qtdemux_add_fragmented_samples (qtdemux) != GST_FLOW_OK)
7978 GST_OBJECT_UNLOCK (qtdemux);
7985 GST_LOG_OBJECT (qtdemux,
7986 "Tried to parse up to sample %u but this sample has already been parsed",
7988 /* if fragmented, there may be more */
7989 if (qtdemux->fragmented && n == stream->stbl_index)
7991 GST_OBJECT_UNLOCK (qtdemux);
7997 GST_LOG_OBJECT (qtdemux,
7998 "Tried to parse up to sample %u but there are only %u samples", n + 1,
8000 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8001 (_("This file is corrupt and cannot be played.")), (NULL));
8006 GST_OBJECT_UNLOCK (qtdemux);
8007 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8008 (_("This file is corrupt and cannot be played.")), (NULL));
8013 /* collect all segment info for @stream.
8016 qtdemux_parse_segments (GstQTDemux * qtdemux, QtDemuxStream * stream,
8020 /* accept edts if they contain gaps at start and there is only
8021 * one media segment */
8022 gboolean allow_pushbased_edts = TRUE;
8023 gint media_segments_count = 0;
8025 /* parse and prepare segment info from the edit list */
8026 GST_DEBUG_OBJECT (qtdemux, "looking for edit list container");
8027 stream->n_segments = 0;
8028 stream->segments = NULL;
8029 if ((edts = qtdemux_tree_get_child_by_type (trak, FOURCC_edts))) {
8037 GST_DEBUG_OBJECT (qtdemux, "looking for edit list");
8038 if (!(elst = qtdemux_tree_get_child_by_type (edts, FOURCC_elst)))
8041 buffer = elst->data;
8043 n_segments = QT_UINT32 (buffer + 12);
8045 /* we might allocate a bit too much, at least allocate 1 segment */
8046 stream->segments = g_new (QtDemuxSegment, MAX (n_segments, 1));
8048 /* segments always start from 0 */
8052 for (i = 0; i < n_segments; i++) {
8055 QtDemuxSegment *segment;
8057 GstClockTime media_start = GST_CLOCK_TIME_NONE;
8059 media_time = QT_UINT32 (buffer + 20 + i * 12);
8060 duration = QT_UINT32 (buffer + 16 + i * 12);
8062 if (media_time != G_MAXUINT32)
8063 media_start = QTSTREAMTIME_TO_GSTTIME (stream, media_time);
8065 segment = &stream->segments[count++];
8067 /* time and duration expressed in global timescale */
8068 segment->time = stime;
8069 /* add non scaled values so we don't cause roundoff errors */
8072 stime = QTTIME_TO_GSTTIME (qtdemux, time);
8073 segment->duration = stime - segment->time;
8075 /* zero duration does not imply media_start == media_stop
8076 * but, only specify media_start.*/
8077 stime = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
8078 if (GST_CLOCK_TIME_IS_VALID (stime) && media_time != G_MAXUINT32
8079 && stime >= media_start) {
8080 segment->duration = stime - media_start;
8082 segment->duration = GST_CLOCK_TIME_NONE;
8085 segment->stop_time = stime;
8087 segment->trak_media_start = media_time;
8088 /* media_time expressed in stream timescale */
8089 if (media_time != G_MAXUINT32) {
8090 segment->media_start = media_start;
8091 segment->media_stop = segment->media_start + segment->duration;
8092 media_segments_count++;
8094 segment->media_start = GST_CLOCK_TIME_NONE;
8095 segment->media_stop = GST_CLOCK_TIME_NONE;
8097 rate_int = GST_READ_UINT32_BE (buffer + 24 + i * 12);
8099 if (rate_int <= 1) {
8100 /* 0 is not allowed, some programs write 1 instead of the floating point
8102 GST_WARNING_OBJECT (qtdemux, "found suspicious rate %" G_GUINT32_FORMAT,
8106 segment->rate = rate_int / 65536.0;
8109 GST_DEBUG_OBJECT (qtdemux, "created segment %d time %" GST_TIME_FORMAT
8110 ", duration %" GST_TIME_FORMAT ", media_start %" GST_TIME_FORMAT
8111 " (%" G_GUINT64_FORMAT ") , media_stop %" GST_TIME_FORMAT
8112 " stop_time %" GST_TIME_FORMAT " rate %g, (%d) timescale %u",
8113 i, GST_TIME_ARGS (segment->time),
8114 GST_TIME_ARGS (segment->duration),
8115 GST_TIME_ARGS (segment->media_start), media_time,
8116 GST_TIME_ARGS (segment->media_stop),
8117 GST_TIME_ARGS (segment->stop_time), segment->rate, rate_int,
8119 if (segment->stop_time > qtdemux->segment.stop) {
8120 GST_WARNING_OBJECT (qtdemux, "Segment %d "
8121 " extends to %" GST_TIME_FORMAT
8122 " past the end of the file duration %" GST_TIME_FORMAT
8123 " it will be truncated", i, GST_TIME_ARGS (segment->stop_time),
8124 GST_TIME_ARGS (qtdemux->segment.stop));
8125 qtdemux->segment.stop = segment->stop_time;
8128 GST_DEBUG_OBJECT (qtdemux, "found %d segments", count);
8129 stream->n_segments = count;
8130 if (media_segments_count != 1)
8131 allow_pushbased_edts = FALSE;
8135 /* push based does not handle segments, so act accordingly here,
8136 * and warn if applicable */
8137 if (!qtdemux->pullbased && !allow_pushbased_edts) {
8138 GST_WARNING_OBJECT (qtdemux, "streaming; discarding edit list segments");
8139 /* remove and use default one below, we stream like it anyway */
8140 g_free (stream->segments);
8141 stream->segments = NULL;
8142 stream->n_segments = 0;
8145 /* no segments, create one to play the complete trak */
8146 if (stream->n_segments == 0) {
8147 GstClockTime stream_duration =
8148 QTSTREAMTIME_TO_GSTTIME (stream, stream->duration);
8150 if (stream->segments == NULL)
8151 stream->segments = g_new (QtDemuxSegment, 1);
8153 /* represent unknown our way */
8154 if (stream_duration == 0)
8155 stream_duration = GST_CLOCK_TIME_NONE;
8157 stream->segments[0].time = 0;
8158 stream->segments[0].stop_time = stream_duration;
8159 stream->segments[0].duration = stream_duration;
8160 stream->segments[0].media_start = 0;
8161 stream->segments[0].media_stop = stream_duration;
8162 stream->segments[0].rate = 1.0;
8163 stream->segments[0].trak_media_start = 0;
8165 GST_DEBUG_OBJECT (qtdemux, "created dummy segment %" GST_TIME_FORMAT,
8166 GST_TIME_ARGS (stream_duration));
8167 stream->n_segments = 1;
8168 stream->dummy_segment = TRUE;
8170 GST_DEBUG_OBJECT (qtdemux, "using %d segments", stream->n_segments);
8176 * Parses the stsd atom of a svq3 trak looking for
8177 * the SMI and gama atoms.
8180 qtdemux_parse_svq3_stsd_data (GstQTDemux * qtdemux, GNode * stsd,
8181 guint8 ** gamma, GstBuffer ** seqh)
8183 guint8 *_gamma = NULL;
8184 GstBuffer *_seqh = NULL;
8185 guint8 *stsd_data = stsd->data;
8186 guint32 length = QT_UINT32 (stsd_data);
8190 GST_WARNING_OBJECT (qtdemux, "stsd too short");
8196 version = QT_UINT16 (stsd_data);
8201 while (length > 8) {
8202 guint32 fourcc, size;
8204 size = QT_UINT32 (stsd_data);
8205 fourcc = QT_FOURCC (stsd_data + 4);
8206 data = stsd_data + 8;
8209 GST_WARNING_OBJECT (qtdemux, "Atom of size 0 found, aborting "
8210 "svq3 atom parsing");
8219 GST_WARNING_OBJECT (qtdemux, "Unexpected size %" G_GUINT32_FORMAT
8220 " for gama atom, expected 12", size);
8225 if (size > 16 && QT_FOURCC (data) == FOURCC_SEQH) {
8227 if (_seqh != NULL) {
8228 GST_WARNING_OBJECT (qtdemux, "Unexpected second SEQH SMI atom "
8229 " found, ignoring");
8231 seqh_size = QT_UINT32 (data + 4);
8232 if (seqh_size > 0) {
8233 _seqh = gst_buffer_new_and_alloc (seqh_size);
8234 gst_buffer_fill (_seqh, 0, data + 8, seqh_size);
8241 GST_WARNING_OBJECT (qtdemux, "Unhandled atom %" GST_FOURCC_FORMAT
8242 " in SVQ3 entry in stsd atom", GST_FOURCC_ARGS (fourcc));
8246 if (size <= length) {
8252 GST_WARNING_OBJECT (qtdemux, "SVQ3 entry too short in stsd atom");
8255 GST_WARNING_OBJECT (qtdemux, "Unexpected version for SVQ3 entry %"
8256 G_GUINT16_FORMAT, version);
8267 gst_buffer_unref (_seqh);
8272 qtdemux_get_rtsp_uri_from_hndl (GstQTDemux * qtdemux, GNode * minf)
8279 * Get 'dinf', to get its child 'dref', that might contain a 'hndl'
8280 * atom that might contain a 'data' atom with the rtsp uri.
8281 * This case was reported in bug #597497, some info about
8282 * the hndl atom can be found in TN1195
8284 dinf = qtdemux_tree_get_child_by_type (minf, FOURCC_dinf);
8285 GST_DEBUG_OBJECT (qtdemux, "Trying to obtain rtsp URI for stream trak");
8288 guint32 dref_num_entries = 0;
8289 if (qtdemux_tree_get_child_by_type_full (dinf, FOURCC_dref, &dref) &&
8290 gst_byte_reader_skip (&dref, 4) &&
8291 gst_byte_reader_get_uint32_be (&dref, &dref_num_entries)) {
8294 /* search dref entries for hndl atom */
8295 for (i = 0; i < dref_num_entries; i++) {
8296 guint32 size = 0, type;
8297 guint8 string_len = 0;
8298 if (gst_byte_reader_get_uint32_be (&dref, &size) &&
8299 qt_atom_parser_get_fourcc (&dref, &type)) {
8300 if (type == FOURCC_hndl) {
8301 GST_DEBUG_OBJECT (qtdemux, "Found hndl atom");
8303 /* skip data reference handle bytes and the
8304 * following pascal string and some extra 4
8305 * bytes I have no idea what are */
8306 if (!gst_byte_reader_skip (&dref, 4) ||
8307 !gst_byte_reader_get_uint8 (&dref, &string_len) ||
8308 !gst_byte_reader_skip (&dref, string_len + 4)) {
8309 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl atom");
8313 /* iterate over the atoms to find the data atom */
8314 while (gst_byte_reader_get_remaining (&dref) >= 8) {
8318 if (gst_byte_reader_get_uint32_be (&dref, &atom_size) &&
8319 qt_atom_parser_get_fourcc (&dref, &atom_type)) {
8320 if (atom_type == FOURCC_data) {
8321 const guint8 *uri_aux = NULL;
8323 /* found the data atom that might contain the rtsp uri */
8324 GST_DEBUG_OBJECT (qtdemux, "Found data atom inside "
8325 "hndl atom, interpreting it as an URI");
8326 if (gst_byte_reader_peek_data (&dref, atom_size - 8,
8328 if (g_strstr_len ((gchar *) uri_aux, 7, "rtsp://") != NULL)
8329 uri = g_strndup ((gchar *) uri_aux, atom_size - 8);
8331 GST_WARNING_OBJECT (qtdemux, "Data atom in hndl atom "
8332 "didn't contain a rtsp address");
8334 GST_WARNING_OBJECT (qtdemux, "Failed to get the data "
8339 /* skipping to the next entry */
8340 if (!gst_byte_reader_skip (&dref, atom_size - 8))
8343 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl child "
8350 /* skip to the next entry */
8351 if (!gst_byte_reader_skip (&dref, size - 8))
8354 GST_WARNING_OBJECT (qtdemux, "Error parsing dref atom");
8357 GST_DEBUG_OBJECT (qtdemux, "Finished parsing dref atom");
8363 #define AMR_NB_ALL_MODES 0x81ff
8364 #define AMR_WB_ALL_MODES 0x83ff
8366 qtdemux_parse_amr_bitrate (GstBuffer * buf, gboolean wb)
8368 /* The 'damr' atom is of the form:
8370 * | vendor | decoder_ver | mode_set | mode_change_period | frames/sample |
8371 * 32 b 8 b 16 b 8 b 8 b
8373 * The highest set bit of the first 7 (AMR-NB) or 8 (AMR-WB) bits of mode_set
8374 * represents the highest mode used in the stream (and thus the maximum
8375 * bitrate), with a couple of special cases as seen below.
8378 /* Map of frame type ID -> bitrate */
8379 static const guint nb_bitrates[] = {
8380 4750, 5150, 5900, 6700, 7400, 7950, 10200, 12200
8382 static const guint wb_bitrates[] = {
8383 6600, 8850, 12650, 14250, 15850, 18250, 19850, 23050, 23850
8389 gst_buffer_map (buf, &map, GST_MAP_READ);
8391 if (map.size != 0x11) {
8392 GST_DEBUG ("Atom should have size 0x11, not %" G_GSIZE_FORMAT, map.size);
8396 if (QT_FOURCC (map.data + 4) != FOURCC_damr) {
8397 GST_DEBUG ("Unknown atom in %" GST_FOURCC_FORMAT,
8398 GST_FOURCC_ARGS (QT_UINT32 (map.data + 4)));
8402 mode_set = QT_UINT16 (map.data + 13);
8404 if (mode_set == (wb ? AMR_WB_ALL_MODES : AMR_NB_ALL_MODES))
8405 max_mode = 7 + (wb ? 1 : 0);
8407 /* AMR-NB modes fo from 0-7, and AMR-WB modes go from 0-8 */
8408 max_mode = g_bit_nth_msf ((gulong) mode_set & (wb ? 0x1ff : 0xff), -1);
8410 if (max_mode == -1) {
8411 GST_DEBUG ("No mode indication was found (mode set) = %x",
8416 gst_buffer_unmap (buf, &map);
8417 return wb ? wb_bitrates[max_mode] : nb_bitrates[max_mode];
8420 gst_buffer_unmap (buf, &map);
8425 qtdemux_parse_transformation_matrix (GstQTDemux * qtdemux,
8426 GstByteReader * reader, guint32 * matrix, const gchar * atom)
8429 * 9 values of 32 bits (fixed point 16.16, except 2 5 and 8 that are 2.30)
8435 if (gst_byte_reader_get_remaining (reader) < 36)
8438 matrix[0] = gst_byte_reader_get_uint32_be_unchecked (reader);
8439 matrix[1] = gst_byte_reader_get_uint32_be_unchecked (reader);
8440 matrix[2] = gst_byte_reader_get_uint32_be_unchecked (reader);
8441 matrix[3] = gst_byte_reader_get_uint32_be_unchecked (reader);
8442 matrix[4] = gst_byte_reader_get_uint32_be_unchecked (reader);
8443 matrix[5] = gst_byte_reader_get_uint32_be_unchecked (reader);
8444 matrix[6] = gst_byte_reader_get_uint32_be_unchecked (reader);
8445 matrix[7] = gst_byte_reader_get_uint32_be_unchecked (reader);
8446 matrix[8] = gst_byte_reader_get_uint32_be_unchecked (reader);
8448 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix from atom %s", atom);
8449 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[0] >> 16,
8450 matrix[0] & 0xFFFF, matrix[1] >> 16, matrix[1] & 0xFF, matrix[2] >> 16,
8452 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[3] >> 16,
8453 matrix[3] & 0xFFFF, matrix[4] >> 16, matrix[4] & 0xFF, matrix[5] >> 16,
8455 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[6] >> 16,
8456 matrix[6] & 0xFFFF, matrix[7] >> 16, matrix[7] & 0xFF, matrix[8] >> 16,
8463 qtdemux_inspect_transformation_matrix (GstQTDemux * qtdemux,
8464 QtDemuxStream * stream, guint32 * matrix, GstTagList ** taglist)
8471 * This macro will only compare value abdegh, it expects cfi to have already
8474 #define QTCHECK_MATRIX(m,a,b,d,e) ((m)[0] == (a << 16) && (m)[1] == (b << 16) && \
8475 (m)[3] == (d << 16) && (m)[4] == (e << 16))
8477 /* only handle the cases where the last column has standard values */
8478 if (matrix[2] == 0 && matrix[5] == 0 && matrix[8] == 1 << 30) {
8479 const gchar *rotation_tag = NULL;
8481 /* no rotation needed */
8482 if (QTCHECK_MATRIX (matrix, 1, 0, 0, 1)) {
8484 } else if (QTCHECK_MATRIX (matrix, 0, 1, G_MAXUINT16, 0)) {
8485 rotation_tag = "rotate-90";
8486 } else if (QTCHECK_MATRIX (matrix, G_MAXUINT16, 0, 0, G_MAXUINT16)) {
8487 rotation_tag = "rotate-180";
8488 } else if (QTCHECK_MATRIX (matrix, 0, G_MAXUINT16, 1, 0)) {
8489 rotation_tag = "rotate-270";
8491 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
8494 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix rotation %s",
8496 if (rotation_tag != NULL) {
8497 if (*taglist == NULL)
8498 *taglist = gst_tag_list_new_empty ();
8499 gst_tag_list_add (*taglist, GST_TAG_MERGE_REPLACE,
8500 GST_TAG_IMAGE_ORIENTATION, rotation_tag, NULL);
8503 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
8507 /* Parses the boxes defined in ISO/IEC 14496-12 that enable support for
8508 * protected streams (sinf, frma, schm and schi); if the protection scheme is
8509 * Common Encryption (cenc), the function will also parse the tenc box (defined
8510 * in ISO/IEC 23001-7). @container points to the node that contains these boxes
8511 * (typically an enc[v|a|t|s] sample entry); the function will set
8512 * @original_fmt to the fourcc of the original unencrypted stream format.
8513 * Returns TRUE if successful; FALSE otherwise. */
8515 qtdemux_parse_protection_scheme_info (GstQTDemux * qtdemux,
8516 QtDemuxStream * stream, GNode * container, guint32 * original_fmt)
8523 g_return_val_if_fail (qtdemux != NULL, FALSE);
8524 g_return_val_if_fail (stream != NULL, FALSE);
8525 g_return_val_if_fail (container != NULL, FALSE);
8526 g_return_val_if_fail (original_fmt != NULL, FALSE);
8528 sinf = qtdemux_tree_get_child_by_type (container, FOURCC_sinf);
8529 if (G_UNLIKELY (!sinf)) {
8530 if (stream->protection_scheme_type == FOURCC_cenc) {
8531 GST_ERROR_OBJECT (qtdemux, "sinf box does not contain schi box, which is "
8532 "mandatory for Common Encryption");
8538 frma = qtdemux_tree_get_child_by_type (sinf, FOURCC_frma);
8539 if (G_UNLIKELY (!frma)) {
8540 GST_ERROR_OBJECT (qtdemux, "sinf box does not contain mandatory frma box");
8544 *original_fmt = QT_FOURCC ((const guint8 *) frma->data + 8);
8545 GST_DEBUG_OBJECT (qtdemux, "original stream format: '%" GST_FOURCC_FORMAT "'",
8546 GST_FOURCC_ARGS (*original_fmt));
8548 schm = qtdemux_tree_get_child_by_type (sinf, FOURCC_schm);
8550 GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schm box");
8553 stream->protection_scheme_type = QT_FOURCC ((const guint8 *) schm->data + 12);
8554 stream->protection_scheme_version =
8555 QT_UINT32 ((const guint8 *) schm->data + 16);
8557 GST_DEBUG_OBJECT (qtdemux,
8558 "protection_scheme_type: %" GST_FOURCC_FORMAT ", "
8559 "protection_scheme_version: %#010x",
8560 GST_FOURCC_ARGS (stream->protection_scheme_type),
8561 stream->protection_scheme_version);
8563 schi = qtdemux_tree_get_child_by_type (sinf, FOURCC_schi);
8565 GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schi box");
8568 if (stream->protection_scheme_type == FOURCC_cenc) {
8569 QtDemuxCencSampleSetInfo *info;
8571 const guint8 *tenc_data;
8572 guint32 isEncrypted;
8574 const guint8 *default_kid;
8577 if (G_UNLIKELY (!stream->protection_scheme_info))
8578 stream->protection_scheme_info =
8579 g_malloc0 (sizeof (QtDemuxCencSampleSetInfo));
8581 info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
8583 tenc = qtdemux_tree_get_child_by_type (schi, FOURCC_tenc);
8585 GST_ERROR_OBJECT (qtdemux, "schi box does not contain tenc box, "
8586 "which is mandatory for Common Encryption");
8589 tenc_data = (const guint8 *) tenc->data + 12;
8590 isEncrypted = QT_UINT24 (tenc_data);
8591 iv_size = QT_UINT8 (tenc_data + 3);
8592 default_kid = (tenc_data + 4);
8593 kid_buf = gst_buffer_new_allocate (NULL, 16, NULL);
8594 gst_buffer_fill (kid_buf, 0, default_kid, 16);
8595 if (info->default_properties)
8596 gst_structure_free (info->default_properties);
8597 info->default_properties =
8598 gst_structure_new ("application/x-cenc",
8599 "iv_size", G_TYPE_UINT, iv_size,
8600 "encrypted", G_TYPE_BOOLEAN, (isEncrypted == 1),
8601 "kid", GST_TYPE_BUFFER, kid_buf, NULL);
8602 GST_DEBUG_OBJECT (qtdemux, "default sample properties: "
8603 "is_encrypted=%u, iv_size=%u", isEncrypted, iv_size);
8604 gst_buffer_unref (kid_buf);
8610 * With each track we associate a new QtDemuxStream that contains all the info
8612 * traks that do not decode to something (like strm traks) will not have a pad.
8615 qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
8634 QtDemuxStream *stream = NULL;
8635 gboolean new_stream = FALSE;
8636 gchar *codec = NULL;
8637 const guint8 *stsd_data;
8638 guint16 lang_code; /* quicktime lang code or packed iso code */
8640 guint32 tkhd_flags = 0;
8641 guint8 tkhd_version = 0;
8643 guint value_size, stsd_len, len;
8647 GST_DEBUG_OBJECT (qtdemux, "parse_trak");
8649 if (!qtdemux_tree_get_child_by_type_full (trak, FOURCC_tkhd, &tkhd)
8650 || !gst_byte_reader_get_uint8 (&tkhd, &tkhd_version)
8651 || !gst_byte_reader_get_uint24_be (&tkhd, &tkhd_flags))
8654 /* pick between 64 or 32 bits */
8655 value_size = tkhd_version == 1 ? 8 : 4;
8656 if (!gst_byte_reader_skip (&tkhd, value_size * 2) ||
8657 !gst_byte_reader_get_uint32_be (&tkhd, &track_id))
8660 if (!qtdemux->got_moov) {
8661 if (qtdemux_find_stream (qtdemux, track_id))
8662 goto existing_stream;
8663 stream = _create_stream ();
8664 stream->track_id = track_id;
8667 stream = qtdemux_find_stream (qtdemux, track_id);
8669 GST_WARNING_OBJECT (qtdemux, "Stream not found, going to ignore it");
8673 /* flush samples data from this track from previous moov */
8674 gst_qtdemux_stream_flush_segments_data (qtdemux, stream);
8675 gst_qtdemux_stream_flush_samples_data (qtdemux, stream);
8677 /* need defaults for fragments */
8678 qtdemux_parse_trex (qtdemux, stream, &dummy, &dummy, &dummy);
8680 if (stream->pending_tags == NULL)
8681 stream->pending_tags = gst_tag_list_new_empty ();
8683 if ((tkhd_flags & 1) == 0)
8684 stream->disabled = TRUE;
8686 GST_LOG_OBJECT (qtdemux, "track[tkhd] version/flags/id: 0x%02x/%06x/%u",
8687 tkhd_version, tkhd_flags, stream->track_id);
8689 if (!(mdia = qtdemux_tree_get_child_by_type (trak, FOURCC_mdia)))
8692 if (!(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mdhd))) {
8693 /* be nice for some crooked mjp2 files that use mhdr for mdhd */
8694 if (qtdemux->major_brand != FOURCC_mjp2 ||
8695 !(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mhdr)))
8699 len = QT_UINT32 ((guint8 *) mdhd->data);
8700 version = QT_UINT32 ((guint8 *) mdhd->data + 8);
8701 GST_LOG_OBJECT (qtdemux, "track version/flags: %08x", version);
8702 if (version == 0x01000000) {
8705 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 28);
8706 stream->duration = QT_UINT64 ((guint8 *) mdhd->data + 32);
8707 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 36);
8711 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 20);
8712 stream->duration = QT_UINT32 ((guint8 *) mdhd->data + 24);
8713 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 28);
8716 if (lang_code < 0x400) {
8717 qtdemux_lang_map_qt_code_to_iso (stream->lang_id, lang_code);
8718 } else if (lang_code == 0x7fff) {
8719 stream->lang_id[0] = 0; /* unspecified */
8721 stream->lang_id[0] = 0x60 + ((lang_code >> 10) & 0x1F);
8722 stream->lang_id[1] = 0x60 + ((lang_code >> 5) & 0x1F);
8723 stream->lang_id[2] = 0x60 + (lang_code & 0x1F);
8724 stream->lang_id[3] = 0;
8727 GST_LOG_OBJECT (qtdemux, "track timescale: %" G_GUINT32_FORMAT,
8729 GST_LOG_OBJECT (qtdemux, "track duration: %" G_GUINT64_FORMAT,
8731 GST_LOG_OBJECT (qtdemux, "track language code/id: 0x%04x/%s",
8732 lang_code, stream->lang_id);
8734 if (G_UNLIKELY (stream->timescale == 0 || qtdemux->timescale == 0))
8737 if ((tref = qtdemux_tree_get_child_by_type (trak, FOURCC_tref))) {
8738 /* chapters track reference */
8739 GNode *chap = qtdemux_tree_get_child_by_type (tref, FOURCC_chap);
8741 gsize length = GST_READ_UINT32_BE (chap->data);
8742 if (qtdemux->chapters_track_id)
8743 GST_FIXME_OBJECT (qtdemux, "Multiple CHAP tracks");
8746 qtdemux->chapters_track_id =
8747 GST_READ_UINT32_BE ((gint8 *) chap->data + 8);
8752 /* fragmented files may have bogus duration in moov */
8753 if (!qtdemux->fragmented &&
8754 qtdemux->duration != G_MAXINT64 && stream->duration != G_MAXINT32) {
8755 guint64 tdur1, tdur2;
8757 /* don't overflow */
8758 tdur1 = stream->timescale * (guint64) qtdemux->duration;
8759 tdur2 = qtdemux->timescale * (guint64) stream->duration;
8762 * some of those trailers, nowadays, have prologue images that are
8763 * themselves vide tracks as well. I haven't really found a way to
8764 * identify those yet, except for just looking at their duration. */
8765 if (tdur1 != 0 && (tdur2 * 10 / tdur1) < 2) {
8766 GST_WARNING_OBJECT (qtdemux,
8767 "Track shorter than 20%% (%" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT
8768 " vs. %" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT ") of the stream "
8769 "found, assuming preview image or something; skipping track",
8770 stream->duration, stream->timescale, qtdemux->duration,
8771 qtdemux->timescale);
8773 gst_qtdemux_stream_free (qtdemux, stream);
8778 if (!(hdlr = qtdemux_tree_get_child_by_type (mdia, FOURCC_hdlr)))
8781 GST_LOG_OBJECT (qtdemux, "track type: %" GST_FOURCC_FORMAT,
8782 GST_FOURCC_ARGS (QT_FOURCC ((guint8 *) hdlr->data + 12)));
8784 len = QT_UINT32 ((guint8 *) hdlr->data);
8786 stream->subtype = QT_FOURCC ((guint8 *) hdlr->data + 16);
8787 GST_LOG_OBJECT (qtdemux, "track subtype: %" GST_FOURCC_FORMAT,
8788 GST_FOURCC_ARGS (stream->subtype));
8790 if (!(minf = qtdemux_tree_get_child_by_type (mdia, FOURCC_minf)))
8793 if (!(stbl = qtdemux_tree_get_child_by_type (minf, FOURCC_stbl)))
8796 /*parse svmi header if existing */
8797 svmi = qtdemux_tree_get_child_by_type (stbl, FOURCC_svmi);
8799 len = QT_UINT32 ((guint8 *) svmi->data);
8800 version = QT_UINT32 ((guint8 *) svmi->data + 8);
8802 GstVideoMultiviewMode mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
8803 GstVideoMultiviewFlags flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
8804 guint8 frame_type, frame_layout;
8806 /* MPEG-A stereo video */
8807 if (qtdemux->major_brand == FOURCC_ss02)
8808 flags |= GST_VIDEO_MULTIVIEW_FLAGS_MIXED_MONO;
8810 frame_type = QT_UINT8 ((guint8 *) svmi->data + 12);
8811 frame_layout = QT_UINT8 ((guint8 *) svmi->data + 13) & 0x01;
8812 switch (frame_type) {
8814 mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
8817 mode = GST_VIDEO_MULTIVIEW_MODE_ROW_INTERLEAVED;
8820 mode = GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME;
8823 /* mode 3 is primary/secondary view sequence, ie
8824 * left/right views in separate tracks. See section 7.2
8825 * of ISO/IEC 23000-11:2009 */
8826 GST_FIXME_OBJECT (qtdemux,
8827 "Implement stereo video in separate streams");
8830 if ((frame_layout & 0x1) == 0)
8831 flags |= GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
8833 GST_LOG_OBJECT (qtdemux,
8834 "StereoVideo: composition type: %u, is_left_first: %u",
8835 frame_type, frame_layout);
8836 stream->multiview_mode = mode;
8837 stream->multiview_flags = flags;
8842 if (!(stsd = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsd)))
8844 stsd_data = (const guint8 *) stsd->data;
8846 /* stsd should at least have one entry */
8847 stsd_len = QT_UINT32 (stsd_data);
8848 if (stsd_len < 24) {
8849 /* .. but skip stream with empty stsd produced by some Vivotek cameras */
8850 if (stream->subtype == FOURCC_vivo) {
8852 gst_qtdemux_stream_free (qtdemux, stream);
8859 GST_LOG_OBJECT (qtdemux, "stsd len: %d", stsd_len);
8861 /* and that entry should fit within stsd */
8862 len = QT_UINT32 (stsd_data + 16);
8863 if (len > stsd_len + 16)
8866 stream->fourcc = fourcc = QT_FOURCC (stsd_data + 16 + 4);
8867 GST_LOG_OBJECT (qtdemux, "stsd type: %" GST_FOURCC_FORMAT,
8868 GST_FOURCC_ARGS (stream->fourcc));
8869 GST_LOG_OBJECT (qtdemux, "stsd type len: %d", len);
8871 if ((fourcc == FOURCC_drms) || (fourcc == FOURCC_drmi))
8872 goto error_encrypted;
8874 if (fourcc == FOURCC_encv || fourcc == FOURCC_enca) {
8875 GNode *enc = qtdemux_tree_get_child_by_type (stsd, fourcc);
8876 stream->protected = TRUE;
8877 if (!qtdemux_parse_protection_scheme_info (qtdemux, stream, enc, &fourcc))
8878 GST_ERROR_OBJECT (qtdemux, "Failed to parse protection scheme info");
8881 if (stream->subtype == FOURCC_vide) {
8882 guint32 w = 0, h = 0;
8884 gint depth, palette_size, palette_count;
8886 guint32 *palette_data = NULL;
8888 stream->sampled = TRUE;
8890 /* version 1 uses some 64-bit ints */
8891 if (!gst_byte_reader_skip (&tkhd, 20 + value_size))
8894 if (!qtdemux_parse_transformation_matrix (qtdemux, &tkhd, matrix, "tkhd"))
8897 if (!gst_byte_reader_get_uint32_be (&tkhd, &w)
8898 || !gst_byte_reader_get_uint32_be (&tkhd, &h))
8901 stream->display_width = w >> 16;
8902 stream->display_height = h >> 16;
8904 qtdemux_inspect_transformation_matrix (qtdemux, stream, matrix,
8905 &stream->pending_tags);
8911 stream->width = QT_UINT16 (stsd_data + offset + 32);
8912 stream->height = QT_UINT16 (stsd_data + offset + 34);
8913 stream->fps_n = 0; /* this is filled in later */
8914 stream->fps_d = 0; /* this is filled in later */
8915 stream->bits_per_sample = QT_UINT16 (stsd_data + offset + 82);
8916 stream->color_table_id = QT_UINT16 (stsd_data + offset + 84);
8918 GST_LOG_OBJECT (qtdemux, "width %d, height %d, bps %d, color table id %d",
8919 stream->width, stream->height, stream->bits_per_sample,
8920 stream->color_table_id);
8922 depth = stream->bits_per_sample;
8924 /* more than 32 bits means grayscale */
8925 gray = (depth > 32);
8926 /* low 32 bits specify the depth */
8929 /* different number of palette entries is determined by depth. */
8931 if ((depth == 1) || (depth == 2) || (depth == 4) || (depth == 8))
8932 palette_count = (1 << depth);
8933 palette_size = palette_count * 4;
8935 if (stream->color_table_id) {
8936 switch (palette_count) {
8940 palette_data = g_memdup (ff_qt_default_palette_2, palette_size);
8943 palette_data = g_memdup (ff_qt_default_palette_4, palette_size);
8947 palette_data = g_memdup (ff_qt_grayscale_palette_16, palette_size);
8949 palette_data = g_memdup (ff_qt_default_palette_16, palette_size);
8953 palette_data = g_memdup (ff_qt_grayscale_palette_256, palette_size);
8955 palette_data = g_memdup (ff_qt_default_palette_256, palette_size);
8958 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
8959 (_("The video in this file might not play correctly.")),
8960 ("unsupported palette depth %d", depth));
8964 gint i, j, start, end;
8970 start = QT_UINT32 (stsd_data + offset + 86);
8971 palette_count = QT_UINT16 (stsd_data + offset + 90);
8972 end = QT_UINT16 (stsd_data + offset + 92);
8974 GST_LOG_OBJECT (qtdemux, "start %d, end %d, palette_count %d",
8975 start, end, palette_count);
8982 if (len < 94 + (end - start) * 8)
8985 /* palette is always the same size */
8986 palette_data = g_malloc0 (256 * 4);
8987 palette_size = 256 * 4;
8989 for (j = 0, i = start; i <= end; j++, i++) {
8992 a = QT_UINT16 (stsd_data + offset + 94 + (j * 8));
8993 r = QT_UINT16 (stsd_data + offset + 96 + (j * 8));
8994 g = QT_UINT16 (stsd_data + offset + 98 + (j * 8));
8995 b = QT_UINT16 (stsd_data + offset + 100 + (j * 8));
8997 palette_data[i] = ((a & 0xff00) << 16) | ((r & 0xff00) << 8) |
8998 (g & 0xff00) | (b >> 8);
9003 gst_caps_unref (stream->caps);
9006 qtdemux_video_caps (qtdemux, stream, fourcc, stsd_data, &codec);
9007 if (G_UNLIKELY (!stream->caps)) {
9008 g_free (palette_data);
9009 goto unknown_stream;
9013 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
9014 GST_TAG_VIDEO_CODEC, codec, NULL);
9023 if (stream->rgb8_palette)
9024 gst_memory_unref (stream->rgb8_palette);
9025 stream->rgb8_palette = gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY,
9026 palette_data, palette_size, 0, palette_size, palette_data, g_free);
9028 s = gst_caps_get_structure (stream->caps, 0);
9030 /* non-raw video has a palette_data property. raw video has the palette as
9031 * an extra plane that we append to the output buffers before we push
9033 if (!gst_structure_has_name (s, "video/x-raw")) {
9036 palette = gst_buffer_new ();
9037 gst_buffer_append_memory (palette, stream->rgb8_palette);
9038 stream->rgb8_palette = NULL;
9040 gst_caps_set_simple (stream->caps, "palette_data",
9041 GST_TYPE_BUFFER, palette, NULL);
9042 gst_buffer_unref (palette);
9044 } else if (palette_count != 0) {
9045 GST_ELEMENT_WARNING (qtdemux, STREAM, NOT_IMPLEMENTED,
9046 (NULL), ("Unsupported palette depth %d", depth));
9049 GST_LOG_OBJECT (qtdemux, "frame count: %u",
9050 QT_UINT16 (stsd_data + offset + 48));
9054 /* pick 'the' stsd child */
9055 if (!stream->protected)
9056 mp4v = qtdemux_tree_get_child_by_type (stsd, fourcc);
9058 mp4v = qtdemux_tree_get_child_by_type (stsd, FOURCC_encv);
9061 esds = qtdemux_tree_get_child_by_type (mp4v, FOURCC_esds);
9062 pasp = qtdemux_tree_get_child_by_type (mp4v, FOURCC_pasp);
9066 const guint8 *pasp_data = (const guint8 *) pasp->data;
9068 stream->par_w = QT_UINT32 (pasp_data + 8);
9069 stream->par_h = QT_UINT32 (pasp_data + 12);
9076 gst_qtdemux_handle_esds (qtdemux, stream, esds, stream->pending_tags);
9083 gint len = QT_UINT32 (stsd_data) - 0x66;
9084 const guint8 *avc_data = stsd_data + 0x66;
9087 while (len >= 0x8) {
9090 if (QT_UINT32 (avc_data) <= len)
9091 size = QT_UINT32 (avc_data) - 0x8;
9096 /* No real data, so break out */
9099 switch (QT_FOURCC (avc_data + 0x4)) {
9102 /* parse, if found */
9105 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
9107 /* First 4 bytes are the length of the atom, the next 4 bytes
9108 * are the fourcc, the next 1 byte is the version, and the
9109 * subsequent bytes are profile_tier_level structure like data. */
9110 gst_codec_utils_h264_caps_set_level_and_profile (stream->caps,
9111 avc_data + 8 + 1, size - 1);
9112 buf = gst_buffer_new_and_alloc (size);
9113 gst_buffer_fill (buf, 0, avc_data + 0x8, size);
9114 gst_caps_set_simple (stream->caps,
9115 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9116 gst_buffer_unref (buf);
9124 GST_DEBUG_OBJECT (qtdemux, "found strf codec_data in stsd");
9126 /* First 4 bytes are the length of the atom, the next 4 bytes
9127 * are the fourcc, next 40 bytes are BITMAPINFOHEADER,
9128 * next 1 byte is the version, and the
9129 * subsequent bytes are sequence parameter set like data. */
9131 size -= 40; /* we'll be skipping BITMAPINFOHEADER */
9133 gst_codec_utils_h264_caps_set_level_and_profile (stream->caps,
9134 avc_data + 8 + 40 + 1, size - 1);
9136 buf = gst_buffer_new_and_alloc (size);
9137 gst_buffer_fill (buf, 0, avc_data + 8 + 40, size);
9138 gst_caps_set_simple (stream->caps,
9139 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9140 gst_buffer_unref (buf);
9146 guint avg_bitrate, max_bitrate;
9148 /* bufferSizeDB, maxBitrate and avgBitrate - 4 bytes each */
9152 max_bitrate = QT_UINT32 (avc_data + 0xc);
9153 avg_bitrate = QT_UINT32 (avc_data + 0x10);
9155 if (!max_bitrate && !avg_bitrate)
9158 /* Some muxers seem to swap the average and maximum bitrates
9159 * (I'm looking at you, YouTube), so we swap for sanity. */
9160 if (max_bitrate > 0 && max_bitrate < avg_bitrate) {
9161 guint temp = avg_bitrate;
9163 avg_bitrate = max_bitrate;
9167 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
9168 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
9169 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
9171 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
9172 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
9173 GST_TAG_BITRATE, avg_bitrate, NULL);
9184 avc_data += size + 8;
9193 gint len = QT_UINT32 (stsd_data) - 0x66;
9194 const guint8 *hevc_data = stsd_data + 0x66;
9197 while (len >= 0x8) {
9200 if (QT_UINT32 (hevc_data) <= len)
9201 size = QT_UINT32 (hevc_data) - 0x8;
9206 /* No real data, so break out */
9209 switch (QT_FOURCC (hevc_data + 0x4)) {
9212 /* parse, if found */
9215 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
9217 /* First 4 bytes are the length of the atom, the next 4 bytes
9218 * are the fourcc, the next 1 byte is the version, and the
9219 * subsequent bytes are sequence parameter set like data. */
9220 gst_codec_utils_h265_caps_set_level_tier_and_profile
9221 (stream->caps, hevc_data + 8 + 1, size - 1);
9223 buf = gst_buffer_new_and_alloc (size);
9224 gst_buffer_fill (buf, 0, hevc_data + 0x8, size);
9225 gst_caps_set_simple (stream->caps,
9226 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9227 gst_buffer_unref (buf);
9234 hevc_data += size + 8;
9245 GST_DEBUG_OBJECT (qtdemux, "found %" GST_FOURCC_FORMAT,
9246 GST_FOURCC_ARGS (fourcc));
9248 /* codec data might be in glbl extension atom */
9250 qtdemux_tree_get_child_by_type (mp4v, FOURCC_glbl) : NULL;
9256 GST_DEBUG_OBJECT (qtdemux, "found glbl data in stsd");
9258 len = QT_UINT32 (data);
9261 buf = gst_buffer_new_and_alloc (len);
9262 gst_buffer_fill (buf, 0, data + 8, len);
9263 gst_caps_set_simple (stream->caps,
9264 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9265 gst_buffer_unref (buf);
9272 /* see annex I of the jpeg2000 spec */
9273 GNode *jp2h, *ihdr, *colr, *mjp2, *field, *prefix, *cmap, *cdef;
9275 const gchar *colorspace = NULL;
9277 guint32 ncomp_map = 0;
9278 gint32 *comp_map = NULL;
9279 guint32 nchan_def = 0;
9280 gint32 *chan_def = NULL;
9282 GST_DEBUG_OBJECT (qtdemux, "found mjp2");
9283 /* some required atoms */
9284 mjp2 = qtdemux_tree_get_child_by_type (stsd, FOURCC_mjp2);
9287 jp2h = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2h);
9291 /* number of components; redundant with info in codestream, but useful
9293 ihdr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_ihdr);
9294 if (!ihdr || QT_UINT32 (ihdr->data) != 22)
9296 ncomp = QT_UINT16 (((guint8 *) ihdr->data) + 16);
9298 colr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_colr);
9301 GST_DEBUG_OBJECT (qtdemux, "found colr");
9302 /* extract colour space info */
9303 if (QT_UINT8 ((guint8 *) colr->data + 8) == 1) {
9304 switch (QT_UINT32 ((guint8 *) colr->data + 11)) {
9306 colorspace = "sRGB";
9309 colorspace = "GRAY";
9312 colorspace = "sYUV";
9320 /* colr is required, and only values 16, 17, and 18 are specified,
9321 so error if we have no colorspace */
9324 /* extract component mapping */
9325 cmap = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cmap);
9327 guint32 cmap_len = 0;
9329 cmap_len = QT_UINT32 (cmap->data);
9330 if (cmap_len >= 8) {
9331 /* normal box, subtract off header */
9333 /* cmap: { u16 cmp; u8 mtyp; u8 pcol; }* */
9334 if (cmap_len % 4 == 0) {
9335 ncomp_map = (cmap_len / 4);
9336 comp_map = g_new0 (gint32, ncomp_map);
9337 for (i = 0; i < ncomp_map; i++) {
9340 cmp = QT_UINT16 (((guint8 *) cmap->data) + 8 + i * 4);
9341 mtyp = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 2);
9342 pcol = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 3);
9343 comp_map[i] = (mtyp << 24) | (pcol << 16) | cmp;
9348 /* extract channel definitions */
9349 cdef = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cdef);
9351 guint32 cdef_len = 0;
9353 cdef_len = QT_UINT32 (cdef->data);
9354 if (cdef_len >= 10) {
9355 /* normal box, subtract off header and len */
9357 /* cdef: u16 n; { u16 cn; u16 typ; u16 asoc; }* */
9358 if (cdef_len % 6 == 0) {
9359 nchan_def = (cdef_len / 6);
9360 chan_def = g_new0 (gint32, nchan_def);
9361 for (i = 0; i < nchan_def; i++)
9363 for (i = 0; i < nchan_def; i++) {
9364 guint16 cn, typ, asoc;
9365 cn = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6);
9366 typ = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 2);
9367 asoc = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 4);
9368 if (cn < nchan_def) {
9371 chan_def[cn] = asoc;
9374 chan_def[cn] = 0; /* alpha */
9377 chan_def[cn] = -typ;
9385 gst_caps_set_simple (stream->caps,
9386 "num-components", G_TYPE_INT, ncomp, NULL);
9387 gst_caps_set_simple (stream->caps,
9388 "colorspace", G_TYPE_STRING, colorspace, NULL);
9391 GValue arr = { 0, };
9392 GValue elt = { 0, };
9394 g_value_init (&arr, GST_TYPE_ARRAY);
9395 g_value_init (&elt, G_TYPE_INT);
9396 for (i = 0; i < ncomp_map; i++) {
9397 g_value_set_int (&elt, comp_map[i]);
9398 gst_value_array_append_value (&arr, &elt);
9400 gst_structure_set_value (gst_caps_get_structure (stream->caps, 0),
9401 "component-map", &arr);
9402 g_value_unset (&elt);
9403 g_value_unset (&arr);
9408 GValue arr = { 0, };
9409 GValue elt = { 0, };
9411 g_value_init (&arr, GST_TYPE_ARRAY);
9412 g_value_init (&elt, G_TYPE_INT);
9413 for (i = 0; i < nchan_def; i++) {
9414 g_value_set_int (&elt, chan_def[i]);
9415 gst_value_array_append_value (&arr, &elt);
9417 gst_structure_set_value (gst_caps_get_structure (stream->caps, 0),
9418 "channel-definitions", &arr);
9419 g_value_unset (&elt);
9420 g_value_unset (&arr);
9424 /* some optional atoms */
9425 field = qtdemux_tree_get_child_by_type (mjp2, FOURCC_fiel);
9426 prefix = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2x);
9428 /* indicate possible fields in caps */
9430 data = (guint8 *) field->data + 8;
9432 gst_caps_set_simple (stream->caps, "fields", G_TYPE_INT,
9433 (gint) * data, NULL);
9435 /* add codec_data if provided */
9440 GST_DEBUG_OBJECT (qtdemux, "found prefix data in stsd");
9441 data = prefix->data;
9442 len = QT_UINT32 (data);
9445 buf = gst_buffer_new_and_alloc (len);
9446 gst_buffer_fill (buf, 0, data + 8, len);
9447 gst_caps_set_simple (stream->caps,
9448 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9449 gst_buffer_unref (buf);
9458 GstBuffer *seqh = NULL;
9459 guint8 *gamma_data = NULL;
9460 gint len = QT_UINT32 (stsd_data);
9462 qtdemux_parse_svq3_stsd_data (qtdemux, stsd, &gamma_data, &seqh);
9464 gst_caps_set_simple (stream->caps, "applied-gamma", G_TYPE_DOUBLE,
9465 QT_FP32 (gamma_data), NULL);
9468 /* sorry for the bad name, but we don't know what this is, other
9469 * than its own fourcc */
9470 gst_caps_set_simple (stream->caps, "seqh", GST_TYPE_BUFFER, seqh,
9474 GST_DEBUG_OBJECT (qtdemux, "found codec_data in stsd");
9475 buf = gst_buffer_new_and_alloc (len);
9476 gst_buffer_fill (buf, 0, stsd_data, len);
9477 gst_caps_set_simple (stream->caps,
9478 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9479 gst_buffer_unref (buf);
9485 gst_caps_set_simple (stream->caps,
9486 "depth", G_TYPE_INT, QT_UINT16 (stsd_data + offset + 82), NULL);
9493 GST_DEBUG_OBJECT (qtdemux, "found XiTh");
9494 xith = qtdemux_tree_get_child_by_type (stsd, FOURCC_XiTh);
9498 xdxt = qtdemux_tree_get_child_by_type (xith, FOURCC_XdxT);
9502 GST_DEBUG_OBJECT (qtdemux, "found XdxT node");
9503 /* collect the headers and store them in a stream list so that we can
9504 * send them out first */
9505 qtdemux_parse_theora_extension (qtdemux, stream, xdxt);
9515 GST_DEBUG_OBJECT (qtdemux, "parse ovc1 header");
9516 ovc1 = qtdemux_tree_get_child_by_type (stsd, FOURCC_ovc1);
9519 ovc1_data = ovc1->data;
9520 ovc1_len = QT_UINT32 (ovc1_data);
9521 if (ovc1_len <= 198) {
9522 GST_WARNING_OBJECT (qtdemux, "Too small ovc1 header, skipping");
9525 buf = gst_buffer_new_and_alloc (ovc1_len - 198);
9526 gst_buffer_fill (buf, 0, ovc1_data + 198, ovc1_len - 198);
9527 gst_caps_set_simple (stream->caps,
9528 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9529 gst_buffer_unref (buf);
9534 gint len = QT_UINT32 (stsd_data) - 0x66;
9535 const guint8 *vc1_data = stsd_data + 0x66;
9541 if (QT_UINT32 (vc1_data) <= len)
9542 size = QT_UINT32 (vc1_data) - 8;
9547 /* No real data, so break out */
9550 switch (QT_FOURCC (vc1_data + 0x4)) {
9551 case GST_MAKE_FOURCC ('d', 'v', 'c', '1'):
9555 GST_DEBUG_OBJECT (qtdemux, "found dvc1 codec_data in stsd");
9556 buf = gst_buffer_new_and_alloc (size);
9557 gst_buffer_fill (buf, 0, vc1_data + 8, size);
9558 gst_caps_set_simple (stream->caps,
9559 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9560 gst_buffer_unref (buf);
9567 vc1_data += size + 8;
9576 GST_INFO_OBJECT (qtdemux,
9577 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
9578 GST_FOURCC_ARGS (fourcc), stream->caps);
9580 } else if (stream->subtype == FOURCC_soun) {
9581 int version, samplesize;
9582 guint16 compression_id;
9583 gboolean amrwb = FALSE;
9586 /* sample description entry (16) + sound sample description v0 (20) */
9590 version = QT_UINT32 (stsd_data + offset);
9591 stream->n_channels = QT_UINT16 (stsd_data + offset + 8);
9592 samplesize = QT_UINT16 (stsd_data + offset + 10);
9593 compression_id = QT_UINT16 (stsd_data + offset + 12);
9594 stream->rate = QT_FP32 (stsd_data + offset + 16);
9596 GST_LOG_OBJECT (qtdemux, "version/rev: %08x", version);
9597 GST_LOG_OBJECT (qtdemux, "vendor: %08x",
9598 QT_UINT32 (stsd_data + offset + 4));
9599 GST_LOG_OBJECT (qtdemux, "n_channels: %d", stream->n_channels);
9600 GST_LOG_OBJECT (qtdemux, "sample_size: %d", samplesize);
9601 GST_LOG_OBJECT (qtdemux, "compression_id: %d", compression_id);
9602 GST_LOG_OBJECT (qtdemux, "packet size: %d",
9603 QT_UINT16 (stsd_data + offset + 14));
9604 GST_LOG_OBJECT (qtdemux, "sample rate: %g", stream->rate);
9606 if (compression_id == 0xfffe)
9607 stream->sampled = TRUE;
9609 /* first assume uncompressed audio */
9610 stream->bytes_per_sample = samplesize / 8;
9611 stream->samples_per_frame = stream->n_channels;
9612 stream->bytes_per_frame = stream->n_channels * stream->bytes_per_sample;
9613 stream->samples_per_packet = stream->samples_per_frame;
9614 stream->bytes_per_packet = stream->bytes_per_sample;
9618 /* Yes, these have to be hard-coded */
9621 stream->samples_per_packet = 6;
9622 stream->bytes_per_packet = 1;
9623 stream->bytes_per_frame = 1 * stream->n_channels;
9624 stream->bytes_per_sample = 1;
9625 stream->samples_per_frame = 6 * stream->n_channels;
9630 stream->samples_per_packet = 3;
9631 stream->bytes_per_packet = 1;
9632 stream->bytes_per_frame = 1 * stream->n_channels;
9633 stream->bytes_per_sample = 1;
9634 stream->samples_per_frame = 3 * stream->n_channels;
9639 stream->samples_per_packet = 64;
9640 stream->bytes_per_packet = 34;
9641 stream->bytes_per_frame = 34 * stream->n_channels;
9642 stream->bytes_per_sample = 2;
9643 stream->samples_per_frame = 64 * stream->n_channels;
9649 stream->samples_per_packet = 1;
9650 stream->bytes_per_packet = 1;
9651 stream->bytes_per_frame = 1 * stream->n_channels;
9652 stream->bytes_per_sample = 1;
9653 stream->samples_per_frame = 1 * stream->n_channels;
9658 stream->samples_per_packet = 160;
9659 stream->bytes_per_packet = 33;
9660 stream->bytes_per_frame = 33 * stream->n_channels;
9661 stream->bytes_per_sample = 2;
9662 stream->samples_per_frame = 160 * stream->n_channels;
9669 if (version == 0x00010000) {
9670 /* sample description entry (16) + sound sample description v1 (20+16) */
9681 /* only parse extra decoding config for non-pcm audio */
9682 stream->samples_per_packet = QT_UINT32 (stsd_data + offset);
9683 stream->bytes_per_packet = QT_UINT32 (stsd_data + offset + 4);
9684 stream->bytes_per_frame = QT_UINT32 (stsd_data + offset + 8);
9685 stream->bytes_per_sample = QT_UINT32 (stsd_data + offset + 12);
9687 GST_LOG_OBJECT (qtdemux, "samples/packet: %d",
9688 stream->samples_per_packet);
9689 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
9690 stream->bytes_per_packet);
9691 GST_LOG_OBJECT (qtdemux, "bytes/frame: %d",
9692 stream->bytes_per_frame);
9693 GST_LOG_OBJECT (qtdemux, "bytes/sample: %d",
9694 stream->bytes_per_sample);
9696 if (!stream->sampled && stream->bytes_per_packet) {
9697 stream->samples_per_frame = (stream->bytes_per_frame /
9698 stream->bytes_per_packet) * stream->samples_per_packet;
9699 GST_LOG_OBJECT (qtdemux, "samples/frame: %d",
9700 stream->samples_per_frame);
9705 } else if (version == 0x00020000) {
9712 /* sample description entry (16) + sound sample description v2 (56) */
9716 qtfp.val = QT_UINT64 (stsd_data + offset + 4);
9717 stream->rate = qtfp.fp;
9718 stream->n_channels = QT_UINT32 (stsd_data + offset + 12);
9720 GST_LOG_OBJECT (qtdemux, "Sound sample description Version 2");
9721 GST_LOG_OBJECT (qtdemux, "sample rate: %g", stream->rate);
9722 GST_LOG_OBJECT (qtdemux, "n_channels: %d", stream->n_channels);
9723 GST_LOG_OBJECT (qtdemux, "bits/channel: %d",
9724 QT_UINT32 (stsd_data + offset + 20));
9725 GST_LOG_OBJECT (qtdemux, "format flags: %X",
9726 QT_UINT32 (stsd_data + offset + 24));
9727 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
9728 QT_UINT32 (stsd_data + offset + 28));
9729 GST_LOG_OBJECT (qtdemux, "LPCM frames/packet: %d",
9730 QT_UINT32 (stsd_data + offset + 32));
9731 } else if (version != 0x00000) {
9732 GST_WARNING_OBJECT (qtdemux, "unknown audio STSD version %08x", version);
9736 gst_caps_unref (stream->caps);
9738 stream->caps = qtdemux_audio_caps (qtdemux, stream, fourcc,
9739 stsd_data + 32, len - 16, &codec);
9747 in24 = qtdemux_tree_get_child_by_type (stsd, FOURCC_in24);
9749 enda = qtdemux_tree_get_child_by_type (in24, FOURCC_enda);
9751 wave = qtdemux_tree_get_child_by_type (in24, FOURCC_wave);
9753 enda = qtdemux_tree_get_child_by_type (wave, FOURCC_enda);
9756 int enda_value = QT_UINT16 ((guint8 *) enda->data + 8);
9757 gst_caps_set_simple (stream->caps,
9758 "format", G_TYPE_STRING, (enda_value) ? "S24LE" : "S24BE", NULL);
9765 const guint8 *owma_data;
9766 const gchar *codec_name = NULL;
9770 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
9771 /* FIXME this should also be gst_riff_strf_auds,
9772 * but the latter one is actually missing bits-per-sample :( */
9777 gint32 nSamplesPerSec;
9778 gint32 nAvgBytesPerSec;
9780 gint16 wBitsPerSample;
9785 GST_DEBUG_OBJECT (qtdemux, "parse owma");
9786 owma = qtdemux_tree_get_child_by_type (stsd, FOURCC_owma);
9789 owma_data = owma->data;
9790 owma_len = QT_UINT32 (owma_data);
9791 if (owma_len <= 54) {
9792 GST_WARNING_OBJECT (qtdemux, "Too small owma header, skipping");
9795 wfex = (WAVEFORMATEX *) (owma_data + 36);
9796 buf = gst_buffer_new_and_alloc (owma_len - 54);
9797 gst_buffer_fill (buf, 0, owma_data + 54, owma_len - 54);
9798 if (wfex->wFormatTag == 0x0161) {
9799 codec_name = "Windows Media Audio";
9801 } else if (wfex->wFormatTag == 0x0162) {
9802 codec_name = "Windows Media Audio 9 Pro";
9804 } else if (wfex->wFormatTag == 0x0163) {
9805 codec_name = "Windows Media Audio 9 Lossless";
9806 /* is that correct? gstffmpegcodecmap.c is missing it, but
9807 * fluendo codec seems to support it */
9811 gst_caps_set_simple (stream->caps,
9812 "codec_data", GST_TYPE_BUFFER, buf,
9813 "wmaversion", G_TYPE_INT, version,
9814 "block_align", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->nBlockAlign),
9815 "bitrate", G_TYPE_INT, GST_READ_UINT32_LE (&wfex->nAvgBytesPerSec),
9816 "width", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->wBitsPerSample),
9817 "depth", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->wBitsPerSample),
9819 gst_buffer_unref (buf);
9823 codec = g_strdup (codec_name);
9829 gint len = QT_UINT32 (stsd_data) - offset;
9830 const guint8 *wfex_data = stsd_data + offset;
9831 const gchar *codec_name = NULL;
9833 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
9834 /* FIXME this should also be gst_riff_strf_auds,
9835 * but the latter one is actually missing bits-per-sample :( */
9840 gint32 nSamplesPerSec;
9841 gint32 nAvgBytesPerSec;
9843 gint16 wBitsPerSample;
9848 /* FIXME: unify with similar wavformatex parsing code above */
9849 GST_DEBUG_OBJECT (qtdemux, "parse wma, looking for wfex");
9855 if (QT_UINT32 (wfex_data) <= len)
9856 size = QT_UINT32 (wfex_data) - 8;
9861 /* No real data, so break out */
9864 switch (QT_FOURCC (wfex_data + 4)) {
9865 case GST_MAKE_FOURCC ('w', 'f', 'e', 'x'):
9867 GST_DEBUG_OBJECT (qtdemux, "found wfex in stsd");
9872 wfex.wFormatTag = GST_READ_UINT16_LE (wfex_data + 8 + 0);
9873 wfex.nChannels = GST_READ_UINT16_LE (wfex_data + 8 + 2);
9874 wfex.nSamplesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 4);
9875 wfex.nAvgBytesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 8);
9876 wfex.nBlockAlign = GST_READ_UINT16_LE (wfex_data + 8 + 12);
9877 wfex.wBitsPerSample = GST_READ_UINT16_LE (wfex_data + 8 + 14);
9878 wfex.cbSize = GST_READ_UINT16_LE (wfex_data + 8 + 16);
9880 GST_LOG_OBJECT (qtdemux, "Found wfex box in stsd:");
9881 GST_LOG_OBJECT (qtdemux, "FormatTag = 0x%04x, Channels = %u, "
9882 "SamplesPerSec = %u, AvgBytesPerSec = %u, BlockAlign = %u, "
9883 "BitsPerSample = %u, Size = %u", wfex.wFormatTag,
9884 wfex.nChannels, wfex.nSamplesPerSec, wfex.nAvgBytesPerSec,
9885 wfex.nBlockAlign, wfex.wBitsPerSample, wfex.cbSize);
9887 if (wfex.wFormatTag == 0x0161) {
9888 codec_name = "Windows Media Audio";
9890 } else if (wfex.wFormatTag == 0x0162) {
9891 codec_name = "Windows Media Audio 9 Pro";
9893 } else if (wfex.wFormatTag == 0x0163) {
9894 codec_name = "Windows Media Audio 9 Lossless";
9895 /* is that correct? gstffmpegcodecmap.c is missing it, but
9896 * fluendo codec seems to support it */
9900 gst_caps_set_simple (stream->caps,
9901 "wmaversion", G_TYPE_INT, version,
9902 "block_align", G_TYPE_INT, wfex.nBlockAlign,
9903 "bitrate", G_TYPE_INT, wfex.nAvgBytesPerSec,
9904 "width", G_TYPE_INT, wfex.wBitsPerSample,
9905 "depth", G_TYPE_INT, wfex.wBitsPerSample, NULL);
9907 if (size > wfex.cbSize) {
9910 buf = gst_buffer_new_and_alloc (size - wfex.cbSize);
9911 gst_buffer_fill (buf, 0, wfex_data + 8 + wfex.cbSize,
9912 size - wfex.cbSize);
9913 gst_caps_set_simple (stream->caps,
9914 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9915 gst_buffer_unref (buf);
9917 GST_WARNING_OBJECT (qtdemux, "no codec data");
9922 codec = g_strdup (codec_name);
9930 wfex_data += size + 8;
9937 const guint8 *opus_data;
9938 guint8 *channel_mapping = NULL;
9941 guint8 channel_mapping_family;
9942 guint8 stream_count;
9943 guint8 coupled_count;
9946 opus = qtdemux_tree_get_child_by_type (stsd, FOURCC_opus);
9947 opus_data = opus->data;
9949 channels = GST_READ_UINT8 (opus_data + 45);
9950 rate = GST_READ_UINT32_LE (opus_data + 48);
9951 channel_mapping_family = GST_READ_UINT8 (opus_data + 54);
9952 stream_count = GST_READ_UINT8 (opus_data + 55);
9953 coupled_count = GST_READ_UINT8 (opus_data + 56);
9956 channel_mapping = g_malloc (channels * sizeof (guint8));
9957 for (i = 0; i < channels; i++)
9958 channel_mapping[i] = GST_READ_UINT8 (opus_data + i + 57);
9961 stream->caps = gst_codec_utils_opus_create_caps (rate, channels,
9962 channel_mapping_family, stream_count, coupled_count,
9974 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
9975 GST_TAG_AUDIO_CODEC, codec, NULL);
9979 /* some bitrate info may have ended up in caps */
9980 s = gst_caps_get_structure (stream->caps, 0);
9981 gst_structure_get_int (s, "bitrate", &bitrate);
9983 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
9984 GST_TAG_BITRATE, bitrate, NULL);
9987 if (stream->protected && fourcc == FOURCC_mp4a)
9988 mp4a = qtdemux_tree_get_child_by_type (stsd, FOURCC_enca);
9990 mp4a = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4a);
9995 wave = qtdemux_tree_get_child_by_type (mp4a, FOURCC_wave);
9997 esds = qtdemux_tree_get_child_by_type (wave, FOURCC_esds);
9999 esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
10003 /* If the fourcc's bottom 16 bits gives 'sm', then the top
10004 16 bits is a byte-swapped wave-style codec identifier,
10005 and we can find a WAVE header internally to a 'wave' atom here.
10006 This can more clearly be thought of as 'ms' as the top 16 bits, and a
10007 codec id as the bottom 16 bits - but byte-swapped to store in QT (which
10010 if ((fourcc & 0xffff) == (('s' << 8) | 'm')) {
10011 if (len < offset + 20) {
10012 GST_WARNING_OBJECT (qtdemux, "No wave atom in MS-style audio");
10014 guint32 datalen = QT_UINT32 (stsd_data + offset + 16);
10015 const guint8 *data = stsd_data + offset + 16;
10017 GNode *waveheadernode;
10019 wavenode = g_node_new ((guint8 *) data);
10020 if (qtdemux_parse_node (qtdemux, wavenode, data, datalen)) {
10021 const guint8 *waveheader;
10024 waveheadernode = qtdemux_tree_get_child_by_type (wavenode, fourcc);
10025 if (waveheadernode) {
10026 waveheader = (const guint8 *) waveheadernode->data;
10027 headerlen = QT_UINT32 (waveheader);
10029 if (headerlen > 8) {
10030 gst_riff_strf_auds *header = NULL;
10031 GstBuffer *headerbuf;
10037 headerbuf = gst_buffer_new_and_alloc (headerlen);
10038 gst_buffer_fill (headerbuf, 0, waveheader, headerlen);
10040 if (gst_riff_parse_strf_auds (GST_ELEMENT_CAST (qtdemux),
10041 headerbuf, &header, &extra)) {
10042 gst_caps_unref (stream->caps);
10043 /* FIXME: Need to do something with the channel reorder map */
10044 stream->caps = gst_riff_create_audio_caps (header->format, NULL,
10045 header, extra, NULL, NULL, NULL);
10048 gst_buffer_unref (extra);
10053 GST_DEBUG ("Didn't find waveheadernode for this codec");
10055 g_node_destroy (wavenode);
10058 gst_qtdemux_handle_esds (qtdemux, stream, esds, stream->pending_tags);
10062 /* FIXME: what is in the chunk? */
10065 gint len = QT_UINT32 (stsd_data);
10067 /* seems to be always = 116 = 0x74 */
10073 gint len = QT_UINT32 (stsd_data);
10076 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x4C);
10078 gst_buffer_fill (buf, 0, stsd_data + 0x4C, len - 0x4C);
10079 gst_caps_set_simple (stream->caps,
10080 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10081 gst_buffer_unref (buf);
10083 gst_caps_set_simple (stream->caps,
10084 "samplesize", G_TYPE_INT, samplesize, NULL);
10089 GNode *alac, *wave = NULL;
10091 /* apparently, m4a has this atom appended directly in the stsd entry,
10092 * while mov has it in a wave atom */
10093 alac = qtdemux_tree_get_child_by_type (stsd, FOURCC_alac);
10095 /* alac now refers to stsd entry atom */
10096 wave = qtdemux_tree_get_child_by_type (alac, FOURCC_wave);
10098 alac = qtdemux_tree_get_child_by_type (wave, FOURCC_alac);
10100 alac = qtdemux_tree_get_child_by_type (alac, FOURCC_alac);
10103 const guint8 *alac_data = alac->data;
10104 gint len = QT_UINT32 (alac->data);
10108 GST_DEBUG_OBJECT (qtdemux,
10109 "discarding alac atom with unexpected len %d", len);
10111 /* codec-data contains alac atom size and prefix,
10112 * ffmpeg likes it that way, not quite gst-ish though ...*/
10113 buf = gst_buffer_new_and_alloc (len);
10114 gst_buffer_fill (buf, 0, alac->data, len);
10115 gst_caps_set_simple (stream->caps,
10116 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10117 gst_buffer_unref (buf);
10119 stream->bytes_per_frame = QT_UINT32 (alac_data + 12);
10120 stream->n_channels = QT_UINT8 (alac_data + 21);
10121 stream->rate = QT_UINT32 (alac_data + 32);
10124 gst_caps_set_simple (stream->caps,
10125 "samplesize", G_TYPE_INT, samplesize, NULL);
10133 gint len = QT_UINT32 (stsd_data);
10136 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x34);
10139 gst_buffer_fill (buf, 0, stsd_data + 0x34, len - 0x34);
10141 /* If we have enough data, let's try to get the 'damr' atom. See
10142 * the 3GPP container spec (26.244) for more details. */
10143 if ((len - 0x34) > 8 &&
10144 (bitrate = qtdemux_parse_amr_bitrate (buf, amrwb))) {
10145 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
10146 GST_TAG_MAXIMUM_BITRATE, bitrate, NULL);
10149 gst_caps_set_simple (stream->caps,
10150 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10151 gst_buffer_unref (buf);
10157 /* mp4a atom withtout ESDS; Attempt to build codec data from atom */
10158 gint len = QT_UINT32 (stsd_data);
10161 guint16 sound_version = QT_UINT16 (stsd_data + 32);
10163 if (sound_version == 1) {
10164 guint16 channels = QT_UINT16 (stsd_data + 40);
10165 guint32 time_scale = QT_UINT32 (stsd_data + 46);
10166 guint8 codec_data[2];
10168 gint profile = 2; /* FIXME: Can this be determined somehow? There doesn't seem to be anything in mp4a atom that specifis compression */
10170 gint sample_rate_index =
10171 gst_codec_utils_aac_get_index_from_sample_rate (time_scale);
10173 /* build AAC codec data */
10174 codec_data[0] = profile << 3;
10175 codec_data[0] |= ((sample_rate_index >> 1) & 0x7);
10176 codec_data[1] = (sample_rate_index & 0x01) << 7;
10177 codec_data[1] |= (channels & 0xF) << 3;
10179 buf = gst_buffer_new_and_alloc (2);
10180 gst_buffer_fill (buf, 0, codec_data, 2);
10181 gst_caps_set_simple (stream->caps,
10182 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10183 gst_buffer_unref (buf);
10189 GST_INFO_OBJECT (qtdemux,
10190 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
10194 GST_INFO_OBJECT (qtdemux,
10195 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
10196 GST_FOURCC_ARGS (fourcc), stream->caps);
10198 } else if (stream->subtype == FOURCC_strm) {
10199 if (fourcc == FOURCC_rtsp) {
10200 stream->redirect_uri = qtdemux_get_rtsp_uri_from_hndl (qtdemux, minf);
10202 GST_INFO_OBJECT (qtdemux, "unhandled stream type %" GST_FOURCC_FORMAT,
10203 GST_FOURCC_ARGS (fourcc));
10204 goto unknown_stream;
10206 stream->sampled = TRUE;
10207 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
10208 || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt) {
10210 stream->sampled = TRUE;
10211 stream->sparse = TRUE;
10214 qtdemux_sub_caps (qtdemux, stream, fourcc, stsd_data, &codec);
10216 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
10217 GST_TAG_SUBTITLE_CODEC, codec, NULL);
10222 /* hunt for sort-of codec data */
10226 GNode *mp4s = NULL;
10227 GNode *esds = NULL;
10229 /* look for palette in a stsd->mp4s->esds sub-atom */
10230 mp4s = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4s);
10232 esds = qtdemux_tree_get_child_by_type (mp4s, FOURCC_esds);
10233 if (esds == NULL) {
10235 GST_LOG_OBJECT (qtdemux, "Skipping invalid stsd: no esds child");
10239 gst_qtdemux_handle_esds (qtdemux, stream, esds, stream->pending_tags);
10243 GST_INFO_OBJECT (qtdemux,
10244 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
10247 GST_INFO_OBJECT (qtdemux,
10248 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
10249 GST_FOURCC_ARGS (fourcc), stream->caps);
10251 /* everything in 1 sample */
10252 stream->sampled = TRUE;
10255 qtdemux_generic_caps (qtdemux, stream, fourcc, stsd_data, &codec);
10257 if (stream->caps == NULL)
10258 goto unknown_stream;
10261 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
10262 GST_TAG_SUBTITLE_CODEC, codec, NULL);
10268 /* promote to sampled format */
10269 if (stream->fourcc == FOURCC_samr) {
10270 /* force mono 8000 Hz for AMR */
10271 stream->sampled = TRUE;
10272 stream->n_channels = 1;
10273 stream->rate = 8000;
10274 } else if (stream->fourcc == FOURCC_sawb) {
10275 /* force mono 16000 Hz for AMR-WB */
10276 stream->sampled = TRUE;
10277 stream->n_channels = 1;
10278 stream->rate = 16000;
10279 } else if (stream->fourcc == FOURCC_mp4a) {
10280 stream->sampled = TRUE;
10283 /* collect sample information */
10284 if (!qtdemux_stbl_init (qtdemux, stream, stbl))
10285 goto samples_failed;
10287 if (qtdemux->fragmented) {
10290 /* need all moov samples as basis; probably not many if any at all */
10291 /* prevent moof parsing taking of at this time */
10292 offset = qtdemux->moof_offset;
10293 qtdemux->moof_offset = 0;
10294 if (stream->n_samples &&
10295 !qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
10296 qtdemux->moof_offset = offset;
10297 goto samples_failed;
10299 qtdemux->moof_offset = 0;
10300 /* movie duration more reliable in this case (e.g. mehd) */
10301 if (qtdemux->segment.duration &&
10302 GST_CLOCK_TIME_IS_VALID (qtdemux->segment.duration))
10304 GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->segment.duration);
10307 /* configure segments */
10308 if (!qtdemux_parse_segments (qtdemux, stream, trak))
10309 goto segments_failed;
10311 /* add some language tag, if useful */
10312 if (stream->lang_id[0] != '\0' && strcmp (stream->lang_id, "unk") &&
10313 strcmp (stream->lang_id, "und")) {
10314 const gchar *lang_code;
10316 /* convert ISO 639-2 code to ISO 639-1 */
10317 lang_code = gst_tag_get_language_code (stream->lang_id);
10318 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
10319 GST_TAG_LANGUAGE_CODE, (lang_code) ? lang_code : stream->lang_id, NULL);
10322 /* Check for UDTA tags */
10323 if ((udta = qtdemux_tree_get_child_by_type (trak, FOURCC_udta))) {
10324 qtdemux_parse_udta (qtdemux, stream->pending_tags, udta);
10327 /* now we are ready to add the stream */
10328 if (qtdemux->n_streams >= GST_QTDEMUX_MAX_STREAMS)
10329 goto too_many_streams;
10331 if (!qtdemux->got_moov) {
10332 qtdemux->streams[qtdemux->n_streams] = stream;
10333 qtdemux->n_streams++;
10334 GST_DEBUG_OBJECT (qtdemux, "n_streams is now %d", qtdemux->n_streams);
10342 GST_INFO_OBJECT (qtdemux, "skip disabled track");
10344 gst_qtdemux_stream_free (qtdemux, stream);
10349 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
10350 (_("This file is corrupt and cannot be played.")), (NULL));
10352 gst_qtdemux_stream_free (qtdemux, stream);
10357 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT, (NULL), (NULL));
10359 gst_qtdemux_stream_free (qtdemux, stream);
10365 /* we posted an error already */
10366 /* free stbl sub-atoms */
10367 gst_qtdemux_stbl_free (stream);
10369 gst_qtdemux_stream_free (qtdemux, stream);
10374 GST_INFO_OBJECT (qtdemux, "stream with track id %i already exists",
10377 gst_qtdemux_stream_free (qtdemux, stream);
10382 GST_INFO_OBJECT (qtdemux, "unknown subtype %" GST_FOURCC_FORMAT,
10383 GST_FOURCC_ARGS (stream->subtype));
10385 gst_qtdemux_stream_free (qtdemux, stream);
10390 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
10391 (_("This file contains too many streams. Only playing first %d"),
10392 GST_QTDEMUX_MAX_STREAMS), (NULL));
10397 /* If we can estimate the overall bitrate, and don't have information about the
10398 * stream bitrate for exactly one stream, this guesses the stream bitrate as
10399 * the overall bitrate minus the sum of the bitrates of all other streams. This
10400 * should be useful for the common case where we have one audio and one video
10401 * stream and can estimate the bitrate of one, but not the other. */
10403 gst_qtdemux_guess_bitrate (GstQTDemux * qtdemux)
10405 QtDemuxStream *stream = NULL;
10406 gint64 size, sys_bitrate, sum_bitrate = 0;
10407 GstClockTime duration;
10411 if (qtdemux->fragmented)
10414 GST_DEBUG_OBJECT (qtdemux, "Looking for streams with unknown bitrate");
10416 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &size)
10418 GST_DEBUG_OBJECT (qtdemux,
10419 "Size in bytes of the stream not known - bailing");
10423 /* Subtract the header size */
10424 GST_DEBUG_OBJECT (qtdemux, "Total size %" G_GINT64_FORMAT ", header size %u",
10425 size, qtdemux->header_size);
10427 if (size < qtdemux->header_size)
10430 size = size - qtdemux->header_size;
10432 if (!gst_qtdemux_get_duration (qtdemux, &duration) ||
10433 duration == GST_CLOCK_TIME_NONE) {
10434 GST_DEBUG_OBJECT (qtdemux, "Stream duration not known - bailing");
10438 for (i = 0; i < qtdemux->n_streams; i++) {
10439 switch (qtdemux->streams[i]->subtype) {
10442 GST_DEBUG_OBJECT (qtdemux, "checking bitrate for %" GST_PTR_FORMAT,
10443 qtdemux->streams[i]->caps);
10444 /* retrieve bitrate, prefer avg then max */
10446 if (qtdemux->streams[i]->pending_tags) {
10447 gst_tag_list_get_uint (qtdemux->streams[i]->pending_tags,
10448 GST_TAG_MAXIMUM_BITRATE, &bitrate);
10449 GST_DEBUG_OBJECT (qtdemux, "max-bitrate: %u", bitrate);
10450 gst_tag_list_get_uint (qtdemux->streams[i]->pending_tags,
10451 GST_TAG_NOMINAL_BITRATE, &bitrate);
10452 GST_DEBUG_OBJECT (qtdemux, "nominal-bitrate: %u", bitrate);
10453 gst_tag_list_get_uint (qtdemux->streams[i]->pending_tags,
10454 GST_TAG_BITRATE, &bitrate);
10455 GST_DEBUG_OBJECT (qtdemux, "bitrate: %u", bitrate);
10458 sum_bitrate += bitrate;
10461 GST_DEBUG_OBJECT (qtdemux,
10462 ">1 stream with unknown bitrate - bailing");
10465 stream = qtdemux->streams[i];
10469 /* For other subtypes, we assume no significant impact on bitrate */
10475 GST_DEBUG_OBJECT (qtdemux, "All stream bitrates are known");
10479 sys_bitrate = gst_util_uint64_scale (size, GST_SECOND * 8, duration);
10481 if (sys_bitrate < sum_bitrate) {
10482 /* This can happen, since sum_bitrate might be derived from maximum
10483 * bitrates and not average bitrates */
10484 GST_DEBUG_OBJECT (qtdemux,
10485 "System bitrate less than sum bitrate - bailing");
10489 bitrate = sys_bitrate - sum_bitrate;
10490 GST_DEBUG_OBJECT (qtdemux, "System bitrate = %" G_GINT64_FORMAT
10491 ", Stream bitrate = %u", sys_bitrate, bitrate);
10493 if (!stream->pending_tags)
10494 stream->pending_tags = gst_tag_list_new_empty ();
10496 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
10497 GST_TAG_BITRATE, bitrate, NULL);
10500 static GstFlowReturn
10501 qtdemux_prepare_streams (GstQTDemux * qtdemux)
10504 GstFlowReturn ret = GST_FLOW_OK;
10506 GST_DEBUG_OBJECT (qtdemux, "prepare streams");
10508 for (i = 0; ret == GST_FLOW_OK && i < qtdemux->n_streams; i++) {
10509 QtDemuxStream *stream = qtdemux->streams[i];
10510 guint32 sample_num = 0;
10512 GST_DEBUG_OBJECT (qtdemux, "stream %d, id %d, fourcc %" GST_FOURCC_FORMAT,
10513 i, stream->track_id, GST_FOURCC_ARGS (stream->fourcc));
10515 if (qtdemux->fragmented) {
10516 /* need all moov samples first */
10517 GST_OBJECT_LOCK (qtdemux);
10518 while (stream->n_samples == 0)
10519 if ((ret = qtdemux_add_fragmented_samples (qtdemux)) != GST_FLOW_OK)
10521 GST_OBJECT_UNLOCK (qtdemux);
10523 /* discard any stray moof */
10524 qtdemux->moof_offset = 0;
10527 /* prepare braking */
10528 if (ret != GST_FLOW_ERROR)
10531 /* in pull mode, we should have parsed some sample info by now;
10532 * and quite some code will not handle no samples.
10533 * in push mode, we'll just have to deal with it */
10534 if (G_UNLIKELY (qtdemux->pullbased && !stream->n_samples)) {
10535 GST_DEBUG_OBJECT (qtdemux, "no samples for stream; discarding");
10536 gst_qtdemux_remove_stream (qtdemux, i);
10541 /* parse the initial sample for use in setting the frame rate cap */
10542 while (sample_num == 0 && sample_num < stream->n_samples) {
10543 if (!qtdemux_parse_samples (qtdemux, stream, sample_num))
10547 if (stream->n_samples > 0 && stream->stbl_index >= 0) {
10548 stream->first_duration = stream->samples[0].duration;
10549 GST_LOG_OBJECT (qtdemux, "stream %d first duration %u",
10550 stream->track_id, stream->first_duration);
10557 static GstFlowReturn
10558 qtdemux_expose_streams (GstQTDemux * qtdemux)
10561 GstFlowReturn ret = GST_FLOW_OK;
10562 GSList *oldpads = NULL;
10565 GST_DEBUG_OBJECT (qtdemux, "exposing streams");
10567 for (i = 0; ret == GST_FLOW_OK && i < qtdemux->n_streams; i++) {
10568 QtDemuxStream *stream = qtdemux->streams[i];
10569 GstPad *oldpad = stream->pad;
10572 GST_DEBUG_OBJECT (qtdemux, "stream %d, id %d, fourcc %" GST_FOURCC_FORMAT,
10573 i, stream->track_id, GST_FOURCC_ARGS (stream->fourcc));
10575 if ((stream->subtype == FOURCC_text || stream->subtype == FOURCC_sbtl) &&
10576 stream->track_id == qtdemux->chapters_track_id) {
10577 /* TODO - parse chapters track and expose it as GstToc; For now just ignore it
10578 so that it doesn't look like a subtitle track */
10579 gst_qtdemux_remove_stream (qtdemux, i);
10584 /* now we have all info and can expose */
10585 list = stream->pending_tags;
10586 stream->pending_tags = NULL;
10588 oldpads = g_slist_prepend (oldpads, oldpad);
10589 gst_qtdemux_add_stream (qtdemux, stream, list);
10592 gst_qtdemux_guess_bitrate (qtdemux);
10594 gst_element_no_more_pads (GST_ELEMENT_CAST (qtdemux));
10596 for (iter = oldpads; iter; iter = g_slist_next (iter)) {
10597 GstPad *oldpad = iter->data;
10599 gst_pad_push_event (oldpad, gst_event_new_eos ());
10600 gst_pad_set_active (oldpad, FALSE);
10601 gst_element_remove_pad (GST_ELEMENT (qtdemux), oldpad);
10602 gst_flow_combiner_remove_pad (qtdemux->flowcombiner, oldpad);
10603 gst_object_unref (oldpad);
10606 /* check if we should post a redirect in case there is a single trak
10607 * and it is a redirecting trak */
10608 if (qtdemux->n_streams == 1 && qtdemux->streams[0]->redirect_uri != NULL) {
10611 GST_INFO_OBJECT (qtdemux, "Issuing a redirect due to a single track with "
10612 "an external content");
10613 m = gst_message_new_element (GST_OBJECT_CAST (qtdemux),
10614 gst_structure_new ("redirect",
10615 "new-location", G_TYPE_STRING, qtdemux->streams[0]->redirect_uri,
10617 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), m);
10618 qtdemux->posted_redirect = TRUE;
10621 for (i = 0; i < qtdemux->n_streams; i++) {
10622 QtDemuxStream *stream = qtdemux->streams[i];
10624 qtdemux_do_allocation (qtdemux, stream);
10627 qtdemux->exposed = TRUE;
10631 /* check if major or compatible brand is 3GP */
10632 static inline gboolean
10633 qtdemux_is_brand_3gp (GstQTDemux * qtdemux, gboolean major)
10636 return ((qtdemux->major_brand & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
10638 } else if (qtdemux->comp_brands != NULL) {
10642 gboolean res = FALSE;
10644 gst_buffer_map (qtdemux->comp_brands, &map, GST_MAP_READ);
10647 while (size >= 4) {
10648 res = res || ((QT_FOURCC (data) & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
10653 gst_buffer_unmap (qtdemux->comp_brands, &map);
10660 /* check if tag is a spec'ed 3GP tag keyword storing a string */
10661 static inline gboolean
10662 qtdemux_is_string_tag_3gp (GstQTDemux * qtdemux, guint32 fourcc)
10664 return fourcc == FOURCC_cprt || fourcc == FOURCC_gnre || fourcc == FOURCC_titl
10665 || fourcc == FOURCC_dscp || fourcc == FOURCC_perf || fourcc == FOURCC_auth
10666 || fourcc == FOURCC_albm;
10670 qtdemux_tag_add_location (GstQTDemux * qtdemux, GstTagList * taglist,
10671 const char *tag, const char *dummy, GNode * node)
10673 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
10677 gdouble longitude, latitude, altitude;
10680 len = QT_UINT32 (node->data);
10687 /* TODO: language code skipped */
10689 name = gst_tag_freeform_string_to_utf8 (data + offset, -1, env_vars);
10692 /* do not alarm in trivial case, but bail out otherwise */
10693 if (*(data + offset) != 0) {
10694 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8, "
10698 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
10699 GST_TAG_GEO_LOCATION_NAME, name, NULL);
10700 offset += strlen (name);
10704 if (len < offset + 2 + 4 + 4 + 4)
10707 /* +1 +1 = skip null-terminator and location role byte */
10709 /* table in spec says unsigned, semantics say negative has meaning ... */
10710 longitude = QT_SFP32 (data + offset);
10713 latitude = QT_SFP32 (data + offset);
10716 altitude = QT_SFP32 (data + offset);
10718 /* one invalid means all are invalid */
10719 if (longitude >= -180.0 && longitude <= 180.0 &&
10720 latitude >= -90.0 && latitude <= 90.0) {
10721 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
10722 GST_TAG_GEO_LOCATION_LATITUDE, latitude,
10723 GST_TAG_GEO_LOCATION_LONGITUDE, longitude,
10724 GST_TAG_GEO_LOCATION_ELEVATION, altitude, NULL);
10727 /* TODO: no GST_TAG_, so astronomical body and additional notes skipped */
10734 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP location");
10741 qtdemux_tag_add_year (GstQTDemux * qtdemux, GstTagList * taglist,
10742 const char *tag, const char *dummy, GNode * node)
10748 len = QT_UINT32 (node->data);
10752 y = QT_UINT16 ((guint8 *) node->data + 12);
10754 GST_DEBUG_OBJECT (qtdemux, "year: %u is not a valid year", y);
10757 GST_DEBUG_OBJECT (qtdemux, "year: %u", y);
10759 date = g_date_new_dmy (1, 1, y);
10760 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, date, NULL);
10761 g_date_free (date);
10765 qtdemux_tag_add_classification (GstQTDemux * qtdemux, GstTagList * taglist,
10766 const char *tag, const char *dummy, GNode * node)
10769 char *tag_str = NULL;
10774 len = QT_UINT32 (node->data);
10779 entity = (guint8 *) node->data + offset;
10780 if (entity[0] == 0 || entity[1] == 0 || entity[2] == 0 || entity[3] == 0) {
10781 GST_DEBUG_OBJECT (qtdemux,
10782 "classification info: %c%c%c%c invalid classification entity",
10783 entity[0], entity[1], entity[2], entity[3]);
10788 table = QT_UINT16 ((guint8 *) node->data + offset);
10790 /* Language code skipped */
10794 /* Tag format: "XXXX://Y[YYYY]/classification info string"
10795 * XXXX: classification entity, fixed length 4 chars.
10796 * Y[YYYY]: classification table, max 5 chars.
10798 tag_str = g_strdup_printf ("----://%u/%s",
10799 table, (char *) node->data + offset);
10801 /* memcpy To be sure we're preserving byte order */
10802 memcpy (tag_str, entity, 4);
10803 GST_DEBUG_OBJECT (qtdemux, "classification info: %s", tag_str);
10805 gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND, tag, tag_str, NULL);
10814 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP classification");
10820 qtdemux_tag_add_str_full (GstQTDemux * qtdemux, GstTagList * taglist,
10821 const char *tag, const char *dummy, GNode * node)
10823 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
10829 gboolean ret = TRUE;
10830 const gchar *charset = NULL;
10832 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
10834 len = QT_UINT32 (data->data);
10835 type = QT_UINT32 ((guint8 *) data->data + 8);
10836 if (type == 0x00000001 && len > 16) {
10837 s = gst_tag_freeform_string_to_utf8 ((char *) data->data + 16, len - 16,
10840 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
10841 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, s, NULL);
10844 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
10848 len = QT_UINT32 (node->data);
10849 type = QT_UINT32 ((guint8 *) node->data + 4);
10850 if ((type >> 24) == 0xa9) {
10854 /* Type starts with the (C) symbol, so the next data is a list
10855 * of (string size(16), language code(16), string) */
10857 str_len = QT_UINT16 ((guint8 *) node->data + 8);
10858 lang_code = QT_UINT16 ((guint8 *) node->data + 10);
10860 /* the string + fourcc + size + 2 16bit fields,
10861 * means that there are more tags in this atom */
10862 if (len > str_len + 8 + 4) {
10863 /* TODO how to represent the same tag in different languages? */
10864 GST_WARNING_OBJECT (qtdemux, "Ignoring metadata entry with multiple "
10865 "text alternatives, reading only first one");
10869 len = str_len + 8 + 4; /* remove trailing strings that we don't use */
10870 GST_DEBUG_OBJECT (qtdemux, "found international text tag");
10872 if (lang_code < 0x800) { /* MAC encoded string */
10875 } else if (len > 14 && qtdemux_is_string_tag_3gp (qtdemux,
10876 QT_FOURCC ((guint8 *) node->data + 4))) {
10877 guint32 type = QT_UINT32 ((guint8 *) node->data + 8);
10879 /* we go for 3GP style encoding if major brands claims so,
10880 * or if no hope for data be ok UTF-8, and compatible 3GP brand present */
10881 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
10882 (qtdemux_is_brand_3gp (qtdemux, FALSE) &&
10883 ((type & 0x00FFFFFF) == 0x0) && (type >> 24 <= 0xF))) {
10885 /* 16-bit Language code is ignored here as well */
10886 GST_DEBUG_OBJECT (qtdemux, "found 3gpp text tag");
10893 GST_DEBUG_OBJECT (qtdemux, "found normal text tag");
10894 ret = FALSE; /* may have to fallback */
10897 GError *err = NULL;
10899 s = g_convert ((gchar *) node->data + offset, len - offset, "utf8",
10900 charset, NULL, NULL, &err);
10902 GST_DEBUG_OBJECT (qtdemux, "Failed to convert string from charset %s:"
10903 " %s(%d): %s", charset, g_quark_to_string (err->domain), err->code,
10905 g_error_free (err);
10908 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
10909 len - offset, env_vars);
10912 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
10913 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, s, NULL);
10917 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
10924 qtdemux_tag_add_str (GstQTDemux * qtdemux, GstTagList * taglist,
10925 const char *tag, const char *dummy, GNode * node)
10927 qtdemux_tag_add_str_full (qtdemux, taglist, tag, dummy, node);
10931 qtdemux_tag_add_keywords (GstQTDemux * qtdemux, GstTagList * taglist,
10932 const char *tag, const char *dummy, GNode * node)
10934 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
10936 char *s, *t, *k = NULL;
10941 /* first try normal string tag if major brand not 3GP */
10942 if (!qtdemux_is_brand_3gp (qtdemux, TRUE)) {
10943 if (!qtdemux_tag_add_str_full (qtdemux, taglist, tag, dummy, node)) {
10944 /* hm, that did not work, maybe 3gpp storage in non-3gpp major brand;
10945 * let's try it 3gpp way after minor safety check */
10947 if (QT_UINT32 (data) < 15 || !qtdemux_is_brand_3gp (qtdemux, FALSE))
10953 GST_DEBUG_OBJECT (qtdemux, "found 3gpp keyword tag");
10957 len = QT_UINT32 (data);
10961 count = QT_UINT8 (data + 14);
10963 for (; count; count--) {
10966 if (offset + 1 > len)
10968 slen = QT_UINT8 (data + offset);
10970 if (offset + slen > len)
10972 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
10975 GST_DEBUG_OBJECT (qtdemux, "adding keyword %s", GST_STR_NULL (s));
10977 t = g_strjoin (",", k, s, NULL);
10985 GST_DEBUG_OBJECT (qtdemux, "failed to convert keyword to UTF-8");
10992 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (k));
10993 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, k, NULL);
11002 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP keywords");
11008 qtdemux_tag_add_num (GstQTDemux * qtdemux, GstTagList * taglist,
11009 const char *tag1, const char *tag2, GNode * node)
11016 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
11018 len = QT_UINT32 (data->data);
11019 type = QT_UINT32 ((guint8 *) data->data + 8);
11020 if (type == 0x00000000 && len >= 22) {
11021 n1 = QT_UINT16 ((guint8 *) data->data + 18);
11022 n2 = QT_UINT16 ((guint8 *) data->data + 20);
11024 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag1, n1);
11025 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, n1, NULL);
11028 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag2, n2);
11029 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag2, n2, NULL);
11036 qtdemux_tag_add_tmpo (GstQTDemux * qtdemux, GstTagList * taglist,
11037 const char *tag1, const char *dummy, GNode * node)
11044 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
11046 len = QT_UINT32 (data->data);
11047 type = QT_UINT32 ((guint8 *) data->data + 8);
11048 GST_DEBUG_OBJECT (qtdemux, "have tempo tag, type=%d,len=%d", type, len);
11049 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
11050 if ((type == 0x00000015 || type == 0x0000000f) && len >= 18) {
11051 n1 = QT_UINT16 ((guint8 *) data->data + 16);
11053 /* do not add bpm=0 */
11054 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", n1);
11055 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, (gdouble) n1,
11063 qtdemux_tag_add_uint32 (GstQTDemux * qtdemux, GstTagList * taglist,
11064 const char *tag1, const char *dummy, GNode * node)
11071 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
11073 len = QT_UINT32 (data->data);
11074 type = QT_UINT32 ((guint8 *) data->data + 8);
11075 GST_DEBUG_OBJECT (qtdemux, "have %s tag, type=%d,len=%d", tag1, type, len);
11076 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
11077 if ((type == 0x00000015 || type == 0x0000000f) && len >= 20) {
11078 num = QT_UINT32 ((guint8 *) data->data + 16);
11080 /* do not add num=0 */
11081 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", num);
11082 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, num, NULL);
11089 qtdemux_tag_add_covr (GstQTDemux * qtdemux, GstTagList * taglist,
11090 const char *tag1, const char *dummy, GNode * node)
11097 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
11099 len = QT_UINT32 (data->data);
11100 type = QT_UINT32 ((guint8 *) data->data + 8);
11101 GST_DEBUG_OBJECT (qtdemux, "have covr tag, type=%d,len=%d", type, len);
11102 if ((type == 0x0000000d || type == 0x0000000e) && len > 16) {
11104 gst_tag_image_data_to_image_sample ((guint8 *) data->data + 16,
11105 len - 16, GST_TAG_IMAGE_TYPE_NONE))) {
11106 GST_DEBUG_OBJECT (qtdemux, "adding tag size %d", len - 16);
11107 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, sample, NULL);
11108 gst_sample_unref (sample);
11115 qtdemux_tag_add_date (GstQTDemux * qtdemux, GstTagList * taglist,
11116 const char *tag, const char *dummy, GNode * node)
11123 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
11125 len = QT_UINT32 (data->data);
11126 type = QT_UINT32 ((guint8 *) data->data + 8);
11127 if (type == 0x00000001 && len > 16) {
11128 guint y, m = 1, d = 1;
11131 s = g_strndup ((char *) data->data + 16, len - 16);
11132 GST_DEBUG_OBJECT (qtdemux, "adding date '%s'", s);
11133 ret = sscanf (s, "%u-%u-%u", &y, &m, &d);
11134 if (ret >= 1 && y > 1500 && y < 3000) {
11137 date = g_date_new_dmy (d, m, y);
11138 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, date, NULL);
11139 g_date_free (date);
11141 GST_DEBUG_OBJECT (qtdemux, "could not parse date string '%s'", s);
11149 qtdemux_tag_add_gnre (GstQTDemux * qtdemux, GstTagList * taglist,
11150 const char *tag, const char *dummy, GNode * node)
11154 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
11156 /* re-route to normal string tag if major brand says so
11157 * or no data atom and compatible brand suggests so */
11158 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
11159 (qtdemux_is_brand_3gp (qtdemux, FALSE) && !data)) {
11160 qtdemux_tag_add_str (qtdemux, taglist, tag, dummy, node);
11165 guint len, type, n;
11167 len = QT_UINT32 (data->data);
11168 type = QT_UINT32 ((guint8 *) data->data + 8);
11169 if (type == 0x00000000 && len >= 18) {
11170 n = QT_UINT16 ((guint8 *) data->data + 16);
11172 const gchar *genre;
11174 genre = gst_tag_id3_genre_get (n - 1);
11175 if (genre != NULL) {
11176 GST_DEBUG_OBJECT (qtdemux, "adding %d [%s]", n, genre);
11177 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, genre, NULL);
11185 qtdemux_add_double_tag_from_str (GstQTDemux * demux, GstTagList * taglist,
11186 const gchar * tag, guint8 * data, guint32 datasize)
11191 /* make a copy to have \0 at the end */
11192 datacopy = g_strndup ((gchar *) data, datasize);
11194 /* convert the str to double */
11195 if (sscanf (datacopy, "%lf", &value) == 1) {
11196 GST_DEBUG_OBJECT (demux, "adding tag: %s [%s]", tag, datacopy);
11197 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, value, NULL);
11199 GST_WARNING_OBJECT (demux, "Failed to parse double from string: %s",
11207 qtdemux_tag_add_revdns (GstQTDemux * demux, GstTagList * taglist,
11208 const char *tag, const char *tag_bis, GNode * node)
11217 const gchar *meanstr;
11218 const gchar *namestr;
11220 /* checking the whole ---- atom size for consistency */
11221 if (QT_UINT32 (node->data) <= 4 + 12 + 12 + 16) {
11222 GST_WARNING_OBJECT (demux, "Tag ---- atom is too small, ignoring");
11226 mean = qtdemux_tree_get_child_by_type (node, FOURCC_mean);
11228 GST_WARNING_OBJECT (demux, "No 'mean' atom found");
11232 meansize = QT_UINT32 (mean->data);
11233 if (meansize <= 12) {
11234 GST_WARNING_OBJECT (demux, "Small mean atom, ignoring the whole tag");
11237 meanstr = ((gchar *) mean->data) + 12;
11240 name = qtdemux_tree_get_child_by_type (node, FOURCC_name);
11242 GST_WARNING_OBJECT (demux, "'name' atom not found, ignoring tag");
11246 namesize = QT_UINT32 (name->data);
11247 if (namesize <= 12) {
11248 GST_WARNING_OBJECT (demux, "'name' atom is too small, ignoring tag");
11251 namestr = ((gchar *) name->data) + 12;
11259 * uint24 - data type
11263 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
11265 GST_WARNING_OBJECT (demux, "No data atom in this tag");
11268 datasize = QT_UINT32 (data->data);
11269 if (datasize <= 16) {
11270 GST_WARNING_OBJECT (demux, "Data atom too small");
11273 datatype = QT_UINT32 (((gchar *) data->data) + 8) & 0xFFFFFF;
11275 if ((strncmp (meanstr, "com.apple.iTunes", meansize) == 0) ||
11276 (strncmp (meanstr, "org.hydrogenaudio.replaygain", meansize) == 0)) {
11277 static const struct
11279 const gchar name[28];
11280 const gchar tag[28];
11283 "replaygain_track_gain", GST_TAG_TRACK_GAIN}, {
11284 "replaygain_track_peak", GST_TAG_TRACK_PEAK}, {
11285 "replaygain_album_gain", GST_TAG_ALBUM_GAIN}, {
11286 "replaygain_album_peak", GST_TAG_ALBUM_PEAK}, {
11287 "MusicBrainz Track Id", GST_TAG_MUSICBRAINZ_TRACKID}, {
11288 "MusicBrainz Artist Id", GST_TAG_MUSICBRAINZ_ARTISTID}, {
11289 "MusicBrainz Album Id", GST_TAG_MUSICBRAINZ_ALBUMID}, {
11290 "MusicBrainz Album Artist Id", GST_TAG_MUSICBRAINZ_ALBUMARTISTID}
11294 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
11295 if (!g_ascii_strncasecmp (tags[i].name, namestr, namesize)) {
11296 switch (gst_tag_get_type (tags[i].tag)) {
11297 case G_TYPE_DOUBLE:
11298 qtdemux_add_double_tag_from_str (demux, taglist, tags[i].tag,
11299 ((guint8 *) data->data) + 16, datasize - 16);
11301 case G_TYPE_STRING:
11302 qtdemux_tag_add_str (demux, taglist, tags[i].tag, NULL, node);
11311 if (i == G_N_ELEMENTS (tags))
11321 #ifndef GST_DISABLE_GST_DEBUG
11323 gchar *namestr_dbg;
11324 gchar *meanstr_dbg;
11326 meanstr_dbg = g_strndup (meanstr, meansize);
11327 namestr_dbg = g_strndup (namestr, namesize);
11329 GST_WARNING_OBJECT (demux, "This tag %s:%s type:%u is not mapped, "
11330 "file a bug at bugzilla.gnome.org", meanstr_dbg, namestr_dbg, datatype);
11332 g_free (namestr_dbg);
11333 g_free (meanstr_dbg);
11340 qtdemux_tag_add_id32 (GstQTDemux * demux, GstTagList * taglist, const char *tag,
11341 const char *tag_bis, GNode * node)
11346 GstTagList *id32_taglist = NULL;
11348 GST_LOG_OBJECT (demux, "parsing ID32");
11351 len = GST_READ_UINT32_BE (data);
11353 /* need at least full box and language tag */
11357 buf = gst_buffer_new_allocate (NULL, len - 14, NULL);
11358 gst_buffer_fill (buf, 0, data + 14, len - 14);
11360 id32_taglist = gst_tag_list_from_id3v2_tag (buf);
11361 if (id32_taglist) {
11362 GST_LOG_OBJECT (demux, "parsing ok");
11363 gst_tag_list_insert (taglist, id32_taglist, GST_TAG_MERGE_KEEP);
11364 gst_tag_list_unref (id32_taglist);
11366 GST_LOG_OBJECT (demux, "parsing failed");
11369 gst_buffer_unref (buf);
11372 typedef void (*GstQTDemuxAddTagFunc) (GstQTDemux * demux, GstTagList * taglist,
11373 const char *tag, const char *tag_bis, GNode * node);
11376 FOURCC_pcst -> if media is a podcast -> bool
11377 FOURCC_cpil -> if media is part of a compilation -> bool
11378 FOURCC_pgap -> if media is part of a gapless context -> bool
11379 FOURCC_tven -> the tv episode id e.g. S01E23 -> str
11382 static const struct
11385 const gchar *gst_tag;
11386 const gchar *gst_tag_bis;
11387 const GstQTDemuxAddTagFunc func;
11390 FOURCC__nam, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
11391 FOURCC_titl, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
11392 FOURCC__grp, GST_TAG_GROUPING, NULL, qtdemux_tag_add_str}, {
11393 FOURCC__wrt, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
11394 FOURCC__ART, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
11395 FOURCC_aART, GST_TAG_ALBUM_ARTIST, NULL, qtdemux_tag_add_str}, {
11396 FOURCC_perf, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
11397 FOURCC_auth, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
11398 FOURCC__alb, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
11399 FOURCC_albm, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
11400 FOURCC_cprt, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
11401 FOURCC__cpy, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
11402 FOURCC__cmt, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
11403 FOURCC__des, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
11404 FOURCC_desc, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
11405 FOURCC_dscp, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
11406 FOURCC__lyr, GST_TAG_LYRICS, NULL, qtdemux_tag_add_str}, {
11407 FOURCC__day, GST_TAG_DATE, NULL, qtdemux_tag_add_date}, {
11408 FOURCC_yrrc, GST_TAG_DATE, NULL, qtdemux_tag_add_year}, {
11409 FOURCC__too, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
11410 FOURCC__inf, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
11411 FOURCC_trkn, GST_TAG_TRACK_NUMBER, GST_TAG_TRACK_COUNT, qtdemux_tag_add_num}, {
11412 FOURCC_disk, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
11413 qtdemux_tag_add_num}, {
11414 FOURCC_disc, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
11415 qtdemux_tag_add_num}, {
11416 FOURCC__gen, GST_TAG_GENRE, NULL, qtdemux_tag_add_str}, {
11417 FOURCC_gnre, GST_TAG_GENRE, NULL, qtdemux_tag_add_gnre}, {
11418 FOURCC_tmpo, GST_TAG_BEATS_PER_MINUTE, NULL, qtdemux_tag_add_tmpo}, {
11419 FOURCC_covr, GST_TAG_PREVIEW_IMAGE, NULL, qtdemux_tag_add_covr}, {
11420 FOURCC_sonm, GST_TAG_TITLE_SORTNAME, NULL, qtdemux_tag_add_str}, {
11421 FOURCC_soal, GST_TAG_ALBUM_SORTNAME, NULL, qtdemux_tag_add_str}, {
11422 FOURCC_soar, GST_TAG_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
11423 FOURCC_soaa, GST_TAG_ALBUM_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
11424 FOURCC_soco, GST_TAG_COMPOSER_SORTNAME, NULL, qtdemux_tag_add_str}, {
11425 FOURCC_sosn, GST_TAG_SHOW_SORTNAME, NULL, qtdemux_tag_add_str}, {
11426 FOURCC_tvsh, GST_TAG_SHOW_NAME, NULL, qtdemux_tag_add_str}, {
11427 FOURCC_tvsn, GST_TAG_SHOW_SEASON_NUMBER, NULL, qtdemux_tag_add_uint32}, {
11428 FOURCC_tves, GST_TAG_SHOW_EPISODE_NUMBER, NULL, qtdemux_tag_add_uint32}, {
11429 FOURCC_kywd, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_keywords}, {
11430 FOURCC_keyw, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_str}, {
11431 FOURCC__enc, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
11432 FOURCC_loci, GST_TAG_GEO_LOCATION_NAME, NULL, qtdemux_tag_add_location}, {
11433 FOURCC_clsf, GST_QT_DEMUX_CLASSIFICATION_TAG, NULL,
11434 qtdemux_tag_add_classification}, {
11435 FOURCC__mak, GST_TAG_DEVICE_MANUFACTURER, NULL, qtdemux_tag_add_str}, {
11436 FOURCC__mod, GST_TAG_DEVICE_MODEL, NULL, qtdemux_tag_add_str}, {
11437 FOURCC__swr, GST_TAG_APPLICATION_NAME, NULL, qtdemux_tag_add_str}, {
11439 /* This is a special case, some tags are stored in this
11440 * 'reverse dns naming', according to:
11441 * http://atomicparsley.sourceforge.net/mpeg-4files.html and
11444 FOURCC_____, "", NULL, qtdemux_tag_add_revdns}, {
11445 /* see http://www.mp4ra.org/specs.html for ID32 in meta box */
11446 FOURCC_ID32, "", NULL, qtdemux_tag_add_id32}
11449 struct _GstQtDemuxTagList
11452 GstTagList *taglist;
11454 typedef struct _GstQtDemuxTagList GstQtDemuxTagList;
11457 qtdemux_tag_add_blob (GNode * node, GstQtDemuxTagList * qtdemuxtaglist)
11463 const gchar *style;
11468 GstQTDemux *demux = qtdemuxtaglist->demux;
11469 GstTagList *taglist = qtdemuxtaglist->taglist;
11472 len = QT_UINT32 (data);
11473 buf = gst_buffer_new_and_alloc (len);
11474 gst_buffer_fill (buf, 0, data, len);
11476 /* heuristic to determine style of tag */
11477 if (QT_FOURCC (data + 4) == FOURCC_____ ||
11478 (len > 8 + 12 && QT_FOURCC (data + 12) == FOURCC_data))
11480 else if (demux->major_brand == FOURCC_qt__)
11481 style = "quicktime";
11482 /* fall back to assuming iso/3gp tag style */
11486 /* santize the name for the caps. */
11487 for (i = 0; i < 4; i++) {
11488 guint8 d = data[4 + i];
11489 if (g_ascii_isalnum (d))
11490 ndata[i] = g_ascii_tolower (d);
11495 media_type = g_strdup_printf ("application/x-gst-qt-%c%c%c%c-tag",
11496 ndata[0], ndata[1], ndata[2], ndata[3]);
11497 GST_DEBUG_OBJECT (demux, "media type %s", media_type);
11499 s = gst_structure_new (media_type, "style", G_TYPE_STRING, style, NULL);
11500 sample = gst_sample_new (buf, NULL, NULL, s);
11501 gst_buffer_unref (buf);
11502 g_free (media_type);
11504 GST_DEBUG_OBJECT (demux, "adding private tag; size %d, info %" GST_PTR_FORMAT,
11507 gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND,
11508 GST_QT_DEMUX_PRIVATE_TAG, sample, NULL);
11510 gst_sample_unref (sample);
11514 qtdemux_parse_udta (GstQTDemux * qtdemux, GstTagList * taglist, GNode * udta)
11521 GstQtDemuxTagList demuxtaglist;
11523 demuxtaglist.demux = qtdemux;
11524 demuxtaglist.taglist = taglist;
11526 meta = qtdemux_tree_get_child_by_type (udta, FOURCC_meta);
11527 if (meta != NULL) {
11528 ilst = qtdemux_tree_get_child_by_type (meta, FOURCC_ilst);
11529 if (ilst == NULL) {
11530 GST_LOG_OBJECT (qtdemux, "no ilst");
11535 GST_LOG_OBJECT (qtdemux, "no meta so using udta itself");
11539 while (i < G_N_ELEMENTS (add_funcs)) {
11540 node = qtdemux_tree_get_child_by_type (ilst, add_funcs[i].fourcc);
11544 len = QT_UINT32 (node->data);
11546 GST_DEBUG_OBJECT (qtdemux, "too small tag atom %" GST_FOURCC_FORMAT,
11547 GST_FOURCC_ARGS (add_funcs[i].fourcc));
11549 add_funcs[i].func (qtdemux, taglist, add_funcs[i].gst_tag,
11550 add_funcs[i].gst_tag_bis, node);
11552 g_node_destroy (node);
11558 /* parsed nodes have been removed, pass along remainder as blob */
11559 g_node_children_foreach (ilst, G_TRAVERSE_ALL,
11560 (GNodeForeachFunc) qtdemux_tag_add_blob, &demuxtaglist);
11562 /* parse up XMP_ node if existing */
11563 xmp_ = qtdemux_tree_get_child_by_type (udta, FOURCC_XMP_);
11564 if (xmp_ != NULL) {
11566 GstTagList *xmptaglist;
11568 buf = _gst_buffer_new_wrapped (((guint8 *) xmp_->data) + 8,
11569 QT_UINT32 ((guint8 *) xmp_->data) - 8, NULL);
11570 xmptaglist = gst_tag_list_from_xmp_buffer (buf);
11571 gst_buffer_unref (buf);
11573 qtdemux_handle_xmp_taglist (qtdemux, taglist, xmptaglist);
11575 GST_DEBUG_OBJECT (qtdemux, "No XMP_ node found");
11581 GstStructure *structure; /* helper for sort function */
11583 guint min_req_bitrate;
11584 guint min_req_qt_version;
11588 qtdemux_redirects_sort_func (gconstpointer a, gconstpointer b)
11590 GstQtReference *ref_a = (GstQtReference *) a;
11591 GstQtReference *ref_b = (GstQtReference *) b;
11593 if (ref_b->min_req_qt_version != ref_a->min_req_qt_version)
11594 return ref_b->min_req_qt_version - ref_a->min_req_qt_version;
11596 /* known bitrates go before unknown; higher bitrates go first */
11597 return ref_b->min_req_bitrate - ref_a->min_req_bitrate;
11600 /* sort the redirects and post a message for the application.
11603 qtdemux_process_redirects (GstQTDemux * qtdemux, GList * references)
11605 GstQtReference *best;
11608 GValue list_val = { 0, };
11611 g_assert (references != NULL);
11613 references = g_list_sort (references, qtdemux_redirects_sort_func);
11615 best = (GstQtReference *) references->data;
11617 g_value_init (&list_val, GST_TYPE_LIST);
11619 for (l = references; l != NULL; l = l->next) {
11620 GstQtReference *ref = (GstQtReference *) l->data;
11621 GValue struct_val = { 0, };
11623 ref->structure = gst_structure_new ("redirect",
11624 "new-location", G_TYPE_STRING, ref->location, NULL);
11626 if (ref->min_req_bitrate > 0) {
11627 gst_structure_set (ref->structure, "minimum-bitrate", G_TYPE_INT,
11628 ref->min_req_bitrate, NULL);
11631 g_value_init (&struct_val, GST_TYPE_STRUCTURE);
11632 g_value_set_boxed (&struct_val, ref->structure);
11633 gst_value_list_append_value (&list_val, &struct_val);
11634 g_value_unset (&struct_val);
11635 /* don't free anything here yet, since we need best->structure below */
11638 g_assert (best != NULL);
11639 s = gst_structure_copy (best->structure);
11641 if (g_list_length (references) > 1) {
11642 gst_structure_set_value (s, "locations", &list_val);
11645 g_value_unset (&list_val);
11647 for (l = references; l != NULL; l = l->next) {
11648 GstQtReference *ref = (GstQtReference *) l->data;
11650 gst_structure_free (ref->structure);
11651 g_free (ref->location);
11654 g_list_free (references);
11656 GST_INFO_OBJECT (qtdemux, "posting redirect message: %" GST_PTR_FORMAT, s);
11657 msg = gst_message_new_element (GST_OBJECT_CAST (qtdemux), s);
11658 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
11659 qtdemux->posted_redirect = TRUE;
11662 /* look for redirect nodes, collect all redirect information and
11666 qtdemux_parse_redirects (GstQTDemux * qtdemux)
11668 GNode *rmra, *rmda, *rdrf;
11670 rmra = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_rmra);
11672 GList *redirects = NULL;
11674 rmda = qtdemux_tree_get_child_by_type (rmra, FOURCC_rmda);
11676 GstQtReference ref = { NULL, NULL, 0, 0 };
11677 GNode *rmdr, *rmvc;
11679 if ((rmdr = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmdr))) {
11680 ref.min_req_bitrate = QT_UINT32 ((guint8 *) rmdr->data + 12);
11681 GST_LOG_OBJECT (qtdemux, "data rate atom, required bitrate = %u",
11682 ref.min_req_bitrate);
11685 if ((rmvc = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmvc))) {
11686 guint32 package = QT_FOURCC ((guint8 *) rmvc->data + 12);
11687 guint version = QT_UINT32 ((guint8 *) rmvc->data + 16);
11689 #ifndef GST_DISABLE_GST_DEBUG
11690 guint bitmask = QT_UINT32 ((guint8 *) rmvc->data + 20);
11692 guint check_type = QT_UINT16 ((guint8 *) rmvc->data + 24);
11694 GST_LOG_OBJECT (qtdemux,
11695 "version check atom [%" GST_FOURCC_FORMAT "], version=0x%08x"
11696 ", mask=%08x, check_type=%u", GST_FOURCC_ARGS (package), version,
11697 bitmask, check_type);
11698 if (package == FOURCC_qtim && check_type == 0) {
11699 ref.min_req_qt_version = version;
11703 rdrf = qtdemux_tree_get_child_by_type (rmda, FOURCC_rdrf);
11709 ref_len = QT_UINT32 ((guint8 *) rdrf->data);
11710 if (ref_len > 20) {
11711 ref_type = QT_FOURCC ((guint8 *) rdrf->data + 12);
11712 ref_data = (guint8 *) rdrf->data + 20;
11713 if (ref_type == FOURCC_alis) {
11714 guint record_len, record_version, fn_len;
11716 if (ref_len > 70) {
11717 /* MacOSX alias record, google for alias-layout.txt */
11718 record_len = QT_UINT16 (ref_data + 4);
11719 record_version = QT_UINT16 (ref_data + 4 + 2);
11720 fn_len = QT_UINT8 (ref_data + 50);
11721 if (record_len > 50 && record_version == 2 && fn_len > 0) {
11722 ref.location = g_strndup ((gchar *) ref_data + 51, fn_len);
11725 GST_WARNING_OBJECT (qtdemux, "Invalid rdrf/alis size (%u < 70)",
11728 } else if (ref_type == FOURCC_url_) {
11729 ref.location = g_strndup ((gchar *) ref_data, ref_len - 8);
11731 GST_DEBUG_OBJECT (qtdemux,
11732 "unknown rdrf reference type %" GST_FOURCC_FORMAT,
11733 GST_FOURCC_ARGS (ref_type));
11735 if (ref.location != NULL) {
11736 GST_INFO_OBJECT (qtdemux, "New location: %s", ref.location);
11738 g_list_prepend (redirects, g_memdup (&ref, sizeof (ref)));
11740 GST_WARNING_OBJECT (qtdemux,
11741 "Failed to extract redirect location from rdrf atom");
11744 GST_WARNING_OBJECT (qtdemux, "Invalid rdrf size (%u < 20)", ref_len);
11748 /* look for others */
11749 rmda = qtdemux_tree_get_sibling_by_type (rmda, FOURCC_rmda);
11752 if (redirects != NULL) {
11753 qtdemux_process_redirects (qtdemux, redirects);
11759 static GstTagList *
11760 qtdemux_add_container_format (GstQTDemux * qtdemux, GstTagList * tags)
11764 if (tags == NULL) {
11765 tags = gst_tag_list_new_empty ();
11766 gst_tag_list_set_scope (tags, GST_TAG_SCOPE_GLOBAL);
11769 if (qtdemux->major_brand == FOURCC_mjp2)
11770 fmt = "Motion JPEG 2000";
11771 else if ((qtdemux->major_brand & 0xffff) == FOURCC_3g__)
11773 else if (qtdemux->major_brand == FOURCC_qt__)
11775 else if (qtdemux->fragmented)
11778 fmt = "ISO MP4/M4A";
11780 GST_LOG_OBJECT (qtdemux, "mapped %" GST_FOURCC_FORMAT " to '%s'",
11781 GST_FOURCC_ARGS (qtdemux->major_brand), fmt);
11783 gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_CONTAINER_FORMAT,
11789 /* we have read th complete moov node now.
11790 * This function parses all of the relevant info, creates the traks and
11791 * prepares all data structures for playback
11794 qtdemux_parse_tree (GstQTDemux * qtdemux)
11800 GstClockTime duration;
11802 guint64 creation_time;
11803 GstDateTime *datetime = NULL;
11806 /* make sure we have a usable taglist */
11807 if (!qtdemux->tag_list) {
11808 qtdemux->tag_list = gst_tag_list_new_empty ();
11809 gst_tag_list_set_scope (qtdemux->tag_list, GST_TAG_SCOPE_GLOBAL);
11811 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
11814 mvhd = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvhd);
11815 if (mvhd == NULL) {
11816 GST_LOG_OBJECT (qtdemux, "No mvhd node found, looking for redirects.");
11817 return qtdemux_parse_redirects (qtdemux);
11820 version = QT_UINT8 ((guint8 *) mvhd->data + 8);
11821 if (version == 1) {
11822 creation_time = QT_UINT64 ((guint8 *) mvhd->data + 12);
11823 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 28);
11824 qtdemux->duration = QT_UINT64 ((guint8 *) mvhd->data + 32);
11825 } else if (version == 0) {
11826 creation_time = QT_UINT32 ((guint8 *) mvhd->data + 12);
11827 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 20);
11828 qtdemux->duration = QT_UINT32 ((guint8 *) mvhd->data + 24);
11830 GST_WARNING_OBJECT (qtdemux, "Unhandled mvhd version %d", version);
11834 /* Moving qt creation time (secs since 1904) to unix time */
11835 if (creation_time != 0) {
11836 /* Try to use epoch first as it should be faster and more commonly found */
11837 if (creation_time >= QTDEMUX_SECONDS_FROM_1904_TO_1970) {
11840 creation_time -= QTDEMUX_SECONDS_FROM_1904_TO_1970;
11841 /* some data cleansing sanity */
11842 g_get_current_time (&now);
11843 if (now.tv_sec + 24 * 3600 < creation_time) {
11844 GST_DEBUG_OBJECT (qtdemux, "discarding bogus future creation time");
11846 datetime = gst_date_time_new_from_unix_epoch_utc (creation_time);
11849 GDateTime *base_dt = g_date_time_new_utc (1904, 1, 1, 0, 0, 0);
11850 GDateTime *dt, *dt_local;
11852 dt = g_date_time_add_seconds (base_dt, creation_time);
11853 dt_local = g_date_time_to_local (dt);
11854 datetime = gst_date_time_new_from_g_date_time (dt_local);
11856 g_date_time_unref (base_dt);
11857 g_date_time_unref (dt);
11861 /* Use KEEP as explicit tags should have a higher priority than mvhd tag */
11862 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_KEEP, GST_TAG_DATE_TIME,
11864 gst_date_time_unref (datetime);
11867 GST_INFO_OBJECT (qtdemux, "timescale: %u", qtdemux->timescale);
11868 GST_INFO_OBJECT (qtdemux, "duration: %" G_GUINT64_FORMAT, qtdemux->duration);
11870 /* check for fragmented file and get some (default) data */
11871 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
11874 GstByteReader mehd_data;
11876 /* let track parsing or anyone know weird stuff might happen ... */
11877 qtdemux->fragmented = TRUE;
11879 /* compensate for total duration */
11880 mehd = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_mehd, &mehd_data);
11882 qtdemux_parse_mehd (qtdemux, &mehd_data);
11885 /* set duration in the segment info */
11886 gst_qtdemux_get_duration (qtdemux, &duration);
11888 qtdemux->segment.duration = duration;
11889 /* also do not exceed duration; stop is set that way post seek anyway,
11890 * and segment activation falls back to duration,
11891 * whereas loop only checks stop, so let's align this here as well */
11892 qtdemux->segment.stop = duration;
11895 /* parse all traks */
11896 trak = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_trak);
11898 qtdemux_parse_trak (qtdemux, trak);
11899 /* iterate all siblings */
11900 trak = qtdemux_tree_get_sibling_by_type (trak, FOURCC_trak);
11903 if (!qtdemux->tag_list) {
11904 GST_DEBUG_OBJECT (qtdemux, "new tag list");
11905 qtdemux->tag_list = gst_tag_list_new_empty ();
11906 gst_tag_list_set_scope (qtdemux->tag_list, GST_TAG_SCOPE_GLOBAL);
11908 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
11912 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_udta);
11914 qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
11916 GST_LOG_OBJECT (qtdemux, "No udta node found.");
11919 /* maybe also some tags in meta box */
11920 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_meta);
11922 GST_DEBUG_OBJECT (qtdemux, "Parsing meta box for tags.");
11923 qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
11925 GST_LOG_OBJECT (qtdemux, "No meta node found.");
11928 /* parse any protection system info */
11929 pssh = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_pssh);
11931 GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
11932 qtdemux_parse_pssh (qtdemux, pssh);
11933 pssh = qtdemux_tree_get_sibling_by_type (pssh, FOURCC_pssh);
11936 qtdemux->tag_list = qtdemux_add_container_format (qtdemux, qtdemux->tag_list);
11941 /* taken from ffmpeg */
11943 read_descr_size (guint8 * ptr, guint8 * end, guint8 ** end_out)
11955 len = (len << 7) | (c & 0x7f);
11963 /* this can change the codec originally present in @list */
11965 gst_qtdemux_handle_esds (GstQTDemux * qtdemux, QtDemuxStream * stream,
11966 GNode * esds, GstTagList * list)
11968 int len = QT_UINT32 (esds->data);
11969 guint8 *ptr = esds->data;
11970 guint8 *end = ptr + len;
11972 guint8 *data_ptr = NULL;
11974 guint8 object_type_id = 0;
11975 const char *codec_name = NULL;
11976 GstCaps *caps = NULL;
11978 GST_MEMDUMP_OBJECT (qtdemux, "esds", ptr, len);
11980 GST_DEBUG_OBJECT (qtdemux, "version/flags = %08x", QT_UINT32 (ptr));
11982 while (ptr + 1 < end) {
11983 tag = QT_UINT8 (ptr);
11984 GST_DEBUG_OBJECT (qtdemux, "tag = %02x", tag);
11986 len = read_descr_size (ptr, end, &ptr);
11987 GST_DEBUG_OBJECT (qtdemux, "len = %d", len);
11989 /* Check the stated amount of data is available for reading */
11990 if (len < 0 || ptr + len > end)
11994 case ES_DESCRIPTOR_TAG:
11995 GST_DEBUG_OBJECT (qtdemux, "ID %04x", QT_UINT16 (ptr));
11996 GST_DEBUG_OBJECT (qtdemux, "priority %04x", QT_UINT8 (ptr + 2));
11999 case DECODER_CONFIG_DESC_TAG:{
12000 guint max_bitrate, avg_bitrate;
12002 object_type_id = QT_UINT8 (ptr);
12003 max_bitrate = QT_UINT32 (ptr + 5);
12004 avg_bitrate = QT_UINT32 (ptr + 9);
12005 GST_DEBUG_OBJECT (qtdemux, "object_type_id %02x", object_type_id);
12006 GST_DEBUG_OBJECT (qtdemux, "stream_type %02x", QT_UINT8 (ptr + 1));
12007 GST_DEBUG_OBJECT (qtdemux, "buffer_size_db %02x", QT_UINT24 (ptr + 2));
12008 GST_DEBUG_OBJECT (qtdemux, "max bitrate %u", max_bitrate);
12009 GST_DEBUG_OBJECT (qtdemux, "avg bitrate %u", avg_bitrate);
12010 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
12011 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
12012 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
12014 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
12015 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
12016 avg_bitrate, NULL);
12021 case DECODER_SPECIFIC_INFO_TAG:
12022 GST_MEMDUMP_OBJECT (qtdemux, "data", ptr, len);
12023 if (object_type_id == 0xe0 && len == 0x40) {
12029 GST_DEBUG_OBJECT (qtdemux,
12030 "Have VOBSUB palette. Creating palette event");
12031 /* move to decConfigDescr data and read palette */
12033 for (i = 0; i < 16; i++) {
12034 clut[i] = QT_UINT32 (data);
12038 s = gst_structure_new ("application/x-gst-dvd", "event",
12039 G_TYPE_STRING, "dvd-spu-clut-change",
12040 "clut00", G_TYPE_INT, clut[0], "clut01", G_TYPE_INT, clut[1],
12041 "clut02", G_TYPE_INT, clut[2], "clut03", G_TYPE_INT, clut[3],
12042 "clut04", G_TYPE_INT, clut[4], "clut05", G_TYPE_INT, clut[5],
12043 "clut06", G_TYPE_INT, clut[6], "clut07", G_TYPE_INT, clut[7],
12044 "clut08", G_TYPE_INT, clut[8], "clut09", G_TYPE_INT, clut[9],
12045 "clut10", G_TYPE_INT, clut[10], "clut11", G_TYPE_INT, clut[11],
12046 "clut12", G_TYPE_INT, clut[12], "clut13", G_TYPE_INT, clut[13],
12047 "clut14", G_TYPE_INT, clut[14], "clut15", G_TYPE_INT, clut[15],
12050 /* store event and trigger custom processing */
12051 stream->pending_event =
12052 gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s);
12054 /* Generic codec_data handler puts it on the caps */
12061 case SL_CONFIG_DESC_TAG:
12062 GST_DEBUG_OBJECT (qtdemux, "data %02x", QT_UINT8 (ptr));
12066 GST_DEBUG_OBJECT (qtdemux, "Unknown/unhandled descriptor tag %02x",
12068 GST_MEMDUMP_OBJECT (qtdemux, "descriptor data", ptr, len);
12074 /* object_type_id in the esds atom in mp4a and mp4v tells us which codec is
12075 * in use, and should also be used to override some other parameters for some
12077 switch (object_type_id) {
12078 case 0x20: /* MPEG-4 */
12079 /* 4 bytes for the visual_object_sequence_start_code and 1 byte for the
12080 * profile_and_level_indication */
12081 if (data_ptr != NULL && data_len >= 5 &&
12082 GST_READ_UINT32_BE (data_ptr) == 0x000001b0) {
12083 gst_codec_utils_mpeg4video_caps_set_level_and_profile (stream->caps,
12084 data_ptr + 4, data_len - 4);
12086 break; /* Nothing special needed here */
12087 case 0x21: /* H.264 */
12088 codec_name = "H.264 / AVC";
12089 caps = gst_caps_new_simple ("video/x-h264",
12090 "stream-format", G_TYPE_STRING, "avc",
12091 "alignment", G_TYPE_STRING, "au", NULL);
12093 case 0x40: /* AAC (any) */
12094 case 0x66: /* AAC Main */
12095 case 0x67: /* AAC LC */
12096 case 0x68: /* AAC SSR */
12097 /* Override channels and rate based on the codec_data, as it's often
12099 /* Only do so for basic setup without HE-AAC extension */
12100 if (data_ptr && data_len == 2) {
12101 guint channels, rateindex, rate;
12103 /* FIXME: add gst_codec_utils_aac_get_{channels|sample_rate}()? */
12104 channels = (data_ptr[1] & 0x7f) >> 3;
12105 if (channels > 0 && channels < 7) {
12106 stream->n_channels = channels;
12107 } else if (channels == 7) {
12108 stream->n_channels = 8;
12111 rateindex = ((data_ptr[0] & 0x7) << 1) | ((data_ptr[1] & 0x80) >> 7);
12112 rate = gst_codec_utils_aac_get_sample_rate_from_index (rateindex);
12114 stream->rate = rate;
12117 /* Set level and profile if possible */
12118 if (data_ptr != NULL && data_len >= 2) {
12119 gst_codec_utils_aac_caps_set_level_and_profile (stream->caps,
12120 data_ptr, data_len);
12123 case 0x60: /* MPEG-2, various profiles */
12129 codec_name = "MPEG-2 video";
12130 caps = gst_caps_new_simple ("video/mpeg",
12131 "mpegversion", G_TYPE_INT, 2,
12132 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
12134 case 0x69: /* MPEG-2 BC audio */
12135 case 0x6B: /* MPEG-1 audio */
12136 caps = gst_caps_new_simple ("audio/mpeg",
12137 "mpegversion", G_TYPE_INT, 1, "parsed", G_TYPE_BOOLEAN, TRUE, NULL);
12138 codec_name = "MPEG-1 audio";
12140 case 0x6A: /* MPEG-1 */
12141 codec_name = "MPEG-1 video";
12142 caps = gst_caps_new_simple ("video/mpeg",
12143 "mpegversion", G_TYPE_INT, 1,
12144 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
12146 case 0x6C: /* MJPEG */
12148 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
12150 codec_name = "Motion-JPEG";
12152 case 0x6D: /* PNG */
12154 gst_caps_new_simple ("image/png", "parsed", G_TYPE_BOOLEAN, TRUE,
12156 codec_name = "PNG still images";
12158 case 0x6E: /* JPEG2000 */
12159 codec_name = "JPEG-2000";
12160 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
12162 case 0xA4: /* Dirac */
12163 codec_name = "Dirac";
12164 caps = gst_caps_new_empty_simple ("video/x-dirac");
12166 case 0xA5: /* AC3 */
12167 codec_name = "AC-3 audio";
12168 caps = gst_caps_new_simple ("audio/x-ac3",
12169 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
12171 case 0xA9: /* AC3 */
12172 codec_name = "DTS audio";
12173 caps = gst_caps_new_simple ("audio/x-dts",
12174 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
12176 case 0xE1: /* QCELP */
12177 /* QCELP, the codec_data is a riff tag (little endian) with
12178 * 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). */
12179 caps = gst_caps_new_empty_simple ("audio/qcelp");
12180 codec_name = "QCELP";
12186 /* If we have a replacement caps, then change our caps for this stream */
12188 gst_caps_unref (stream->caps);
12189 stream->caps = caps;
12192 if (codec_name && list)
12193 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
12194 GST_TAG_AUDIO_CODEC, codec_name, NULL);
12196 /* Add the codec_data attribute to caps, if we have it */
12200 buffer = gst_buffer_new_and_alloc (data_len);
12201 gst_buffer_fill (buffer, 0, data_ptr, data_len);
12203 GST_DEBUG_OBJECT (qtdemux, "setting codec_data from esds");
12204 GST_MEMDUMP_OBJECT (qtdemux, "codec_data from esds", data_ptr, data_len);
12206 gst_caps_set_simple (stream->caps, "codec_data", GST_TYPE_BUFFER,
12208 gst_buffer_unref (buffer);
12213 #define _codec(name) \
12215 if (codec_name) { \
12216 *codec_name = g_strdup (name); \
12221 qtdemux_video_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
12222 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
12224 GstCaps *caps = NULL;
12225 GstVideoFormat format = GST_VIDEO_FORMAT_UNKNOWN;
12228 case GST_MAKE_FOURCC ('p', 'n', 'g', ' '):
12229 _codec ("PNG still images");
12230 caps = gst_caps_new_empty_simple ("image/png");
12233 _codec ("JPEG still images");
12235 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
12238 case GST_MAKE_FOURCC ('m', 'j', 'p', 'a'):
12239 case GST_MAKE_FOURCC ('A', 'V', 'D', 'J'):
12240 case GST_MAKE_FOURCC ('M', 'J', 'P', 'G'):
12241 case GST_MAKE_FOURCC ('d', 'm', 'b', '1'):
12242 _codec ("Motion-JPEG");
12244 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
12247 case GST_MAKE_FOURCC ('m', 'j', 'p', 'b'):
12248 _codec ("Motion-JPEG format B");
12249 caps = gst_caps_new_empty_simple ("video/x-mjpeg-b");
12252 _codec ("JPEG-2000");
12253 /* override to what it should be according to spec, avoid palette_data */
12254 stream->bits_per_sample = 24;
12255 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
12258 _codec ("Sorensen video v.3");
12259 caps = gst_caps_new_simple ("video/x-svq",
12260 "svqversion", G_TYPE_INT, 3, NULL);
12262 case GST_MAKE_FOURCC ('s', 'v', 'q', 'i'):
12263 case GST_MAKE_FOURCC ('S', 'V', 'Q', '1'):
12264 _codec ("Sorensen video v.1");
12265 caps = gst_caps_new_simple ("video/x-svq",
12266 "svqversion", G_TYPE_INT, 1, NULL);
12268 case GST_MAKE_FOURCC ('W', 'R', 'A', 'W'):
12269 caps = gst_caps_new_empty_simple ("video/x-raw");
12270 gst_caps_set_simple (caps, "format", G_TYPE_STRING, "RGB8P", NULL);
12271 _codec ("Windows Raw RGB");
12277 bps = QT_UINT16 (stsd_data + 98);
12280 format = GST_VIDEO_FORMAT_RGB15;
12283 format = GST_VIDEO_FORMAT_RGB16;
12286 format = GST_VIDEO_FORMAT_RGB;
12289 format = GST_VIDEO_FORMAT_ARGB;
12297 case GST_MAKE_FOURCC ('y', 'v', '1', '2'):
12298 format = GST_VIDEO_FORMAT_I420;
12300 case GST_MAKE_FOURCC ('y', 'u', 'v', '2'):
12301 case GST_MAKE_FOURCC ('Y', 'u', 'v', '2'):
12302 format = GST_VIDEO_FORMAT_I420;
12305 case GST_MAKE_FOURCC ('2', 'V', 'u', 'y'):
12306 format = GST_VIDEO_FORMAT_UYVY;
12308 case GST_MAKE_FOURCC ('v', '3', '0', '8'):
12309 format = GST_VIDEO_FORMAT_v308;
12311 case GST_MAKE_FOURCC ('v', '2', '1', '6'):
12312 format = GST_VIDEO_FORMAT_v216;
12315 format = GST_VIDEO_FORMAT_v210;
12317 case GST_MAKE_FOURCC ('r', '2', '1', '0'):
12318 format = GST_VIDEO_FORMAT_r210;
12320 /* Packed YUV 4:4:4 10 bit in 32 bits, complex
12321 case GST_MAKE_FOURCC ('v', '4', '1', '0'):
12322 format = GST_VIDEO_FORMAT_v410;
12325 /* Packed YUV 4:4:4:4 8 bit in 32 bits
12326 * but different order than AYUV
12327 case GST_MAKE_FOURCC ('v', '4', '0', '8'):
12328 format = GST_VIDEO_FORMAT_v408;
12331 case GST_MAKE_FOURCC ('m', 'p', 'e', 'g'):
12332 case GST_MAKE_FOURCC ('m', 'p', 'g', '1'):
12333 _codec ("MPEG-1 video");
12334 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
12335 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
12337 case GST_MAKE_FOURCC ('h', 'd', 'v', '1'): /* HDV 720p30 */
12338 case GST_MAKE_FOURCC ('h', 'd', 'v', '2'): /* HDV 1080i60 */
12339 case GST_MAKE_FOURCC ('h', 'd', 'v', '3'): /* HDV 1080i50 */
12340 case GST_MAKE_FOURCC ('h', 'd', 'v', '4'): /* HDV 720p24 */
12341 case GST_MAKE_FOURCC ('h', 'd', 'v', '5'): /* HDV 720p25 */
12342 case GST_MAKE_FOURCC ('h', 'd', 'v', '6'): /* HDV 1080p24 */
12343 case GST_MAKE_FOURCC ('h', 'd', 'v', '7'): /* HDV 1080p25 */
12344 case GST_MAKE_FOURCC ('h', 'd', 'v', '8'): /* HDV 1080p30 */
12345 case GST_MAKE_FOURCC ('h', 'd', 'v', '9'): /* HDV 720p60 */
12346 case GST_MAKE_FOURCC ('h', 'd', 'v', 'a'): /* HDV 720p50 */
12347 case GST_MAKE_FOURCC ('m', 'x', '5', 'n'): /* MPEG2 IMX NTSC 525/60 50mb/s produced by FCP */
12348 case GST_MAKE_FOURCC ('m', 'x', '5', 'p'): /* MPEG2 IMX PAL 625/60 50mb/s produced by FCP */
12349 case GST_MAKE_FOURCC ('m', 'x', '4', 'n'): /* MPEG2 IMX NTSC 525/60 40mb/s produced by FCP */
12350 case GST_MAKE_FOURCC ('m', 'x', '4', 'p'): /* MPEG2 IMX PAL 625/60 40mb/s produced by FCP */
12351 case GST_MAKE_FOURCC ('m', 'x', '3', 'n'): /* MPEG2 IMX NTSC 525/60 30mb/s produced by FCP */
12352 case GST_MAKE_FOURCC ('m', 'x', '3', 'p'): /* MPEG2 IMX PAL 625/50 30mb/s produced by FCP */
12353 case GST_MAKE_FOURCC ('x', 'd', 'v', '1'): /* XDCAM HD 720p30 35Mb/s */
12354 case GST_MAKE_FOURCC ('x', 'd', 'v', '2'): /* XDCAM HD 1080i60 35Mb/s */
12355 case GST_MAKE_FOURCC ('x', 'd', 'v', '3'): /* XDCAM HD 1080i50 35Mb/s */
12356 case GST_MAKE_FOURCC ('x', 'd', 'v', '4'): /* XDCAM HD 720p24 35Mb/s */
12357 case GST_MAKE_FOURCC ('x', 'd', 'v', '5'): /* XDCAM HD 720p25 35Mb/s */
12358 case GST_MAKE_FOURCC ('x', 'd', 'v', '6'): /* XDCAM HD 1080p24 35Mb/s */
12359 case GST_MAKE_FOURCC ('x', 'd', 'v', '7'): /* XDCAM HD 1080p25 35Mb/s */
12360 case GST_MAKE_FOURCC ('x', 'd', 'v', '8'): /* XDCAM HD 1080p30 35Mb/s */
12361 case GST_MAKE_FOURCC ('x', 'd', 'v', '9'): /* XDCAM HD 720p60 35Mb/s */
12362 case GST_MAKE_FOURCC ('x', 'd', 'v', 'a'): /* XDCAM HD 720p50 35Mb/s */
12363 case GST_MAKE_FOURCC ('x', 'd', 'v', 'b'): /* XDCAM EX 1080i60 50Mb/s CBR */
12364 case GST_MAKE_FOURCC ('x', 'd', 'v', 'c'): /* XDCAM EX 1080i50 50Mb/s CBR */
12365 case GST_MAKE_FOURCC ('x', 'd', 'v', 'd'): /* XDCAM HD 1080p24 50Mb/s CBR */
12366 case GST_MAKE_FOURCC ('x', 'd', 'v', 'e'): /* XDCAM HD 1080p25 50Mb/s CBR */
12367 case GST_MAKE_FOURCC ('x', 'd', 'v', 'f'): /* XDCAM HD 1080p30 50Mb/s CBR */
12368 case GST_MAKE_FOURCC ('x', 'd', '5', '1'): /* XDCAM HD422 720p30 50Mb/s CBR */
12369 case GST_MAKE_FOURCC ('x', 'd', '5', '4'): /* XDCAM HD422 720p24 50Mb/s CBR */
12370 case GST_MAKE_FOURCC ('x', 'd', '5', '5'): /* XDCAM HD422 720p25 50Mb/s CBR */
12371 case GST_MAKE_FOURCC ('x', 'd', '5', '9'): /* XDCAM HD422 720p60 50Mb/s CBR */
12372 case GST_MAKE_FOURCC ('x', 'd', '5', 'a'): /* XDCAM HD422 720p50 50Mb/s CBR */
12373 case GST_MAKE_FOURCC ('x', 'd', '5', 'b'): /* XDCAM HD422 1080i50 50Mb/s CBR */
12374 case GST_MAKE_FOURCC ('x', 'd', '5', 'c'): /* XDCAM HD422 1080i50 50Mb/s CBR */
12375 case GST_MAKE_FOURCC ('x', 'd', '5', 'd'): /* XDCAM HD422 1080p24 50Mb/s CBR */
12376 case GST_MAKE_FOURCC ('x', 'd', '5', 'e'): /* XDCAM HD422 1080p25 50Mb/s CBR */
12377 case GST_MAKE_FOURCC ('x', 'd', '5', 'f'): /* XDCAM HD422 1080p30 50Mb/s CBR */
12378 case GST_MAKE_FOURCC ('x', 'd', 'h', 'd'): /* XDCAM HD 540p */
12379 case GST_MAKE_FOURCC ('x', 'd', 'h', '2'): /* XDCAM HD422 540p */
12380 case GST_MAKE_FOURCC ('A', 'V', 'm', 'p'): /* AVID IMX PAL */
12381 case GST_MAKE_FOURCC ('m', 'p', 'g', '2'): /* AVID IMX PAL */
12382 case GST_MAKE_FOURCC ('m', 'p', '2', 'v'): /* AVID IMX PAL */
12383 _codec ("MPEG-2 video");
12384 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 2,
12385 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
12387 case GST_MAKE_FOURCC ('g', 'i', 'f', ' '):
12388 _codec ("GIF still images");
12389 caps = gst_caps_new_empty_simple ("image/gif");
12392 case GST_MAKE_FOURCC ('H', '2', '6', '3'):
12394 case GST_MAKE_FOURCC ('U', '2', '6', '3'):
12396 /* ffmpeg uses the height/width props, don't know why */
12397 caps = gst_caps_new_simple ("video/x-h263",
12398 "variant", G_TYPE_STRING, "itu", NULL);
12402 _codec ("MPEG-4 video");
12403 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
12404 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
12406 case GST_MAKE_FOURCC ('3', 'i', 'v', 'd'):
12407 case GST_MAKE_FOURCC ('3', 'I', 'V', 'D'):
12408 _codec ("Microsoft MPEG-4 4.3"); /* FIXME? */
12409 caps = gst_caps_new_simple ("video/x-msmpeg",
12410 "msmpegversion", G_TYPE_INT, 43, NULL);
12412 case GST_MAKE_FOURCC ('D', 'I', 'V', '3'):
12414 caps = gst_caps_new_simple ("video/x-divx",
12415 "divxversion", G_TYPE_INT, 3, NULL);
12417 case GST_MAKE_FOURCC ('D', 'I', 'V', 'X'):
12418 case GST_MAKE_FOURCC ('d', 'i', 'v', 'x'):
12420 caps = gst_caps_new_simple ("video/x-divx",
12421 "divxversion", G_TYPE_INT, 4, NULL);
12423 case GST_MAKE_FOURCC ('D', 'X', '5', '0'):
12425 caps = gst_caps_new_simple ("video/x-divx",
12426 "divxversion", G_TYPE_INT, 5, NULL);
12429 case GST_MAKE_FOURCC ('F', 'F', 'V', '1'):
12431 caps = gst_caps_new_simple ("video/x-ffv",
12432 "ffvversion", G_TYPE_INT, 1, NULL);
12435 case GST_MAKE_FOURCC ('3', 'I', 'V', '1'):
12436 case GST_MAKE_FOURCC ('3', 'I', 'V', '2'):
12437 case GST_MAKE_FOURCC ('X', 'V', 'I', 'D'):
12438 case GST_MAKE_FOURCC ('x', 'v', 'i', 'd'):
12440 case GST_MAKE_FOURCC ('U', 'M', 'P', '4'):
12441 caps = gst_caps_new_simple ("video/mpeg",
12442 "mpegversion", G_TYPE_INT, 4, NULL);
12446 case GST_MAKE_FOURCC ('c', 'v', 'i', 'd'):
12447 _codec ("Cinepak");
12448 caps = gst_caps_new_empty_simple ("video/x-cinepak");
12450 case GST_MAKE_FOURCC ('q', 'd', 'r', 'w'):
12451 _codec ("Apple QuickDraw");
12452 caps = gst_caps_new_empty_simple ("video/x-qdrw");
12454 case GST_MAKE_FOURCC ('r', 'p', 'z', 'a'):
12455 _codec ("Apple video");
12456 caps = gst_caps_new_empty_simple ("video/x-apple-video");
12460 _codec ("H.264 / AVC");
12461 caps = gst_caps_new_simple ("video/x-h264",
12462 "stream-format", G_TYPE_STRING, "avc",
12463 "alignment", G_TYPE_STRING, "au", NULL);
12466 _codec ("H.264 / AVC");
12467 caps = gst_caps_new_simple ("video/x-h264",
12468 "stream-format", G_TYPE_STRING, "avc3",
12469 "alignment", G_TYPE_STRING, "au", NULL);
12473 _codec ("H.265 / HEVC");
12474 caps = gst_caps_new_simple ("video/x-h265",
12475 "stream-format", G_TYPE_STRING, "hvc1",
12476 "alignment", G_TYPE_STRING, "au", NULL);
12479 _codec ("H.265 / HEVC");
12480 caps = gst_caps_new_simple ("video/x-h265",
12481 "stream-format", G_TYPE_STRING, "hev1",
12482 "alignment", G_TYPE_STRING, "au", NULL);
12485 _codec ("Run-length encoding");
12486 caps = gst_caps_new_simple ("video/x-rle",
12487 "layout", G_TYPE_STRING, "quicktime", NULL);
12490 _codec ("Run-length encoding");
12491 caps = gst_caps_new_simple ("video/x-rle",
12492 "layout", G_TYPE_STRING, "microsoft", NULL);
12494 case GST_MAKE_FOURCC ('I', 'V', '3', '2'):
12495 case GST_MAKE_FOURCC ('i', 'v', '3', '2'):
12496 _codec ("Indeo Video 3");
12497 caps = gst_caps_new_simple ("video/x-indeo",
12498 "indeoversion", G_TYPE_INT, 3, NULL);
12500 case GST_MAKE_FOURCC ('I', 'V', '4', '1'):
12501 case GST_MAKE_FOURCC ('i', 'v', '4', '1'):
12502 _codec ("Intel Video 4");
12503 caps = gst_caps_new_simple ("video/x-indeo",
12504 "indeoversion", G_TYPE_INT, 4, NULL);
12508 case GST_MAKE_FOURCC ('d', 'v', 's', 'd'):
12509 case GST_MAKE_FOURCC ('D', 'V', 'S', 'D'):
12510 case GST_MAKE_FOURCC ('d', 'v', 'c', 's'):
12511 case GST_MAKE_FOURCC ('D', 'V', 'C', 'S'):
12512 case GST_MAKE_FOURCC ('d', 'v', '2', '5'):
12513 case GST_MAKE_FOURCC ('d', 'v', 'p', 'p'):
12514 _codec ("DV Video");
12515 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 25,
12516 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
12518 case FOURCC_dv5n: /* DVCPRO50 NTSC */
12519 case FOURCC_dv5p: /* DVCPRO50 PAL */
12520 _codec ("DVCPro50 Video");
12521 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 50,
12522 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
12524 case GST_MAKE_FOURCC ('d', 'v', 'h', '5'): /* DVCPRO HD 50i produced by FCP */
12525 case GST_MAKE_FOURCC ('d', 'v', 'h', '6'): /* DVCPRO HD 60i produced by FCP */
12526 _codec ("DVCProHD Video");
12527 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 100,
12528 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
12530 case GST_MAKE_FOURCC ('s', 'm', 'c', ' '):
12531 _codec ("Apple Graphics (SMC)");
12532 caps = gst_caps_new_empty_simple ("video/x-smc");
12534 case GST_MAKE_FOURCC ('V', 'P', '3', '1'):
12536 caps = gst_caps_new_empty_simple ("video/x-vp3");
12538 case GST_MAKE_FOURCC ('V', 'P', '6', 'F'):
12539 _codec ("VP6 Flash");
12540 caps = gst_caps_new_empty_simple ("video/x-vp6-flash");
12544 caps = gst_caps_new_empty_simple ("video/x-theora");
12545 /* theora uses one byte of padding in the data stream because it does not
12546 * allow 0 sized packets while theora does */
12547 stream->padding = 1;
12551 caps = gst_caps_new_empty_simple ("video/x-dirac");
12553 case GST_MAKE_FOURCC ('t', 'i', 'f', 'f'):
12554 _codec ("TIFF still images");
12555 caps = gst_caps_new_empty_simple ("image/tiff");
12557 case GST_MAKE_FOURCC ('i', 'c', 'o', 'd'):
12558 _codec ("Apple Intermediate Codec");
12559 caps = gst_caps_from_string ("video/x-apple-intermediate-codec");
12561 case GST_MAKE_FOURCC ('A', 'V', 'd', 'n'):
12562 _codec ("AVID DNxHD");
12563 caps = gst_caps_from_string ("video/x-dnxhd");
12566 _codec ("On2 VP8");
12567 caps = gst_caps_from_string ("video/x-vp8");
12570 _codec ("Apple ProRes LT");
12572 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "lt",
12576 _codec ("Apple ProRes HQ");
12578 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "hq",
12582 _codec ("Apple ProRes");
12584 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
12588 _codec ("Apple ProRes Proxy");
12590 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
12594 _codec ("Apple ProRes 4444");
12596 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
12602 caps = gst_caps_new_simple ("video/x-wmv",
12603 "wmvversion", G_TYPE_INT, 3, "format", G_TYPE_STRING, "WVC1", NULL);
12605 case GST_MAKE_FOURCC ('k', 'p', 'c', 'd'):
12608 char *s, fourstr[5];
12610 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
12611 s = g_strdup_printf ("video/x-gst-fourcc-%s", g_strstrip (fourstr));
12612 caps = gst_caps_new_empty_simple (s);
12618 if (format != GST_VIDEO_FORMAT_UNKNOWN) {
12621 gst_video_info_init (&info);
12622 gst_video_info_set_format (&info, format, stream->width, stream->height);
12624 caps = gst_video_info_to_caps (&info);
12625 *codec_name = gst_pb_utils_get_codec_description (caps);
12627 /* enable clipping for raw video streams */
12628 stream->need_clip = TRUE;
12635 qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
12636 guint32 fourcc, const guint8 * data, int len, gchar ** codec_name)
12639 const GstStructure *s;
12642 GstAudioFormat format = 0;
12645 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
12647 depth = stream->bytes_per_packet * 8;
12650 case GST_MAKE_FOURCC ('N', 'O', 'N', 'E'):
12652 /* 8-bit audio is unsigned */
12654 format = GST_AUDIO_FORMAT_U8;
12655 /* otherwise it's signed and big-endian just like 'twos' */
12657 endian = G_BIG_ENDIAN;
12664 endian = G_LITTLE_ENDIAN;
12667 format = gst_audio_format_build_integer (TRUE, endian, depth, depth);
12669 str = g_strdup_printf ("Raw %d-bit PCM audio", depth);
12673 caps = gst_caps_new_simple ("audio/x-raw",
12674 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
12675 "layout", G_TYPE_STRING, "interleaved", NULL);
12678 case GST_MAKE_FOURCC ('f', 'l', '6', '4'):
12679 _codec ("Raw 64-bit floating-point audio");
12680 caps = gst_caps_new_simple ("audio/x-raw",
12681 "format", G_TYPE_STRING, "F64BE",
12682 "layout", G_TYPE_STRING, "interleaved", NULL);
12684 case GST_MAKE_FOURCC ('f', 'l', '3', '2'):
12685 _codec ("Raw 32-bit floating-point audio");
12686 caps = gst_caps_new_simple ("audio/x-raw",
12687 "format", G_TYPE_STRING, "F32BE",
12688 "layout", G_TYPE_STRING, "interleaved", NULL);
12691 _codec ("Raw 24-bit PCM audio");
12692 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
12694 caps = gst_caps_new_simple ("audio/x-raw",
12695 "format", G_TYPE_STRING, "S24BE",
12696 "layout", G_TYPE_STRING, "interleaved", NULL);
12698 case GST_MAKE_FOURCC ('i', 'n', '3', '2'):
12699 _codec ("Raw 32-bit PCM audio");
12700 caps = gst_caps_new_simple ("audio/x-raw",
12701 "format", G_TYPE_STRING, "S32BE",
12702 "layout", G_TYPE_STRING, "interleaved", NULL);
12705 _codec ("Mu-law audio");
12706 caps = gst_caps_new_empty_simple ("audio/x-mulaw");
12709 _codec ("A-law audio");
12710 caps = gst_caps_new_empty_simple ("audio/x-alaw");
12714 _codec ("Microsoft ADPCM");
12715 /* Microsoft ADPCM-ACM code 2 */
12716 caps = gst_caps_new_simple ("audio/x-adpcm",
12717 "layout", G_TYPE_STRING, "microsoft", NULL);
12721 _codec ("DVI/IMA ADPCM");
12722 caps = gst_caps_new_simple ("audio/x-adpcm",
12723 "layout", G_TYPE_STRING, "dvi", NULL);
12727 _codec ("DVI/Intel IMA ADPCM");
12728 /* FIXME DVI/Intel IMA ADPCM/ACM code 17 */
12729 caps = gst_caps_new_simple ("audio/x-adpcm",
12730 "layout", G_TYPE_STRING, "quicktime", NULL);
12734 /* MPEG layer 3, CBR only (pre QT4.1) */
12736 _codec ("MPEG-1 layer 3");
12737 /* MPEG layer 3, CBR & VBR (QT4.1 and later) */
12738 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 3,
12739 "mpegversion", G_TYPE_INT, 1, NULL);
12742 case GST_MAKE_FOURCC ('e', 'c', '-', '3'):
12743 _codec ("EAC-3 audio");
12744 caps = gst_caps_new_simple ("audio/x-eac3",
12745 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
12746 stream->sampled = TRUE;
12748 case GST_MAKE_FOURCC ('s', 'a', 'c', '3'): // Nero Recode
12750 _codec ("AC-3 audio");
12751 caps = gst_caps_new_simple ("audio/x-ac3",
12752 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
12753 stream->sampled = TRUE;
12755 case GST_MAKE_FOURCC ('d', 't', 's', 'c'):
12756 case GST_MAKE_FOURCC ('D', 'T', 'S', ' '):
12757 _codec ("DTS audio");
12758 caps = gst_caps_new_simple ("audio/x-dts",
12759 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
12760 stream->sampled = TRUE;
12762 case GST_MAKE_FOURCC ('d', 't', 's', 'h'): // DTS-HD
12763 case GST_MAKE_FOURCC ('d', 't', 's', 'l'): // DTS-HD Lossless
12764 _codec ("DTS-HD audio");
12765 caps = gst_caps_new_simple ("audio/x-dts",
12766 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
12767 stream->sampled = TRUE;
12771 caps = gst_caps_new_simple ("audio/x-mace",
12772 "maceversion", G_TYPE_INT, 3, NULL);
12776 caps = gst_caps_new_simple ("audio/x-mace",
12777 "maceversion", G_TYPE_INT, 6, NULL);
12779 case GST_MAKE_FOURCC ('O', 'g', 'g', 'V'):
12781 caps = gst_caps_new_empty_simple ("application/ogg");
12783 case GST_MAKE_FOURCC ('d', 'v', 'c', 'a'):
12784 _codec ("DV audio");
12785 caps = gst_caps_new_empty_simple ("audio/x-dv");
12788 _codec ("MPEG-4 AAC audio");
12789 caps = gst_caps_new_simple ("audio/mpeg",
12790 "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE,
12791 "stream-format", G_TYPE_STRING, "raw", NULL);
12793 case GST_MAKE_FOURCC ('Q', 'D', 'M', 'C'):
12794 _codec ("QDesign Music");
12795 caps = gst_caps_new_empty_simple ("audio/x-qdm");
12798 _codec ("QDesign Music v.2");
12799 /* FIXME: QDesign music version 2 (no constant) */
12800 if (FALSE && data) {
12801 caps = gst_caps_new_simple ("audio/x-qdm2",
12802 "framesize", G_TYPE_INT, QT_UINT32 (data + 52),
12803 "bitrate", G_TYPE_INT, QT_UINT32 (data + 40),
12804 "blocksize", G_TYPE_INT, QT_UINT32 (data + 44), NULL);
12806 caps = gst_caps_new_empty_simple ("audio/x-qdm2");
12810 _codec ("GSM audio");
12811 caps = gst_caps_new_empty_simple ("audio/x-gsm");
12814 _codec ("AMR audio");
12815 caps = gst_caps_new_empty_simple ("audio/AMR");
12818 _codec ("AMR-WB audio");
12819 caps = gst_caps_new_empty_simple ("audio/AMR-WB");
12822 _codec ("Quicktime IMA ADPCM");
12823 caps = gst_caps_new_simple ("audio/x-adpcm",
12824 "layout", G_TYPE_STRING, "quicktime", NULL);
12827 _codec ("Apple lossless audio");
12828 caps = gst_caps_new_empty_simple ("audio/x-alac");
12830 case GST_MAKE_FOURCC ('Q', 'c', 'l', 'p'):
12831 _codec ("QualComm PureVoice");
12832 caps = gst_caps_from_string ("audio/qcelp");
12837 caps = gst_caps_new_empty_simple ("audio/x-wma");
12841 caps = gst_caps_new_empty_simple ("audio/x-opus");
12843 case GST_MAKE_FOURCC ('l', 'p', 'c', 'm'):
12848 GstAudioFormat format;
12851 FLAG_IS_FLOAT = 0x1,
12852 FLAG_IS_BIG_ENDIAN = 0x2,
12853 FLAG_IS_SIGNED = 0x4,
12854 FLAG_IS_PACKED = 0x8,
12855 FLAG_IS_ALIGNED_HIGH = 0x10,
12856 FLAG_IS_NON_INTERLEAVED = 0x20
12858 _codec ("Raw LPCM audio");
12860 if (data && len >= 56) {
12861 depth = QT_UINT32 (data + 40);
12862 flags = QT_UINT32 (data + 44);
12863 width = QT_UINT32 (data + 48) * 8 / stream->n_channels;
12865 if ((flags & FLAG_IS_FLOAT) == 0) {
12870 format = gst_audio_format_build_integer ((flags & FLAG_IS_SIGNED) ?
12871 TRUE : FALSE, (flags & FLAG_IS_BIG_ENDIAN) ?
12872 G_BIG_ENDIAN : G_LITTLE_ENDIAN, width, depth);
12873 caps = gst_caps_new_simple ("audio/x-raw",
12874 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
12875 "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
12876 "non-interleaved" : "interleaved", NULL);
12881 if (flags & FLAG_IS_BIG_ENDIAN)
12882 format = GST_AUDIO_FORMAT_F64BE;
12884 format = GST_AUDIO_FORMAT_F64LE;
12886 if (flags & FLAG_IS_BIG_ENDIAN)
12887 format = GST_AUDIO_FORMAT_F32BE;
12889 format = GST_AUDIO_FORMAT_F32LE;
12891 caps = gst_caps_new_simple ("audio/x-raw",
12892 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
12893 "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
12894 "non-interleaved" : "interleaved", NULL);
12898 case GST_MAKE_FOURCC ('q', 't', 'v', 'r'):
12902 char *s, fourstr[5];
12904 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
12905 s = g_strdup_printf ("audio/x-gst-fourcc-%s", g_strstrip (fourstr));
12906 caps = gst_caps_new_empty_simple (s);
12913 GstCaps *templ_caps =
12914 gst_static_pad_template_get_caps (&gst_qtdemux_audiosrc_template);
12915 GstCaps *intersection = gst_caps_intersect (caps, templ_caps);
12916 gst_caps_unref (caps);
12917 gst_caps_unref (templ_caps);
12918 caps = intersection;
12921 /* enable clipping for raw audio streams */
12922 s = gst_caps_get_structure (caps, 0);
12923 name = gst_structure_get_name (s);
12924 if (g_str_has_prefix (name, "audio/x-raw")) {
12925 stream->need_clip = TRUE;
12926 stream->max_buffer_size = 4096 * stream->bytes_per_frame;
12927 GST_DEBUG ("setting max buffer size to %d", stream->max_buffer_size);
12933 qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
12934 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
12938 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
12942 _codec ("DVD subtitle");
12943 caps = gst_caps_new_empty_simple ("subpicture/x-dvd");
12944 stream->need_process = TRUE;
12947 _codec ("Quicktime timed text");
12950 _codec ("3GPP timed text");
12952 caps = gst_caps_new_simple ("text/x-raw", "format", G_TYPE_STRING,
12954 /* actual text piece needs to be extracted */
12955 stream->need_process = TRUE;
12958 _codec ("XML subtitles");
12959 caps = gst_caps_new_empty_simple ("application/ttml+xml");
12963 char *s, fourstr[5];
12965 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
12966 s = g_strdup_printf ("text/x-gst-fourcc-%s", g_strstrip (fourstr));
12967 caps = gst_caps_new_empty_simple (s);
12976 qtdemux_generic_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
12977 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
12983 _codec ("MPEG 1 video");
12984 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
12985 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
12995 gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux,
12996 const gchar * system_id)
13000 if (!qtdemux->protection_system_ids)
13001 qtdemux->protection_system_ids =
13002 g_ptr_array_new_with_free_func ((GDestroyNotify) g_free);
13003 /* Check whether we already have an entry for this system ID. */
13004 for (i = 0; i < qtdemux->protection_system_ids->len; ++i) {
13005 const gchar *id = g_ptr_array_index (qtdemux->protection_system_ids, i);
13006 if (g_ascii_strcasecmp (system_id, id) == 0) {
13010 GST_DEBUG_OBJECT (qtdemux, "Adding cenc protection system ID %s", system_id);
13011 g_ptr_array_add (qtdemux->protection_system_ids, g_ascii_strdown (system_id,