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;
3168 const guint8 *aux_info_type_data = NULL;
3170 g_return_val_if_fail (qtdemux != NULL, FALSE);
3171 g_return_val_if_fail (stream != NULL, FALSE);
3172 g_return_val_if_fail (br != NULL, FALSE);
3173 g_return_val_if_fail (offset != NULL, FALSE);
3175 if (!gst_byte_reader_get_uint8 (br, &version))
3178 if (!gst_byte_reader_get_uint24_be (br, &flags))
3183 if (!gst_byte_reader_get_data (br, 4, &aux_info_type_data))
3185 aux_info_type = QT_FOURCC (aux_info_type_data);
3187 if (!gst_byte_reader_get_uint32_be (br, &aux_info_type_parameter))
3189 } else if (stream->protected) {
3190 aux_info_type = stream->protection_scheme_type;
3192 aux_info_type = stream->fourcc;
3196 *info_type = aux_info_type;
3197 if (info_type_parameter)
3198 *info_type_parameter = aux_info_type_parameter;
3200 GST_DEBUG_OBJECT (qtdemux, "aux_info_type: '%" GST_FOURCC_FORMAT "', "
3201 "aux_info_type_parameter: %#06x",
3202 GST_FOURCC_ARGS (aux_info_type), aux_info_type_parameter);
3204 if (!gst_byte_reader_get_uint32_be (br, &entry_count))
3207 if (entry_count != 1) {
3208 GST_ERROR_OBJECT (qtdemux, "multiple offsets are not supported");
3213 if (!gst_byte_reader_get_uint32_be (br, &off_32))
3215 *offset = (guint64) off_32;
3217 if (!gst_byte_reader_get_uint64_be (br, &off_64))
3222 GST_DEBUG_OBJECT (qtdemux, "offset: %" G_GUINT64_FORMAT, *offset);
3227 qtdemux_gst_structure_free (GstStructure * gststructure)
3230 gst_structure_free (gststructure);
3234 /* Parses auxiliary information relating to samples protected using Common
3235 * Encryption (cenc); the format of this information is defined in
3236 * ISO/IEC 23001-7. Returns TRUE if successful; FALSE otherwise. */
3238 qtdemux_parse_cenc_aux_info (GstQTDemux * qtdemux, QtDemuxStream * stream,
3239 GstByteReader * br, guint8 * info_sizes, guint32 sample_count)
3241 QtDemuxCencSampleSetInfo *ss_info = NULL;
3245 g_return_val_if_fail (qtdemux != NULL, FALSE);
3246 g_return_val_if_fail (stream != NULL, FALSE);
3247 g_return_val_if_fail (br != NULL, FALSE);
3248 g_return_val_if_fail (stream->protected, FALSE);
3249 g_return_val_if_fail (stream->protection_scheme_info != NULL, FALSE);
3251 ss_info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
3253 if (ss_info->crypto_info) {
3254 GST_LOG_OBJECT (qtdemux, "unreffing existing crypto_info");
3255 g_ptr_array_free (ss_info->crypto_info, TRUE);
3258 ss_info->crypto_info =
3259 g_ptr_array_new_full (sample_count,
3260 (GDestroyNotify) qtdemux_gst_structure_free);
3262 for (i = 0; i < sample_count; ++i) {
3263 GstStructure *properties;
3264 guint16 n_subsamples = 0;
3269 properties = qtdemux_get_cenc_sample_properties (qtdemux, stream, i);
3270 if (properties == NULL) {
3271 GST_ERROR_OBJECT (qtdemux, "failed to get properties for sample %u", i);
3274 if (!gst_structure_get_uint (properties, "iv_size", &iv_size)) {
3275 GST_ERROR_OBJECT (qtdemux, "failed to get iv_size for sample %u", i);
3276 gst_structure_free (properties);
3279 if (!gst_byte_reader_dup_data (br, iv_size, &data)) {
3280 GST_ERROR_OBJECT (qtdemux, "failed to get IV for sample %u", i);
3281 gst_structure_free (properties);
3284 buf = gst_buffer_new_wrapped (data, iv_size);
3285 gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL);
3286 gst_buffer_unref (buf);
3287 size = info_sizes[i];
3288 if (size > iv_size) {
3289 if (!gst_byte_reader_get_uint16_be (br, &n_subsamples)
3290 || !(n_subsamples > 0)) {
3291 gst_structure_free (properties);
3292 GST_ERROR_OBJECT (qtdemux,
3293 "failed to get subsample count for sample %u", i);
3296 GST_LOG_OBJECT (qtdemux, "subsample count: %u", n_subsamples);
3297 if (!gst_byte_reader_dup_data (br, n_subsamples * 6, &data)) {
3298 GST_ERROR_OBJECT (qtdemux, "failed to get subsample data for sample %u",
3300 gst_structure_free (properties);
3303 buf = gst_buffer_new_wrapped (data, n_subsamples * 6);
3305 gst_structure_free (properties);
3308 gst_structure_set (properties,
3309 "subsample_count", G_TYPE_UINT, n_subsamples,
3310 "subsamples", GST_TYPE_BUFFER, buf, NULL);
3311 gst_buffer_unref (buf);
3313 gst_structure_set (properties, "subsample_count", G_TYPE_UINT, 0, NULL);
3315 g_ptr_array_add (ss_info->crypto_info, properties);
3320 /* Converts a UUID in raw byte form to a string representation, as defined in
3321 * RFC 4122. The caller takes ownership of the returned string and is
3322 * responsible for freeing it after use. */
3324 qtdemux_uuid_bytes_to_string (gconstpointer uuid_bytes)
3326 const guint8 *uuid = (const guint8 *) uuid_bytes;
3328 return g_strdup_printf ("%02x%02x%02x%02x-%02x%02x-%02x%02x-"
3329 "%02x%02x-%02x%02x%02x%02x%02x%02x",
3330 uuid[0], uuid[1], uuid[2], uuid[3],
3331 uuid[4], uuid[5], uuid[6], uuid[7],
3332 uuid[8], uuid[9], uuid[10], uuid[11],
3333 uuid[12], uuid[13], uuid[14], uuid[15]);
3336 /* Parses a Protection System Specific Header box (pssh), as defined in the
3337 * Common Encryption (cenc) standard (ISO/IEC 23001-7), which contains
3338 * information needed by a specific content protection system in order to
3339 * decrypt cenc-protected tracks. Returns TRUE if successful; FALSE
3342 qtdemux_parse_pssh (GstQTDemux * qtdemux, GNode * node)
3344 gchar *sysid_string;
3345 guint32 pssh_size = QT_UINT32 (node->data);
3346 GstBuffer *pssh = NULL;
3347 GstEvent *event = NULL;
3348 guint32 parent_box_type;
3351 if (G_UNLIKELY (pssh_size < 32U)) {
3352 GST_ERROR_OBJECT (qtdemux, "invalid box size");
3357 qtdemux_uuid_bytes_to_string ((const guint8 *) node->data + 12);
3359 gst_qtdemux_append_protection_system_id (qtdemux, sysid_string);
3361 pssh = gst_buffer_new_wrapped (g_memdup (node->data, pssh_size), pssh_size);
3362 GST_LOG_OBJECT (qtdemux, "cenc pssh size: %" G_GSIZE_FORMAT,
3363 gst_buffer_get_size (pssh));
3365 parent_box_type = QT_FOURCC ((const guint8 *) node->parent->data + 4);
3367 /* Push an event containing the pssh box onto the queues of all streams. */
3368 event = gst_event_new_protection (sysid_string, pssh,
3369 (parent_box_type == FOURCC_moov) ? "isobmff/moov" : "isobmff/moof");
3370 for (i = 0; i < qtdemux->n_streams; ++i) {
3371 g_queue_push_tail (&qtdemux->streams[i]->protection_scheme_event_queue,
3372 gst_event_ref (event));
3374 g_free (sysid_string);
3375 gst_event_unref (event);
3376 gst_buffer_unref (pssh);
3381 qtdemux_parse_moof (GstQTDemux * qtdemux, const guint8 * buffer, guint length,
3382 guint64 moof_offset, QtDemuxStream * stream)
3384 GNode *moof_node, *traf_node, *tfhd_node, *trun_node, *tfdt_node, *mfhd_node;
3385 GstByteReader mfhd_data, trun_data, tfhd_data, tfdt_data;
3386 GNode *saiz_node, *saio_node, *pssh_node;
3387 GstByteReader saiz_data, saio_data;
3388 guint32 ds_size = 0, ds_duration = 0, ds_flags = 0;
3389 gint64 base_offset, running_offset;
3392 /* NOTE @stream ignored */
3394 moof_node = g_node_new ((guint8 *) buffer);
3395 qtdemux_parse_node (qtdemux, moof_node, buffer, length);
3396 qtdemux_node_dump (qtdemux, moof_node);
3398 /* Get fragment number from mfhd and check it's valid */
3400 qtdemux_tree_get_child_by_type_full (moof_node, FOURCC_mfhd, &mfhd_data);
3401 if (mfhd_node == NULL)
3403 if (!qtdemux_parse_mfhd (qtdemux, &mfhd_data, &frag_num))
3405 GST_DEBUG_OBJECT (qtdemux, "Fragment #%d", frag_num);
3407 /* unknown base_offset to start with */
3408 base_offset = running_offset = -1;
3409 traf_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_traf);
3411 guint64 decode_time = 0;
3413 /* Fragment Header node */
3415 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfhd,
3419 if (!qtdemux_parse_tfhd (qtdemux, &tfhd_data, &stream, &ds_duration,
3420 &ds_size, &ds_flags, &base_offset))
3423 /* The following code assumes at most a single set of sample auxiliary
3424 * data in the fragment (consisting of a saiz box and a corresponding saio
3425 * box); in theory, however, there could be multiple sets of sample
3426 * auxiliary data in a fragment. */
3428 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saiz,
3431 guint32 info_type = 0;
3433 guint32 info_type_parameter = 0;
3435 g_free (qtdemux->cenc_aux_info_sizes);
3437 qtdemux->cenc_aux_info_sizes =
3438 qtdemux_parse_saiz (qtdemux, stream, &saiz_data,
3439 &qtdemux->cenc_aux_sample_count);
3440 if (qtdemux->cenc_aux_info_sizes == NULL) {
3441 GST_ERROR_OBJECT (qtdemux, "failed to parse saiz box");
3445 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saio,
3448 GST_ERROR_OBJECT (qtdemux, "saiz box without a corresponding saio box");
3449 g_free (qtdemux->cenc_aux_info_sizes);
3450 qtdemux->cenc_aux_info_sizes = NULL;
3454 if (G_UNLIKELY (!qtdemux_parse_saio (qtdemux, stream, &saio_data,
3455 &info_type, &info_type_parameter, &offset))) {
3456 GST_ERROR_OBJECT (qtdemux, "failed to parse saio box");
3457 g_free (qtdemux->cenc_aux_info_sizes);
3458 qtdemux->cenc_aux_info_sizes = NULL;
3461 if (base_offset > qtdemux->moof_offset)
3462 offset += (guint64) (base_offset - qtdemux->moof_offset);
3463 if (info_type == FOURCC_cenc && info_type_parameter == 0U) {
3465 if (offset > length) {
3466 GST_DEBUG_OBJECT (qtdemux, "cenc auxiliary info stored out of moof");
3467 qtdemux->cenc_aux_info_offset = offset;
3469 gst_byte_reader_init (&br, buffer + offset, length - offset);
3470 if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
3471 qtdemux->cenc_aux_info_sizes,
3472 qtdemux->cenc_aux_sample_count)) {
3473 GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
3474 g_free (qtdemux->cenc_aux_info_sizes);
3475 qtdemux->cenc_aux_info_sizes = NULL;
3483 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfdt,
3486 GstClockTime decode_time_ts;
3488 /* We'll use decode_time to interpolate timestamps
3489 * in case the input timestamps are missing */
3490 qtdemux_parse_tfdt (qtdemux, &tfdt_data, &decode_time);
3492 decode_time_ts = QTSTREAMTIME_TO_GSTTIME (stream, decode_time);
3494 GST_DEBUG_OBJECT (qtdemux, "decode time %" G_GINT64_FORMAT
3495 " (%" GST_TIME_FORMAT ")", decode_time,
3496 GST_TIME_ARGS (decode_time_ts));
3498 /* Discard the fragment buffer timestamp info to avoid using it.
3499 * Rely on tfdt instead as it is more accurate than the timestamp
3500 * that is fetched from a manifest/playlist and is usually
3502 qtdemux->fragment_start = -1;
3505 if (G_UNLIKELY (!stream)) {
3506 /* we lost track of offset, we'll need to regain it,
3507 * but can delay complaining until later or avoid doing so altogether */
3511 if (G_UNLIKELY (base_offset < -1))
3514 if (qtdemux->upstream_format_is_time)
3515 gst_qtdemux_stream_flush_samples_data (qtdemux, stream);
3517 /* initialise moof sample data */
3518 stream->n_samples_moof = 0;
3519 stream->duration_moof = 0;
3521 /* Track Run node */
3523 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_trun,
3526 qtdemux_parse_trun (qtdemux, &trun_data, stream,
3527 ds_duration, ds_size, ds_flags, moof_offset, length, &base_offset,
3528 &running_offset, decode_time);
3529 /* iterate all siblings */
3530 trun_node = qtdemux_tree_get_sibling_by_type_full (trun_node, FOURCC_trun,
3533 /* if no new base_offset provided for next traf,
3534 * base is end of current traf */
3535 base_offset = running_offset;
3536 running_offset = -1;
3538 if (stream->n_samples_moof && stream->duration_moof)
3539 stream->new_caps = TRUE;
3542 /* iterate all siblings */
3543 traf_node = qtdemux_tree_get_sibling_by_type (traf_node, FOURCC_traf);
3546 /* parse any protection system info */
3547 pssh_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_pssh);
3549 GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
3550 qtdemux_parse_pssh (qtdemux, pssh_node);
3551 pssh_node = qtdemux_tree_get_sibling_by_type (pssh_node, FOURCC_pssh);
3554 g_node_destroy (moof_node);
3559 GST_DEBUG_OBJECT (qtdemux, "missing tfhd box");
3564 GST_DEBUG_OBJECT (qtdemux, "Missing mfhd box");
3569 GST_DEBUG_OBJECT (qtdemux, "lost offset");
3574 g_node_destroy (moof_node);
3575 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
3576 (_("This file is corrupt and cannot be played.")), (NULL));
3582 /* might be used if some day we actually use mfra & co
3583 * for random access to fragments,
3584 * but that will require quite some modifications and much less relying
3585 * on a sample array */
3589 qtdemux_parse_tfra (GstQTDemux * qtdemux, GNode * tfra_node)
3591 QtDemuxStream *stream;
3592 guint32 ver_flags, track_id, len, num_entries, i;
3593 guint value_size, traf_size, trun_size, sample_size;
3594 guint64 time = 0, moof_offset = 0;
3596 GstBuffer *buf = NULL;
3601 gst_byte_reader_init (&tfra, tfra_node->data, QT_UINT32 (tfra_node->data));
3603 if (!gst_byte_reader_skip (&tfra, 8))
3606 if (!gst_byte_reader_get_uint32_be (&tfra, &ver_flags))
3609 if (!gst_byte_reader_get_uint32_be (&tfra, &track_id)
3610 || !gst_byte_reader_get_uint32_be (&tfra, &len)
3611 || !gst_byte_reader_get_uint32_be (&tfra, &num_entries))
3614 GST_DEBUG_OBJECT (qtdemux, "parsing tfra box for track id %u", track_id);
3616 stream = qtdemux_find_stream (qtdemux, track_id);
3618 goto unknown_trackid;
3620 value_size = ((ver_flags >> 24) == 1) ? sizeof (guint64) : sizeof (guint32);
3621 sample_size = (len & 3) + 1;
3622 trun_size = ((len & 12) >> 2) + 1;
3623 traf_size = ((len & 48) >> 4) + 1;
3625 GST_DEBUG_OBJECT (qtdemux, "%u entries, sizes: value %u, traf %u, trun %u, "
3626 "sample %u", num_entries, value_size, traf_size, trun_size, sample_size);
3628 if (num_entries == 0)
3631 if (!qt_atom_parser_has_chunks (&tfra, num_entries,
3632 value_size + value_size + traf_size + trun_size + sample_size))
3635 g_free (stream->ra_entries);
3636 stream->ra_entries = g_new (QtDemuxRandomAccessEntry, num_entries);
3637 stream->n_ra_entries = num_entries;
3639 for (i = 0; i < num_entries; i++) {
3640 qt_atom_parser_get_offset (&tfra, value_size, &time);
3641 qt_atom_parser_get_offset (&tfra, value_size, &moof_offset);
3642 qt_atom_parser_get_uint_with_size_unchecked (&tfra, traf_size);
3643 qt_atom_parser_get_uint_with_size_unchecked (&tfra, trun_size);
3644 qt_atom_parser_get_uint_with_size_unchecked (&tfra, sample_size);
3646 time = QTSTREAMTIME_TO_GSTTIME (stream, time);
3648 GST_LOG_OBJECT (qtdemux, "fragment time: %" GST_TIME_FORMAT ", "
3649 " moof_offset: %" G_GUINT64_FORMAT, GST_TIME_ARGS (time), moof_offset);
3651 stream->ra_entries[i].ts = time;
3652 stream->ra_entries[i].moof_offset = moof_offset;
3654 /* don't want to go through the entire file and read all moofs at startup */
3656 ret = gst_qtdemux_pull_atom (qtdemux, moof_offset, 0, &buf);
3657 if (ret != GST_FLOW_OK)
3659 qtdemux_parse_moof (qtdemux, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf),
3660 moof_offset, stream);
3661 gst_buffer_unref (buf);
3665 check_update_duration (qtdemux, time);
3672 GST_WARNING_OBJECT (qtdemux, "Couldn't find stream for track %u", track_id);
3677 GST_WARNING_OBJECT (qtdemux, "broken traf box, ignoring");
3682 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
3688 qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux)
3690 GstMapInfo mfro_map = GST_MAP_INFO_INIT;
3691 GstMapInfo mfra_map = GST_MAP_INFO_INIT;
3692 GstBuffer *mfro = NULL, *mfra = NULL;
3694 gboolean ret = FALSE;
3695 GNode *mfra_node, *tfra_node;
3696 guint64 mfra_offset = 0;
3697 guint32 fourcc, mfra_size;
3700 /* query upstream size in bytes */
3701 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &len))
3702 goto size_query_failed;
3704 /* mfro box should be at the very end of the file */
3705 flow = gst_qtdemux_pull_atom (qtdemux, len - 16, 16, &mfro);
3706 if (flow != GST_FLOW_OK)
3709 gst_buffer_map (mfro, &mfro_map, GST_MAP_READ);
3711 fourcc = QT_FOURCC (mfro_map.data + 4);
3712 if (fourcc != FOURCC_mfro)
3715 GST_INFO_OBJECT (qtdemux, "Found mfro box");
3716 if (mfro_map.size < 16)
3717 goto invalid_mfro_size;
3719 mfra_size = QT_UINT32 (mfro_map.data + 12);
3720 if (mfra_size >= len)
3721 goto invalid_mfra_size;
3723 mfra_offset = len - mfra_size;
3725 GST_INFO_OBJECT (qtdemux, "mfra offset: %" G_GUINT64_FORMAT ", size %u",
3726 mfra_offset, mfra_size);
3728 /* now get and parse mfra box */
3729 flow = gst_qtdemux_pull_atom (qtdemux, mfra_offset, mfra_size, &mfra);
3730 if (flow != GST_FLOW_OK)
3733 gst_buffer_map (mfra, &mfra_map, GST_MAP_READ);
3735 mfra_node = g_node_new ((guint8 *) mfra_map.data);
3736 qtdemux_parse_node (qtdemux, mfra_node, mfra_map.data, mfra_map.size);
3738 tfra_node = qtdemux_tree_get_child_by_type (mfra_node, FOURCC_tfra);
3741 qtdemux_parse_tfra (qtdemux, tfra_node);
3742 /* iterate all siblings */
3743 tfra_node = qtdemux_tree_get_sibling_by_type (tfra_node, FOURCC_tfra);
3745 g_node_destroy (mfra_node);
3747 GST_INFO_OBJECT (qtdemux, "parsed movie fragment random access box (mfra)");
3753 if (mfro_map.memory != NULL)
3754 gst_buffer_unmap (mfro, &mfro_map);
3755 gst_buffer_unref (mfro);
3758 if (mfra_map.memory != NULL)
3759 gst_buffer_unmap (mfra, &mfra_map);
3760 gst_buffer_unref (mfra);
3767 GST_WARNING_OBJECT (qtdemux, "could not query upstream size");
3772 GST_WARNING_OBJECT (qtdemux, "mfro size is too small");
3777 GST_WARNING_OBJECT (qtdemux, "mfra_size in mfro box is invalid");
3782 GST_WARNING_OBJECT (qtdemux, "bogus mfra offset or size, broken file");
3788 add_offset (guint64 offset, guint64 advance)
3790 /* Avoid 64-bit overflow by clamping */
3791 if (offset > G_MAXUINT64 - advance)
3793 return offset + advance;
3796 static GstFlowReturn
3797 gst_qtdemux_loop_state_header (GstQTDemux * qtdemux)
3801 GstBuffer *buf = NULL;
3802 GstFlowReturn ret = GST_FLOW_OK;
3803 guint64 cur_offset = qtdemux->offset;
3806 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, 16, &buf);
3807 if (G_UNLIKELY (ret != GST_FLOW_OK))
3809 gst_buffer_map (buf, &map, GST_MAP_READ);
3810 if (G_LIKELY (map.size >= 8))
3811 extract_initial_length_and_fourcc (map.data, map.size, &length, &fourcc);
3812 gst_buffer_unmap (buf, &map);
3813 gst_buffer_unref (buf);
3815 /* maybe we already got most we needed, so only consider this eof */
3816 if (G_UNLIKELY (length == 0)) {
3817 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
3818 (_("Invalid atom size.")),
3819 ("Header atom '%" GST_FOURCC_FORMAT "' has empty length",
3820 GST_FOURCC_ARGS (fourcc)));
3827 /* record for later parsing when needed */
3828 if (!qtdemux->moof_offset) {
3829 qtdemux->moof_offset = qtdemux->offset;
3831 if (qtdemux_pull_mfro_mfra (qtdemux)) {
3834 qtdemux->offset += length; /* skip moof and keep going */
3836 if (qtdemux->got_moov) {
3837 GST_INFO_OBJECT (qtdemux, "moof header, got moov, done with headers");
3848 GST_LOG_OBJECT (qtdemux,
3849 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
3850 GST_FOURCC_ARGS (fourcc), cur_offset);
3851 qtdemux->offset = add_offset (qtdemux->offset, length);
3856 GstBuffer *moov = NULL;
3858 if (qtdemux->got_moov) {
3859 GST_DEBUG_OBJECT (qtdemux, "Skipping moov atom as we have one already");
3860 qtdemux->offset = add_offset (qtdemux->offset, length);
3864 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, length, &moov);
3865 if (ret != GST_FLOW_OK)
3867 gst_buffer_map (moov, &map, GST_MAP_READ);
3869 if (length != map.size) {
3870 /* Some files have a 'moov' atom at the end of the file which contains
3871 * a terminal 'free' atom where the body of the atom is missing.
3872 * Check for, and permit, this special case.
3874 if (map.size >= 8) {
3875 guint8 *final_data = map.data + (map.size - 8);
3876 guint32 final_length = QT_UINT32 (final_data);
3877 guint32 final_fourcc = QT_FOURCC (final_data + 4);
3879 if (final_fourcc == FOURCC_free
3880 && map.size + final_length - 8 == length) {
3881 /* Ok, we've found that special case. Allocate a new buffer with
3882 * that free atom actually present. */
3883 GstBuffer *newmoov = gst_buffer_new_and_alloc (length);
3884 gst_buffer_fill (newmoov, 0, map.data, map.size);
3885 gst_buffer_memset (newmoov, map.size, 0, final_length - 8);
3886 gst_buffer_unmap (moov, &map);
3887 gst_buffer_unref (moov);
3889 gst_buffer_map (moov, &map, GST_MAP_READ);
3894 if (length != map.size) {
3895 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
3896 (_("This file is incomplete and cannot be played.")),
3897 ("We got less than expected (received %" G_GSIZE_FORMAT
3898 ", wanted %u, offset %" G_GUINT64_FORMAT ")", map.size,
3899 (guint) length, cur_offset));
3900 gst_buffer_unmap (moov, &map);
3901 gst_buffer_unref (moov);
3902 ret = GST_FLOW_ERROR;
3905 qtdemux->offset += length;
3907 qtdemux_parse_moov (qtdemux, map.data, length);
3908 qtdemux_node_dump (qtdemux, qtdemux->moov_node);
3910 qtdemux_parse_tree (qtdemux);
3911 g_node_destroy (qtdemux->moov_node);
3912 gst_buffer_unmap (moov, &map);
3913 gst_buffer_unref (moov);
3914 qtdemux->moov_node = NULL;
3915 qtdemux->got_moov = TRUE;
3921 GstBuffer *ftyp = NULL;
3923 /* extract major brand; might come in handy for ISO vs QT issues */
3924 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &ftyp);
3925 if (ret != GST_FLOW_OK)
3927 qtdemux->offset += length;
3928 gst_buffer_map (ftyp, &map, GST_MAP_READ);
3929 qtdemux_parse_ftyp (qtdemux, map.data, map.size);
3930 gst_buffer_unmap (ftyp, &map);
3931 gst_buffer_unref (ftyp);
3936 GstBuffer *uuid = NULL;
3938 /* uuid are extension atoms */
3939 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &uuid);
3940 if (ret != GST_FLOW_OK)
3942 qtdemux->offset += length;
3943 gst_buffer_map (uuid, &map, GST_MAP_READ);
3944 qtdemux_parse_uuid (qtdemux, map.data, map.size);
3945 gst_buffer_unmap (uuid, &map);
3946 gst_buffer_unref (uuid);
3951 GstBuffer *sidx = NULL;
3952 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &sidx);
3953 if (ret != GST_FLOW_OK)
3955 qtdemux->offset += length;
3956 gst_buffer_map (sidx, &map, GST_MAP_READ);
3957 qtdemux_parse_sidx (qtdemux, map.data, map.size);
3958 gst_buffer_unmap (sidx, &map);
3959 gst_buffer_unref (sidx);
3964 GstBuffer *unknown = NULL;
3966 GST_LOG_OBJECT (qtdemux,
3967 "unknown %08x '%" GST_FOURCC_FORMAT "' of size %" G_GUINT64_FORMAT
3968 " at %" G_GUINT64_FORMAT, fourcc, GST_FOURCC_ARGS (fourcc), length,
3970 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &unknown);
3971 if (ret != GST_FLOW_OK)
3973 gst_buffer_map (unknown, &map, GST_MAP_READ);
3974 GST_MEMDUMP ("Unknown tag", map.data, map.size);
3975 gst_buffer_unmap (unknown, &map);
3976 gst_buffer_unref (unknown);
3977 qtdemux->offset += length;
3983 if (ret == GST_FLOW_EOS && (qtdemux->got_moov || qtdemux->media_caps)) {
3984 /* digested all data, show what we have */
3985 qtdemux_prepare_streams (qtdemux);
3986 ret = qtdemux_expose_streams (qtdemux);
3988 qtdemux->state = QTDEMUX_STATE_MOVIE;
3989 GST_DEBUG_OBJECT (qtdemux, "switching state to STATE_MOVIE (%d)",
3996 /* Seeks to the previous keyframe of the indexed stream and
3997 * aligns other streams with respect to the keyframe timestamp
3998 * of indexed stream. Only called in case of Reverse Playback
4000 static GstFlowReturn
4001 gst_qtdemux_seek_to_previous_keyframe (GstQTDemux * qtdemux)
4004 guint32 seg_idx = 0, k_index = 0;
4005 guint32 ref_seg_idx, ref_k_index;
4006 GstClockTime k_pos = 0, last_stop = 0;
4007 QtDemuxSegment *seg = NULL;
4008 QtDemuxStream *ref_str = NULL;
4009 guint64 seg_media_start_mov; /* segment media start time in mov format */
4012 /* Now we choose an arbitrary stream, get the previous keyframe timestamp
4013 * and finally align all the other streams on that timestamp with their
4014 * respective keyframes */
4015 for (n = 0; n < qtdemux->n_streams; n++) {
4016 QtDemuxStream *str = qtdemux->streams[n];
4018 /* No candidate yet, take the first stream */
4024 /* So that stream has a segment, we prefer video streams */
4025 if (str->subtype == FOURCC_vide) {
4031 if (G_UNLIKELY (!ref_str)) {
4032 GST_DEBUG_OBJECT (qtdemux, "couldn't find any stream");
4036 if (G_UNLIKELY (!ref_str->from_sample)) {
4037 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of the file");
4041 /* So that stream has been playing from from_sample to to_sample. We will
4042 * get the timestamp of the previous sample and search for a keyframe before
4043 * that. For audio streams we do an arbitrary jump in the past (10 samples) */
4044 if (ref_str->subtype == FOURCC_vide) {
4045 k_index = gst_qtdemux_find_keyframe (qtdemux, ref_str,
4046 ref_str->from_sample - 1);
4048 if (ref_str->from_sample >= 10)
4049 k_index = ref_str->from_sample - 10;
4055 ref_str->samples[k_index].timestamp +
4056 ref_str->samples[k_index].pts_offset;
4058 /* get current segment for that stream */
4059 seg = &ref_str->segments[ref_str->segment_index];
4060 /* Use segment start in original timescale for comparisons */
4061 seg_media_start_mov = seg->trak_media_start;
4063 GST_LOG_OBJECT (qtdemux, "keyframe index %u ts %" G_GUINT64_FORMAT
4064 " seg start %" G_GUINT64_FORMAT " %" GST_TIME_FORMAT "\n",
4065 k_index, target_ts, seg_media_start_mov,
4066 GST_TIME_ARGS (seg->media_start));
4068 /* Crawl back through segments to find the one containing this I frame */
4069 while (target_ts < seg_media_start_mov) {
4070 GST_DEBUG_OBJECT (qtdemux,
4071 "keyframe position (sample %u) is out of segment %u " " target %"
4072 G_GUINT64_FORMAT " seg start %" G_GUINT64_FORMAT, k_index,
4073 ref_str->segment_index, target_ts, seg_media_start_mov);
4075 if (G_UNLIKELY (!ref_str->segment_index)) {
4076 /* Reached first segment, let's consider it's EOS */
4079 ref_str->segment_index--;
4080 seg = &ref_str->segments[ref_str->segment_index];
4081 /* Use segment start in original timescale for comparisons */
4082 seg_media_start_mov = seg->trak_media_start;
4084 /* Calculate time position of the keyframe and where we should stop */
4086 QTSTREAMTIME_TO_GSTTIME (ref_str,
4087 target_ts - seg->trak_media_start) + seg->time;
4089 QTSTREAMTIME_TO_GSTTIME (ref_str,
4090 ref_str->samples[ref_str->from_sample].timestamp -
4091 seg->trak_media_start) + seg->time;
4093 GST_DEBUG_OBJECT (qtdemux, "preferred stream played from sample %u, "
4094 "now going to sample %u (pts %" GST_TIME_FORMAT ")", ref_str->from_sample,
4095 k_index, GST_TIME_ARGS (k_pos));
4097 /* Set last_stop with the keyframe timestamp we pushed of that stream */
4098 qtdemux->segment.position = last_stop;
4099 GST_DEBUG_OBJECT (qtdemux, "last_stop now is %" GST_TIME_FORMAT,
4100 GST_TIME_ARGS (last_stop));
4102 if (G_UNLIKELY (last_stop < qtdemux->segment.start)) {
4103 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of segment");
4107 ref_seg_idx = ref_str->segment_index;
4108 ref_k_index = k_index;
4110 /* Align them all on this */
4111 for (n = 0; n < qtdemux->n_streams; n++) {
4113 GstClockTime seg_time = 0;
4114 QtDemuxStream *str = qtdemux->streams[n];
4116 /* aligning reference stream again might lead to backing up to yet another
4117 * keyframe (due to timestamp rounding issues),
4118 * potentially putting more load on downstream; so let's try to avoid */
4119 if (str == ref_str) {
4120 seg_idx = ref_seg_idx;
4121 seg = &str->segments[seg_idx];
4122 k_index = ref_k_index;
4123 GST_DEBUG_OBJECT (qtdemux, "reference stream %d segment %d, "
4124 "sample at index %d", n, ref_str->segment_index, k_index);
4126 seg_idx = gst_qtdemux_find_segment (qtdemux, str, k_pos);
4127 GST_DEBUG_OBJECT (qtdemux,
4128 "stream %d align segment %d for keyframe pos %" GST_TIME_FORMAT, n,
4129 seg_idx, GST_TIME_ARGS (k_pos));
4131 /* get segment and time in the segment */
4132 seg = &str->segments[seg_idx];
4133 seg_time = k_pos - seg->time;
4135 /* get the media time in the segment.
4136 * No adjustment for empty "filler" segments */
4137 if (seg->media_start != GST_CLOCK_TIME_NONE)
4138 seg_time += seg->media_start;
4140 /* get the index of the sample with media time */
4141 index = gst_qtdemux_find_index_linear (qtdemux, str, seg_time);
4142 GST_DEBUG_OBJECT (qtdemux,
4143 "stream %d sample for %" GST_TIME_FORMAT " at %u", n,
4144 GST_TIME_ARGS (seg_time), index);
4146 /* find previous keyframe */
4147 k_index = gst_qtdemux_find_keyframe (qtdemux, str, index);
4150 /* Remember until where we want to go */
4151 str->to_sample = str->from_sample - 1;
4152 /* Define our time position */
4154 str->samples[k_index].timestamp + str->samples[k_index].pts_offset;
4155 str->time_position = QTSTREAMTIME_TO_GSTTIME (str, target_ts) + seg->time;
4156 if (seg->media_start != GST_CLOCK_TIME_NONE)
4157 str->time_position -= seg->media_start;
4159 /* Now seek back in time */
4160 gst_qtdemux_move_stream (qtdemux, str, k_index);
4161 GST_DEBUG_OBJECT (qtdemux, "stream %d keyframe at %u, time position %"
4162 GST_TIME_FORMAT " playing from sample %u to %u", n, k_index,
4163 GST_TIME_ARGS (str->time_position), str->from_sample, str->to_sample);
4169 return GST_FLOW_EOS;
4172 /* activate the given segment number @seg_idx of @stream at time @offset.
4173 * @offset is an absolute global position over all the segments.
4175 * This will push out a NEWSEGMENT event with the right values and
4176 * position the stream index to the first decodable sample before
4180 gst_qtdemux_activate_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
4181 guint32 seg_idx, GstClockTime offset)
4184 QtDemuxSegment *segment;
4185 guint32 index, kf_index;
4186 GstClockTime seg_time;
4187 GstClockTime start, stop, time;
4190 GST_LOG_OBJECT (stream->pad, "activate segment %d, offset %" GST_TIME_FORMAT,
4191 seg_idx, GST_TIME_ARGS (offset));
4193 /* update the current segment */
4194 stream->segment_index = seg_idx;
4196 /* get the segment */
4197 segment = &stream->segments[seg_idx];
4199 if (G_UNLIKELY (offset < segment->time)) {
4200 GST_WARNING_OBJECT (stream->pad, "offset < segment->time %" GST_TIME_FORMAT,
4201 GST_TIME_ARGS (segment->time));
4205 /* segment lies beyond total indicated duration */
4206 if (G_UNLIKELY (qtdemux->segment.duration != GST_CLOCK_TIME_NONE &&
4207 segment->time > qtdemux->segment.duration)) {
4208 GST_WARNING_OBJECT (stream->pad, "file duration %" GST_TIME_FORMAT
4209 " < segment->time %" GST_TIME_FORMAT,
4210 GST_TIME_ARGS (qtdemux->segment.duration),
4211 GST_TIME_ARGS (segment->time));
4215 /* get time in this segment */
4216 seg_time = offset - segment->time;
4218 GST_LOG_OBJECT (stream->pad, "seg_time %" GST_TIME_FORMAT,
4219 GST_TIME_ARGS (seg_time));
4221 if (G_UNLIKELY (seg_time > segment->duration)) {
4222 GST_LOG_OBJECT (stream->pad,
4223 "seg_time > segment->duration %" GST_TIME_FORMAT,
4224 GST_TIME_ARGS (segment->duration));
4225 seg_time = segment->duration;
4228 /* qtdemux->segment.stop is in outside-time-realm, whereas
4229 * segment->media_stop is in track-time-realm.
4231 * In order to compare the two, we need to bring segment.stop
4232 * into the track-time-realm */
4234 stop = qtdemux->segment.stop;
4235 if (stop == GST_CLOCK_TIME_NONE)
4236 stop = qtdemux->segment.duration;
4237 if (stop == GST_CLOCK_TIME_NONE)
4238 stop = segment->media_stop;
4241 MIN (segment->media_stop, stop - segment->time + segment->media_start);
4243 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
4244 start = segment->time + seg_time;
4246 stop = start - seg_time + segment->duration;
4247 } else if (qtdemux->segment.rate >= 0) {
4248 start = MIN (segment->media_start + seg_time, stop);
4251 if (segment->media_start >= qtdemux->segment.start) {
4252 time = segment->time;
4254 time = segment->time + (qtdemux->segment.start - segment->media_start);
4257 start = MAX (segment->media_start, qtdemux->segment.start);
4258 stop = MIN (segment->media_start + seg_time, stop);
4261 GST_DEBUG_OBJECT (stream->pad, "new segment %d from %" GST_TIME_FORMAT
4262 " to %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT, seg_idx,
4263 GST_TIME_ARGS (start), GST_TIME_ARGS (stop), GST_TIME_ARGS (time));
4265 /* combine global rate with that of the segment */
4266 rate = segment->rate * qtdemux->segment.rate;
4268 /* Copy flags from main segment */
4269 stream->segment.flags = qtdemux->segment.flags;
4271 /* update the segment values used for clipping */
4272 stream->segment.offset = qtdemux->segment.offset;
4273 stream->segment.base = qtdemux->segment.base + stream->accumulated_base;
4274 stream->segment.applied_rate = qtdemux->segment.applied_rate;
4275 stream->segment.rate = rate;
4276 stream->segment.start = start + QTSTREAMTIME_TO_GSTTIME (stream,
4277 stream->cslg_shift);
4278 stream->segment.stop = stop + QTSTREAMTIME_TO_GSTTIME (stream,
4279 stream->cslg_shift);
4280 stream->segment.time = time;
4281 stream->segment.position = stream->segment.start;
4283 GST_DEBUG_OBJECT (stream->pad, "New segment: %" GST_SEGMENT_FORMAT,
4286 /* now prepare and send the segment */
4288 event = gst_event_new_segment (&stream->segment);
4289 if (stream->segment_seqnum) {
4290 gst_event_set_seqnum (event, stream->segment_seqnum);
4292 gst_pad_push_event (stream->pad, event);
4293 /* assume we can send more data now */
4294 GST_PAD_LAST_FLOW_RETURN (stream->pad) = GST_FLOW_OK;
4295 /* clear to send tags on this pad now */
4296 gst_qtdemux_push_tags (qtdemux, stream);
4299 /* in the fragmented case, we pick a fragment that starts before our
4300 * desired position and rely on downstream to wait for a keyframe
4301 * (FIXME: doesn't seem to work so well with ismv and wmv, as no parser; the
4302 * tfra entries tells us which trun/sample the key unit is in, but we don't
4303 * make use of this additional information at the moment) */
4304 if (qtdemux->fragmented) {
4305 stream->to_sample = G_MAXUINT32;
4309 /* We don't need to look for a sample in push-based */
4310 if (!qtdemux->pullbased)
4313 /* and move to the keyframe before the indicated media time of the
4315 if (G_LIKELY (!QTSEGMENT_IS_EMPTY (segment))) {
4316 if (qtdemux->segment.rate >= 0) {
4317 index = gst_qtdemux_find_index_linear (qtdemux, stream, start);
4318 stream->to_sample = G_MAXUINT32;
4319 GST_DEBUG_OBJECT (stream->pad,
4320 "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
4321 GST_TIME_FORMAT, GST_TIME_ARGS (start), index,
4322 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
4324 index = gst_qtdemux_find_index_linear (qtdemux, stream, stop);
4325 stream->to_sample = index;
4326 GST_DEBUG_OBJECT (stream->pad,
4327 "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
4328 GST_TIME_FORMAT, GST_TIME_ARGS (stop), index,
4329 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
4332 GST_DEBUG_OBJECT (stream->pad, "No need to look for keyframe, "
4333 "this is an empty segment");
4337 /* gst_qtdemux_parse_sample () called from gst_qtdemux_find_index_linear ()
4338 * encountered an error and printed a message so we return appropriately */
4342 /* we're at the right spot */
4343 if (index == stream->sample_index) {
4344 GST_DEBUG_OBJECT (stream->pad, "we are at the right index");
4348 /* find keyframe of the target index */
4349 kf_index = gst_qtdemux_find_keyframe (qtdemux, stream, index);
4352 /* indent does stupid stuff with stream->samples[].timestamp */
4354 /* if we move forwards, we don't have to go back to the previous
4355 * keyframe since we already sent that. We can also just jump to
4356 * the keyframe right before the target index if there is one. */
4357 if (index > stream->sample_index) {
4358 /* moving forwards check if we move past a keyframe */
4359 if (kf_index > stream->sample_index) {
4360 GST_DEBUG_OBJECT (stream->pad,
4361 "moving forwards to keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" )", kf_index,
4362 GST_TIME_ARGS (QTSAMPLE_PTS(stream, &stream->samples[kf_index])),
4363 GST_TIME_ARGS (QTSAMPLE_DTS(stream, &stream->samples[kf_index])));
4364 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
4366 GST_DEBUG_OBJECT (stream->pad,
4367 "moving forwards, keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" ) already sent", kf_index,
4368 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[kf_index])),
4369 GST_TIME_ARGS (QTSAMPLE_DTS (stream, &stream->samples[kf_index])));
4372 GST_DEBUG_OBJECT (stream->pad,
4373 "moving backwards to keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" )", kf_index,
4374 GST_TIME_ARGS (QTSAMPLE_PTS(stream, &stream->samples[kf_index])),
4375 GST_TIME_ARGS (QTSAMPLE_DTS(stream, &stream->samples[kf_index])));
4376 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
4384 /* prepare to get the current sample of @stream, getting essential values.
4386 * This function will also prepare and send the segment when needed.
4388 * Return FALSE if the stream is EOS.
4393 gst_qtdemux_prepare_current_sample (GstQTDemux * qtdemux,
4394 QtDemuxStream * stream, gboolean * empty, guint64 * offset, guint * size,
4395 GstClockTime * dts, GstClockTime * pts, GstClockTime * duration,
4396 gboolean * keyframe)
4398 QtDemuxSample *sample;
4399 GstClockTime time_position;
4402 g_return_val_if_fail (stream != NULL, FALSE);
4404 time_position = stream->time_position;
4405 if (G_UNLIKELY (time_position == GST_CLOCK_TIME_NONE))
4408 seg_idx = stream->segment_index;
4409 if (G_UNLIKELY (seg_idx == -1)) {
4410 /* find segment corresponding to time_position if we are looking
4412 seg_idx = gst_qtdemux_find_segment (qtdemux, stream, time_position);
4415 /* different segment, activate it, sample_index will be set. */
4416 if (G_UNLIKELY (stream->segment_index != seg_idx))
4417 gst_qtdemux_activate_segment (qtdemux, stream, seg_idx, time_position);
4419 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (&stream->segments[stream->
4421 QtDemuxSegment *seg = &stream->segments[stream->segment_index];
4423 GST_LOG_OBJECT (qtdemux, "Empty segment activated,"
4424 " prepare empty sample");
4427 *pts = *dts = time_position;
4428 *duration = seg->duration - (time_position - seg->time);
4435 if (stream->sample_index == -1)
4436 stream->sample_index = 0;
4438 GST_LOG_OBJECT (qtdemux, "segment active, index = %u of %u",
4439 stream->sample_index, stream->n_samples);
4441 if (G_UNLIKELY (stream->sample_index >= stream->n_samples)) {
4442 if (!qtdemux->fragmented)
4445 GST_INFO_OBJECT (qtdemux, "out of samples, trying to add more");
4449 GST_OBJECT_LOCK (qtdemux);
4450 flow = qtdemux_add_fragmented_samples (qtdemux);
4451 GST_OBJECT_UNLOCK (qtdemux);
4453 if (flow != GST_FLOW_OK)
4456 while (stream->sample_index >= stream->n_samples);
4459 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
4460 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
4461 stream->sample_index);
4465 /* now get the info for the sample we're at */
4466 sample = &stream->samples[stream->sample_index];
4468 *dts = QTSAMPLE_DTS (stream, sample);
4469 *pts = QTSAMPLE_PTS (stream, sample);
4470 *offset = sample->offset;
4471 *size = sample->size;
4472 *duration = QTSAMPLE_DUR_DTS (stream, sample, *dts);
4473 *keyframe = QTSAMPLE_KEYFRAME (stream, sample);
4480 stream->time_position = GST_CLOCK_TIME_NONE;
4485 /* move to the next sample in @stream.
4487 * Moves to the next segment when needed.
4490 gst_qtdemux_advance_sample (GstQTDemux * qtdemux, QtDemuxStream * stream)
4492 QtDemuxSample *sample;
4493 QtDemuxSegment *segment;
4495 /* get current segment */
4496 segment = &stream->segments[stream->segment_index];
4498 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
4499 GST_DEBUG_OBJECT (qtdemux, "Empty segment, no samples to advance");
4503 if (G_UNLIKELY (stream->sample_index >= stream->to_sample)) {
4504 /* Mark the stream as EOS */
4505 GST_DEBUG_OBJECT (qtdemux,
4506 "reached max allowed sample %u, mark EOS", stream->to_sample);
4507 stream->time_position = GST_CLOCK_TIME_NONE;
4511 /* move to next sample */
4512 stream->sample_index++;
4513 stream->offset_in_sample = 0;
4515 /* reached the last sample, we need the next segment */
4516 if (G_UNLIKELY (stream->sample_index >= stream->n_samples))
4519 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
4520 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
4521 stream->sample_index);
4525 /* get next sample */
4526 sample = &stream->samples[stream->sample_index];
4528 /* see if we are past the segment */
4529 if (G_UNLIKELY (QTSAMPLE_DTS (stream, sample) >= segment->media_stop))
4532 if (QTSAMPLE_DTS (stream, sample) >= segment->media_start) {
4533 /* inside the segment, update time_position, looks very familiar to
4534 * GStreamer segments, doesn't it? */
4535 stream->time_position =
4536 QTSAMPLE_DTS (stream, sample) - segment->media_start + segment->time;
4538 /* not yet in segment, time does not yet increment. This means
4539 * that we are still prerolling keyframes to the decoder so it can
4540 * decode the first sample of the segment. */
4541 stream->time_position = segment->time;
4545 /* move to the next segment */
4548 GST_DEBUG_OBJECT (qtdemux, "segment %d ended ", stream->segment_index);
4550 if (stream->segment_index == stream->n_segments - 1) {
4551 /* are we at the end of the last segment, we're EOS */
4552 stream->time_position = GST_CLOCK_TIME_NONE;
4554 /* else we're only at the end of the current segment */
4555 stream->time_position = segment->stop_time;
4557 /* make sure we select a new segment */
4559 /* accumulate previous segments */
4560 if (GST_CLOCK_TIME_IS_VALID (stream->segment.stop))
4561 stream->accumulated_base +=
4562 (stream->segment.stop -
4563 stream->segment.start) / ABS (stream->segment.rate);
4565 stream->segment_index = -1;
4570 gst_qtdemux_sync_streams (GstQTDemux * demux)
4574 if (demux->n_streams <= 1)
4577 for (i = 0; i < demux->n_streams; i++) {
4578 QtDemuxStream *stream;
4579 GstClockTime end_time;
4581 stream = demux->streams[i];
4586 /* TODO advance time on subtitle streams here, if any some day */
4588 /* some clips/trailers may have unbalanced streams at the end,
4589 * so send EOS on shorter stream to prevent stalling others */
4591 /* do not mess with EOS if SEGMENT seeking */
4592 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT)
4595 if (demux->pullbased) {
4596 /* loop mode is sample time based */
4597 if (!STREAM_IS_EOS (stream))
4600 /* push mode is byte position based */
4601 if (stream->n_samples &&
4602 stream->samples[stream->n_samples - 1].offset >= demux->offset)
4606 if (stream->sent_eos)
4609 /* only act if some gap */
4610 end_time = stream->segments[stream->n_segments - 1].stop_time;
4611 GST_LOG_OBJECT (demux, "current position: %" GST_TIME_FORMAT
4612 ", stream end: %" GST_TIME_FORMAT,
4613 GST_TIME_ARGS (demux->segment.position), GST_TIME_ARGS (end_time));
4614 if (GST_CLOCK_TIME_IS_VALID (end_time)
4615 && (end_time + 2 * GST_SECOND < demux->segment.position)) {
4616 GST_DEBUG_OBJECT (demux, "sending EOS for stream %s",
4617 GST_PAD_NAME (stream->pad));
4618 stream->sent_eos = TRUE;
4619 gst_pad_push_event (stream->pad, gst_event_new_eos ());
4624 /* EOS and NOT_LINKED need to be combined. This means that we return:
4626 * GST_FLOW_NOT_LINKED: when all pads NOT_LINKED.
4627 * GST_FLOW_EOS: when all pads EOS or NOT_LINKED.
4629 static GstFlowReturn
4630 gst_qtdemux_combine_flows (GstQTDemux * demux, QtDemuxStream * stream,
4633 GST_LOG_OBJECT (demux, "flow return: %s", gst_flow_get_name (ret));
4636 ret = gst_flow_combiner_update_pad_flow (demux->flowcombiner, stream->pad,
4639 ret = gst_flow_combiner_update_flow (demux->flowcombiner, ret);
4641 GST_LOG_OBJECT (demux, "combined flow return: %s", gst_flow_get_name (ret));
4645 /* the input buffer metadata must be writable. Returns NULL when the buffer is
4646 * completely clipped
4648 * Should be used only with raw buffers */
4650 gst_qtdemux_clip_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
4653 guint64 start, stop, cstart, cstop, diff;
4654 GstClockTime pts, duration;
4656 gint num_rate, denom_rate;
4661 osize = size = gst_buffer_get_size (buf);
4664 /* depending on the type, setup the clip parameters */
4665 if (stream->subtype == FOURCC_soun) {
4666 frame_size = stream->bytes_per_frame;
4667 num_rate = GST_SECOND;
4668 denom_rate = (gint) stream->rate;
4670 } else if (stream->subtype == FOURCC_vide) {
4672 num_rate = stream->fps_n;
4673 denom_rate = stream->fps_d;
4678 if (frame_size <= 0)
4679 goto bad_frame_size;
4681 /* we can only clip if we have a valid pts */
4682 pts = GST_BUFFER_PTS (buf);
4683 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (pts)))
4686 duration = GST_BUFFER_DURATION (buf);
4688 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (duration))) {
4690 gst_util_uint64_scale_int (size / frame_size, num_rate, denom_rate);
4694 stop = start + duration;
4696 if (G_UNLIKELY (!gst_segment_clip (&stream->segment,
4697 GST_FORMAT_TIME, start, stop, &cstart, &cstop)))
4700 /* see if some clipping happened */
4701 diff = cstart - start;
4707 /* bring clipped time to samples and to bytes */
4708 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
4711 GST_DEBUG_OBJECT (qtdemux,
4712 "clipping start to %" GST_TIME_FORMAT " %"
4713 G_GUINT64_FORMAT " bytes", GST_TIME_ARGS (cstart), diff);
4719 diff = stop - cstop;
4724 /* bring clipped time to samples and then to bytes */
4725 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
4727 GST_DEBUG_OBJECT (qtdemux,
4728 "clipping stop to %" GST_TIME_FORMAT " %" G_GUINT64_FORMAT
4729 " bytes", GST_TIME_ARGS (cstop), diff);
4734 if (offset != 0 || size != osize)
4735 gst_buffer_resize (buf, offset, size);
4737 GST_BUFFER_DTS (buf) = GST_CLOCK_TIME_NONE;
4738 GST_BUFFER_PTS (buf) = pts;
4739 GST_BUFFER_DURATION (buf) = duration;
4743 /* dropped buffer */
4746 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
4751 GST_DEBUG_OBJECT (qtdemux, "bad frame size");
4756 GST_DEBUG_OBJECT (qtdemux, "no pts on buffer");
4761 GST_DEBUG_OBJECT (qtdemux, "clipped buffer");
4762 gst_buffer_unref (buf);
4767 /* the input buffer metadata must be writable,
4768 * but time/duration etc not yet set and need not be preserved */
4770 gst_qtdemux_process_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
4777 /* not many cases for now */
4778 if (G_UNLIKELY (stream->fourcc == FOURCC_mp4s)) {
4779 /* send a one time dvd clut event */
4780 if (stream->pending_event && stream->pad)
4781 gst_pad_push_event (stream->pad, stream->pending_event);
4782 stream->pending_event = NULL;
4785 if (G_UNLIKELY (stream->subtype != FOURCC_text
4786 && stream->subtype != FOURCC_sbtl &&
4787 stream->subtype != FOURCC_subp)) {
4791 gst_buffer_map (buf, &map, GST_MAP_READ);
4793 /* empty buffer is sent to terminate previous subtitle */
4794 if (map.size <= 2) {
4795 gst_buffer_unmap (buf, &map);
4796 gst_buffer_unref (buf);
4799 if (stream->subtype == FOURCC_subp) {
4800 /* That's all the processing needed for subpictures */
4801 gst_buffer_unmap (buf, &map);
4805 nsize = GST_READ_UINT16_BE (map.data);
4806 nsize = MIN (nsize, map.size - 2);
4808 GST_LOG_OBJECT (qtdemux, "3GPP timed text subtitle: %d/%" G_GSIZE_FORMAT "",
4811 /* takes care of UTF-8 validation or UTF-16 recognition,
4812 * no other encoding expected */
4813 str = gst_tag_freeform_string_to_utf8 ((gchar *) map.data + 2, nsize, NULL);
4814 gst_buffer_unmap (buf, &map);
4816 gst_buffer_unref (buf);
4817 buf = _gst_buffer_new_wrapped (str, strlen (str), g_free);
4819 /* this should not really happen unless the subtitle is corrupted */
4820 gst_buffer_unref (buf);
4824 /* FIXME ? convert optional subsequent style info to markup */
4829 /* Sets a buffer's attributes properly and pushes it downstream.
4830 * Also checks for additional actions and custom processing that may
4831 * need to be done first.
4833 static GstFlowReturn
4834 gst_qtdemux_decorate_and_push_buffer (GstQTDemux * qtdemux,
4835 QtDemuxStream * stream, GstBuffer * buf,
4836 GstClockTime dts, GstClockTime pts, GstClockTime duration,
4837 gboolean keyframe, GstClockTime position, guint64 byte_position)
4839 GstFlowReturn ret = GST_FLOW_OK;
4841 /* offset the timestamps according to the edit list */
4843 if (G_UNLIKELY (stream->fourcc == FOURCC_rtsp)) {
4847 gst_buffer_map (buf, &map, GST_MAP_READ);
4848 url = g_strndup ((gchar *) map.data, map.size);
4849 gst_buffer_unmap (buf, &map);
4850 if (url != NULL && strlen (url) != 0) {
4851 /* we have RTSP redirect now */
4852 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
4853 gst_message_new_element (GST_OBJECT_CAST (qtdemux),
4854 gst_structure_new ("redirect",
4855 "new-location", G_TYPE_STRING, url, NULL)));
4856 qtdemux->posted_redirect = TRUE;
4858 GST_WARNING_OBJECT (qtdemux, "Redirect URI of stream is empty, not "
4864 /* position reporting */
4865 if (qtdemux->segment.rate >= 0) {
4866 qtdemux->segment.position = position;
4867 gst_qtdemux_sync_streams (qtdemux);
4870 if (G_UNLIKELY (!stream->pad)) {
4871 GST_DEBUG_OBJECT (qtdemux, "No output pad for stream, ignoring");
4872 gst_buffer_unref (buf);
4876 /* send out pending buffers */
4877 while (stream->buffers) {
4878 GstBuffer *buffer = (GstBuffer *) stream->buffers->data;
4880 if (G_UNLIKELY (stream->discont)) {
4881 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
4882 GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
4883 stream->discont = FALSE;
4885 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
4888 gst_pad_push (stream->pad, buffer);
4890 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
4893 /* we're going to modify the metadata */
4894 buf = gst_buffer_make_writable (buf);
4896 if (G_UNLIKELY (stream->need_process))
4897 buf = gst_qtdemux_process_buffer (qtdemux, stream, buf);
4903 GST_BUFFER_DTS (buf) = dts;
4904 GST_BUFFER_PTS (buf) = pts;
4905 GST_BUFFER_DURATION (buf) = duration;
4906 GST_BUFFER_OFFSET (buf) = -1;
4907 GST_BUFFER_OFFSET_END (buf) = -1;
4909 if (G_UNLIKELY (stream->rgb8_palette))
4910 gst_buffer_append_memory (buf, gst_memory_ref (stream->rgb8_palette));
4912 if (G_UNLIKELY (stream->padding)) {
4913 gst_buffer_resize (buf, stream->padding, -1);
4916 if (G_UNLIKELY (qtdemux->element_index)) {
4917 GstClockTime stream_time;
4920 gst_segment_to_stream_time (&stream->segment, GST_FORMAT_TIME,
4922 if (GST_CLOCK_TIME_IS_VALID (stream_time)) {
4923 GST_LOG_OBJECT (qtdemux,
4924 "adding association %" GST_TIME_FORMAT "-> %"
4925 G_GUINT64_FORMAT, GST_TIME_ARGS (stream_time), byte_position);
4926 gst_index_add_association (qtdemux->element_index,
4928 keyframe ? GST_ASSOCIATION_FLAG_KEY_UNIT :
4929 GST_ASSOCIATION_FLAG_DELTA_UNIT, GST_FORMAT_TIME, stream_time,
4930 GST_FORMAT_BYTES, byte_position, NULL);
4935 if (stream->need_clip)
4936 buf = gst_qtdemux_clip_buffer (qtdemux, stream, buf);
4938 if (G_UNLIKELY (buf == NULL))
4941 if (G_UNLIKELY (stream->discont)) {
4942 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
4943 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
4944 stream->discont = FALSE;
4946 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
4950 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
4951 stream->on_keyframe = FALSE;
4953 stream->on_keyframe = TRUE;
4957 GST_LOG_OBJECT (qtdemux,
4958 "Pushing buffer with dts %" GST_TIME_FORMAT ", pts %" GST_TIME_FORMAT
4959 ", duration %" GST_TIME_FORMAT " on pad %s", GST_TIME_ARGS (dts),
4960 GST_TIME_ARGS (pts), GST_TIME_ARGS (duration),
4961 GST_PAD_NAME (stream->pad));
4963 if (stream->protected && stream->protection_scheme_type == FOURCC_cenc) {
4964 GstStructure *crypto_info;
4965 QtDemuxCencSampleSetInfo *info =
4966 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
4970 while ((event = g_queue_pop_head (&stream->protection_scheme_event_queue))) {
4971 gst_pad_push_event (stream->pad, event);
4974 if (qtdemux->cenc_aux_info_offset > 0 && info->crypto_info == NULL) {
4975 GST_DEBUG_OBJECT (qtdemux, "cenc metadata hasn't been parsed yet");
4976 gst_buffer_unref (buf);
4980 index = stream->sample_index - (stream->n_samples - info->crypto_info->len);
4981 if (G_LIKELY (index >= 0 && index < info->crypto_info->len)) {
4982 /* steal structure from array */
4983 crypto_info = g_ptr_array_index (info->crypto_info, index);
4984 g_ptr_array_index (info->crypto_info, index) = NULL;
4985 GST_LOG_OBJECT (qtdemux, "attaching cenc metadata [%u]", index);
4986 if (!crypto_info || !gst_buffer_add_protection_meta (buf, crypto_info))
4987 GST_ERROR_OBJECT (qtdemux, "failed to attach cenc metadata to buffer");
4991 ret = gst_pad_push (stream->pad, buf);
4993 if (GST_CLOCK_TIME_IS_VALID (pts) && GST_CLOCK_TIME_IS_VALID (duration)) {
4994 /* mark position in stream, we'll need this to know when to send GAP event */
4995 stream->segment.position = pts + duration;
5002 static const QtDemuxRandomAccessEntry *
5003 gst_qtdemux_stream_seek_fragment (GstQTDemux * qtdemux, QtDemuxStream * stream,
5004 GstClockTime pos, gboolean after)
5006 QtDemuxRandomAccessEntry *entries = stream->ra_entries;
5007 guint n_entries = stream->n_ra_entries;
5010 /* we assume the table is sorted */
5011 for (i = 0; i < n_entries; ++i) {
5012 if (entries[i].ts > pos)
5016 /* FIXME: maybe save first moof_offset somewhere instead, but for now it's
5017 * probably okay to assume that the index lists the very first fragment */
5024 return &entries[i - 1];
5028 gst_qtdemux_do_fragmented_seek (GstQTDemux * qtdemux)
5030 const QtDemuxRandomAccessEntry *best_entry = NULL;
5033 GST_OBJECT_LOCK (qtdemux);
5035 g_assert (qtdemux->n_streams > 0);
5037 for (i = 0; i < qtdemux->n_streams; i++) {
5038 const QtDemuxRandomAccessEntry *entry;
5039 QtDemuxStream *stream;
5040 gboolean is_audio_or_video;
5042 stream = qtdemux->streams[i];
5044 g_free (stream->samples);
5045 stream->samples = NULL;
5046 stream->n_samples = 0;
5047 stream->stbl_index = -1; /* no samples have yet been parsed */
5048 stream->sample_index = -1;
5050 if (stream->ra_entries == NULL)
5053 if (stream->subtype == FOURCC_vide || stream->subtype == FOURCC_soun)
5054 is_audio_or_video = TRUE;
5056 is_audio_or_video = FALSE;
5059 gst_qtdemux_stream_seek_fragment (qtdemux, stream,
5060 stream->time_position, !is_audio_or_video);
5062 GST_INFO_OBJECT (stream->pad, "%" GST_TIME_FORMAT " at offset "
5063 "%" G_GUINT64_FORMAT, GST_TIME_ARGS (entry->ts), entry->moof_offset);
5065 stream->pending_seek = entry;
5067 /* decide position to jump to just based on audio/video tracks, not subs */
5068 if (!is_audio_or_video)
5071 if (best_entry == NULL || entry->moof_offset < best_entry->moof_offset)
5075 if (best_entry == NULL) {
5076 GST_OBJECT_UNLOCK (qtdemux);
5080 GST_INFO_OBJECT (qtdemux, "seek to %" GST_TIME_FORMAT ", best fragment "
5081 "moof offset: %" G_GUINT64_FORMAT ", ts %" GST_TIME_FORMAT,
5082 GST_TIME_ARGS (qtdemux->streams[0]->time_position),
5083 best_entry->moof_offset, GST_TIME_ARGS (best_entry->ts));
5085 qtdemux->moof_offset = best_entry->moof_offset;
5087 qtdemux_add_fragmented_samples (qtdemux);
5089 GST_OBJECT_UNLOCK (qtdemux);
5093 static GstFlowReturn
5094 gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux)
5096 GstFlowReturn ret = GST_FLOW_OK;
5097 GstBuffer *buf = NULL;
5098 QtDemuxStream *stream;
5099 GstClockTime min_time;
5101 GstClockTime dts = GST_CLOCK_TIME_NONE;
5102 GstClockTime pts = GST_CLOCK_TIME_NONE;
5103 GstClockTime duration = 0;
5104 gboolean keyframe = FALSE;
5105 guint sample_size = 0;
5111 gst_qtdemux_push_pending_newsegment (qtdemux);
5113 if (qtdemux->fragmented_seek_pending) {
5114 GST_INFO_OBJECT (qtdemux, "pending fragmented seek");
5115 gst_qtdemux_do_fragmented_seek (qtdemux);
5116 GST_INFO_OBJECT (qtdemux, "fragmented seek done!");
5117 qtdemux->fragmented_seek_pending = FALSE;
5120 /* Figure out the next stream sample to output, min_time is expressed in
5121 * global time and runs over the edit list segments. */
5122 min_time = G_MAXUINT64;
5124 for (i = 0; i < qtdemux->n_streams; i++) {
5125 GstClockTime position;
5127 stream = qtdemux->streams[i];
5128 position = stream->time_position;
5130 /* position of -1 is EOS */
5131 if (position != GST_CLOCK_TIME_NONE && position < min_time) {
5132 min_time = position;
5137 if (G_UNLIKELY (index == -1)) {
5138 GST_DEBUG_OBJECT (qtdemux, "all streams are EOS");
5142 /* check for segment end */
5143 if (G_UNLIKELY (qtdemux->segment.stop != -1
5144 && ((qtdemux->segment.rate >= 0 && qtdemux->segment.stop <= min_time)
5145 || (qtdemux->segment.rate < 0
5146 && qtdemux->segment.start > min_time))
5147 && qtdemux->streams[index]->on_keyframe)) {
5148 GST_DEBUG_OBJECT (qtdemux, "we reached the end of our segment.");
5149 qtdemux->streams[index]->time_position = GST_CLOCK_TIME_NONE;
5153 /* gap events for subtitle streams */
5154 for (i = 0; i < qtdemux->n_streams; i++) {
5155 stream = qtdemux->streams[i];
5156 if (stream->pad && (stream->subtype == FOURCC_subp
5157 || stream->subtype == FOURCC_text
5158 || stream->subtype == FOURCC_sbtl)) {
5159 /* send one second gap events until the stream catches up */
5160 /* gaps can only be sent after segment is activated (segment.stop is no longer -1) */
5161 while (GST_CLOCK_TIME_IS_VALID (stream->segment.stop) &&
5162 GST_CLOCK_TIME_IS_VALID (stream->segment.position) &&
5163 stream->segment.position + GST_SECOND < min_time) {
5165 gst_event_new_gap (stream->segment.position, GST_SECOND);
5166 gst_pad_push_event (stream->pad, gap);
5167 stream->segment.position += GST_SECOND;
5172 stream = qtdemux->streams[index];
5173 if (stream->new_caps) {
5174 gst_qtdemux_configure_stream (qtdemux, stream);
5175 qtdemux_do_allocation (qtdemux, stream);
5178 /* fetch info for the current sample of this stream */
5179 if (G_UNLIKELY (!gst_qtdemux_prepare_current_sample (qtdemux, stream, &empty,
5180 &offset, &sample_size, &dts, &pts, &duration, &keyframe)))
5183 /* If we're doing a keyframe-only trickmode, only push keyframes on video streams */
5184 if (G_UNLIKELY (qtdemux->
5185 segment.flags & GST_SEGMENT_FLAG_TRICKMODE_KEY_UNITS)) {
5186 if (stream->subtype == FOURCC_vide && !keyframe) {
5187 GST_LOG_OBJECT (qtdemux, "Skipping non-keyframe on stream %d", index);
5192 GST_DEBUG_OBJECT (qtdemux,
5193 "pushing from stream %d, empty %d offset %" G_GUINT64_FORMAT
5194 ", size %d, dts=%" GST_TIME_FORMAT ", pts=%" GST_TIME_FORMAT
5195 ", duration %" GST_TIME_FORMAT, index, empty, offset, sample_size,
5196 GST_TIME_ARGS (dts), GST_TIME_ARGS (pts), GST_TIME_ARGS (duration));
5198 if (G_UNLIKELY (empty)) {
5199 /* empty segment, push a gap and move to the next one */
5200 gst_pad_push_event (stream->pad, gst_event_new_gap (pts, duration));
5201 stream->segment.position = pts + duration;
5205 /* hmm, empty sample, skip and move to next sample */
5206 if (G_UNLIKELY (sample_size <= 0))
5209 /* last pushed sample was out of boundary, goto next sample */
5210 if (G_UNLIKELY (GST_PAD_LAST_FLOW_RETURN (stream->pad) == GST_FLOW_EOS))
5213 if (stream->max_buffer_size == 0 || sample_size <= stream->max_buffer_size) {
5216 GST_DEBUG_OBJECT (qtdemux,
5217 "size %d larger than stream max_buffer_size %d, trimming",
5218 sample_size, stream->max_buffer_size);
5220 MIN (sample_size - stream->offset_in_sample, stream->max_buffer_size);
5223 GST_LOG_OBJECT (qtdemux, "reading %d bytes @ %" G_GUINT64_FORMAT, size,
5226 if (stream->use_allocator) {
5227 /* if we have a per-stream allocator, use it */
5228 buf = gst_buffer_new_allocate (stream->allocator, size, &stream->params);
5231 ret = gst_qtdemux_pull_atom (qtdemux, offset + stream->offset_in_sample,
5233 if (G_UNLIKELY (ret != GST_FLOW_OK))
5236 if (size != sample_size) {
5237 pts += gst_util_uint64_scale_int (GST_SECOND,
5238 stream->offset_in_sample / stream->bytes_per_frame, stream->timescale);
5239 dts += gst_util_uint64_scale_int (GST_SECOND,
5240 stream->offset_in_sample / stream->bytes_per_frame, stream->timescale);
5241 duration = gst_util_uint64_scale_int (GST_SECOND,
5242 size / stream->bytes_per_frame, stream->timescale);
5245 ret = gst_qtdemux_decorate_and_push_buffer (qtdemux, stream, buf,
5246 dts, pts, duration, keyframe, min_time, offset);
5248 if (size != sample_size) {
5249 QtDemuxSample *sample = &stream->samples[stream->sample_index];
5250 QtDemuxSegment *segment = &stream->segments[stream->segment_index];
5252 GstClockTime time_position = QTSTREAMTIME_TO_GSTTIME (stream,
5253 sample->timestamp + stream->offset_in_sample / stream->bytes_per_frame);
5254 if (time_position >= segment->media_start) {
5255 /* inside the segment, update time_position, looks very familiar to
5256 * GStreamer segments, doesn't it? */
5257 stream->time_position = (time_position - segment->media_start) +
5260 /* not yet in segment, time does not yet increment. This means
5261 * that we are still prerolling keyframes to the decoder so it can
5262 * decode the first sample of the segment. */
5263 stream->time_position = segment->time;
5268 ret = gst_qtdemux_combine_flows (qtdemux, stream, ret);
5269 /* ignore unlinked, we will not push on the pad anymore and we will EOS when
5270 * we have no more data for the pad to push */
5271 if (ret == GST_FLOW_EOS)
5274 stream->offset_in_sample += size;
5275 if (stream->offset_in_sample >= sample_size) {
5276 gst_qtdemux_advance_sample (qtdemux, stream);
5281 gst_qtdemux_advance_sample (qtdemux, stream);
5289 GST_DEBUG_OBJECT (qtdemux, "No samples left for any streams - EOS");
5295 GST_DEBUG_OBJECT (qtdemux, "No samples left for stream");
5296 /* EOS will be raised if all are EOS */
5303 gst_qtdemux_loop (GstPad * pad)
5305 GstQTDemux *qtdemux;
5309 qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
5311 cur_offset = qtdemux->offset;
5312 GST_LOG_OBJECT (qtdemux, "loop at position %" G_GUINT64_FORMAT ", state %d",
5313 cur_offset, qtdemux->state);
5315 switch (qtdemux->state) {
5316 case QTDEMUX_STATE_INITIAL:
5317 case QTDEMUX_STATE_HEADER:
5318 ret = gst_qtdemux_loop_state_header (qtdemux);
5320 case QTDEMUX_STATE_MOVIE:
5321 ret = gst_qtdemux_loop_state_movie (qtdemux);
5322 if (qtdemux->segment.rate < 0 && ret == GST_FLOW_EOS) {
5323 ret = gst_qtdemux_seek_to_previous_keyframe (qtdemux);
5331 /* if something went wrong, pause */
5332 if (ret != GST_FLOW_OK)
5336 gst_object_unref (qtdemux);
5342 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
5343 (NULL), ("streaming stopped, invalid state"));
5344 gst_pad_pause_task (pad);
5345 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
5350 const gchar *reason = gst_flow_get_name (ret);
5352 GST_LOG_OBJECT (qtdemux, "pausing task, reason %s", reason);
5354 gst_pad_pause_task (pad);
5356 /* fatal errors need special actions */
5358 if (ret == GST_FLOW_EOS) {
5359 if (qtdemux->n_streams == 0) {
5360 /* we have no streams, post an error */
5361 gst_qtdemux_post_no_playable_stream_error (qtdemux);
5363 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
5366 if ((stop = qtdemux->segment.stop) == -1)
5367 stop = qtdemux->segment.duration;
5369 if (qtdemux->segment.rate >= 0) {
5370 GST_LOG_OBJECT (qtdemux, "Sending segment done, at end of segment");
5371 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
5372 gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
5373 GST_FORMAT_TIME, stop));
5374 gst_qtdemux_push_event (qtdemux,
5375 gst_event_new_segment_done (GST_FORMAT_TIME, stop));
5377 /* For Reverse Playback */
5378 GST_LOG_OBJECT (qtdemux, "Sending segment done, at start of segment");
5379 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
5380 gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
5381 GST_FORMAT_TIME, qtdemux->segment.start));
5382 gst_qtdemux_push_event (qtdemux,
5383 gst_event_new_segment_done (GST_FORMAT_TIME,
5384 qtdemux->segment.start));
5387 GST_LOG_OBJECT (qtdemux, "Sending EOS at end of segment");
5388 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
5390 } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
5391 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
5392 (NULL), ("streaming stopped, reason %s", reason));
5393 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
5402 * Returns if there are samples to be played.
5405 has_next_entry (GstQTDemux * demux)
5407 QtDemuxStream *stream;
5410 GST_DEBUG_OBJECT (demux, "Checking if there are samples not played yet");
5412 for (i = 0; i < demux->n_streams; i++) {
5413 stream = demux->streams[i];
5415 if (stream->sample_index == -1) {
5416 stream->sample_index = 0;
5417 stream->offset_in_sample = 0;
5420 if (stream->sample_index >= stream->n_samples) {
5421 GST_LOG_OBJECT (demux, "stream %d samples exhausted", i);
5424 GST_DEBUG_OBJECT (demux, "Found a sample");
5428 GST_DEBUG_OBJECT (demux, "There wasn't any next sample");
5435 * Returns the size of the first entry at the current offset.
5436 * If -1, there are none (which means EOS or empty file).
5439 next_entry_size (GstQTDemux * demux)
5441 QtDemuxStream *stream;
5444 guint64 smalloffs = (guint64) - 1;
5445 QtDemuxSample *sample;
5447 GST_LOG_OBJECT (demux, "Finding entry at offset %" G_GUINT64_FORMAT,
5450 for (i = 0; i < demux->n_streams; i++) {
5451 stream = demux->streams[i];
5453 if (stream->sample_index == -1) {
5454 stream->sample_index = 0;
5455 stream->offset_in_sample = 0;
5458 if (stream->sample_index >= stream->n_samples) {
5459 GST_LOG_OBJECT (demux, "stream %d samples exhausted", i);
5463 if (!qtdemux_parse_samples (demux, stream, stream->sample_index)) {
5464 GST_LOG_OBJECT (demux, "Parsing of index %u from stbl atom failed!",
5465 stream->sample_index);
5469 sample = &stream->samples[stream->sample_index];
5471 GST_LOG_OBJECT (demux,
5472 "Checking Stream %d (sample_index:%d / offset:%" G_GUINT64_FORMAT
5473 " / size:%" G_GUINT32_FORMAT ")", i, stream->sample_index,
5474 sample->offset, sample->size);
5476 if (((smalloffs == -1)
5477 || (sample->offset < smalloffs)) && (sample->size)) {
5479 smalloffs = sample->offset;
5483 GST_LOG_OBJECT (demux,
5484 "stream %d offset %" G_GUINT64_FORMAT " demux->offset :%"
5485 G_GUINT64_FORMAT, smallidx, smalloffs, demux->offset);
5490 stream = demux->streams[smallidx];
5491 sample = &stream->samples[stream->sample_index];
5493 if (sample->offset >= demux->offset) {
5494 demux->todrop = sample->offset - demux->offset;
5495 return sample->size + demux->todrop;
5498 GST_DEBUG_OBJECT (demux,
5499 "There wasn't any entry at offset %" G_GUINT64_FORMAT, demux->offset);
5504 gst_qtdemux_post_progress (GstQTDemux * demux, gint num, gint denom)
5506 gint perc = (gint) ((gdouble) num * 100.0 / (gdouble) denom);
5508 gst_element_post_message (GST_ELEMENT_CAST (demux),
5509 gst_message_new_element (GST_OBJECT_CAST (demux),
5510 gst_structure_new ("progress", "percent", G_TYPE_INT, perc, NULL)));
5514 qtdemux_seek_offset (GstQTDemux * demux, guint64 offset)
5519 GST_DEBUG_OBJECT (demux, "Seeking to %" G_GUINT64_FORMAT, offset);
5522 gst_event_new_seek (1.0, GST_FORMAT_BYTES,
5523 GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset,
5524 GST_SEEK_TYPE_NONE, -1);
5526 /* store seqnum to drop flush events, they don't need to reach downstream */
5527 demux->offset_seek_seqnum = gst_event_get_seqnum (event);
5528 res = gst_pad_push_event (demux->sinkpad, event);
5529 demux->offset_seek_seqnum = 0;
5534 /* check for seekable upstream, above and beyond a mere query */
5536 gst_qtdemux_check_seekability (GstQTDemux * demux)
5539 gboolean seekable = FALSE;
5540 gint64 start = -1, stop = -1;
5542 if (demux->upstream_size)
5545 query = gst_query_new_seeking (GST_FORMAT_BYTES);
5546 if (!gst_pad_peer_query (demux->sinkpad, query)) {
5547 GST_DEBUG_OBJECT (demux, "seeking query failed");
5551 gst_query_parse_seeking (query, NULL, &seekable, &start, &stop);
5553 /* try harder to query upstream size if we didn't get it the first time */
5554 if (seekable && stop == -1) {
5555 GST_DEBUG_OBJECT (demux, "doing duration query to fix up unset stop");
5556 gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &stop);
5559 /* if upstream doesn't know the size, it's likely that it's not seekable in
5560 * practice even if it technically may be seekable */
5561 if (seekable && (start != 0 || stop <= start)) {
5562 GST_DEBUG_OBJECT (demux, "seekable but unknown start/stop -> disable");
5567 gst_query_unref (query);
5569 GST_DEBUG_OBJECT (demux, "seekable: %d (%" G_GUINT64_FORMAT " - %"
5570 G_GUINT64_FORMAT ")", seekable, start, stop);
5571 demux->upstream_seekable = seekable;
5572 demux->upstream_size = seekable ? stop : -1;
5576 gst_qtdemux_drop_data (GstQTDemux * demux, gint bytes)
5578 g_return_if_fail (bytes <= demux->todrop);
5580 GST_LOG_OBJECT (demux, "Dropping %d bytes", bytes);
5581 gst_adapter_flush (demux->adapter, bytes);
5582 demux->neededbytes -= bytes;
5583 demux->offset += bytes;
5584 demux->todrop -= bytes;
5588 gst_qtdemux_check_send_pending_segment (GstQTDemux * demux)
5590 if (G_UNLIKELY (demux->pending_newsegment)) {
5593 gst_qtdemux_push_pending_newsegment (demux);
5594 /* clear to send tags on all streams */
5595 for (i = 0; i < demux->n_streams; i++) {
5596 QtDemuxStream *stream;
5597 stream = demux->streams[i];
5598 gst_qtdemux_push_tags (demux, stream);
5599 if (stream->sparse) {
5600 GST_INFO_OBJECT (demux, "Sending gap event on stream %d", i);
5601 gst_pad_push_event (stream->pad,
5602 gst_event_new_gap (stream->segment.position, GST_CLOCK_TIME_NONE));
5609 gst_qtdemux_stream_send_initial_gap_segments (GstQTDemux * demux,
5610 QtDemuxStream * stream)
5614 /* Push any initial gap segments before proceeding to the
5616 for (i = 0; i < stream->n_segments; i++) {
5617 gst_qtdemux_activate_segment (demux, stream, i, stream->time_position);
5619 if (QTSEGMENT_IS_EMPTY (&stream->segments[i])) {
5620 GstClockTime ts, dur;
5623 ts = stream->time_position;
5625 stream->segments[i].duration - (stream->time_position -
5626 stream->segments[i].time);
5627 gap = gst_event_new_gap (ts, dur);
5628 stream->time_position += dur;
5630 GST_DEBUG_OBJECT (stream->pad, "Pushing gap for empty "
5631 "segment: %" GST_PTR_FORMAT, gap);
5632 gst_pad_push_event (stream->pad, gap);
5634 /* Only support empty segment at the beginning followed by
5635 * one non-empty segment, this was checked when parsing the
5636 * edts atom, arriving here is unexpected */
5637 g_assert (i + 1 == stream->n_segments);
5643 static GstFlowReturn
5644 gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent, GstBuffer * inbuf)
5648 demux = GST_QTDEMUX (parent);
5650 if (GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_DISCONT)) {
5653 GST_DEBUG_OBJECT (demux, "Got DISCONT, marking all streams as DISCONT");
5655 for (i = 0; i < demux->n_streams; i++) {
5656 demux->streams[i]->discont = TRUE;
5659 /* Reverse fragmented playback, need to flush all we have before
5660 * consuming a new fragment.
5661 * The samples array have the timestamps calculated by accumulating the
5662 * durations but this won't work for reverse playback of fragments as
5663 * the timestamps of a subsequent fragment should be smaller than the
5664 * previously received one. */
5665 if (demux->fragmented && demux->segment.rate < 0) {
5666 gst_qtdemux_process_adapter (demux, TRUE);
5667 for (i = 0; i < demux->n_streams; i++)
5668 gst_qtdemux_stream_flush_samples_data (demux, demux->streams[i]);
5672 gst_adapter_push (demux->adapter, inbuf);
5674 GST_DEBUG_OBJECT (demux,
5675 "pushing in inbuf %p, neededbytes:%u, available:%" G_GSIZE_FORMAT, inbuf,
5676 demux->neededbytes, gst_adapter_available (demux->adapter));
5678 return gst_qtdemux_process_adapter (demux, FALSE);
5681 static GstFlowReturn
5682 gst_qtdemux_process_adapter (GstQTDemux * demux, gboolean force)
5684 GstFlowReturn ret = GST_FLOW_OK;
5686 /* we never really mean to buffer that much */
5687 if (demux->neededbytes == -1) {
5691 while (((gst_adapter_available (demux->adapter)) >= demux->neededbytes) &&
5692 (ret == GST_FLOW_OK || (ret == GST_FLOW_NOT_LINKED && force))) {
5694 GST_DEBUG_OBJECT (demux,
5695 "state:%d , demux->neededbytes:%d, demux->offset:%" G_GUINT64_FORMAT,
5696 demux->state, demux->neededbytes, demux->offset);
5698 switch (demux->state) {
5699 case QTDEMUX_STATE_INITIAL:{
5704 gst_qtdemux_check_seekability (demux);
5706 data = gst_adapter_map (demux->adapter, demux->neededbytes);
5708 /* get fourcc/length, set neededbytes */
5709 extract_initial_length_and_fourcc ((guint8 *) data, demux->neededbytes,
5711 gst_adapter_unmap (demux->adapter);
5713 GST_DEBUG_OBJECT (demux, "Peeking found [%" GST_FOURCC_FORMAT "] "
5714 "size: %" G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), size);
5716 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
5717 (_("This file is invalid and cannot be played.")),
5718 ("initial atom '%" GST_FOURCC_FORMAT "' has empty length",
5719 GST_FOURCC_ARGS (fourcc)));
5720 ret = GST_FLOW_ERROR;
5723 if (fourcc == FOURCC_mdat) {
5724 gint next_entry = next_entry_size (demux);
5725 if (demux->n_streams > 0 && (next_entry != -1 || !demux->fragmented)) {
5726 /* we have the headers, start playback */
5727 demux->state = QTDEMUX_STATE_MOVIE;
5728 demux->neededbytes = next_entry;
5729 demux->mdatleft = size;
5731 /* no headers yet, try to get them */
5734 guint64 old, target;
5737 old = demux->offset;
5738 target = old + size;
5740 /* try to jump over the atom with a seek */
5741 /* only bother if it seems worth doing so,
5742 * and avoids possible upstream/server problems */
5743 if (demux->upstream_seekable &&
5744 demux->upstream_size > 4 * (1 << 20)) {
5745 res = qtdemux_seek_offset (demux, target);
5747 GST_DEBUG_OBJECT (demux, "skipping seek");
5752 GST_DEBUG_OBJECT (demux, "seek success");
5753 /* remember the offset fo the first mdat so we can seek back to it
5754 * after we have the headers */
5755 if (fourcc == FOURCC_mdat && demux->first_mdat == -1) {
5756 demux->first_mdat = old;
5757 GST_DEBUG_OBJECT (demux, "first mdat at %" G_GUINT64_FORMAT,
5760 /* seek worked, continue reading */
5761 demux->offset = target;
5762 demux->neededbytes = 16;
5763 demux->state = QTDEMUX_STATE_INITIAL;
5765 /* seek failed, need to buffer */
5766 demux->offset = old;
5767 GST_DEBUG_OBJECT (demux, "seek failed/skipped");
5768 /* there may be multiple mdat (or alike) buffers */
5770 if (demux->mdatbuffer)
5771 bs = gst_buffer_get_size (demux->mdatbuffer);
5774 if (size + bs > 10 * (1 << 20))
5776 demux->state = QTDEMUX_STATE_BUFFER_MDAT;
5777 demux->neededbytes = size;
5778 if (!demux->mdatbuffer)
5779 demux->mdatoffset = demux->offset;
5782 } else if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
5783 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
5784 (_("This file is invalid and cannot be played.")),
5785 ("atom %" GST_FOURCC_FORMAT " has bogus size %" G_GUINT64_FORMAT,
5786 GST_FOURCC_ARGS (fourcc), size));
5787 ret = GST_FLOW_ERROR;
5790 /* this means we already started buffering and still no moov header,
5791 * let's continue buffering everything till we get moov */
5792 if (demux->mdatbuffer && !(fourcc == FOURCC_moov
5793 || fourcc == FOURCC_moof))
5795 demux->neededbytes = size;
5796 demux->state = QTDEMUX_STATE_HEADER;
5800 case QTDEMUX_STATE_HEADER:{
5804 GST_DEBUG_OBJECT (demux, "In header");
5806 data = gst_adapter_map (demux->adapter, demux->neededbytes);
5808 /* parse the header */
5809 extract_initial_length_and_fourcc (data, demux->neededbytes, NULL,
5811 if (fourcc == FOURCC_moov) {
5813 gboolean got_samples = FALSE;
5815 /* in usual fragmented setup we could try to scan for more
5816 * and end up at the the moov (after mdat) again */
5817 if (demux->got_moov && demux->n_streams > 0 &&
5819 || demux->last_moov_offset == demux->offset)) {
5820 GST_DEBUG_OBJECT (demux,
5821 "Skipping moov atom as we have (this) one already");
5823 GST_DEBUG_OBJECT (demux, "Parsing [moov]");
5825 if (demux->got_moov && demux->fragmented) {
5826 GST_DEBUG_OBJECT (demux,
5827 "Got a second moov, clean up data from old one");
5828 if (demux->moov_node)
5829 g_node_destroy (demux->moov_node);
5830 demux->moov_node = NULL;
5831 demux->moov_node_compressed = NULL;
5833 /* prepare newsegment to send when streaming actually starts */
5834 if (!demux->pending_newsegment)
5835 demux->pending_newsegment =
5836 gst_event_new_segment (&demux->segment);
5839 demux->last_moov_offset = demux->offset;
5841 qtdemux_parse_moov (demux, data, demux->neededbytes);
5842 qtdemux_node_dump (demux, demux->moov_node);
5843 qtdemux_parse_tree (demux);
5844 qtdemux_prepare_streams (demux);
5846 for (n = 0; n < demux->n_streams; n++) {
5847 QtDemuxStream *stream = demux->streams[n];
5848 got_samples |= stream->stbl_index >= 0;
5850 if (!demux->fragmented || got_samples) {
5851 if (!demux->got_moov) {
5852 qtdemux_expose_streams (demux);
5854 for (n = 0; n < demux->n_streams; n++) {
5855 QtDemuxStream *stream = demux->streams[n];
5856 gst_qtdemux_configure_stream (demux, stream);
5859 gst_qtdemux_check_send_pending_segment (demux);
5860 demux->pending_configure = FALSE;
5862 demux->pending_configure = TRUE;
5865 demux->got_moov = TRUE;
5867 /* fragmented streams headers shouldn't contain edts atoms */
5868 if (!demux->fragmented) {
5869 for (n = 0; n < demux->n_streams; n++) {
5870 gst_qtdemux_stream_send_initial_gap_segments (demux,
5875 g_node_destroy (demux->moov_node);
5876 demux->moov_node = NULL;
5877 GST_DEBUG_OBJECT (demux, "Finished parsing the header");
5879 } else if (fourcc == FOURCC_moof) {
5880 if ((demux->got_moov || demux->media_caps) && demux->fragmented) {
5882 GstClockTime prev_pts;
5883 guint64 prev_offset;
5886 GST_DEBUG_OBJECT (demux, "Parsing [moof]");
5889 * The timestamp of the moof buffer is relevant as some scenarios
5890 * won't have the initial timestamp in the atoms. Whenever a new
5891 * buffer has started, we get that buffer's PTS and use it as a base
5892 * timestamp for the trun entries.
5894 * To keep track of the current buffer timestamp and starting point
5895 * we use gst_adapter_prev_pts that gives us the PTS and the distance
5896 * from the beggining of the buffer, with the distance and demux->offset
5897 * we know if it is still the same buffer or not.
5899 prev_pts = gst_adapter_prev_pts (demux->adapter, &dist);
5900 prev_offset = demux->offset - dist;
5901 if (demux->fragment_start_offset == -1
5902 || prev_offset > demux->fragment_start_offset) {
5903 demux->fragment_start_offset = prev_offset;
5904 demux->fragment_start = prev_pts;
5905 GST_DEBUG_OBJECT (demux,
5906 "New fragment start found at: %" G_GUINT64_FORMAT " : %"
5907 GST_TIME_FORMAT, demux->fragment_start_offset,
5908 GST_TIME_ARGS (demux->fragment_start));
5911 demux->moof_offset = demux->offset;
5912 if (!qtdemux_parse_moof (demux, data, demux->neededbytes,
5913 demux->offset, NULL)) {
5914 gst_adapter_unmap (demux->adapter);
5915 ret = GST_FLOW_ERROR;
5918 /* in MSS we need to expose the pads after the first moof as we won't get a moov
5919 * Also, fragmented format need to be exposed if a moov have no valid sample data */
5920 if (demux->mss_mode || demux->pending_configure) {
5921 if (!demux->exposed) {
5922 if (!demux->pending_newsegment) {
5924 gst_segment_init (&segment, GST_FORMAT_TIME);
5925 GST_DEBUG_OBJECT (demux, "new pending_newsegment");
5926 demux->pending_newsegment = gst_event_new_segment (&segment);
5928 qtdemux_expose_streams (demux);
5930 for (n = 0; n < demux->n_streams; n++) {
5931 QtDemuxStream *stream = demux->streams[n];
5932 gst_qtdemux_configure_stream (demux, stream);
5935 gst_qtdemux_check_send_pending_segment (demux);
5936 demux->pending_configure = FALSE;
5939 GST_DEBUG_OBJECT (demux, "Discarding [moof]");
5941 } else if (fourcc == FOURCC_ftyp) {
5942 GST_DEBUG_OBJECT (demux, "Parsing [ftyp]");
5943 qtdemux_parse_ftyp (demux, data, demux->neededbytes);
5944 } else if (fourcc == FOURCC_uuid) {
5945 GST_DEBUG_OBJECT (demux, "Parsing [uuid]");
5946 qtdemux_parse_uuid (demux, data, demux->neededbytes);
5947 } else if (fourcc == FOURCC_sidx) {
5948 GST_DEBUG_OBJECT (demux, "Parsing [sidx]");
5949 qtdemux_parse_sidx (demux, data, demux->neededbytes);
5951 GST_WARNING_OBJECT (demux,
5952 "Unknown fourcc while parsing header : %" GST_FOURCC_FORMAT,
5953 GST_FOURCC_ARGS (fourcc));
5954 /* Let's jump that one and go back to initial state */
5956 gst_adapter_unmap (demux->adapter);
5959 if (demux->mdatbuffer && demux->n_streams) {
5960 gsize remaining_data_size = 0;
5962 /* the mdat was before the header */
5963 GST_DEBUG_OBJECT (demux, "We have n_streams:%d and mdatbuffer:%p",
5964 demux->n_streams, demux->mdatbuffer);
5965 /* restore our adapter/offset view of things with upstream;
5966 * put preceding buffered data ahead of current moov data.
5967 * This should also handle evil mdat, moov, mdat cases and alike */
5968 gst_adapter_flush (demux->adapter, demux->neededbytes);
5970 /* Store any remaining data after the mdat for later usage */
5971 remaining_data_size = gst_adapter_available (demux->adapter);
5972 if (remaining_data_size > 0) {
5973 g_assert (demux->restoredata_buffer == NULL);
5974 demux->restoredata_buffer =
5975 gst_adapter_take_buffer (demux->adapter, remaining_data_size);
5976 demux->restoredata_offset = demux->offset + demux->neededbytes;
5977 GST_DEBUG_OBJECT (demux,
5978 "Stored %" G_GSIZE_FORMAT " post mdat bytes at offset %"
5979 G_GUINT64_FORMAT, remaining_data_size,
5980 demux->restoredata_offset);
5983 gst_adapter_push (demux->adapter, demux->mdatbuffer);
5984 demux->mdatbuffer = NULL;
5985 demux->offset = demux->mdatoffset;
5986 demux->neededbytes = next_entry_size (demux);
5987 demux->state = QTDEMUX_STATE_MOVIE;
5988 demux->mdatleft = gst_adapter_available (demux->adapter);
5990 GST_DEBUG_OBJECT (demux, "Carrying on normally");
5991 gst_adapter_flush (demux->adapter, demux->neededbytes);
5993 /* only go back to the mdat if there are samples to play */
5994 if (demux->got_moov && demux->first_mdat != -1
5995 && has_next_entry (demux)) {
5998 /* we need to seek back */
5999 res = qtdemux_seek_offset (demux, demux->first_mdat);
6001 demux->offset = demux->first_mdat;
6003 GST_DEBUG_OBJECT (demux, "Seek back failed");
6006 demux->offset += demux->neededbytes;
6008 demux->neededbytes = 16;
6009 demux->state = QTDEMUX_STATE_INITIAL;
6014 case QTDEMUX_STATE_BUFFER_MDAT:{
6018 GST_DEBUG_OBJECT (demux, "Got our buffer at offset %" G_GUINT64_FORMAT,
6020 buf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
6021 gst_buffer_extract (buf, 0, fourcc, 4);
6022 GST_DEBUG_OBJECT (demux, "mdatbuffer starts with %" GST_FOURCC_FORMAT,
6023 GST_FOURCC_ARGS (QT_FOURCC (fourcc)));
6024 if (demux->mdatbuffer)
6025 demux->mdatbuffer = gst_buffer_append (demux->mdatbuffer, buf);
6027 demux->mdatbuffer = buf;
6028 demux->offset += demux->neededbytes;
6029 demux->neededbytes = 16;
6030 demux->state = QTDEMUX_STATE_INITIAL;
6031 gst_qtdemux_post_progress (demux, 1, 1);
6035 case QTDEMUX_STATE_MOVIE:{
6036 QtDemuxStream *stream = NULL;
6037 QtDemuxSample *sample;
6039 GstClockTime dts, pts, duration;
6042 GST_DEBUG_OBJECT (demux,
6043 "BEGIN // in MOVIE for offset %" G_GUINT64_FORMAT, demux->offset);
6045 if (demux->fragmented) {
6046 GST_DEBUG_OBJECT (demux, "mdat remaining %" G_GUINT64_FORMAT,
6048 if (G_LIKELY (demux->todrop < demux->mdatleft)) {
6049 /* if needed data starts within this atom,
6050 * then it should not exceed this atom */
6051 if (G_UNLIKELY (demux->neededbytes > demux->mdatleft)) {
6052 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
6053 (_("This file is invalid and cannot be played.")),
6054 ("sample data crosses atom boundary"));
6055 ret = GST_FLOW_ERROR;
6058 demux->mdatleft -= demux->neededbytes;
6060 GST_DEBUG_OBJECT (demux, "data atom emptied; resuming atom scan");
6061 /* so we are dropping more than left in this atom */
6062 gst_qtdemux_drop_data (demux, demux->mdatleft);
6063 demux->mdatleft = 0;
6065 /* need to resume atom parsing so we do not miss any other pieces */
6066 demux->state = QTDEMUX_STATE_INITIAL;
6067 demux->neededbytes = 16;
6069 /* check if there was any stored post mdat data from previous buffers */
6070 if (demux->restoredata_buffer) {
6071 g_assert (gst_adapter_available (demux->adapter) == 0);
6073 gst_adapter_push (demux->adapter, demux->restoredata_buffer);
6074 demux->restoredata_buffer = NULL;
6075 demux->offset = demux->restoredata_offset;
6082 if (demux->todrop) {
6083 if (demux->cenc_aux_info_offset > 0) {
6087 GST_DEBUG_OBJECT (demux, "parsing cenc auxiliary info");
6088 data = gst_adapter_map (demux->adapter, demux->todrop);
6089 gst_byte_reader_init (&br, data + 8, demux->todrop);
6090 if (!qtdemux_parse_cenc_aux_info (demux, demux->streams[0], &br,
6091 demux->cenc_aux_info_sizes, demux->cenc_aux_sample_count)) {
6092 GST_ERROR_OBJECT (demux, "failed to parse cenc auxiliary info");
6093 ret = GST_FLOW_ERROR;
6094 gst_adapter_unmap (demux->adapter);
6095 g_free (demux->cenc_aux_info_sizes);
6096 demux->cenc_aux_info_sizes = NULL;
6099 demux->cenc_aux_info_offset = 0;
6100 g_free (demux->cenc_aux_info_sizes);
6101 demux->cenc_aux_info_sizes = NULL;
6102 gst_adapter_unmap (demux->adapter);
6104 gst_qtdemux_drop_data (demux, demux->todrop);
6108 /* initial newsegment sent here after having added pads,
6109 * possible others in sink_event */
6110 gst_qtdemux_check_send_pending_segment (demux);
6112 /* Figure out which stream this packet belongs to */
6113 for (i = 0; i < demux->n_streams; i++) {
6114 stream = demux->streams[i];
6115 if (stream->sample_index >= stream->n_samples)
6117 GST_LOG_OBJECT (demux,
6118 "Checking stream %d (sample_index:%d / offset:%" G_GUINT64_FORMAT
6119 " / size:%d)", i, stream->sample_index,
6120 stream->samples[stream->sample_index].offset,
6121 stream->samples[stream->sample_index].size);
6123 if (stream->samples[stream->sample_index].offset == demux->offset)
6127 if (G_UNLIKELY (stream == NULL || i == demux->n_streams))
6128 goto unknown_stream;
6130 if (stream->new_caps) {
6131 gst_qtdemux_configure_stream (demux, stream);
6134 /* Put data in a buffer, set timestamps, caps, ... */
6135 sample = &stream->samples[stream->sample_index];
6137 if (G_LIKELY (!(STREAM_IS_EOS (stream)))) {
6138 GST_DEBUG_OBJECT (demux, "stream : %" GST_FOURCC_FORMAT,
6139 GST_FOURCC_ARGS (stream->fourcc));
6141 dts = QTSAMPLE_DTS (stream, sample);
6142 pts = QTSAMPLE_PTS (stream, sample);
6143 duration = QTSAMPLE_DUR_DTS (stream, sample, dts);
6144 keyframe = QTSAMPLE_KEYFRAME (stream, sample);
6146 /* check for segment end */
6147 if (G_UNLIKELY (demux->segment.stop != -1
6148 && demux->segment.stop <= pts && stream->on_keyframe)) {
6149 GST_DEBUG_OBJECT (demux, "we reached the end of our segment.");
6150 stream->time_position = GST_CLOCK_TIME_NONE; /* this means EOS */
6152 /* skip this data, stream is EOS */
6153 gst_adapter_flush (demux->adapter, demux->neededbytes);
6155 /* check if all streams are eos */
6157 for (i = 0; i < demux->n_streams; i++) {
6158 if (!STREAM_IS_EOS (demux->streams[i])) {
6164 if (ret == GST_FLOW_EOS) {
6165 GST_DEBUG_OBJECT (demux, "All streams are EOS, signal upstream");
6172 gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
6174 /* FIXME: should either be an assert or a plain check */
6175 g_return_val_if_fail (outbuf != NULL, GST_FLOW_ERROR);
6177 ret = gst_qtdemux_decorate_and_push_buffer (demux, stream, outbuf,
6178 dts, pts, duration, keyframe, dts, demux->offset);
6182 ret = gst_qtdemux_combine_flows (demux, stream, ret);
6183 if (ret != GST_FLOW_OK && ret != GST_FLOW_NOT_LINKED)
6184 goto non_ok_unlinked_flow;
6186 /* skip this data, stream is EOS */
6187 gst_adapter_flush (demux->adapter, demux->neededbytes);
6190 stream->sample_index++;
6191 stream->offset_in_sample = 0;
6193 /* update current offset and figure out size of next buffer */
6194 GST_LOG_OBJECT (demux, "increasing offset %" G_GUINT64_FORMAT " by %u",
6195 demux->offset, demux->neededbytes);
6196 demux->offset += demux->neededbytes;
6197 GST_LOG_OBJECT (demux, "offset is now %" G_GUINT64_FORMAT,
6200 if ((demux->neededbytes = next_entry_size (demux)) == -1) {
6201 if (demux->fragmented) {
6202 GST_DEBUG_OBJECT (demux, "(temporarily) out of fragmented samples");
6203 /* there may be more to follow, only finish this atom */
6204 demux->todrop = demux->mdatleft;
6205 demux->neededbytes = demux->todrop;
6217 /* when buffering movie data, at least show user something is happening */
6218 if (ret == GST_FLOW_OK && demux->state == QTDEMUX_STATE_BUFFER_MDAT &&
6219 gst_adapter_available (demux->adapter) <= demux->neededbytes) {
6220 gst_qtdemux_post_progress (demux, gst_adapter_available (demux->adapter),
6221 demux->neededbytes);
6228 non_ok_unlinked_flow:
6230 GST_DEBUG_OBJECT (demux, "Stopping, combined return flow %s",
6231 gst_flow_get_name (ret));
6236 GST_ELEMENT_ERROR (demux, STREAM, FAILED, (NULL), ("unknown stream found"));
6237 ret = GST_FLOW_ERROR;
6242 GST_DEBUG_OBJECT (demux, "no next entry, EOS");
6248 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
6249 (NULL), ("qtdemuxer invalid state %d", demux->state));
6250 ret = GST_FLOW_ERROR;
6255 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
6256 (NULL), ("no 'moov' atom within the first 10 MB"));
6257 ret = GST_FLOW_ERROR;
6263 qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent)
6268 query = gst_query_new_scheduling ();
6270 if (!gst_pad_peer_query (sinkpad, query)) {
6271 gst_query_unref (query);
6275 pull_mode = gst_query_has_scheduling_mode_with_flags (query,
6276 GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
6277 gst_query_unref (query);
6282 GST_DEBUG_OBJECT (sinkpad, "activating pull");
6283 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
6287 GST_DEBUG_OBJECT (sinkpad, "activating push");
6288 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
6293 qtdemux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
6294 GstPadMode mode, gboolean active)
6297 GstQTDemux *demux = GST_QTDEMUX (parent);
6300 case GST_PAD_MODE_PUSH:
6301 demux->pullbased = FALSE;
6304 case GST_PAD_MODE_PULL:
6306 demux->pullbased = TRUE;
6307 res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_qtdemux_loop,
6310 res = gst_pad_stop_task (sinkpad);
6322 qtdemux_zalloc (void *opaque, unsigned int items, unsigned int size)
6324 return g_malloc (items * size);
6328 qtdemux_zfree (void *opaque, void *addr)
6334 qtdemux_inflate (void *z_buffer, guint z_length, guint length)
6340 z = g_new0 (z_stream, 1);
6341 z->zalloc = qtdemux_zalloc;
6342 z->zfree = qtdemux_zfree;
6345 z->next_in = z_buffer;
6346 z->avail_in = z_length;
6348 buffer = (guint8 *) g_malloc (length);
6349 ret = inflateInit (z);
6350 while (z->avail_in > 0) {
6351 if (z->avail_out == 0) {
6353 buffer = (guint8 *) g_realloc (buffer, length);
6354 z->next_out = buffer + z->total_out;
6355 z->avail_out = 1024;
6357 ret = inflate (z, Z_SYNC_FLUSH);
6361 if (ret != Z_STREAM_END) {
6362 g_warning ("inflate() returned %d", ret);
6368 #endif /* HAVE_ZLIB */
6371 qtdemux_parse_moov (GstQTDemux * qtdemux, const guint8 * buffer, guint length)
6375 qtdemux->moov_node = g_node_new ((guint8 *) buffer);
6377 /* counts as header data */
6378 qtdemux->header_size += length;
6380 GST_DEBUG_OBJECT (qtdemux, "parsing 'moov' atom");
6381 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buffer, length);
6383 cmov = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_cmov);
6389 dcom = qtdemux_tree_get_child_by_type (cmov, FOURCC_dcom);
6390 cmvd = qtdemux_tree_get_child_by_type (cmov, FOURCC_cmvd);
6391 if (dcom == NULL || cmvd == NULL)
6392 goto invalid_compression;
6394 method = QT_FOURCC ((guint8 *) dcom->data + 8);
6398 guint uncompressed_length;
6399 guint compressed_length;
6402 uncompressed_length = QT_UINT32 ((guint8 *) cmvd->data + 8);
6403 compressed_length = QT_UINT32 ((guint8 *) cmvd->data + 4) - 12;
6404 GST_LOG ("length = %u", uncompressed_length);
6407 (guint8 *) qtdemux_inflate ((guint8 *) cmvd->data + 12,
6408 compressed_length, uncompressed_length);
6410 qtdemux->moov_node_compressed = qtdemux->moov_node;
6411 qtdemux->moov_node = g_node_new (buf);
6413 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buf,
6414 uncompressed_length);
6417 #endif /* HAVE_ZLIB */
6419 GST_WARNING_OBJECT (qtdemux, "unknown or unhandled header compression "
6420 "type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (method));
6427 invalid_compression:
6429 GST_ERROR_OBJECT (qtdemux, "invalid compressed header");
6435 qtdemux_parse_container (GstQTDemux * qtdemux, GNode * node, const guint8 * buf,
6438 while (G_UNLIKELY (buf < end)) {
6442 if (G_UNLIKELY (buf + 4 > end)) {
6443 GST_LOG_OBJECT (qtdemux, "buffer overrun");
6446 len = QT_UINT32 (buf);
6447 if (G_UNLIKELY (len == 0)) {
6448 GST_LOG_OBJECT (qtdemux, "empty container");
6451 if (G_UNLIKELY (len < 8)) {
6452 GST_WARNING_OBJECT (qtdemux, "length too short (%d < 8)", len);
6455 if (G_UNLIKELY (len > (end - buf))) {
6456 GST_WARNING_OBJECT (qtdemux, "length too long (%d > %d)", len,
6457 (gint) (end - buf));
6461 child = g_node_new ((guint8 *) buf);
6462 g_node_append (node, child);
6463 GST_LOG_OBJECT (qtdemux, "adding new node of len %d", len);
6464 qtdemux_parse_node (qtdemux, child, buf, len);
6472 qtdemux_parse_theora_extension (GstQTDemux * qtdemux, QtDemuxStream * stream,
6475 int len = QT_UINT32 (xdxt->data);
6476 guint8 *buf = xdxt->data;
6477 guint8 *end = buf + len;
6480 /* skip size and type */
6488 size = QT_UINT32 (buf);
6489 type = QT_FOURCC (buf + 4);
6491 GST_LOG_OBJECT (qtdemux, "%p %p", buf, end);
6493 if (buf + size > end || size <= 0)
6499 GST_WARNING_OBJECT (qtdemux, "have cookie %" GST_FOURCC_FORMAT,
6500 GST_FOURCC_ARGS (type));
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 header");
6510 buffer = gst_buffer_new_and_alloc (size);
6511 gst_buffer_fill (buffer, 0, buf, size);
6512 stream->buffers = g_slist_append (stream->buffers, buffer);
6513 GST_LOG_OBJECT (qtdemux, "parsing theora comment");
6516 buffer = gst_buffer_new_and_alloc (size);
6517 gst_buffer_fill (buffer, 0, buf, size);
6518 stream->buffers = g_slist_append (stream->buffers, buffer);
6519 GST_LOG_OBJECT (qtdemux, "parsing theora codebook");
6522 GST_WARNING_OBJECT (qtdemux,
6523 "unknown theora cookie %" GST_FOURCC_FORMAT,
6524 GST_FOURCC_ARGS (type));
6533 qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node, const guint8 * buffer,
6537 guint32 node_length = 0;
6538 const QtNodeType *type;
6541 GST_LOG_OBJECT (qtdemux, "qtdemux_parse buffer %p length %u", buffer, length);
6543 if (G_UNLIKELY (length < 8))
6544 goto not_enough_data;
6546 node_length = QT_UINT32 (buffer);
6547 fourcc = QT_FOURCC (buffer + 4);
6549 /* ignore empty nodes */
6550 if (G_UNLIKELY (fourcc == 0 || node_length == 8))
6553 type = qtdemux_type_get (fourcc);
6555 end = buffer + length;
6557 GST_LOG_OBJECT (qtdemux,
6558 "parsing '%" GST_FOURCC_FORMAT "', length=%u, name '%s'",
6559 GST_FOURCC_ARGS (fourcc), node_length, type->name);
6561 if (node_length > length)
6562 goto broken_atom_size;
6564 if (type->flags & QT_FLAG_CONTAINER) {
6565 qtdemux_parse_container (qtdemux, node, buffer + 8, end);
6570 if (node_length < 20) {
6571 GST_LOG_OBJECT (qtdemux, "skipping small stsd box");
6574 GST_DEBUG_OBJECT (qtdemux,
6575 "parsing stsd (sample table, sample description) atom");
6576 /* Skip over 8 byte atom hdr + 1 byte version, 3 bytes flags, 4 byte num_entries */
6577 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
6587 /* also read alac (or whatever) in stead of mp4a in the following,
6588 * since a similar layout is used in other cases as well */
6589 if (fourcc == FOURCC_mp4a)
6594 /* There are two things we might encounter here: a true mp4a atom, and
6595 an mp4a entry in an stsd atom. The latter is what we're interested
6596 in, and it looks like an atom, but isn't really one. The true mp4a
6597 atom is short, so we detect it based on length here. */
6598 if (length < min_size) {
6599 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
6600 GST_FOURCC_ARGS (fourcc));
6604 /* 'version' here is the sound sample description version. Types 0 and
6605 1 are documented in the QTFF reference, but type 2 is not: it's
6606 described in Apple header files instead (struct SoundDescriptionV2
6608 version = QT_UINT16 (buffer + 16);
6610 GST_DEBUG_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT " version 0x%08x",
6611 GST_FOURCC_ARGS (fourcc), version);
6613 /* parse any esds descriptors */
6625 GST_WARNING_OBJECT (qtdemux,
6626 "unhandled %" GST_FOURCC_FORMAT " version 0x%08x",
6627 GST_FOURCC_ARGS (fourcc), version);
6632 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
6649 /* codec_data is contained inside these atoms, which all have
6650 * the same format. */
6652 GST_DEBUG_OBJECT (qtdemux, "parsing in %" GST_FOURCC_FORMAT,
6653 GST_FOURCC_ARGS (fourcc));
6654 version = QT_UINT32 (buffer + 16);
6655 GST_DEBUG_OBJECT (qtdemux, "version %08x", version);
6656 if (1 || version == 0x00000000) {
6657 buf = buffer + 0x32;
6659 /* FIXME Quicktime uses PASCAL string while
6660 * the iso format uses C strings. Check the file
6661 * type before attempting to parse the string here. */
6662 tlen = QT_UINT8 (buf);
6663 GST_DEBUG_OBJECT (qtdemux, "tlen = %d", tlen);
6665 GST_DEBUG_OBJECT (qtdemux, "string = %.*s", tlen, (char *) buf);
6666 /* the string has a reserved space of 32 bytes so skip
6667 * the remaining 31 */
6669 buf += 4; /* and 4 bytes reserved */
6671 GST_MEMDUMP_OBJECT (qtdemux, "mp4v", buf, end - buf);
6673 qtdemux_parse_container (qtdemux, node, buf, end);
6679 GST_MEMDUMP_OBJECT (qtdemux, "H264", buffer, end - buffer);
6680 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
6685 GST_MEMDUMP_OBJECT (qtdemux, "avc1", buffer, end - buffer);
6686 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
6691 GST_MEMDUMP_OBJECT (qtdemux, "avc3", buffer, end - buffer);
6692 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
6697 GST_MEMDUMP_OBJECT (qtdemux, "H265", buffer, end - buffer);
6698 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
6703 GST_MEMDUMP_OBJECT (qtdemux, "hvc1", buffer, end - buffer);
6704 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
6709 GST_MEMDUMP_OBJECT (qtdemux, "hev1", buffer, end - buffer);
6710 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
6715 qtdemux_parse_container (qtdemux, node, buffer + 86, end);
6720 GST_DEBUG_OBJECT (qtdemux, "parsing meta atom");
6721 qtdemux_parse_container (qtdemux, node, buffer + 12, end);
6726 GST_MEMDUMP_OBJECT (qtdemux, "mp4s", buffer, end - buffer);
6727 /* Skip 8 byte header, plus 8 byte version + flags + entry_count */
6728 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
6736 version = QT_UINT32 (buffer + 12);
6737 GST_DEBUG_OBJECT (qtdemux, "parsing XiTh atom version 0x%08x", version);
6744 GST_DEBUG_OBJECT (qtdemux, "unknown version 0x%08x", version);
6749 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
6754 qtdemux_parse_container (qtdemux, node, buffer + 0x34, end);
6759 qtdemux_parse_uuid (qtdemux, buffer, end - buffer);
6764 qtdemux_parse_container (qtdemux, node, buffer + 86, end);
6769 qtdemux_parse_container (qtdemux, node, buffer + 36, end);
6773 if (!strcmp (type->name, "unknown"))
6774 GST_MEMDUMP ("Unknown tag", buffer + 4, end - buffer - 4);
6778 GST_LOG_OBJECT (qtdemux, "parsed '%" GST_FOURCC_FORMAT "'",
6779 GST_FOURCC_ARGS (fourcc));
6785 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
6786 (_("This file is corrupt and cannot be played.")),
6787 ("Not enough data for an atom header, got only %u bytes", length));
6792 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
6793 (_("This file is corrupt and cannot be played.")),
6794 ("Atom '%" GST_FOURCC_FORMAT "' has size of %u bytes, but we have only "
6795 "%u bytes available.", GST_FOURCC_ARGS (fourcc), node_length,
6802 qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc)
6806 guint32 child_fourcc;
6808 for (child = g_node_first_child (node); child;
6809 child = g_node_next_sibling (child)) {
6810 buffer = (guint8 *) child->data;
6812 child_fourcc = QT_FOURCC (buffer + 4);
6814 if (G_UNLIKELY (child_fourcc == fourcc)) {
6822 qtdemux_tree_get_child_by_type_full (GNode * node, guint32 fourcc,
6823 GstByteReader * parser)
6827 guint32 child_fourcc, child_len;
6829 for (child = g_node_first_child (node); child;
6830 child = g_node_next_sibling (child)) {
6831 buffer = (guint8 *) child->data;
6833 child_len = QT_UINT32 (buffer);
6834 child_fourcc = QT_FOURCC (buffer + 4);
6836 if (G_UNLIKELY (child_fourcc == fourcc)) {
6837 if (G_UNLIKELY (child_len < (4 + 4)))
6839 /* FIXME: must verify if atom length < parent atom length */
6840 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
6848 qtdemux_tree_get_sibling_by_type_full (GNode * node, guint32 fourcc,
6849 GstByteReader * parser)
6853 guint32 child_fourcc, child_len;
6855 for (child = g_node_next_sibling (node); child;
6856 child = g_node_next_sibling (child)) {
6857 buffer = (guint8 *) child->data;
6859 child_fourcc = QT_FOURCC (buffer + 4);
6861 if (child_fourcc == fourcc) {
6863 child_len = QT_UINT32 (buffer);
6864 if (G_UNLIKELY (child_len < (4 + 4)))
6866 /* FIXME: must verify if atom length < parent atom length */
6867 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
6876 qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc)
6878 return qtdemux_tree_get_sibling_by_type_full (node, fourcc, NULL);
6882 qtdemux_do_allocation (GstQTDemux * qtdemux, QtDemuxStream * stream)
6884 /* FIXME: This can only reliably work if demuxers have a
6885 * separate streaming thread per srcpad. This should be
6886 * done in a demuxer base class, which integrates parts
6889 * https://bugzilla.gnome.org/show_bug.cgi?id=701856
6894 query = gst_query_new_allocation (stream->caps, FALSE);
6896 if (!gst_pad_peer_query (stream->pad, query)) {
6897 /* not a problem, just debug a little */
6898 GST_DEBUG_OBJECT (qtdemux, "peer ALLOCATION query failed");
6901 if (stream->allocator)
6902 gst_object_unref (stream->allocator);
6904 if (gst_query_get_n_allocation_params (query) > 0) {
6905 /* try the allocator */
6906 gst_query_parse_nth_allocation_param (query, 0, &stream->allocator,
6908 stream->use_allocator = TRUE;
6910 stream->allocator = NULL;
6911 gst_allocation_params_init (&stream->params);
6912 stream->use_allocator = FALSE;
6914 gst_query_unref (query);
6919 gst_qtdemux_configure_protected_caps (GstQTDemux * qtdemux,
6920 QtDemuxStream * stream)
6923 const gchar *selected_system;
6925 g_return_val_if_fail (qtdemux != NULL, FALSE);
6926 g_return_val_if_fail (stream != NULL, FALSE);
6927 g_return_val_if_fail (gst_caps_get_size (stream->caps) == 1, FALSE);
6929 if (stream->protection_scheme_type != FOURCC_cenc) {
6930 GST_ERROR_OBJECT (qtdemux, "unsupported protection scheme");
6933 if (qtdemux->protection_system_ids == NULL) {
6934 GST_ERROR_OBJECT (qtdemux, "stream is protected using cenc, but no "
6935 "cenc protection system information has been found");
6938 g_ptr_array_add (qtdemux->protection_system_ids, NULL);
6939 selected_system = gst_protection_select_system ((const gchar **)
6940 qtdemux->protection_system_ids->pdata);
6941 g_ptr_array_remove_index (qtdemux->protection_system_ids,
6942 qtdemux->protection_system_ids->len - 1);
6943 if (!selected_system) {
6944 GST_ERROR_OBJECT (qtdemux, "stream is protected, but no "
6945 "suitable decryptor element has been found");
6949 s = gst_caps_get_structure (stream->caps, 0);
6950 if (!gst_structure_has_name (s, "application/x-cenc")) {
6951 gst_structure_set (s,
6952 "original-media-type", G_TYPE_STRING, gst_structure_get_name (s),
6953 GST_PROTECTION_SYSTEM_ID_CAPS_FIELD, G_TYPE_STRING, selected_system,
6955 gst_structure_set_name (s, "application/x-cenc");
6961 gst_qtdemux_configure_stream (GstQTDemux * qtdemux, QtDemuxStream * stream)
6963 if (stream->subtype == FOURCC_vide) {
6964 /* fps is calculated base on the duration of the average framerate since
6965 * qt does not have a fixed framerate. */
6966 if ((stream->n_samples == 1) && (stream->first_duration == 0)) {
6971 if (stream->duration == 0 || stream->n_samples < 2) {
6972 stream->fps_n = stream->timescale;
6975 GstClockTime avg_duration;
6979 /* duration and n_samples can be updated for fragmented format
6980 * so, framerate of fragmented format is calculated using data in a moof */
6981 if (qtdemux->fragmented && stream->n_samples_moof > 0
6982 && stream->duration_moof > 0) {
6983 n_samples = stream->n_samples_moof;
6984 duration = stream->duration_moof;
6986 n_samples = stream->n_samples;
6987 duration = stream->duration;
6990 /* Calculate a framerate, ignoring the first sample which is sometimes truncated */
6991 /* stream->duration is guint64, timescale, n_samples are guint32 */
6993 gst_util_uint64_scale_round (duration -
6994 stream->first_duration, GST_SECOND,
6995 (guint64) (stream->timescale) * (n_samples - 1));
6997 GST_LOG_OBJECT (qtdemux,
6998 "Calculating avg sample duration based on stream (or moof) duration %"
7000 " minus first sample %u, leaving %d samples gives %"
7001 GST_TIME_FORMAT, duration, stream->first_duration,
7002 n_samples - 1, GST_TIME_ARGS (avg_duration));
7004 gst_video_guess_framerate (avg_duration, &stream->fps_n,
7007 GST_DEBUG_OBJECT (qtdemux,
7008 "Calculating framerate, timescale %u gave fps_n %d fps_d %d",
7009 stream->timescale, stream->fps_n, stream->fps_d);
7013 stream->caps = gst_caps_make_writable (stream->caps);
7015 gst_caps_set_simple (stream->caps,
7016 "width", G_TYPE_INT, stream->width,
7017 "height", G_TYPE_INT, stream->height,
7018 "framerate", GST_TYPE_FRACTION, stream->fps_n, stream->fps_d, NULL);
7020 /* calculate pixel-aspect-ratio using display width and height */
7021 GST_DEBUG_OBJECT (qtdemux,
7022 "video size %dx%d, target display size %dx%d", stream->width,
7023 stream->height, stream->display_width, stream->display_height);
7024 /* qt file might have pasp atom */
7025 if (stream->par_w > 0 && stream->par_h > 0) {
7026 GST_DEBUG_OBJECT (qtdemux, "par %d:%d", stream->par_w, stream->par_h);
7027 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
7028 GST_TYPE_FRACTION, stream->par_w, stream->par_h, NULL);
7029 } else if (stream->display_width > 0 && stream->display_height > 0 &&
7030 stream->width > 0 && stream->height > 0) {
7033 /* calculate the pixel aspect ratio using the display and pixel w/h */
7034 n = stream->display_width * stream->height;
7035 d = stream->display_height * stream->width;
7038 GST_DEBUG_OBJECT (qtdemux, "setting PAR to %d/%d", n, d);
7041 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
7042 GST_TYPE_FRACTION, stream->par_w, stream->par_h, NULL);
7045 if (stream->multiview_mode != GST_VIDEO_MULTIVIEW_MODE_NONE) {
7046 guint par_w = 1, par_h = 1;
7048 if (stream->par_w > 0 && stream->par_h > 0) {
7049 par_w = stream->par_w;
7050 par_h = stream->par_h;
7053 if (gst_video_multiview_guess_half_aspect (stream->multiview_mode,
7054 stream->width, stream->height, par_w, par_h)) {
7055 stream->multiview_flags |= GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT;
7058 gst_caps_set_simple (stream->caps,
7059 "multiview-mode", G_TYPE_STRING,
7060 gst_video_multiview_mode_to_caps_string (stream->multiview_mode),
7061 "multiview-flags", GST_TYPE_VIDEO_MULTIVIEW_FLAGSET,
7062 stream->multiview_flags, GST_FLAG_SET_MASK_EXACT, NULL);
7067 else if (stream->subtype == FOURCC_soun) {
7069 stream->caps = gst_caps_make_writable (stream->caps);
7070 if (stream->rate > 0)
7071 gst_caps_set_simple (stream->caps,
7072 "rate", G_TYPE_INT, (int) stream->rate, NULL);
7073 if (stream->n_channels > 0)
7074 gst_caps_set_simple (stream->caps,
7075 "channels", G_TYPE_INT, stream->n_channels, NULL);
7076 if (stream->n_channels > 2) {
7077 /* FIXME: Need to parse the 'chan' atom to get channel layouts
7078 * correctly; this is just the minimum we can do - assume
7079 * we don't actually have any channel positions. */
7080 gst_caps_set_simple (stream->caps,
7081 "channel-mask", GST_TYPE_BITMASK, G_GUINT64_CONSTANT (0), NULL);
7087 GST_PAD_ELEMENT_PRIVATE (stream->pad) = stream;
7088 gst_pad_set_event_function (stream->pad, gst_qtdemux_handle_src_event);
7089 gst_pad_set_query_function (stream->pad, gst_qtdemux_handle_src_query);
7090 gst_pad_set_active (stream->pad, TRUE);
7092 gst_pad_use_fixed_caps (stream->pad);
7094 if (stream->protected) {
7095 if (!gst_qtdemux_configure_protected_caps (qtdemux, stream)) {
7096 GST_ERROR_OBJECT (qtdemux,
7097 "Failed to configure protected stream caps.");
7102 GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT, stream->caps);
7103 if (stream->new_stream) {
7106 GstStreamFlags stream_flags;
7109 gst_pad_get_sticky_event (qtdemux->sinkpad, GST_EVENT_STREAM_START,
7112 if (gst_event_parse_group_id (event, &qtdemux->group_id))
7113 qtdemux->have_group_id = TRUE;
7115 qtdemux->have_group_id = FALSE;
7116 gst_event_unref (event);
7117 } else if (!qtdemux->have_group_id) {
7118 qtdemux->have_group_id = TRUE;
7119 qtdemux->group_id = gst_util_group_id_next ();
7122 stream->new_stream = FALSE;
7124 gst_pad_create_stream_id_printf (stream->pad,
7125 GST_ELEMENT_CAST (qtdemux), "%03u", stream->track_id);
7126 event = gst_event_new_stream_start (stream_id);
7127 if (qtdemux->have_group_id)
7128 gst_event_set_group_id (event, qtdemux->group_id);
7129 stream_flags = GST_STREAM_FLAG_NONE;
7130 if (stream->disabled)
7131 stream_flags |= GST_STREAM_FLAG_UNSELECT;
7133 stream_flags |= GST_STREAM_FLAG_SPARSE;
7134 gst_event_set_stream_flags (event, stream_flags);
7135 gst_pad_push_event (stream->pad, event);
7138 gst_pad_set_caps (stream->pad, stream->caps);
7139 stream->new_caps = FALSE;
7145 gst_qtdemux_add_stream (GstQTDemux * qtdemux,
7146 QtDemuxStream * stream, GstTagList * list)
7148 /* consistent default for push based mode */
7149 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
7151 if (stream->subtype == FOURCC_vide) {
7152 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
7155 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
7158 gst_qtdemux_configure_stream (qtdemux, stream);
7159 qtdemux->n_video_streams++;
7160 } else if (stream->subtype == FOURCC_soun) {
7161 gchar *name = g_strdup_printf ("audio_%u", qtdemux->n_audio_streams);
7164 gst_pad_new_from_static_template (&gst_qtdemux_audiosrc_template, name);
7166 gst_qtdemux_configure_stream (qtdemux, stream);
7167 qtdemux->n_audio_streams++;
7168 } else if (stream->subtype == FOURCC_strm) {
7169 GST_DEBUG_OBJECT (qtdemux, "stream type, not creating pad");
7170 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
7171 || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt) {
7172 gchar *name = g_strdup_printf ("subtitle_%u", qtdemux->n_sub_streams);
7175 gst_pad_new_from_static_template (&gst_qtdemux_subsrc_template, name);
7177 gst_qtdemux_configure_stream (qtdemux, stream);
7178 qtdemux->n_sub_streams++;
7179 } else if (stream->caps) {
7180 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
7183 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
7185 gst_qtdemux_configure_stream (qtdemux, stream);
7186 qtdemux->n_video_streams++;
7188 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
7195 GST_DEBUG_OBJECT (qtdemux, "adding pad %s %p to qtdemux %p",
7196 GST_OBJECT_NAME (stream->pad), stream->pad, qtdemux);
7197 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
7198 gst_flow_combiner_add_pad (qtdemux->flowcombiner, stream->pad);
7200 if (stream->pending_tags)
7201 gst_tag_list_unref (stream->pending_tags);
7202 stream->pending_tags = list;
7204 /* global tags go on each pad anyway */
7205 stream->send_global_tags = TRUE;
7206 /* send upstream GST_EVENT_PROTECTION events that were received before
7207 this source pad was created */
7208 for (l = qtdemux->protection_event_queue.head; l != NULL; l = l->next)
7209 gst_pad_push_event (stream->pad, gst_event_ref (l->data));
7213 gst_tag_list_unref (list);
7217 /* find next atom with @fourcc starting at @offset */
7218 static GstFlowReturn
7219 qtdemux_find_atom (GstQTDemux * qtdemux, guint64 * offset,
7220 guint64 * length, guint32 fourcc)
7226 GST_LOG_OBJECT (qtdemux, "finding fourcc %" GST_FOURCC_FORMAT " at offset %"
7227 G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), *offset);
7233 ret = gst_pad_pull_range (qtdemux->sinkpad, *offset, 16, &buf);
7234 if (G_UNLIKELY (ret != GST_FLOW_OK))
7236 if (G_UNLIKELY (gst_buffer_get_size (buf) != 16)) {
7239 gst_buffer_unref (buf);
7242 gst_buffer_map (buf, &map, GST_MAP_READ);
7243 extract_initial_length_and_fourcc (map.data, 16, length, &lfourcc);
7244 gst_buffer_unmap (buf, &map);
7245 gst_buffer_unref (buf);
7247 if (G_UNLIKELY (*length == 0)) {
7248 GST_DEBUG_OBJECT (qtdemux, "invalid length 0");
7249 ret = GST_FLOW_ERROR;
7253 if (lfourcc == fourcc) {
7254 GST_DEBUG_OBJECT (qtdemux, "found fourcc at offset %" G_GUINT64_FORMAT,
7258 GST_LOG_OBJECT (qtdemux,
7259 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
7260 GST_FOURCC_ARGS (fourcc), *offset);
7269 /* might simply have had last one */
7270 GST_DEBUG_OBJECT (qtdemux, "fourcc not found");
7275 /* should only do something in pull mode */
7276 /* call with OBJECT lock */
7277 static GstFlowReturn
7278 qtdemux_add_fragmented_samples (GstQTDemux * qtdemux)
7280 guint64 length, offset;
7281 GstBuffer *buf = NULL;
7282 GstFlowReturn ret = GST_FLOW_OK;
7283 GstFlowReturn res = GST_FLOW_OK;
7286 offset = qtdemux->moof_offset;
7287 GST_DEBUG_OBJECT (qtdemux, "next moof at offset %" G_GUINT64_FORMAT, offset);
7290 GST_DEBUG_OBJECT (qtdemux, "no next moof");
7291 return GST_FLOW_EOS;
7294 /* best not do pull etc with lock held */
7295 GST_OBJECT_UNLOCK (qtdemux);
7297 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
7298 if (ret != GST_FLOW_OK)
7301 ret = gst_qtdemux_pull_atom (qtdemux, offset, length, &buf);
7302 if (G_UNLIKELY (ret != GST_FLOW_OK))
7304 gst_buffer_map (buf, &map, GST_MAP_READ);
7305 if (!qtdemux_parse_moof (qtdemux, map.data, map.size, offset, NULL)) {
7306 gst_buffer_unmap (buf, &map);
7307 gst_buffer_unref (buf);
7312 gst_buffer_unmap (buf, &map);
7313 gst_buffer_unref (buf);
7317 /* look for next moof */
7318 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
7319 if (G_UNLIKELY (ret != GST_FLOW_OK))
7323 GST_OBJECT_LOCK (qtdemux);
7325 qtdemux->moof_offset = offset;
7331 GST_DEBUG_OBJECT (qtdemux, "failed to parse moof");
7333 res = GST_FLOW_ERROR;
7338 /* maybe upstream temporarily flushing */
7339 if (ret != GST_FLOW_FLUSHING) {
7340 GST_DEBUG_OBJECT (qtdemux, "no next moof");
7343 GST_DEBUG_OBJECT (qtdemux, "upstream WRONG_STATE");
7344 /* resume at current position next time */
7351 /* initialise bytereaders for stbl sub-atoms */
7353 qtdemux_stbl_init (GstQTDemux * qtdemux, QtDemuxStream * stream, GNode * stbl)
7355 stream->stbl_index = -1; /* no samples have yet been parsed */
7356 stream->sample_index = -1;
7358 /* time-to-sample atom */
7359 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stts, &stream->stts))
7362 /* copy atom data into a new buffer for later use */
7363 stream->stts.data = g_memdup (stream->stts.data, stream->stts.size);
7365 /* skip version + flags */
7366 if (!gst_byte_reader_skip (&stream->stts, 1 + 3) ||
7367 !gst_byte_reader_get_uint32_be (&stream->stts, &stream->n_sample_times))
7369 GST_LOG_OBJECT (qtdemux, "%u timestamp blocks", stream->n_sample_times);
7371 /* make sure there's enough data */
7372 if (!qt_atom_parser_has_chunks (&stream->stts, stream->n_sample_times, 8)) {
7373 stream->n_sample_times = gst_byte_reader_get_remaining (&stream->stts) / 8;
7374 GST_LOG_OBJECT (qtdemux, "overriding to %u timestamp blocks",
7375 stream->n_sample_times);
7376 if (!stream->n_sample_times)
7380 /* sync sample atom */
7381 stream->stps_present = FALSE;
7382 if ((stream->stss_present =
7383 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stss,
7384 &stream->stss) ? TRUE : FALSE) == TRUE) {
7385 /* copy atom data into a new buffer for later use */
7386 stream->stss.data = g_memdup (stream->stss.data, stream->stss.size);
7388 /* skip version + flags */
7389 if (!gst_byte_reader_skip (&stream->stss, 1 + 3) ||
7390 !gst_byte_reader_get_uint32_be (&stream->stss, &stream->n_sample_syncs))
7393 if (stream->n_sample_syncs) {
7394 /* make sure there's enough data */
7395 if (!qt_atom_parser_has_chunks (&stream->stss, stream->n_sample_syncs, 4))
7399 /* partial sync sample atom */
7400 if ((stream->stps_present =
7401 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stps,
7402 &stream->stps) ? TRUE : FALSE) == TRUE) {
7403 /* copy atom data into a new buffer for later use */
7404 stream->stps.data = g_memdup (stream->stps.data, stream->stps.size);
7406 /* skip version + flags */
7407 if (!gst_byte_reader_skip (&stream->stps, 1 + 3) ||
7408 !gst_byte_reader_get_uint32_be (&stream->stps,
7409 &stream->n_sample_partial_syncs))
7412 /* if there are no entries, the stss table contains the real
7414 if (stream->n_sample_partial_syncs) {
7415 /* make sure there's enough data */
7416 if (!qt_atom_parser_has_chunks (&stream->stps,
7417 stream->n_sample_partial_syncs, 4))
7424 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsz, &stream->stsz))
7427 /* copy atom data into a new buffer for later use */
7428 stream->stsz.data = g_memdup (stream->stsz.data, stream->stsz.size);
7430 /* skip version + flags */
7431 if (!gst_byte_reader_skip (&stream->stsz, 1 + 3) ||
7432 !gst_byte_reader_get_uint32_be (&stream->stsz, &stream->sample_size))
7435 if (!gst_byte_reader_get_uint32_be (&stream->stsz, &stream->n_samples))
7438 if (!stream->n_samples)
7441 /* sample-to-chunk atom */
7442 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsc, &stream->stsc))
7445 /* copy atom data into a new buffer for later use */
7446 stream->stsc.data = g_memdup (stream->stsc.data, stream->stsc.size);
7448 /* skip version + flags */
7449 if (!gst_byte_reader_skip (&stream->stsc, 1 + 3) ||
7450 !gst_byte_reader_get_uint32_be (&stream->stsc,
7451 &stream->n_samples_per_chunk))
7454 GST_DEBUG_OBJECT (qtdemux, "n_samples_per_chunk %u",
7455 stream->n_samples_per_chunk);
7457 /* make sure there's enough data */
7458 if (!qt_atom_parser_has_chunks (&stream->stsc, stream->n_samples_per_chunk,
7464 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stco, &stream->stco))
7465 stream->co_size = sizeof (guint32);
7466 else if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_co64,
7468 stream->co_size = sizeof (guint64);
7472 /* copy atom data into a new buffer for later use */
7473 stream->stco.data = g_memdup (stream->stco.data, stream->stco.size);
7475 /* skip version + flags */
7476 if (!gst_byte_reader_skip (&stream->stco, 1 + 3))
7479 /* chunks_are_samples == TRUE means treat chunks as samples */
7480 stream->chunks_are_samples = stream->sample_size && !stream->sampled;
7481 if (stream->chunks_are_samples) {
7482 /* treat chunks as samples */
7483 if (!gst_byte_reader_get_uint32_be (&stream->stco, &stream->n_samples))
7486 /* skip number of entries */
7487 if (!gst_byte_reader_skip (&stream->stco, 4))
7490 /* make sure there are enough data in the stsz atom */
7491 if (!stream->sample_size) {
7492 /* different sizes for each sample */
7493 if (!qt_atom_parser_has_chunks (&stream->stsz, stream->n_samples, 4))
7498 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
7499 stream->n_samples, (guint) sizeof (QtDemuxSample),
7500 stream->n_samples * sizeof (QtDemuxSample) / (1024.0 * 1024.0));
7502 if (stream->n_samples >=
7503 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample)) {
7504 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
7505 "be larger than %uMB (broken file?)", stream->n_samples,
7506 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
7510 g_assert (stream->samples == NULL);
7511 stream->samples = g_try_new0 (QtDemuxSample, stream->n_samples);
7512 if (!stream->samples) {
7513 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
7518 /* composition time-to-sample */
7519 if ((stream->ctts_present =
7520 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_ctts,
7521 &stream->ctts) ? TRUE : FALSE) == TRUE) {
7522 GstByteReader cslg = GST_BYTE_READER_INIT (NULL, 0);
7524 /* copy atom data into a new buffer for later use */
7525 stream->ctts.data = g_memdup (stream->ctts.data, stream->ctts.size);
7527 /* skip version + flags */
7528 if (!gst_byte_reader_skip (&stream->ctts, 1 + 3)
7529 || !gst_byte_reader_get_uint32_be (&stream->ctts,
7530 &stream->n_composition_times))
7533 /* make sure there's enough data */
7534 if (!qt_atom_parser_has_chunks (&stream->ctts, stream->n_composition_times,
7538 /* This is optional, if missing we iterate the ctts */
7539 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_cslg, &cslg)) {
7540 if (!gst_byte_reader_skip (&cslg, 1 + 3)
7541 || !gst_byte_reader_get_uint32_be (&cslg, &stream->cslg_shift)) {
7542 g_free ((gpointer) cslg.data);
7546 gint32 cslg_least = 0;
7547 guint num_entries, pos;
7550 pos = gst_byte_reader_get_pos (&stream->ctts);
7551 num_entries = stream->n_composition_times;
7553 stream->cslg_shift = 0;
7555 for (i = 0; i < num_entries; i++) {
7558 gst_byte_reader_skip_unchecked (&stream->ctts, 4);
7559 offset = gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
7561 if (offset < cslg_least)
7562 cslg_least = offset;
7566 stream->cslg_shift = ABS (cslg_least);
7568 stream->cslg_shift = 0;
7570 /* reset the reader so we can generate sample table */
7571 gst_byte_reader_set_pos (&stream->ctts, pos);
7574 /* Ensure the cslg_shift value is consistent so we can use it
7575 * unconditionnally to produce TS and Segment */
7576 stream->cslg_shift = 0;
7583 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
7584 (_("This file is corrupt and cannot be played.")), (NULL));
7589 gst_qtdemux_stbl_free (stream);
7590 if (!qtdemux->fragmented) {
7591 /* not quite good */
7592 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
7595 /* may pick up samples elsewhere */
7601 /* collect samples from the next sample to be parsed up to sample @n for @stream
7602 * by reading the info from @stbl
7604 * This code can be executed from both the streaming thread and the seeking
7605 * thread so it takes the object lock to protect itself
7608 qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream, guint32 n)
7611 QtDemuxSample *samples, *first, *cur, *last;
7612 guint32 n_samples_per_chunk;
7615 GST_LOG_OBJECT (qtdemux, "parsing samples for stream fourcc %"
7616 GST_FOURCC_FORMAT ", pad %s", GST_FOURCC_ARGS (stream->fourcc),
7617 stream->pad ? GST_PAD_NAME (stream->pad) : "(NULL)");
7619 n_samples = stream->n_samples;
7622 goto out_of_samples;
7624 GST_OBJECT_LOCK (qtdemux);
7625 if (n <= stream->stbl_index)
7626 goto already_parsed;
7628 GST_DEBUG_OBJECT (qtdemux, "parsing up to sample %u", n);
7630 if (!stream->stsz.data) {
7631 /* so we already parsed and passed all the moov samples;
7632 * onto fragmented ones */
7633 g_assert (qtdemux->fragmented);
7637 /* pointer to the sample table */
7638 samples = stream->samples;
7640 /* starts from -1, moves to the next sample index to parse */
7641 stream->stbl_index++;
7643 /* keep track of the first and last sample to fill */
7644 first = &samples[stream->stbl_index];
7647 if (!stream->chunks_are_samples) {
7648 /* set the sample sizes */
7649 if (stream->sample_size == 0) {
7650 /* different sizes for each sample */
7651 for (cur = first; cur <= last; cur++) {
7652 cur->size = gst_byte_reader_get_uint32_be_unchecked (&stream->stsz);
7653 GST_LOG_OBJECT (qtdemux, "sample %d has size %u",
7654 (guint) (cur - samples), cur->size);
7657 /* samples have the same size */
7658 GST_LOG_OBJECT (qtdemux, "all samples have size %u", stream->sample_size);
7659 for (cur = first; cur <= last; cur++)
7660 cur->size = stream->sample_size;
7664 n_samples_per_chunk = stream->n_samples_per_chunk;
7667 for (i = stream->stsc_index; i < n_samples_per_chunk; i++) {
7670 if (stream->stsc_chunk_index >= stream->last_chunk
7671 || stream->stsc_chunk_index < stream->first_chunk) {
7672 stream->first_chunk =
7673 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
7674 stream->samples_per_chunk =
7675 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
7676 gst_byte_reader_skip_unchecked (&stream->stsc, 4);
7678 /* chunk numbers are counted from 1 it seems */
7679 if (G_UNLIKELY (stream->first_chunk == 0))
7682 --stream->first_chunk;
7684 /* the last chunk of each entry is calculated by taking the first chunk
7685 * of the next entry; except if there is no next, where we fake it with
7687 if (G_UNLIKELY (i == (stream->n_samples_per_chunk - 1))) {
7688 stream->last_chunk = G_MAXUINT32;
7690 stream->last_chunk =
7691 gst_byte_reader_peek_uint32_be_unchecked (&stream->stsc);
7692 if (G_UNLIKELY (stream->last_chunk == 0))
7695 --stream->last_chunk;
7698 GST_LOG_OBJECT (qtdemux,
7699 "entry %d has first_chunk %d, last_chunk %d, samples_per_chunk %d", i,
7700 stream->first_chunk, stream->last_chunk, stream->samples_per_chunk);
7702 if (G_UNLIKELY (stream->last_chunk < stream->first_chunk))
7705 if (stream->last_chunk != G_MAXUINT32) {
7706 if (!qt_atom_parser_peek_sub (&stream->stco,
7707 stream->first_chunk * stream->co_size,
7708 (stream->last_chunk - stream->first_chunk) * stream->co_size,
7713 stream->co_chunk = stream->stco;
7714 if (!gst_byte_reader_skip (&stream->co_chunk,
7715 stream->first_chunk * stream->co_size))
7719 stream->stsc_chunk_index = stream->first_chunk;
7722 last_chunk = stream->last_chunk;
7724 if (stream->chunks_are_samples) {
7725 cur = &samples[stream->stsc_chunk_index];
7727 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
7730 stream->stsc_chunk_index = j;
7735 qt_atom_parser_get_offset_unchecked (&stream->co_chunk,
7738 GST_LOG_OBJECT (qtdemux, "Created entry %d with offset "
7739 "%" G_GUINT64_FORMAT, j, cur->offset);
7741 if (stream->samples_per_frame * stream->bytes_per_frame) {
7743 (stream->samples_per_chunk * stream->n_channels) /
7744 stream->samples_per_frame * stream->bytes_per_frame;
7746 cur->size = stream->samples_per_chunk;
7749 GST_DEBUG_OBJECT (qtdemux,
7750 "keyframe sample %d: timestamp %" GST_TIME_FORMAT ", size %u",
7751 j, GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream,
7752 stream->stco_sample_index)), cur->size);
7754 cur->timestamp = stream->stco_sample_index;
7755 cur->duration = stream->samples_per_chunk;
7756 cur->keyframe = TRUE;
7759 stream->stco_sample_index += stream->samples_per_chunk;
7761 stream->stsc_chunk_index = j;
7763 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
7764 guint32 samples_per_chunk;
7765 guint64 chunk_offset;
7767 if (!stream->stsc_sample_index
7768 && !qt_atom_parser_get_offset (&stream->co_chunk, stream->co_size,
7769 &stream->chunk_offset))
7772 samples_per_chunk = stream->samples_per_chunk;
7773 chunk_offset = stream->chunk_offset;
7775 for (k = stream->stsc_sample_index; k < samples_per_chunk; k++) {
7776 GST_LOG_OBJECT (qtdemux, "creating entry %d with offset %"
7777 G_GUINT64_FORMAT " and size %d",
7778 (guint) (cur - samples), chunk_offset, cur->size);
7780 cur->offset = chunk_offset;
7781 chunk_offset += cur->size;
7784 if (G_UNLIKELY (cur > last)) {
7786 stream->stsc_sample_index = k + 1;
7787 stream->chunk_offset = chunk_offset;
7788 stream->stsc_chunk_index = j;
7792 stream->stsc_sample_index = 0;
7794 stream->stsc_chunk_index = j;
7796 stream->stsc_index++;
7799 if (stream->chunks_are_samples)
7803 guint32 n_sample_times;
7805 n_sample_times = stream->n_sample_times;
7808 for (i = stream->stts_index; i < n_sample_times; i++) {
7809 guint32 stts_samples;
7810 gint32 stts_duration;
7813 if (stream->stts_sample_index >= stream->stts_samples
7814 || !stream->stts_sample_index) {
7816 stream->stts_samples =
7817 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
7818 stream->stts_duration =
7819 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
7821 GST_LOG_OBJECT (qtdemux, "block %d, %u timestamps, duration %u",
7822 i, stream->stts_samples, stream->stts_duration);
7824 stream->stts_sample_index = 0;
7827 stts_samples = stream->stts_samples;
7828 stts_duration = stream->stts_duration;
7829 stts_time = stream->stts_time;
7831 for (j = stream->stts_sample_index; j < stts_samples; j++) {
7832 GST_DEBUG_OBJECT (qtdemux,
7833 "sample %d: index %d, timestamp %" GST_TIME_FORMAT,
7834 (guint) (cur - samples), j,
7835 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stts_time)));
7837 cur->timestamp = stts_time;
7838 cur->duration = stts_duration;
7840 /* avoid 32-bit wrap-around,
7841 * but still mind possible 'negative' duration */
7842 stts_time += (gint64) stts_duration;
7845 if (G_UNLIKELY (cur > last)) {
7847 stream->stts_time = stts_time;
7848 stream->stts_sample_index = j + 1;
7852 stream->stts_sample_index = 0;
7853 stream->stts_time = stts_time;
7854 stream->stts_index++;
7856 /* fill up empty timestamps with the last timestamp, this can happen when
7857 * the last samples do not decode and so we don't have timestamps for them.
7858 * We however look at the last timestamp to estimate the track length so we
7859 * need something in here. */
7860 for (; cur < last; cur++) {
7861 GST_DEBUG_OBJECT (qtdemux,
7862 "fill sample %d: timestamp %" GST_TIME_FORMAT,
7863 (guint) (cur - samples),
7864 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stream->stts_time)));
7865 cur->timestamp = stream->stts_time;
7871 /* sample sync, can be NULL */
7872 if (stream->stss_present == TRUE) {
7873 guint32 n_sample_syncs;
7875 n_sample_syncs = stream->n_sample_syncs;
7877 if (!n_sample_syncs) {
7878 GST_DEBUG_OBJECT (qtdemux, "all samples are keyframes");
7879 stream->all_keyframe = TRUE;
7881 for (i = stream->stss_index; i < n_sample_syncs; i++) {
7882 /* note that the first sample is index 1, not 0 */
7885 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stss);
7887 if (G_LIKELY (index > 0 && index <= n_samples)) {
7889 samples[index].keyframe = TRUE;
7890 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
7891 /* and exit if we have enough samples */
7892 if (G_UNLIKELY (index >= n)) {
7899 stream->stss_index = i;
7902 /* stps marks partial sync frames like open GOP I-Frames */
7903 if (stream->stps_present == TRUE) {
7904 guint32 n_sample_partial_syncs;
7906 n_sample_partial_syncs = stream->n_sample_partial_syncs;
7908 /* if there are no entries, the stss table contains the real
7910 if (n_sample_partial_syncs) {
7911 for (i = stream->stps_index; i < n_sample_partial_syncs; i++) {
7912 /* note that the first sample is index 1, not 0 */
7915 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stps);
7917 if (G_LIKELY (index > 0 && index <= n_samples)) {
7919 samples[index].keyframe = TRUE;
7920 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
7921 /* and exit if we have enough samples */
7922 if (G_UNLIKELY (index >= n)) {
7929 stream->stps_index = i;
7933 /* no stss, all samples are keyframes */
7934 stream->all_keyframe = TRUE;
7935 GST_DEBUG_OBJECT (qtdemux, "setting all keyframes");
7940 /* composition time to sample */
7941 if (stream->ctts_present == TRUE) {
7942 guint32 n_composition_times;
7944 gint32 ctts_soffset;
7946 /* Fill in the pts_offsets */
7948 n_composition_times = stream->n_composition_times;
7950 for (i = stream->ctts_index; i < n_composition_times; i++) {
7951 if (stream->ctts_sample_index >= stream->ctts_count
7952 || !stream->ctts_sample_index) {
7953 stream->ctts_count =
7954 gst_byte_reader_get_uint32_be_unchecked (&stream->ctts);
7955 stream->ctts_soffset =
7956 gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
7957 stream->ctts_sample_index = 0;
7960 ctts_count = stream->ctts_count;
7961 ctts_soffset = stream->ctts_soffset;
7963 for (j = stream->ctts_sample_index; j < ctts_count; j++) {
7964 cur->pts_offset = ctts_soffset;
7967 if (G_UNLIKELY (cur > last)) {
7969 stream->ctts_sample_index = j + 1;
7973 stream->ctts_sample_index = 0;
7974 stream->ctts_index++;
7978 stream->stbl_index = n;
7979 /* if index has been completely parsed, free data that is no-longer needed */
7980 if (n + 1 == stream->n_samples) {
7981 gst_qtdemux_stbl_free (stream);
7982 GST_DEBUG_OBJECT (qtdemux, "parsed all available samples;");
7983 if (qtdemux->pullbased) {
7984 GST_DEBUG_OBJECT (qtdemux, "checking for more samples");
7985 while (n + 1 == stream->n_samples)
7986 if (qtdemux_add_fragmented_samples (qtdemux) != GST_FLOW_OK)
7990 GST_OBJECT_UNLOCK (qtdemux);
7997 GST_LOG_OBJECT (qtdemux,
7998 "Tried to parse up to sample %u but this sample has already been parsed",
8000 /* if fragmented, there may be more */
8001 if (qtdemux->fragmented && n == stream->stbl_index)
8003 GST_OBJECT_UNLOCK (qtdemux);
8009 GST_LOG_OBJECT (qtdemux,
8010 "Tried to parse up to sample %u but there are only %u samples", n + 1,
8012 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8013 (_("This file is corrupt and cannot be played.")), (NULL));
8018 GST_OBJECT_UNLOCK (qtdemux);
8019 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8020 (_("This file is corrupt and cannot be played.")), (NULL));
8025 /* collect all segment info for @stream.
8028 qtdemux_parse_segments (GstQTDemux * qtdemux, QtDemuxStream * stream,
8032 /* accept edts if they contain gaps at start and there is only
8033 * one media segment */
8034 gboolean allow_pushbased_edts = TRUE;
8035 gint media_segments_count = 0;
8037 /* parse and prepare segment info from the edit list */
8038 GST_DEBUG_OBJECT (qtdemux, "looking for edit list container");
8039 stream->n_segments = 0;
8040 stream->segments = NULL;
8041 if ((edts = qtdemux_tree_get_child_by_type (trak, FOURCC_edts))) {
8049 GST_DEBUG_OBJECT (qtdemux, "looking for edit list");
8050 if (!(elst = qtdemux_tree_get_child_by_type (edts, FOURCC_elst)))
8053 buffer = elst->data;
8055 n_segments = QT_UINT32 (buffer + 12);
8057 /* we might allocate a bit too much, at least allocate 1 segment */
8058 stream->segments = g_new (QtDemuxSegment, MAX (n_segments, 1));
8060 /* segments always start from 0 */
8064 for (i = 0; i < n_segments; i++) {
8067 QtDemuxSegment *segment;
8069 GstClockTime media_start = GST_CLOCK_TIME_NONE;
8071 media_time = QT_UINT32 (buffer + 20 + i * 12);
8072 duration = QT_UINT32 (buffer + 16 + i * 12);
8074 if (media_time != G_MAXUINT32)
8075 media_start = QTSTREAMTIME_TO_GSTTIME (stream, media_time);
8077 segment = &stream->segments[count++];
8079 /* time and duration expressed in global timescale */
8080 segment->time = stime;
8081 /* add non scaled values so we don't cause roundoff errors */
8084 stime = QTTIME_TO_GSTTIME (qtdemux, time);
8085 segment->duration = stime - segment->time;
8087 /* zero duration does not imply media_start == media_stop
8088 * but, only specify media_start.*/
8089 stime = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
8090 if (GST_CLOCK_TIME_IS_VALID (stime) && media_time != G_MAXUINT32
8091 && stime >= media_start) {
8092 segment->duration = stime - media_start;
8094 segment->duration = GST_CLOCK_TIME_NONE;
8097 segment->stop_time = stime;
8099 segment->trak_media_start = media_time;
8100 /* media_time expressed in stream timescale */
8101 if (media_time != G_MAXUINT32) {
8102 segment->media_start = media_start;
8103 segment->media_stop = segment->media_start + segment->duration;
8104 media_segments_count++;
8106 segment->media_start = GST_CLOCK_TIME_NONE;
8107 segment->media_stop = GST_CLOCK_TIME_NONE;
8109 rate_int = GST_READ_UINT32_BE (buffer + 24 + i * 12);
8111 if (rate_int <= 1) {
8112 /* 0 is not allowed, some programs write 1 instead of the floating point
8114 GST_WARNING_OBJECT (qtdemux, "found suspicious rate %" G_GUINT32_FORMAT,
8118 segment->rate = rate_int / 65536.0;
8121 GST_DEBUG_OBJECT (qtdemux, "created segment %d time %" GST_TIME_FORMAT
8122 ", duration %" GST_TIME_FORMAT ", media_start %" GST_TIME_FORMAT
8123 " (%" G_GUINT64_FORMAT ") , media_stop %" GST_TIME_FORMAT
8124 " stop_time %" GST_TIME_FORMAT " rate %g, (%d) timescale %u",
8125 i, GST_TIME_ARGS (segment->time),
8126 GST_TIME_ARGS (segment->duration),
8127 GST_TIME_ARGS (segment->media_start), media_time,
8128 GST_TIME_ARGS (segment->media_stop),
8129 GST_TIME_ARGS (segment->stop_time), segment->rate, rate_int,
8131 if (segment->stop_time > qtdemux->segment.stop) {
8132 GST_WARNING_OBJECT (qtdemux, "Segment %d "
8133 " extends to %" GST_TIME_FORMAT
8134 " past the end of the file duration %" GST_TIME_FORMAT
8135 " it will be truncated", i, GST_TIME_ARGS (segment->stop_time),
8136 GST_TIME_ARGS (qtdemux->segment.stop));
8137 qtdemux->segment.stop = segment->stop_time;
8140 GST_DEBUG_OBJECT (qtdemux, "found %d segments", count);
8141 stream->n_segments = count;
8142 if (media_segments_count != 1)
8143 allow_pushbased_edts = FALSE;
8147 /* push based does not handle segments, so act accordingly here,
8148 * and warn if applicable */
8149 if (!qtdemux->pullbased && !allow_pushbased_edts) {
8150 GST_WARNING_OBJECT (qtdemux, "streaming; discarding edit list segments");
8151 /* remove and use default one below, we stream like it anyway */
8152 g_free (stream->segments);
8153 stream->segments = NULL;
8154 stream->n_segments = 0;
8157 /* no segments, create one to play the complete trak */
8158 if (stream->n_segments == 0) {
8159 GstClockTime stream_duration =
8160 QTSTREAMTIME_TO_GSTTIME (stream, stream->duration);
8162 if (stream->segments == NULL)
8163 stream->segments = g_new (QtDemuxSegment, 1);
8165 /* represent unknown our way */
8166 if (stream_duration == 0)
8167 stream_duration = GST_CLOCK_TIME_NONE;
8169 stream->segments[0].time = 0;
8170 stream->segments[0].stop_time = stream_duration;
8171 stream->segments[0].duration = stream_duration;
8172 stream->segments[0].media_start = 0;
8173 stream->segments[0].media_stop = stream_duration;
8174 stream->segments[0].rate = 1.0;
8175 stream->segments[0].trak_media_start = 0;
8177 GST_DEBUG_OBJECT (qtdemux, "created dummy segment %" GST_TIME_FORMAT,
8178 GST_TIME_ARGS (stream_duration));
8179 stream->n_segments = 1;
8180 stream->dummy_segment = TRUE;
8182 GST_DEBUG_OBJECT (qtdemux, "using %d segments", stream->n_segments);
8188 * Parses the stsd atom of a svq3 trak looking for
8189 * the SMI and gama atoms.
8192 qtdemux_parse_svq3_stsd_data (GstQTDemux * qtdemux, GNode * stsd,
8193 guint8 ** gamma, GstBuffer ** seqh)
8195 guint8 *_gamma = NULL;
8196 GstBuffer *_seqh = NULL;
8197 guint8 *stsd_data = stsd->data;
8198 guint32 length = QT_UINT32 (stsd_data);
8202 GST_WARNING_OBJECT (qtdemux, "stsd too short");
8208 version = QT_UINT16 (stsd_data);
8213 while (length > 8) {
8214 guint32 fourcc, size;
8216 size = QT_UINT32 (stsd_data);
8217 fourcc = QT_FOURCC (stsd_data + 4);
8218 data = stsd_data + 8;
8221 GST_WARNING_OBJECT (qtdemux, "Atom of size 0 found, aborting "
8222 "svq3 atom parsing");
8231 GST_WARNING_OBJECT (qtdemux, "Unexpected size %" G_GUINT32_FORMAT
8232 " for gama atom, expected 12", size);
8237 if (size > 16 && QT_FOURCC (data) == FOURCC_SEQH) {
8239 if (_seqh != NULL) {
8240 GST_WARNING_OBJECT (qtdemux, "Unexpected second SEQH SMI atom "
8241 " found, ignoring");
8243 seqh_size = QT_UINT32 (data + 4);
8244 if (seqh_size > 0) {
8245 _seqh = gst_buffer_new_and_alloc (seqh_size);
8246 gst_buffer_fill (_seqh, 0, data + 8, seqh_size);
8253 GST_WARNING_OBJECT (qtdemux, "Unhandled atom %" GST_FOURCC_FORMAT
8254 " in SVQ3 entry in stsd atom", GST_FOURCC_ARGS (fourcc));
8258 if (size <= length) {
8264 GST_WARNING_OBJECT (qtdemux, "SVQ3 entry too short in stsd atom");
8267 GST_WARNING_OBJECT (qtdemux, "Unexpected version for SVQ3 entry %"
8268 G_GUINT16_FORMAT, version);
8279 gst_buffer_unref (_seqh);
8284 qtdemux_get_rtsp_uri_from_hndl (GstQTDemux * qtdemux, GNode * minf)
8291 * Get 'dinf', to get its child 'dref', that might contain a 'hndl'
8292 * atom that might contain a 'data' atom with the rtsp uri.
8293 * This case was reported in bug #597497, some info about
8294 * the hndl atom can be found in TN1195
8296 dinf = qtdemux_tree_get_child_by_type (minf, FOURCC_dinf);
8297 GST_DEBUG_OBJECT (qtdemux, "Trying to obtain rtsp URI for stream trak");
8300 guint32 dref_num_entries = 0;
8301 if (qtdemux_tree_get_child_by_type_full (dinf, FOURCC_dref, &dref) &&
8302 gst_byte_reader_skip (&dref, 4) &&
8303 gst_byte_reader_get_uint32_be (&dref, &dref_num_entries)) {
8306 /* search dref entries for hndl atom */
8307 for (i = 0; i < dref_num_entries; i++) {
8308 guint32 size = 0, type;
8309 guint8 string_len = 0;
8310 if (gst_byte_reader_get_uint32_be (&dref, &size) &&
8311 qt_atom_parser_get_fourcc (&dref, &type)) {
8312 if (type == FOURCC_hndl) {
8313 GST_DEBUG_OBJECT (qtdemux, "Found hndl atom");
8315 /* skip data reference handle bytes and the
8316 * following pascal string and some extra 4
8317 * bytes I have no idea what are */
8318 if (!gst_byte_reader_skip (&dref, 4) ||
8319 !gst_byte_reader_get_uint8 (&dref, &string_len) ||
8320 !gst_byte_reader_skip (&dref, string_len + 4)) {
8321 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl atom");
8325 /* iterate over the atoms to find the data atom */
8326 while (gst_byte_reader_get_remaining (&dref) >= 8) {
8330 if (gst_byte_reader_get_uint32_be (&dref, &atom_size) &&
8331 qt_atom_parser_get_fourcc (&dref, &atom_type)) {
8332 if (atom_type == FOURCC_data) {
8333 const guint8 *uri_aux = NULL;
8335 /* found the data atom that might contain the rtsp uri */
8336 GST_DEBUG_OBJECT (qtdemux, "Found data atom inside "
8337 "hndl atom, interpreting it as an URI");
8338 if (gst_byte_reader_peek_data (&dref, atom_size - 8,
8340 if (g_strstr_len ((gchar *) uri_aux, 7, "rtsp://") != NULL)
8341 uri = g_strndup ((gchar *) uri_aux, atom_size - 8);
8343 GST_WARNING_OBJECT (qtdemux, "Data atom in hndl atom "
8344 "didn't contain a rtsp address");
8346 GST_WARNING_OBJECT (qtdemux, "Failed to get the data "
8351 /* skipping to the next entry */
8352 if (!gst_byte_reader_skip (&dref, atom_size - 8))
8355 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl child "
8362 /* skip to the next entry */
8363 if (!gst_byte_reader_skip (&dref, size - 8))
8366 GST_WARNING_OBJECT (qtdemux, "Error parsing dref atom");
8369 GST_DEBUG_OBJECT (qtdemux, "Finished parsing dref atom");
8375 #define AMR_NB_ALL_MODES 0x81ff
8376 #define AMR_WB_ALL_MODES 0x83ff
8378 qtdemux_parse_amr_bitrate (GstBuffer * buf, gboolean wb)
8380 /* The 'damr' atom is of the form:
8382 * | vendor | decoder_ver | mode_set | mode_change_period | frames/sample |
8383 * 32 b 8 b 16 b 8 b 8 b
8385 * The highest set bit of the first 7 (AMR-NB) or 8 (AMR-WB) bits of mode_set
8386 * represents the highest mode used in the stream (and thus the maximum
8387 * bitrate), with a couple of special cases as seen below.
8390 /* Map of frame type ID -> bitrate */
8391 static const guint nb_bitrates[] = {
8392 4750, 5150, 5900, 6700, 7400, 7950, 10200, 12200
8394 static const guint wb_bitrates[] = {
8395 6600, 8850, 12650, 14250, 15850, 18250, 19850, 23050, 23850
8401 gst_buffer_map (buf, &map, GST_MAP_READ);
8403 if (map.size != 0x11) {
8404 GST_DEBUG ("Atom should have size 0x11, not %" G_GSIZE_FORMAT, map.size);
8408 if (QT_FOURCC (map.data + 4) != FOURCC_damr) {
8409 GST_DEBUG ("Unknown atom in %" GST_FOURCC_FORMAT,
8410 GST_FOURCC_ARGS (QT_UINT32 (map.data + 4)));
8414 mode_set = QT_UINT16 (map.data + 13);
8416 if (mode_set == (wb ? AMR_WB_ALL_MODES : AMR_NB_ALL_MODES))
8417 max_mode = 7 + (wb ? 1 : 0);
8419 /* AMR-NB modes fo from 0-7, and AMR-WB modes go from 0-8 */
8420 max_mode = g_bit_nth_msf ((gulong) mode_set & (wb ? 0x1ff : 0xff), -1);
8422 if (max_mode == -1) {
8423 GST_DEBUG ("No mode indication was found (mode set) = %x",
8428 gst_buffer_unmap (buf, &map);
8429 return wb ? wb_bitrates[max_mode] : nb_bitrates[max_mode];
8432 gst_buffer_unmap (buf, &map);
8437 qtdemux_parse_transformation_matrix (GstQTDemux * qtdemux,
8438 GstByteReader * reader, guint32 * matrix, const gchar * atom)
8441 * 9 values of 32 bits (fixed point 16.16, except 2 5 and 8 that are 2.30)
8447 if (gst_byte_reader_get_remaining (reader) < 36)
8450 matrix[0] = gst_byte_reader_get_uint32_be_unchecked (reader);
8451 matrix[1] = gst_byte_reader_get_uint32_be_unchecked (reader);
8452 matrix[2] = gst_byte_reader_get_uint32_be_unchecked (reader);
8453 matrix[3] = gst_byte_reader_get_uint32_be_unchecked (reader);
8454 matrix[4] = gst_byte_reader_get_uint32_be_unchecked (reader);
8455 matrix[5] = gst_byte_reader_get_uint32_be_unchecked (reader);
8456 matrix[6] = gst_byte_reader_get_uint32_be_unchecked (reader);
8457 matrix[7] = gst_byte_reader_get_uint32_be_unchecked (reader);
8458 matrix[8] = gst_byte_reader_get_uint32_be_unchecked (reader);
8460 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix from atom %s", atom);
8461 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[0] >> 16,
8462 matrix[0] & 0xFFFF, matrix[1] >> 16, matrix[1] & 0xFF, matrix[2] >> 16,
8464 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[3] >> 16,
8465 matrix[3] & 0xFFFF, matrix[4] >> 16, matrix[4] & 0xFF, matrix[5] >> 16,
8467 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[6] >> 16,
8468 matrix[6] & 0xFFFF, matrix[7] >> 16, matrix[7] & 0xFF, matrix[8] >> 16,
8475 qtdemux_inspect_transformation_matrix (GstQTDemux * qtdemux,
8476 QtDemuxStream * stream, guint32 * matrix, GstTagList ** taglist)
8483 * This macro will only compare value abdegh, it expects cfi to have already
8486 #define QTCHECK_MATRIX(m,a,b,d,e) ((m)[0] == (a << 16) && (m)[1] == (b << 16) && \
8487 (m)[3] == (d << 16) && (m)[4] == (e << 16))
8489 /* only handle the cases where the last column has standard values */
8490 if (matrix[2] == 0 && matrix[5] == 0 && matrix[8] == 1 << 30) {
8491 const gchar *rotation_tag = NULL;
8493 /* no rotation needed */
8494 if (QTCHECK_MATRIX (matrix, 1, 0, 0, 1)) {
8496 } else if (QTCHECK_MATRIX (matrix, 0, 1, G_MAXUINT16, 0)) {
8497 rotation_tag = "rotate-90";
8498 } else if (QTCHECK_MATRIX (matrix, G_MAXUINT16, 0, 0, G_MAXUINT16)) {
8499 rotation_tag = "rotate-180";
8500 } else if (QTCHECK_MATRIX (matrix, 0, G_MAXUINT16, 1, 0)) {
8501 rotation_tag = "rotate-270";
8503 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
8506 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix rotation %s",
8508 if (rotation_tag != NULL) {
8509 if (*taglist == NULL)
8510 *taglist = gst_tag_list_new_empty ();
8511 gst_tag_list_add (*taglist, GST_TAG_MERGE_REPLACE,
8512 GST_TAG_IMAGE_ORIENTATION, rotation_tag, NULL);
8515 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
8519 /* Parses the boxes defined in ISO/IEC 14496-12 that enable support for
8520 * protected streams (sinf, frma, schm and schi); if the protection scheme is
8521 * Common Encryption (cenc), the function will also parse the tenc box (defined
8522 * in ISO/IEC 23001-7). @container points to the node that contains these boxes
8523 * (typically an enc[v|a|t|s] sample entry); the function will set
8524 * @original_fmt to the fourcc of the original unencrypted stream format.
8525 * Returns TRUE if successful; FALSE otherwise. */
8527 qtdemux_parse_protection_scheme_info (GstQTDemux * qtdemux,
8528 QtDemuxStream * stream, GNode * container, guint32 * original_fmt)
8535 g_return_val_if_fail (qtdemux != NULL, FALSE);
8536 g_return_val_if_fail (stream != NULL, FALSE);
8537 g_return_val_if_fail (container != NULL, FALSE);
8538 g_return_val_if_fail (original_fmt != NULL, FALSE);
8540 sinf = qtdemux_tree_get_child_by_type (container, FOURCC_sinf);
8541 if (G_UNLIKELY (!sinf)) {
8542 if (stream->protection_scheme_type == FOURCC_cenc) {
8543 GST_ERROR_OBJECT (qtdemux, "sinf box does not contain schi box, which is "
8544 "mandatory for Common Encryption");
8550 frma = qtdemux_tree_get_child_by_type (sinf, FOURCC_frma);
8551 if (G_UNLIKELY (!frma)) {
8552 GST_ERROR_OBJECT (qtdemux, "sinf box does not contain mandatory frma box");
8556 *original_fmt = QT_FOURCC ((const guint8 *) frma->data + 8);
8557 GST_DEBUG_OBJECT (qtdemux, "original stream format: '%" GST_FOURCC_FORMAT "'",
8558 GST_FOURCC_ARGS (*original_fmt));
8560 schm = qtdemux_tree_get_child_by_type (sinf, FOURCC_schm);
8562 GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schm box");
8565 stream->protection_scheme_type = QT_FOURCC ((const guint8 *) schm->data + 12);
8566 stream->protection_scheme_version =
8567 QT_UINT32 ((const guint8 *) schm->data + 16);
8569 GST_DEBUG_OBJECT (qtdemux,
8570 "protection_scheme_type: %" GST_FOURCC_FORMAT ", "
8571 "protection_scheme_version: %#010x",
8572 GST_FOURCC_ARGS (stream->protection_scheme_type),
8573 stream->protection_scheme_version);
8575 schi = qtdemux_tree_get_child_by_type (sinf, FOURCC_schi);
8577 GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schi box");
8580 if (stream->protection_scheme_type == FOURCC_cenc) {
8581 QtDemuxCencSampleSetInfo *info;
8583 const guint8 *tenc_data;
8584 guint32 isEncrypted;
8586 const guint8 *default_kid;
8589 if (G_UNLIKELY (!stream->protection_scheme_info))
8590 stream->protection_scheme_info =
8591 g_malloc0 (sizeof (QtDemuxCencSampleSetInfo));
8593 info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
8595 tenc = qtdemux_tree_get_child_by_type (schi, FOURCC_tenc);
8597 GST_ERROR_OBJECT (qtdemux, "schi box does not contain tenc box, "
8598 "which is mandatory for Common Encryption");
8601 tenc_data = (const guint8 *) tenc->data + 12;
8602 isEncrypted = QT_UINT24 (tenc_data);
8603 iv_size = QT_UINT8 (tenc_data + 3);
8604 default_kid = (tenc_data + 4);
8605 kid_buf = gst_buffer_new_allocate (NULL, 16, NULL);
8606 gst_buffer_fill (kid_buf, 0, default_kid, 16);
8607 if (info->default_properties)
8608 gst_structure_free (info->default_properties);
8609 info->default_properties =
8610 gst_structure_new ("application/x-cenc",
8611 "iv_size", G_TYPE_UINT, iv_size,
8612 "encrypted", G_TYPE_BOOLEAN, (isEncrypted == 1),
8613 "kid", GST_TYPE_BUFFER, kid_buf, NULL);
8614 GST_DEBUG_OBJECT (qtdemux, "default sample properties: "
8615 "is_encrypted=%u, iv_size=%u", isEncrypted, iv_size);
8616 gst_buffer_unref (kid_buf);
8622 * With each track we associate a new QtDemuxStream that contains all the info
8624 * traks that do not decode to something (like strm traks) will not have a pad.
8627 qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
8646 QtDemuxStream *stream = NULL;
8647 gboolean new_stream = FALSE;
8648 gchar *codec = NULL;
8649 const guint8 *stsd_data;
8650 guint16 lang_code; /* quicktime lang code or packed iso code */
8652 guint32 tkhd_flags = 0;
8653 guint8 tkhd_version = 0;
8655 guint value_size, stsd_len, len;
8659 GST_DEBUG_OBJECT (qtdemux, "parse_trak");
8661 if (!qtdemux_tree_get_child_by_type_full (trak, FOURCC_tkhd, &tkhd)
8662 || !gst_byte_reader_get_uint8 (&tkhd, &tkhd_version)
8663 || !gst_byte_reader_get_uint24_be (&tkhd, &tkhd_flags))
8666 /* pick between 64 or 32 bits */
8667 value_size = tkhd_version == 1 ? 8 : 4;
8668 if (!gst_byte_reader_skip (&tkhd, value_size * 2) ||
8669 !gst_byte_reader_get_uint32_be (&tkhd, &track_id))
8672 if (!qtdemux->got_moov) {
8673 if (qtdemux_find_stream (qtdemux, track_id))
8674 goto existing_stream;
8675 stream = _create_stream ();
8676 stream->track_id = track_id;
8679 stream = qtdemux_find_stream (qtdemux, track_id);
8681 GST_WARNING_OBJECT (qtdemux, "Stream not found, going to ignore it");
8685 /* flush samples data from this track from previous moov */
8686 gst_qtdemux_stream_flush_segments_data (qtdemux, stream);
8687 gst_qtdemux_stream_flush_samples_data (qtdemux, stream);
8689 /* need defaults for fragments */
8690 qtdemux_parse_trex (qtdemux, stream, &dummy, &dummy, &dummy);
8692 if (stream->pending_tags == NULL)
8693 stream->pending_tags = gst_tag_list_new_empty ();
8695 if ((tkhd_flags & 1) == 0)
8696 stream->disabled = TRUE;
8698 GST_LOG_OBJECT (qtdemux, "track[tkhd] version/flags/id: 0x%02x/%06x/%u",
8699 tkhd_version, tkhd_flags, stream->track_id);
8701 if (!(mdia = qtdemux_tree_get_child_by_type (trak, FOURCC_mdia)))
8704 if (!(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mdhd))) {
8705 /* be nice for some crooked mjp2 files that use mhdr for mdhd */
8706 if (qtdemux->major_brand != FOURCC_mjp2 ||
8707 !(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mhdr)))
8711 len = QT_UINT32 ((guint8 *) mdhd->data);
8712 version = QT_UINT32 ((guint8 *) mdhd->data + 8);
8713 GST_LOG_OBJECT (qtdemux, "track version/flags: %08x", version);
8714 if (version == 0x01000000) {
8717 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 28);
8718 stream->duration = QT_UINT64 ((guint8 *) mdhd->data + 32);
8719 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 36);
8723 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 20);
8724 stream->duration = QT_UINT32 ((guint8 *) mdhd->data + 24);
8725 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 28);
8728 if (lang_code < 0x400) {
8729 qtdemux_lang_map_qt_code_to_iso (stream->lang_id, lang_code);
8730 } else if (lang_code == 0x7fff) {
8731 stream->lang_id[0] = 0; /* unspecified */
8733 stream->lang_id[0] = 0x60 + ((lang_code >> 10) & 0x1F);
8734 stream->lang_id[1] = 0x60 + ((lang_code >> 5) & 0x1F);
8735 stream->lang_id[2] = 0x60 + (lang_code & 0x1F);
8736 stream->lang_id[3] = 0;
8739 GST_LOG_OBJECT (qtdemux, "track timescale: %" G_GUINT32_FORMAT,
8741 GST_LOG_OBJECT (qtdemux, "track duration: %" G_GUINT64_FORMAT,
8743 GST_LOG_OBJECT (qtdemux, "track language code/id: 0x%04x/%s",
8744 lang_code, stream->lang_id);
8746 if (G_UNLIKELY (stream->timescale == 0 || qtdemux->timescale == 0))
8749 if ((tref = qtdemux_tree_get_child_by_type (trak, FOURCC_tref))) {
8750 /* chapters track reference */
8751 GNode *chap = qtdemux_tree_get_child_by_type (tref, FOURCC_chap);
8753 gsize length = GST_READ_UINT32_BE (chap->data);
8754 if (qtdemux->chapters_track_id)
8755 GST_FIXME_OBJECT (qtdemux, "Multiple CHAP tracks");
8758 qtdemux->chapters_track_id =
8759 GST_READ_UINT32_BE ((gint8 *) chap->data + 8);
8764 /* fragmented files may have bogus duration in moov */
8765 if (!qtdemux->fragmented &&
8766 qtdemux->duration != G_MAXINT64 && stream->duration != G_MAXINT32) {
8767 guint64 tdur1, tdur2;
8769 /* don't overflow */
8770 tdur1 = stream->timescale * (guint64) qtdemux->duration;
8771 tdur2 = qtdemux->timescale * (guint64) stream->duration;
8774 * some of those trailers, nowadays, have prologue images that are
8775 * themselves vide tracks as well. I haven't really found a way to
8776 * identify those yet, except for just looking at their duration. */
8777 if (tdur1 != 0 && (tdur2 * 10 / tdur1) < 2) {
8778 GST_WARNING_OBJECT (qtdemux,
8779 "Track shorter than 20%% (%" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT
8780 " vs. %" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT ") of the stream "
8781 "found, assuming preview image or something; skipping track",
8782 stream->duration, stream->timescale, qtdemux->duration,
8783 qtdemux->timescale);
8785 gst_qtdemux_stream_free (qtdemux, stream);
8790 if (!(hdlr = qtdemux_tree_get_child_by_type (mdia, FOURCC_hdlr)))
8793 GST_LOG_OBJECT (qtdemux, "track type: %" GST_FOURCC_FORMAT,
8794 GST_FOURCC_ARGS (QT_FOURCC ((guint8 *) hdlr->data + 12)));
8796 len = QT_UINT32 ((guint8 *) hdlr->data);
8798 stream->subtype = QT_FOURCC ((guint8 *) hdlr->data + 16);
8799 GST_LOG_OBJECT (qtdemux, "track subtype: %" GST_FOURCC_FORMAT,
8800 GST_FOURCC_ARGS (stream->subtype));
8802 if (!(minf = qtdemux_tree_get_child_by_type (mdia, FOURCC_minf)))
8805 if (!(stbl = qtdemux_tree_get_child_by_type (minf, FOURCC_stbl)))
8808 /*parse svmi header if existing */
8809 svmi = qtdemux_tree_get_child_by_type (stbl, FOURCC_svmi);
8811 len = QT_UINT32 ((guint8 *) svmi->data);
8812 version = QT_UINT32 ((guint8 *) svmi->data + 8);
8814 GstVideoMultiviewMode mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
8815 GstVideoMultiviewFlags flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
8816 guint8 frame_type, frame_layout;
8818 /* MPEG-A stereo video */
8819 if (qtdemux->major_brand == FOURCC_ss02)
8820 flags |= GST_VIDEO_MULTIVIEW_FLAGS_MIXED_MONO;
8822 frame_type = QT_UINT8 ((guint8 *) svmi->data + 12);
8823 frame_layout = QT_UINT8 ((guint8 *) svmi->data + 13) & 0x01;
8824 switch (frame_type) {
8826 mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
8829 mode = GST_VIDEO_MULTIVIEW_MODE_ROW_INTERLEAVED;
8832 mode = GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME;
8835 /* mode 3 is primary/secondary view sequence, ie
8836 * left/right views in separate tracks. See section 7.2
8837 * of ISO/IEC 23000-11:2009 */
8838 GST_FIXME_OBJECT (qtdemux,
8839 "Implement stereo video in separate streams");
8842 if ((frame_layout & 0x1) == 0)
8843 flags |= GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
8845 GST_LOG_OBJECT (qtdemux,
8846 "StereoVideo: composition type: %u, is_left_first: %u",
8847 frame_type, frame_layout);
8848 stream->multiview_mode = mode;
8849 stream->multiview_flags = flags;
8854 if (!(stsd = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsd)))
8856 stsd_data = (const guint8 *) stsd->data;
8858 /* stsd should at least have one entry */
8859 stsd_len = QT_UINT32 (stsd_data);
8860 if (stsd_len < 24) {
8861 /* .. but skip stream with empty stsd produced by some Vivotek cameras */
8862 if (stream->subtype == FOURCC_vivo) {
8864 gst_qtdemux_stream_free (qtdemux, stream);
8871 GST_LOG_OBJECT (qtdemux, "stsd len: %d", stsd_len);
8873 /* and that entry should fit within stsd */
8874 len = QT_UINT32 (stsd_data + 16);
8875 if (len > stsd_len + 16)
8878 stream->fourcc = fourcc = QT_FOURCC (stsd_data + 16 + 4);
8879 GST_LOG_OBJECT (qtdemux, "stsd type: %" GST_FOURCC_FORMAT,
8880 GST_FOURCC_ARGS (stream->fourcc));
8881 GST_LOG_OBJECT (qtdemux, "stsd type len: %d", len);
8883 if ((fourcc == FOURCC_drms) || (fourcc == FOURCC_drmi))
8884 goto error_encrypted;
8886 if (fourcc == FOURCC_encv || fourcc == FOURCC_enca) {
8887 GNode *enc = qtdemux_tree_get_child_by_type (stsd, fourcc);
8888 stream->protected = TRUE;
8889 if (!qtdemux_parse_protection_scheme_info (qtdemux, stream, enc, &fourcc))
8890 GST_ERROR_OBJECT (qtdemux, "Failed to parse protection scheme info");
8893 if (stream->subtype == FOURCC_vide) {
8894 guint32 w = 0, h = 0;
8896 gint depth, palette_size, palette_count;
8898 guint32 *palette_data = NULL;
8900 stream->sampled = TRUE;
8902 /* version 1 uses some 64-bit ints */
8903 if (!gst_byte_reader_skip (&tkhd, 20 + value_size))
8906 if (!qtdemux_parse_transformation_matrix (qtdemux, &tkhd, matrix, "tkhd"))
8909 if (!gst_byte_reader_get_uint32_be (&tkhd, &w)
8910 || !gst_byte_reader_get_uint32_be (&tkhd, &h))
8913 stream->display_width = w >> 16;
8914 stream->display_height = h >> 16;
8916 qtdemux_inspect_transformation_matrix (qtdemux, stream, matrix,
8917 &stream->pending_tags);
8923 stream->width = QT_UINT16 (stsd_data + offset + 32);
8924 stream->height = QT_UINT16 (stsd_data + offset + 34);
8925 stream->fps_n = 0; /* this is filled in later */
8926 stream->fps_d = 0; /* this is filled in later */
8927 stream->bits_per_sample = QT_UINT16 (stsd_data + offset + 82);
8928 stream->color_table_id = QT_UINT16 (stsd_data + offset + 84);
8930 /* if color_table_id is 0, ctab atom must follow; however some files
8931 * produced by TMPEGEnc have color_table_id = 0 and no ctab atom, so
8932 * if color table is not present we'll correct the value */
8933 if (stream->color_table_id == 0 &&
8934 (len < 90 || QT_FOURCC (stsd_data + offset + 86) != FOURCC_ctab)) {
8935 stream->color_table_id = -1;
8938 GST_LOG_OBJECT (qtdemux, "width %d, height %d, bps %d, color table id %d",
8939 stream->width, stream->height, stream->bits_per_sample,
8940 stream->color_table_id);
8942 depth = stream->bits_per_sample;
8944 /* more than 32 bits means grayscale */
8945 gray = (depth > 32);
8946 /* low 32 bits specify the depth */
8949 /* different number of palette entries is determined by depth. */
8951 if ((depth == 1) || (depth == 2) || (depth == 4) || (depth == 8))
8952 palette_count = (1 << depth);
8953 palette_size = palette_count * 4;
8955 if (stream->color_table_id) {
8956 switch (palette_count) {
8960 palette_data = g_memdup (ff_qt_default_palette_2, palette_size);
8963 palette_data = g_memdup (ff_qt_default_palette_4, palette_size);
8967 palette_data = g_memdup (ff_qt_grayscale_palette_16, palette_size);
8969 palette_data = g_memdup (ff_qt_default_palette_16, palette_size);
8973 palette_data = g_memdup (ff_qt_grayscale_palette_256, palette_size);
8975 palette_data = g_memdup (ff_qt_default_palette_256, palette_size);
8978 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
8979 (_("The video in this file might not play correctly.")),
8980 ("unsupported palette depth %d", depth));
8984 gint i, j, start, end;
8990 start = QT_UINT32 (stsd_data + offset + 86);
8991 palette_count = QT_UINT16 (stsd_data + offset + 90);
8992 end = QT_UINT16 (stsd_data + offset + 92);
8994 GST_LOG_OBJECT (qtdemux, "start %d, end %d, palette_count %d",
8995 start, end, palette_count);
9002 if (len < 94 + (end - start) * 8)
9005 /* palette is always the same size */
9006 palette_data = g_malloc0 (256 * 4);
9007 palette_size = 256 * 4;
9009 for (j = 0, i = start; i <= end; j++, i++) {
9012 a = QT_UINT16 (stsd_data + offset + 94 + (j * 8));
9013 r = QT_UINT16 (stsd_data + offset + 96 + (j * 8));
9014 g = QT_UINT16 (stsd_data + offset + 98 + (j * 8));
9015 b = QT_UINT16 (stsd_data + offset + 100 + (j * 8));
9017 palette_data[i] = ((a & 0xff00) << 16) | ((r & 0xff00) << 8) |
9018 (g & 0xff00) | (b >> 8);
9023 gst_caps_unref (stream->caps);
9026 qtdemux_video_caps (qtdemux, stream, fourcc, stsd_data, &codec);
9027 if (G_UNLIKELY (!stream->caps)) {
9028 g_free (palette_data);
9029 goto unknown_stream;
9033 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
9034 GST_TAG_VIDEO_CODEC, codec, NULL);
9043 if (stream->rgb8_palette)
9044 gst_memory_unref (stream->rgb8_palette);
9045 stream->rgb8_palette = gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY,
9046 palette_data, palette_size, 0, palette_size, palette_data, g_free);
9048 s = gst_caps_get_structure (stream->caps, 0);
9050 /* non-raw video has a palette_data property. raw video has the palette as
9051 * an extra plane that we append to the output buffers before we push
9053 if (!gst_structure_has_name (s, "video/x-raw")) {
9056 palette = gst_buffer_new ();
9057 gst_buffer_append_memory (palette, stream->rgb8_palette);
9058 stream->rgb8_palette = NULL;
9060 gst_caps_set_simple (stream->caps, "palette_data",
9061 GST_TYPE_BUFFER, palette, NULL);
9062 gst_buffer_unref (palette);
9064 } else if (palette_count != 0) {
9065 GST_ELEMENT_WARNING (qtdemux, STREAM, NOT_IMPLEMENTED,
9066 (NULL), ("Unsupported palette depth %d", depth));
9069 GST_LOG_OBJECT (qtdemux, "frame count: %u",
9070 QT_UINT16 (stsd_data + offset + 48));
9074 /* pick 'the' stsd child */
9075 if (!stream->protected)
9076 mp4v = qtdemux_tree_get_child_by_type (stsd, fourcc);
9078 mp4v = qtdemux_tree_get_child_by_type (stsd, FOURCC_encv);
9081 esds = qtdemux_tree_get_child_by_type (mp4v, FOURCC_esds);
9082 pasp = qtdemux_tree_get_child_by_type (mp4v, FOURCC_pasp);
9086 const guint8 *pasp_data = (const guint8 *) pasp->data;
9088 stream->par_w = QT_UINT32 (pasp_data + 8);
9089 stream->par_h = QT_UINT32 (pasp_data + 12);
9096 gst_qtdemux_handle_esds (qtdemux, stream, esds, stream->pending_tags);
9103 gint len = QT_UINT32 (stsd_data) - 0x66;
9104 const guint8 *avc_data = stsd_data + 0x66;
9107 while (len >= 0x8) {
9110 if (QT_UINT32 (avc_data) <= len)
9111 size = QT_UINT32 (avc_data) - 0x8;
9116 /* No real data, so break out */
9119 switch (QT_FOURCC (avc_data + 0x4)) {
9122 /* parse, if found */
9125 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
9127 /* First 4 bytes are the length of the atom, the next 4 bytes
9128 * are the fourcc, the next 1 byte is the version, and the
9129 * subsequent bytes are profile_tier_level structure like data. */
9130 gst_codec_utils_h264_caps_set_level_and_profile (stream->caps,
9131 avc_data + 8 + 1, size - 1);
9132 buf = gst_buffer_new_and_alloc (size);
9133 gst_buffer_fill (buf, 0, avc_data + 0x8, size);
9134 gst_caps_set_simple (stream->caps,
9135 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9136 gst_buffer_unref (buf);
9144 GST_DEBUG_OBJECT (qtdemux, "found strf codec_data in stsd");
9146 /* First 4 bytes are the length of the atom, the next 4 bytes
9147 * are the fourcc, next 40 bytes are BITMAPINFOHEADER,
9148 * next 1 byte is the version, and the
9149 * subsequent bytes are sequence parameter set like data. */
9151 size -= 40; /* we'll be skipping BITMAPINFOHEADER */
9153 gst_codec_utils_h264_caps_set_level_and_profile (stream->caps,
9154 avc_data + 8 + 40 + 1, size - 1);
9156 buf = gst_buffer_new_and_alloc (size);
9157 gst_buffer_fill (buf, 0, avc_data + 8 + 40, size);
9158 gst_caps_set_simple (stream->caps,
9159 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9160 gst_buffer_unref (buf);
9166 guint avg_bitrate, max_bitrate;
9168 /* bufferSizeDB, maxBitrate and avgBitrate - 4 bytes each */
9172 max_bitrate = QT_UINT32 (avc_data + 0xc);
9173 avg_bitrate = QT_UINT32 (avc_data + 0x10);
9175 if (!max_bitrate && !avg_bitrate)
9178 /* Some muxers seem to swap the average and maximum bitrates
9179 * (I'm looking at you, YouTube), so we swap for sanity. */
9180 if (max_bitrate > 0 && max_bitrate < avg_bitrate) {
9181 guint temp = avg_bitrate;
9183 avg_bitrate = max_bitrate;
9187 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
9188 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
9189 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
9191 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
9192 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
9193 GST_TAG_BITRATE, avg_bitrate, NULL);
9204 avc_data += size + 8;
9213 gint len = QT_UINT32 (stsd_data) - 0x66;
9214 const guint8 *hevc_data = stsd_data + 0x66;
9217 while (len >= 0x8) {
9220 if (QT_UINT32 (hevc_data) <= len)
9221 size = QT_UINT32 (hevc_data) - 0x8;
9226 /* No real data, so break out */
9229 switch (QT_FOURCC (hevc_data + 0x4)) {
9232 /* parse, if found */
9235 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
9237 /* First 4 bytes are the length of the atom, the next 4 bytes
9238 * are the fourcc, the next 1 byte is the version, and the
9239 * subsequent bytes are sequence parameter set like data. */
9240 gst_codec_utils_h265_caps_set_level_tier_and_profile
9241 (stream->caps, hevc_data + 8 + 1, size - 1);
9243 buf = gst_buffer_new_and_alloc (size);
9244 gst_buffer_fill (buf, 0, hevc_data + 0x8, size);
9245 gst_caps_set_simple (stream->caps,
9246 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9247 gst_buffer_unref (buf);
9254 hevc_data += size + 8;
9265 GST_DEBUG_OBJECT (qtdemux, "found %" GST_FOURCC_FORMAT,
9266 GST_FOURCC_ARGS (fourcc));
9268 /* codec data might be in glbl extension atom */
9270 qtdemux_tree_get_child_by_type (mp4v, FOURCC_glbl) : NULL;
9276 GST_DEBUG_OBJECT (qtdemux, "found glbl data in stsd");
9278 len = QT_UINT32 (data);
9281 buf = gst_buffer_new_and_alloc (len);
9282 gst_buffer_fill (buf, 0, data + 8, len);
9283 gst_caps_set_simple (stream->caps,
9284 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9285 gst_buffer_unref (buf);
9292 /* see annex I of the jpeg2000 spec */
9293 GNode *jp2h, *ihdr, *colr, *mjp2, *field, *prefix, *cmap, *cdef;
9295 const gchar *colorspace = NULL;
9297 guint32 ncomp_map = 0;
9298 gint32 *comp_map = NULL;
9299 guint32 nchan_def = 0;
9300 gint32 *chan_def = NULL;
9302 GST_DEBUG_OBJECT (qtdemux, "found mjp2");
9303 /* some required atoms */
9304 mjp2 = qtdemux_tree_get_child_by_type (stsd, FOURCC_mjp2);
9307 jp2h = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2h);
9311 /* number of components; redundant with info in codestream, but useful
9313 ihdr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_ihdr);
9314 if (!ihdr || QT_UINT32 (ihdr->data) != 22)
9316 ncomp = QT_UINT16 (((guint8 *) ihdr->data) + 16);
9318 colr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_colr);
9321 GST_DEBUG_OBJECT (qtdemux, "found colr");
9322 /* extract colour space info */
9323 if (QT_UINT8 ((guint8 *) colr->data + 8) == 1) {
9324 switch (QT_UINT32 ((guint8 *) colr->data + 11)) {
9326 colorspace = "sRGB";
9329 colorspace = "GRAY";
9332 colorspace = "sYUV";
9340 /* colr is required, and only values 16, 17, and 18 are specified,
9341 so error if we have no colorspace */
9344 /* extract component mapping */
9345 cmap = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cmap);
9347 guint32 cmap_len = 0;
9349 cmap_len = QT_UINT32 (cmap->data);
9350 if (cmap_len >= 8) {
9351 /* normal box, subtract off header */
9353 /* cmap: { u16 cmp; u8 mtyp; u8 pcol; }* */
9354 if (cmap_len % 4 == 0) {
9355 ncomp_map = (cmap_len / 4);
9356 comp_map = g_new0 (gint32, ncomp_map);
9357 for (i = 0; i < ncomp_map; i++) {
9360 cmp = QT_UINT16 (((guint8 *) cmap->data) + 8 + i * 4);
9361 mtyp = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 2);
9362 pcol = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 3);
9363 comp_map[i] = (mtyp << 24) | (pcol << 16) | cmp;
9368 /* extract channel definitions */
9369 cdef = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cdef);
9371 guint32 cdef_len = 0;
9373 cdef_len = QT_UINT32 (cdef->data);
9374 if (cdef_len >= 10) {
9375 /* normal box, subtract off header and len */
9377 /* cdef: u16 n; { u16 cn; u16 typ; u16 asoc; }* */
9378 if (cdef_len % 6 == 0) {
9379 nchan_def = (cdef_len / 6);
9380 chan_def = g_new0 (gint32, nchan_def);
9381 for (i = 0; i < nchan_def; i++)
9383 for (i = 0; i < nchan_def; i++) {
9384 guint16 cn, typ, asoc;
9385 cn = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6);
9386 typ = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 2);
9387 asoc = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 4);
9388 if (cn < nchan_def) {
9391 chan_def[cn] = asoc;
9394 chan_def[cn] = 0; /* alpha */
9397 chan_def[cn] = -typ;
9405 gst_caps_set_simple (stream->caps,
9406 "num-components", G_TYPE_INT, ncomp, NULL);
9407 gst_caps_set_simple (stream->caps,
9408 "colorspace", G_TYPE_STRING, colorspace, NULL);
9411 GValue arr = { 0, };
9412 GValue elt = { 0, };
9414 g_value_init (&arr, GST_TYPE_ARRAY);
9415 g_value_init (&elt, G_TYPE_INT);
9416 for (i = 0; i < ncomp_map; i++) {
9417 g_value_set_int (&elt, comp_map[i]);
9418 gst_value_array_append_value (&arr, &elt);
9420 gst_structure_set_value (gst_caps_get_structure (stream->caps, 0),
9421 "component-map", &arr);
9422 g_value_unset (&elt);
9423 g_value_unset (&arr);
9428 GValue arr = { 0, };
9429 GValue elt = { 0, };
9431 g_value_init (&arr, GST_TYPE_ARRAY);
9432 g_value_init (&elt, G_TYPE_INT);
9433 for (i = 0; i < nchan_def; i++) {
9434 g_value_set_int (&elt, chan_def[i]);
9435 gst_value_array_append_value (&arr, &elt);
9437 gst_structure_set_value (gst_caps_get_structure (stream->caps, 0),
9438 "channel-definitions", &arr);
9439 g_value_unset (&elt);
9440 g_value_unset (&arr);
9444 /* some optional atoms */
9445 field = qtdemux_tree_get_child_by_type (mjp2, FOURCC_fiel);
9446 prefix = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2x);
9448 /* indicate possible fields in caps */
9450 data = (guint8 *) field->data + 8;
9452 gst_caps_set_simple (stream->caps, "fields", G_TYPE_INT,
9453 (gint) * data, NULL);
9455 /* add codec_data if provided */
9460 GST_DEBUG_OBJECT (qtdemux, "found prefix data in stsd");
9461 data = prefix->data;
9462 len = QT_UINT32 (data);
9465 buf = gst_buffer_new_and_alloc (len);
9466 gst_buffer_fill (buf, 0, data + 8, len);
9467 gst_caps_set_simple (stream->caps,
9468 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9469 gst_buffer_unref (buf);
9478 GstBuffer *seqh = NULL;
9479 guint8 *gamma_data = NULL;
9480 gint len = QT_UINT32 (stsd_data);
9482 qtdemux_parse_svq3_stsd_data (qtdemux, stsd, &gamma_data, &seqh);
9484 gst_caps_set_simple (stream->caps, "applied-gamma", G_TYPE_DOUBLE,
9485 QT_FP32 (gamma_data), NULL);
9488 /* sorry for the bad name, but we don't know what this is, other
9489 * than its own fourcc */
9490 gst_caps_set_simple (stream->caps, "seqh", GST_TYPE_BUFFER, seqh,
9494 GST_DEBUG_OBJECT (qtdemux, "found codec_data in stsd");
9495 buf = gst_buffer_new_and_alloc (len);
9496 gst_buffer_fill (buf, 0, stsd_data, len);
9497 gst_caps_set_simple (stream->caps,
9498 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9499 gst_buffer_unref (buf);
9505 gst_caps_set_simple (stream->caps,
9506 "depth", G_TYPE_INT, QT_UINT16 (stsd_data + offset + 82), NULL);
9513 GST_DEBUG_OBJECT (qtdemux, "found XiTh");
9514 xith = qtdemux_tree_get_child_by_type (stsd, FOURCC_XiTh);
9518 xdxt = qtdemux_tree_get_child_by_type (xith, FOURCC_XdxT);
9522 GST_DEBUG_OBJECT (qtdemux, "found XdxT node");
9523 /* collect the headers and store them in a stream list so that we can
9524 * send them out first */
9525 qtdemux_parse_theora_extension (qtdemux, stream, xdxt);
9535 GST_DEBUG_OBJECT (qtdemux, "parse ovc1 header");
9536 ovc1 = qtdemux_tree_get_child_by_type (stsd, FOURCC_ovc1);
9539 ovc1_data = ovc1->data;
9540 ovc1_len = QT_UINT32 (ovc1_data);
9541 if (ovc1_len <= 198) {
9542 GST_WARNING_OBJECT (qtdemux, "Too small ovc1 header, skipping");
9545 buf = gst_buffer_new_and_alloc (ovc1_len - 198);
9546 gst_buffer_fill (buf, 0, ovc1_data + 198, ovc1_len - 198);
9547 gst_caps_set_simple (stream->caps,
9548 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9549 gst_buffer_unref (buf);
9554 gint len = QT_UINT32 (stsd_data) - 0x66;
9555 const guint8 *vc1_data = stsd_data + 0x66;
9561 if (QT_UINT32 (vc1_data) <= len)
9562 size = QT_UINT32 (vc1_data) - 8;
9567 /* No real data, so break out */
9570 switch (QT_FOURCC (vc1_data + 0x4)) {
9571 case GST_MAKE_FOURCC ('d', 'v', 'c', '1'):
9575 GST_DEBUG_OBJECT (qtdemux, "found dvc1 codec_data in stsd");
9576 buf = gst_buffer_new_and_alloc (size);
9577 gst_buffer_fill (buf, 0, vc1_data + 8, size);
9578 gst_caps_set_simple (stream->caps,
9579 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9580 gst_buffer_unref (buf);
9587 vc1_data += size + 8;
9596 GST_INFO_OBJECT (qtdemux,
9597 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
9598 GST_FOURCC_ARGS (fourcc), stream->caps);
9600 } else if (stream->subtype == FOURCC_soun) {
9601 int version, samplesize;
9602 guint16 compression_id;
9603 gboolean amrwb = FALSE;
9606 /* sample description entry (16) + sound sample description v0 (20) */
9610 version = QT_UINT32 (stsd_data + offset);
9611 stream->n_channels = QT_UINT16 (stsd_data + offset + 8);
9612 samplesize = QT_UINT16 (stsd_data + offset + 10);
9613 compression_id = QT_UINT16 (stsd_data + offset + 12);
9614 stream->rate = QT_FP32 (stsd_data + offset + 16);
9616 GST_LOG_OBJECT (qtdemux, "version/rev: %08x", version);
9617 GST_LOG_OBJECT (qtdemux, "vendor: %08x",
9618 QT_UINT32 (stsd_data + offset + 4));
9619 GST_LOG_OBJECT (qtdemux, "n_channels: %d", stream->n_channels);
9620 GST_LOG_OBJECT (qtdemux, "sample_size: %d", samplesize);
9621 GST_LOG_OBJECT (qtdemux, "compression_id: %d", compression_id);
9622 GST_LOG_OBJECT (qtdemux, "packet size: %d",
9623 QT_UINT16 (stsd_data + offset + 14));
9624 GST_LOG_OBJECT (qtdemux, "sample rate: %g", stream->rate);
9626 if (compression_id == 0xfffe)
9627 stream->sampled = TRUE;
9629 /* first assume uncompressed audio */
9630 stream->bytes_per_sample = samplesize / 8;
9631 stream->samples_per_frame = stream->n_channels;
9632 stream->bytes_per_frame = stream->n_channels * stream->bytes_per_sample;
9633 stream->samples_per_packet = stream->samples_per_frame;
9634 stream->bytes_per_packet = stream->bytes_per_sample;
9638 /* Yes, these have to be hard-coded */
9641 stream->samples_per_packet = 6;
9642 stream->bytes_per_packet = 1;
9643 stream->bytes_per_frame = 1 * stream->n_channels;
9644 stream->bytes_per_sample = 1;
9645 stream->samples_per_frame = 6 * stream->n_channels;
9650 stream->samples_per_packet = 3;
9651 stream->bytes_per_packet = 1;
9652 stream->bytes_per_frame = 1 * stream->n_channels;
9653 stream->bytes_per_sample = 1;
9654 stream->samples_per_frame = 3 * stream->n_channels;
9659 stream->samples_per_packet = 64;
9660 stream->bytes_per_packet = 34;
9661 stream->bytes_per_frame = 34 * stream->n_channels;
9662 stream->bytes_per_sample = 2;
9663 stream->samples_per_frame = 64 * stream->n_channels;
9669 stream->samples_per_packet = 1;
9670 stream->bytes_per_packet = 1;
9671 stream->bytes_per_frame = 1 * stream->n_channels;
9672 stream->bytes_per_sample = 1;
9673 stream->samples_per_frame = 1 * stream->n_channels;
9678 stream->samples_per_packet = 160;
9679 stream->bytes_per_packet = 33;
9680 stream->bytes_per_frame = 33 * stream->n_channels;
9681 stream->bytes_per_sample = 2;
9682 stream->samples_per_frame = 160 * stream->n_channels;
9689 if (version == 0x00010000) {
9690 /* sample description entry (16) + sound sample description v1 (20+16) */
9701 /* only parse extra decoding config for non-pcm audio */
9702 stream->samples_per_packet = QT_UINT32 (stsd_data + offset);
9703 stream->bytes_per_packet = QT_UINT32 (stsd_data + offset + 4);
9704 stream->bytes_per_frame = QT_UINT32 (stsd_data + offset + 8);
9705 stream->bytes_per_sample = QT_UINT32 (stsd_data + offset + 12);
9707 GST_LOG_OBJECT (qtdemux, "samples/packet: %d",
9708 stream->samples_per_packet);
9709 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
9710 stream->bytes_per_packet);
9711 GST_LOG_OBJECT (qtdemux, "bytes/frame: %d",
9712 stream->bytes_per_frame);
9713 GST_LOG_OBJECT (qtdemux, "bytes/sample: %d",
9714 stream->bytes_per_sample);
9716 if (!stream->sampled && stream->bytes_per_packet) {
9717 stream->samples_per_frame = (stream->bytes_per_frame /
9718 stream->bytes_per_packet) * stream->samples_per_packet;
9719 GST_LOG_OBJECT (qtdemux, "samples/frame: %d",
9720 stream->samples_per_frame);
9725 } else if (version == 0x00020000) {
9732 /* sample description entry (16) + sound sample description v2 (56) */
9736 qtfp.val = QT_UINT64 (stsd_data + offset + 4);
9737 stream->rate = qtfp.fp;
9738 stream->n_channels = QT_UINT32 (stsd_data + offset + 12);
9740 GST_LOG_OBJECT (qtdemux, "Sound sample description Version 2");
9741 GST_LOG_OBJECT (qtdemux, "sample rate: %g", stream->rate);
9742 GST_LOG_OBJECT (qtdemux, "n_channels: %d", stream->n_channels);
9743 GST_LOG_OBJECT (qtdemux, "bits/channel: %d",
9744 QT_UINT32 (stsd_data + offset + 20));
9745 GST_LOG_OBJECT (qtdemux, "format flags: %X",
9746 QT_UINT32 (stsd_data + offset + 24));
9747 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
9748 QT_UINT32 (stsd_data + offset + 28));
9749 GST_LOG_OBJECT (qtdemux, "LPCM frames/packet: %d",
9750 QT_UINT32 (stsd_data + offset + 32));
9751 } else if (version != 0x00000) {
9752 GST_WARNING_OBJECT (qtdemux, "unknown audio STSD version %08x", version);
9756 gst_caps_unref (stream->caps);
9758 stream->caps = qtdemux_audio_caps (qtdemux, stream, fourcc,
9759 stsd_data + 32, len - 16, &codec);
9767 in24 = qtdemux_tree_get_child_by_type (stsd, FOURCC_in24);
9769 enda = qtdemux_tree_get_child_by_type (in24, FOURCC_enda);
9771 wave = qtdemux_tree_get_child_by_type (in24, FOURCC_wave);
9773 enda = qtdemux_tree_get_child_by_type (wave, FOURCC_enda);
9776 int enda_value = QT_UINT16 ((guint8 *) enda->data + 8);
9777 gst_caps_set_simple (stream->caps,
9778 "format", G_TYPE_STRING, (enda_value) ? "S24LE" : "S24BE", NULL);
9785 const guint8 *owma_data;
9786 const gchar *codec_name = NULL;
9790 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
9791 /* FIXME this should also be gst_riff_strf_auds,
9792 * but the latter one is actually missing bits-per-sample :( */
9797 gint32 nSamplesPerSec;
9798 gint32 nAvgBytesPerSec;
9800 gint16 wBitsPerSample;
9805 GST_DEBUG_OBJECT (qtdemux, "parse owma");
9806 owma = qtdemux_tree_get_child_by_type (stsd, FOURCC_owma);
9809 owma_data = owma->data;
9810 owma_len = QT_UINT32 (owma_data);
9811 if (owma_len <= 54) {
9812 GST_WARNING_OBJECT (qtdemux, "Too small owma header, skipping");
9815 wfex = (WAVEFORMATEX *) (owma_data + 36);
9816 buf = gst_buffer_new_and_alloc (owma_len - 54);
9817 gst_buffer_fill (buf, 0, owma_data + 54, owma_len - 54);
9818 if (wfex->wFormatTag == 0x0161) {
9819 codec_name = "Windows Media Audio";
9821 } else if (wfex->wFormatTag == 0x0162) {
9822 codec_name = "Windows Media Audio 9 Pro";
9824 } else if (wfex->wFormatTag == 0x0163) {
9825 codec_name = "Windows Media Audio 9 Lossless";
9826 /* is that correct? gstffmpegcodecmap.c is missing it, but
9827 * fluendo codec seems to support it */
9831 gst_caps_set_simple (stream->caps,
9832 "codec_data", GST_TYPE_BUFFER, buf,
9833 "wmaversion", G_TYPE_INT, version,
9834 "block_align", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->nBlockAlign),
9835 "bitrate", G_TYPE_INT, GST_READ_UINT32_LE (&wfex->nAvgBytesPerSec),
9836 "width", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->wBitsPerSample),
9837 "depth", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->wBitsPerSample),
9839 gst_buffer_unref (buf);
9843 codec = g_strdup (codec_name);
9849 gint len = QT_UINT32 (stsd_data) - offset;
9850 const guint8 *wfex_data = stsd_data + offset;
9851 const gchar *codec_name = NULL;
9853 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
9854 /* FIXME this should also be gst_riff_strf_auds,
9855 * but the latter one is actually missing bits-per-sample :( */
9860 gint32 nSamplesPerSec;
9861 gint32 nAvgBytesPerSec;
9863 gint16 wBitsPerSample;
9868 /* FIXME: unify with similar wavformatex parsing code above */
9869 GST_DEBUG_OBJECT (qtdemux, "parse wma, looking for wfex");
9875 if (QT_UINT32 (wfex_data) <= len)
9876 size = QT_UINT32 (wfex_data) - 8;
9881 /* No real data, so break out */
9884 switch (QT_FOURCC (wfex_data + 4)) {
9885 case GST_MAKE_FOURCC ('w', 'f', 'e', 'x'):
9887 GST_DEBUG_OBJECT (qtdemux, "found wfex in stsd");
9892 wfex.wFormatTag = GST_READ_UINT16_LE (wfex_data + 8 + 0);
9893 wfex.nChannels = GST_READ_UINT16_LE (wfex_data + 8 + 2);
9894 wfex.nSamplesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 4);
9895 wfex.nAvgBytesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 8);
9896 wfex.nBlockAlign = GST_READ_UINT16_LE (wfex_data + 8 + 12);
9897 wfex.wBitsPerSample = GST_READ_UINT16_LE (wfex_data + 8 + 14);
9898 wfex.cbSize = GST_READ_UINT16_LE (wfex_data + 8 + 16);
9900 GST_LOG_OBJECT (qtdemux, "Found wfex box in stsd:");
9901 GST_LOG_OBJECT (qtdemux, "FormatTag = 0x%04x, Channels = %u, "
9902 "SamplesPerSec = %u, AvgBytesPerSec = %u, BlockAlign = %u, "
9903 "BitsPerSample = %u, Size = %u", wfex.wFormatTag,
9904 wfex.nChannels, wfex.nSamplesPerSec, wfex.nAvgBytesPerSec,
9905 wfex.nBlockAlign, wfex.wBitsPerSample, wfex.cbSize);
9907 if (wfex.wFormatTag == 0x0161) {
9908 codec_name = "Windows Media Audio";
9910 } else if (wfex.wFormatTag == 0x0162) {
9911 codec_name = "Windows Media Audio 9 Pro";
9913 } else if (wfex.wFormatTag == 0x0163) {
9914 codec_name = "Windows Media Audio 9 Lossless";
9915 /* is that correct? gstffmpegcodecmap.c is missing it, but
9916 * fluendo codec seems to support it */
9920 gst_caps_set_simple (stream->caps,
9921 "wmaversion", G_TYPE_INT, version,
9922 "block_align", G_TYPE_INT, wfex.nBlockAlign,
9923 "bitrate", G_TYPE_INT, wfex.nAvgBytesPerSec,
9924 "width", G_TYPE_INT, wfex.wBitsPerSample,
9925 "depth", G_TYPE_INT, wfex.wBitsPerSample, NULL);
9927 if (size > wfex.cbSize) {
9930 buf = gst_buffer_new_and_alloc (size - wfex.cbSize);
9931 gst_buffer_fill (buf, 0, wfex_data + 8 + wfex.cbSize,
9932 size - wfex.cbSize);
9933 gst_caps_set_simple (stream->caps,
9934 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9935 gst_buffer_unref (buf);
9937 GST_WARNING_OBJECT (qtdemux, "no codec data");
9942 codec = g_strdup (codec_name);
9950 wfex_data += size + 8;
9957 const guint8 *opus_data;
9958 guint8 *channel_mapping = NULL;
9961 guint8 channel_mapping_family;
9962 guint8 stream_count;
9963 guint8 coupled_count;
9966 opus = qtdemux_tree_get_child_by_type (stsd, FOURCC_opus);
9967 opus_data = opus->data;
9969 channels = GST_READ_UINT8 (opus_data + 45);
9970 rate = GST_READ_UINT32_LE (opus_data + 48);
9971 channel_mapping_family = GST_READ_UINT8 (opus_data + 54);
9972 stream_count = GST_READ_UINT8 (opus_data + 55);
9973 coupled_count = GST_READ_UINT8 (opus_data + 56);
9976 channel_mapping = g_malloc (channels * sizeof (guint8));
9977 for (i = 0; i < channels; i++)
9978 channel_mapping[i] = GST_READ_UINT8 (opus_data + i + 57);
9981 stream->caps = gst_codec_utils_opus_create_caps (rate, channels,
9982 channel_mapping_family, stream_count, coupled_count,
9994 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
9995 GST_TAG_AUDIO_CODEC, codec, NULL);
9999 /* some bitrate info may have ended up in caps */
10000 s = gst_caps_get_structure (stream->caps, 0);
10001 gst_structure_get_int (s, "bitrate", &bitrate);
10003 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
10004 GST_TAG_BITRATE, bitrate, NULL);
10007 if (stream->protected && fourcc == FOURCC_mp4a)
10008 mp4a = qtdemux_tree_get_child_by_type (stsd, FOURCC_enca);
10010 mp4a = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4a);
10015 wave = qtdemux_tree_get_child_by_type (mp4a, FOURCC_wave);
10017 esds = qtdemux_tree_get_child_by_type (wave, FOURCC_esds);
10019 esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
10023 /* If the fourcc's bottom 16 bits gives 'sm', then the top
10024 16 bits is a byte-swapped wave-style codec identifier,
10025 and we can find a WAVE header internally to a 'wave' atom here.
10026 This can more clearly be thought of as 'ms' as the top 16 bits, and a
10027 codec id as the bottom 16 bits - but byte-swapped to store in QT (which
10030 if ((fourcc & 0xffff) == (('s' << 8) | 'm')) {
10031 if (len < offset + 20) {
10032 GST_WARNING_OBJECT (qtdemux, "No wave atom in MS-style audio");
10034 guint32 datalen = QT_UINT32 (stsd_data + offset + 16);
10035 const guint8 *data = stsd_data + offset + 16;
10037 GNode *waveheadernode;
10039 wavenode = g_node_new ((guint8 *) data);
10040 if (qtdemux_parse_node (qtdemux, wavenode, data, datalen)) {
10041 const guint8 *waveheader;
10044 waveheadernode = qtdemux_tree_get_child_by_type (wavenode, fourcc);
10045 if (waveheadernode) {
10046 waveheader = (const guint8 *) waveheadernode->data;
10047 headerlen = QT_UINT32 (waveheader);
10049 if (headerlen > 8) {
10050 gst_riff_strf_auds *header = NULL;
10051 GstBuffer *headerbuf;
10057 headerbuf = gst_buffer_new_and_alloc (headerlen);
10058 gst_buffer_fill (headerbuf, 0, waveheader, headerlen);
10060 if (gst_riff_parse_strf_auds (GST_ELEMENT_CAST (qtdemux),
10061 headerbuf, &header, &extra)) {
10062 gst_caps_unref (stream->caps);
10063 /* FIXME: Need to do something with the channel reorder map */
10064 stream->caps = gst_riff_create_audio_caps (header->format, NULL,
10065 header, extra, NULL, NULL, NULL);
10068 gst_buffer_unref (extra);
10073 GST_DEBUG ("Didn't find waveheadernode for this codec");
10075 g_node_destroy (wavenode);
10078 gst_qtdemux_handle_esds (qtdemux, stream, esds, stream->pending_tags);
10082 /* FIXME: what is in the chunk? */
10085 gint len = QT_UINT32 (stsd_data);
10087 /* seems to be always = 116 = 0x74 */
10093 gint len = QT_UINT32 (stsd_data);
10096 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x4C);
10098 gst_buffer_fill (buf, 0, stsd_data + 0x4C, len - 0x4C);
10099 gst_caps_set_simple (stream->caps,
10100 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10101 gst_buffer_unref (buf);
10103 gst_caps_set_simple (stream->caps,
10104 "samplesize", G_TYPE_INT, samplesize, NULL);
10109 GNode *alac, *wave = NULL;
10111 /* apparently, m4a has this atom appended directly in the stsd entry,
10112 * while mov has it in a wave atom */
10113 alac = qtdemux_tree_get_child_by_type (stsd, FOURCC_alac);
10115 /* alac now refers to stsd entry atom */
10116 wave = qtdemux_tree_get_child_by_type (alac, FOURCC_wave);
10118 alac = qtdemux_tree_get_child_by_type (wave, FOURCC_alac);
10120 alac = qtdemux_tree_get_child_by_type (alac, FOURCC_alac);
10123 const guint8 *alac_data = alac->data;
10124 gint len = QT_UINT32 (alac->data);
10128 GST_DEBUG_OBJECT (qtdemux,
10129 "discarding alac atom with unexpected len %d", len);
10131 /* codec-data contains alac atom size and prefix,
10132 * ffmpeg likes it that way, not quite gst-ish though ...*/
10133 buf = gst_buffer_new_and_alloc (len);
10134 gst_buffer_fill (buf, 0, alac->data, len);
10135 gst_caps_set_simple (stream->caps,
10136 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10137 gst_buffer_unref (buf);
10139 stream->bytes_per_frame = QT_UINT32 (alac_data + 12);
10140 stream->n_channels = QT_UINT8 (alac_data + 21);
10141 stream->rate = QT_UINT32 (alac_data + 32);
10144 gst_caps_set_simple (stream->caps,
10145 "samplesize", G_TYPE_INT, samplesize, NULL);
10153 gint len = QT_UINT32 (stsd_data);
10156 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x34);
10159 gst_buffer_fill (buf, 0, stsd_data + 0x34, len - 0x34);
10161 /* If we have enough data, let's try to get the 'damr' atom. See
10162 * the 3GPP container spec (26.244) for more details. */
10163 if ((len - 0x34) > 8 &&
10164 (bitrate = qtdemux_parse_amr_bitrate (buf, amrwb))) {
10165 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
10166 GST_TAG_MAXIMUM_BITRATE, bitrate, NULL);
10169 gst_caps_set_simple (stream->caps,
10170 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10171 gst_buffer_unref (buf);
10177 /* mp4a atom withtout ESDS; Attempt to build codec data from atom */
10178 gint len = QT_UINT32 (stsd_data);
10181 guint16 sound_version = QT_UINT16 (stsd_data + 32);
10183 if (sound_version == 1) {
10184 guint16 channels = QT_UINT16 (stsd_data + 40);
10185 guint32 time_scale = QT_UINT32 (stsd_data + 46);
10186 guint8 codec_data[2];
10188 gint profile = 2; /* FIXME: Can this be determined somehow? There doesn't seem to be anything in mp4a atom that specifis compression */
10190 gint sample_rate_index =
10191 gst_codec_utils_aac_get_index_from_sample_rate (time_scale);
10193 /* build AAC codec data */
10194 codec_data[0] = profile << 3;
10195 codec_data[0] |= ((sample_rate_index >> 1) & 0x7);
10196 codec_data[1] = (sample_rate_index & 0x01) << 7;
10197 codec_data[1] |= (channels & 0xF) << 3;
10199 buf = gst_buffer_new_and_alloc (2);
10200 gst_buffer_fill (buf, 0, codec_data, 2);
10201 gst_caps_set_simple (stream->caps,
10202 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10203 gst_buffer_unref (buf);
10209 GST_INFO_OBJECT (qtdemux,
10210 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
10214 GST_INFO_OBJECT (qtdemux,
10215 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
10216 GST_FOURCC_ARGS (fourcc), stream->caps);
10218 } else if (stream->subtype == FOURCC_strm) {
10219 if (fourcc == FOURCC_rtsp) {
10220 stream->redirect_uri = qtdemux_get_rtsp_uri_from_hndl (qtdemux, minf);
10222 GST_INFO_OBJECT (qtdemux, "unhandled stream type %" GST_FOURCC_FORMAT,
10223 GST_FOURCC_ARGS (fourcc));
10224 goto unknown_stream;
10226 stream->sampled = TRUE;
10227 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
10228 || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt) {
10230 stream->sampled = TRUE;
10231 stream->sparse = TRUE;
10234 qtdemux_sub_caps (qtdemux, stream, fourcc, stsd_data, &codec);
10236 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
10237 GST_TAG_SUBTITLE_CODEC, codec, NULL);
10242 /* hunt for sort-of codec data */
10246 GNode *mp4s = NULL;
10247 GNode *esds = NULL;
10249 /* look for palette in a stsd->mp4s->esds sub-atom */
10250 mp4s = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4s);
10252 esds = qtdemux_tree_get_child_by_type (mp4s, FOURCC_esds);
10253 if (esds == NULL) {
10255 GST_LOG_OBJECT (qtdemux, "Skipping invalid stsd: no esds child");
10259 gst_qtdemux_handle_esds (qtdemux, stream, esds, stream->pending_tags);
10263 GST_INFO_OBJECT (qtdemux,
10264 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
10267 GST_INFO_OBJECT (qtdemux,
10268 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
10269 GST_FOURCC_ARGS (fourcc), stream->caps);
10271 /* everything in 1 sample */
10272 stream->sampled = TRUE;
10275 qtdemux_generic_caps (qtdemux, stream, fourcc, stsd_data, &codec);
10277 if (stream->caps == NULL)
10278 goto unknown_stream;
10281 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
10282 GST_TAG_SUBTITLE_CODEC, codec, NULL);
10288 /* promote to sampled format */
10289 if (stream->fourcc == FOURCC_samr) {
10290 /* force mono 8000 Hz for AMR */
10291 stream->sampled = TRUE;
10292 stream->n_channels = 1;
10293 stream->rate = 8000;
10294 } else if (stream->fourcc == FOURCC_sawb) {
10295 /* force mono 16000 Hz for AMR-WB */
10296 stream->sampled = TRUE;
10297 stream->n_channels = 1;
10298 stream->rate = 16000;
10299 } else if (stream->fourcc == FOURCC_mp4a) {
10300 stream->sampled = TRUE;
10303 /* collect sample information */
10304 if (!qtdemux_stbl_init (qtdemux, stream, stbl))
10305 goto samples_failed;
10307 if (qtdemux->fragmented) {
10310 /* need all moov samples as basis; probably not many if any at all */
10311 /* prevent moof parsing taking of at this time */
10312 offset = qtdemux->moof_offset;
10313 qtdemux->moof_offset = 0;
10314 if (stream->n_samples &&
10315 !qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
10316 qtdemux->moof_offset = offset;
10317 goto samples_failed;
10319 qtdemux->moof_offset = 0;
10320 /* movie duration more reliable in this case (e.g. mehd) */
10321 if (qtdemux->segment.duration &&
10322 GST_CLOCK_TIME_IS_VALID (qtdemux->segment.duration))
10324 GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->segment.duration);
10327 /* configure segments */
10328 if (!qtdemux_parse_segments (qtdemux, stream, trak))
10329 goto segments_failed;
10331 /* add some language tag, if useful */
10332 if (stream->lang_id[0] != '\0' && strcmp (stream->lang_id, "unk") &&
10333 strcmp (stream->lang_id, "und")) {
10334 const gchar *lang_code;
10336 /* convert ISO 639-2 code to ISO 639-1 */
10337 lang_code = gst_tag_get_language_code (stream->lang_id);
10338 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
10339 GST_TAG_LANGUAGE_CODE, (lang_code) ? lang_code : stream->lang_id, NULL);
10342 /* Check for UDTA tags */
10343 if ((udta = qtdemux_tree_get_child_by_type (trak, FOURCC_udta))) {
10344 qtdemux_parse_udta (qtdemux, stream->pending_tags, udta);
10347 /* now we are ready to add the stream */
10348 if (qtdemux->n_streams >= GST_QTDEMUX_MAX_STREAMS)
10349 goto too_many_streams;
10351 if (!qtdemux->got_moov) {
10352 qtdemux->streams[qtdemux->n_streams] = stream;
10353 qtdemux->n_streams++;
10354 GST_DEBUG_OBJECT (qtdemux, "n_streams is now %d", qtdemux->n_streams);
10362 GST_INFO_OBJECT (qtdemux, "skip disabled track");
10364 gst_qtdemux_stream_free (qtdemux, stream);
10369 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
10370 (_("This file is corrupt and cannot be played.")), (NULL));
10372 gst_qtdemux_stream_free (qtdemux, stream);
10377 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT, (NULL), (NULL));
10379 gst_qtdemux_stream_free (qtdemux, stream);
10385 /* we posted an error already */
10386 /* free stbl sub-atoms */
10387 gst_qtdemux_stbl_free (stream);
10389 gst_qtdemux_stream_free (qtdemux, stream);
10394 GST_INFO_OBJECT (qtdemux, "stream with track id %i already exists",
10397 gst_qtdemux_stream_free (qtdemux, stream);
10402 GST_INFO_OBJECT (qtdemux, "unknown subtype %" GST_FOURCC_FORMAT,
10403 GST_FOURCC_ARGS (stream->subtype));
10405 gst_qtdemux_stream_free (qtdemux, stream);
10410 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
10411 (_("This file contains too many streams. Only playing first %d"),
10412 GST_QTDEMUX_MAX_STREAMS), (NULL));
10417 /* If we can estimate the overall bitrate, and don't have information about the
10418 * stream bitrate for exactly one stream, this guesses the stream bitrate as
10419 * the overall bitrate minus the sum of the bitrates of all other streams. This
10420 * should be useful for the common case where we have one audio and one video
10421 * stream and can estimate the bitrate of one, but not the other. */
10423 gst_qtdemux_guess_bitrate (GstQTDemux * qtdemux)
10425 QtDemuxStream *stream = NULL;
10426 gint64 size, sys_bitrate, sum_bitrate = 0;
10427 GstClockTime duration;
10431 if (qtdemux->fragmented)
10434 GST_DEBUG_OBJECT (qtdemux, "Looking for streams with unknown bitrate");
10436 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &size)
10438 GST_DEBUG_OBJECT (qtdemux,
10439 "Size in bytes of the stream not known - bailing");
10443 /* Subtract the header size */
10444 GST_DEBUG_OBJECT (qtdemux, "Total size %" G_GINT64_FORMAT ", header size %u",
10445 size, qtdemux->header_size);
10447 if (size < qtdemux->header_size)
10450 size = size - qtdemux->header_size;
10452 if (!gst_qtdemux_get_duration (qtdemux, &duration) ||
10453 duration == GST_CLOCK_TIME_NONE) {
10454 GST_DEBUG_OBJECT (qtdemux, "Stream duration not known - bailing");
10458 for (i = 0; i < qtdemux->n_streams; i++) {
10459 switch (qtdemux->streams[i]->subtype) {
10462 GST_DEBUG_OBJECT (qtdemux, "checking bitrate for %" GST_PTR_FORMAT,
10463 qtdemux->streams[i]->caps);
10464 /* retrieve bitrate, prefer avg then max */
10466 if (qtdemux->streams[i]->pending_tags) {
10467 gst_tag_list_get_uint (qtdemux->streams[i]->pending_tags,
10468 GST_TAG_MAXIMUM_BITRATE, &bitrate);
10469 GST_DEBUG_OBJECT (qtdemux, "max-bitrate: %u", bitrate);
10470 gst_tag_list_get_uint (qtdemux->streams[i]->pending_tags,
10471 GST_TAG_NOMINAL_BITRATE, &bitrate);
10472 GST_DEBUG_OBJECT (qtdemux, "nominal-bitrate: %u", bitrate);
10473 gst_tag_list_get_uint (qtdemux->streams[i]->pending_tags,
10474 GST_TAG_BITRATE, &bitrate);
10475 GST_DEBUG_OBJECT (qtdemux, "bitrate: %u", bitrate);
10478 sum_bitrate += bitrate;
10481 GST_DEBUG_OBJECT (qtdemux,
10482 ">1 stream with unknown bitrate - bailing");
10485 stream = qtdemux->streams[i];
10489 /* For other subtypes, we assume no significant impact on bitrate */
10495 GST_DEBUG_OBJECT (qtdemux, "All stream bitrates are known");
10499 sys_bitrate = gst_util_uint64_scale (size, GST_SECOND * 8, duration);
10501 if (sys_bitrate < sum_bitrate) {
10502 /* This can happen, since sum_bitrate might be derived from maximum
10503 * bitrates and not average bitrates */
10504 GST_DEBUG_OBJECT (qtdemux,
10505 "System bitrate less than sum bitrate - bailing");
10509 bitrate = sys_bitrate - sum_bitrate;
10510 GST_DEBUG_OBJECT (qtdemux, "System bitrate = %" G_GINT64_FORMAT
10511 ", Stream bitrate = %u", sys_bitrate, bitrate);
10513 if (!stream->pending_tags)
10514 stream->pending_tags = gst_tag_list_new_empty ();
10516 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
10517 GST_TAG_BITRATE, bitrate, NULL);
10520 static GstFlowReturn
10521 qtdemux_prepare_streams (GstQTDemux * qtdemux)
10524 GstFlowReturn ret = GST_FLOW_OK;
10526 GST_DEBUG_OBJECT (qtdemux, "prepare streams");
10528 for (i = 0; ret == GST_FLOW_OK && i < qtdemux->n_streams; i++) {
10529 QtDemuxStream *stream = qtdemux->streams[i];
10530 guint32 sample_num = 0;
10532 GST_DEBUG_OBJECT (qtdemux, "stream %d, id %d, fourcc %" GST_FOURCC_FORMAT,
10533 i, stream->track_id, GST_FOURCC_ARGS (stream->fourcc));
10535 if (qtdemux->fragmented) {
10536 /* need all moov samples first */
10537 GST_OBJECT_LOCK (qtdemux);
10538 while (stream->n_samples == 0)
10539 if ((ret = qtdemux_add_fragmented_samples (qtdemux)) != GST_FLOW_OK)
10541 GST_OBJECT_UNLOCK (qtdemux);
10543 /* discard any stray moof */
10544 qtdemux->moof_offset = 0;
10547 /* prepare braking */
10548 if (ret != GST_FLOW_ERROR)
10551 /* in pull mode, we should have parsed some sample info by now;
10552 * and quite some code will not handle no samples.
10553 * in push mode, we'll just have to deal with it */
10554 if (G_UNLIKELY (qtdemux->pullbased && !stream->n_samples)) {
10555 GST_DEBUG_OBJECT (qtdemux, "no samples for stream; discarding");
10556 gst_qtdemux_remove_stream (qtdemux, i);
10561 /* parse the initial sample for use in setting the frame rate cap */
10562 while (sample_num == 0 && sample_num < stream->n_samples) {
10563 if (!qtdemux_parse_samples (qtdemux, stream, sample_num))
10567 if (stream->n_samples > 0 && stream->stbl_index >= 0) {
10568 stream->first_duration = stream->samples[0].duration;
10569 GST_LOG_OBJECT (qtdemux, "stream %d first duration %u",
10570 stream->track_id, stream->first_duration);
10577 static GstFlowReturn
10578 qtdemux_expose_streams (GstQTDemux * qtdemux)
10581 GstFlowReturn ret = GST_FLOW_OK;
10582 GSList *oldpads = NULL;
10585 GST_DEBUG_OBJECT (qtdemux, "exposing streams");
10587 for (i = 0; ret == GST_FLOW_OK && i < qtdemux->n_streams; i++) {
10588 QtDemuxStream *stream = qtdemux->streams[i];
10589 GstPad *oldpad = stream->pad;
10592 GST_DEBUG_OBJECT (qtdemux, "stream %d, id %d, fourcc %" GST_FOURCC_FORMAT,
10593 i, stream->track_id, GST_FOURCC_ARGS (stream->fourcc));
10595 if ((stream->subtype == FOURCC_text || stream->subtype == FOURCC_sbtl) &&
10596 stream->track_id == qtdemux->chapters_track_id) {
10597 /* TODO - parse chapters track and expose it as GstToc; For now just ignore it
10598 so that it doesn't look like a subtitle track */
10599 gst_qtdemux_remove_stream (qtdemux, i);
10604 /* now we have all info and can expose */
10605 list = stream->pending_tags;
10606 stream->pending_tags = NULL;
10608 oldpads = g_slist_prepend (oldpads, oldpad);
10609 gst_qtdemux_add_stream (qtdemux, stream, list);
10612 gst_qtdemux_guess_bitrate (qtdemux);
10614 gst_element_no_more_pads (GST_ELEMENT_CAST (qtdemux));
10616 for (iter = oldpads; iter; iter = g_slist_next (iter)) {
10617 GstPad *oldpad = iter->data;
10619 gst_pad_push_event (oldpad, gst_event_new_eos ());
10620 gst_pad_set_active (oldpad, FALSE);
10621 gst_element_remove_pad (GST_ELEMENT (qtdemux), oldpad);
10622 gst_flow_combiner_remove_pad (qtdemux->flowcombiner, oldpad);
10623 gst_object_unref (oldpad);
10626 /* check if we should post a redirect in case there is a single trak
10627 * and it is a redirecting trak */
10628 if (qtdemux->n_streams == 1 && qtdemux->streams[0]->redirect_uri != NULL) {
10631 GST_INFO_OBJECT (qtdemux, "Issuing a redirect due to a single track with "
10632 "an external content");
10633 m = gst_message_new_element (GST_OBJECT_CAST (qtdemux),
10634 gst_structure_new ("redirect",
10635 "new-location", G_TYPE_STRING, qtdemux->streams[0]->redirect_uri,
10637 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), m);
10638 qtdemux->posted_redirect = TRUE;
10641 for (i = 0; i < qtdemux->n_streams; i++) {
10642 QtDemuxStream *stream = qtdemux->streams[i];
10644 qtdemux_do_allocation (qtdemux, stream);
10647 qtdemux->exposed = TRUE;
10651 /* check if major or compatible brand is 3GP */
10652 static inline gboolean
10653 qtdemux_is_brand_3gp (GstQTDemux * qtdemux, gboolean major)
10656 return ((qtdemux->major_brand & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
10658 } else if (qtdemux->comp_brands != NULL) {
10662 gboolean res = FALSE;
10664 gst_buffer_map (qtdemux->comp_brands, &map, GST_MAP_READ);
10667 while (size >= 4) {
10668 res = res || ((QT_FOURCC (data) & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
10673 gst_buffer_unmap (qtdemux->comp_brands, &map);
10680 /* check if tag is a spec'ed 3GP tag keyword storing a string */
10681 static inline gboolean
10682 qtdemux_is_string_tag_3gp (GstQTDemux * qtdemux, guint32 fourcc)
10684 return fourcc == FOURCC_cprt || fourcc == FOURCC_gnre || fourcc == FOURCC_titl
10685 || fourcc == FOURCC_dscp || fourcc == FOURCC_perf || fourcc == FOURCC_auth
10686 || fourcc == FOURCC_albm;
10690 qtdemux_tag_add_location (GstQTDemux * qtdemux, GstTagList * taglist,
10691 const char *tag, const char *dummy, GNode * node)
10693 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
10697 gdouble longitude, latitude, altitude;
10700 len = QT_UINT32 (node->data);
10707 /* TODO: language code skipped */
10709 name = gst_tag_freeform_string_to_utf8 (data + offset, -1, env_vars);
10712 /* do not alarm in trivial case, but bail out otherwise */
10713 if (*(data + offset) != 0) {
10714 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8, "
10718 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
10719 GST_TAG_GEO_LOCATION_NAME, name, NULL);
10720 offset += strlen (name);
10724 if (len < offset + 2 + 4 + 4 + 4)
10727 /* +1 +1 = skip null-terminator and location role byte */
10729 /* table in spec says unsigned, semantics say negative has meaning ... */
10730 longitude = QT_SFP32 (data + offset);
10733 latitude = QT_SFP32 (data + offset);
10736 altitude = QT_SFP32 (data + offset);
10738 /* one invalid means all are invalid */
10739 if (longitude >= -180.0 && longitude <= 180.0 &&
10740 latitude >= -90.0 && latitude <= 90.0) {
10741 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
10742 GST_TAG_GEO_LOCATION_LATITUDE, latitude,
10743 GST_TAG_GEO_LOCATION_LONGITUDE, longitude,
10744 GST_TAG_GEO_LOCATION_ELEVATION, altitude, NULL);
10747 /* TODO: no GST_TAG_, so astronomical body and additional notes skipped */
10754 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP location");
10761 qtdemux_tag_add_year (GstQTDemux * qtdemux, GstTagList * taglist,
10762 const char *tag, const char *dummy, GNode * node)
10768 len = QT_UINT32 (node->data);
10772 y = QT_UINT16 ((guint8 *) node->data + 12);
10774 GST_DEBUG_OBJECT (qtdemux, "year: %u is not a valid year", y);
10777 GST_DEBUG_OBJECT (qtdemux, "year: %u", y);
10779 date = g_date_new_dmy (1, 1, y);
10780 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, date, NULL);
10781 g_date_free (date);
10785 qtdemux_tag_add_classification (GstQTDemux * qtdemux, GstTagList * taglist,
10786 const char *tag, const char *dummy, GNode * node)
10789 char *tag_str = NULL;
10794 len = QT_UINT32 (node->data);
10799 entity = (guint8 *) node->data + offset;
10800 if (entity[0] == 0 || entity[1] == 0 || entity[2] == 0 || entity[3] == 0) {
10801 GST_DEBUG_OBJECT (qtdemux,
10802 "classification info: %c%c%c%c invalid classification entity",
10803 entity[0], entity[1], entity[2], entity[3]);
10808 table = QT_UINT16 ((guint8 *) node->data + offset);
10810 /* Language code skipped */
10814 /* Tag format: "XXXX://Y[YYYY]/classification info string"
10815 * XXXX: classification entity, fixed length 4 chars.
10816 * Y[YYYY]: classification table, max 5 chars.
10818 tag_str = g_strdup_printf ("----://%u/%s",
10819 table, (char *) node->data + offset);
10821 /* memcpy To be sure we're preserving byte order */
10822 memcpy (tag_str, entity, 4);
10823 GST_DEBUG_OBJECT (qtdemux, "classification info: %s", tag_str);
10825 gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND, tag, tag_str, NULL);
10834 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP classification");
10840 qtdemux_tag_add_str_full (GstQTDemux * qtdemux, GstTagList * taglist,
10841 const char *tag, const char *dummy, GNode * node)
10843 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
10849 gboolean ret = TRUE;
10850 const gchar *charset = NULL;
10852 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
10854 len = QT_UINT32 (data->data);
10855 type = QT_UINT32 ((guint8 *) data->data + 8);
10856 if (type == 0x00000001 && len > 16) {
10857 s = gst_tag_freeform_string_to_utf8 ((char *) data->data + 16, len - 16,
10860 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
10861 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, s, NULL);
10864 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
10868 len = QT_UINT32 (node->data);
10869 type = QT_UINT32 ((guint8 *) node->data + 4);
10870 if ((type >> 24) == 0xa9) {
10874 /* Type starts with the (C) symbol, so the next data is a list
10875 * of (string size(16), language code(16), string) */
10877 str_len = QT_UINT16 ((guint8 *) node->data + 8);
10878 lang_code = QT_UINT16 ((guint8 *) node->data + 10);
10880 /* the string + fourcc + size + 2 16bit fields,
10881 * means that there are more tags in this atom */
10882 if (len > str_len + 8 + 4) {
10883 /* TODO how to represent the same tag in different languages? */
10884 GST_WARNING_OBJECT (qtdemux, "Ignoring metadata entry with multiple "
10885 "text alternatives, reading only first one");
10889 len = str_len + 8 + 4; /* remove trailing strings that we don't use */
10890 GST_DEBUG_OBJECT (qtdemux, "found international text tag");
10892 if (lang_code < 0x800) { /* MAC encoded string */
10895 } else if (len > 14 && qtdemux_is_string_tag_3gp (qtdemux,
10896 QT_FOURCC ((guint8 *) node->data + 4))) {
10897 guint32 type = QT_UINT32 ((guint8 *) node->data + 8);
10899 /* we go for 3GP style encoding if major brands claims so,
10900 * or if no hope for data be ok UTF-8, and compatible 3GP brand present */
10901 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
10902 (qtdemux_is_brand_3gp (qtdemux, FALSE) &&
10903 ((type & 0x00FFFFFF) == 0x0) && (type >> 24 <= 0xF))) {
10905 /* 16-bit Language code is ignored here as well */
10906 GST_DEBUG_OBJECT (qtdemux, "found 3gpp text tag");
10913 GST_DEBUG_OBJECT (qtdemux, "found normal text tag");
10914 ret = FALSE; /* may have to fallback */
10917 GError *err = NULL;
10919 s = g_convert ((gchar *) node->data + offset, len - offset, "utf8",
10920 charset, NULL, NULL, &err);
10922 GST_DEBUG_OBJECT (qtdemux, "Failed to convert string from charset %s:"
10923 " %s(%d): %s", charset, g_quark_to_string (err->domain), err->code,
10925 g_error_free (err);
10928 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
10929 len - offset, env_vars);
10932 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
10933 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, s, NULL);
10937 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
10944 qtdemux_tag_add_str (GstQTDemux * qtdemux, GstTagList * taglist,
10945 const char *tag, const char *dummy, GNode * node)
10947 qtdemux_tag_add_str_full (qtdemux, taglist, tag, dummy, node);
10951 qtdemux_tag_add_keywords (GstQTDemux * qtdemux, GstTagList * taglist,
10952 const char *tag, const char *dummy, GNode * node)
10954 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
10956 char *s, *t, *k = NULL;
10961 /* first try normal string tag if major brand not 3GP */
10962 if (!qtdemux_is_brand_3gp (qtdemux, TRUE)) {
10963 if (!qtdemux_tag_add_str_full (qtdemux, taglist, tag, dummy, node)) {
10964 /* hm, that did not work, maybe 3gpp storage in non-3gpp major brand;
10965 * let's try it 3gpp way after minor safety check */
10967 if (QT_UINT32 (data) < 15 || !qtdemux_is_brand_3gp (qtdemux, FALSE))
10973 GST_DEBUG_OBJECT (qtdemux, "found 3gpp keyword tag");
10977 len = QT_UINT32 (data);
10981 count = QT_UINT8 (data + 14);
10983 for (; count; count--) {
10986 if (offset + 1 > len)
10988 slen = QT_UINT8 (data + offset);
10990 if (offset + slen > len)
10992 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
10995 GST_DEBUG_OBJECT (qtdemux, "adding keyword %s", GST_STR_NULL (s));
10997 t = g_strjoin (",", k, s, NULL);
11005 GST_DEBUG_OBJECT (qtdemux, "failed to convert keyword to UTF-8");
11012 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (k));
11013 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, k, NULL);
11022 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP keywords");
11028 qtdemux_tag_add_num (GstQTDemux * qtdemux, GstTagList * taglist,
11029 const char *tag1, const char *tag2, GNode * node)
11036 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
11038 len = QT_UINT32 (data->data);
11039 type = QT_UINT32 ((guint8 *) data->data + 8);
11040 if (type == 0x00000000 && len >= 22) {
11041 n1 = QT_UINT16 ((guint8 *) data->data + 18);
11042 n2 = QT_UINT16 ((guint8 *) data->data + 20);
11044 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag1, n1);
11045 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, n1, NULL);
11048 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag2, n2);
11049 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag2, n2, NULL);
11056 qtdemux_tag_add_tmpo (GstQTDemux * qtdemux, GstTagList * taglist,
11057 const char *tag1, const char *dummy, GNode * node)
11064 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
11066 len = QT_UINT32 (data->data);
11067 type = QT_UINT32 ((guint8 *) data->data + 8);
11068 GST_DEBUG_OBJECT (qtdemux, "have tempo tag, type=%d,len=%d", type, len);
11069 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
11070 if ((type == 0x00000015 || type == 0x0000000f) && len >= 18) {
11071 n1 = QT_UINT16 ((guint8 *) data->data + 16);
11073 /* do not add bpm=0 */
11074 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", n1);
11075 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, (gdouble) n1,
11083 qtdemux_tag_add_uint32 (GstQTDemux * qtdemux, GstTagList * taglist,
11084 const char *tag1, const char *dummy, GNode * node)
11091 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
11093 len = QT_UINT32 (data->data);
11094 type = QT_UINT32 ((guint8 *) data->data + 8);
11095 GST_DEBUG_OBJECT (qtdemux, "have %s tag, type=%d,len=%d", tag1, type, len);
11096 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
11097 if ((type == 0x00000015 || type == 0x0000000f) && len >= 20) {
11098 num = QT_UINT32 ((guint8 *) data->data + 16);
11100 /* do not add num=0 */
11101 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", num);
11102 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, num, NULL);
11109 qtdemux_tag_add_covr (GstQTDemux * qtdemux, GstTagList * taglist,
11110 const char *tag1, const char *dummy, GNode * node)
11117 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
11119 len = QT_UINT32 (data->data);
11120 type = QT_UINT32 ((guint8 *) data->data + 8);
11121 GST_DEBUG_OBJECT (qtdemux, "have covr tag, type=%d,len=%d", type, len);
11122 if ((type == 0x0000000d || type == 0x0000000e) && len > 16) {
11124 gst_tag_image_data_to_image_sample ((guint8 *) data->data + 16,
11125 len - 16, GST_TAG_IMAGE_TYPE_NONE))) {
11126 GST_DEBUG_OBJECT (qtdemux, "adding tag size %d", len - 16);
11127 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, sample, NULL);
11128 gst_sample_unref (sample);
11135 qtdemux_tag_add_date (GstQTDemux * qtdemux, GstTagList * taglist,
11136 const char *tag, const char *dummy, GNode * node)
11143 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
11145 len = QT_UINT32 (data->data);
11146 type = QT_UINT32 ((guint8 *) data->data + 8);
11147 if (type == 0x00000001 && len > 16) {
11148 guint y, m = 1, d = 1;
11151 s = g_strndup ((char *) data->data + 16, len - 16);
11152 GST_DEBUG_OBJECT (qtdemux, "adding date '%s'", s);
11153 ret = sscanf (s, "%u-%u-%u", &y, &m, &d);
11154 if (ret >= 1 && y > 1500 && y < 3000) {
11157 date = g_date_new_dmy (d, m, y);
11158 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, date, NULL);
11159 g_date_free (date);
11161 GST_DEBUG_OBJECT (qtdemux, "could not parse date string '%s'", s);
11169 qtdemux_tag_add_gnre (GstQTDemux * qtdemux, GstTagList * taglist,
11170 const char *tag, const char *dummy, GNode * node)
11174 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
11176 /* re-route to normal string tag if major brand says so
11177 * or no data atom and compatible brand suggests so */
11178 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
11179 (qtdemux_is_brand_3gp (qtdemux, FALSE) && !data)) {
11180 qtdemux_tag_add_str (qtdemux, taglist, tag, dummy, node);
11185 guint len, type, n;
11187 len = QT_UINT32 (data->data);
11188 type = QT_UINT32 ((guint8 *) data->data + 8);
11189 if (type == 0x00000000 && len >= 18) {
11190 n = QT_UINT16 ((guint8 *) data->data + 16);
11192 const gchar *genre;
11194 genre = gst_tag_id3_genre_get (n - 1);
11195 if (genre != NULL) {
11196 GST_DEBUG_OBJECT (qtdemux, "adding %d [%s]", n, genre);
11197 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, genre, NULL);
11205 qtdemux_add_double_tag_from_str (GstQTDemux * demux, GstTagList * taglist,
11206 const gchar * tag, guint8 * data, guint32 datasize)
11211 /* make a copy to have \0 at the end */
11212 datacopy = g_strndup ((gchar *) data, datasize);
11214 /* convert the str to double */
11215 if (sscanf (datacopy, "%lf", &value) == 1) {
11216 GST_DEBUG_OBJECT (demux, "adding tag: %s [%s]", tag, datacopy);
11217 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, value, NULL);
11219 GST_WARNING_OBJECT (demux, "Failed to parse double from string: %s",
11227 qtdemux_tag_add_revdns (GstQTDemux * demux, GstTagList * taglist,
11228 const char *tag, const char *tag_bis, GNode * node)
11237 const gchar *meanstr;
11238 const gchar *namestr;
11240 /* checking the whole ---- atom size for consistency */
11241 if (QT_UINT32 (node->data) <= 4 + 12 + 12 + 16) {
11242 GST_WARNING_OBJECT (demux, "Tag ---- atom is too small, ignoring");
11246 mean = qtdemux_tree_get_child_by_type (node, FOURCC_mean);
11248 GST_WARNING_OBJECT (demux, "No 'mean' atom found");
11252 meansize = QT_UINT32 (mean->data);
11253 if (meansize <= 12) {
11254 GST_WARNING_OBJECT (demux, "Small mean atom, ignoring the whole tag");
11257 meanstr = ((gchar *) mean->data) + 12;
11260 name = qtdemux_tree_get_child_by_type (node, FOURCC_name);
11262 GST_WARNING_OBJECT (demux, "'name' atom not found, ignoring tag");
11266 namesize = QT_UINT32 (name->data);
11267 if (namesize <= 12) {
11268 GST_WARNING_OBJECT (demux, "'name' atom is too small, ignoring tag");
11271 namestr = ((gchar *) name->data) + 12;
11279 * uint24 - data type
11283 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
11285 GST_WARNING_OBJECT (demux, "No data atom in this tag");
11288 datasize = QT_UINT32 (data->data);
11289 if (datasize <= 16) {
11290 GST_WARNING_OBJECT (demux, "Data atom too small");
11293 datatype = QT_UINT32 (((gchar *) data->data) + 8) & 0xFFFFFF;
11295 if ((strncmp (meanstr, "com.apple.iTunes", meansize) == 0) ||
11296 (strncmp (meanstr, "org.hydrogenaudio.replaygain", meansize) == 0)) {
11297 static const struct
11299 const gchar name[28];
11300 const gchar tag[28];
11303 "replaygain_track_gain", GST_TAG_TRACK_GAIN}, {
11304 "replaygain_track_peak", GST_TAG_TRACK_PEAK}, {
11305 "replaygain_album_gain", GST_TAG_ALBUM_GAIN}, {
11306 "replaygain_album_peak", GST_TAG_ALBUM_PEAK}, {
11307 "MusicBrainz Track Id", GST_TAG_MUSICBRAINZ_TRACKID}, {
11308 "MusicBrainz Artist Id", GST_TAG_MUSICBRAINZ_ARTISTID}, {
11309 "MusicBrainz Album Id", GST_TAG_MUSICBRAINZ_ALBUMID}, {
11310 "MusicBrainz Album Artist Id", GST_TAG_MUSICBRAINZ_ALBUMARTISTID}
11314 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
11315 if (!g_ascii_strncasecmp (tags[i].name, namestr, namesize)) {
11316 switch (gst_tag_get_type (tags[i].tag)) {
11317 case G_TYPE_DOUBLE:
11318 qtdemux_add_double_tag_from_str (demux, taglist, tags[i].tag,
11319 ((guint8 *) data->data) + 16, datasize - 16);
11321 case G_TYPE_STRING:
11322 qtdemux_tag_add_str (demux, taglist, tags[i].tag, NULL, node);
11331 if (i == G_N_ELEMENTS (tags))
11341 #ifndef GST_DISABLE_GST_DEBUG
11343 gchar *namestr_dbg;
11344 gchar *meanstr_dbg;
11346 meanstr_dbg = g_strndup (meanstr, meansize);
11347 namestr_dbg = g_strndup (namestr, namesize);
11349 GST_WARNING_OBJECT (demux, "This tag %s:%s type:%u is not mapped, "
11350 "file a bug at bugzilla.gnome.org", meanstr_dbg, namestr_dbg, datatype);
11352 g_free (namestr_dbg);
11353 g_free (meanstr_dbg);
11360 qtdemux_tag_add_id32 (GstQTDemux * demux, GstTagList * taglist, const char *tag,
11361 const char *tag_bis, GNode * node)
11366 GstTagList *id32_taglist = NULL;
11368 GST_LOG_OBJECT (demux, "parsing ID32");
11371 len = GST_READ_UINT32_BE (data);
11373 /* need at least full box and language tag */
11377 buf = gst_buffer_new_allocate (NULL, len - 14, NULL);
11378 gst_buffer_fill (buf, 0, data + 14, len - 14);
11380 id32_taglist = gst_tag_list_from_id3v2_tag (buf);
11381 if (id32_taglist) {
11382 GST_LOG_OBJECT (demux, "parsing ok");
11383 gst_tag_list_insert (taglist, id32_taglist, GST_TAG_MERGE_KEEP);
11384 gst_tag_list_unref (id32_taglist);
11386 GST_LOG_OBJECT (demux, "parsing failed");
11389 gst_buffer_unref (buf);
11392 typedef void (*GstQTDemuxAddTagFunc) (GstQTDemux * demux, GstTagList * taglist,
11393 const char *tag, const char *tag_bis, GNode * node);
11396 FOURCC_pcst -> if media is a podcast -> bool
11397 FOURCC_cpil -> if media is part of a compilation -> bool
11398 FOURCC_pgap -> if media is part of a gapless context -> bool
11399 FOURCC_tven -> the tv episode id e.g. S01E23 -> str
11402 static const struct
11405 const gchar *gst_tag;
11406 const gchar *gst_tag_bis;
11407 const GstQTDemuxAddTagFunc func;
11410 FOURCC__nam, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
11411 FOURCC_titl, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
11412 FOURCC__grp, GST_TAG_GROUPING, NULL, qtdemux_tag_add_str}, {
11413 FOURCC__wrt, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
11414 FOURCC__ART, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
11415 FOURCC_aART, GST_TAG_ALBUM_ARTIST, NULL, qtdemux_tag_add_str}, {
11416 FOURCC_perf, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
11417 FOURCC_auth, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
11418 FOURCC__alb, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
11419 FOURCC_albm, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
11420 FOURCC_cprt, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
11421 FOURCC__cpy, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
11422 FOURCC__cmt, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
11423 FOURCC__des, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
11424 FOURCC_desc, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
11425 FOURCC_dscp, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
11426 FOURCC__lyr, GST_TAG_LYRICS, NULL, qtdemux_tag_add_str}, {
11427 FOURCC__day, GST_TAG_DATE, NULL, qtdemux_tag_add_date}, {
11428 FOURCC_yrrc, GST_TAG_DATE, NULL, qtdemux_tag_add_year}, {
11429 FOURCC__too, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
11430 FOURCC__inf, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
11431 FOURCC_trkn, GST_TAG_TRACK_NUMBER, GST_TAG_TRACK_COUNT, qtdemux_tag_add_num}, {
11432 FOURCC_disk, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
11433 qtdemux_tag_add_num}, {
11434 FOURCC_disc, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
11435 qtdemux_tag_add_num}, {
11436 FOURCC__gen, GST_TAG_GENRE, NULL, qtdemux_tag_add_str}, {
11437 FOURCC_gnre, GST_TAG_GENRE, NULL, qtdemux_tag_add_gnre}, {
11438 FOURCC_tmpo, GST_TAG_BEATS_PER_MINUTE, NULL, qtdemux_tag_add_tmpo}, {
11439 FOURCC_covr, GST_TAG_PREVIEW_IMAGE, NULL, qtdemux_tag_add_covr}, {
11440 FOURCC_sonm, GST_TAG_TITLE_SORTNAME, NULL, qtdemux_tag_add_str}, {
11441 FOURCC_soal, GST_TAG_ALBUM_SORTNAME, NULL, qtdemux_tag_add_str}, {
11442 FOURCC_soar, GST_TAG_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
11443 FOURCC_soaa, GST_TAG_ALBUM_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
11444 FOURCC_soco, GST_TAG_COMPOSER_SORTNAME, NULL, qtdemux_tag_add_str}, {
11445 FOURCC_sosn, GST_TAG_SHOW_SORTNAME, NULL, qtdemux_tag_add_str}, {
11446 FOURCC_tvsh, GST_TAG_SHOW_NAME, NULL, qtdemux_tag_add_str}, {
11447 FOURCC_tvsn, GST_TAG_SHOW_SEASON_NUMBER, NULL, qtdemux_tag_add_uint32}, {
11448 FOURCC_tves, GST_TAG_SHOW_EPISODE_NUMBER, NULL, qtdemux_tag_add_uint32}, {
11449 FOURCC_kywd, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_keywords}, {
11450 FOURCC_keyw, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_str}, {
11451 FOURCC__enc, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
11452 FOURCC_loci, GST_TAG_GEO_LOCATION_NAME, NULL, qtdemux_tag_add_location}, {
11453 FOURCC_clsf, GST_QT_DEMUX_CLASSIFICATION_TAG, NULL,
11454 qtdemux_tag_add_classification}, {
11455 FOURCC__mak, GST_TAG_DEVICE_MANUFACTURER, NULL, qtdemux_tag_add_str}, {
11456 FOURCC__mod, GST_TAG_DEVICE_MODEL, NULL, qtdemux_tag_add_str}, {
11457 FOURCC__swr, GST_TAG_APPLICATION_NAME, NULL, qtdemux_tag_add_str}, {
11459 /* This is a special case, some tags are stored in this
11460 * 'reverse dns naming', according to:
11461 * http://atomicparsley.sourceforge.net/mpeg-4files.html and
11464 FOURCC_____, "", NULL, qtdemux_tag_add_revdns}, {
11465 /* see http://www.mp4ra.org/specs.html for ID32 in meta box */
11466 FOURCC_ID32, "", NULL, qtdemux_tag_add_id32}
11469 struct _GstQtDemuxTagList
11472 GstTagList *taglist;
11474 typedef struct _GstQtDemuxTagList GstQtDemuxTagList;
11477 qtdemux_tag_add_blob (GNode * node, GstQtDemuxTagList * qtdemuxtaglist)
11483 const gchar *style;
11488 GstQTDemux *demux = qtdemuxtaglist->demux;
11489 GstTagList *taglist = qtdemuxtaglist->taglist;
11492 len = QT_UINT32 (data);
11493 buf = gst_buffer_new_and_alloc (len);
11494 gst_buffer_fill (buf, 0, data, len);
11496 /* heuristic to determine style of tag */
11497 if (QT_FOURCC (data + 4) == FOURCC_____ ||
11498 (len > 8 + 12 && QT_FOURCC (data + 12) == FOURCC_data))
11500 else if (demux->major_brand == FOURCC_qt__)
11501 style = "quicktime";
11502 /* fall back to assuming iso/3gp tag style */
11506 /* santize the name for the caps. */
11507 for (i = 0; i < 4; i++) {
11508 guint8 d = data[4 + i];
11509 if (g_ascii_isalnum (d))
11510 ndata[i] = g_ascii_tolower (d);
11515 media_type = g_strdup_printf ("application/x-gst-qt-%c%c%c%c-tag",
11516 ndata[0], ndata[1], ndata[2], ndata[3]);
11517 GST_DEBUG_OBJECT (demux, "media type %s", media_type);
11519 s = gst_structure_new (media_type, "style", G_TYPE_STRING, style, NULL);
11520 sample = gst_sample_new (buf, NULL, NULL, s);
11521 gst_buffer_unref (buf);
11522 g_free (media_type);
11524 GST_DEBUG_OBJECT (demux, "adding private tag; size %d, info %" GST_PTR_FORMAT,
11527 gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND,
11528 GST_QT_DEMUX_PRIVATE_TAG, sample, NULL);
11530 gst_sample_unref (sample);
11534 qtdemux_parse_udta (GstQTDemux * qtdemux, GstTagList * taglist, GNode * udta)
11541 GstQtDemuxTagList demuxtaglist;
11543 demuxtaglist.demux = qtdemux;
11544 demuxtaglist.taglist = taglist;
11546 meta = qtdemux_tree_get_child_by_type (udta, FOURCC_meta);
11547 if (meta != NULL) {
11548 ilst = qtdemux_tree_get_child_by_type (meta, FOURCC_ilst);
11549 if (ilst == NULL) {
11550 GST_LOG_OBJECT (qtdemux, "no ilst");
11555 GST_LOG_OBJECT (qtdemux, "no meta so using udta itself");
11559 while (i < G_N_ELEMENTS (add_funcs)) {
11560 node = qtdemux_tree_get_child_by_type (ilst, add_funcs[i].fourcc);
11564 len = QT_UINT32 (node->data);
11566 GST_DEBUG_OBJECT (qtdemux, "too small tag atom %" GST_FOURCC_FORMAT,
11567 GST_FOURCC_ARGS (add_funcs[i].fourcc));
11569 add_funcs[i].func (qtdemux, taglist, add_funcs[i].gst_tag,
11570 add_funcs[i].gst_tag_bis, node);
11572 g_node_destroy (node);
11578 /* parsed nodes have been removed, pass along remainder as blob */
11579 g_node_children_foreach (ilst, G_TRAVERSE_ALL,
11580 (GNodeForeachFunc) qtdemux_tag_add_blob, &demuxtaglist);
11582 /* parse up XMP_ node if existing */
11583 xmp_ = qtdemux_tree_get_child_by_type (udta, FOURCC_XMP_);
11584 if (xmp_ != NULL) {
11586 GstTagList *xmptaglist;
11588 buf = _gst_buffer_new_wrapped (((guint8 *) xmp_->data) + 8,
11589 QT_UINT32 ((guint8 *) xmp_->data) - 8, NULL);
11590 xmptaglist = gst_tag_list_from_xmp_buffer (buf);
11591 gst_buffer_unref (buf);
11593 qtdemux_handle_xmp_taglist (qtdemux, taglist, xmptaglist);
11595 GST_DEBUG_OBJECT (qtdemux, "No XMP_ node found");
11601 GstStructure *structure; /* helper for sort function */
11603 guint min_req_bitrate;
11604 guint min_req_qt_version;
11608 qtdemux_redirects_sort_func (gconstpointer a, gconstpointer b)
11610 GstQtReference *ref_a = (GstQtReference *) a;
11611 GstQtReference *ref_b = (GstQtReference *) b;
11613 if (ref_b->min_req_qt_version != ref_a->min_req_qt_version)
11614 return ref_b->min_req_qt_version - ref_a->min_req_qt_version;
11616 /* known bitrates go before unknown; higher bitrates go first */
11617 return ref_b->min_req_bitrate - ref_a->min_req_bitrate;
11620 /* sort the redirects and post a message for the application.
11623 qtdemux_process_redirects (GstQTDemux * qtdemux, GList * references)
11625 GstQtReference *best;
11628 GValue list_val = { 0, };
11631 g_assert (references != NULL);
11633 references = g_list_sort (references, qtdemux_redirects_sort_func);
11635 best = (GstQtReference *) references->data;
11637 g_value_init (&list_val, GST_TYPE_LIST);
11639 for (l = references; l != NULL; l = l->next) {
11640 GstQtReference *ref = (GstQtReference *) l->data;
11641 GValue struct_val = { 0, };
11643 ref->structure = gst_structure_new ("redirect",
11644 "new-location", G_TYPE_STRING, ref->location, NULL);
11646 if (ref->min_req_bitrate > 0) {
11647 gst_structure_set (ref->structure, "minimum-bitrate", G_TYPE_INT,
11648 ref->min_req_bitrate, NULL);
11651 g_value_init (&struct_val, GST_TYPE_STRUCTURE);
11652 g_value_set_boxed (&struct_val, ref->structure);
11653 gst_value_list_append_value (&list_val, &struct_val);
11654 g_value_unset (&struct_val);
11655 /* don't free anything here yet, since we need best->structure below */
11658 g_assert (best != NULL);
11659 s = gst_structure_copy (best->structure);
11661 if (g_list_length (references) > 1) {
11662 gst_structure_set_value (s, "locations", &list_val);
11665 g_value_unset (&list_val);
11667 for (l = references; l != NULL; l = l->next) {
11668 GstQtReference *ref = (GstQtReference *) l->data;
11670 gst_structure_free (ref->structure);
11671 g_free (ref->location);
11674 g_list_free (references);
11676 GST_INFO_OBJECT (qtdemux, "posting redirect message: %" GST_PTR_FORMAT, s);
11677 msg = gst_message_new_element (GST_OBJECT_CAST (qtdemux), s);
11678 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
11679 qtdemux->posted_redirect = TRUE;
11682 /* look for redirect nodes, collect all redirect information and
11686 qtdemux_parse_redirects (GstQTDemux * qtdemux)
11688 GNode *rmra, *rmda, *rdrf;
11690 rmra = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_rmra);
11692 GList *redirects = NULL;
11694 rmda = qtdemux_tree_get_child_by_type (rmra, FOURCC_rmda);
11696 GstQtReference ref = { NULL, NULL, 0, 0 };
11697 GNode *rmdr, *rmvc;
11699 if ((rmdr = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmdr))) {
11700 ref.min_req_bitrate = QT_UINT32 ((guint8 *) rmdr->data + 12);
11701 GST_LOG_OBJECT (qtdemux, "data rate atom, required bitrate = %u",
11702 ref.min_req_bitrate);
11705 if ((rmvc = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmvc))) {
11706 guint32 package = QT_FOURCC ((guint8 *) rmvc->data + 12);
11707 guint version = QT_UINT32 ((guint8 *) rmvc->data + 16);
11709 #ifndef GST_DISABLE_GST_DEBUG
11710 guint bitmask = QT_UINT32 ((guint8 *) rmvc->data + 20);
11712 guint check_type = QT_UINT16 ((guint8 *) rmvc->data + 24);
11714 GST_LOG_OBJECT (qtdemux,
11715 "version check atom [%" GST_FOURCC_FORMAT "], version=0x%08x"
11716 ", mask=%08x, check_type=%u", GST_FOURCC_ARGS (package), version,
11717 bitmask, check_type);
11718 if (package == FOURCC_qtim && check_type == 0) {
11719 ref.min_req_qt_version = version;
11723 rdrf = qtdemux_tree_get_child_by_type (rmda, FOURCC_rdrf);
11729 ref_len = QT_UINT32 ((guint8 *) rdrf->data);
11730 if (ref_len > 20) {
11731 ref_type = QT_FOURCC ((guint8 *) rdrf->data + 12);
11732 ref_data = (guint8 *) rdrf->data + 20;
11733 if (ref_type == FOURCC_alis) {
11734 guint record_len, record_version, fn_len;
11736 if (ref_len > 70) {
11737 /* MacOSX alias record, google for alias-layout.txt */
11738 record_len = QT_UINT16 (ref_data + 4);
11739 record_version = QT_UINT16 (ref_data + 4 + 2);
11740 fn_len = QT_UINT8 (ref_data + 50);
11741 if (record_len > 50 && record_version == 2 && fn_len > 0) {
11742 ref.location = g_strndup ((gchar *) ref_data + 51, fn_len);
11745 GST_WARNING_OBJECT (qtdemux, "Invalid rdrf/alis size (%u < 70)",
11748 } else if (ref_type == FOURCC_url_) {
11749 ref.location = g_strndup ((gchar *) ref_data, ref_len - 8);
11751 GST_DEBUG_OBJECT (qtdemux,
11752 "unknown rdrf reference type %" GST_FOURCC_FORMAT,
11753 GST_FOURCC_ARGS (ref_type));
11755 if (ref.location != NULL) {
11756 GST_INFO_OBJECT (qtdemux, "New location: %s", ref.location);
11758 g_list_prepend (redirects, g_memdup (&ref, sizeof (ref)));
11760 GST_WARNING_OBJECT (qtdemux,
11761 "Failed to extract redirect location from rdrf atom");
11764 GST_WARNING_OBJECT (qtdemux, "Invalid rdrf size (%u < 20)", ref_len);
11768 /* look for others */
11769 rmda = qtdemux_tree_get_sibling_by_type (rmda, FOURCC_rmda);
11772 if (redirects != NULL) {
11773 qtdemux_process_redirects (qtdemux, redirects);
11779 static GstTagList *
11780 qtdemux_add_container_format (GstQTDemux * qtdemux, GstTagList * tags)
11784 if (tags == NULL) {
11785 tags = gst_tag_list_new_empty ();
11786 gst_tag_list_set_scope (tags, GST_TAG_SCOPE_GLOBAL);
11789 if (qtdemux->major_brand == FOURCC_mjp2)
11790 fmt = "Motion JPEG 2000";
11791 else if ((qtdemux->major_brand & 0xffff) == FOURCC_3g__)
11793 else if (qtdemux->major_brand == FOURCC_qt__)
11795 else if (qtdemux->fragmented)
11798 fmt = "ISO MP4/M4A";
11800 GST_LOG_OBJECT (qtdemux, "mapped %" GST_FOURCC_FORMAT " to '%s'",
11801 GST_FOURCC_ARGS (qtdemux->major_brand), fmt);
11803 gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_CONTAINER_FORMAT,
11809 /* we have read th complete moov node now.
11810 * This function parses all of the relevant info, creates the traks and
11811 * prepares all data structures for playback
11814 qtdemux_parse_tree (GstQTDemux * qtdemux)
11820 GstClockTime duration;
11822 guint64 creation_time;
11823 GstDateTime *datetime = NULL;
11826 /* make sure we have a usable taglist */
11827 if (!qtdemux->tag_list) {
11828 qtdemux->tag_list = gst_tag_list_new_empty ();
11829 gst_tag_list_set_scope (qtdemux->tag_list, GST_TAG_SCOPE_GLOBAL);
11831 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
11834 mvhd = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvhd);
11835 if (mvhd == NULL) {
11836 GST_LOG_OBJECT (qtdemux, "No mvhd node found, looking for redirects.");
11837 return qtdemux_parse_redirects (qtdemux);
11840 version = QT_UINT8 ((guint8 *) mvhd->data + 8);
11841 if (version == 1) {
11842 creation_time = QT_UINT64 ((guint8 *) mvhd->data + 12);
11843 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 28);
11844 qtdemux->duration = QT_UINT64 ((guint8 *) mvhd->data + 32);
11845 } else if (version == 0) {
11846 creation_time = QT_UINT32 ((guint8 *) mvhd->data + 12);
11847 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 20);
11848 qtdemux->duration = QT_UINT32 ((guint8 *) mvhd->data + 24);
11850 GST_WARNING_OBJECT (qtdemux, "Unhandled mvhd version %d", version);
11854 /* Moving qt creation time (secs since 1904) to unix time */
11855 if (creation_time != 0) {
11856 /* Try to use epoch first as it should be faster and more commonly found */
11857 if (creation_time >= QTDEMUX_SECONDS_FROM_1904_TO_1970) {
11860 creation_time -= QTDEMUX_SECONDS_FROM_1904_TO_1970;
11861 /* some data cleansing sanity */
11862 g_get_current_time (&now);
11863 if (now.tv_sec + 24 * 3600 < creation_time) {
11864 GST_DEBUG_OBJECT (qtdemux, "discarding bogus future creation time");
11866 datetime = gst_date_time_new_from_unix_epoch_utc (creation_time);
11869 GDateTime *base_dt = g_date_time_new_utc (1904, 1, 1, 0, 0, 0);
11870 GDateTime *dt, *dt_local;
11872 dt = g_date_time_add_seconds (base_dt, creation_time);
11873 dt_local = g_date_time_to_local (dt);
11874 datetime = gst_date_time_new_from_g_date_time (dt_local);
11876 g_date_time_unref (base_dt);
11877 g_date_time_unref (dt);
11881 /* Use KEEP as explicit tags should have a higher priority than mvhd tag */
11882 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_KEEP, GST_TAG_DATE_TIME,
11884 gst_date_time_unref (datetime);
11887 GST_INFO_OBJECT (qtdemux, "timescale: %u", qtdemux->timescale);
11888 GST_INFO_OBJECT (qtdemux, "duration: %" G_GUINT64_FORMAT, qtdemux->duration);
11890 /* check for fragmented file and get some (default) data */
11891 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
11894 GstByteReader mehd_data;
11896 /* let track parsing or anyone know weird stuff might happen ... */
11897 qtdemux->fragmented = TRUE;
11899 /* compensate for total duration */
11900 mehd = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_mehd, &mehd_data);
11902 qtdemux_parse_mehd (qtdemux, &mehd_data);
11905 /* set duration in the segment info */
11906 gst_qtdemux_get_duration (qtdemux, &duration);
11908 qtdemux->segment.duration = duration;
11909 /* also do not exceed duration; stop is set that way post seek anyway,
11910 * and segment activation falls back to duration,
11911 * whereas loop only checks stop, so let's align this here as well */
11912 qtdemux->segment.stop = duration;
11915 /* parse all traks */
11916 trak = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_trak);
11918 qtdemux_parse_trak (qtdemux, trak);
11919 /* iterate all siblings */
11920 trak = qtdemux_tree_get_sibling_by_type (trak, FOURCC_trak);
11923 if (!qtdemux->tag_list) {
11924 GST_DEBUG_OBJECT (qtdemux, "new tag list");
11925 qtdemux->tag_list = gst_tag_list_new_empty ();
11926 gst_tag_list_set_scope (qtdemux->tag_list, GST_TAG_SCOPE_GLOBAL);
11928 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
11932 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_udta);
11934 qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
11936 GST_LOG_OBJECT (qtdemux, "No udta node found.");
11939 /* maybe also some tags in meta box */
11940 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_meta);
11942 GST_DEBUG_OBJECT (qtdemux, "Parsing meta box for tags.");
11943 qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
11945 GST_LOG_OBJECT (qtdemux, "No meta node found.");
11948 /* parse any protection system info */
11949 pssh = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_pssh);
11951 GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
11952 qtdemux_parse_pssh (qtdemux, pssh);
11953 pssh = qtdemux_tree_get_sibling_by_type (pssh, FOURCC_pssh);
11956 qtdemux->tag_list = qtdemux_add_container_format (qtdemux, qtdemux->tag_list);
11961 /* taken from ffmpeg */
11963 read_descr_size (guint8 * ptr, guint8 * end, guint8 ** end_out)
11975 len = (len << 7) | (c & 0x7f);
11983 /* this can change the codec originally present in @list */
11985 gst_qtdemux_handle_esds (GstQTDemux * qtdemux, QtDemuxStream * stream,
11986 GNode * esds, GstTagList * list)
11988 int len = QT_UINT32 (esds->data);
11989 guint8 *ptr = esds->data;
11990 guint8 *end = ptr + len;
11992 guint8 *data_ptr = NULL;
11994 guint8 object_type_id = 0;
11995 const char *codec_name = NULL;
11996 GstCaps *caps = NULL;
11998 GST_MEMDUMP_OBJECT (qtdemux, "esds", ptr, len);
12000 GST_DEBUG_OBJECT (qtdemux, "version/flags = %08x", QT_UINT32 (ptr));
12002 while (ptr + 1 < end) {
12003 tag = QT_UINT8 (ptr);
12004 GST_DEBUG_OBJECT (qtdemux, "tag = %02x", tag);
12006 len = read_descr_size (ptr, end, &ptr);
12007 GST_DEBUG_OBJECT (qtdemux, "len = %d", len);
12009 /* Check the stated amount of data is available for reading */
12010 if (len < 0 || ptr + len > end)
12014 case ES_DESCRIPTOR_TAG:
12015 GST_DEBUG_OBJECT (qtdemux, "ID %04x", QT_UINT16 (ptr));
12016 GST_DEBUG_OBJECT (qtdemux, "priority %04x", QT_UINT8 (ptr + 2));
12019 case DECODER_CONFIG_DESC_TAG:{
12020 guint max_bitrate, avg_bitrate;
12022 object_type_id = QT_UINT8 (ptr);
12023 max_bitrate = QT_UINT32 (ptr + 5);
12024 avg_bitrate = QT_UINT32 (ptr + 9);
12025 GST_DEBUG_OBJECT (qtdemux, "object_type_id %02x", object_type_id);
12026 GST_DEBUG_OBJECT (qtdemux, "stream_type %02x", QT_UINT8 (ptr + 1));
12027 GST_DEBUG_OBJECT (qtdemux, "buffer_size_db %02x", QT_UINT24 (ptr + 2));
12028 GST_DEBUG_OBJECT (qtdemux, "max bitrate %u", max_bitrate);
12029 GST_DEBUG_OBJECT (qtdemux, "avg bitrate %u", avg_bitrate);
12030 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
12031 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
12032 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
12034 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
12035 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
12036 avg_bitrate, NULL);
12041 case DECODER_SPECIFIC_INFO_TAG:
12042 GST_MEMDUMP_OBJECT (qtdemux, "data", ptr, len);
12043 if (object_type_id == 0xe0 && len == 0x40) {
12049 GST_DEBUG_OBJECT (qtdemux,
12050 "Have VOBSUB palette. Creating palette event");
12051 /* move to decConfigDescr data and read palette */
12053 for (i = 0; i < 16; i++) {
12054 clut[i] = QT_UINT32 (data);
12058 s = gst_structure_new ("application/x-gst-dvd", "event",
12059 G_TYPE_STRING, "dvd-spu-clut-change",
12060 "clut00", G_TYPE_INT, clut[0], "clut01", G_TYPE_INT, clut[1],
12061 "clut02", G_TYPE_INT, clut[2], "clut03", G_TYPE_INT, clut[3],
12062 "clut04", G_TYPE_INT, clut[4], "clut05", G_TYPE_INT, clut[5],
12063 "clut06", G_TYPE_INT, clut[6], "clut07", G_TYPE_INT, clut[7],
12064 "clut08", G_TYPE_INT, clut[8], "clut09", G_TYPE_INT, clut[9],
12065 "clut10", G_TYPE_INT, clut[10], "clut11", G_TYPE_INT, clut[11],
12066 "clut12", G_TYPE_INT, clut[12], "clut13", G_TYPE_INT, clut[13],
12067 "clut14", G_TYPE_INT, clut[14], "clut15", G_TYPE_INT, clut[15],
12070 /* store event and trigger custom processing */
12071 stream->pending_event =
12072 gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s);
12074 /* Generic codec_data handler puts it on the caps */
12081 case SL_CONFIG_DESC_TAG:
12082 GST_DEBUG_OBJECT (qtdemux, "data %02x", QT_UINT8 (ptr));
12086 GST_DEBUG_OBJECT (qtdemux, "Unknown/unhandled descriptor tag %02x",
12088 GST_MEMDUMP_OBJECT (qtdemux, "descriptor data", ptr, len);
12094 /* object_type_id in the esds atom in mp4a and mp4v tells us which codec is
12095 * in use, and should also be used to override some other parameters for some
12097 switch (object_type_id) {
12098 case 0x20: /* MPEG-4 */
12099 /* 4 bytes for the visual_object_sequence_start_code and 1 byte for the
12100 * profile_and_level_indication */
12101 if (data_ptr != NULL && data_len >= 5 &&
12102 GST_READ_UINT32_BE (data_ptr) == 0x000001b0) {
12103 gst_codec_utils_mpeg4video_caps_set_level_and_profile (stream->caps,
12104 data_ptr + 4, data_len - 4);
12106 break; /* Nothing special needed here */
12107 case 0x21: /* H.264 */
12108 codec_name = "H.264 / AVC";
12109 caps = gst_caps_new_simple ("video/x-h264",
12110 "stream-format", G_TYPE_STRING, "avc",
12111 "alignment", G_TYPE_STRING, "au", NULL);
12113 case 0x40: /* AAC (any) */
12114 case 0x66: /* AAC Main */
12115 case 0x67: /* AAC LC */
12116 case 0x68: /* AAC SSR */
12117 /* Override channels and rate based on the codec_data, as it's often
12119 /* Only do so for basic setup without HE-AAC extension */
12120 if (data_ptr && data_len == 2) {
12121 guint channels, rateindex, rate;
12123 /* FIXME: add gst_codec_utils_aac_get_{channels|sample_rate}()? */
12124 channels = (data_ptr[1] & 0x7f) >> 3;
12125 if (channels > 0 && channels < 7) {
12126 stream->n_channels = channels;
12127 } else if (channels == 7) {
12128 stream->n_channels = 8;
12131 rateindex = ((data_ptr[0] & 0x7) << 1) | ((data_ptr[1] & 0x80) >> 7);
12132 rate = gst_codec_utils_aac_get_sample_rate_from_index (rateindex);
12134 stream->rate = rate;
12137 /* Set level and profile if possible */
12138 if (data_ptr != NULL && data_len >= 2) {
12139 gst_codec_utils_aac_caps_set_level_and_profile (stream->caps,
12140 data_ptr, data_len);
12143 case 0x60: /* MPEG-2, various profiles */
12149 codec_name = "MPEG-2 video";
12150 caps = gst_caps_new_simple ("video/mpeg",
12151 "mpegversion", G_TYPE_INT, 2,
12152 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
12154 case 0x69: /* MPEG-2 BC audio */
12155 case 0x6B: /* MPEG-1 audio */
12156 caps = gst_caps_new_simple ("audio/mpeg",
12157 "mpegversion", G_TYPE_INT, 1, "parsed", G_TYPE_BOOLEAN, TRUE, NULL);
12158 codec_name = "MPEG-1 audio";
12160 case 0x6A: /* MPEG-1 */
12161 codec_name = "MPEG-1 video";
12162 caps = gst_caps_new_simple ("video/mpeg",
12163 "mpegversion", G_TYPE_INT, 1,
12164 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
12166 case 0x6C: /* MJPEG */
12168 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
12170 codec_name = "Motion-JPEG";
12172 case 0x6D: /* PNG */
12174 gst_caps_new_simple ("image/png", "parsed", G_TYPE_BOOLEAN, TRUE,
12176 codec_name = "PNG still images";
12178 case 0x6E: /* JPEG2000 */
12179 codec_name = "JPEG-2000";
12180 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
12182 case 0xA4: /* Dirac */
12183 codec_name = "Dirac";
12184 caps = gst_caps_new_empty_simple ("video/x-dirac");
12186 case 0xA5: /* AC3 */
12187 codec_name = "AC-3 audio";
12188 caps = gst_caps_new_simple ("audio/x-ac3",
12189 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
12191 case 0xA9: /* AC3 */
12192 codec_name = "DTS audio";
12193 caps = gst_caps_new_simple ("audio/x-dts",
12194 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
12196 case 0xE1: /* QCELP */
12197 /* QCELP, the codec_data is a riff tag (little endian) with
12198 * 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). */
12199 caps = gst_caps_new_empty_simple ("audio/qcelp");
12200 codec_name = "QCELP";
12206 /* If we have a replacement caps, then change our caps for this stream */
12208 gst_caps_unref (stream->caps);
12209 stream->caps = caps;
12212 if (codec_name && list)
12213 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
12214 GST_TAG_AUDIO_CODEC, codec_name, NULL);
12216 /* Add the codec_data attribute to caps, if we have it */
12220 buffer = gst_buffer_new_and_alloc (data_len);
12221 gst_buffer_fill (buffer, 0, data_ptr, data_len);
12223 GST_DEBUG_OBJECT (qtdemux, "setting codec_data from esds");
12224 GST_MEMDUMP_OBJECT (qtdemux, "codec_data from esds", data_ptr, data_len);
12226 gst_caps_set_simple (stream->caps, "codec_data", GST_TYPE_BUFFER,
12228 gst_buffer_unref (buffer);
12233 #define _codec(name) \
12235 if (codec_name) { \
12236 *codec_name = g_strdup (name); \
12241 qtdemux_video_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
12242 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
12244 GstCaps *caps = NULL;
12245 GstVideoFormat format = GST_VIDEO_FORMAT_UNKNOWN;
12248 case GST_MAKE_FOURCC ('p', 'n', 'g', ' '):
12249 _codec ("PNG still images");
12250 caps = gst_caps_new_empty_simple ("image/png");
12253 _codec ("JPEG still images");
12255 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
12258 case GST_MAKE_FOURCC ('m', 'j', 'p', 'a'):
12259 case GST_MAKE_FOURCC ('A', 'V', 'D', 'J'):
12260 case GST_MAKE_FOURCC ('M', 'J', 'P', 'G'):
12261 case GST_MAKE_FOURCC ('d', 'm', 'b', '1'):
12262 _codec ("Motion-JPEG");
12264 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
12267 case GST_MAKE_FOURCC ('m', 'j', 'p', 'b'):
12268 _codec ("Motion-JPEG format B");
12269 caps = gst_caps_new_empty_simple ("video/x-mjpeg-b");
12272 _codec ("JPEG-2000");
12273 /* override to what it should be according to spec, avoid palette_data */
12274 stream->bits_per_sample = 24;
12275 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
12278 _codec ("Sorensen video v.3");
12279 caps = gst_caps_new_simple ("video/x-svq",
12280 "svqversion", G_TYPE_INT, 3, NULL);
12282 case GST_MAKE_FOURCC ('s', 'v', 'q', 'i'):
12283 case GST_MAKE_FOURCC ('S', 'V', 'Q', '1'):
12284 _codec ("Sorensen video v.1");
12285 caps = gst_caps_new_simple ("video/x-svq",
12286 "svqversion", G_TYPE_INT, 1, NULL);
12288 case GST_MAKE_FOURCC ('W', 'R', 'A', 'W'):
12289 caps = gst_caps_new_empty_simple ("video/x-raw");
12290 gst_caps_set_simple (caps, "format", G_TYPE_STRING, "RGB8P", NULL);
12291 _codec ("Windows Raw RGB");
12297 bps = QT_UINT16 (stsd_data + 98);
12300 format = GST_VIDEO_FORMAT_RGB15;
12303 format = GST_VIDEO_FORMAT_RGB16;
12306 format = GST_VIDEO_FORMAT_RGB;
12309 format = GST_VIDEO_FORMAT_ARGB;
12317 case GST_MAKE_FOURCC ('y', 'v', '1', '2'):
12318 format = GST_VIDEO_FORMAT_I420;
12320 case GST_MAKE_FOURCC ('y', 'u', 'v', '2'):
12321 case GST_MAKE_FOURCC ('Y', 'u', 'v', '2'):
12322 format = GST_VIDEO_FORMAT_I420;
12325 case GST_MAKE_FOURCC ('2', 'V', 'u', 'y'):
12326 format = GST_VIDEO_FORMAT_UYVY;
12328 case GST_MAKE_FOURCC ('v', '3', '0', '8'):
12329 format = GST_VIDEO_FORMAT_v308;
12331 case GST_MAKE_FOURCC ('v', '2', '1', '6'):
12332 format = GST_VIDEO_FORMAT_v216;
12335 format = GST_VIDEO_FORMAT_v210;
12337 case GST_MAKE_FOURCC ('r', '2', '1', '0'):
12338 format = GST_VIDEO_FORMAT_r210;
12340 /* Packed YUV 4:4:4 10 bit in 32 bits, complex
12341 case GST_MAKE_FOURCC ('v', '4', '1', '0'):
12342 format = GST_VIDEO_FORMAT_v410;
12345 /* Packed YUV 4:4:4:4 8 bit in 32 bits
12346 * but different order than AYUV
12347 case GST_MAKE_FOURCC ('v', '4', '0', '8'):
12348 format = GST_VIDEO_FORMAT_v408;
12351 case GST_MAKE_FOURCC ('m', 'p', 'e', 'g'):
12352 case GST_MAKE_FOURCC ('m', 'p', 'g', '1'):
12353 _codec ("MPEG-1 video");
12354 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
12355 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
12357 case GST_MAKE_FOURCC ('h', 'd', 'v', '1'): /* HDV 720p30 */
12358 case GST_MAKE_FOURCC ('h', 'd', 'v', '2'): /* HDV 1080i60 */
12359 case GST_MAKE_FOURCC ('h', 'd', 'v', '3'): /* HDV 1080i50 */
12360 case GST_MAKE_FOURCC ('h', 'd', 'v', '4'): /* HDV 720p24 */
12361 case GST_MAKE_FOURCC ('h', 'd', 'v', '5'): /* HDV 720p25 */
12362 case GST_MAKE_FOURCC ('h', 'd', 'v', '6'): /* HDV 1080p24 */
12363 case GST_MAKE_FOURCC ('h', 'd', 'v', '7'): /* HDV 1080p25 */
12364 case GST_MAKE_FOURCC ('h', 'd', 'v', '8'): /* HDV 1080p30 */
12365 case GST_MAKE_FOURCC ('h', 'd', 'v', '9'): /* HDV 720p60 */
12366 case GST_MAKE_FOURCC ('h', 'd', 'v', 'a'): /* HDV 720p50 */
12367 case GST_MAKE_FOURCC ('m', 'x', '5', 'n'): /* MPEG2 IMX NTSC 525/60 50mb/s produced by FCP */
12368 case GST_MAKE_FOURCC ('m', 'x', '5', 'p'): /* MPEG2 IMX PAL 625/60 50mb/s produced by FCP */
12369 case GST_MAKE_FOURCC ('m', 'x', '4', 'n'): /* MPEG2 IMX NTSC 525/60 40mb/s produced by FCP */
12370 case GST_MAKE_FOURCC ('m', 'x', '4', 'p'): /* MPEG2 IMX PAL 625/60 40mb/s produced by FCP */
12371 case GST_MAKE_FOURCC ('m', 'x', '3', 'n'): /* MPEG2 IMX NTSC 525/60 30mb/s produced by FCP */
12372 case GST_MAKE_FOURCC ('m', 'x', '3', 'p'): /* MPEG2 IMX PAL 625/50 30mb/s produced by FCP */
12373 case GST_MAKE_FOURCC ('x', 'd', 'v', '1'): /* XDCAM HD 720p30 35Mb/s */
12374 case GST_MAKE_FOURCC ('x', 'd', 'v', '2'): /* XDCAM HD 1080i60 35Mb/s */
12375 case GST_MAKE_FOURCC ('x', 'd', 'v', '3'): /* XDCAM HD 1080i50 35Mb/s */
12376 case GST_MAKE_FOURCC ('x', 'd', 'v', '4'): /* XDCAM HD 720p24 35Mb/s */
12377 case GST_MAKE_FOURCC ('x', 'd', 'v', '5'): /* XDCAM HD 720p25 35Mb/s */
12378 case GST_MAKE_FOURCC ('x', 'd', 'v', '6'): /* XDCAM HD 1080p24 35Mb/s */
12379 case GST_MAKE_FOURCC ('x', 'd', 'v', '7'): /* XDCAM HD 1080p25 35Mb/s */
12380 case GST_MAKE_FOURCC ('x', 'd', 'v', '8'): /* XDCAM HD 1080p30 35Mb/s */
12381 case GST_MAKE_FOURCC ('x', 'd', 'v', '9'): /* XDCAM HD 720p60 35Mb/s */
12382 case GST_MAKE_FOURCC ('x', 'd', 'v', 'a'): /* XDCAM HD 720p50 35Mb/s */
12383 case GST_MAKE_FOURCC ('x', 'd', 'v', 'b'): /* XDCAM EX 1080i60 50Mb/s CBR */
12384 case GST_MAKE_FOURCC ('x', 'd', 'v', 'c'): /* XDCAM EX 1080i50 50Mb/s CBR */
12385 case GST_MAKE_FOURCC ('x', 'd', 'v', 'd'): /* XDCAM HD 1080p24 50Mb/s CBR */
12386 case GST_MAKE_FOURCC ('x', 'd', 'v', 'e'): /* XDCAM HD 1080p25 50Mb/s CBR */
12387 case GST_MAKE_FOURCC ('x', 'd', 'v', 'f'): /* XDCAM HD 1080p30 50Mb/s CBR */
12388 case GST_MAKE_FOURCC ('x', 'd', '5', '1'): /* XDCAM HD422 720p30 50Mb/s CBR */
12389 case GST_MAKE_FOURCC ('x', 'd', '5', '4'): /* XDCAM HD422 720p24 50Mb/s CBR */
12390 case GST_MAKE_FOURCC ('x', 'd', '5', '5'): /* XDCAM HD422 720p25 50Mb/s CBR */
12391 case GST_MAKE_FOURCC ('x', 'd', '5', '9'): /* XDCAM HD422 720p60 50Mb/s CBR */
12392 case GST_MAKE_FOURCC ('x', 'd', '5', 'a'): /* XDCAM HD422 720p50 50Mb/s CBR */
12393 case GST_MAKE_FOURCC ('x', 'd', '5', 'b'): /* XDCAM HD422 1080i50 50Mb/s CBR */
12394 case GST_MAKE_FOURCC ('x', 'd', '5', 'c'): /* XDCAM HD422 1080i50 50Mb/s CBR */
12395 case GST_MAKE_FOURCC ('x', 'd', '5', 'd'): /* XDCAM HD422 1080p24 50Mb/s CBR */
12396 case GST_MAKE_FOURCC ('x', 'd', '5', 'e'): /* XDCAM HD422 1080p25 50Mb/s CBR */
12397 case GST_MAKE_FOURCC ('x', 'd', '5', 'f'): /* XDCAM HD422 1080p30 50Mb/s CBR */
12398 case GST_MAKE_FOURCC ('x', 'd', 'h', 'd'): /* XDCAM HD 540p */
12399 case GST_MAKE_FOURCC ('x', 'd', 'h', '2'): /* XDCAM HD422 540p */
12400 case GST_MAKE_FOURCC ('A', 'V', 'm', 'p'): /* AVID IMX PAL */
12401 case GST_MAKE_FOURCC ('m', 'p', 'g', '2'): /* AVID IMX PAL */
12402 case GST_MAKE_FOURCC ('m', 'p', '2', 'v'): /* AVID IMX PAL */
12403 _codec ("MPEG-2 video");
12404 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 2,
12405 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
12407 case GST_MAKE_FOURCC ('g', 'i', 'f', ' '):
12408 _codec ("GIF still images");
12409 caps = gst_caps_new_empty_simple ("image/gif");
12412 case GST_MAKE_FOURCC ('H', '2', '6', '3'):
12414 case GST_MAKE_FOURCC ('U', '2', '6', '3'):
12416 /* ffmpeg uses the height/width props, don't know why */
12417 caps = gst_caps_new_simple ("video/x-h263",
12418 "variant", G_TYPE_STRING, "itu", NULL);
12422 _codec ("MPEG-4 video");
12423 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
12424 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
12426 case GST_MAKE_FOURCC ('3', 'i', 'v', 'd'):
12427 case GST_MAKE_FOURCC ('3', 'I', 'V', 'D'):
12428 _codec ("Microsoft MPEG-4 4.3"); /* FIXME? */
12429 caps = gst_caps_new_simple ("video/x-msmpeg",
12430 "msmpegversion", G_TYPE_INT, 43, NULL);
12432 case GST_MAKE_FOURCC ('D', 'I', 'V', '3'):
12434 caps = gst_caps_new_simple ("video/x-divx",
12435 "divxversion", G_TYPE_INT, 3, NULL);
12437 case GST_MAKE_FOURCC ('D', 'I', 'V', 'X'):
12438 case GST_MAKE_FOURCC ('d', 'i', 'v', 'x'):
12440 caps = gst_caps_new_simple ("video/x-divx",
12441 "divxversion", G_TYPE_INT, 4, NULL);
12443 case GST_MAKE_FOURCC ('D', 'X', '5', '0'):
12445 caps = gst_caps_new_simple ("video/x-divx",
12446 "divxversion", G_TYPE_INT, 5, NULL);
12449 case GST_MAKE_FOURCC ('F', 'F', 'V', '1'):
12451 caps = gst_caps_new_simple ("video/x-ffv",
12452 "ffvversion", G_TYPE_INT, 1, NULL);
12455 case GST_MAKE_FOURCC ('3', 'I', 'V', '1'):
12456 case GST_MAKE_FOURCC ('3', 'I', 'V', '2'):
12457 case GST_MAKE_FOURCC ('X', 'V', 'I', 'D'):
12458 case GST_MAKE_FOURCC ('x', 'v', 'i', 'd'):
12460 case GST_MAKE_FOURCC ('U', 'M', 'P', '4'):
12461 caps = gst_caps_new_simple ("video/mpeg",
12462 "mpegversion", G_TYPE_INT, 4, NULL);
12466 case GST_MAKE_FOURCC ('c', 'v', 'i', 'd'):
12467 _codec ("Cinepak");
12468 caps = gst_caps_new_empty_simple ("video/x-cinepak");
12470 case GST_MAKE_FOURCC ('q', 'd', 'r', 'w'):
12471 _codec ("Apple QuickDraw");
12472 caps = gst_caps_new_empty_simple ("video/x-qdrw");
12474 case GST_MAKE_FOURCC ('r', 'p', 'z', 'a'):
12475 _codec ("Apple video");
12476 caps = gst_caps_new_empty_simple ("video/x-apple-video");
12480 _codec ("H.264 / AVC");
12481 caps = gst_caps_new_simple ("video/x-h264",
12482 "stream-format", G_TYPE_STRING, "avc",
12483 "alignment", G_TYPE_STRING, "au", NULL);
12486 _codec ("H.264 / AVC");
12487 caps = gst_caps_new_simple ("video/x-h264",
12488 "stream-format", G_TYPE_STRING, "avc3",
12489 "alignment", G_TYPE_STRING, "au", NULL);
12493 _codec ("H.265 / HEVC");
12494 caps = gst_caps_new_simple ("video/x-h265",
12495 "stream-format", G_TYPE_STRING, "hvc1",
12496 "alignment", G_TYPE_STRING, "au", NULL);
12499 _codec ("H.265 / HEVC");
12500 caps = gst_caps_new_simple ("video/x-h265",
12501 "stream-format", G_TYPE_STRING, "hev1",
12502 "alignment", G_TYPE_STRING, "au", NULL);
12505 _codec ("Run-length encoding");
12506 caps = gst_caps_new_simple ("video/x-rle",
12507 "layout", G_TYPE_STRING, "quicktime", NULL);
12510 _codec ("Run-length encoding");
12511 caps = gst_caps_new_simple ("video/x-rle",
12512 "layout", G_TYPE_STRING, "microsoft", NULL);
12514 case GST_MAKE_FOURCC ('I', 'V', '3', '2'):
12515 case GST_MAKE_FOURCC ('i', 'v', '3', '2'):
12516 _codec ("Indeo Video 3");
12517 caps = gst_caps_new_simple ("video/x-indeo",
12518 "indeoversion", G_TYPE_INT, 3, NULL);
12520 case GST_MAKE_FOURCC ('I', 'V', '4', '1'):
12521 case GST_MAKE_FOURCC ('i', 'v', '4', '1'):
12522 _codec ("Intel Video 4");
12523 caps = gst_caps_new_simple ("video/x-indeo",
12524 "indeoversion", G_TYPE_INT, 4, NULL);
12528 case GST_MAKE_FOURCC ('d', 'v', 's', 'd'):
12529 case GST_MAKE_FOURCC ('D', 'V', 'S', 'D'):
12530 case GST_MAKE_FOURCC ('d', 'v', 'c', 's'):
12531 case GST_MAKE_FOURCC ('D', 'V', 'C', 'S'):
12532 case GST_MAKE_FOURCC ('d', 'v', '2', '5'):
12533 case GST_MAKE_FOURCC ('d', 'v', 'p', 'p'):
12534 _codec ("DV Video");
12535 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 25,
12536 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
12538 case FOURCC_dv5n: /* DVCPRO50 NTSC */
12539 case FOURCC_dv5p: /* DVCPRO50 PAL */
12540 _codec ("DVCPro50 Video");
12541 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 50,
12542 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
12544 case GST_MAKE_FOURCC ('d', 'v', 'h', '5'): /* DVCPRO HD 50i produced by FCP */
12545 case GST_MAKE_FOURCC ('d', 'v', 'h', '6'): /* DVCPRO HD 60i produced by FCP */
12546 _codec ("DVCProHD Video");
12547 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 100,
12548 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
12550 case GST_MAKE_FOURCC ('s', 'm', 'c', ' '):
12551 _codec ("Apple Graphics (SMC)");
12552 caps = gst_caps_new_empty_simple ("video/x-smc");
12554 case GST_MAKE_FOURCC ('V', 'P', '3', '1'):
12556 caps = gst_caps_new_empty_simple ("video/x-vp3");
12558 case GST_MAKE_FOURCC ('V', 'P', '6', 'F'):
12559 _codec ("VP6 Flash");
12560 caps = gst_caps_new_empty_simple ("video/x-vp6-flash");
12564 caps = gst_caps_new_empty_simple ("video/x-theora");
12565 /* theora uses one byte of padding in the data stream because it does not
12566 * allow 0 sized packets while theora does */
12567 stream->padding = 1;
12571 caps = gst_caps_new_empty_simple ("video/x-dirac");
12573 case GST_MAKE_FOURCC ('t', 'i', 'f', 'f'):
12574 _codec ("TIFF still images");
12575 caps = gst_caps_new_empty_simple ("image/tiff");
12577 case GST_MAKE_FOURCC ('i', 'c', 'o', 'd'):
12578 _codec ("Apple Intermediate Codec");
12579 caps = gst_caps_from_string ("video/x-apple-intermediate-codec");
12581 case GST_MAKE_FOURCC ('A', 'V', 'd', 'n'):
12582 _codec ("AVID DNxHD");
12583 caps = gst_caps_from_string ("video/x-dnxhd");
12586 _codec ("On2 VP8");
12587 caps = gst_caps_from_string ("video/x-vp8");
12590 _codec ("Apple ProRes LT");
12592 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "lt",
12596 _codec ("Apple ProRes HQ");
12598 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "hq",
12602 _codec ("Apple ProRes");
12604 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
12608 _codec ("Apple ProRes Proxy");
12610 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
12614 _codec ("Apple ProRes 4444");
12616 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
12622 caps = gst_caps_new_simple ("video/x-wmv",
12623 "wmvversion", G_TYPE_INT, 3, "format", G_TYPE_STRING, "WVC1", NULL);
12625 case GST_MAKE_FOURCC ('k', 'p', 'c', 'd'):
12628 char *s, fourstr[5];
12630 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
12631 s = g_strdup_printf ("video/x-gst-fourcc-%s", g_strstrip (fourstr));
12632 caps = gst_caps_new_empty_simple (s);
12638 if (format != GST_VIDEO_FORMAT_UNKNOWN) {
12641 gst_video_info_init (&info);
12642 gst_video_info_set_format (&info, format, stream->width, stream->height);
12644 caps = gst_video_info_to_caps (&info);
12645 *codec_name = gst_pb_utils_get_codec_description (caps);
12647 /* enable clipping for raw video streams */
12648 stream->need_clip = TRUE;
12655 qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
12656 guint32 fourcc, const guint8 * data, int len, gchar ** codec_name)
12659 const GstStructure *s;
12662 GstAudioFormat format = 0;
12665 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
12667 depth = stream->bytes_per_packet * 8;
12670 case GST_MAKE_FOURCC ('N', 'O', 'N', 'E'):
12672 /* 8-bit audio is unsigned */
12674 format = GST_AUDIO_FORMAT_U8;
12675 /* otherwise it's signed and big-endian just like 'twos' */
12677 endian = G_BIG_ENDIAN;
12684 endian = G_LITTLE_ENDIAN;
12687 format = gst_audio_format_build_integer (TRUE, endian, depth, depth);
12689 str = g_strdup_printf ("Raw %d-bit PCM audio", depth);
12693 caps = gst_caps_new_simple ("audio/x-raw",
12694 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
12695 "layout", G_TYPE_STRING, "interleaved", NULL);
12698 case GST_MAKE_FOURCC ('f', 'l', '6', '4'):
12699 _codec ("Raw 64-bit floating-point audio");
12700 caps = gst_caps_new_simple ("audio/x-raw",
12701 "format", G_TYPE_STRING, "F64BE",
12702 "layout", G_TYPE_STRING, "interleaved", NULL);
12704 case GST_MAKE_FOURCC ('f', 'l', '3', '2'):
12705 _codec ("Raw 32-bit floating-point audio");
12706 caps = gst_caps_new_simple ("audio/x-raw",
12707 "format", G_TYPE_STRING, "F32BE",
12708 "layout", G_TYPE_STRING, "interleaved", NULL);
12711 _codec ("Raw 24-bit PCM audio");
12712 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
12714 caps = gst_caps_new_simple ("audio/x-raw",
12715 "format", G_TYPE_STRING, "S24BE",
12716 "layout", G_TYPE_STRING, "interleaved", NULL);
12718 case GST_MAKE_FOURCC ('i', 'n', '3', '2'):
12719 _codec ("Raw 32-bit PCM audio");
12720 caps = gst_caps_new_simple ("audio/x-raw",
12721 "format", G_TYPE_STRING, "S32BE",
12722 "layout", G_TYPE_STRING, "interleaved", NULL);
12725 _codec ("Mu-law audio");
12726 caps = gst_caps_new_empty_simple ("audio/x-mulaw");
12729 _codec ("A-law audio");
12730 caps = gst_caps_new_empty_simple ("audio/x-alaw");
12734 _codec ("Microsoft ADPCM");
12735 /* Microsoft ADPCM-ACM code 2 */
12736 caps = gst_caps_new_simple ("audio/x-adpcm",
12737 "layout", G_TYPE_STRING, "microsoft", NULL);
12741 _codec ("DVI/IMA ADPCM");
12742 caps = gst_caps_new_simple ("audio/x-adpcm",
12743 "layout", G_TYPE_STRING, "dvi", NULL);
12747 _codec ("DVI/Intel IMA ADPCM");
12748 /* FIXME DVI/Intel IMA ADPCM/ACM code 17 */
12749 caps = gst_caps_new_simple ("audio/x-adpcm",
12750 "layout", G_TYPE_STRING, "quicktime", NULL);
12754 /* MPEG layer 3, CBR only (pre QT4.1) */
12756 _codec ("MPEG-1 layer 3");
12757 /* MPEG layer 3, CBR & VBR (QT4.1 and later) */
12758 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 3,
12759 "mpegversion", G_TYPE_INT, 1, NULL);
12762 case GST_MAKE_FOURCC ('e', 'c', '-', '3'):
12763 _codec ("EAC-3 audio");
12764 caps = gst_caps_new_simple ("audio/x-eac3",
12765 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
12766 stream->sampled = TRUE;
12768 case GST_MAKE_FOURCC ('s', 'a', 'c', '3'): // Nero Recode
12770 _codec ("AC-3 audio");
12771 caps = gst_caps_new_simple ("audio/x-ac3",
12772 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
12773 stream->sampled = TRUE;
12775 case GST_MAKE_FOURCC ('d', 't', 's', 'c'):
12776 case GST_MAKE_FOURCC ('D', 'T', 'S', ' '):
12777 _codec ("DTS audio");
12778 caps = gst_caps_new_simple ("audio/x-dts",
12779 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
12780 stream->sampled = TRUE;
12782 case GST_MAKE_FOURCC ('d', 't', 's', 'h'): // DTS-HD
12783 case GST_MAKE_FOURCC ('d', 't', 's', 'l'): // DTS-HD Lossless
12784 _codec ("DTS-HD audio");
12785 caps = gst_caps_new_simple ("audio/x-dts",
12786 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
12787 stream->sampled = TRUE;
12791 caps = gst_caps_new_simple ("audio/x-mace",
12792 "maceversion", G_TYPE_INT, 3, NULL);
12796 caps = gst_caps_new_simple ("audio/x-mace",
12797 "maceversion", G_TYPE_INT, 6, NULL);
12799 case GST_MAKE_FOURCC ('O', 'g', 'g', 'V'):
12801 caps = gst_caps_new_empty_simple ("application/ogg");
12803 case GST_MAKE_FOURCC ('d', 'v', 'c', 'a'):
12804 _codec ("DV audio");
12805 caps = gst_caps_new_empty_simple ("audio/x-dv");
12808 _codec ("MPEG-4 AAC audio");
12809 caps = gst_caps_new_simple ("audio/mpeg",
12810 "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE,
12811 "stream-format", G_TYPE_STRING, "raw", NULL);
12813 case GST_MAKE_FOURCC ('Q', 'D', 'M', 'C'):
12814 _codec ("QDesign Music");
12815 caps = gst_caps_new_empty_simple ("audio/x-qdm");
12818 _codec ("QDesign Music v.2");
12819 /* FIXME: QDesign music version 2 (no constant) */
12820 if (FALSE && data) {
12821 caps = gst_caps_new_simple ("audio/x-qdm2",
12822 "framesize", G_TYPE_INT, QT_UINT32 (data + 52),
12823 "bitrate", G_TYPE_INT, QT_UINT32 (data + 40),
12824 "blocksize", G_TYPE_INT, QT_UINT32 (data + 44), NULL);
12826 caps = gst_caps_new_empty_simple ("audio/x-qdm2");
12830 _codec ("GSM audio");
12831 caps = gst_caps_new_empty_simple ("audio/x-gsm");
12834 _codec ("AMR audio");
12835 caps = gst_caps_new_empty_simple ("audio/AMR");
12838 _codec ("AMR-WB audio");
12839 caps = gst_caps_new_empty_simple ("audio/AMR-WB");
12842 _codec ("Quicktime IMA ADPCM");
12843 caps = gst_caps_new_simple ("audio/x-adpcm",
12844 "layout", G_TYPE_STRING, "quicktime", NULL);
12847 _codec ("Apple lossless audio");
12848 caps = gst_caps_new_empty_simple ("audio/x-alac");
12850 case GST_MAKE_FOURCC ('Q', 'c', 'l', 'p'):
12851 _codec ("QualComm PureVoice");
12852 caps = gst_caps_from_string ("audio/qcelp");
12857 caps = gst_caps_new_empty_simple ("audio/x-wma");
12861 caps = gst_caps_new_empty_simple ("audio/x-opus");
12863 case GST_MAKE_FOURCC ('l', 'p', 'c', 'm'):
12868 GstAudioFormat format;
12871 FLAG_IS_FLOAT = 0x1,
12872 FLAG_IS_BIG_ENDIAN = 0x2,
12873 FLAG_IS_SIGNED = 0x4,
12874 FLAG_IS_PACKED = 0x8,
12875 FLAG_IS_ALIGNED_HIGH = 0x10,
12876 FLAG_IS_NON_INTERLEAVED = 0x20
12878 _codec ("Raw LPCM audio");
12880 if (data && len >= 56) {
12881 depth = QT_UINT32 (data + 40);
12882 flags = QT_UINT32 (data + 44);
12883 width = QT_UINT32 (data + 48) * 8 / stream->n_channels;
12885 if ((flags & FLAG_IS_FLOAT) == 0) {
12890 format = gst_audio_format_build_integer ((flags & FLAG_IS_SIGNED) ?
12891 TRUE : FALSE, (flags & FLAG_IS_BIG_ENDIAN) ?
12892 G_BIG_ENDIAN : G_LITTLE_ENDIAN, width, depth);
12893 caps = gst_caps_new_simple ("audio/x-raw",
12894 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
12895 "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
12896 "non-interleaved" : "interleaved", NULL);
12901 if (flags & FLAG_IS_BIG_ENDIAN)
12902 format = GST_AUDIO_FORMAT_F64BE;
12904 format = GST_AUDIO_FORMAT_F64LE;
12906 if (flags & FLAG_IS_BIG_ENDIAN)
12907 format = GST_AUDIO_FORMAT_F32BE;
12909 format = GST_AUDIO_FORMAT_F32LE;
12911 caps = gst_caps_new_simple ("audio/x-raw",
12912 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
12913 "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
12914 "non-interleaved" : "interleaved", NULL);
12918 case GST_MAKE_FOURCC ('q', 't', 'v', 'r'):
12922 char *s, fourstr[5];
12924 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
12925 s = g_strdup_printf ("audio/x-gst-fourcc-%s", g_strstrip (fourstr));
12926 caps = gst_caps_new_empty_simple (s);
12933 GstCaps *templ_caps =
12934 gst_static_pad_template_get_caps (&gst_qtdemux_audiosrc_template);
12935 GstCaps *intersection = gst_caps_intersect (caps, templ_caps);
12936 gst_caps_unref (caps);
12937 gst_caps_unref (templ_caps);
12938 caps = intersection;
12941 /* enable clipping for raw audio streams */
12942 s = gst_caps_get_structure (caps, 0);
12943 name = gst_structure_get_name (s);
12944 if (g_str_has_prefix (name, "audio/x-raw")) {
12945 stream->need_clip = TRUE;
12946 stream->max_buffer_size = 4096 * stream->bytes_per_frame;
12947 GST_DEBUG ("setting max buffer size to %d", stream->max_buffer_size);
12953 qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
12954 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
12958 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
12962 _codec ("DVD subtitle");
12963 caps = gst_caps_new_empty_simple ("subpicture/x-dvd");
12964 stream->need_process = TRUE;
12967 _codec ("Quicktime timed text");
12970 _codec ("3GPP timed text");
12972 caps = gst_caps_new_simple ("text/x-raw", "format", G_TYPE_STRING,
12974 /* actual text piece needs to be extracted */
12975 stream->need_process = TRUE;
12978 _codec ("XML subtitles");
12979 caps = gst_caps_new_empty_simple ("application/ttml+xml");
12983 char *s, fourstr[5];
12985 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
12986 s = g_strdup_printf ("text/x-gst-fourcc-%s", g_strstrip (fourstr));
12987 caps = gst_caps_new_empty_simple (s);
12996 qtdemux_generic_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
12997 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
13003 _codec ("MPEG 1 video");
13004 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
13005 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13015 gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux,
13016 const gchar * system_id)
13020 if (!qtdemux->protection_system_ids)
13021 qtdemux->protection_system_ids =
13022 g_ptr_array_new_with_free_func ((GDestroyNotify) g_free);
13023 /* Check whether we already have an entry for this system ID. */
13024 for (i = 0; i < qtdemux->protection_system_ids->len; ++i) {
13025 const gchar *id = g_ptr_array_index (qtdemux->protection_system_ids, i);
13026 if (g_ascii_strcasecmp (system_id, id) == 0) {
13030 GST_DEBUG_OBJECT (qtdemux, "Adding cenc protection system ID %s", system_id);
13031 g_ptr_array_add (qtdemux->protection_system_ids, g_ascii_strdown (system_id,