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 */
318 /* quicktime segments */
320 QtDemuxSegment *segments;
321 gboolean dummy_segment;
326 GstTagList *pending_tags;
327 gboolean send_global_tags;
329 GstEvent *pending_event;
339 gboolean chunks_are_samples; /* TRUE means treat chunks as samples */
343 GstByteReader co_chunk;
345 guint32 current_chunk;
347 guint32 samples_per_chunk;
348 guint32 stco_sample_index;
350 guint32 sample_size; /* 0 means variable sizes are stored in stsz */
353 guint32 n_samples_per_chunk;
354 guint32 stsc_chunk_index;
355 guint32 stsc_sample_index;
356 guint64 chunk_offset;
359 guint32 stts_samples;
360 guint32 n_sample_times;
361 guint32 stts_sample_index;
363 guint32 stts_duration;
365 gboolean stss_present;
366 guint32 n_sample_syncs;
369 gboolean stps_present;
370 guint32 n_sample_partial_syncs;
372 QtDemuxRandomAccessEntry *ra_entries;
375 const QtDemuxRandomAccessEntry *pending_seek;
378 gboolean ctts_present;
379 guint32 n_composition_times;
381 guint32 ctts_sample_index;
389 gboolean parsed_trex;
390 guint32 def_sample_duration;
391 guint32 def_sample_size;
392 guint32 def_sample_flags;
396 /* stereoscopic video streams */
397 GstVideoMultiviewMode multiview_mode;
398 GstVideoMultiviewFlags multiview_flags;
400 /* protected streams */
402 guint32 protection_scheme_type;
403 guint32 protection_scheme_version;
404 gpointer protection_scheme_info; /* specific to the protection scheme */
405 GQueue protection_scheme_event_queue;
408 /* Contains properties and cryptographic info for a set of samples from a
409 * track protected using Common Encryption (cenc) */
410 struct _QtDemuxCencSampleSetInfo
412 GstStructure *default_properties;
414 /* @crypto_info holds one GstStructure per sample */
415 GPtrArray *crypto_info;
420 QTDEMUX_STATE_INITIAL, /* Initial state (haven't got the header yet) */
421 QTDEMUX_STATE_HEADER, /* Parsing the header */
422 QTDEMUX_STATE_MOVIE, /* Parsing/Playing the media data */
423 QTDEMUX_STATE_BUFFER_MDAT /* Buffering the mdat atom */
426 static GNode *qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc);
427 static GNode *qtdemux_tree_get_child_by_type_full (GNode * node,
428 guint32 fourcc, GstByteReader * parser);
429 static GNode *qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc);
430 static GNode *qtdemux_tree_get_sibling_by_type_full (GNode * node,
431 guint32 fourcc, GstByteReader * parser);
433 static GstFlowReturn qtdemux_add_fragmented_samples (GstQTDemux * qtdemux);
435 static GstStaticPadTemplate gst_qtdemux_sink_template =
436 GST_STATIC_PAD_TEMPLATE ("sink",
439 GST_STATIC_CAPS ("video/quicktime; video/mj2; audio/x-m4a; "
443 static GstStaticPadTemplate gst_qtdemux_videosrc_template =
444 GST_STATIC_PAD_TEMPLATE ("video_%u",
447 GST_STATIC_CAPS_ANY);
449 static GstStaticPadTemplate gst_qtdemux_audiosrc_template =
450 GST_STATIC_PAD_TEMPLATE ("audio_%u",
453 GST_STATIC_CAPS_ANY);
455 static GstStaticPadTemplate gst_qtdemux_subsrc_template =
456 GST_STATIC_PAD_TEMPLATE ("subtitle_%u",
459 GST_STATIC_CAPS_ANY);
461 #define gst_qtdemux_parent_class parent_class
462 G_DEFINE_TYPE (GstQTDemux, gst_qtdemux, GST_TYPE_ELEMENT);
464 static void gst_qtdemux_dispose (GObject * object);
467 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
468 GstClockTime media_time);
470 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
471 QtDemuxStream * str, gint64 media_offset);
474 static void gst_qtdemux_set_index (GstElement * element, GstIndex * index);
475 static GstIndex *gst_qtdemux_get_index (GstElement * element);
477 static GstStateChangeReturn gst_qtdemux_change_state (GstElement * element,
478 GstStateChange transition);
479 static gboolean qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent);
480 static gboolean qtdemux_sink_activate_mode (GstPad * sinkpad,
481 GstObject * parent, GstPadMode mode, gboolean active);
483 static void gst_qtdemux_loop (GstPad * pad);
484 static GstFlowReturn gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent,
486 static gboolean gst_qtdemux_handle_sink_event (GstPad * pad, GstObject * parent,
488 static gboolean gst_qtdemux_setcaps (GstQTDemux * qtdemux, GstCaps * caps);
489 static gboolean gst_qtdemux_configure_stream (GstQTDemux * qtdemux,
490 QtDemuxStream * stream);
491 static GstFlowReturn gst_qtdemux_process_adapter (GstQTDemux * demux,
494 static gboolean qtdemux_parse_moov (GstQTDemux * qtdemux,
495 const guint8 * buffer, guint length);
496 static gboolean qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node,
497 const guint8 * buffer, guint length);
498 static gboolean qtdemux_parse_tree (GstQTDemux * qtdemux);
499 static void qtdemux_parse_udta (GstQTDemux * qtdemux, GstTagList * taglist,
502 static void gst_qtdemux_handle_esds (GstQTDemux * qtdemux,
503 QtDemuxStream * stream, GNode * esds, GstTagList * list);
504 static GstCaps *qtdemux_video_caps (GstQTDemux * qtdemux,
505 QtDemuxStream * stream, guint32 fourcc, const guint8 * stsd_data,
506 gchar ** codec_name);
507 static GstCaps *qtdemux_audio_caps (GstQTDemux * qtdemux,
508 QtDemuxStream * stream, guint32 fourcc, const guint8 * data, int len,
509 gchar ** codec_name);
510 static GstCaps *qtdemux_sub_caps (GstQTDemux * qtdemux,
511 QtDemuxStream * stream, guint32 fourcc, const guint8 * data,
512 gchar ** codec_name);
513 static GstCaps *qtdemux_generic_caps (GstQTDemux * qtdemux,
514 QtDemuxStream * stream, guint32 fourcc, const guint8 * stsd_data,
515 gchar ** codec_name);
517 static gboolean qtdemux_parse_samples (GstQTDemux * qtdemux,
518 QtDemuxStream * stream, guint32 n);
519 static GstFlowReturn qtdemux_expose_streams (GstQTDemux * qtdemux);
520 static void gst_qtdemux_stream_free (GstQTDemux * qtdemux,
521 QtDemuxStream * stream);
522 static void gst_qtdemux_stream_clear (GstQTDemux * qtdemux,
523 QtDemuxStream * stream);
524 static void gst_qtdemux_remove_stream (GstQTDemux * qtdemux, int index);
525 static GstFlowReturn qtdemux_prepare_streams (GstQTDemux * qtdemux);
526 static void qtdemux_do_allocation (GstQTDemux * qtdemux,
527 QtDemuxStream * stream);
528 static gboolean gst_qtdemux_activate_segment (GstQTDemux * qtdemux,
529 QtDemuxStream * stream, guint32 seg_idx, GstClockTime offset);
530 static gboolean gst_qtdemux_stream_update_segment (GstQTDemux * qtdemux,
531 QtDemuxStream * stream, gint seg_idx, GstClockTime offset,
532 GstClockTime * _start, GstClockTime * _stop);
534 static gboolean qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux);
535 static void check_update_duration (GstQTDemux * qtdemux, GstClockTime duration);
537 static gchar *qtdemux_uuid_bytes_to_string (gconstpointer uuid_bytes);
539 static GstStructure *qtdemux_get_cenc_sample_properties (GstQTDemux * qtdemux,
540 QtDemuxStream * stream, guint sample_index);
541 static void gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux,
543 static void qtdemux_gst_structure_free (GstStructure * gststructure);
546 gst_qtdemux_class_init (GstQTDemuxClass * klass)
548 GObjectClass *gobject_class;
549 GstElementClass *gstelement_class;
551 gobject_class = (GObjectClass *) klass;
552 gstelement_class = (GstElementClass *) klass;
554 parent_class = g_type_class_peek_parent (klass);
556 gobject_class->dispose = gst_qtdemux_dispose;
558 gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_qtdemux_change_state);
560 gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_qtdemux_set_index);
561 gstelement_class->get_index = GST_DEBUG_FUNCPTR (gst_qtdemux_get_index);
564 gst_tag_register_musicbrainz_tags ();
566 gst_element_class_add_static_pad_template (gstelement_class,
567 &gst_qtdemux_sink_template);
568 gst_element_class_add_static_pad_template (gstelement_class,
569 &gst_qtdemux_videosrc_template);
570 gst_element_class_add_static_pad_template (gstelement_class,
571 &gst_qtdemux_audiosrc_template);
572 gst_element_class_add_static_pad_template (gstelement_class,
573 &gst_qtdemux_subsrc_template);
574 gst_element_class_set_static_metadata (gstelement_class, "QuickTime demuxer",
576 "Demultiplex a QuickTime file into audio and video streams",
577 "David Schleef <ds@schleef.org>, Wim Taymans <wim@fluendo.com>");
579 GST_DEBUG_CATEGORY_INIT (qtdemux_debug, "qtdemux", 0, "qtdemux plugin");
584 gst_qtdemux_init (GstQTDemux * qtdemux)
587 gst_pad_new_from_static_template (&gst_qtdemux_sink_template, "sink");
588 gst_pad_set_activate_function (qtdemux->sinkpad, qtdemux_sink_activate);
589 gst_pad_set_activatemode_function (qtdemux->sinkpad,
590 qtdemux_sink_activate_mode);
591 gst_pad_set_chain_function (qtdemux->sinkpad, gst_qtdemux_chain);
592 gst_pad_set_event_function (qtdemux->sinkpad, gst_qtdemux_handle_sink_event);
593 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), qtdemux->sinkpad);
595 qtdemux->state = QTDEMUX_STATE_INITIAL;
596 qtdemux->pullbased = FALSE;
597 qtdemux->posted_redirect = FALSE;
598 qtdemux->neededbytes = 16;
600 qtdemux->adapter = gst_adapter_new ();
602 qtdemux->first_mdat = -1;
603 qtdemux->got_moov = FALSE;
604 qtdemux->mdatoffset = -1;
605 qtdemux->mdatbuffer = NULL;
606 qtdemux->restoredata_buffer = NULL;
607 qtdemux->restoredata_offset = -1;
608 qtdemux->fragment_start = -1;
609 qtdemux->fragment_start_offset = -1;
610 qtdemux->media_caps = NULL;
611 qtdemux->exposed = FALSE;
612 qtdemux->mss_mode = FALSE;
613 qtdemux->pending_newsegment = NULL;
614 qtdemux->upstream_format_is_time = FALSE;
615 qtdemux->have_group_id = FALSE;
616 qtdemux->group_id = G_MAXUINT;
617 qtdemux->cenc_aux_info_offset = 0;
618 qtdemux->cenc_aux_info_sizes = NULL;
619 qtdemux->cenc_aux_sample_count = 0;
620 qtdemux->protection_system_ids = NULL;
621 g_queue_init (&qtdemux->protection_event_queue);
622 gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
623 qtdemux->flowcombiner = gst_flow_combiner_new ();
625 GST_OBJECT_FLAG_SET (qtdemux, GST_ELEMENT_FLAG_INDEXABLE);
629 gst_qtdemux_dispose (GObject * object)
631 GstQTDemux *qtdemux = GST_QTDEMUX (object);
633 if (qtdemux->adapter) {
634 g_object_unref (G_OBJECT (qtdemux->adapter));
635 qtdemux->adapter = NULL;
637 gst_flow_combiner_free (qtdemux->flowcombiner);
638 g_queue_foreach (&qtdemux->protection_event_queue, (GFunc) gst_event_unref,
640 g_queue_clear (&qtdemux->protection_event_queue);
642 g_free (qtdemux->cenc_aux_info_sizes);
643 qtdemux->cenc_aux_info_sizes = NULL;
645 G_OBJECT_CLASS (parent_class)->dispose (object);
649 gst_qtdemux_post_no_playable_stream_error (GstQTDemux * qtdemux)
651 if (qtdemux->posted_redirect) {
652 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
653 (_("This file contains no playable streams.")),
654 ("no known streams found, a redirect message has been posted"));
656 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
657 (_("This file contains no playable streams.")),
658 ("no known streams found"));
663 _gst_buffer_new_wrapped (gpointer mem, gsize size, GFreeFunc free_func)
665 return gst_buffer_new_wrapped_full (free_func ? 0 : GST_MEMORY_FLAG_READONLY,
666 mem, size, 0, size, mem, free_func);
670 gst_qtdemux_pull_atom (GstQTDemux * qtdemux, guint64 offset, guint64 size,
677 if (G_UNLIKELY (size == 0)) {
679 GstBuffer *tmp = NULL;
681 ret = gst_qtdemux_pull_atom (qtdemux, offset, sizeof (guint32), &tmp);
682 if (ret != GST_FLOW_OK)
685 gst_buffer_map (tmp, &map, GST_MAP_READ);
686 size = QT_UINT32 (map.data);
687 GST_DEBUG_OBJECT (qtdemux, "size 0x%08" G_GINT64_MODIFIER "x", size);
689 gst_buffer_unmap (tmp, &map);
690 gst_buffer_unref (tmp);
693 /* Sanity check: catch bogus sizes (fuzzed/broken files) */
694 if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
695 if (qtdemux->state != QTDEMUX_STATE_MOVIE && qtdemux->got_moov) {
696 /* we're pulling header but already got most interesting bits,
697 * so never mind the rest (e.g. tags) (that much) */
698 GST_WARNING_OBJECT (qtdemux, "atom has bogus size %" G_GUINT64_FORMAT,
702 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
703 (_("This file is invalid and cannot be played.")),
704 ("atom has bogus size %" G_GUINT64_FORMAT, size));
705 return GST_FLOW_ERROR;
709 flow = gst_pad_pull_range (qtdemux->sinkpad, offset, size, buf);
711 if (G_UNLIKELY (flow != GST_FLOW_OK))
714 bsize = gst_buffer_get_size (*buf);
715 /* Catch short reads - we don't want any partial atoms */
716 if (G_UNLIKELY (bsize < size)) {
717 GST_WARNING_OBJECT (qtdemux,
718 "short read: %" G_GSIZE_FORMAT " < %" G_GUINT64_FORMAT, bsize, size);
719 gst_buffer_unref (*buf);
729 gst_qtdemux_src_convert (GstQTDemux * qtdemux, GstPad * pad,
730 GstFormat src_format, gint64 src_value, GstFormat dest_format,
734 QtDemuxStream *stream = gst_pad_get_element_private (pad);
737 if (stream->subtype != FOURCC_vide) {
742 switch (src_format) {
743 case GST_FORMAT_TIME:
744 switch (dest_format) {
745 case GST_FORMAT_BYTES:{
746 index = gst_qtdemux_find_index_linear (qtdemux, stream, src_value);
752 *dest_value = stream->samples[index].offset;
754 GST_DEBUG_OBJECT (qtdemux, "Format Conversion Time->Offset :%"
755 GST_TIME_FORMAT "->%" G_GUINT64_FORMAT,
756 GST_TIME_ARGS (src_value), *dest_value);
764 case GST_FORMAT_BYTES:
765 switch (dest_format) {
766 case GST_FORMAT_TIME:{
768 gst_qtdemux_find_index_for_given_media_offset_linear (qtdemux,
777 QTSTREAMTIME_TO_GSTTIME (stream,
778 stream->samples[index].timestamp);
779 GST_DEBUG_OBJECT (qtdemux,
780 "Format Conversion Offset->Time :%" G_GUINT64_FORMAT "->%"
781 GST_TIME_FORMAT, src_value, GST_TIME_ARGS (*dest_value));
800 gst_qtdemux_get_duration (GstQTDemux * qtdemux, GstClockTime * duration)
802 gboolean res = FALSE;
804 *duration = GST_CLOCK_TIME_NONE;
806 if (qtdemux->duration != 0 &&
807 qtdemux->duration != G_MAXINT64 && qtdemux->timescale != 0) {
808 *duration = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
811 *duration = GST_CLOCK_TIME_NONE;
818 gst_qtdemux_handle_src_query (GstPad * pad, GstObject * parent,
821 gboolean res = FALSE;
822 GstQTDemux *qtdemux = GST_QTDEMUX (parent);
824 GST_LOG_OBJECT (pad, "%s query", GST_QUERY_TYPE_NAME (query));
826 switch (GST_QUERY_TYPE (query)) {
827 case GST_QUERY_POSITION:{
830 gst_query_parse_position (query, &fmt, NULL);
831 if (fmt == GST_FORMAT_TIME
832 && GST_CLOCK_TIME_IS_VALID (qtdemux->segment.position)) {
833 gst_query_set_position (query, GST_FORMAT_TIME,
834 qtdemux->segment.position);
839 case GST_QUERY_DURATION:{
842 gst_query_parse_duration (query, &fmt, NULL);
843 if (fmt == GST_FORMAT_TIME) {
844 /* First try to query upstream */
845 res = gst_pad_query_default (pad, parent, query);
847 GstClockTime duration;
848 if (gst_qtdemux_get_duration (qtdemux, &duration) && duration > 0) {
849 gst_query_set_duration (query, GST_FORMAT_TIME, duration);
856 case GST_QUERY_CONVERT:{
857 GstFormat src_fmt, dest_fmt;
858 gint64 src_value, dest_value = 0;
860 gst_query_parse_convert (query, &src_fmt, &src_value, &dest_fmt, NULL);
862 res = gst_qtdemux_src_convert (qtdemux, pad,
863 src_fmt, src_value, dest_fmt, &dest_value);
865 gst_query_set_convert (query, src_fmt, src_value, dest_fmt, dest_value);
870 case GST_QUERY_FORMATS:
871 gst_query_set_formats (query, 2, GST_FORMAT_TIME, GST_FORMAT_BYTES);
874 case GST_QUERY_SEEKING:{
878 /* try upstream first */
879 res = gst_pad_query_default (pad, parent, query);
882 gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
883 if (fmt == GST_FORMAT_TIME) {
884 GstClockTime duration;
886 gst_qtdemux_get_duration (qtdemux, &duration);
888 if (!qtdemux->pullbased) {
891 /* we might be able with help from upstream */
893 q = gst_query_new_seeking (GST_FORMAT_BYTES);
894 if (gst_pad_peer_query (qtdemux->sinkpad, q)) {
895 gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL);
896 GST_LOG_OBJECT (qtdemux, "upstream BYTE seekable %d", seekable);
900 gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0, duration);
906 case GST_QUERY_SEGMENT:
911 format = qtdemux->segment.format;
914 gst_segment_to_stream_time (&qtdemux->segment, format,
915 qtdemux->segment.start);
916 if ((stop = qtdemux->segment.stop) == -1)
917 stop = qtdemux->segment.duration;
919 stop = gst_segment_to_stream_time (&qtdemux->segment, format, stop);
921 gst_query_set_segment (query, qtdemux->segment.rate, format, start, stop);
926 res = gst_pad_query_default (pad, parent, query);
934 gst_qtdemux_push_tags (GstQTDemux * qtdemux, QtDemuxStream * stream)
936 if (G_LIKELY (stream->pad)) {
937 GST_DEBUG_OBJECT (qtdemux, "Checking pad %s:%s for tags",
938 GST_DEBUG_PAD_NAME (stream->pad));
940 if (G_UNLIKELY (stream->pending_tags)) {
941 GST_DEBUG_OBJECT (qtdemux, "Sending tags %" GST_PTR_FORMAT,
942 stream->pending_tags);
943 gst_pad_push_event (stream->pad,
944 gst_event_new_tag (stream->pending_tags));
945 stream->pending_tags = NULL;
948 if (G_UNLIKELY (stream->send_global_tags && qtdemux->tag_list)) {
949 GST_DEBUG_OBJECT (qtdemux, "Sending global tags %" GST_PTR_FORMAT,
951 gst_pad_push_event (stream->pad,
952 gst_event_new_tag (gst_tag_list_ref (qtdemux->tag_list)));
953 stream->send_global_tags = FALSE;
958 /* push event on all source pads; takes ownership of the event */
960 gst_qtdemux_push_event (GstQTDemux * qtdemux, GstEvent * event)
963 gboolean has_valid_stream = FALSE;
964 GstEventType etype = GST_EVENT_TYPE (event);
966 GST_DEBUG_OBJECT (qtdemux, "pushing %s event on all source pads",
967 GST_EVENT_TYPE_NAME (event));
969 for (n = 0; n < qtdemux->n_streams; n++) {
971 QtDemuxStream *stream = qtdemux->streams[n];
972 GST_DEBUG_OBJECT (qtdemux, "pushing on pad %i", n);
974 if ((pad = stream->pad)) {
975 has_valid_stream = TRUE;
977 if (etype == GST_EVENT_EOS) {
978 /* let's not send twice */
979 if (stream->sent_eos)
981 stream->sent_eos = TRUE;
984 gst_pad_push_event (pad, gst_event_ref (event));
988 gst_event_unref (event);
990 /* if it is EOS and there are no pads, post an error */
991 if (!has_valid_stream && etype == GST_EVENT_EOS) {
992 gst_qtdemux_post_no_playable_stream_error (qtdemux);
996 /* push a pending newsegment event, if any from the streaming thread */
998 gst_qtdemux_push_pending_newsegment (GstQTDemux * qtdemux)
1000 if (qtdemux->pending_newsegment) {
1001 gst_qtdemux_push_event (qtdemux, qtdemux->pending_newsegment);
1002 qtdemux->pending_newsegment = NULL;
1012 find_func (QtDemuxSample * s1, gint64 * media_time, gpointer user_data)
1014 if ((gint64) s1->timestamp + s1->pts_offset > *media_time)
1016 if ((gint64) s1->timestamp + s1->pts_offset == *media_time)
1022 /* find the index of the sample that includes the data for @media_time using a
1023 * binary search. Only to be called in optimized cases of linear search below.
1025 * Returns the index of the sample.
1028 gst_qtdemux_find_index (GstQTDemux * qtdemux, QtDemuxStream * str,
1031 QtDemuxSample *result;
1034 /* convert media_time to mov format */
1036 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
1038 result = gst_util_array_binary_search (str->samples, str->stbl_index + 1,
1039 sizeof (QtDemuxSample), (GCompareDataFunc) find_func,
1040 GST_SEARCH_MODE_BEFORE, &media_time, NULL);
1042 if (G_LIKELY (result))
1043 index = result - str->samples;
1052 /* find the index of the sample that includes the data for @media_offset using a
1055 * Returns the index of the sample.
1058 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
1059 QtDemuxStream * str, gint64 media_offset)
1061 QtDemuxSample *result = str->samples;
1064 if (result == NULL || str->n_samples == 0)
1067 if (media_offset == result->offset)
1071 while (index < str->n_samples - 1) {
1072 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
1075 if (media_offset < result->offset)
1086 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
1091 /* find the index of the sample that includes the data for @media_time using a
1092 * linear search, and keeping in mind that not all samples may have been parsed
1093 * yet. If possible, it will delegate to binary search.
1095 * Returns the index of the sample.
1098 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
1099 GstClockTime media_time)
1103 QtDemuxSample *sample;
1105 /* convert media_time to mov format */
1107 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
1109 sample = str->samples;
1110 if (mov_time == sample->timestamp + sample->pts_offset)
1113 /* use faster search if requested time in already parsed range */
1114 sample = str->samples + str->stbl_index;
1115 if (str->stbl_index >= 0 &&
1116 mov_time <= (sample->timestamp + sample->pts_offset))
1117 return gst_qtdemux_find_index (qtdemux, str, media_time);
1119 while (index < str->n_samples - 1) {
1120 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
1123 sample = str->samples + index + 1;
1124 if (mov_time < (sample->timestamp + sample->pts_offset))
1134 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
1139 /* find the index of the keyframe needed to decode the sample at @index
1142 * Returns the index of the keyframe.
1145 gst_qtdemux_find_keyframe (GstQTDemux * qtdemux, QtDemuxStream * str,
1148 guint32 new_index = index;
1150 if (index >= str->n_samples) {
1151 new_index = str->n_samples;
1155 /* all keyframes, return index */
1156 if (str->all_keyframe) {
1161 /* else go back until we have a keyframe */
1163 if (str->samples[new_index].keyframe)
1173 GST_DEBUG_OBJECT (qtdemux, "searching for keyframe index before index %u "
1174 "gave %u", index, new_index);
1179 /* find the segment for @time_position for @stream
1181 * Returns the index of the segment containing @time_position.
1182 * Returns the last segment and sets the @eos variable to TRUE
1183 * if the time is beyond the end. @eos may be NULL
1186 gst_qtdemux_find_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
1187 GstClockTime time_position)
1192 GST_LOG_OBJECT (stream->pad, "finding segment for %" GST_TIME_FORMAT,
1193 GST_TIME_ARGS (time_position));
1196 for (i = 0; i < stream->n_segments; i++) {
1197 QtDemuxSegment *segment = &stream->segments[i];
1199 GST_LOG_OBJECT (stream->pad,
1200 "looking at segment %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT,
1201 GST_TIME_ARGS (segment->time), GST_TIME_ARGS (segment->stop_time));
1203 /* For the last segment we include stop_time in the last segment */
1204 if (i < stream->n_segments - 1) {
1205 if (segment->time <= time_position && time_position < segment->stop_time) {
1206 GST_LOG_OBJECT (stream->pad, "segment %d matches", i);
1211 /* Last segment always matches */
1219 /* move the stream @str to the sample position @index.
1221 * Updates @str->sample_index and marks discontinuity if needed.
1224 gst_qtdemux_move_stream (GstQTDemux * qtdemux, QtDemuxStream * str,
1227 /* no change needed */
1228 if (index == str->sample_index)
1231 GST_DEBUG_OBJECT (qtdemux, "moving to sample %u of %u", index,
1234 /* position changed, we have a discont */
1235 str->sample_index = index;
1236 str->offset_in_sample = 0;
1237 /* Each time we move in the stream we store the position where we are
1239 str->from_sample = index;
1240 str->discont = TRUE;
1244 gst_qtdemux_adjust_seek (GstQTDemux * qtdemux, gint64 desired_time,
1245 gboolean use_sparse, gint64 * key_time, gint64 * key_offset)
1248 gint64 min_byte_offset = -1;
1251 min_offset = desired_time;
1253 /* for each stream, find the index of the sample in the segment
1254 * and move back to the previous keyframe. */
1255 for (n = 0; n < qtdemux->n_streams; n++) {
1257 guint32 index, kindex;
1259 GstClockTime media_start;
1260 GstClockTime media_time;
1261 GstClockTime seg_time;
1262 QtDemuxSegment *seg;
1263 gboolean empty_segment = FALSE;
1265 str = qtdemux->streams[n];
1267 if (str->sparse && !use_sparse)
1270 seg_idx = gst_qtdemux_find_segment (qtdemux, str, desired_time);
1271 GST_DEBUG_OBJECT (qtdemux, "align segment %d", seg_idx);
1273 /* get segment and time in the segment */
1274 seg = &str->segments[seg_idx];
1275 seg_time = (desired_time - seg->time) * seg->rate;
1277 while (QTSEGMENT_IS_EMPTY (seg)) {
1279 empty_segment = TRUE;
1280 GST_DEBUG_OBJECT (str->pad, "Segment %d is empty, moving to next one",
1283 if (seg_idx == str->n_segments)
1285 seg = &str->segments[seg_idx];
1288 if (seg_idx == str->n_segments) {
1289 /* FIXME track shouldn't have the last segment as empty, but if it
1290 * happens we better handle it */
1294 /* get the media time in the segment */
1295 media_start = seg->media_start + seg_time;
1297 /* get the index of the sample with media time */
1298 index = gst_qtdemux_find_index_linear (qtdemux, str, media_start);
1299 GST_DEBUG_OBJECT (qtdemux, "sample for %" GST_TIME_FORMAT " at %u"
1300 " at offset %" G_GUINT64_FORMAT " (empty segment: %d)",
1301 GST_TIME_ARGS (media_start), index, str->samples[index].offset,
1304 if (!empty_segment) {
1305 /* find previous keyframe */
1306 kindex = gst_qtdemux_find_keyframe (qtdemux, str, index);
1308 /* if the keyframe is at a different position, we need to update the
1309 * requested seek time */
1310 if (index != kindex) {
1313 /* get timestamp of keyframe */
1314 media_time = QTSAMPLE_DTS (str, &str->samples[kindex]);
1315 GST_DEBUG_OBJECT (qtdemux,
1316 "keyframe at %u with time %" GST_TIME_FORMAT " at offset %"
1317 G_GUINT64_FORMAT, kindex, GST_TIME_ARGS (media_time),
1318 str->samples[kindex].offset);
1320 /* keyframes in the segment get a chance to change the
1321 * desired_offset. keyframes out of the segment are
1323 if (media_time >= seg->media_start) {
1324 GstClockTime seg_time;
1326 /* this keyframe is inside the segment, convert back to
1328 seg_time = (media_time - seg->media_start) + seg->time;
1329 if (seg_time < min_offset)
1330 min_offset = seg_time;
1335 if (min_byte_offset < 0 || str->samples[index].offset < min_byte_offset)
1336 min_byte_offset = str->samples[index].offset;
1340 *key_time = min_offset;
1342 *key_offset = min_byte_offset;
1346 gst_qtdemux_convert_seek (GstPad * pad, GstFormat * format,
1347 GstSeekType cur_type, gint64 * cur, GstSeekType stop_type, gint64 * stop)
1351 g_return_val_if_fail (format != NULL, FALSE);
1352 g_return_val_if_fail (cur != NULL, FALSE);
1353 g_return_val_if_fail (stop != NULL, FALSE);
1355 if (*format == GST_FORMAT_TIME)
1359 if (cur_type != GST_SEEK_TYPE_NONE)
1360 res = gst_pad_query_convert (pad, *format, *cur, GST_FORMAT_TIME, cur);
1361 if (res && stop_type != GST_SEEK_TYPE_NONE)
1362 res = gst_pad_query_convert (pad, *format, *stop, GST_FORMAT_TIME, stop);
1365 *format = GST_FORMAT_TIME;
1370 /* perform seek in push based mode:
1371 find BYTE position to move to based on time and delegate to upstream
1374 gst_qtdemux_do_push_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1379 GstSeekType cur_type, stop_type;
1380 gint64 cur, stop, key_cur;
1383 gint64 original_stop;
1386 GST_DEBUG_OBJECT (qtdemux, "doing push-based seek");
1388 gst_event_parse_seek (event, &rate, &format, &flags,
1389 &cur_type, &cur, &stop_type, &stop);
1390 seqnum = gst_event_get_seqnum (event);
1392 /* only forward streaming and seeking is possible */
1394 goto unsupported_seek;
1396 /* convert to TIME if needed and possible */
1397 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1401 /* Upstream seek in bytes will have undefined stop, but qtdemux stores
1402 * the original stop position to use when upstream pushes the new segment
1404 original_stop = stop;
1407 /* find reasonable corresponding BYTE position,
1408 * also try to mind about keyframes, since we can not go back a bit for them
1410 gst_qtdemux_adjust_seek (qtdemux, cur, FALSE, &key_cur, &byte_cur);
1415 GST_DEBUG_OBJECT (qtdemux, "Pushing BYTE seek rate %g, "
1416 "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, byte_cur,
1419 GST_OBJECT_LOCK (qtdemux);
1420 qtdemux->seek_offset = byte_cur;
1421 if (!(flags & GST_SEEK_FLAG_KEY_UNIT)) {
1422 qtdemux->push_seek_start = cur;
1424 qtdemux->push_seek_start = key_cur;
1427 if (stop_type == GST_SEEK_TYPE_NONE) {
1428 qtdemux->push_seek_stop = qtdemux->segment.stop;
1430 qtdemux->push_seek_stop = original_stop;
1432 GST_OBJECT_UNLOCK (qtdemux);
1434 /* BYTE seek event */
1435 event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type, byte_cur,
1437 gst_event_set_seqnum (event, seqnum);
1438 res = gst_pad_push_event (qtdemux->sinkpad, event);
1445 GST_DEBUG_OBJECT (qtdemux, "could not determine byte position to seek to, "
1451 GST_DEBUG_OBJECT (qtdemux, "unsupported seek, seek aborted.");
1456 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1461 /* perform the seek.
1463 * We set all segment_indexes in the streams to unknown and
1464 * adjust the time_position to the desired position. this is enough
1465 * to trigger a segment switch in the streaming thread to start
1466 * streaming from the desired position.
1468 * Keyframe seeking is a little more complicated when dealing with
1469 * segments. Ideally we want to move to the previous keyframe in
1470 * the segment but there might not be a keyframe in the segment. In
1471 * fact, none of the segments could contain a keyframe. We take a
1472 * practical approach: seek to the previous keyframe in the segment,
1473 * if there is none, seek to the beginning of the segment.
1475 * Called with STREAM_LOCK
1478 gst_qtdemux_perform_seek (GstQTDemux * qtdemux, GstSegment * segment,
1479 guint32 seqnum, GstSeekFlags flags)
1481 gint64 desired_offset;
1484 desired_offset = segment->position;
1486 GST_DEBUG_OBJECT (qtdemux, "seeking to %" GST_TIME_FORMAT,
1487 GST_TIME_ARGS (desired_offset));
1489 /* may not have enough fragmented info to do this adjustment,
1490 * and we can't scan (and probably should not) at this time with
1491 * possibly flushing upstream */
1492 if ((flags & GST_SEEK_FLAG_KEY_UNIT) && !qtdemux->fragmented) {
1495 gst_qtdemux_adjust_seek (qtdemux, desired_offset, TRUE, &min_offset, NULL);
1496 GST_DEBUG_OBJECT (qtdemux, "keyframe seek, align to %"
1497 GST_TIME_FORMAT, GST_TIME_ARGS (min_offset));
1498 desired_offset = min_offset;
1501 /* and set all streams to the final position */
1502 gst_flow_combiner_reset (qtdemux->flowcombiner);
1503 qtdemux->segment_seqnum = seqnum;
1504 for (n = 0; n < qtdemux->n_streams; n++) {
1505 QtDemuxStream *stream = qtdemux->streams[n];
1507 stream->time_position = desired_offset;
1508 stream->accumulated_base = 0;
1509 stream->sample_index = -1;
1510 stream->offset_in_sample = 0;
1511 stream->segment_index = -1;
1512 stream->sent_eos = FALSE;
1514 if (segment->flags & GST_SEEK_FLAG_FLUSH)
1515 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
1517 segment->position = desired_offset;
1518 segment->time = desired_offset;
1519 if (segment->rate >= 0) {
1520 segment->start = desired_offset;
1522 /* we stop at the end */
1523 if (segment->stop == -1)
1524 segment->stop = segment->duration;
1526 segment->stop = desired_offset;
1529 if (qtdemux->fragmented)
1530 qtdemux->fragmented_seek_pending = TRUE;
1535 /* do a seek in pull based mode */
1537 gst_qtdemux_do_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1542 GstSeekType cur_type, stop_type;
1546 GstSegment seeksegment;
1548 GstEvent *flush_event;
1551 GST_DEBUG_OBJECT (qtdemux, "doing seek with event");
1553 gst_event_parse_seek (event, &rate, &format, &flags,
1554 &cur_type, &cur, &stop_type, &stop);
1555 seqnum = gst_event_get_seqnum (event);
1557 /* we have to have a format as the segment format. Try to convert
1559 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1563 GST_DEBUG_OBJECT (qtdemux, "seek format %s", gst_format_get_name (format));
1565 GST_DEBUG_OBJECT (qtdemux, "doing seek without event");
1569 flush = flags & GST_SEEK_FLAG_FLUSH;
1571 /* stop streaming, either by flushing or by pausing the task */
1573 flush_event = gst_event_new_flush_start ();
1575 gst_event_set_seqnum (flush_event, seqnum);
1576 /* unlock upstream pull_range */
1577 gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event));
1578 /* make sure out loop function exits */
1579 gst_qtdemux_push_event (qtdemux, flush_event);
1581 /* non flushing seek, pause the task */
1582 gst_pad_pause_task (qtdemux->sinkpad);
1585 /* wait for streaming to finish */
1586 GST_PAD_STREAM_LOCK (qtdemux->sinkpad);
1588 /* copy segment, we need this because we still need the old
1589 * segment when we close the current segment. */
1590 memcpy (&seeksegment, &qtdemux->segment, sizeof (GstSegment));
1593 /* configure the segment with the seek variables */
1594 GST_DEBUG_OBJECT (qtdemux, "configuring seek");
1595 gst_segment_do_seek (&seeksegment, rate, format, flags,
1596 cur_type, cur, stop_type, stop, &update);
1599 /* now do the seek, this actually never returns FALSE */
1600 gst_qtdemux_perform_seek (qtdemux, &seeksegment, seqnum, flags);
1602 /* prepare for streaming again */
1604 flush_event = gst_event_new_flush_stop (TRUE);
1606 gst_event_set_seqnum (flush_event, seqnum);
1608 gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event));
1609 gst_qtdemux_push_event (qtdemux, flush_event);
1612 /* commit the new segment */
1613 memcpy (&qtdemux->segment, &seeksegment, sizeof (GstSegment));
1615 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
1616 GstMessage *msg = gst_message_new_segment_start (GST_OBJECT_CAST (qtdemux),
1617 qtdemux->segment.format, qtdemux->segment.position);
1619 gst_message_set_seqnum (msg, seqnum);
1620 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
1623 /* restart streaming, NEWSEGMENT will be sent from the streaming thread. */
1624 gst_pad_start_task (qtdemux->sinkpad, (GstTaskFunction) gst_qtdemux_loop,
1625 qtdemux->sinkpad, NULL);
1627 GST_PAD_STREAM_UNLOCK (qtdemux->sinkpad);
1634 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1640 qtdemux_ensure_index (GstQTDemux * qtdemux)
1644 GST_DEBUG_OBJECT (qtdemux, "collecting all metadata for all streams");
1646 /* Build complete index */
1647 for (i = 0; i < qtdemux->n_streams; i++) {
1648 QtDemuxStream *stream = qtdemux->streams[i];
1650 if (!qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1))
1658 GST_LOG_OBJECT (qtdemux,
1659 "Building complete index of stream %u for seeking failed!", i);
1665 gst_qtdemux_handle_src_event (GstPad * pad, GstObject * parent,
1668 gboolean res = TRUE;
1669 GstQTDemux *qtdemux = GST_QTDEMUX (parent);
1671 switch (GST_EVENT_TYPE (event)) {
1672 case GST_EVENT_SEEK:
1674 #ifndef GST_DISABLE_GST_DEBUG
1675 GstClockTime ts = gst_util_get_timestamp ();
1678 if (qtdemux->upstream_format_is_time && qtdemux->fragmented) {
1679 /* seek should be handled by upstream, we might need to re-download fragments */
1680 GST_DEBUG_OBJECT (qtdemux,
1681 "let upstream handle seek for fragmented playback");
1685 /* Build complete index for seeking;
1686 * if not a fragmented file at least */
1687 if (!qtdemux->fragmented)
1688 if (!qtdemux_ensure_index (qtdemux))
1690 #ifndef GST_DISABLE_GST_DEBUG
1691 ts = gst_util_get_timestamp () - ts;
1692 GST_INFO_OBJECT (qtdemux,
1693 "Time taken to parse index %" GST_TIME_FORMAT, GST_TIME_ARGS (ts));
1696 if (qtdemux->pullbased) {
1697 res = gst_qtdemux_do_seek (qtdemux, pad, event);
1698 } else if (gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (event))) {
1699 GST_DEBUG_OBJECT (qtdemux, "Upstream successfully seeked");
1701 } else if (qtdemux->state == QTDEMUX_STATE_MOVIE && qtdemux->n_streams
1702 && !qtdemux->fragmented) {
1703 res = gst_qtdemux_do_push_seek (qtdemux, pad, event);
1705 GST_DEBUG_OBJECT (qtdemux,
1706 "ignoring seek in push mode in current state");
1709 gst_event_unref (event);
1712 case GST_EVENT_NAVIGATION:
1714 gst_event_unref (event);
1718 res = gst_pad_event_default (pad, parent, event);
1728 GST_ERROR_OBJECT (qtdemux, "Index failed");
1729 gst_event_unref (event);
1735 /* stream/index return sample that is min/max w.r.t. byte position,
1736 * time is min/max w.r.t. time of samples,
1737 * the latter need not be time of the former sample */
1739 gst_qtdemux_find_sample (GstQTDemux * qtdemux, gint64 byte_pos, gboolean fw,
1740 gboolean set, QtDemuxStream ** _stream, gint * _index, gint64 * _time)
1743 gint64 time, min_time;
1744 QtDemuxStream *stream;
1750 for (n = 0; n < qtdemux->n_streams; ++n) {
1753 gboolean set_sample;
1755 str = qtdemux->streams[n];
1762 i = str->n_samples - 1;
1766 for (; (i >= 0) && (i < str->n_samples); i += inc) {
1767 if (str->samples[i].size == 0)
1770 if (fw && (str->samples[i].offset < byte_pos))
1773 if (!fw && (str->samples[i].offset + str->samples[i].size > byte_pos))
1776 /* move stream to first available sample */
1778 gst_qtdemux_move_stream (qtdemux, str, i);
1782 /* avoid index from sparse streams since they might be far away */
1784 /* determine min/max time */
1785 time = QTSAMPLE_PTS (str, &str->samples[i]);
1786 if (min_time == -1 || (!fw && time > min_time) ||
1787 (fw && time < min_time)) {
1791 /* determine stream with leading sample, to get its position */
1793 (fw && (str->samples[i].offset < stream->samples[index].offset)) ||
1794 (!fw && (str->samples[i].offset > stream->samples[index].offset))) {
1802 /* no sample for this stream, mark eos */
1804 gst_qtdemux_move_stream (qtdemux, str, str->n_samples);
1815 static QtDemuxStream *
1816 _create_stream (void)
1818 QtDemuxStream *stream;
1820 stream = g_new0 (QtDemuxStream, 1);
1821 /* new streams always need a discont */
1822 stream->discont = TRUE;
1823 /* we enable clipping for raw audio/video streams */
1824 stream->need_clip = FALSE;
1825 stream->need_process = FALSE;
1826 stream->segment_index = -1;
1827 stream->time_position = 0;
1828 stream->sample_index = -1;
1829 stream->offset_in_sample = 0;
1830 stream->new_stream = TRUE;
1831 stream->multiview_mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
1832 stream->multiview_flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
1833 stream->protected = FALSE;
1834 stream->protection_scheme_type = 0;
1835 stream->protection_scheme_version = 0;
1836 stream->protection_scheme_info = NULL;
1837 stream->n_samples_moof = 0;
1838 stream->duration_moof = 0;
1839 g_queue_init (&stream->protection_scheme_event_queue);
1844 gst_qtdemux_setcaps (GstQTDemux * demux, GstCaps * caps)
1846 GstStructure *structure;
1847 const gchar *variant;
1848 const GstCaps *mediacaps = NULL;
1850 GST_DEBUG_OBJECT (demux, "Sink set caps: %" GST_PTR_FORMAT, caps);
1852 structure = gst_caps_get_structure (caps, 0);
1853 variant = gst_structure_get_string (structure, "variant");
1855 if (variant && strcmp (variant, "mss-fragmented") == 0) {
1856 QtDemuxStream *stream;
1857 const GValue *value;
1859 demux->fragmented = TRUE;
1860 demux->mss_mode = TRUE;
1862 if (demux->n_streams > 1) {
1863 /* can't do this, we can only renegotiate for another mss format */
1867 value = gst_structure_get_value (structure, "media-caps");
1870 const GValue *timescale_v;
1872 /* TODO update when stream changes during playback */
1874 if (demux->n_streams == 0) {
1875 stream = _create_stream ();
1876 demux->streams[demux->n_streams] = stream;
1877 demux->n_streams = 1;
1879 stream = demux->streams[0];
1882 timescale_v = gst_structure_get_value (structure, "timescale");
1884 stream->timescale = g_value_get_uint64 (timescale_v);
1886 /* default mss timescale */
1887 stream->timescale = 10000000;
1889 demux->timescale = stream->timescale;
1891 mediacaps = gst_value_get_caps (value);
1892 if (!stream->caps || !gst_caps_is_equal_fixed (mediacaps, stream->caps)) {
1893 GST_DEBUG_OBJECT (demux, "We have a new caps %" GST_PTR_FORMAT,
1895 stream->new_caps = TRUE;
1897 gst_caps_replace (&stream->caps, (GstCaps *) mediacaps);
1898 structure = gst_caps_get_structure (mediacaps, 0);
1899 if (g_str_has_prefix (gst_structure_get_name (structure), "video")) {
1900 stream->subtype = FOURCC_vide;
1902 gst_structure_get_int (structure, "width", &stream->width);
1903 gst_structure_get_int (structure, "height", &stream->height);
1904 gst_structure_get_fraction (structure, "framerate", &stream->fps_n,
1906 } else if (g_str_has_prefix (gst_structure_get_name (structure), "audio")) {
1908 stream->subtype = FOURCC_soun;
1909 gst_structure_get_int (structure, "channels", &stream->n_channels);
1910 gst_structure_get_int (structure, "rate", &rate);
1911 stream->rate = rate;
1914 gst_caps_replace (&demux->media_caps, (GstCaps *) mediacaps);
1916 demux->mss_mode = FALSE;
1923 gst_qtdemux_reset (GstQTDemux * qtdemux, gboolean hard)
1927 GST_DEBUG_OBJECT (qtdemux, "Resetting demux");
1928 gst_pad_stop_task (qtdemux->sinkpad);
1930 if (hard || qtdemux->upstream_format_is_time) {
1931 qtdemux->state = QTDEMUX_STATE_INITIAL;
1932 qtdemux->neededbytes = 16;
1933 qtdemux->todrop = 0;
1934 qtdemux->pullbased = FALSE;
1935 qtdemux->posted_redirect = FALSE;
1936 qtdemux->first_mdat = -1;
1937 qtdemux->header_size = 0;
1938 qtdemux->mdatoffset = -1;
1939 qtdemux->restoredata_offset = -1;
1940 if (qtdemux->mdatbuffer)
1941 gst_buffer_unref (qtdemux->mdatbuffer);
1942 if (qtdemux->restoredata_buffer)
1943 gst_buffer_unref (qtdemux->restoredata_buffer);
1944 qtdemux->mdatbuffer = NULL;
1945 qtdemux->restoredata_buffer = NULL;
1946 qtdemux->mdatleft = 0;
1947 if (qtdemux->comp_brands)
1948 gst_buffer_unref (qtdemux->comp_brands);
1949 qtdemux->comp_brands = NULL;
1950 qtdemux->last_moov_offset = -1;
1951 if (qtdemux->moov_node)
1952 g_node_destroy (qtdemux->moov_node);
1953 qtdemux->moov_node = NULL;
1954 qtdemux->moov_node_compressed = NULL;
1955 if (qtdemux->tag_list)
1956 gst_mini_object_unref (GST_MINI_OBJECT_CAST (qtdemux->tag_list));
1957 qtdemux->tag_list = NULL;
1959 if (qtdemux->element_index)
1960 gst_object_unref (qtdemux->element_index);
1961 qtdemux->element_index = NULL;
1963 qtdemux->major_brand = 0;
1964 if (qtdemux->pending_newsegment)
1965 gst_event_unref (qtdemux->pending_newsegment);
1966 qtdemux->pending_newsegment = NULL;
1967 qtdemux->upstream_format_is_time = FALSE;
1968 qtdemux->upstream_seekable = FALSE;
1969 qtdemux->upstream_size = 0;
1971 qtdemux->fragment_start = -1;
1972 qtdemux->fragment_start_offset = -1;
1973 qtdemux->duration = 0;
1974 qtdemux->moof_offset = 0;
1975 qtdemux->chapters_track_id = 0;
1976 qtdemux->have_group_id = FALSE;
1977 qtdemux->group_id = G_MAXUINT;
1979 g_queue_foreach (&qtdemux->protection_event_queue, (GFunc) gst_event_unref,
1981 g_queue_clear (&qtdemux->protection_event_queue);
1983 qtdemux->offset = 0;
1984 gst_adapter_clear (qtdemux->adapter);
1985 gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
1986 qtdemux->segment_seqnum = 0;
1989 for (n = 0; n < qtdemux->n_streams; n++) {
1990 gst_qtdemux_stream_free (qtdemux, qtdemux->streams[n]);
1991 qtdemux->streams[n] = NULL;
1993 qtdemux->n_streams = 0;
1994 qtdemux->n_video_streams = 0;
1995 qtdemux->n_audio_streams = 0;
1996 qtdemux->n_sub_streams = 0;
1997 qtdemux->exposed = FALSE;
1998 qtdemux->fragmented = FALSE;
1999 qtdemux->mss_mode = FALSE;
2000 gst_caps_replace (&qtdemux->media_caps, NULL);
2001 qtdemux->timescale = 0;
2002 qtdemux->got_moov = FALSE;
2003 if (qtdemux->protection_system_ids) {
2004 g_ptr_array_free (qtdemux->protection_system_ids, TRUE);
2005 qtdemux->protection_system_ids = NULL;
2007 } else if (qtdemux->mss_mode) {
2008 gst_flow_combiner_reset (qtdemux->flowcombiner);
2009 for (n = 0; n < qtdemux->n_streams; n++)
2010 gst_qtdemux_stream_clear (qtdemux, qtdemux->streams[n]);
2012 gst_flow_combiner_reset (qtdemux->flowcombiner);
2013 for (n = 0; n < qtdemux->n_streams; n++) {
2014 qtdemux->streams[n]->sent_eos = FALSE;
2015 qtdemux->streams[n]->time_position = 0;
2016 qtdemux->streams[n]->accumulated_base = 0;
2018 if (!qtdemux->pending_newsegment) {
2019 qtdemux->pending_newsegment = gst_event_new_segment (&qtdemux->segment);
2025 gst_qtdemux_handle_sink_event (GstPad * sinkpad, GstObject * parent,
2028 GstQTDemux *demux = GST_QTDEMUX (parent);
2029 gboolean res = TRUE;
2031 GST_LOG_OBJECT (demux, "handling %s event", GST_EVENT_TYPE_NAME (event));
2033 switch (GST_EVENT_TYPE (event)) {
2034 case GST_EVENT_SEGMENT:
2037 QtDemuxStream *stream;
2040 GstEvent *segment_event;
2042 /* some debug output */
2043 gst_event_copy_segment (event, &segment);
2044 GST_DEBUG_OBJECT (demux, "received newsegment %" GST_SEGMENT_FORMAT,
2047 if (segment.format == GST_FORMAT_TIME) {
2048 GST_DEBUG_OBJECT (demux, "new pending_newsegment");
2049 gst_event_replace (&demux->pending_newsegment, event);
2050 demux->upstream_format_is_time = TRUE;
2052 GST_DEBUG_OBJECT (demux, "Not storing upstream newsegment, "
2053 "not in time format");
2055 /* chain will send initial newsegment after pads have been added */
2056 if (demux->state != QTDEMUX_STATE_MOVIE || !demux->n_streams) {
2057 GST_DEBUG_OBJECT (demux, "still starting, eating event");
2062 /* check if this matches a time seek we received previously
2063 * FIXME for backwards compatibility reasons we use the
2064 * seek_offset here to compare. In the future we might want to
2065 * change this to use the seqnum as it uniquely should identify
2066 * the segment that corresponds to the seek. */
2067 GST_DEBUG_OBJECT (demux, "Stored seek offset: %" G_GINT64_FORMAT
2068 ", received segment offset %" G_GINT64_FORMAT,
2069 demux->seek_offset, segment.start);
2070 if (segment.format == GST_FORMAT_BYTES
2071 && demux->seek_offset == segment.start) {
2072 GST_OBJECT_LOCK (demux);
2073 offset = segment.start;
2075 segment.format = GST_FORMAT_TIME;
2076 segment.start = demux->push_seek_start;
2077 segment.stop = demux->push_seek_stop;
2078 GST_DEBUG_OBJECT (demux, "Replaced segment with stored seek "
2079 "segment %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT,
2080 GST_TIME_ARGS (segment.start), GST_TIME_ARGS (segment.stop));
2081 GST_OBJECT_UNLOCK (demux);
2084 /* we only expect a BYTE segment, e.g. following a seek */
2085 if (segment.format == GST_FORMAT_BYTES) {
2086 if (GST_CLOCK_TIME_IS_VALID (segment.start)) {
2087 offset = segment.start;
2089 gst_qtdemux_find_sample (demux, segment.start, TRUE, FALSE, NULL,
2090 NULL, (gint64 *) & segment.start);
2091 if ((gint64) segment.start < 0)
2094 if (GST_CLOCK_TIME_IS_VALID (segment.stop)) {
2095 gst_qtdemux_find_sample (demux, segment.stop, FALSE, FALSE, NULL,
2096 NULL, (gint64 *) & segment.stop);
2097 /* keyframe seeking should already arrange for start >= stop,
2098 * but make sure in other rare cases */
2099 segment.stop = MAX (segment.stop, segment.start);
2101 } else if (segment.format == GST_FORMAT_TIME) {
2102 /* push all data on the adapter before starting this
2104 gst_qtdemux_process_adapter (demux, TRUE);
2106 GST_DEBUG_OBJECT (demux, "unsupported segment format, ignoring");
2110 /* accept upstream's notion of segment and distribute along */
2111 segment.format = GST_FORMAT_TIME;
2112 segment.position = segment.time = segment.start;
2113 segment.duration = demux->segment.duration;
2114 segment.base = gst_segment_to_running_time (&demux->segment,
2115 GST_FORMAT_TIME, demux->segment.position);
2117 gst_segment_copy_into (&segment, &demux->segment);
2118 GST_DEBUG_OBJECT (demux, "Pushing newseg %" GST_SEGMENT_FORMAT, &segment);
2119 segment_event = gst_event_new_segment (&segment);
2120 gst_event_set_seqnum (segment_event, gst_event_get_seqnum (event));
2121 /* erase any previously set segment */
2122 gst_event_replace (&demux->pending_newsegment, NULL);
2123 gst_qtdemux_push_event (demux, segment_event);
2125 /* clear leftover in current segment, if any */
2126 gst_adapter_clear (demux->adapter);
2128 /* set up streaming thread */
2129 demux->offset = offset;
2130 if (demux->upstream_format_is_time) {
2131 GST_DEBUG_OBJECT (demux, "Upstream is driving in time format, "
2132 "set values to restart reading from a new atom");
2133 demux->neededbytes = 16;
2136 gst_qtdemux_find_sample (demux, offset, TRUE, TRUE, &stream, &idx,
2139 demux->todrop = stream->samples[idx].offset - offset;
2140 demux->neededbytes = demux->todrop + stream->samples[idx].size;
2142 /* set up for EOS */
2143 demux->neededbytes = -1;
2148 gst_event_unref (event);
2152 case GST_EVENT_FLUSH_START:
2154 if (gst_event_get_seqnum (event) == demux->offset_seek_seqnum) {
2155 gst_event_unref (event);
2160 case GST_EVENT_FLUSH_STOP:
2164 dur = demux->segment.duration;
2165 gst_qtdemux_reset (demux, FALSE);
2166 demux->segment.duration = dur;
2168 if (gst_event_get_seqnum (event) == demux->offset_seek_seqnum) {
2169 gst_event_unref (event);
2175 /* If we are in push mode, and get an EOS before we've seen any streams,
2176 * then error out - we have nowhere to send the EOS */
2177 if (!demux->pullbased) {
2179 gboolean has_valid_stream = FALSE;
2180 for (i = 0; i < demux->n_streams; i++) {
2181 if (demux->streams[i]->pad != NULL) {
2182 has_valid_stream = TRUE;
2186 if (!has_valid_stream)
2187 gst_qtdemux_post_no_playable_stream_error (demux);
2189 GST_DEBUG_OBJECT (demux, "Data still available after EOS: %u",
2190 (guint) gst_adapter_available (demux->adapter));
2191 if (gst_qtdemux_process_adapter (demux, TRUE) != GST_FLOW_OK) {
2197 case GST_EVENT_CAPS:{
2198 GstCaps *caps = NULL;
2200 gst_event_parse_caps (event, &caps);
2201 gst_qtdemux_setcaps (demux, caps);
2203 gst_event_unref (event);
2206 case GST_EVENT_PROTECTION:
2208 const gchar *system_id = NULL;
2210 gst_event_parse_protection (event, &system_id, NULL, NULL);
2211 GST_DEBUG_OBJECT (demux, "Received protection event for system ID %s",
2213 gst_qtdemux_append_protection_system_id (demux, system_id);
2214 /* save the event for later, for source pads that have not been created */
2215 g_queue_push_tail (&demux->protection_event_queue, gst_event_ref (event));
2216 /* send it to all pads that already exist */
2217 gst_qtdemux_push_event (demux, event);
2225 res = gst_pad_event_default (demux->sinkpad, parent, event) & res;
2233 gst_qtdemux_set_index (GstElement * element, GstIndex * index)
2235 GstQTDemux *demux = GST_QTDEMUX (element);
2237 GST_OBJECT_LOCK (demux);
2238 if (demux->element_index)
2239 gst_object_unref (demux->element_index);
2241 demux->element_index = gst_object_ref (index);
2243 demux->element_index = NULL;
2245 GST_OBJECT_UNLOCK (demux);
2246 /* object lock might be taken again */
2248 gst_index_get_writer_id (index, GST_OBJECT (element), &demux->index_id);
2249 GST_DEBUG_OBJECT (demux, "Set index %" GST_PTR_FORMAT "for writer id %d",
2250 demux->element_index, demux->index_id);
2254 gst_qtdemux_get_index (GstElement * element)
2256 GstIndex *result = NULL;
2257 GstQTDemux *demux = GST_QTDEMUX (element);
2259 GST_OBJECT_LOCK (demux);
2260 if (demux->element_index)
2261 result = gst_object_ref (demux->element_index);
2262 GST_OBJECT_UNLOCK (demux);
2264 GST_DEBUG_OBJECT (demux, "Returning index %" GST_PTR_FORMAT, result);
2271 gst_qtdemux_stbl_free (QtDemuxStream * stream)
2273 g_free ((gpointer) stream->stco.data);
2274 stream->stco.data = NULL;
2275 g_free ((gpointer) stream->stsz.data);
2276 stream->stsz.data = NULL;
2277 g_free ((gpointer) stream->stsc.data);
2278 stream->stsc.data = NULL;
2279 g_free ((gpointer) stream->stts.data);
2280 stream->stts.data = NULL;
2281 g_free ((gpointer) stream->stss.data);
2282 stream->stss.data = NULL;
2283 g_free ((gpointer) stream->stps.data);
2284 stream->stps.data = NULL;
2285 g_free ((gpointer) stream->ctts.data);
2286 stream->ctts.data = NULL;
2290 gst_qtdemux_stream_flush_segments_data (GstQTDemux * qtdemux,
2291 QtDemuxStream * stream)
2293 g_free (stream->segments);
2294 stream->segments = NULL;
2295 stream->segment_index = -1;
2296 stream->accumulated_base = 0;
2300 gst_qtdemux_stream_flush_samples_data (GstQTDemux * qtdemux,
2301 QtDemuxStream * stream)
2303 g_free (stream->samples);
2304 stream->samples = NULL;
2305 gst_qtdemux_stbl_free (stream);
2308 g_free (stream->ra_entries);
2309 stream->ra_entries = NULL;
2310 stream->n_ra_entries = 0;
2312 stream->sample_index = -1;
2313 stream->stbl_index = -1;
2314 stream->n_samples = 0;
2315 stream->time_position = 0;
2317 stream->n_samples_moof = 0;
2318 stream->duration_moof = 0;
2322 gst_qtdemux_stream_clear (GstQTDemux * qtdemux, QtDemuxStream * stream)
2324 if (stream->allocator)
2325 gst_object_unref (stream->allocator);
2326 while (stream->buffers) {
2327 gst_buffer_unref (GST_BUFFER_CAST (stream->buffers->data));
2328 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
2330 if (stream->rgb8_palette) {
2331 gst_memory_unref (stream->rgb8_palette);
2332 stream->rgb8_palette = NULL;
2335 if (stream->pending_tags)
2336 gst_tag_list_unref (stream->pending_tags);
2337 stream->pending_tags = NULL;
2338 g_free (stream->redirect_uri);
2339 stream->redirect_uri = NULL;
2340 stream->sent_eos = FALSE;
2341 stream->sparse = FALSE;
2342 stream->protected = FALSE;
2343 if (stream->protection_scheme_info) {
2344 if (stream->protection_scheme_type == FOURCC_cenc) {
2345 QtDemuxCencSampleSetInfo *info =
2346 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
2347 if (info->default_properties)
2348 gst_structure_free (info->default_properties);
2349 if (info->crypto_info)
2350 g_ptr_array_free (info->crypto_info, TRUE);
2352 g_free (stream->protection_scheme_info);
2353 stream->protection_scheme_info = NULL;
2355 stream->protection_scheme_type = 0;
2356 stream->protection_scheme_version = 0;
2357 g_queue_foreach (&stream->protection_scheme_event_queue,
2358 (GFunc) gst_event_unref, NULL);
2359 g_queue_clear (&stream->protection_scheme_event_queue);
2360 gst_qtdemux_stream_flush_segments_data (qtdemux, stream);
2361 gst_qtdemux_stream_flush_samples_data (qtdemux, stream);
2365 gst_qtdemux_stream_free (GstQTDemux * qtdemux, QtDemuxStream * stream)
2367 gst_qtdemux_stream_clear (qtdemux, stream);
2369 gst_caps_unref (stream->caps);
2370 stream->caps = NULL;
2372 gst_element_remove_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
2373 gst_flow_combiner_remove_pad (qtdemux->flowcombiner, stream->pad);
2379 gst_qtdemux_remove_stream (GstQTDemux * qtdemux, int i)
2381 g_assert (i >= 0 && i < qtdemux->n_streams && qtdemux->streams[i] != NULL);
2383 gst_qtdemux_stream_free (qtdemux, qtdemux->streams[i]);
2384 qtdemux->streams[i] = qtdemux->streams[qtdemux->n_streams - 1];
2385 qtdemux->streams[qtdemux->n_streams - 1] = NULL;
2386 qtdemux->n_streams--;
2389 static GstStateChangeReturn
2390 gst_qtdemux_change_state (GstElement * element, GstStateChange transition)
2392 GstQTDemux *qtdemux = GST_QTDEMUX (element);
2393 GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
2395 switch (transition) {
2396 case GST_STATE_CHANGE_PAUSED_TO_READY:
2402 result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
2404 switch (transition) {
2405 case GST_STATE_CHANGE_PAUSED_TO_READY:{
2406 gst_qtdemux_reset (qtdemux, TRUE);
2417 qtdemux_parse_ftyp (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2419 /* counts as header data */
2420 qtdemux->header_size += length;
2422 /* only consider at least a sufficiently complete ftyp atom */
2426 qtdemux->major_brand = QT_FOURCC (buffer + 8);
2427 GST_DEBUG_OBJECT (qtdemux, "major brand: %" GST_FOURCC_FORMAT,
2428 GST_FOURCC_ARGS (qtdemux->major_brand));
2429 if (qtdemux->comp_brands)
2430 gst_buffer_unref (qtdemux->comp_brands);
2431 buf = qtdemux->comp_brands = gst_buffer_new_and_alloc (length - 16);
2432 gst_buffer_fill (buf, 0, buffer + 16, length - 16);
2437 qtdemux_handle_xmp_taglist (GstQTDemux * qtdemux, GstTagList * taglist,
2438 GstTagList * xmptaglist)
2440 /* Strip out bogus fields */
2442 if (gst_tag_list_get_scope (taglist) == GST_TAG_SCOPE_GLOBAL) {
2443 gst_tag_list_remove_tag (xmptaglist, GST_TAG_VIDEO_CODEC);
2444 gst_tag_list_remove_tag (xmptaglist, GST_TAG_AUDIO_CODEC);
2446 gst_tag_list_remove_tag (xmptaglist, GST_TAG_CONTAINER_FORMAT);
2449 GST_DEBUG_OBJECT (qtdemux, "Found XMP tags %" GST_PTR_FORMAT, xmptaglist);
2451 /* prioritize native tags using _KEEP mode */
2452 gst_tag_list_insert (taglist, xmptaglist, GST_TAG_MERGE_KEEP);
2453 gst_tag_list_unref (xmptaglist);
2458 qtdemux_parse_piff (GstQTDemux * qtdemux, const guint8 * buffer, gint length,
2466 QtDemuxStream *stream;
2467 GstStructure *structure;
2468 QtDemuxCencSampleSetInfo *ss_info = NULL;
2469 const gchar *system_id;
2470 gboolean uses_sub_sample_encryption = FALSE;
2472 if (qtdemux->n_streams == 0)
2475 stream = qtdemux->streams[0];
2477 structure = gst_caps_get_structure (stream->caps, 0);
2478 if (!gst_structure_has_name (structure, "application/x-cenc")) {
2479 GST_WARNING_OBJECT (qtdemux,
2480 "Attempting PIFF box parsing on an unencrypted stream.");
2484 gst_structure_get (structure, GST_PROTECTION_SYSTEM_ID_CAPS_FIELD,
2485 G_TYPE_STRING, &system_id, NULL);
2486 gst_qtdemux_append_protection_system_id (qtdemux, system_id);
2488 stream->protected = TRUE;
2489 stream->protection_scheme_type = FOURCC_cenc;
2491 if (!stream->protection_scheme_info)
2492 stream->protection_scheme_info = g_new0 (QtDemuxCencSampleSetInfo, 1);
2494 ss_info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
2496 if (ss_info->default_properties)
2497 gst_structure_free (ss_info->default_properties);
2499 ss_info->default_properties =
2500 gst_structure_new ("application/x-cenc",
2501 "iv_size", G_TYPE_UINT, iv_size, "encrypted", G_TYPE_BOOLEAN, TRUE, NULL);
2503 if (ss_info->crypto_info) {
2504 GST_LOG_OBJECT (qtdemux, "unreffing existing crypto_info");
2505 g_ptr_array_free (ss_info->crypto_info, TRUE);
2506 ss_info->crypto_info = NULL;
2510 gst_byte_reader_init (&br, buffer + offset + 16, length - offset - 16);
2512 if (!gst_byte_reader_get_uint8 (&br, &version)) {
2513 GST_ERROR_OBJECT (qtdemux, "Error getting box's version field");
2517 if (!gst_byte_reader_get_uint24_be (&br, &flags)) {
2518 GST_ERROR_OBJECT (qtdemux, "Error getting box's flags field");
2522 if ((flags & 0x000001)) {
2523 guint32 algorithm_id = 0;
2526 gboolean is_encrypted = TRUE;
2528 if (!gst_byte_reader_get_uint24_le (&br, &algorithm_id)) {
2529 GST_ERROR_OBJECT (qtdemux, "Error getting box's algorithm ID field");
2534 if (algorithm_id == 0) {
2535 is_encrypted = FALSE;
2536 } else if (algorithm_id == 1) {
2537 /* FIXME: maybe store this in properties? */
2538 GST_DEBUG_OBJECT (qtdemux, "AES 128-bits CTR encrypted stream");
2539 } else if (algorithm_id == 2) {
2540 /* FIXME: maybe store this in properties? */
2541 GST_DEBUG_OBJECT (qtdemux, "AES 128-bits CBC encrypted stream");
2544 if (!gst_byte_reader_get_uint8 (&br, &iv_size))
2547 if (!gst_byte_reader_get_data (&br, 16, &kid))
2550 kid_buf = gst_buffer_new_allocate (NULL, 16, NULL);
2551 gst_buffer_fill (kid_buf, 0, kid, 16);
2552 if (ss_info->default_properties)
2553 gst_structure_free (ss_info->default_properties);
2554 ss_info->default_properties =
2555 gst_structure_new ("application/x-cenc",
2556 "iv_size", G_TYPE_UINT, iv_size,
2557 "encrypted", G_TYPE_BOOLEAN, is_encrypted,
2558 "kid", GST_TYPE_BUFFER, kid_buf, NULL);
2559 GST_DEBUG_OBJECT (qtdemux, "default sample properties: "
2560 "is_encrypted=%u, iv_size=%u", is_encrypted, iv_size);
2561 gst_buffer_unref (kid_buf);
2562 } else if ((flags & 0x000002)) {
2563 uses_sub_sample_encryption = TRUE;
2566 if (!gst_byte_reader_get_uint32_be (&br, &qtdemux->cenc_aux_sample_count)) {
2567 GST_ERROR_OBJECT (qtdemux, "Error getting box's sample count field");
2571 ss_info->crypto_info =
2572 g_ptr_array_new_full (qtdemux->cenc_aux_sample_count,
2573 (GDestroyNotify) qtdemux_gst_structure_free);
2575 for (i = 0; i < qtdemux->cenc_aux_sample_count; ++i) {
2576 GstStructure *properties;
2580 properties = qtdemux_get_cenc_sample_properties (qtdemux, stream, i);
2581 if (properties == NULL) {
2582 GST_ERROR_OBJECT (qtdemux, "failed to get properties for sample %u", i);
2586 if (!gst_byte_reader_dup_data (&br, iv_size, &data)) {
2587 GST_ERROR_OBJECT (qtdemux, "IV data not present for sample %u", i);
2588 gst_structure_free (properties);
2591 buf = gst_buffer_new_wrapped (data, iv_size);
2592 gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL);
2593 gst_buffer_unref (buf);
2595 if (uses_sub_sample_encryption) {
2596 guint16 n_subsamples;
2598 if (!gst_byte_reader_get_uint16_be (&br, &n_subsamples)
2599 || n_subsamples == 0) {
2600 GST_ERROR_OBJECT (qtdemux,
2601 "failed to get subsample count for sample %u", i);
2602 gst_structure_free (properties);
2605 GST_LOG_OBJECT (qtdemux, "subsample count: %u", n_subsamples);
2606 if (!gst_byte_reader_dup_data (&br, n_subsamples * 6, &data)) {
2607 GST_ERROR_OBJECT (qtdemux, "failed to get subsample data for sample %u",
2609 gst_structure_free (properties);
2612 buf = gst_buffer_new_wrapped (data, n_subsamples * 6);
2613 gst_structure_set (properties,
2614 "subsample_count", G_TYPE_UINT, n_subsamples,
2615 "subsamples", GST_TYPE_BUFFER, buf, NULL);
2616 gst_buffer_unref (buf);
2618 gst_structure_set (properties, "subsample_count", G_TYPE_UINT, 0, NULL);
2621 g_ptr_array_add (ss_info->crypto_info, properties);
2626 qtdemux_parse_uuid (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2628 static const guint8 xmp_uuid[] = { 0xBE, 0x7A, 0xCF, 0xCB,
2629 0x97, 0xA9, 0x42, 0xE8,
2630 0x9C, 0x71, 0x99, 0x94,
2631 0x91, 0xE3, 0xAF, 0xAC
2633 static const guint8 playready_uuid[] = {
2634 0xd0, 0x8a, 0x4f, 0x18, 0x10, 0xf3, 0x4a, 0x82,
2635 0xb6, 0xc8, 0x32, 0xd8, 0xab, 0xa1, 0x83, 0xd3
2638 static const guint8 piff_sample_encryption_uuid[] = {
2639 0xa2, 0x39, 0x4f, 0x52, 0x5a, 0x9b, 0x4f, 0x14,
2640 0xa2, 0x44, 0x6c, 0x42, 0x7c, 0x64, 0x8d, 0xf4
2645 /* counts as header data */
2646 qtdemux->header_size += length;
2648 offset = (QT_UINT32 (buffer) == 0) ? 16 : 8;
2650 if (length <= offset + 16) {
2651 GST_DEBUG_OBJECT (qtdemux, "uuid atom is too short, skipping");
2655 if (memcmp (buffer + offset, xmp_uuid, 16) == 0) {
2657 GstTagList *taglist;
2659 buf = _gst_buffer_new_wrapped ((guint8 *) buffer + offset + 16,
2660 length - offset - 16, NULL);
2661 taglist = gst_tag_list_from_xmp_buffer (buf);
2662 gst_buffer_unref (buf);
2664 qtdemux_handle_xmp_taglist (qtdemux, qtdemux->tag_list, taglist);
2666 } else if (memcmp (buffer + offset, playready_uuid, 16) == 0) {
2668 const gunichar2 *s_utf16;
2671 len = GST_READ_UINT16_LE (buffer + offset + 0x30);
2672 s_utf16 = (const gunichar2 *) (buffer + offset + 0x32);
2673 contents = g_utf16_to_utf8 (s_utf16, len / 2, NULL, NULL, NULL);
2674 GST_ERROR_OBJECT (qtdemux, "contents: %s", contents);
2678 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT,
2679 (_("Cannot play stream because it is encrypted with PlayReady DRM.")),
2681 } else if (memcmp (buffer + offset, piff_sample_encryption_uuid, 16) == 0) {
2682 qtdemux_parse_piff (qtdemux, buffer, length, offset);
2684 GST_DEBUG_OBJECT (qtdemux, "Ignoring unknown uuid: %08x-%08x-%08x-%08x",
2685 GST_READ_UINT32_LE (buffer + offset),
2686 GST_READ_UINT32_LE (buffer + offset + 4),
2687 GST_READ_UINT32_LE (buffer + offset + 8),
2688 GST_READ_UINT32_LE (buffer + offset + 12));
2693 qtdemux_parse_sidx (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2695 GstSidxParser sidx_parser;
2696 GstIsoffParserResult res;
2699 gst_isoff_qt_sidx_parser_init (&sidx_parser);
2702 gst_isoff_qt_sidx_parser_add_data (&sidx_parser, buffer, length,
2704 GST_DEBUG_OBJECT (qtdemux, "sidx parse result: %d", res);
2705 if (res == GST_ISOFF_QT_PARSER_DONE) {
2706 check_update_duration (qtdemux, sidx_parser.cumulative_pts);
2708 gst_isoff_qt_sidx_parser_clear (&sidx_parser);
2711 /* caller verifies at least 8 bytes in buf */
2713 extract_initial_length_and_fourcc (const guint8 * data, guint size,
2714 guint64 * plength, guint32 * pfourcc)
2719 length = QT_UINT32 (data);
2720 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
2721 fourcc = QT_FOURCC (data + 4);
2722 GST_DEBUG ("atom type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
2725 length = G_MAXUINT64;
2726 } else if (length == 1 && size >= 16) {
2727 /* this means we have an extended size, which is the 64 bit value of
2728 * the next 8 bytes */
2729 length = QT_UINT64 (data + 8);
2730 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
2740 qtdemux_parse_mehd (GstQTDemux * qtdemux, GstByteReader * br)
2742 guint32 version = 0;
2743 GstClockTime duration = 0;
2745 if (!gst_byte_reader_get_uint32_be (br, &version))
2750 if (!gst_byte_reader_get_uint64_be (br, &duration))
2755 if (!gst_byte_reader_get_uint32_be (br, &dur))
2760 GST_INFO_OBJECT (qtdemux, "mehd duration: %" G_GUINT64_FORMAT, duration);
2761 qtdemux->duration = duration;
2767 GST_DEBUG_OBJECT (qtdemux, "parsing mehd failed");
2773 qtdemux_parse_trex (GstQTDemux * qtdemux, QtDemuxStream * stream,
2774 guint32 * ds_duration, guint32 * ds_size, guint32 * ds_flags)
2776 if (!stream->parsed_trex && qtdemux->moov_node) {
2778 GstByteReader trex_data;
2780 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
2782 trex = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_trex,
2785 guint32 id = 0, dur = 0, size = 0, flags = 0, dummy = 0;
2787 /* skip version/flags */
2788 if (!gst_byte_reader_skip (&trex_data, 4))
2790 if (!gst_byte_reader_get_uint32_be (&trex_data, &id))
2792 if (id != stream->track_id)
2794 /* sample description index; ignore */
2795 if (!gst_byte_reader_get_uint32_be (&trex_data, &dummy))
2797 if (!gst_byte_reader_get_uint32_be (&trex_data, &dur))
2799 if (!gst_byte_reader_get_uint32_be (&trex_data, &size))
2801 if (!gst_byte_reader_get_uint32_be (&trex_data, &flags))
2804 GST_DEBUG_OBJECT (qtdemux, "fragment defaults for stream %d; "
2805 "duration %d, size %d, flags 0x%x", stream->track_id,
2808 stream->parsed_trex = TRUE;
2809 stream->def_sample_duration = dur;
2810 stream->def_sample_size = size;
2811 stream->def_sample_flags = flags;
2814 /* iterate all siblings */
2815 trex = qtdemux_tree_get_sibling_by_type_full (trex, FOURCC_trex,
2821 *ds_duration = stream->def_sample_duration;
2822 *ds_size = stream->def_sample_size;
2823 *ds_flags = stream->def_sample_flags;
2825 /* even then, above values are better than random ... */
2826 if (G_UNLIKELY (!stream->parsed_trex)) {
2827 GST_WARNING_OBJECT (qtdemux,
2828 "failed to find fragment defaults for stream %d", stream->track_id);
2835 /* This method should be called whenever a more accurate duration might
2836 * have been found. It will update all relevant variables if/where needed
2839 check_update_duration (GstQTDemux * qtdemux, GstClockTime duration)
2843 GstClockTime prevdur;
2845 movdur = GSTTIME_TO_QTTIME (qtdemux, duration);
2847 if (movdur > qtdemux->duration) {
2848 prevdur = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
2849 GST_DEBUG_OBJECT (qtdemux,
2850 "Updating total duration to %" GST_TIME_FORMAT " was %" GST_TIME_FORMAT,
2851 GST_TIME_ARGS (duration), GST_TIME_ARGS (prevdur));
2852 qtdemux->duration = movdur;
2853 GST_DEBUG_OBJECT (qtdemux,
2854 "qtdemux->segment.duration: %" GST_TIME_FORMAT " .stop: %"
2855 GST_TIME_FORMAT, GST_TIME_ARGS (qtdemux->segment.duration),
2856 GST_TIME_ARGS (qtdemux->segment.stop));
2857 if (qtdemux->segment.duration == prevdur) {
2858 /* If the current segment has duration/stop identical to previous duration
2859 * update them also (because they were set at that point in time with
2860 * the wrong duration */
2861 /* We convert the value *from* the timescale version to avoid rounding errors */
2862 GstClockTime fixeddur = QTTIME_TO_GSTTIME (qtdemux, movdur);
2863 GST_DEBUG_OBJECT (qtdemux, "Updated segment.duration and segment.stop");
2864 qtdemux->segment.duration = fixeddur;
2865 qtdemux->segment.stop = fixeddur;
2868 for (i = 0; i < qtdemux->n_streams; i++) {
2869 QtDemuxStream *stream = qtdemux->streams[i];
2871 movdur = GSTTIME_TO_QTSTREAMTIME (stream, duration);
2872 if (movdur > stream->duration) {
2873 GST_DEBUG_OBJECT (qtdemux,
2874 "Updating stream #%d duration to %" GST_TIME_FORMAT, i,
2875 GST_TIME_ARGS (duration));
2876 stream->duration = movdur;
2877 if (stream->dummy_segment) {
2878 /* Update all dummy values to new duration */
2879 stream->segments[0].stop_time = duration;
2880 stream->segments[0].duration = duration;
2881 stream->segments[0].media_stop = duration;
2883 /* let downstream know we possibly have a new stop time */
2884 if (stream->segment_index != -1) {
2887 if (qtdemux->segment.rate >= 0) {
2888 pos = stream->segment.start;
2890 pos = stream->segment.stop;
2893 gst_qtdemux_stream_update_segment (qtdemux, stream,
2894 stream->segment_index, pos, NULL, NULL);
2903 qtdemux_parse_trun (GstQTDemux * qtdemux, GstByteReader * trun,
2904 QtDemuxStream * stream, guint32 d_sample_duration, guint32 d_sample_size,
2905 guint32 d_sample_flags, gint64 moof_offset, gint64 moof_length,
2906 gint64 * base_offset, gint64 * running_offset, gint64 decode_ts)
2908 GstClockTime gst_ts = GST_CLOCK_TIME_NONE;
2910 gint32 data_offset = 0;
2911 guint32 flags = 0, first_flags = 0, samples_count = 0;
2914 guint entry_size, dur_offset, size_offset, flags_offset = 0, ct_offset = 0;
2915 QtDemuxSample *sample;
2916 gboolean ismv = FALSE;
2918 GST_LOG_OBJECT (qtdemux, "parsing trun stream %d; "
2919 "default dur %d, size %d, flags 0x%x, base offset %" G_GINT64_FORMAT ", "
2920 "decode ts %" G_GINT64_FORMAT, stream->track_id, d_sample_duration,
2921 d_sample_size, d_sample_flags, *base_offset, decode_ts);
2923 if (stream->pending_seek && moof_offset < stream->pending_seek->moof_offset) {
2924 GST_INFO_OBJECT (stream->pad, "skipping trun before seek target fragment");
2928 /* presence of stss or not can't really tell us much,
2929 * and flags and so on tend to be marginally reliable in these files */
2930 if (stream->subtype == FOURCC_soun) {
2931 GST_DEBUG_OBJECT (qtdemux,
2932 "sound track in fragmented file; marking all keyframes");
2933 stream->all_keyframe = TRUE;
2936 if (!gst_byte_reader_skip (trun, 1) ||
2937 !gst_byte_reader_get_uint24_be (trun, &flags))
2940 if (!gst_byte_reader_get_uint32_be (trun, &samples_count))
2943 if (flags & TR_DATA_OFFSET) {
2944 /* note this is really signed */
2945 if (!gst_byte_reader_get_int32_be (trun, &data_offset))
2947 GST_LOG_OBJECT (qtdemux, "trun data offset %d", data_offset);
2948 /* default base offset = first byte of moof */
2949 if (*base_offset == -1) {
2950 GST_LOG_OBJECT (qtdemux, "base_offset at moof");
2951 *base_offset = moof_offset;
2953 *running_offset = *base_offset + data_offset;
2955 /* if no offset at all, that would mean data starts at moof start,
2956 * which is a bit wrong and is ismv crappy way, so compensate
2957 * assuming data is in mdat following moof */
2958 if (*base_offset == -1) {
2959 *base_offset = moof_offset + moof_length + 8;
2960 GST_LOG_OBJECT (qtdemux, "base_offset assumed in mdat after moof");
2963 if (*running_offset == -1)
2964 *running_offset = *base_offset;
2967 GST_LOG_OBJECT (qtdemux, "running offset now %" G_GINT64_FORMAT,
2969 GST_LOG_OBJECT (qtdemux, "trun offset %d, flags 0x%x, entries %d",
2970 data_offset, flags, samples_count);
2972 if (flags & TR_FIRST_SAMPLE_FLAGS) {
2973 if (G_UNLIKELY (flags & TR_SAMPLE_FLAGS)) {
2974 GST_DEBUG_OBJECT (qtdemux,
2975 "invalid flags; SAMPLE and FIRST_SAMPLE present, discarding latter");
2976 flags ^= TR_FIRST_SAMPLE_FLAGS;
2978 if (!gst_byte_reader_get_uint32_be (trun, &first_flags))
2980 GST_LOG_OBJECT (qtdemux, "first flags: 0x%x", first_flags);
2984 /* FIXME ? spec says other bits should also be checked to determine
2985 * entry size (and prefix size for that matter) */
2987 dur_offset = size_offset = 0;
2988 if (flags & TR_SAMPLE_DURATION) {
2989 GST_LOG_OBJECT (qtdemux, "entry duration present");
2990 dur_offset = entry_size;
2993 if (flags & TR_SAMPLE_SIZE) {
2994 GST_LOG_OBJECT (qtdemux, "entry size present");
2995 size_offset = entry_size;
2998 if (flags & TR_SAMPLE_FLAGS) {
2999 GST_LOG_OBJECT (qtdemux, "entry flags present");
3000 flags_offset = entry_size;
3003 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
3004 GST_LOG_OBJECT (qtdemux, "entry ct offset present");
3005 ct_offset = entry_size;
3009 if (!qt_atom_parser_has_chunks (trun, samples_count, entry_size))
3011 data = (guint8 *) gst_byte_reader_peek_data_unchecked (trun);
3013 if (stream->n_samples + samples_count >=
3014 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample))
3017 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
3018 stream->n_samples + samples_count, (guint) sizeof (QtDemuxSample),
3019 (stream->n_samples + samples_count) *
3020 sizeof (QtDemuxSample) / (1024.0 * 1024.0));
3022 /* create a new array of samples if it's the first sample parsed */
3023 if (stream->n_samples == 0) {
3024 g_assert (stream->samples == NULL);
3025 stream->samples = g_try_new0 (QtDemuxSample, samples_count);
3026 /* or try to reallocate it with space enough to insert the new samples */
3028 stream->samples = g_try_renew (QtDemuxSample, stream->samples,
3029 stream->n_samples + samples_count);
3030 if (stream->samples == NULL)
3033 if (qtdemux->fragment_start != -1) {
3034 timestamp = GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->fragment_start);
3035 qtdemux->fragment_start = -1;
3037 if (stream->n_samples == 0) {
3038 if (decode_ts > 0) {
3039 timestamp = decode_ts;
3040 } else if (stream->pending_seek != NULL) {
3041 /* if we don't have a timestamp from a tfdt box, we'll use the one
3042 * from the mfra seek table */
3043 GST_INFO_OBJECT (stream->pad, "pending seek ts = %" GST_TIME_FORMAT,
3044 GST_TIME_ARGS (stream->pending_seek->ts));
3046 /* FIXME: this is not fully correct, the timestamp refers to the random
3047 * access sample refered to in the tfra entry, which may not necessarily
3048 * be the first sample in the tfrag/trun (but hopefully/usually is) */
3049 timestamp = GSTTIME_TO_QTSTREAMTIME (stream, stream->pending_seek->ts);
3054 gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
3055 GST_INFO_OBJECT (stream->pad, "first sample ts %" GST_TIME_FORMAT,
3056 GST_TIME_ARGS (gst_ts));
3058 /* subsequent fragments extend stream */
3060 stream->samples[stream->n_samples - 1].timestamp +
3061 stream->samples[stream->n_samples - 1].duration;
3063 gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
3064 GST_INFO_OBJECT (qtdemux, "first sample ts %" GST_TIME_FORMAT
3065 " (extends previous samples)", GST_TIME_ARGS (gst_ts));
3069 sample = stream->samples + stream->n_samples;
3070 for (i = 0; i < samples_count; i++) {
3071 guint32 dur, size, sflags, ct;
3073 /* first read sample data */
3074 if (flags & TR_SAMPLE_DURATION) {
3075 dur = QT_UINT32 (data + dur_offset);
3077 dur = d_sample_duration;
3079 if (flags & TR_SAMPLE_SIZE) {
3080 size = QT_UINT32 (data + size_offset);
3082 size = d_sample_size;
3084 if (flags & TR_FIRST_SAMPLE_FLAGS) {
3086 sflags = first_flags;
3088 sflags = d_sample_flags;
3090 } else if (flags & TR_SAMPLE_FLAGS) {
3091 sflags = QT_UINT32 (data + flags_offset);
3093 sflags = d_sample_flags;
3095 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
3096 ct = QT_UINT32 (data + ct_offset);
3102 /* fill the sample information */
3103 sample->offset = *running_offset;
3104 sample->pts_offset = ct;
3105 sample->size = size;
3106 sample->timestamp = timestamp;
3107 sample->duration = dur;
3108 /* sample-is-difference-sample */
3109 /* ismv seems to use 0x40 for keyframe, 0xc0 for non-keyframe,
3110 * now idea how it relates to bitfield other than massive LE/BE confusion */
3111 sample->keyframe = ismv ? ((sflags & 0xff) == 0x40) : !(sflags & 0x10000);
3112 *running_offset += size;
3114 stream->duration_moof += dur;
3118 /* Update total duration if needed */
3119 check_update_duration (qtdemux, QTSTREAMTIME_TO_GSTTIME (stream, timestamp));
3121 stream->n_samples += samples_count;
3122 stream->n_samples_moof += samples_count;
3124 if (stream->pending_seek != NULL)
3125 stream->pending_seek = NULL;
3131 GST_WARNING_OBJECT (qtdemux, "failed to parse trun");
3136 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
3142 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
3143 "be larger than %uMB (broken file?)", stream->n_samples,
3144 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
3149 /* find stream with @id */
3150 static inline QtDemuxStream *
3151 qtdemux_find_stream (GstQTDemux * qtdemux, guint32 id)
3153 QtDemuxStream *stream;
3157 if (G_UNLIKELY (!id)) {
3158 GST_DEBUG_OBJECT (qtdemux, "invalid track id 0");
3162 /* try to get it fast and simple */
3163 if (G_LIKELY (id <= qtdemux->n_streams)) {
3164 stream = qtdemux->streams[id - 1];
3165 if (G_LIKELY (stream->track_id == id))
3169 /* linear search otherwise */
3170 for (i = 0; i < qtdemux->n_streams; i++) {
3171 stream = qtdemux->streams[i];
3172 if (stream->track_id == id)
3175 if (qtdemux->mss_mode) {
3176 /* mss should have only 1 stream anyway */
3177 return qtdemux->streams[0];
3184 qtdemux_parse_mfhd (GstQTDemux * qtdemux, GstByteReader * mfhd,
3185 guint32 * fragment_number)
3187 if (!gst_byte_reader_skip (mfhd, 4))
3189 if (!gst_byte_reader_get_uint32_be (mfhd, fragment_number))
3194 GST_WARNING_OBJECT (qtdemux, "Failed to parse mfhd atom");
3200 qtdemux_parse_tfhd (GstQTDemux * qtdemux, GstByteReader * tfhd,
3201 QtDemuxStream ** stream, guint32 * default_sample_duration,
3202 guint32 * default_sample_size, guint32 * default_sample_flags,
3203 gint64 * base_offset)
3206 guint32 track_id = 0;
3208 if (!gst_byte_reader_skip (tfhd, 1) ||
3209 !gst_byte_reader_get_uint24_be (tfhd, &flags))
3212 if (!gst_byte_reader_get_uint32_be (tfhd, &track_id))
3215 *stream = qtdemux_find_stream (qtdemux, track_id);
3216 if (G_UNLIKELY (!*stream))
3217 goto unknown_stream;
3219 if (flags & TF_DEFAULT_BASE_IS_MOOF)
3220 *base_offset = qtdemux->moof_offset;
3222 if (flags & TF_BASE_DATA_OFFSET)
3223 if (!gst_byte_reader_get_uint64_be (tfhd, (guint64 *) base_offset))
3226 /* obtain stream defaults */
3227 qtdemux_parse_trex (qtdemux, *stream,
3228 default_sample_duration, default_sample_size, default_sample_flags);
3230 /* FIXME: Handle TF_SAMPLE_DESCRIPTION_INDEX properly */
3231 if (flags & TF_SAMPLE_DESCRIPTION_INDEX)
3232 if (!gst_byte_reader_skip (tfhd, 4))
3235 if (flags & TF_DEFAULT_SAMPLE_DURATION)
3236 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_duration))
3239 if (flags & TF_DEFAULT_SAMPLE_SIZE)
3240 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_size))
3243 if (flags & TF_DEFAULT_SAMPLE_FLAGS)
3244 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_flags))
3251 GST_WARNING_OBJECT (qtdemux, "invalid track fragment header");
3256 GST_DEBUG_OBJECT (qtdemux, "unknown stream in tfhd");
3262 qtdemux_parse_tfdt (GstQTDemux * qtdemux, GstByteReader * br,
3263 guint64 * decode_time)
3265 guint32 version = 0;
3267 if (!gst_byte_reader_get_uint32_be (br, &version))
3272 if (!gst_byte_reader_get_uint64_be (br, decode_time))
3275 guint32 dec_time = 0;
3276 if (!gst_byte_reader_get_uint32_be (br, &dec_time))
3278 *decode_time = dec_time;
3281 GST_INFO_OBJECT (qtdemux, "Track fragment decode time: %" G_GUINT64_FORMAT,
3288 GST_DEBUG_OBJECT (qtdemux, "parsing tfdt failed");
3293 /* Returns a pointer to a GstStructure containing the properties of
3294 * the stream sample identified by @sample_index. The caller must unref
3295 * the returned object after use. Returns NULL if unsuccessful. */
3296 static GstStructure *
3297 qtdemux_get_cenc_sample_properties (GstQTDemux * qtdemux,
3298 QtDemuxStream * stream, guint sample_index)
3300 QtDemuxCencSampleSetInfo *info = NULL;
3302 g_return_val_if_fail (stream != NULL, NULL);
3303 g_return_val_if_fail (stream->protected, NULL);
3304 g_return_val_if_fail (stream->protection_scheme_info != NULL, NULL);
3306 info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
3308 /* Currently, cenc properties for groups of samples are not supported, so
3309 * simply return a copy of the default sample properties */
3310 return gst_structure_copy (info->default_properties);
3313 /* Parses the sizes of sample auxiliary information contained within a stream,
3314 * as given in a saiz box. Returns array of sample_count guint8 size values,
3315 * or NULL on failure */
3317 qtdemux_parse_saiz (GstQTDemux * qtdemux, QtDemuxStream * stream,
3318 GstByteReader * br, guint32 * sample_count)
3322 guint8 default_info_size;
3324 g_return_val_if_fail (qtdemux != NULL, NULL);
3325 g_return_val_if_fail (stream != NULL, NULL);
3326 g_return_val_if_fail (br != NULL, NULL);
3327 g_return_val_if_fail (sample_count != NULL, NULL);
3329 if (!gst_byte_reader_get_uint32_be (br, &flags))
3333 /* aux_info_type and aux_info_type_parameter are ignored */
3334 if (!gst_byte_reader_skip (br, 8))
3338 if (!gst_byte_reader_get_uint8 (br, &default_info_size))
3340 GST_DEBUG_OBJECT (qtdemux, "default_info_size: %u", default_info_size);
3342 if (!gst_byte_reader_get_uint32_be (br, sample_count))
3344 GST_DEBUG_OBJECT (qtdemux, "sample_count: %u", *sample_count);
3347 if (default_info_size == 0) {
3348 if (!gst_byte_reader_dup_data (br, *sample_count, &info_sizes)) {
3352 info_sizes = g_new (guint8, *sample_count);
3353 memset (info_sizes, default_info_size, *sample_count);
3359 /* Parses the offset of sample auxiliary information contained within a stream,
3360 * as given in a saio box. Returns TRUE if successful; FALSE otherwise. */
3362 qtdemux_parse_saio (GstQTDemux * qtdemux, QtDemuxStream * stream,
3363 GstByteReader * br, guint32 * info_type, guint32 * info_type_parameter,
3368 guint32 aux_info_type = 0;
3369 guint32 aux_info_type_parameter = 0;
3370 guint32 entry_count;
3373 const guint8 *aux_info_type_data = NULL;
3375 g_return_val_if_fail (qtdemux != NULL, FALSE);
3376 g_return_val_if_fail (stream != NULL, FALSE);
3377 g_return_val_if_fail (br != NULL, FALSE);
3378 g_return_val_if_fail (offset != NULL, FALSE);
3380 if (!gst_byte_reader_get_uint8 (br, &version))
3383 if (!gst_byte_reader_get_uint24_be (br, &flags))
3388 if (!gst_byte_reader_get_data (br, 4, &aux_info_type_data))
3390 aux_info_type = QT_FOURCC (aux_info_type_data);
3392 if (!gst_byte_reader_get_uint32_be (br, &aux_info_type_parameter))
3394 } else if (stream->protected) {
3395 aux_info_type = stream->protection_scheme_type;
3397 aux_info_type = stream->fourcc;
3401 *info_type = aux_info_type;
3402 if (info_type_parameter)
3403 *info_type_parameter = aux_info_type_parameter;
3405 GST_DEBUG_OBJECT (qtdemux, "aux_info_type: '%" GST_FOURCC_FORMAT "', "
3406 "aux_info_type_parameter: %#06x",
3407 GST_FOURCC_ARGS (aux_info_type), aux_info_type_parameter);
3409 if (!gst_byte_reader_get_uint32_be (br, &entry_count))
3412 if (entry_count != 1) {
3413 GST_ERROR_OBJECT (qtdemux, "multiple offsets are not supported");
3418 if (!gst_byte_reader_get_uint32_be (br, &off_32))
3420 *offset = (guint64) off_32;
3422 if (!gst_byte_reader_get_uint64_be (br, &off_64))
3427 GST_DEBUG_OBJECT (qtdemux, "offset: %" G_GUINT64_FORMAT, *offset);
3432 qtdemux_gst_structure_free (GstStructure * gststructure)
3435 gst_structure_free (gststructure);
3439 /* Parses auxiliary information relating to samples protected using Common
3440 * Encryption (cenc); the format of this information is defined in
3441 * ISO/IEC 23001-7. Returns TRUE if successful; FALSE otherwise. */
3443 qtdemux_parse_cenc_aux_info (GstQTDemux * qtdemux, QtDemuxStream * stream,
3444 GstByteReader * br, guint8 * info_sizes, guint32 sample_count)
3446 QtDemuxCencSampleSetInfo *ss_info = NULL;
3450 g_return_val_if_fail (qtdemux != NULL, FALSE);
3451 g_return_val_if_fail (stream != NULL, FALSE);
3452 g_return_val_if_fail (br != NULL, FALSE);
3453 g_return_val_if_fail (stream->protected, FALSE);
3454 g_return_val_if_fail (stream->protection_scheme_info != NULL, FALSE);
3456 ss_info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
3458 if (ss_info->crypto_info) {
3459 GST_LOG_OBJECT (qtdemux, "unreffing existing crypto_info");
3460 g_ptr_array_free (ss_info->crypto_info, TRUE);
3463 ss_info->crypto_info =
3464 g_ptr_array_new_full (sample_count,
3465 (GDestroyNotify) qtdemux_gst_structure_free);
3467 for (i = 0; i < sample_count; ++i) {
3468 GstStructure *properties;
3469 guint16 n_subsamples = 0;
3474 properties = qtdemux_get_cenc_sample_properties (qtdemux, stream, i);
3475 if (properties == NULL) {
3476 GST_ERROR_OBJECT (qtdemux, "failed to get properties for sample %u", i);
3479 if (!gst_structure_get_uint (properties, "iv_size", &iv_size)) {
3480 GST_ERROR_OBJECT (qtdemux, "failed to get iv_size for sample %u", i);
3481 gst_structure_free (properties);
3484 if (!gst_byte_reader_dup_data (br, iv_size, &data)) {
3485 GST_ERROR_OBJECT (qtdemux, "failed to get IV for sample %u", i);
3486 gst_structure_free (properties);
3489 buf = gst_buffer_new_wrapped (data, iv_size);
3490 gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL);
3491 gst_buffer_unref (buf);
3492 size = info_sizes[i];
3493 if (size > iv_size) {
3494 if (!gst_byte_reader_get_uint16_be (br, &n_subsamples)
3495 || !(n_subsamples > 0)) {
3496 gst_structure_free (properties);
3497 GST_ERROR_OBJECT (qtdemux,
3498 "failed to get subsample count for sample %u", i);
3501 GST_LOG_OBJECT (qtdemux, "subsample count: %u", n_subsamples);
3502 if (!gst_byte_reader_dup_data (br, n_subsamples * 6, &data)) {
3503 GST_ERROR_OBJECT (qtdemux, "failed to get subsample data for sample %u",
3505 gst_structure_free (properties);
3508 buf = gst_buffer_new_wrapped (data, n_subsamples * 6);
3510 gst_structure_free (properties);
3513 gst_structure_set (properties,
3514 "subsample_count", G_TYPE_UINT, n_subsamples,
3515 "subsamples", GST_TYPE_BUFFER, buf, NULL);
3516 gst_buffer_unref (buf);
3518 gst_structure_set (properties, "subsample_count", G_TYPE_UINT, 0, NULL);
3520 g_ptr_array_add (ss_info->crypto_info, properties);
3525 /* Converts a UUID in raw byte form to a string representation, as defined in
3526 * RFC 4122. The caller takes ownership of the returned string and is
3527 * responsible for freeing it after use. */
3529 qtdemux_uuid_bytes_to_string (gconstpointer uuid_bytes)
3531 const guint8 *uuid = (const guint8 *) uuid_bytes;
3533 return g_strdup_printf ("%02x%02x%02x%02x-%02x%02x-%02x%02x-"
3534 "%02x%02x-%02x%02x%02x%02x%02x%02x",
3535 uuid[0], uuid[1], uuid[2], uuid[3],
3536 uuid[4], uuid[5], uuid[6], uuid[7],
3537 uuid[8], uuid[9], uuid[10], uuid[11],
3538 uuid[12], uuid[13], uuid[14], uuid[15]);
3541 /* Parses a Protection System Specific Header box (pssh), as defined in the
3542 * Common Encryption (cenc) standard (ISO/IEC 23001-7), which contains
3543 * information needed by a specific content protection system in order to
3544 * decrypt cenc-protected tracks. Returns TRUE if successful; FALSE
3547 qtdemux_parse_pssh (GstQTDemux * qtdemux, GNode * node)
3549 gchar *sysid_string;
3550 guint32 pssh_size = QT_UINT32 (node->data);
3551 GstBuffer *pssh = NULL;
3552 GstEvent *event = NULL;
3553 guint32 parent_box_type;
3556 if (G_UNLIKELY (pssh_size < 32U)) {
3557 GST_ERROR_OBJECT (qtdemux, "invalid box size");
3562 qtdemux_uuid_bytes_to_string ((const guint8 *) node->data + 12);
3564 gst_qtdemux_append_protection_system_id (qtdemux, sysid_string);
3566 pssh = gst_buffer_new_wrapped (g_memdup (node->data, pssh_size), pssh_size);
3567 GST_LOG_OBJECT (qtdemux, "cenc pssh size: %" G_GSIZE_FORMAT,
3568 gst_buffer_get_size (pssh));
3570 parent_box_type = QT_FOURCC ((const guint8 *) node->parent->data + 4);
3572 /* Push an event containing the pssh box onto the queues of all streams. */
3573 event = gst_event_new_protection (sysid_string, pssh,
3574 (parent_box_type == FOURCC_moov) ? "isobmff/moov" : "isobmff/moof");
3575 for (i = 0; i < qtdemux->n_streams; ++i) {
3576 g_queue_push_tail (&qtdemux->streams[i]->protection_scheme_event_queue,
3577 gst_event_ref (event));
3579 g_free (sysid_string);
3580 gst_event_unref (event);
3581 gst_buffer_unref (pssh);
3586 qtdemux_parse_moof (GstQTDemux * qtdemux, const guint8 * buffer, guint length,
3587 guint64 moof_offset, QtDemuxStream * stream)
3589 GNode *moof_node, *traf_node, *tfhd_node, *trun_node, *tfdt_node, *mfhd_node;
3591 GstByteReader mfhd_data, trun_data, tfhd_data, tfdt_data;
3592 GNode *saiz_node, *saio_node, *pssh_node;
3593 GstByteReader saiz_data, saio_data;
3594 guint32 ds_size = 0, ds_duration = 0, ds_flags = 0;
3595 gint64 base_offset, running_offset;
3598 /* NOTE @stream ignored */
3600 moof_node = g_node_new ((guint8 *) buffer);
3601 qtdemux_parse_node (qtdemux, moof_node, buffer, length);
3602 qtdemux_node_dump (qtdemux, moof_node);
3604 /* Get fragment number from mfhd and check it's valid */
3606 qtdemux_tree_get_child_by_type_full (moof_node, FOURCC_mfhd, &mfhd_data);
3607 if (mfhd_node == NULL)
3609 if (!qtdemux_parse_mfhd (qtdemux, &mfhd_data, &frag_num))
3611 GST_DEBUG_OBJECT (qtdemux, "Fragment #%d", frag_num);
3613 /* unknown base_offset to start with */
3614 base_offset = running_offset = -1;
3615 traf_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_traf);
3617 guint64 decode_time = 0;
3619 /* Fragment Header node */
3621 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfhd,
3625 if (!qtdemux_parse_tfhd (qtdemux, &tfhd_data, &stream, &ds_duration,
3626 &ds_size, &ds_flags, &base_offset))
3629 /* The following code assumes at most a single set of sample auxiliary
3630 * data in the fragment (consisting of a saiz box and a corresponding saio
3631 * box); in theory, however, there could be multiple sets of sample
3632 * auxiliary data in a fragment. */
3634 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saiz,
3637 guint32 info_type = 0;
3639 guint32 info_type_parameter = 0;
3641 g_free (qtdemux->cenc_aux_info_sizes);
3643 qtdemux->cenc_aux_info_sizes =
3644 qtdemux_parse_saiz (qtdemux, stream, &saiz_data,
3645 &qtdemux->cenc_aux_sample_count);
3646 if (qtdemux->cenc_aux_info_sizes == NULL) {
3647 GST_ERROR_OBJECT (qtdemux, "failed to parse saiz box");
3651 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saio,
3654 GST_ERROR_OBJECT (qtdemux, "saiz box without a corresponding saio box");
3655 g_free (qtdemux->cenc_aux_info_sizes);
3656 qtdemux->cenc_aux_info_sizes = NULL;
3660 if (G_UNLIKELY (!qtdemux_parse_saio (qtdemux, stream, &saio_data,
3661 &info_type, &info_type_parameter, &offset))) {
3662 GST_ERROR_OBJECT (qtdemux, "failed to parse saio box");
3663 g_free (qtdemux->cenc_aux_info_sizes);
3664 qtdemux->cenc_aux_info_sizes = NULL;
3667 if (base_offset > -1 && base_offset > qtdemux->moof_offset)
3668 offset += (guint64) (base_offset - qtdemux->moof_offset);
3669 if (info_type == FOURCC_cenc && info_type_parameter == 0U) {
3671 if (offset > length) {
3672 GST_DEBUG_OBJECT (qtdemux, "cenc auxiliary info stored out of moof");
3673 qtdemux->cenc_aux_info_offset = offset;
3675 gst_byte_reader_init (&br, buffer + offset, length - offset);
3676 if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
3677 qtdemux->cenc_aux_info_sizes,
3678 qtdemux->cenc_aux_sample_count)) {
3679 GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
3680 g_free (qtdemux->cenc_aux_info_sizes);
3681 qtdemux->cenc_aux_info_sizes = NULL;
3689 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfdt,
3692 GstClockTime decode_time_ts;
3694 /* We'll use decode_time to interpolate timestamps
3695 * in case the input timestamps are missing */
3696 qtdemux_parse_tfdt (qtdemux, &tfdt_data, &decode_time);
3698 decode_time_ts = QTSTREAMTIME_TO_GSTTIME (stream, decode_time);
3700 GST_DEBUG_OBJECT (qtdemux, "decode time %" G_GINT64_FORMAT
3701 " (%" GST_TIME_FORMAT ")", decode_time,
3702 GST_TIME_ARGS (decode_time_ts));
3704 /* Discard the fragment buffer timestamp info to avoid using it.
3705 * Rely on tfdt instead as it is more accurate than the timestamp
3706 * that is fetched from a manifest/playlist and is usually
3708 qtdemux->fragment_start = -1;
3711 if (G_UNLIKELY (!stream)) {
3712 /* we lost track of offset, we'll need to regain it,
3713 * but can delay complaining until later or avoid doing so altogether */
3717 if (G_UNLIKELY (base_offset < -1))
3720 if (qtdemux->upstream_format_is_time)
3721 gst_qtdemux_stream_flush_samples_data (qtdemux, stream);
3723 /* initialise moof sample data */
3724 stream->n_samples_moof = 0;
3725 stream->duration_moof = 0;
3727 /* Track Run node */
3729 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_trun,
3732 qtdemux_parse_trun (qtdemux, &trun_data, stream,
3733 ds_duration, ds_size, ds_flags, moof_offset, length, &base_offset,
3734 &running_offset, decode_time);
3735 /* iterate all siblings */
3736 trun_node = qtdemux_tree_get_sibling_by_type_full (trun_node, FOURCC_trun,
3740 uuid_node = qtdemux_tree_get_child_by_type (traf_node, FOURCC_uuid);
3742 guint8 *uuid_buffer = (guint8 *) uuid_node->data;
3743 guint32 box_length = QT_UINT32 (uuid_buffer);
3745 qtdemux_parse_uuid (qtdemux, uuid_buffer, box_length);
3748 /* if no new base_offset provided for next traf,
3749 * base is end of current traf */
3750 base_offset = running_offset;
3751 running_offset = -1;
3753 if (stream->n_samples_moof && stream->duration_moof)
3754 stream->new_caps = TRUE;
3757 /* iterate all siblings */
3758 traf_node = qtdemux_tree_get_sibling_by_type (traf_node, FOURCC_traf);
3761 /* parse any protection system info */
3762 pssh_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_pssh);
3764 GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
3765 qtdemux_parse_pssh (qtdemux, pssh_node);
3766 pssh_node = qtdemux_tree_get_sibling_by_type (pssh_node, FOURCC_pssh);
3769 g_node_destroy (moof_node);
3774 GST_DEBUG_OBJECT (qtdemux, "missing tfhd box");
3779 GST_DEBUG_OBJECT (qtdemux, "Missing mfhd box");
3784 GST_DEBUG_OBJECT (qtdemux, "lost offset");
3789 g_node_destroy (moof_node);
3790 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
3791 (_("This file is corrupt and cannot be played.")), (NULL));
3797 /* might be used if some day we actually use mfra & co
3798 * for random access to fragments,
3799 * but that will require quite some modifications and much less relying
3800 * on a sample array */
3804 qtdemux_parse_tfra (GstQTDemux * qtdemux, GNode * tfra_node)
3806 QtDemuxStream *stream;
3807 guint32 ver_flags, track_id, len, num_entries, i;
3808 guint value_size, traf_size, trun_size, sample_size;
3809 guint64 time = 0, moof_offset = 0;
3811 GstBuffer *buf = NULL;
3816 gst_byte_reader_init (&tfra, tfra_node->data, QT_UINT32 (tfra_node->data));
3818 if (!gst_byte_reader_skip (&tfra, 8))
3821 if (!gst_byte_reader_get_uint32_be (&tfra, &ver_flags))
3824 if (!gst_byte_reader_get_uint32_be (&tfra, &track_id)
3825 || !gst_byte_reader_get_uint32_be (&tfra, &len)
3826 || !gst_byte_reader_get_uint32_be (&tfra, &num_entries))
3829 GST_DEBUG_OBJECT (qtdemux, "parsing tfra box for track id %u", track_id);
3831 stream = qtdemux_find_stream (qtdemux, track_id);
3833 goto unknown_trackid;
3835 value_size = ((ver_flags >> 24) == 1) ? sizeof (guint64) : sizeof (guint32);
3836 sample_size = (len & 3) + 1;
3837 trun_size = ((len & 12) >> 2) + 1;
3838 traf_size = ((len & 48) >> 4) + 1;
3840 GST_DEBUG_OBJECT (qtdemux, "%u entries, sizes: value %u, traf %u, trun %u, "
3841 "sample %u", num_entries, value_size, traf_size, trun_size, sample_size);
3843 if (num_entries == 0)
3846 if (!qt_atom_parser_has_chunks (&tfra, num_entries,
3847 value_size + value_size + traf_size + trun_size + sample_size))
3850 g_free (stream->ra_entries);
3851 stream->ra_entries = g_new (QtDemuxRandomAccessEntry, num_entries);
3852 stream->n_ra_entries = num_entries;
3854 for (i = 0; i < num_entries; i++) {
3855 qt_atom_parser_get_offset (&tfra, value_size, &time);
3856 qt_atom_parser_get_offset (&tfra, value_size, &moof_offset);
3857 qt_atom_parser_get_uint_with_size_unchecked (&tfra, traf_size);
3858 qt_atom_parser_get_uint_with_size_unchecked (&tfra, trun_size);
3859 qt_atom_parser_get_uint_with_size_unchecked (&tfra, sample_size);
3861 time = QTSTREAMTIME_TO_GSTTIME (stream, time);
3863 GST_LOG_OBJECT (qtdemux, "fragment time: %" GST_TIME_FORMAT ", "
3864 " moof_offset: %" G_GUINT64_FORMAT, GST_TIME_ARGS (time), moof_offset);
3866 stream->ra_entries[i].ts = time;
3867 stream->ra_entries[i].moof_offset = moof_offset;
3869 /* don't want to go through the entire file and read all moofs at startup */
3871 ret = gst_qtdemux_pull_atom (qtdemux, moof_offset, 0, &buf);
3872 if (ret != GST_FLOW_OK)
3874 qtdemux_parse_moof (qtdemux, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf),
3875 moof_offset, stream);
3876 gst_buffer_unref (buf);
3880 check_update_duration (qtdemux, time);
3887 GST_WARNING_OBJECT (qtdemux, "Couldn't find stream for track %u", track_id);
3892 GST_WARNING_OBJECT (qtdemux, "broken traf box, ignoring");
3897 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
3903 qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux)
3905 GstMapInfo mfro_map = GST_MAP_INFO_INIT;
3906 GstMapInfo mfra_map = GST_MAP_INFO_INIT;
3907 GstBuffer *mfro = NULL, *mfra = NULL;
3909 gboolean ret = FALSE;
3910 GNode *mfra_node, *tfra_node;
3911 guint64 mfra_offset = 0;
3912 guint32 fourcc, mfra_size;
3915 /* query upstream size in bytes */
3916 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &len))
3917 goto size_query_failed;
3919 /* mfro box should be at the very end of the file */
3920 flow = gst_qtdemux_pull_atom (qtdemux, len - 16, 16, &mfro);
3921 if (flow != GST_FLOW_OK)
3924 gst_buffer_map (mfro, &mfro_map, GST_MAP_READ);
3926 fourcc = QT_FOURCC (mfro_map.data + 4);
3927 if (fourcc != FOURCC_mfro)
3930 GST_INFO_OBJECT (qtdemux, "Found mfro box");
3931 if (mfro_map.size < 16)
3932 goto invalid_mfro_size;
3934 mfra_size = QT_UINT32 (mfro_map.data + 12);
3935 if (mfra_size >= len)
3936 goto invalid_mfra_size;
3938 mfra_offset = len - mfra_size;
3940 GST_INFO_OBJECT (qtdemux, "mfra offset: %" G_GUINT64_FORMAT ", size %u",
3941 mfra_offset, mfra_size);
3943 /* now get and parse mfra box */
3944 flow = gst_qtdemux_pull_atom (qtdemux, mfra_offset, mfra_size, &mfra);
3945 if (flow != GST_FLOW_OK)
3948 gst_buffer_map (mfra, &mfra_map, GST_MAP_READ);
3950 mfra_node = g_node_new ((guint8 *) mfra_map.data);
3951 qtdemux_parse_node (qtdemux, mfra_node, mfra_map.data, mfra_map.size);
3953 tfra_node = qtdemux_tree_get_child_by_type (mfra_node, FOURCC_tfra);
3956 qtdemux_parse_tfra (qtdemux, tfra_node);
3957 /* iterate all siblings */
3958 tfra_node = qtdemux_tree_get_sibling_by_type (tfra_node, FOURCC_tfra);
3960 g_node_destroy (mfra_node);
3962 GST_INFO_OBJECT (qtdemux, "parsed movie fragment random access box (mfra)");
3968 if (mfro_map.memory != NULL)
3969 gst_buffer_unmap (mfro, &mfro_map);
3970 gst_buffer_unref (mfro);
3973 if (mfra_map.memory != NULL)
3974 gst_buffer_unmap (mfra, &mfra_map);
3975 gst_buffer_unref (mfra);
3982 GST_WARNING_OBJECT (qtdemux, "could not query upstream size");
3987 GST_WARNING_OBJECT (qtdemux, "mfro size is too small");
3992 GST_WARNING_OBJECT (qtdemux, "mfra_size in mfro box is invalid");
3997 GST_WARNING_OBJECT (qtdemux, "bogus mfra offset or size, broken file");
4003 add_offset (guint64 offset, guint64 advance)
4005 /* Avoid 64-bit overflow by clamping */
4006 if (offset > G_MAXUINT64 - advance)
4008 return offset + advance;
4011 static GstFlowReturn
4012 gst_qtdemux_loop_state_header (GstQTDemux * qtdemux)
4016 GstBuffer *buf = NULL;
4017 GstFlowReturn ret = GST_FLOW_OK;
4018 guint64 cur_offset = qtdemux->offset;
4021 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, 16, &buf);
4022 if (G_UNLIKELY (ret != GST_FLOW_OK))
4024 gst_buffer_map (buf, &map, GST_MAP_READ);
4025 if (G_LIKELY (map.size >= 8))
4026 extract_initial_length_and_fourcc (map.data, map.size, &length, &fourcc);
4027 gst_buffer_unmap (buf, &map);
4028 gst_buffer_unref (buf);
4030 /* maybe we already got most we needed, so only consider this eof */
4031 if (G_UNLIKELY (length == 0)) {
4032 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
4033 (_("Invalid atom size.")),
4034 ("Header atom '%" GST_FOURCC_FORMAT "' has empty length",
4035 GST_FOURCC_ARGS (fourcc)));
4042 /* record for later parsing when needed */
4043 if (!qtdemux->moof_offset) {
4044 qtdemux->moof_offset = qtdemux->offset;
4046 if (qtdemux_pull_mfro_mfra (qtdemux)) {
4049 qtdemux->offset += length; /* skip moof and keep going */
4051 if (qtdemux->got_moov) {
4052 GST_INFO_OBJECT (qtdemux, "moof header, got moov, done with headers");
4063 GST_LOG_OBJECT (qtdemux,
4064 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
4065 GST_FOURCC_ARGS (fourcc), cur_offset);
4066 qtdemux->offset = add_offset (qtdemux->offset, length);
4071 GstBuffer *moov = NULL;
4073 if (qtdemux->got_moov) {
4074 GST_DEBUG_OBJECT (qtdemux, "Skipping moov atom as we have one already");
4075 qtdemux->offset = add_offset (qtdemux->offset, length);
4079 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, length, &moov);
4080 if (ret != GST_FLOW_OK)
4082 gst_buffer_map (moov, &map, GST_MAP_READ);
4084 if (length != map.size) {
4085 /* Some files have a 'moov' atom at the end of the file which contains
4086 * a terminal 'free' atom where the body of the atom is missing.
4087 * Check for, and permit, this special case.
4089 if (map.size >= 8) {
4090 guint8 *final_data = map.data + (map.size - 8);
4091 guint32 final_length = QT_UINT32 (final_data);
4092 guint32 final_fourcc = QT_FOURCC (final_data + 4);
4094 if (final_fourcc == FOURCC_free
4095 && map.size + final_length - 8 == length) {
4096 /* Ok, we've found that special case. Allocate a new buffer with
4097 * that free atom actually present. */
4098 GstBuffer *newmoov = gst_buffer_new_and_alloc (length);
4099 gst_buffer_fill (newmoov, 0, map.data, map.size);
4100 gst_buffer_memset (newmoov, map.size, 0, final_length - 8);
4101 gst_buffer_unmap (moov, &map);
4102 gst_buffer_unref (moov);
4104 gst_buffer_map (moov, &map, GST_MAP_READ);
4109 if (length != map.size) {
4110 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4111 (_("This file is incomplete and cannot be played.")),
4112 ("We got less than expected (received %" G_GSIZE_FORMAT
4113 ", wanted %u, offset %" G_GUINT64_FORMAT ")", map.size,
4114 (guint) length, cur_offset));
4115 gst_buffer_unmap (moov, &map);
4116 gst_buffer_unref (moov);
4117 ret = GST_FLOW_ERROR;
4120 qtdemux->offset += length;
4122 qtdemux_parse_moov (qtdemux, map.data, length);
4123 qtdemux_node_dump (qtdemux, qtdemux->moov_node);
4125 qtdemux_parse_tree (qtdemux);
4126 g_node_destroy (qtdemux->moov_node);
4127 gst_buffer_unmap (moov, &map);
4128 gst_buffer_unref (moov);
4129 qtdemux->moov_node = NULL;
4130 qtdemux->got_moov = TRUE;
4136 GstBuffer *ftyp = NULL;
4138 /* extract major brand; might come in handy for ISO vs QT issues */
4139 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &ftyp);
4140 if (ret != GST_FLOW_OK)
4142 qtdemux->offset += length;
4143 gst_buffer_map (ftyp, &map, GST_MAP_READ);
4144 qtdemux_parse_ftyp (qtdemux, map.data, map.size);
4145 gst_buffer_unmap (ftyp, &map);
4146 gst_buffer_unref (ftyp);
4151 GstBuffer *uuid = NULL;
4153 /* uuid are extension atoms */
4154 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &uuid);
4155 if (ret != GST_FLOW_OK)
4157 qtdemux->offset += length;
4158 gst_buffer_map (uuid, &map, GST_MAP_READ);
4159 qtdemux_parse_uuid (qtdemux, map.data, map.size);
4160 gst_buffer_unmap (uuid, &map);
4161 gst_buffer_unref (uuid);
4166 GstBuffer *sidx = NULL;
4167 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &sidx);
4168 if (ret != GST_FLOW_OK)
4170 qtdemux->offset += length;
4171 gst_buffer_map (sidx, &map, GST_MAP_READ);
4172 qtdemux_parse_sidx (qtdemux, map.data, map.size);
4173 gst_buffer_unmap (sidx, &map);
4174 gst_buffer_unref (sidx);
4179 GstBuffer *unknown = NULL;
4181 GST_LOG_OBJECT (qtdemux,
4182 "unknown %08x '%" GST_FOURCC_FORMAT "' of size %" G_GUINT64_FORMAT
4183 " at %" G_GUINT64_FORMAT, fourcc, GST_FOURCC_ARGS (fourcc), length,
4185 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &unknown);
4186 if (ret != GST_FLOW_OK)
4188 gst_buffer_map (unknown, &map, GST_MAP_READ);
4189 GST_MEMDUMP ("Unknown tag", map.data, map.size);
4190 gst_buffer_unmap (unknown, &map);
4191 gst_buffer_unref (unknown);
4192 qtdemux->offset += length;
4198 if (ret == GST_FLOW_EOS && (qtdemux->got_moov || qtdemux->media_caps)) {
4199 /* digested all data, show what we have */
4200 qtdemux_prepare_streams (qtdemux);
4201 ret = qtdemux_expose_streams (qtdemux);
4203 qtdemux->state = QTDEMUX_STATE_MOVIE;
4204 GST_DEBUG_OBJECT (qtdemux, "switching state to STATE_MOVIE (%d)",
4211 /* Seeks to the previous keyframe of the indexed stream and
4212 * aligns other streams with respect to the keyframe timestamp
4213 * of indexed stream. Only called in case of Reverse Playback
4215 static GstFlowReturn
4216 gst_qtdemux_seek_to_previous_keyframe (GstQTDemux * qtdemux)
4219 guint32 seg_idx = 0, k_index = 0;
4220 guint32 ref_seg_idx, ref_k_index;
4221 GstClockTime k_pos = 0, last_stop = 0;
4222 QtDemuxSegment *seg = NULL;
4223 QtDemuxStream *ref_str = NULL;
4224 guint64 seg_media_start_mov; /* segment media start time in mov format */
4227 /* Now we choose an arbitrary stream, get the previous keyframe timestamp
4228 * and finally align all the other streams on that timestamp with their
4229 * respective keyframes */
4230 for (n = 0; n < qtdemux->n_streams; n++) {
4231 QtDemuxStream *str = qtdemux->streams[n];
4233 /* No candidate yet, take the first stream */
4239 /* So that stream has a segment, we prefer video streams */
4240 if (str->subtype == FOURCC_vide) {
4246 if (G_UNLIKELY (!ref_str)) {
4247 GST_DEBUG_OBJECT (qtdemux, "couldn't find any stream");
4251 if (G_UNLIKELY (!ref_str->from_sample)) {
4252 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of the file");
4256 /* So that stream has been playing from from_sample to to_sample. We will
4257 * get the timestamp of the previous sample and search for a keyframe before
4258 * that. For audio streams we do an arbitrary jump in the past (10 samples) */
4259 if (ref_str->subtype == FOURCC_vide) {
4260 k_index = gst_qtdemux_find_keyframe (qtdemux, ref_str,
4261 ref_str->from_sample - 1);
4263 if (ref_str->from_sample >= 10)
4264 k_index = ref_str->from_sample - 10;
4270 ref_str->samples[k_index].timestamp +
4271 ref_str->samples[k_index].pts_offset;
4273 /* get current segment for that stream */
4274 seg = &ref_str->segments[ref_str->segment_index];
4275 /* Use segment start in original timescale for comparisons */
4276 seg_media_start_mov = seg->trak_media_start;
4278 GST_LOG_OBJECT (qtdemux, "keyframe index %u ts %" G_GUINT64_FORMAT
4279 " seg start %" G_GUINT64_FORMAT " %" GST_TIME_FORMAT "\n",
4280 k_index, target_ts, seg_media_start_mov,
4281 GST_TIME_ARGS (seg->media_start));
4283 /* Crawl back through segments to find the one containing this I frame */
4284 while (target_ts < seg_media_start_mov) {
4285 GST_DEBUG_OBJECT (qtdemux,
4286 "keyframe position (sample %u) is out of segment %u " " target %"
4287 G_GUINT64_FORMAT " seg start %" G_GUINT64_FORMAT, k_index,
4288 ref_str->segment_index, target_ts, seg_media_start_mov);
4290 if (G_UNLIKELY (!ref_str->segment_index)) {
4291 /* Reached first segment, let's consider it's EOS */
4294 ref_str->segment_index--;
4295 seg = &ref_str->segments[ref_str->segment_index];
4296 /* Use segment start in original timescale for comparisons */
4297 seg_media_start_mov = seg->trak_media_start;
4299 /* Calculate time position of the keyframe and where we should stop */
4301 QTSTREAMTIME_TO_GSTTIME (ref_str,
4302 target_ts - seg->trak_media_start) + seg->time;
4304 QTSTREAMTIME_TO_GSTTIME (ref_str,
4305 ref_str->samples[ref_str->from_sample].timestamp -
4306 seg->trak_media_start) + seg->time;
4308 GST_DEBUG_OBJECT (qtdemux, "preferred stream played from sample %u, "
4309 "now going to sample %u (pts %" GST_TIME_FORMAT ")", ref_str->from_sample,
4310 k_index, GST_TIME_ARGS (k_pos));
4312 /* Set last_stop with the keyframe timestamp we pushed of that stream */
4313 qtdemux->segment.position = last_stop;
4314 GST_DEBUG_OBJECT (qtdemux, "last_stop now is %" GST_TIME_FORMAT,
4315 GST_TIME_ARGS (last_stop));
4317 if (G_UNLIKELY (last_stop < qtdemux->segment.start)) {
4318 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of segment");
4322 ref_seg_idx = ref_str->segment_index;
4323 ref_k_index = k_index;
4325 /* Align them all on this */
4326 for (n = 0; n < qtdemux->n_streams; n++) {
4328 GstClockTime seg_time = 0;
4329 QtDemuxStream *str = qtdemux->streams[n];
4331 /* aligning reference stream again might lead to backing up to yet another
4332 * keyframe (due to timestamp rounding issues),
4333 * potentially putting more load on downstream; so let's try to avoid */
4334 if (str == ref_str) {
4335 seg_idx = ref_seg_idx;
4336 seg = &str->segments[seg_idx];
4337 k_index = ref_k_index;
4338 GST_DEBUG_OBJECT (qtdemux, "reference stream %d segment %d, "
4339 "sample at index %d", n, ref_str->segment_index, k_index);
4341 seg_idx = gst_qtdemux_find_segment (qtdemux, str, k_pos);
4342 GST_DEBUG_OBJECT (qtdemux,
4343 "stream %d align segment %d for keyframe pos %" GST_TIME_FORMAT, n,
4344 seg_idx, GST_TIME_ARGS (k_pos));
4346 /* get segment and time in the segment */
4347 seg = &str->segments[seg_idx];
4348 seg_time = k_pos - seg->time;
4350 /* get the media time in the segment.
4351 * No adjustment for empty "filler" segments */
4352 if (seg->media_start != GST_CLOCK_TIME_NONE)
4353 seg_time += seg->media_start;
4355 /* get the index of the sample with media time */
4356 index = gst_qtdemux_find_index_linear (qtdemux, str, seg_time);
4357 GST_DEBUG_OBJECT (qtdemux,
4358 "stream %d sample for %" GST_TIME_FORMAT " at %u", n,
4359 GST_TIME_ARGS (seg_time), index);
4361 /* find previous keyframe */
4362 k_index = gst_qtdemux_find_keyframe (qtdemux, str, index);
4365 /* Remember until where we want to go */
4366 str->to_sample = str->from_sample - 1;
4367 /* Define our time position */
4369 str->samples[k_index].timestamp + str->samples[k_index].pts_offset;
4370 str->time_position = QTSTREAMTIME_TO_GSTTIME (str, target_ts) + seg->time;
4371 if (seg->media_start != GST_CLOCK_TIME_NONE)
4372 str->time_position -= seg->media_start;
4374 /* Now seek back in time */
4375 gst_qtdemux_move_stream (qtdemux, str, k_index);
4376 GST_DEBUG_OBJECT (qtdemux, "stream %d keyframe at %u, time position %"
4377 GST_TIME_FORMAT " playing from sample %u to %u", n, k_index,
4378 GST_TIME_ARGS (str->time_position), str->from_sample, str->to_sample);
4384 return GST_FLOW_EOS;
4388 * Gets the current qt segment start, stop and position for the
4389 * given time offset. This is used in update_segment()
4392 gst_qtdemux_stream_segment_get_boundaries (GstQTDemux * qtdemux,
4393 QtDemuxStream * stream, GstClockTime offset,
4394 GstClockTime * _start, GstClockTime * _stop, GstClockTime * _time)
4396 GstClockTime seg_time;
4397 GstClockTime start, stop, time;
4398 QtDemuxSegment *segment;
4400 segment = &stream->segments[stream->segment_index];
4402 /* get time in this segment */
4403 seg_time = (offset - segment->time) * segment->rate;
4405 GST_LOG_OBJECT (stream->pad, "seg_time %" GST_TIME_FORMAT,
4406 GST_TIME_ARGS (seg_time));
4408 if (G_UNLIKELY (seg_time > segment->duration)) {
4409 GST_LOG_OBJECT (stream->pad,
4410 "seg_time > segment->duration %" GST_TIME_FORMAT,
4411 GST_TIME_ARGS (segment->duration));
4412 seg_time = segment->duration;
4415 /* qtdemux->segment.stop is in outside-time-realm, whereas
4416 * segment->media_stop is in track-time-realm.
4418 * In order to compare the two, we need to bring segment.stop
4419 * into the track-time-realm
4421 * FIXME - does this comment still hold? Don't see any conversion here */
4423 stop = qtdemux->segment.stop;
4424 if (stop == GST_CLOCK_TIME_NONE)
4425 stop = qtdemux->segment.duration;
4426 if (stop == GST_CLOCK_TIME_NONE)
4427 stop = segment->media_stop;
4430 MIN (segment->media_stop, stop - segment->time + segment->media_start);
4432 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
4433 start = segment->time + seg_time;
4435 stop = start - seg_time + segment->duration;
4436 } else if (qtdemux->segment.rate >= 0) {
4437 start = MIN (segment->media_start + seg_time, stop);
4440 if (segment->media_start >= qtdemux->segment.start) {
4441 time = segment->time;
4443 time = segment->time + (qtdemux->segment.start - segment->media_start);
4446 start = MAX (segment->media_start, qtdemux->segment.start);
4447 stop = MIN (segment->media_start + seg_time, stop);
4456 * Updates the qt segment used for the stream and pushes a new segment event
4457 * downstream on this stream's pad.
4460 gst_qtdemux_stream_update_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
4461 gint seg_idx, GstClockTime offset, GstClockTime * _start,
4462 GstClockTime * _stop)
4464 QtDemuxSegment *segment;
4465 GstClockTime start = 0, stop = GST_CLOCK_TIME_NONE, time = 0;
4469 /* update the current segment */
4470 stream->segment_index = seg_idx;
4472 /* get the segment */
4473 segment = &stream->segments[seg_idx];
4475 if (G_UNLIKELY (offset < segment->time)) {
4476 GST_WARNING_OBJECT (stream->pad, "offset < segment->time %" GST_TIME_FORMAT,
4477 GST_TIME_ARGS (segment->time));
4481 /* segment lies beyond total indicated duration */
4482 if (G_UNLIKELY (qtdemux->segment.duration != GST_CLOCK_TIME_NONE &&
4483 segment->time > qtdemux->segment.duration)) {
4484 GST_WARNING_OBJECT (stream->pad, "file duration %" GST_TIME_FORMAT
4485 " < segment->time %" GST_TIME_FORMAT,
4486 GST_TIME_ARGS (qtdemux->segment.duration),
4487 GST_TIME_ARGS (segment->time));
4491 gst_qtdemux_stream_segment_get_boundaries (qtdemux, stream, offset,
4492 &start, &stop, &time);
4494 GST_DEBUG_OBJECT (stream->pad, "new segment %d from %" GST_TIME_FORMAT
4495 " to %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT, seg_idx,
4496 GST_TIME_ARGS (start), GST_TIME_ARGS (stop), GST_TIME_ARGS (time));
4498 /* combine global rate with that of the segment */
4499 rate = segment->rate * qtdemux->segment.rate;
4501 /* Copy flags from main segment */
4502 stream->segment.flags = qtdemux->segment.flags;
4504 /* update the segment values used for clipping */
4505 stream->segment.offset = qtdemux->segment.offset;
4506 stream->segment.base = qtdemux->segment.base + stream->accumulated_base;
4507 stream->segment.applied_rate = qtdemux->segment.applied_rate;
4508 stream->segment.rate = rate;
4509 stream->segment.start = start + QTSTREAMTIME_TO_GSTTIME (stream,
4510 stream->cslg_shift);
4511 stream->segment.stop = stop + QTSTREAMTIME_TO_GSTTIME (stream,
4512 stream->cslg_shift);
4513 stream->segment.time = time;
4514 stream->segment.position = stream->segment.start;
4516 GST_DEBUG_OBJECT (stream->pad, "New segment: %" GST_SEGMENT_FORMAT,
4519 /* now prepare and send the segment */
4521 event = gst_event_new_segment (&stream->segment);
4522 if (qtdemux->segment_seqnum) {
4523 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
4525 gst_pad_push_event (stream->pad, event);
4526 /* assume we can send more data now */
4527 GST_PAD_LAST_FLOW_RETURN (stream->pad) = GST_FLOW_OK;
4528 /* clear to send tags on this pad now */
4529 gst_qtdemux_push_tags (qtdemux, stream);
4540 /* activate the given segment number @seg_idx of @stream at time @offset.
4541 * @offset is an absolute global position over all the segments.
4543 * This will push out a NEWSEGMENT event with the right values and
4544 * position the stream index to the first decodable sample before
4548 gst_qtdemux_activate_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
4549 guint32 seg_idx, GstClockTime offset)
4551 QtDemuxSegment *segment;
4552 guint32 index, kf_index;
4553 GstClockTime start = 0, stop = GST_CLOCK_TIME_NONE;
4555 GST_LOG_OBJECT (stream->pad, "activate segment %d, offset %" GST_TIME_FORMAT,
4556 seg_idx, GST_TIME_ARGS (offset));
4558 if (!gst_qtdemux_stream_update_segment (qtdemux, stream, seg_idx, offset,
4562 segment = &stream->segments[stream->segment_index];
4564 /* in the fragmented case, we pick a fragment that starts before our
4565 * desired position and rely on downstream to wait for a keyframe
4566 * (FIXME: doesn't seem to work so well with ismv and wmv, as no parser; the
4567 * tfra entries tells us which trun/sample the key unit is in, but we don't
4568 * make use of this additional information at the moment) */
4569 if (qtdemux->fragmented) {
4570 stream->to_sample = G_MAXUINT32;
4574 /* We don't need to look for a sample in push-based */
4575 if (!qtdemux->pullbased)
4578 /* and move to the keyframe before the indicated media time of the
4580 if (G_LIKELY (!QTSEGMENT_IS_EMPTY (segment))) {
4581 if (qtdemux->segment.rate >= 0) {
4582 index = gst_qtdemux_find_index_linear (qtdemux, stream, start);
4583 stream->to_sample = G_MAXUINT32;
4584 GST_DEBUG_OBJECT (stream->pad,
4585 "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
4586 GST_TIME_FORMAT, GST_TIME_ARGS (start), index,
4587 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
4589 index = gst_qtdemux_find_index_linear (qtdemux, stream, stop);
4590 stream->to_sample = index;
4591 GST_DEBUG_OBJECT (stream->pad,
4592 "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
4593 GST_TIME_FORMAT, GST_TIME_ARGS (stop), index,
4594 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
4597 GST_DEBUG_OBJECT (stream->pad, "No need to look for keyframe, "
4598 "this is an empty segment");
4602 /* gst_qtdemux_parse_sample () called from gst_qtdemux_find_index_linear ()
4603 * encountered an error and printed a message so we return appropriately */
4607 /* we're at the right spot */
4608 if (index == stream->sample_index) {
4609 GST_DEBUG_OBJECT (stream->pad, "we are at the right index");
4613 /* find keyframe of the target index */
4614 kf_index = gst_qtdemux_find_keyframe (qtdemux, stream, index);
4617 /* indent does stupid stuff with stream->samples[].timestamp */
4619 /* if we move forwards, we don't have to go back to the previous
4620 * keyframe since we already sent that. We can also just jump to
4621 * the keyframe right before the target index if there is one. */
4622 if (index > stream->sample_index) {
4623 /* moving forwards check if we move past a keyframe */
4624 if (kf_index > stream->sample_index) {
4625 GST_DEBUG_OBJECT (stream->pad,
4626 "moving forwards to keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" )", kf_index,
4627 GST_TIME_ARGS (QTSAMPLE_PTS(stream, &stream->samples[kf_index])),
4628 GST_TIME_ARGS (QTSAMPLE_DTS(stream, &stream->samples[kf_index])));
4629 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
4631 GST_DEBUG_OBJECT (stream->pad,
4632 "moving forwards, keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" ) already sent", kf_index,
4633 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[kf_index])),
4634 GST_TIME_ARGS (QTSAMPLE_DTS (stream, &stream->samples[kf_index])));
4637 GST_DEBUG_OBJECT (stream->pad,
4638 "moving backwards to keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" )", kf_index,
4639 GST_TIME_ARGS (QTSAMPLE_PTS(stream, &stream->samples[kf_index])),
4640 GST_TIME_ARGS (QTSAMPLE_DTS(stream, &stream->samples[kf_index])));
4641 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
4649 /* prepare to get the current sample of @stream, getting essential values.
4651 * This function will also prepare and send the segment when needed.
4653 * Return FALSE if the stream is EOS.
4658 gst_qtdemux_prepare_current_sample (GstQTDemux * qtdemux,
4659 QtDemuxStream * stream, gboolean * empty, guint64 * offset, guint * size,
4660 GstClockTime * dts, GstClockTime * pts, GstClockTime * duration,
4661 gboolean * keyframe)
4663 QtDemuxSample *sample;
4664 GstClockTime time_position;
4667 g_return_val_if_fail (stream != NULL, FALSE);
4669 time_position = stream->time_position;
4670 if (G_UNLIKELY (time_position == GST_CLOCK_TIME_NONE))
4673 seg_idx = stream->segment_index;
4674 if (G_UNLIKELY (seg_idx == -1)) {
4675 /* find segment corresponding to time_position if we are looking
4677 seg_idx = gst_qtdemux_find_segment (qtdemux, stream, time_position);
4680 /* different segment, activate it, sample_index will be set. */
4681 if (G_UNLIKELY (stream->segment_index != seg_idx))
4682 gst_qtdemux_activate_segment (qtdemux, stream, seg_idx, time_position);
4684 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (&stream->segments[stream->
4686 QtDemuxSegment *seg = &stream->segments[stream->segment_index];
4688 GST_LOG_OBJECT (qtdemux, "Empty segment activated,"
4689 " prepare empty sample");
4692 *pts = *dts = time_position;
4693 *duration = seg->duration - (time_position - seg->time);
4700 if (stream->sample_index == -1)
4701 stream->sample_index = 0;
4703 GST_LOG_OBJECT (qtdemux, "segment active, index = %u of %u",
4704 stream->sample_index, stream->n_samples);
4706 if (G_UNLIKELY (stream->sample_index >= stream->n_samples)) {
4707 if (!qtdemux->fragmented)
4710 GST_INFO_OBJECT (qtdemux, "out of samples, trying to add more");
4714 GST_OBJECT_LOCK (qtdemux);
4715 flow = qtdemux_add_fragmented_samples (qtdemux);
4716 GST_OBJECT_UNLOCK (qtdemux);
4718 if (flow != GST_FLOW_OK)
4721 while (stream->sample_index >= stream->n_samples);
4724 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
4725 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
4726 stream->sample_index);
4730 /* now get the info for the sample we're at */
4731 sample = &stream->samples[stream->sample_index];
4733 *dts = QTSAMPLE_DTS (stream, sample);
4734 *pts = QTSAMPLE_PTS (stream, sample);
4735 *offset = sample->offset;
4736 *size = sample->size;
4737 *duration = QTSAMPLE_DUR_DTS (stream, sample, *dts);
4738 *keyframe = QTSAMPLE_KEYFRAME (stream, sample);
4745 stream->time_position = GST_CLOCK_TIME_NONE;
4750 /* move to the next sample in @stream.
4752 * Moves to the next segment when needed.
4755 gst_qtdemux_advance_sample (GstQTDemux * qtdemux, QtDemuxStream * stream)
4757 QtDemuxSample *sample;
4758 QtDemuxSegment *segment;
4760 /* get current segment */
4761 segment = &stream->segments[stream->segment_index];
4763 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
4764 GST_DEBUG_OBJECT (qtdemux, "Empty segment, no samples to advance");
4768 if (G_UNLIKELY (stream->sample_index >= stream->to_sample)) {
4769 /* Mark the stream as EOS */
4770 GST_DEBUG_OBJECT (qtdemux,
4771 "reached max allowed sample %u, mark EOS", stream->to_sample);
4772 stream->time_position = GST_CLOCK_TIME_NONE;
4776 /* move to next sample */
4777 stream->sample_index++;
4778 stream->offset_in_sample = 0;
4780 /* reached the last sample, we need the next segment */
4781 if (G_UNLIKELY (stream->sample_index >= stream->n_samples))
4784 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
4785 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
4786 stream->sample_index);
4790 /* get next sample */
4791 sample = &stream->samples[stream->sample_index];
4793 /* see if we are past the segment */
4794 if (G_UNLIKELY (QTSAMPLE_DTS (stream, sample) >= segment->media_stop))
4797 if (QTSAMPLE_DTS (stream, sample) >= segment->media_start) {
4798 /* inside the segment, update time_position, looks very familiar to
4799 * GStreamer segments, doesn't it? */
4800 stream->time_position =
4801 QTSAMPLE_DTS (stream, sample) - segment->media_start + segment->time;
4803 /* not yet in segment, time does not yet increment. This means
4804 * that we are still prerolling keyframes to the decoder so it can
4805 * decode the first sample of the segment. */
4806 stream->time_position = segment->time;
4810 /* move to the next segment */
4813 GST_DEBUG_OBJECT (qtdemux, "segment %d ended ", stream->segment_index);
4815 if (stream->segment_index == stream->n_segments - 1) {
4816 /* are we at the end of the last segment, we're EOS */
4817 stream->time_position = GST_CLOCK_TIME_NONE;
4819 /* else we're only at the end of the current segment */
4820 stream->time_position = segment->stop_time;
4822 /* make sure we select a new segment */
4824 /* accumulate previous segments */
4825 if (GST_CLOCK_TIME_IS_VALID (stream->segment.stop))
4826 stream->accumulated_base +=
4827 (stream->segment.stop -
4828 stream->segment.start) / ABS (stream->segment.rate);
4830 stream->segment_index = -1;
4835 gst_qtdemux_sync_streams (GstQTDemux * demux)
4839 if (demux->n_streams <= 1)
4842 for (i = 0; i < demux->n_streams; i++) {
4843 QtDemuxStream *stream;
4844 GstClockTime end_time;
4846 stream = demux->streams[i];
4851 /* TODO advance time on subtitle streams here, if any some day */
4853 /* some clips/trailers may have unbalanced streams at the end,
4854 * so send EOS on shorter stream to prevent stalling others */
4856 /* do not mess with EOS if SEGMENT seeking */
4857 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT)
4860 if (demux->pullbased) {
4861 /* loop mode is sample time based */
4862 if (!STREAM_IS_EOS (stream))
4865 /* push mode is byte position based */
4866 if (stream->n_samples &&
4867 stream->samples[stream->n_samples - 1].offset >= demux->offset)
4871 if (stream->sent_eos)
4874 /* only act if some gap */
4875 end_time = stream->segments[stream->n_segments - 1].stop_time;
4876 GST_LOG_OBJECT (demux, "current position: %" GST_TIME_FORMAT
4877 ", stream end: %" GST_TIME_FORMAT,
4878 GST_TIME_ARGS (demux->segment.position), GST_TIME_ARGS (end_time));
4879 if (GST_CLOCK_TIME_IS_VALID (end_time)
4880 && (end_time + 2 * GST_SECOND < demux->segment.position)) {
4883 GST_DEBUG_OBJECT (demux, "sending EOS for stream %s",
4884 GST_PAD_NAME (stream->pad));
4885 stream->sent_eos = TRUE;
4886 event = gst_event_new_eos ();
4887 if (demux->segment_seqnum)
4888 gst_event_set_seqnum (event, demux->segment_seqnum);
4889 gst_pad_push_event (stream->pad, event);
4894 /* EOS and NOT_LINKED need to be combined. This means that we return:
4896 * GST_FLOW_NOT_LINKED: when all pads NOT_LINKED.
4897 * GST_FLOW_EOS: when all pads EOS or NOT_LINKED.
4899 static GstFlowReturn
4900 gst_qtdemux_combine_flows (GstQTDemux * demux, QtDemuxStream * stream,
4903 GST_LOG_OBJECT (demux, "flow return: %s", gst_flow_get_name (ret));
4906 ret = gst_flow_combiner_update_pad_flow (demux->flowcombiner, stream->pad,
4909 ret = gst_flow_combiner_update_flow (demux->flowcombiner, ret);
4911 GST_LOG_OBJECT (demux, "combined flow return: %s", gst_flow_get_name (ret));
4915 /* the input buffer metadata must be writable. Returns NULL when the buffer is
4916 * completely clipped
4918 * Should be used only with raw buffers */
4920 gst_qtdemux_clip_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
4923 guint64 start, stop, cstart, cstop, diff;
4924 GstClockTime pts, duration;
4926 gint num_rate, denom_rate;
4931 osize = size = gst_buffer_get_size (buf);
4934 /* depending on the type, setup the clip parameters */
4935 if (stream->subtype == FOURCC_soun) {
4936 frame_size = stream->bytes_per_frame;
4937 num_rate = GST_SECOND;
4938 denom_rate = (gint) stream->rate;
4940 } else if (stream->subtype == FOURCC_vide) {
4942 num_rate = stream->fps_n;
4943 denom_rate = stream->fps_d;
4948 if (frame_size <= 0)
4949 goto bad_frame_size;
4951 /* we can only clip if we have a valid pts */
4952 pts = GST_BUFFER_PTS (buf);
4953 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (pts)))
4956 duration = GST_BUFFER_DURATION (buf);
4958 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (duration))) {
4960 gst_util_uint64_scale_int (size / frame_size, num_rate, denom_rate);
4964 stop = start + duration;
4966 if (G_UNLIKELY (!gst_segment_clip (&stream->segment,
4967 GST_FORMAT_TIME, start, stop, &cstart, &cstop)))
4970 /* see if some clipping happened */
4971 diff = cstart - start;
4977 /* bring clipped time to samples and to bytes */
4978 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
4981 GST_DEBUG_OBJECT (qtdemux,
4982 "clipping start to %" GST_TIME_FORMAT " %"
4983 G_GUINT64_FORMAT " bytes", GST_TIME_ARGS (cstart), diff);
4989 diff = stop - cstop;
4994 /* bring clipped time to samples and then to bytes */
4995 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
4997 GST_DEBUG_OBJECT (qtdemux,
4998 "clipping stop to %" GST_TIME_FORMAT " %" G_GUINT64_FORMAT
4999 " bytes", GST_TIME_ARGS (cstop), diff);
5004 if (offset != 0 || size != osize)
5005 gst_buffer_resize (buf, offset, size);
5007 GST_BUFFER_DTS (buf) = GST_CLOCK_TIME_NONE;
5008 GST_BUFFER_PTS (buf) = pts;
5009 GST_BUFFER_DURATION (buf) = duration;
5013 /* dropped buffer */
5016 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
5021 GST_DEBUG_OBJECT (qtdemux, "bad frame size");
5026 GST_DEBUG_OBJECT (qtdemux, "no pts on buffer");
5031 GST_DEBUG_OBJECT (qtdemux, "clipped buffer");
5032 gst_buffer_unref (buf);
5037 /* the input buffer metadata must be writable,
5038 * but time/duration etc not yet set and need not be preserved */
5040 gst_qtdemux_process_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
5047 /* not many cases for now */
5048 if (G_UNLIKELY (stream->fourcc == FOURCC_mp4s)) {
5049 /* send a one time dvd clut event */
5050 if (stream->pending_event && stream->pad)
5051 gst_pad_push_event (stream->pad, stream->pending_event);
5052 stream->pending_event = NULL;
5055 if (G_UNLIKELY (stream->subtype != FOURCC_text
5056 && stream->subtype != FOURCC_sbtl &&
5057 stream->subtype != FOURCC_subp)) {
5061 gst_buffer_map (buf, &map, GST_MAP_READ);
5063 /* empty buffer is sent to terminate previous subtitle */
5064 if (map.size <= 2) {
5065 gst_buffer_unmap (buf, &map);
5066 gst_buffer_unref (buf);
5069 if (stream->subtype == FOURCC_subp) {
5070 /* That's all the processing needed for subpictures */
5071 gst_buffer_unmap (buf, &map);
5075 nsize = GST_READ_UINT16_BE (map.data);
5076 nsize = MIN (nsize, map.size - 2);
5078 GST_LOG_OBJECT (qtdemux, "3GPP timed text subtitle: %d/%" G_GSIZE_FORMAT "",
5081 /* takes care of UTF-8 validation or UTF-16 recognition,
5082 * no other encoding expected */
5083 str = gst_tag_freeform_string_to_utf8 ((gchar *) map.data + 2, nsize, NULL);
5084 gst_buffer_unmap (buf, &map);
5086 gst_buffer_unref (buf);
5087 buf = _gst_buffer_new_wrapped (str, strlen (str), g_free);
5089 /* this should not really happen unless the subtitle is corrupted */
5090 gst_buffer_unref (buf);
5094 /* FIXME ? convert optional subsequent style info to markup */
5099 /* Sets a buffer's attributes properly and pushes it downstream.
5100 * Also checks for additional actions and custom processing that may
5101 * need to be done first.
5103 static GstFlowReturn
5104 gst_qtdemux_decorate_and_push_buffer (GstQTDemux * qtdemux,
5105 QtDemuxStream * stream, GstBuffer * buf,
5106 GstClockTime dts, GstClockTime pts, GstClockTime duration,
5107 gboolean keyframe, GstClockTime position, guint64 byte_position)
5109 GstFlowReturn ret = GST_FLOW_OK;
5111 /* offset the timestamps according to the edit list */
5113 if (G_UNLIKELY (stream->fourcc == FOURCC_rtsp)) {
5117 gst_buffer_map (buf, &map, GST_MAP_READ);
5118 url = g_strndup ((gchar *) map.data, map.size);
5119 gst_buffer_unmap (buf, &map);
5120 if (url != NULL && strlen (url) != 0) {
5121 /* we have RTSP redirect now */
5122 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
5123 gst_message_new_element (GST_OBJECT_CAST (qtdemux),
5124 gst_structure_new ("redirect",
5125 "new-location", G_TYPE_STRING, url, NULL)));
5126 qtdemux->posted_redirect = TRUE;
5128 GST_WARNING_OBJECT (qtdemux, "Redirect URI of stream is empty, not "
5134 /* position reporting */
5135 if (qtdemux->segment.rate >= 0) {
5136 qtdemux->segment.position = position;
5137 gst_qtdemux_sync_streams (qtdemux);
5140 if (G_UNLIKELY (!stream->pad)) {
5141 GST_DEBUG_OBJECT (qtdemux, "No output pad for stream, ignoring");
5142 gst_buffer_unref (buf);
5146 /* send out pending buffers */
5147 while (stream->buffers) {
5148 GstBuffer *buffer = (GstBuffer *) stream->buffers->data;
5150 if (G_UNLIKELY (stream->discont)) {
5151 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
5152 GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
5153 stream->discont = FALSE;
5155 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
5158 gst_pad_push (stream->pad, buffer);
5160 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
5163 /* we're going to modify the metadata */
5164 buf = gst_buffer_make_writable (buf);
5166 if (G_UNLIKELY (stream->need_process))
5167 buf = gst_qtdemux_process_buffer (qtdemux, stream, buf);
5173 GST_BUFFER_DTS (buf) = dts;
5174 GST_BUFFER_PTS (buf) = pts;
5175 GST_BUFFER_DURATION (buf) = duration;
5176 GST_BUFFER_OFFSET (buf) = -1;
5177 GST_BUFFER_OFFSET_END (buf) = -1;
5179 if (G_UNLIKELY (stream->rgb8_palette))
5180 gst_buffer_append_memory (buf, gst_memory_ref (stream->rgb8_palette));
5182 if (G_UNLIKELY (stream->padding)) {
5183 gst_buffer_resize (buf, stream->padding, -1);
5186 if (G_UNLIKELY (qtdemux->element_index)) {
5187 GstClockTime stream_time;
5190 gst_segment_to_stream_time (&stream->segment, GST_FORMAT_TIME,
5192 if (GST_CLOCK_TIME_IS_VALID (stream_time)) {
5193 GST_LOG_OBJECT (qtdemux,
5194 "adding association %" GST_TIME_FORMAT "-> %"
5195 G_GUINT64_FORMAT, GST_TIME_ARGS (stream_time), byte_position);
5196 gst_index_add_association (qtdemux->element_index,
5198 keyframe ? GST_ASSOCIATION_FLAG_KEY_UNIT :
5199 GST_ASSOCIATION_FLAG_DELTA_UNIT, GST_FORMAT_TIME, stream_time,
5200 GST_FORMAT_BYTES, byte_position, NULL);
5205 if (stream->need_clip)
5206 buf = gst_qtdemux_clip_buffer (qtdemux, stream, buf);
5208 if (G_UNLIKELY (buf == NULL))
5211 if (G_UNLIKELY (stream->discont)) {
5212 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
5213 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
5214 stream->discont = FALSE;
5216 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
5220 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
5221 stream->on_keyframe = FALSE;
5223 stream->on_keyframe = TRUE;
5227 GST_LOG_OBJECT (qtdemux,
5228 "Pushing buffer with dts %" GST_TIME_FORMAT ", pts %" GST_TIME_FORMAT
5229 ", duration %" GST_TIME_FORMAT " on pad %s", GST_TIME_ARGS (dts),
5230 GST_TIME_ARGS (pts), GST_TIME_ARGS (duration),
5231 GST_PAD_NAME (stream->pad));
5233 if (stream->protected && stream->protection_scheme_type == FOURCC_cenc) {
5234 GstStructure *crypto_info;
5235 QtDemuxCencSampleSetInfo *info =
5236 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
5240 while ((event = g_queue_pop_head (&stream->protection_scheme_event_queue))) {
5241 gst_pad_push_event (stream->pad, event);
5244 if (qtdemux->cenc_aux_info_offset > 0 && info->crypto_info == NULL) {
5245 GST_DEBUG_OBJECT (qtdemux, "cenc metadata hasn't been parsed yet");
5246 gst_buffer_unref (buf);
5250 index = stream->sample_index - (stream->n_samples - info->crypto_info->len);
5251 if (G_LIKELY (index >= 0 && index < info->crypto_info->len)) {
5252 /* steal structure from array */
5253 crypto_info = g_ptr_array_index (info->crypto_info, index);
5254 g_ptr_array_index (info->crypto_info, index) = NULL;
5255 GST_LOG_OBJECT (qtdemux, "attaching cenc metadata [%u]", index);
5256 if (!crypto_info || !gst_buffer_add_protection_meta (buf, crypto_info))
5257 GST_ERROR_OBJECT (qtdemux, "failed to attach cenc metadata to buffer");
5261 ret = gst_pad_push (stream->pad, buf);
5263 if (GST_CLOCK_TIME_IS_VALID (pts) && GST_CLOCK_TIME_IS_VALID (duration)) {
5264 /* mark position in stream, we'll need this to know when to send GAP event */
5265 stream->segment.position = pts + duration;
5272 static const QtDemuxRandomAccessEntry *
5273 gst_qtdemux_stream_seek_fragment (GstQTDemux * qtdemux, QtDemuxStream * stream,
5274 GstClockTime pos, gboolean after)
5276 QtDemuxRandomAccessEntry *entries = stream->ra_entries;
5277 guint n_entries = stream->n_ra_entries;
5280 /* we assume the table is sorted */
5281 for (i = 0; i < n_entries; ++i) {
5282 if (entries[i].ts > pos)
5286 /* FIXME: maybe save first moof_offset somewhere instead, but for now it's
5287 * probably okay to assume that the index lists the very first fragment */
5294 return &entries[i - 1];
5298 gst_qtdemux_do_fragmented_seek (GstQTDemux * qtdemux)
5300 const QtDemuxRandomAccessEntry *best_entry = NULL;
5303 GST_OBJECT_LOCK (qtdemux);
5305 g_assert (qtdemux->n_streams > 0);
5307 for (i = 0; i < qtdemux->n_streams; i++) {
5308 const QtDemuxRandomAccessEntry *entry;
5309 QtDemuxStream *stream;
5310 gboolean is_audio_or_video;
5312 stream = qtdemux->streams[i];
5314 g_free (stream->samples);
5315 stream->samples = NULL;
5316 stream->n_samples = 0;
5317 stream->stbl_index = -1; /* no samples have yet been parsed */
5318 stream->sample_index = -1;
5320 if (stream->ra_entries == NULL)
5323 if (stream->subtype == FOURCC_vide || stream->subtype == FOURCC_soun)
5324 is_audio_or_video = TRUE;
5326 is_audio_or_video = FALSE;
5329 gst_qtdemux_stream_seek_fragment (qtdemux, stream,
5330 stream->time_position, !is_audio_or_video);
5332 GST_INFO_OBJECT (stream->pad, "%" GST_TIME_FORMAT " at offset "
5333 "%" G_GUINT64_FORMAT, GST_TIME_ARGS (entry->ts), entry->moof_offset);
5335 stream->pending_seek = entry;
5337 /* decide position to jump to just based on audio/video tracks, not subs */
5338 if (!is_audio_or_video)
5341 if (best_entry == NULL || entry->moof_offset < best_entry->moof_offset)
5345 if (best_entry == NULL) {
5346 GST_OBJECT_UNLOCK (qtdemux);
5350 GST_INFO_OBJECT (qtdemux, "seek to %" GST_TIME_FORMAT ", best fragment "
5351 "moof offset: %" G_GUINT64_FORMAT ", ts %" GST_TIME_FORMAT,
5352 GST_TIME_ARGS (qtdemux->streams[0]->time_position),
5353 best_entry->moof_offset, GST_TIME_ARGS (best_entry->ts));
5355 qtdemux->moof_offset = best_entry->moof_offset;
5357 qtdemux_add_fragmented_samples (qtdemux);
5359 GST_OBJECT_UNLOCK (qtdemux);
5363 static GstFlowReturn
5364 gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux)
5366 GstFlowReturn ret = GST_FLOW_OK;
5367 GstBuffer *buf = NULL;
5368 QtDemuxStream *stream;
5369 GstClockTime min_time;
5371 GstClockTime dts = GST_CLOCK_TIME_NONE;
5372 GstClockTime pts = GST_CLOCK_TIME_NONE;
5373 GstClockTime duration = 0;
5374 gboolean keyframe = FALSE;
5375 guint sample_size = 0;
5381 gst_qtdemux_push_pending_newsegment (qtdemux);
5383 if (qtdemux->fragmented_seek_pending) {
5384 GST_INFO_OBJECT (qtdemux, "pending fragmented seek");
5385 gst_qtdemux_do_fragmented_seek (qtdemux);
5386 GST_INFO_OBJECT (qtdemux, "fragmented seek done!");
5387 qtdemux->fragmented_seek_pending = FALSE;
5390 /* Figure out the next stream sample to output, min_time is expressed in
5391 * global time and runs over the edit list segments. */
5392 min_time = G_MAXUINT64;
5394 for (i = 0; i < qtdemux->n_streams; i++) {
5395 GstClockTime position;
5397 stream = qtdemux->streams[i];
5398 position = stream->time_position;
5400 /* position of -1 is EOS */
5401 if (position != GST_CLOCK_TIME_NONE && position < min_time) {
5402 min_time = position;
5407 if (G_UNLIKELY (index == -1)) {
5408 GST_DEBUG_OBJECT (qtdemux, "all streams are EOS");
5412 /* check for segment end */
5413 if (G_UNLIKELY (qtdemux->segment.stop != -1
5414 && ((qtdemux->segment.rate >= 0 && qtdemux->segment.stop <= min_time)
5415 || (qtdemux->segment.rate < 0
5416 && qtdemux->segment.start > min_time))
5417 && qtdemux->streams[index]->on_keyframe)) {
5418 GST_DEBUG_OBJECT (qtdemux, "we reached the end of our segment.");
5419 qtdemux->streams[index]->time_position = GST_CLOCK_TIME_NONE;
5423 /* gap events for subtitle streams */
5424 for (i = 0; i < qtdemux->n_streams; i++) {
5425 stream = qtdemux->streams[i];
5426 if (stream->pad && (stream->subtype == FOURCC_subp
5427 || stream->subtype == FOURCC_text
5428 || stream->subtype == FOURCC_sbtl)) {
5429 /* send one second gap events until the stream catches up */
5430 /* gaps can only be sent after segment is activated (segment.stop is no longer -1) */
5431 while (GST_CLOCK_TIME_IS_VALID (stream->segment.stop) &&
5432 GST_CLOCK_TIME_IS_VALID (stream->segment.position) &&
5433 stream->segment.position + GST_SECOND < min_time) {
5435 gst_event_new_gap (stream->segment.position, GST_SECOND);
5436 gst_pad_push_event (stream->pad, gap);
5437 stream->segment.position += GST_SECOND;
5442 stream = qtdemux->streams[index];
5443 if (stream->new_caps) {
5444 gst_qtdemux_configure_stream (qtdemux, stream);
5445 qtdemux_do_allocation (qtdemux, stream);
5448 /* fetch info for the current sample of this stream */
5449 if (G_UNLIKELY (!gst_qtdemux_prepare_current_sample (qtdemux, stream, &empty,
5450 &offset, &sample_size, &dts, &pts, &duration, &keyframe)))
5453 /* If we're doing a keyframe-only trickmode, only push keyframes on video streams */
5454 if (G_UNLIKELY (qtdemux->
5455 segment.flags & GST_SEGMENT_FLAG_TRICKMODE_KEY_UNITS)) {
5456 if (stream->subtype == FOURCC_vide && !keyframe) {
5457 GST_LOG_OBJECT (qtdemux, "Skipping non-keyframe on stream %d", index);
5462 GST_DEBUG_OBJECT (qtdemux,
5463 "pushing from stream %d, empty %d offset %" G_GUINT64_FORMAT
5464 ", size %d, dts=%" GST_TIME_FORMAT ", pts=%" GST_TIME_FORMAT
5465 ", duration %" GST_TIME_FORMAT, index, empty, offset, sample_size,
5466 GST_TIME_ARGS (dts), GST_TIME_ARGS (pts), GST_TIME_ARGS (duration));
5468 if (G_UNLIKELY (empty)) {
5469 /* empty segment, push a gap and move to the next one */
5470 gst_pad_push_event (stream->pad, gst_event_new_gap (pts, duration));
5471 stream->segment.position = pts + duration;
5475 /* hmm, empty sample, skip and move to next sample */
5476 if (G_UNLIKELY (sample_size <= 0))
5479 /* last pushed sample was out of boundary, goto next sample */
5480 if (G_UNLIKELY (GST_PAD_LAST_FLOW_RETURN (stream->pad) == GST_FLOW_EOS))
5483 if (stream->max_buffer_size == 0 || sample_size <= stream->max_buffer_size) {
5486 GST_DEBUG_OBJECT (qtdemux,
5487 "size %d larger than stream max_buffer_size %d, trimming",
5488 sample_size, stream->max_buffer_size);
5490 MIN (sample_size - stream->offset_in_sample, stream->max_buffer_size);
5493 if (qtdemux->cenc_aux_info_offset > 0) {
5496 GstBuffer *aux_info = NULL;
5498 /* pull the data stored before the sample */
5500 gst_qtdemux_pull_atom (qtdemux, qtdemux->offset,
5501 offset + stream->offset_in_sample - qtdemux->offset, &aux_info);
5502 if (G_UNLIKELY (ret != GST_FLOW_OK))
5504 gst_buffer_map (aux_info, &map, GST_MAP_READ);
5505 GST_DEBUG_OBJECT (qtdemux, "parsing cenc auxiliary info");
5506 gst_byte_reader_init (&br, map.data + 8, map.size);
5507 if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
5508 qtdemux->cenc_aux_info_sizes, qtdemux->cenc_aux_sample_count)) {
5509 GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
5510 gst_buffer_unmap (aux_info, &map);
5511 gst_buffer_unref (aux_info);
5512 ret = GST_FLOW_ERROR;
5515 gst_buffer_unmap (aux_info, &map);
5516 gst_buffer_unref (aux_info);
5519 GST_LOG_OBJECT (qtdemux, "reading %d bytes @ %" G_GUINT64_FORMAT, size,
5522 if (stream->use_allocator) {
5523 /* if we have a per-stream allocator, use it */
5524 buf = gst_buffer_new_allocate (stream->allocator, size, &stream->params);
5527 ret = gst_qtdemux_pull_atom (qtdemux, offset + stream->offset_in_sample,
5529 if (G_UNLIKELY (ret != GST_FLOW_OK))
5532 if (size != sample_size) {
5533 pts += gst_util_uint64_scale_int (GST_SECOND,
5534 stream->offset_in_sample / stream->bytes_per_frame, stream->timescale);
5535 dts += gst_util_uint64_scale_int (GST_SECOND,
5536 stream->offset_in_sample / stream->bytes_per_frame, stream->timescale);
5537 duration = gst_util_uint64_scale_int (GST_SECOND,
5538 size / stream->bytes_per_frame, stream->timescale);
5541 ret = gst_qtdemux_decorate_and_push_buffer (qtdemux, stream, buf,
5542 dts, pts, duration, keyframe, min_time, offset);
5544 if (size != sample_size) {
5545 QtDemuxSample *sample = &stream->samples[stream->sample_index];
5546 QtDemuxSegment *segment = &stream->segments[stream->segment_index];
5548 GstClockTime time_position = QTSTREAMTIME_TO_GSTTIME (stream,
5549 sample->timestamp + stream->offset_in_sample / stream->bytes_per_frame);
5550 if (time_position >= segment->media_start) {
5551 /* inside the segment, update time_position, looks very familiar to
5552 * GStreamer segments, doesn't it? */
5553 stream->time_position = (time_position - segment->media_start) +
5556 /* not yet in segment, time does not yet increment. This means
5557 * that we are still prerolling keyframes to the decoder so it can
5558 * decode the first sample of the segment. */
5559 stream->time_position = segment->time;
5564 ret = gst_qtdemux_combine_flows (qtdemux, stream, ret);
5565 /* ignore unlinked, we will not push on the pad anymore and we will EOS when
5566 * we have no more data for the pad to push */
5567 if (ret == GST_FLOW_EOS)
5570 stream->offset_in_sample += size;
5571 if (stream->offset_in_sample >= sample_size) {
5572 gst_qtdemux_advance_sample (qtdemux, stream);
5577 gst_qtdemux_advance_sample (qtdemux, stream);
5585 GST_DEBUG_OBJECT (qtdemux, "No samples left for any streams - EOS");
5591 GST_DEBUG_OBJECT (qtdemux, "No samples left for stream");
5592 /* EOS will be raised if all are EOS */
5599 gst_qtdemux_loop (GstPad * pad)
5601 GstQTDemux *qtdemux;
5605 qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
5607 cur_offset = qtdemux->offset;
5608 GST_LOG_OBJECT (qtdemux, "loop at position %" G_GUINT64_FORMAT ", state %d",
5609 cur_offset, qtdemux->state);
5611 switch (qtdemux->state) {
5612 case QTDEMUX_STATE_INITIAL:
5613 case QTDEMUX_STATE_HEADER:
5614 ret = gst_qtdemux_loop_state_header (qtdemux);
5616 case QTDEMUX_STATE_MOVIE:
5617 ret = gst_qtdemux_loop_state_movie (qtdemux);
5618 if (qtdemux->segment.rate < 0 && ret == GST_FLOW_EOS) {
5619 ret = gst_qtdemux_seek_to_previous_keyframe (qtdemux);
5627 /* if something went wrong, pause */
5628 if (ret != GST_FLOW_OK)
5632 gst_object_unref (qtdemux);
5638 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
5639 (NULL), ("streaming stopped, invalid state"));
5640 gst_pad_pause_task (pad);
5641 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
5646 const gchar *reason = gst_flow_get_name (ret);
5648 GST_LOG_OBJECT (qtdemux, "pausing task, reason %s", reason);
5650 gst_pad_pause_task (pad);
5652 /* fatal errors need special actions */
5654 if (ret == GST_FLOW_EOS) {
5655 if (qtdemux->n_streams == 0) {
5656 /* we have no streams, post an error */
5657 gst_qtdemux_post_no_playable_stream_error (qtdemux);
5659 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
5662 if ((stop = qtdemux->segment.stop) == -1)
5663 stop = qtdemux->segment.duration;
5665 if (qtdemux->segment.rate >= 0) {
5666 GstMessage *message;
5669 GST_LOG_OBJECT (qtdemux, "Sending segment done, at end of segment");
5670 message = gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
5671 GST_FORMAT_TIME, stop);
5672 event = gst_event_new_segment_done (GST_FORMAT_TIME, stop);
5673 if (qtdemux->segment_seqnum) {
5674 gst_message_set_seqnum (message, qtdemux->segment_seqnum);
5675 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
5677 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), message);
5678 gst_qtdemux_push_event (qtdemux, event);
5680 GstMessage *message;
5683 /* For Reverse Playback */
5684 GST_LOG_OBJECT (qtdemux, "Sending segment done, at start of segment");
5685 message = gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
5686 GST_FORMAT_TIME, qtdemux->segment.start);
5687 event = gst_event_new_segment_done (GST_FORMAT_TIME,
5688 qtdemux->segment.start);
5689 if (qtdemux->segment_seqnum) {
5690 gst_message_set_seqnum (message, qtdemux->segment_seqnum);
5691 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
5693 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), message);
5694 gst_qtdemux_push_event (qtdemux, event);
5699 GST_LOG_OBJECT (qtdemux, "Sending EOS at end of segment");
5700 event = gst_event_new_eos ();
5701 if (qtdemux->segment_seqnum)
5702 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
5703 gst_qtdemux_push_event (qtdemux, event);
5705 } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
5706 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
5707 (NULL), ("streaming stopped, reason %s", reason));
5708 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
5717 * Returns if there are samples to be played.
5720 has_next_entry (GstQTDemux * demux)
5722 QtDemuxStream *stream;
5725 GST_DEBUG_OBJECT (demux, "Checking if there are samples not played yet");
5727 for (i = 0; i < demux->n_streams; i++) {
5728 stream = demux->streams[i];
5730 if (stream->sample_index == -1) {
5731 stream->sample_index = 0;
5732 stream->offset_in_sample = 0;
5735 if (stream->sample_index >= stream->n_samples) {
5736 GST_LOG_OBJECT (demux, "stream %d samples exhausted", i);
5739 GST_DEBUG_OBJECT (demux, "Found a sample");
5743 GST_DEBUG_OBJECT (demux, "There wasn't any next sample");
5750 * Returns the size of the first entry at the current offset.
5751 * If -1, there are none (which means EOS or empty file).
5754 next_entry_size (GstQTDemux * demux)
5756 QtDemuxStream *stream;
5759 guint64 smalloffs = (guint64) - 1;
5760 QtDemuxSample *sample;
5762 GST_LOG_OBJECT (demux, "Finding entry at offset %" G_GUINT64_FORMAT,
5765 for (i = 0; i < demux->n_streams; i++) {
5766 stream = demux->streams[i];
5768 if (stream->sample_index == -1) {
5769 stream->sample_index = 0;
5770 stream->offset_in_sample = 0;
5773 if (stream->sample_index >= stream->n_samples) {
5774 GST_LOG_OBJECT (demux, "stream %d samples exhausted", i);
5778 if (!qtdemux_parse_samples (demux, stream, stream->sample_index)) {
5779 GST_LOG_OBJECT (demux, "Parsing of index %u from stbl atom failed!",
5780 stream->sample_index);
5784 sample = &stream->samples[stream->sample_index];
5786 GST_LOG_OBJECT (demux,
5787 "Checking Stream %d (sample_index:%d / offset:%" G_GUINT64_FORMAT
5788 " / size:%" G_GUINT32_FORMAT ")", i, stream->sample_index,
5789 sample->offset, sample->size);
5791 if (((smalloffs == -1)
5792 || (sample->offset < smalloffs)) && (sample->size)) {
5794 smalloffs = sample->offset;
5798 GST_LOG_OBJECT (demux,
5799 "stream %d offset %" G_GUINT64_FORMAT " demux->offset :%"
5800 G_GUINT64_FORMAT, smallidx, smalloffs, demux->offset);
5805 stream = demux->streams[smallidx];
5806 sample = &stream->samples[stream->sample_index];
5808 if (sample->offset >= demux->offset) {
5809 demux->todrop = sample->offset - demux->offset;
5810 return sample->size + demux->todrop;
5813 GST_DEBUG_OBJECT (demux,
5814 "There wasn't any entry at offset %" G_GUINT64_FORMAT, demux->offset);
5819 gst_qtdemux_post_progress (GstQTDemux * demux, gint num, gint denom)
5821 gint perc = (gint) ((gdouble) num * 100.0 / (gdouble) denom);
5823 gst_element_post_message (GST_ELEMENT_CAST (demux),
5824 gst_message_new_element (GST_OBJECT_CAST (demux),
5825 gst_structure_new ("progress", "percent", G_TYPE_INT, perc, NULL)));
5829 qtdemux_seek_offset (GstQTDemux * demux, guint64 offset)
5834 GST_DEBUG_OBJECT (demux, "Seeking to %" G_GUINT64_FORMAT, offset);
5837 gst_event_new_seek (1.0, GST_FORMAT_BYTES,
5838 GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset,
5839 GST_SEEK_TYPE_NONE, -1);
5841 /* store seqnum to drop flush events, they don't need to reach downstream */
5842 demux->offset_seek_seqnum = gst_event_get_seqnum (event);
5843 res = gst_pad_push_event (demux->sinkpad, event);
5844 demux->offset_seek_seqnum = 0;
5849 /* check for seekable upstream, above and beyond a mere query */
5851 gst_qtdemux_check_seekability (GstQTDemux * demux)
5854 gboolean seekable = FALSE;
5855 gint64 start = -1, stop = -1;
5857 if (demux->upstream_size)
5860 query = gst_query_new_seeking (GST_FORMAT_BYTES);
5861 if (!gst_pad_peer_query (demux->sinkpad, query)) {
5862 GST_DEBUG_OBJECT (demux, "seeking query failed");
5866 gst_query_parse_seeking (query, NULL, &seekable, &start, &stop);
5868 /* try harder to query upstream size if we didn't get it the first time */
5869 if (seekable && stop == -1) {
5870 GST_DEBUG_OBJECT (demux, "doing duration query to fix up unset stop");
5871 gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &stop);
5874 /* if upstream doesn't know the size, it's likely that it's not seekable in
5875 * practice even if it technically may be seekable */
5876 if (seekable && (start != 0 || stop <= start)) {
5877 GST_DEBUG_OBJECT (demux, "seekable but unknown start/stop -> disable");
5882 gst_query_unref (query);
5884 GST_DEBUG_OBJECT (demux, "seekable: %d (%" G_GUINT64_FORMAT " - %"
5885 G_GUINT64_FORMAT ")", seekable, start, stop);
5886 demux->upstream_seekable = seekable;
5887 demux->upstream_size = seekable ? stop : -1;
5891 gst_qtdemux_drop_data (GstQTDemux * demux, gint bytes)
5893 g_return_if_fail (bytes <= demux->todrop);
5895 GST_LOG_OBJECT (demux, "Dropping %d bytes", bytes);
5896 gst_adapter_flush (demux->adapter, bytes);
5897 demux->neededbytes -= bytes;
5898 demux->offset += bytes;
5899 demux->todrop -= bytes;
5903 gst_qtdemux_check_send_pending_segment (GstQTDemux * demux)
5905 if (G_UNLIKELY (demux->pending_newsegment)) {
5908 gst_qtdemux_push_pending_newsegment (demux);
5909 /* clear to send tags on all streams */
5910 for (i = 0; i < demux->n_streams; i++) {
5911 QtDemuxStream *stream;
5912 stream = demux->streams[i];
5913 gst_qtdemux_push_tags (demux, stream);
5914 if (stream->sparse) {
5915 GST_INFO_OBJECT (demux, "Sending gap event on stream %d", i);
5916 gst_pad_push_event (stream->pad,
5917 gst_event_new_gap (stream->segment.position, GST_CLOCK_TIME_NONE));
5924 gst_qtdemux_stream_send_initial_gap_segments (GstQTDemux * demux,
5925 QtDemuxStream * stream)
5929 /* Push any initial gap segments before proceeding to the
5931 for (i = 0; i < stream->n_segments; i++) {
5932 gst_qtdemux_activate_segment (demux, stream, i, stream->time_position);
5934 if (QTSEGMENT_IS_EMPTY (&stream->segments[i])) {
5935 GstClockTime ts, dur;
5938 ts = stream->time_position;
5940 stream->segments[i].duration - (stream->time_position -
5941 stream->segments[i].time);
5942 gap = gst_event_new_gap (ts, dur);
5943 stream->time_position += dur;
5945 GST_DEBUG_OBJECT (stream->pad, "Pushing gap for empty "
5946 "segment: %" GST_PTR_FORMAT, gap);
5947 gst_pad_push_event (stream->pad, gap);
5949 /* Only support empty segment at the beginning followed by
5950 * one non-empty segment, this was checked when parsing the
5951 * edts atom, arriving here is unexpected */
5952 g_assert (i + 1 == stream->n_segments);
5958 static GstFlowReturn
5959 gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent, GstBuffer * inbuf)
5963 demux = GST_QTDEMUX (parent);
5965 if (GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_DISCONT)) {
5968 GST_DEBUG_OBJECT (demux, "Got DISCONT, marking all streams as DISCONT");
5970 for (i = 0; i < demux->n_streams; i++) {
5971 demux->streams[i]->discont = TRUE;
5974 /* Reverse fragmented playback, need to flush all we have before
5975 * consuming a new fragment.
5976 * The samples array have the timestamps calculated by accumulating the
5977 * durations but this won't work for reverse playback of fragments as
5978 * the timestamps of a subsequent fragment should be smaller than the
5979 * previously received one. */
5980 if (demux->fragmented && demux->segment.rate < 0) {
5981 gst_qtdemux_process_adapter (demux, TRUE);
5982 for (i = 0; i < demux->n_streams; i++)
5983 gst_qtdemux_stream_flush_samples_data (demux, demux->streams[i]);
5987 gst_adapter_push (demux->adapter, inbuf);
5989 GST_DEBUG_OBJECT (demux,
5990 "pushing in inbuf %p, neededbytes:%u, available:%" G_GSIZE_FORMAT, inbuf,
5991 demux->neededbytes, gst_adapter_available (demux->adapter));
5993 return gst_qtdemux_process_adapter (demux, FALSE);
5996 static GstFlowReturn
5997 gst_qtdemux_process_adapter (GstQTDemux * demux, gboolean force)
5999 GstFlowReturn ret = GST_FLOW_OK;
6001 /* we never really mean to buffer that much */
6002 if (demux->neededbytes == -1) {
6006 while (((gst_adapter_available (demux->adapter)) >= demux->neededbytes) &&
6007 (ret == GST_FLOW_OK || (ret == GST_FLOW_NOT_LINKED && force))) {
6009 GST_DEBUG_OBJECT (demux,
6010 "state:%d , demux->neededbytes:%d, demux->offset:%" G_GUINT64_FORMAT,
6011 demux->state, demux->neededbytes, demux->offset);
6013 switch (demux->state) {
6014 case QTDEMUX_STATE_INITIAL:{
6019 gst_qtdemux_check_seekability (demux);
6021 data = gst_adapter_map (demux->adapter, demux->neededbytes);
6023 /* get fourcc/length, set neededbytes */
6024 extract_initial_length_and_fourcc ((guint8 *) data, demux->neededbytes,
6026 gst_adapter_unmap (demux->adapter);
6028 GST_DEBUG_OBJECT (demux, "Peeking found [%" GST_FOURCC_FORMAT "] "
6029 "size: %" G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), size);
6031 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
6032 (_("This file is invalid and cannot be played.")),
6033 ("initial atom '%" GST_FOURCC_FORMAT "' has empty length",
6034 GST_FOURCC_ARGS (fourcc)));
6035 ret = GST_FLOW_ERROR;
6038 if (fourcc == FOURCC_mdat) {
6039 gint next_entry = next_entry_size (demux);
6040 if (demux->n_streams > 0 && (next_entry != -1 || !demux->fragmented)) {
6041 /* we have the headers, start playback */
6042 demux->state = QTDEMUX_STATE_MOVIE;
6043 demux->neededbytes = next_entry;
6044 demux->mdatleft = size;
6046 /* no headers yet, try to get them */
6049 guint64 old, target;
6052 old = demux->offset;
6053 target = old + size;
6055 /* try to jump over the atom with a seek */
6056 /* only bother if it seems worth doing so,
6057 * and avoids possible upstream/server problems */
6058 if (demux->upstream_seekable &&
6059 demux->upstream_size > 4 * (1 << 20)) {
6060 res = qtdemux_seek_offset (demux, target);
6062 GST_DEBUG_OBJECT (demux, "skipping seek");
6067 GST_DEBUG_OBJECT (demux, "seek success");
6068 /* remember the offset fo the first mdat so we can seek back to it
6069 * after we have the headers */
6070 if (fourcc == FOURCC_mdat && demux->first_mdat == -1) {
6071 demux->first_mdat = old;
6072 GST_DEBUG_OBJECT (demux, "first mdat at %" G_GUINT64_FORMAT,
6075 /* seek worked, continue reading */
6076 demux->offset = target;
6077 demux->neededbytes = 16;
6078 demux->state = QTDEMUX_STATE_INITIAL;
6080 /* seek failed, need to buffer */
6081 demux->offset = old;
6082 GST_DEBUG_OBJECT (demux, "seek failed/skipped");
6083 /* there may be multiple mdat (or alike) buffers */
6085 if (demux->mdatbuffer)
6086 bs = gst_buffer_get_size (demux->mdatbuffer);
6089 if (size + bs > 10 * (1 << 20))
6091 demux->state = QTDEMUX_STATE_BUFFER_MDAT;
6092 demux->neededbytes = size;
6093 if (!demux->mdatbuffer)
6094 demux->mdatoffset = demux->offset;
6097 } else if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
6098 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
6099 (_("This file is invalid and cannot be played.")),
6100 ("atom %" GST_FOURCC_FORMAT " has bogus size %" G_GUINT64_FORMAT,
6101 GST_FOURCC_ARGS (fourcc), size));
6102 ret = GST_FLOW_ERROR;
6105 /* this means we already started buffering and still no moov header,
6106 * let's continue buffering everything till we get moov */
6107 if (demux->mdatbuffer && !(fourcc == FOURCC_moov
6108 || fourcc == FOURCC_moof))
6110 demux->neededbytes = size;
6111 demux->state = QTDEMUX_STATE_HEADER;
6115 case QTDEMUX_STATE_HEADER:{
6119 GST_DEBUG_OBJECT (demux, "In header");
6121 data = gst_adapter_map (demux->adapter, demux->neededbytes);
6123 /* parse the header */
6124 extract_initial_length_and_fourcc (data, demux->neededbytes, NULL,
6126 if (fourcc == FOURCC_moov) {
6129 /* in usual fragmented setup we could try to scan for more
6130 * and end up at the the moov (after mdat) again */
6131 if (demux->got_moov && demux->n_streams > 0 &&
6133 || demux->last_moov_offset == demux->offset)) {
6134 GST_DEBUG_OBJECT (demux,
6135 "Skipping moov atom as we have (this) one already");
6137 GST_DEBUG_OBJECT (demux, "Parsing [moov]");
6139 if (demux->got_moov && demux->fragmented) {
6140 GST_DEBUG_OBJECT (demux,
6141 "Got a second moov, clean up data from old one");
6142 if (demux->moov_node)
6143 g_node_destroy (demux->moov_node);
6144 demux->moov_node = NULL;
6145 demux->moov_node_compressed = NULL;
6147 /* prepare newsegment to send when streaming actually starts */
6148 if (!demux->pending_newsegment)
6149 demux->pending_newsegment =
6150 gst_event_new_segment (&demux->segment);
6153 demux->last_moov_offset = demux->offset;
6155 qtdemux_parse_moov (demux, data, demux->neededbytes);
6156 qtdemux_node_dump (demux, demux->moov_node);
6157 qtdemux_parse_tree (demux);
6158 qtdemux_prepare_streams (demux);
6159 if (!demux->got_moov)
6160 qtdemux_expose_streams (demux);
6163 for (n = 0; n < demux->n_streams; n++) {
6164 QtDemuxStream *stream = demux->streams[n];
6166 gst_qtdemux_configure_stream (demux, stream);
6170 demux->got_moov = TRUE;
6171 gst_qtdemux_check_send_pending_segment (demux);
6173 /* fragmented streams headers shouldn't contain edts atoms */
6174 if (!demux->fragmented) {
6175 for (n = 0; n < demux->n_streams; n++) {
6176 gst_qtdemux_stream_send_initial_gap_segments (demux,
6181 g_node_destroy (demux->moov_node);
6182 demux->moov_node = NULL;
6183 GST_DEBUG_OBJECT (demux, "Finished parsing the header");
6185 } else if (fourcc == FOURCC_moof) {
6186 if ((demux->got_moov || demux->media_caps) && demux->fragmented) {
6188 GstClockTime prev_pts;
6189 guint64 prev_offset;
6191 GST_DEBUG_OBJECT (demux, "Parsing [moof]");
6194 * The timestamp of the moof buffer is relevant as some scenarios
6195 * won't have the initial timestamp in the atoms. Whenever a new
6196 * buffer has started, we get that buffer's PTS and use it as a base
6197 * timestamp for the trun entries.
6199 * To keep track of the current buffer timestamp and starting point
6200 * we use gst_adapter_prev_pts that gives us the PTS and the distance
6201 * from the beggining of the buffer, with the distance and demux->offset
6202 * we know if it is still the same buffer or not.
6204 prev_pts = gst_adapter_prev_pts (demux->adapter, &dist);
6205 prev_offset = demux->offset - dist;
6206 if (demux->fragment_start_offset == -1
6207 || prev_offset > demux->fragment_start_offset) {
6208 demux->fragment_start_offset = prev_offset;
6209 demux->fragment_start = prev_pts;
6210 GST_DEBUG_OBJECT (demux,
6211 "New fragment start found at: %" G_GUINT64_FORMAT " : %"
6212 GST_TIME_FORMAT, demux->fragment_start_offset,
6213 GST_TIME_ARGS (demux->fragment_start));
6216 demux->moof_offset = demux->offset;
6217 if (!qtdemux_parse_moof (demux, data, demux->neededbytes,
6218 demux->offset, NULL)) {
6219 gst_adapter_unmap (demux->adapter);
6220 ret = GST_FLOW_ERROR;
6223 /* in MSS we need to expose the pads after the first moof as we won't get a moov */
6224 if (demux->mss_mode && !demux->exposed) {
6225 if (!demux->pending_newsegment) {
6227 gst_segment_init (&segment, GST_FORMAT_TIME);
6228 GST_DEBUG_OBJECT (demux, "new pending_newsegment");
6229 demux->pending_newsegment = gst_event_new_segment (&segment);
6231 qtdemux_expose_streams (demux);
6234 GST_DEBUG_OBJECT (demux, "Discarding [moof]");
6236 } else if (fourcc == FOURCC_ftyp) {
6237 GST_DEBUG_OBJECT (demux, "Parsing [ftyp]");
6238 qtdemux_parse_ftyp (demux, data, demux->neededbytes);
6239 } else if (fourcc == FOURCC_uuid) {
6240 GST_DEBUG_OBJECT (demux, "Parsing [uuid]");
6241 qtdemux_parse_uuid (demux, data, demux->neededbytes);
6242 } else if (fourcc == FOURCC_sidx) {
6243 GST_DEBUG_OBJECT (demux, "Parsing [sidx]");
6244 qtdemux_parse_sidx (demux, data, demux->neededbytes);
6246 GST_WARNING_OBJECT (demux,
6247 "Unknown fourcc while parsing header : %" GST_FOURCC_FORMAT,
6248 GST_FOURCC_ARGS (fourcc));
6249 /* Let's jump that one and go back to initial state */
6251 gst_adapter_unmap (demux->adapter);
6254 if (demux->mdatbuffer && demux->n_streams) {
6255 gsize remaining_data_size = 0;
6257 /* the mdat was before the header */
6258 GST_DEBUG_OBJECT (demux, "We have n_streams:%d and mdatbuffer:%p",
6259 demux->n_streams, demux->mdatbuffer);
6260 /* restore our adapter/offset view of things with upstream;
6261 * put preceding buffered data ahead of current moov data.
6262 * This should also handle evil mdat, moov, mdat cases and alike */
6263 gst_adapter_flush (demux->adapter, demux->neededbytes);
6265 /* Store any remaining data after the mdat for later usage */
6266 remaining_data_size = gst_adapter_available (demux->adapter);
6267 if (remaining_data_size > 0) {
6268 g_assert (demux->restoredata_buffer == NULL);
6269 demux->restoredata_buffer =
6270 gst_adapter_take_buffer (demux->adapter, remaining_data_size);
6271 demux->restoredata_offset = demux->offset + demux->neededbytes;
6272 GST_DEBUG_OBJECT (demux,
6273 "Stored %" G_GSIZE_FORMAT " post mdat bytes at offset %"
6274 G_GUINT64_FORMAT, remaining_data_size,
6275 demux->restoredata_offset);
6278 gst_adapter_push (demux->adapter, demux->mdatbuffer);
6279 demux->mdatbuffer = NULL;
6280 demux->offset = demux->mdatoffset;
6281 demux->neededbytes = next_entry_size (demux);
6282 demux->state = QTDEMUX_STATE_MOVIE;
6283 demux->mdatleft = gst_adapter_available (demux->adapter);
6285 GST_DEBUG_OBJECT (demux, "Carrying on normally");
6286 gst_adapter_flush (demux->adapter, demux->neededbytes);
6288 /* only go back to the mdat if there are samples to play */
6289 if (demux->got_moov && demux->first_mdat != -1
6290 && has_next_entry (demux)) {
6293 /* we need to seek back */
6294 res = qtdemux_seek_offset (demux, demux->first_mdat);
6296 demux->offset = demux->first_mdat;
6298 GST_DEBUG_OBJECT (demux, "Seek back failed");
6301 demux->offset += demux->neededbytes;
6303 demux->neededbytes = 16;
6304 demux->state = QTDEMUX_STATE_INITIAL;
6309 case QTDEMUX_STATE_BUFFER_MDAT:{
6313 GST_DEBUG_OBJECT (demux, "Got our buffer at offset %" G_GUINT64_FORMAT,
6315 buf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
6316 gst_buffer_extract (buf, 0, fourcc, 4);
6317 GST_DEBUG_OBJECT (demux, "mdatbuffer starts with %" GST_FOURCC_FORMAT,
6318 GST_FOURCC_ARGS (QT_FOURCC (fourcc)));
6319 if (demux->mdatbuffer)
6320 demux->mdatbuffer = gst_buffer_append (demux->mdatbuffer, buf);
6322 demux->mdatbuffer = buf;
6323 demux->offset += demux->neededbytes;
6324 demux->neededbytes = 16;
6325 demux->state = QTDEMUX_STATE_INITIAL;
6326 gst_qtdemux_post_progress (demux, 1, 1);
6330 case QTDEMUX_STATE_MOVIE:{
6331 QtDemuxStream *stream = NULL;
6332 QtDemuxSample *sample;
6334 GstClockTime dts, pts, duration;
6337 GST_DEBUG_OBJECT (demux,
6338 "BEGIN // in MOVIE for offset %" G_GUINT64_FORMAT, demux->offset);
6340 if (demux->fragmented) {
6341 GST_DEBUG_OBJECT (demux, "mdat remaining %" G_GUINT64_FORMAT,
6343 if (G_LIKELY (demux->todrop < demux->mdatleft)) {
6344 /* if needed data starts within this atom,
6345 * then it should not exceed this atom */
6346 if (G_UNLIKELY (demux->neededbytes > demux->mdatleft)) {
6347 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
6348 (_("This file is invalid and cannot be played.")),
6349 ("sample data crosses atom boundary"));
6350 ret = GST_FLOW_ERROR;
6353 demux->mdatleft -= demux->neededbytes;
6355 GST_DEBUG_OBJECT (demux, "data atom emptied; resuming atom scan");
6356 /* so we are dropping more than left in this atom */
6357 gst_qtdemux_drop_data (demux, demux->mdatleft);
6358 demux->mdatleft = 0;
6360 /* need to resume atom parsing so we do not miss any other pieces */
6361 demux->state = QTDEMUX_STATE_INITIAL;
6362 demux->neededbytes = 16;
6364 /* check if there was any stored post mdat data from previous buffers */
6365 if (demux->restoredata_buffer) {
6366 g_assert (gst_adapter_available (demux->adapter) == 0);
6368 gst_adapter_push (demux->adapter, demux->restoredata_buffer);
6369 demux->restoredata_buffer = NULL;
6370 demux->offset = demux->restoredata_offset;
6377 if (demux->todrop) {
6378 if (demux->cenc_aux_info_offset > 0) {
6382 GST_DEBUG_OBJECT (demux, "parsing cenc auxiliary info");
6383 data = gst_adapter_map (demux->adapter, demux->todrop);
6384 gst_byte_reader_init (&br, data + 8, demux->todrop);
6385 if (!qtdemux_parse_cenc_aux_info (demux, demux->streams[0], &br,
6386 demux->cenc_aux_info_sizes, demux->cenc_aux_sample_count)) {
6387 GST_ERROR_OBJECT (demux, "failed to parse cenc auxiliary info");
6388 ret = GST_FLOW_ERROR;
6389 gst_adapter_unmap (demux->adapter);
6390 g_free (demux->cenc_aux_info_sizes);
6391 demux->cenc_aux_info_sizes = NULL;
6394 demux->cenc_aux_info_offset = 0;
6395 g_free (demux->cenc_aux_info_sizes);
6396 demux->cenc_aux_info_sizes = NULL;
6397 gst_adapter_unmap (demux->adapter);
6399 gst_qtdemux_drop_data (demux, demux->todrop);
6403 /* initial newsegment sent here after having added pads,
6404 * possible others in sink_event */
6405 gst_qtdemux_check_send_pending_segment (demux);
6407 /* Figure out which stream this packet belongs to */
6408 for (i = 0; i < demux->n_streams; i++) {
6409 stream = demux->streams[i];
6410 if (stream->sample_index >= stream->n_samples)
6412 GST_LOG_OBJECT (demux,
6413 "Checking stream %d (sample_index:%d / offset:%" G_GUINT64_FORMAT
6414 " / size:%d)", i, stream->sample_index,
6415 stream->samples[stream->sample_index].offset,
6416 stream->samples[stream->sample_index].size);
6418 if (stream->samples[stream->sample_index].offset == demux->offset)
6422 if (G_UNLIKELY (stream == NULL || i == demux->n_streams))
6423 goto unknown_stream;
6425 if (stream->new_caps) {
6426 gst_qtdemux_configure_stream (demux, stream);
6429 /* Put data in a buffer, set timestamps, caps, ... */
6430 sample = &stream->samples[stream->sample_index];
6432 if (G_LIKELY (!(STREAM_IS_EOS (stream)))) {
6433 GST_DEBUG_OBJECT (demux, "stream : %" GST_FOURCC_FORMAT,
6434 GST_FOURCC_ARGS (stream->fourcc));
6436 dts = QTSAMPLE_DTS (stream, sample);
6437 pts = QTSAMPLE_PTS (stream, sample);
6438 duration = QTSAMPLE_DUR_DTS (stream, sample, dts);
6439 keyframe = QTSAMPLE_KEYFRAME (stream, sample);
6441 /* check for segment end */
6442 if (G_UNLIKELY (demux->segment.stop != -1
6443 && demux->segment.stop <= pts && stream->on_keyframe)) {
6444 GST_DEBUG_OBJECT (demux, "we reached the end of our segment.");
6445 stream->time_position = GST_CLOCK_TIME_NONE; /* this means EOS */
6447 /* skip this data, stream is EOS */
6448 gst_adapter_flush (demux->adapter, demux->neededbytes);
6450 /* check if all streams are eos */
6452 for (i = 0; i < demux->n_streams; i++) {
6453 if (!STREAM_IS_EOS (demux->streams[i])) {
6459 if (ret == GST_FLOW_EOS) {
6460 GST_DEBUG_OBJECT (demux, "All streams are EOS, signal upstream");
6467 gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
6469 /* FIXME: should either be an assert or a plain check */
6470 g_return_val_if_fail (outbuf != NULL, GST_FLOW_ERROR);
6472 ret = gst_qtdemux_decorate_and_push_buffer (demux, stream, outbuf,
6473 dts, pts, duration, keyframe, dts, demux->offset);
6477 ret = gst_qtdemux_combine_flows (demux, stream, ret);
6478 if (ret != GST_FLOW_OK && ret != GST_FLOW_NOT_LINKED)
6479 goto non_ok_unlinked_flow;
6481 /* skip this data, stream is EOS */
6482 gst_adapter_flush (demux->adapter, demux->neededbytes);
6485 stream->sample_index++;
6486 stream->offset_in_sample = 0;
6488 /* update current offset and figure out size of next buffer */
6489 GST_LOG_OBJECT (demux, "increasing offset %" G_GUINT64_FORMAT " by %u",
6490 demux->offset, demux->neededbytes);
6491 demux->offset += demux->neededbytes;
6492 GST_LOG_OBJECT (demux, "offset is now %" G_GUINT64_FORMAT,
6495 if ((demux->neededbytes = next_entry_size (demux)) == -1) {
6496 if (demux->fragmented) {
6497 GST_DEBUG_OBJECT (demux, "(temporarily) out of fragmented samples");
6498 /* there may be more to follow, only finish this atom */
6499 demux->todrop = demux->mdatleft;
6500 demux->neededbytes = demux->todrop;
6512 /* when buffering movie data, at least show user something is happening */
6513 if (ret == GST_FLOW_OK && demux->state == QTDEMUX_STATE_BUFFER_MDAT &&
6514 gst_adapter_available (demux->adapter) <= demux->neededbytes) {
6515 gst_qtdemux_post_progress (demux, gst_adapter_available (demux->adapter),
6516 demux->neededbytes);
6523 non_ok_unlinked_flow:
6525 GST_DEBUG_OBJECT (demux, "Stopping, combined return flow %s",
6526 gst_flow_get_name (ret));
6531 GST_ELEMENT_ERROR (demux, STREAM, FAILED, (NULL), ("unknown stream found"));
6532 ret = GST_FLOW_ERROR;
6537 GST_DEBUG_OBJECT (demux, "no next entry, EOS");
6543 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
6544 (NULL), ("qtdemuxer invalid state %d", demux->state));
6545 ret = GST_FLOW_ERROR;
6550 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
6551 (NULL), ("no 'moov' atom within the first 10 MB"));
6552 ret = GST_FLOW_ERROR;
6558 qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent)
6563 query = gst_query_new_scheduling ();
6565 if (!gst_pad_peer_query (sinkpad, query)) {
6566 gst_query_unref (query);
6570 pull_mode = gst_query_has_scheduling_mode_with_flags (query,
6571 GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
6572 gst_query_unref (query);
6577 GST_DEBUG_OBJECT (sinkpad, "activating pull");
6578 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
6582 GST_DEBUG_OBJECT (sinkpad, "activating push");
6583 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
6588 qtdemux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
6589 GstPadMode mode, gboolean active)
6592 GstQTDemux *demux = GST_QTDEMUX (parent);
6595 case GST_PAD_MODE_PUSH:
6596 demux->pullbased = FALSE;
6599 case GST_PAD_MODE_PULL:
6601 demux->pullbased = TRUE;
6602 res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_qtdemux_loop,
6605 res = gst_pad_stop_task (sinkpad);
6617 qtdemux_zalloc (void *opaque, unsigned int items, unsigned int size)
6619 return g_malloc (items * size);
6623 qtdemux_zfree (void *opaque, void *addr)
6629 qtdemux_inflate (void *z_buffer, guint z_length, guint length)
6635 z = g_new0 (z_stream, 1);
6636 z->zalloc = qtdemux_zalloc;
6637 z->zfree = qtdemux_zfree;
6640 z->next_in = z_buffer;
6641 z->avail_in = z_length;
6643 buffer = (guint8 *) g_malloc (length);
6644 ret = inflateInit (z);
6645 while (z->avail_in > 0) {
6646 if (z->avail_out == 0) {
6648 buffer = (guint8 *) g_realloc (buffer, length);
6649 z->next_out = buffer + z->total_out;
6650 z->avail_out = 1024;
6652 ret = inflate (z, Z_SYNC_FLUSH);
6656 if (ret != Z_STREAM_END) {
6657 g_warning ("inflate() returned %d", ret);
6663 #endif /* HAVE_ZLIB */
6666 qtdemux_parse_moov (GstQTDemux * qtdemux, const guint8 * buffer, guint length)
6670 qtdemux->moov_node = g_node_new ((guint8 *) buffer);
6672 /* counts as header data */
6673 qtdemux->header_size += length;
6675 GST_DEBUG_OBJECT (qtdemux, "parsing 'moov' atom");
6676 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buffer, length);
6678 cmov = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_cmov);
6684 dcom = qtdemux_tree_get_child_by_type (cmov, FOURCC_dcom);
6685 cmvd = qtdemux_tree_get_child_by_type (cmov, FOURCC_cmvd);
6686 if (dcom == NULL || cmvd == NULL)
6687 goto invalid_compression;
6689 method = QT_FOURCC ((guint8 *) dcom->data + 8);
6693 guint uncompressed_length;
6694 guint compressed_length;
6697 uncompressed_length = QT_UINT32 ((guint8 *) cmvd->data + 8);
6698 compressed_length = QT_UINT32 ((guint8 *) cmvd->data + 4) - 12;
6699 GST_LOG ("length = %u", uncompressed_length);
6702 (guint8 *) qtdemux_inflate ((guint8 *) cmvd->data + 12,
6703 compressed_length, uncompressed_length);
6705 qtdemux->moov_node_compressed = qtdemux->moov_node;
6706 qtdemux->moov_node = g_node_new (buf);
6708 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buf,
6709 uncompressed_length);
6712 #endif /* HAVE_ZLIB */
6714 GST_WARNING_OBJECT (qtdemux, "unknown or unhandled header compression "
6715 "type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (method));
6722 invalid_compression:
6724 GST_ERROR_OBJECT (qtdemux, "invalid compressed header");
6730 qtdemux_parse_container (GstQTDemux * qtdemux, GNode * node, const guint8 * buf,
6733 while (G_UNLIKELY (buf < end)) {
6737 if (G_UNLIKELY (buf + 4 > end)) {
6738 GST_LOG_OBJECT (qtdemux, "buffer overrun");
6741 len = QT_UINT32 (buf);
6742 if (G_UNLIKELY (len == 0)) {
6743 GST_LOG_OBJECT (qtdemux, "empty container");
6746 if (G_UNLIKELY (len < 8)) {
6747 GST_WARNING_OBJECT (qtdemux, "length too short (%d < 8)", len);
6750 if (G_UNLIKELY (len > (end - buf))) {
6751 GST_WARNING_OBJECT (qtdemux, "length too long (%d > %d)", len,
6752 (gint) (end - buf));
6756 child = g_node_new ((guint8 *) buf);
6757 g_node_append (node, child);
6758 GST_LOG_OBJECT (qtdemux, "adding new node of len %d", len);
6759 qtdemux_parse_node (qtdemux, child, buf, len);
6767 qtdemux_parse_theora_extension (GstQTDemux * qtdemux, QtDemuxStream * stream,
6770 int len = QT_UINT32 (xdxt->data);
6771 guint8 *buf = xdxt->data;
6772 guint8 *end = buf + len;
6775 /* skip size and type */
6783 size = QT_UINT32 (buf);
6784 type = QT_FOURCC (buf + 4);
6786 GST_LOG_OBJECT (qtdemux, "%p %p", buf, end);
6788 if (buf + size > end || size <= 0)
6794 GST_WARNING_OBJECT (qtdemux, "have cookie %" GST_FOURCC_FORMAT,
6795 GST_FOURCC_ARGS (type));
6799 buffer = gst_buffer_new_and_alloc (size);
6800 gst_buffer_fill (buffer, 0, buf, size);
6801 stream->buffers = g_slist_append (stream->buffers, buffer);
6802 GST_LOG_OBJECT (qtdemux, "parsing theora header");
6805 buffer = gst_buffer_new_and_alloc (size);
6806 gst_buffer_fill (buffer, 0, buf, size);
6807 stream->buffers = g_slist_append (stream->buffers, buffer);
6808 GST_LOG_OBJECT (qtdemux, "parsing theora comment");
6811 buffer = gst_buffer_new_and_alloc (size);
6812 gst_buffer_fill (buffer, 0, buf, size);
6813 stream->buffers = g_slist_append (stream->buffers, buffer);
6814 GST_LOG_OBJECT (qtdemux, "parsing theora codebook");
6817 GST_WARNING_OBJECT (qtdemux,
6818 "unknown theora cookie %" GST_FOURCC_FORMAT,
6819 GST_FOURCC_ARGS (type));
6828 qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node, const guint8 * buffer,
6832 guint32 node_length = 0;
6833 const QtNodeType *type;
6836 GST_LOG_OBJECT (qtdemux, "qtdemux_parse buffer %p length %u", buffer, length);
6838 if (G_UNLIKELY (length < 8))
6839 goto not_enough_data;
6841 node_length = QT_UINT32 (buffer);
6842 fourcc = QT_FOURCC (buffer + 4);
6844 /* ignore empty nodes */
6845 if (G_UNLIKELY (fourcc == 0 || node_length == 8))
6848 type = qtdemux_type_get (fourcc);
6850 end = buffer + length;
6852 GST_LOG_OBJECT (qtdemux,
6853 "parsing '%" GST_FOURCC_FORMAT "', length=%u, name '%s'",
6854 GST_FOURCC_ARGS (fourcc), node_length, type->name);
6856 if (node_length > length)
6857 goto broken_atom_size;
6859 if (type->flags & QT_FLAG_CONTAINER) {
6860 qtdemux_parse_container (qtdemux, node, buffer + 8, end);
6865 if (node_length < 20) {
6866 GST_LOG_OBJECT (qtdemux, "skipping small stsd box");
6869 GST_DEBUG_OBJECT (qtdemux,
6870 "parsing stsd (sample table, sample description) atom");
6871 /* Skip over 8 byte atom hdr + 1 byte version, 3 bytes flags, 4 byte num_entries */
6872 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
6882 /* also read alac (or whatever) in stead of mp4a in the following,
6883 * since a similar layout is used in other cases as well */
6884 if (fourcc == FOURCC_mp4a)
6889 /* There are two things we might encounter here: a true mp4a atom, and
6890 an mp4a entry in an stsd atom. The latter is what we're interested
6891 in, and it looks like an atom, but isn't really one. The true mp4a
6892 atom is short, so we detect it based on length here. */
6893 if (length < min_size) {
6894 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
6895 GST_FOURCC_ARGS (fourcc));
6899 /* 'version' here is the sound sample description version. Types 0 and
6900 1 are documented in the QTFF reference, but type 2 is not: it's
6901 described in Apple header files instead (struct SoundDescriptionV2
6903 version = QT_UINT16 (buffer + 16);
6905 GST_DEBUG_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT " version 0x%08x",
6906 GST_FOURCC_ARGS (fourcc), version);
6908 /* parse any esds descriptors */
6920 GST_WARNING_OBJECT (qtdemux,
6921 "unhandled %" GST_FOURCC_FORMAT " version 0x%08x",
6922 GST_FOURCC_ARGS (fourcc), version);
6927 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
6944 /* codec_data is contained inside these atoms, which all have
6945 * the same format. */
6947 GST_DEBUG_OBJECT (qtdemux, "parsing in %" GST_FOURCC_FORMAT,
6948 GST_FOURCC_ARGS (fourcc));
6949 version = QT_UINT32 (buffer + 16);
6950 GST_DEBUG_OBJECT (qtdemux, "version %08x", version);
6951 if (1 || version == 0x00000000) {
6952 buf = buffer + 0x32;
6954 /* FIXME Quicktime uses PASCAL string while
6955 * the iso format uses C strings. Check the file
6956 * type before attempting to parse the string here. */
6957 tlen = QT_UINT8 (buf);
6958 GST_DEBUG_OBJECT (qtdemux, "tlen = %d", tlen);
6960 GST_DEBUG_OBJECT (qtdemux, "string = %.*s", tlen, (char *) buf);
6961 /* the string has a reserved space of 32 bytes so skip
6962 * the remaining 31 */
6964 buf += 4; /* and 4 bytes reserved */
6966 GST_MEMDUMP_OBJECT (qtdemux, "mp4v", buf, end - buf);
6968 qtdemux_parse_container (qtdemux, node, buf, end);
6974 GST_MEMDUMP_OBJECT (qtdemux, "H264", buffer, end - buffer);
6975 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
6980 GST_MEMDUMP_OBJECT (qtdemux, "avc1", buffer, end - buffer);
6981 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
6986 GST_MEMDUMP_OBJECT (qtdemux, "avc3", buffer, end - buffer);
6987 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
6992 GST_MEMDUMP_OBJECT (qtdemux, "H265", buffer, end - buffer);
6993 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
6998 GST_MEMDUMP_OBJECT (qtdemux, "hvc1", buffer, end - buffer);
6999 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
7004 GST_MEMDUMP_OBJECT (qtdemux, "hev1", buffer, end - buffer);
7005 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
7010 qtdemux_parse_container (qtdemux, node, buffer + 86, end);
7015 GST_DEBUG_OBJECT (qtdemux, "parsing meta atom");
7016 qtdemux_parse_container (qtdemux, node, buffer + 12, end);
7021 GST_MEMDUMP_OBJECT (qtdemux, "mp4s", buffer, end - buffer);
7022 /* Skip 8 byte header, plus 8 byte version + flags + entry_count */
7023 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
7031 version = QT_UINT32 (buffer + 12);
7032 GST_DEBUG_OBJECT (qtdemux, "parsing XiTh atom version 0x%08x", version);
7039 GST_DEBUG_OBJECT (qtdemux, "unknown version 0x%08x", version);
7044 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
7049 qtdemux_parse_container (qtdemux, node, buffer + 0x34, end);
7054 qtdemux_parse_uuid (qtdemux, buffer, end - buffer);
7059 qtdemux_parse_container (qtdemux, node, buffer + 86, end);
7064 qtdemux_parse_container (qtdemux, node, buffer + 36, end);
7068 if (!strcmp (type->name, "unknown"))
7069 GST_MEMDUMP ("Unknown tag", buffer + 4, end - buffer - 4);
7073 GST_LOG_OBJECT (qtdemux, "parsed '%" GST_FOURCC_FORMAT "'",
7074 GST_FOURCC_ARGS (fourcc));
7080 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
7081 (_("This file is corrupt and cannot be played.")),
7082 ("Not enough data for an atom header, got only %u bytes", length));
7087 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
7088 (_("This file is corrupt and cannot be played.")),
7089 ("Atom '%" GST_FOURCC_FORMAT "' has size of %u bytes, but we have only "
7090 "%u bytes available.", GST_FOURCC_ARGS (fourcc), node_length,
7097 qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc)
7101 guint32 child_fourcc;
7103 for (child = g_node_first_child (node); child;
7104 child = g_node_next_sibling (child)) {
7105 buffer = (guint8 *) child->data;
7107 child_fourcc = QT_FOURCC (buffer + 4);
7109 if (G_UNLIKELY (child_fourcc == fourcc)) {
7117 qtdemux_tree_get_child_by_type_full (GNode * node, guint32 fourcc,
7118 GstByteReader * parser)
7122 guint32 child_fourcc, child_len;
7124 for (child = g_node_first_child (node); child;
7125 child = g_node_next_sibling (child)) {
7126 buffer = (guint8 *) child->data;
7128 child_len = QT_UINT32 (buffer);
7129 child_fourcc = QT_FOURCC (buffer + 4);
7131 if (G_UNLIKELY (child_fourcc == fourcc)) {
7132 if (G_UNLIKELY (child_len < (4 + 4)))
7134 /* FIXME: must verify if atom length < parent atom length */
7135 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
7143 qtdemux_tree_get_sibling_by_type_full (GNode * node, guint32 fourcc,
7144 GstByteReader * parser)
7148 guint32 child_fourcc, child_len;
7150 for (child = g_node_next_sibling (node); child;
7151 child = g_node_next_sibling (child)) {
7152 buffer = (guint8 *) child->data;
7154 child_fourcc = QT_FOURCC (buffer + 4);
7156 if (child_fourcc == fourcc) {
7158 child_len = QT_UINT32 (buffer);
7159 if (G_UNLIKELY (child_len < (4 + 4)))
7161 /* FIXME: must verify if atom length < parent atom length */
7162 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
7171 qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc)
7173 return qtdemux_tree_get_sibling_by_type_full (node, fourcc, NULL);
7177 qtdemux_do_allocation (GstQTDemux * qtdemux, QtDemuxStream * stream)
7179 /* FIXME: This can only reliably work if demuxers have a
7180 * separate streaming thread per srcpad. This should be
7181 * done in a demuxer base class, which integrates parts
7184 * https://bugzilla.gnome.org/show_bug.cgi?id=701856
7189 query = gst_query_new_allocation (stream->caps, FALSE);
7191 if (!gst_pad_peer_query (stream->pad, query)) {
7192 /* not a problem, just debug a little */
7193 GST_DEBUG_OBJECT (qtdemux, "peer ALLOCATION query failed");
7196 if (stream->allocator)
7197 gst_object_unref (stream->allocator);
7199 if (gst_query_get_n_allocation_params (query) > 0) {
7200 /* try the allocator */
7201 gst_query_parse_nth_allocation_param (query, 0, &stream->allocator,
7203 stream->use_allocator = TRUE;
7205 stream->allocator = NULL;
7206 gst_allocation_params_init (&stream->params);
7207 stream->use_allocator = FALSE;
7209 gst_query_unref (query);
7214 gst_qtdemux_configure_protected_caps (GstQTDemux * qtdemux,
7215 QtDemuxStream * stream)
7218 const gchar *selected_system;
7220 g_return_val_if_fail (qtdemux != NULL, FALSE);
7221 g_return_val_if_fail (stream != NULL, FALSE);
7222 g_return_val_if_fail (gst_caps_get_size (stream->caps) == 1, FALSE);
7224 if (stream->protection_scheme_type != FOURCC_cenc) {
7225 GST_ERROR_OBJECT (qtdemux, "unsupported protection scheme");
7228 if (qtdemux->protection_system_ids == NULL) {
7229 GST_ERROR_OBJECT (qtdemux, "stream is protected using cenc, but no "
7230 "cenc protection system information has been found");
7233 g_ptr_array_add (qtdemux->protection_system_ids, NULL);
7234 selected_system = gst_protection_select_system ((const gchar **)
7235 qtdemux->protection_system_ids->pdata);
7236 g_ptr_array_remove_index (qtdemux->protection_system_ids,
7237 qtdemux->protection_system_ids->len - 1);
7238 if (!selected_system) {
7239 GST_ERROR_OBJECT (qtdemux, "stream is protected, but no "
7240 "suitable decryptor element has been found");
7244 s = gst_caps_get_structure (stream->caps, 0);
7245 if (!gst_structure_has_name (s, "application/x-cenc")) {
7246 gst_structure_set (s,
7247 "original-media-type", G_TYPE_STRING, gst_structure_get_name (s),
7248 GST_PROTECTION_SYSTEM_ID_CAPS_FIELD, G_TYPE_STRING, selected_system,
7250 gst_structure_set_name (s, "application/x-cenc");
7256 gst_qtdemux_configure_stream (GstQTDemux * qtdemux, QtDemuxStream * stream)
7258 if (stream->subtype == FOURCC_vide) {
7259 /* fps is calculated base on the duration of the average framerate since
7260 * qt does not have a fixed framerate. */
7261 gboolean fps_available = TRUE;
7263 if ((stream->n_samples == 1) && (stream->first_duration == 0)) {
7268 if (stream->duration == 0 || stream->n_samples < 2) {
7269 stream->fps_n = stream->timescale;
7271 fps_available = FALSE;
7273 GstClockTime avg_duration;
7277 /* duration and n_samples can be updated for fragmented format
7278 * so, framerate of fragmented format is calculated using data in a moof */
7279 if (qtdemux->fragmented && stream->n_samples_moof > 0
7280 && stream->duration_moof > 0) {
7281 n_samples = stream->n_samples_moof;
7282 duration = stream->duration_moof;
7284 n_samples = stream->n_samples;
7285 duration = stream->duration;
7288 /* Calculate a framerate, ignoring the first sample which is sometimes truncated */
7289 /* stream->duration is guint64, timescale, n_samples are guint32 */
7291 gst_util_uint64_scale_round (duration -
7292 stream->first_duration, GST_SECOND,
7293 (guint64) (stream->timescale) * (n_samples - 1));
7295 GST_LOG_OBJECT (qtdemux,
7296 "Calculating avg sample duration based on stream (or moof) duration %"
7298 " minus first sample %u, leaving %d samples gives %"
7299 GST_TIME_FORMAT, duration, stream->first_duration,
7300 n_samples - 1, GST_TIME_ARGS (avg_duration));
7302 gst_video_guess_framerate (avg_duration, &stream->fps_n,
7305 GST_DEBUG_OBJECT (qtdemux,
7306 "Calculating framerate, timescale %u gave fps_n %d fps_d %d",
7307 stream->timescale, stream->fps_n, stream->fps_d);
7312 stream->caps = gst_caps_make_writable (stream->caps);
7314 gst_caps_set_simple (stream->caps,
7315 "width", G_TYPE_INT, stream->width,
7316 "height", G_TYPE_INT, stream->height, NULL);
7318 /* set framerate if calculated framerate is reliable */
7319 if (fps_available) {
7320 gst_caps_set_simple (stream->caps,
7321 "framerate", GST_TYPE_FRACTION, stream->fps_n, stream->fps_d, NULL);
7324 /* calculate pixel-aspect-ratio using display width and height */
7325 GST_DEBUG_OBJECT (qtdemux,
7326 "video size %dx%d, target display size %dx%d", stream->width,
7327 stream->height, stream->display_width, stream->display_height);
7328 /* qt file might have pasp atom */
7329 if (stream->par_w > 0 && stream->par_h > 0) {
7330 GST_DEBUG_OBJECT (qtdemux, "par %d:%d", stream->par_w, stream->par_h);
7331 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
7332 GST_TYPE_FRACTION, stream->par_w, stream->par_h, NULL);
7333 } else if (stream->display_width > 0 && stream->display_height > 0 &&
7334 stream->width > 0 && stream->height > 0) {
7337 /* calculate the pixel aspect ratio using the display and pixel w/h */
7338 n = stream->display_width * stream->height;
7339 d = stream->display_height * stream->width;
7342 GST_DEBUG_OBJECT (qtdemux, "setting PAR to %d/%d", n, d);
7345 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
7346 GST_TYPE_FRACTION, stream->par_w, stream->par_h, NULL);
7349 if (stream->multiview_mode != GST_VIDEO_MULTIVIEW_MODE_NONE) {
7350 guint par_w = 1, par_h = 1;
7352 if (stream->par_w > 0 && stream->par_h > 0) {
7353 par_w = stream->par_w;
7354 par_h = stream->par_h;
7357 if (gst_video_multiview_guess_half_aspect (stream->multiview_mode,
7358 stream->width, stream->height, par_w, par_h)) {
7359 stream->multiview_flags |= GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT;
7362 gst_caps_set_simple (stream->caps,
7363 "multiview-mode", G_TYPE_STRING,
7364 gst_video_multiview_mode_to_caps_string (stream->multiview_mode),
7365 "multiview-flags", GST_TYPE_VIDEO_MULTIVIEW_FLAGSET,
7366 stream->multiview_flags, GST_FLAG_SET_MASK_EXACT, NULL);
7371 else if (stream->subtype == FOURCC_soun) {
7373 stream->caps = gst_caps_make_writable (stream->caps);
7374 if (stream->rate > 0)
7375 gst_caps_set_simple (stream->caps,
7376 "rate", G_TYPE_INT, (int) stream->rate, NULL);
7377 if (stream->n_channels > 0)
7378 gst_caps_set_simple (stream->caps,
7379 "channels", G_TYPE_INT, stream->n_channels, NULL);
7380 if (stream->n_channels > 2) {
7381 /* FIXME: Need to parse the 'chan' atom to get channel layouts
7382 * correctly; this is just the minimum we can do - assume
7383 * we don't actually have any channel positions. */
7384 gst_caps_set_simple (stream->caps,
7385 "channel-mask", GST_TYPE_BITMASK, G_GUINT64_CONSTANT (0), NULL);
7391 GST_PAD_ELEMENT_PRIVATE (stream->pad) = stream;
7392 gst_pad_set_event_function (stream->pad, gst_qtdemux_handle_src_event);
7393 gst_pad_set_query_function (stream->pad, gst_qtdemux_handle_src_query);
7394 gst_pad_set_active (stream->pad, TRUE);
7396 gst_pad_use_fixed_caps (stream->pad);
7398 if (stream->protected) {
7399 if (!gst_qtdemux_configure_protected_caps (qtdemux, stream)) {
7400 GST_ERROR_OBJECT (qtdemux,
7401 "Failed to configure protected stream caps.");
7406 GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT, stream->caps);
7407 if (stream->new_stream) {
7410 GstStreamFlags stream_flags;
7413 gst_pad_get_sticky_event (qtdemux->sinkpad, GST_EVENT_STREAM_START,
7416 if (gst_event_parse_group_id (event, &qtdemux->group_id))
7417 qtdemux->have_group_id = TRUE;
7419 qtdemux->have_group_id = FALSE;
7420 gst_event_unref (event);
7421 } else if (!qtdemux->have_group_id) {
7422 qtdemux->have_group_id = TRUE;
7423 qtdemux->group_id = gst_util_group_id_next ();
7426 stream->new_stream = FALSE;
7428 gst_pad_create_stream_id_printf (stream->pad,
7429 GST_ELEMENT_CAST (qtdemux), "%03u", stream->track_id);
7430 event = gst_event_new_stream_start (stream_id);
7431 if (qtdemux->have_group_id)
7432 gst_event_set_group_id (event, qtdemux->group_id);
7433 stream_flags = GST_STREAM_FLAG_NONE;
7434 if (stream->disabled)
7435 stream_flags |= GST_STREAM_FLAG_UNSELECT;
7437 stream_flags |= GST_STREAM_FLAG_SPARSE;
7438 gst_event_set_stream_flags (event, stream_flags);
7439 gst_pad_push_event (stream->pad, event);
7442 gst_pad_set_caps (stream->pad, stream->caps);
7443 stream->new_caps = FALSE;
7449 gst_qtdemux_add_stream (GstQTDemux * qtdemux,
7450 QtDemuxStream * stream, GstTagList * list)
7452 gboolean ret = TRUE;
7453 /* consistent default for push based mode */
7454 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
7456 if (stream->subtype == FOURCC_vide) {
7457 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
7460 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
7463 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
7464 gst_object_unref (stream->pad);
7470 qtdemux->n_video_streams++;
7471 } else if (stream->subtype == FOURCC_soun) {
7472 gchar *name = g_strdup_printf ("audio_%u", qtdemux->n_audio_streams);
7475 gst_pad_new_from_static_template (&gst_qtdemux_audiosrc_template, name);
7477 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
7478 gst_object_unref (stream->pad);
7483 qtdemux->n_audio_streams++;
7484 } else if (stream->subtype == FOURCC_strm) {
7485 GST_DEBUG_OBJECT (qtdemux, "stream type, not creating pad");
7486 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
7487 || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt) {
7488 gchar *name = g_strdup_printf ("subtitle_%u", qtdemux->n_sub_streams);
7491 gst_pad_new_from_static_template (&gst_qtdemux_subsrc_template, name);
7493 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
7494 gst_object_unref (stream->pad);
7499 qtdemux->n_sub_streams++;
7500 } else if (stream->caps) {
7501 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
7504 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
7506 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
7507 gst_object_unref (stream->pad);
7512 qtdemux->n_video_streams++;
7514 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
7521 GST_DEBUG_OBJECT (qtdemux, "adding pad %s %p to qtdemux %p",
7522 GST_OBJECT_NAME (stream->pad), stream->pad, qtdemux);
7523 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
7524 gst_flow_combiner_add_pad (qtdemux->flowcombiner, stream->pad);
7526 if (stream->pending_tags)
7527 gst_tag_list_unref (stream->pending_tags);
7528 stream->pending_tags = list;
7530 /* global tags go on each pad anyway */
7531 stream->send_global_tags = TRUE;
7532 /* send upstream GST_EVENT_PROTECTION events that were received before
7533 this source pad was created */
7534 for (l = qtdemux->protection_event_queue.head; l != NULL; l = l->next)
7535 gst_pad_push_event (stream->pad, gst_event_ref (l->data));
7539 gst_tag_list_unref (list);
7543 /* find next atom with @fourcc starting at @offset */
7544 static GstFlowReturn
7545 qtdemux_find_atom (GstQTDemux * qtdemux, guint64 * offset,
7546 guint64 * length, guint32 fourcc)
7552 GST_LOG_OBJECT (qtdemux, "finding fourcc %" GST_FOURCC_FORMAT " at offset %"
7553 G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), *offset);
7559 ret = gst_pad_pull_range (qtdemux->sinkpad, *offset, 16, &buf);
7560 if (G_UNLIKELY (ret != GST_FLOW_OK))
7562 if (G_UNLIKELY (gst_buffer_get_size (buf) != 16)) {
7565 gst_buffer_unref (buf);
7568 gst_buffer_map (buf, &map, GST_MAP_READ);
7569 extract_initial_length_and_fourcc (map.data, 16, length, &lfourcc);
7570 gst_buffer_unmap (buf, &map);
7571 gst_buffer_unref (buf);
7573 if (G_UNLIKELY (*length == 0)) {
7574 GST_DEBUG_OBJECT (qtdemux, "invalid length 0");
7575 ret = GST_FLOW_ERROR;
7579 if (lfourcc == fourcc) {
7580 GST_DEBUG_OBJECT (qtdemux, "found fourcc at offset %" G_GUINT64_FORMAT,
7584 GST_LOG_OBJECT (qtdemux,
7585 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
7586 GST_FOURCC_ARGS (fourcc), *offset);
7595 /* might simply have had last one */
7596 GST_DEBUG_OBJECT (qtdemux, "fourcc not found");
7601 /* should only do something in pull mode */
7602 /* call with OBJECT lock */
7603 static GstFlowReturn
7604 qtdemux_add_fragmented_samples (GstQTDemux * qtdemux)
7606 guint64 length, offset;
7607 GstBuffer *buf = NULL;
7608 GstFlowReturn ret = GST_FLOW_OK;
7609 GstFlowReturn res = GST_FLOW_OK;
7612 offset = qtdemux->moof_offset;
7613 GST_DEBUG_OBJECT (qtdemux, "next moof at offset %" G_GUINT64_FORMAT, offset);
7616 GST_DEBUG_OBJECT (qtdemux, "no next moof");
7617 return GST_FLOW_EOS;
7620 /* best not do pull etc with lock held */
7621 GST_OBJECT_UNLOCK (qtdemux);
7623 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
7624 if (ret != GST_FLOW_OK)
7627 ret = gst_qtdemux_pull_atom (qtdemux, offset, length, &buf);
7628 if (G_UNLIKELY (ret != GST_FLOW_OK))
7630 gst_buffer_map (buf, &map, GST_MAP_READ);
7631 if (!qtdemux_parse_moof (qtdemux, map.data, map.size, offset, NULL)) {
7632 gst_buffer_unmap (buf, &map);
7633 gst_buffer_unref (buf);
7638 gst_buffer_unmap (buf, &map);
7639 gst_buffer_unref (buf);
7643 /* look for next moof */
7644 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
7645 if (G_UNLIKELY (ret != GST_FLOW_OK))
7649 GST_OBJECT_LOCK (qtdemux);
7651 qtdemux->moof_offset = offset;
7657 GST_DEBUG_OBJECT (qtdemux, "failed to parse moof");
7659 res = GST_FLOW_ERROR;
7664 /* maybe upstream temporarily flushing */
7665 if (ret != GST_FLOW_FLUSHING) {
7666 GST_DEBUG_OBJECT (qtdemux, "no next moof");
7669 GST_DEBUG_OBJECT (qtdemux, "upstream WRONG_STATE");
7670 /* resume at current position next time */
7677 /* initialise bytereaders for stbl sub-atoms */
7679 qtdemux_stbl_init (GstQTDemux * qtdemux, QtDemuxStream * stream, GNode * stbl)
7681 stream->stbl_index = -1; /* no samples have yet been parsed */
7682 stream->sample_index = -1;
7684 /* time-to-sample atom */
7685 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stts, &stream->stts))
7688 /* copy atom data into a new buffer for later use */
7689 stream->stts.data = g_memdup (stream->stts.data, stream->stts.size);
7691 /* skip version + flags */
7692 if (!gst_byte_reader_skip (&stream->stts, 1 + 3) ||
7693 !gst_byte_reader_get_uint32_be (&stream->stts, &stream->n_sample_times))
7695 GST_LOG_OBJECT (qtdemux, "%u timestamp blocks", stream->n_sample_times);
7697 /* make sure there's enough data */
7698 if (!qt_atom_parser_has_chunks (&stream->stts, stream->n_sample_times, 8)) {
7699 stream->n_sample_times = gst_byte_reader_get_remaining (&stream->stts) / 8;
7700 GST_LOG_OBJECT (qtdemux, "overriding to %u timestamp blocks",
7701 stream->n_sample_times);
7702 if (!stream->n_sample_times)
7706 /* sync sample atom */
7707 stream->stps_present = FALSE;
7708 if ((stream->stss_present =
7709 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stss,
7710 &stream->stss) ? TRUE : FALSE) == TRUE) {
7711 /* copy atom data into a new buffer for later use */
7712 stream->stss.data = g_memdup (stream->stss.data, stream->stss.size);
7714 /* skip version + flags */
7715 if (!gst_byte_reader_skip (&stream->stss, 1 + 3) ||
7716 !gst_byte_reader_get_uint32_be (&stream->stss, &stream->n_sample_syncs))
7719 if (stream->n_sample_syncs) {
7720 /* make sure there's enough data */
7721 if (!qt_atom_parser_has_chunks (&stream->stss, stream->n_sample_syncs, 4))
7725 /* partial sync sample atom */
7726 if ((stream->stps_present =
7727 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stps,
7728 &stream->stps) ? TRUE : FALSE) == TRUE) {
7729 /* copy atom data into a new buffer for later use */
7730 stream->stps.data = g_memdup (stream->stps.data, stream->stps.size);
7732 /* skip version + flags */
7733 if (!gst_byte_reader_skip (&stream->stps, 1 + 3) ||
7734 !gst_byte_reader_get_uint32_be (&stream->stps,
7735 &stream->n_sample_partial_syncs))
7738 /* if there are no entries, the stss table contains the real
7740 if (stream->n_sample_partial_syncs) {
7741 /* make sure there's enough data */
7742 if (!qt_atom_parser_has_chunks (&stream->stps,
7743 stream->n_sample_partial_syncs, 4))
7750 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsz, &stream->stsz))
7753 /* copy atom data into a new buffer for later use */
7754 stream->stsz.data = g_memdup (stream->stsz.data, stream->stsz.size);
7756 /* skip version + flags */
7757 if (!gst_byte_reader_skip (&stream->stsz, 1 + 3) ||
7758 !gst_byte_reader_get_uint32_be (&stream->stsz, &stream->sample_size))
7761 if (!gst_byte_reader_get_uint32_be (&stream->stsz, &stream->n_samples))
7764 if (!stream->n_samples)
7767 /* sample-to-chunk atom */
7768 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsc, &stream->stsc))
7771 /* copy atom data into a new buffer for later use */
7772 stream->stsc.data = g_memdup (stream->stsc.data, stream->stsc.size);
7774 /* skip version + flags */
7775 if (!gst_byte_reader_skip (&stream->stsc, 1 + 3) ||
7776 !gst_byte_reader_get_uint32_be (&stream->stsc,
7777 &stream->n_samples_per_chunk))
7780 GST_DEBUG_OBJECT (qtdemux, "n_samples_per_chunk %u",
7781 stream->n_samples_per_chunk);
7783 /* make sure there's enough data */
7784 if (!qt_atom_parser_has_chunks (&stream->stsc, stream->n_samples_per_chunk,
7790 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stco, &stream->stco))
7791 stream->co_size = sizeof (guint32);
7792 else if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_co64,
7794 stream->co_size = sizeof (guint64);
7798 /* copy atom data into a new buffer for later use */
7799 stream->stco.data = g_memdup (stream->stco.data, stream->stco.size);
7801 /* skip version + flags */
7802 if (!gst_byte_reader_skip (&stream->stco, 1 + 3))
7805 /* chunks_are_samples == TRUE means treat chunks as samples */
7806 stream->chunks_are_samples = stream->sample_size && !stream->sampled;
7807 if (stream->chunks_are_samples) {
7808 /* treat chunks as samples */
7809 if (!gst_byte_reader_get_uint32_be (&stream->stco, &stream->n_samples))
7812 /* skip number of entries */
7813 if (!gst_byte_reader_skip (&stream->stco, 4))
7816 /* make sure there are enough data in the stsz atom */
7817 if (!stream->sample_size) {
7818 /* different sizes for each sample */
7819 if (!qt_atom_parser_has_chunks (&stream->stsz, stream->n_samples, 4))
7824 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
7825 stream->n_samples, (guint) sizeof (QtDemuxSample),
7826 stream->n_samples * sizeof (QtDemuxSample) / (1024.0 * 1024.0));
7828 if (stream->n_samples >=
7829 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample)) {
7830 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
7831 "be larger than %uMB (broken file?)", stream->n_samples,
7832 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
7836 g_assert (stream->samples == NULL);
7837 stream->samples = g_try_new0 (QtDemuxSample, stream->n_samples);
7838 if (!stream->samples) {
7839 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
7844 /* composition time-to-sample */
7845 if ((stream->ctts_present =
7846 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_ctts,
7847 &stream->ctts) ? TRUE : FALSE) == TRUE) {
7848 GstByteReader cslg = GST_BYTE_READER_INIT (NULL, 0);
7850 /* copy atom data into a new buffer for later use */
7851 stream->ctts.data = g_memdup (stream->ctts.data, stream->ctts.size);
7853 /* skip version + flags */
7854 if (!gst_byte_reader_skip (&stream->ctts, 1 + 3)
7855 || !gst_byte_reader_get_uint32_be (&stream->ctts,
7856 &stream->n_composition_times))
7859 /* make sure there's enough data */
7860 if (!qt_atom_parser_has_chunks (&stream->ctts, stream->n_composition_times,
7864 /* This is optional, if missing we iterate the ctts */
7865 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_cslg, &cslg)) {
7866 if (!gst_byte_reader_skip (&cslg, 1 + 3)
7867 || !gst_byte_reader_get_uint32_be (&cslg, &stream->cslg_shift)) {
7868 g_free ((gpointer) cslg.data);
7872 gint32 cslg_least = 0;
7873 guint num_entries, pos;
7876 pos = gst_byte_reader_get_pos (&stream->ctts);
7877 num_entries = stream->n_composition_times;
7879 stream->cslg_shift = 0;
7881 for (i = 0; i < num_entries; i++) {
7884 gst_byte_reader_skip_unchecked (&stream->ctts, 4);
7885 offset = gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
7887 if (offset < cslg_least)
7888 cslg_least = offset;
7892 stream->cslg_shift = ABS (cslg_least);
7894 stream->cslg_shift = 0;
7896 /* reset the reader so we can generate sample table */
7897 gst_byte_reader_set_pos (&stream->ctts, pos);
7900 /* Ensure the cslg_shift value is consistent so we can use it
7901 * unconditionnally to produce TS and Segment */
7902 stream->cslg_shift = 0;
7909 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
7910 (_("This file is corrupt and cannot be played.")), (NULL));
7915 gst_qtdemux_stbl_free (stream);
7916 if (!qtdemux->fragmented) {
7917 /* not quite good */
7918 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
7921 /* may pick up samples elsewhere */
7927 /* collect samples from the next sample to be parsed up to sample @n for @stream
7928 * by reading the info from @stbl
7930 * This code can be executed from both the streaming thread and the seeking
7931 * thread so it takes the object lock to protect itself
7934 qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream, guint32 n)
7937 QtDemuxSample *samples, *first, *cur, *last;
7938 guint32 n_samples_per_chunk;
7941 GST_LOG_OBJECT (qtdemux, "parsing samples for stream fourcc %"
7942 GST_FOURCC_FORMAT ", pad %s", GST_FOURCC_ARGS (stream->fourcc),
7943 stream->pad ? GST_PAD_NAME (stream->pad) : "(NULL)");
7945 n_samples = stream->n_samples;
7948 goto out_of_samples;
7950 GST_OBJECT_LOCK (qtdemux);
7951 if (n <= stream->stbl_index)
7952 goto already_parsed;
7954 GST_DEBUG_OBJECT (qtdemux, "parsing up to sample %u", n);
7956 if (!stream->stsz.data) {
7957 /* so we already parsed and passed all the moov samples;
7958 * onto fragmented ones */
7959 g_assert (qtdemux->fragmented);
7963 /* pointer to the sample table */
7964 samples = stream->samples;
7966 /* starts from -1, moves to the next sample index to parse */
7967 stream->stbl_index++;
7969 /* keep track of the first and last sample to fill */
7970 first = &samples[stream->stbl_index];
7973 if (!stream->chunks_are_samples) {
7974 /* set the sample sizes */
7975 if (stream->sample_size == 0) {
7976 /* different sizes for each sample */
7977 for (cur = first; cur <= last; cur++) {
7978 cur->size = gst_byte_reader_get_uint32_be_unchecked (&stream->stsz);
7979 GST_LOG_OBJECT (qtdemux, "sample %d has size %u",
7980 (guint) (cur - samples), cur->size);
7983 /* samples have the same size */
7984 GST_LOG_OBJECT (qtdemux, "all samples have size %u", stream->sample_size);
7985 for (cur = first; cur <= last; cur++)
7986 cur->size = stream->sample_size;
7990 n_samples_per_chunk = stream->n_samples_per_chunk;
7993 for (i = stream->stsc_index; i < n_samples_per_chunk; i++) {
7996 if (stream->stsc_chunk_index >= stream->last_chunk
7997 || stream->stsc_chunk_index < stream->first_chunk) {
7998 stream->first_chunk =
7999 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
8000 stream->samples_per_chunk =
8001 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
8002 gst_byte_reader_skip_unchecked (&stream->stsc, 4);
8004 /* chunk numbers are counted from 1 it seems */
8005 if (G_UNLIKELY (stream->first_chunk == 0))
8008 --stream->first_chunk;
8010 /* the last chunk of each entry is calculated by taking the first chunk
8011 * of the next entry; except if there is no next, where we fake it with
8013 if (G_UNLIKELY (i == (stream->n_samples_per_chunk - 1))) {
8014 stream->last_chunk = G_MAXUINT32;
8016 stream->last_chunk =
8017 gst_byte_reader_peek_uint32_be_unchecked (&stream->stsc);
8018 if (G_UNLIKELY (stream->last_chunk == 0))
8021 --stream->last_chunk;
8024 GST_LOG_OBJECT (qtdemux,
8025 "entry %d has first_chunk %d, last_chunk %d, samples_per_chunk %d", i,
8026 stream->first_chunk, stream->last_chunk, stream->samples_per_chunk);
8028 if (G_UNLIKELY (stream->last_chunk < stream->first_chunk))
8031 if (stream->last_chunk != G_MAXUINT32) {
8032 if (!qt_atom_parser_peek_sub (&stream->stco,
8033 stream->first_chunk * stream->co_size,
8034 (stream->last_chunk - stream->first_chunk) * stream->co_size,
8039 stream->co_chunk = stream->stco;
8040 if (!gst_byte_reader_skip (&stream->co_chunk,
8041 stream->first_chunk * stream->co_size))
8045 stream->stsc_chunk_index = stream->first_chunk;
8048 last_chunk = stream->last_chunk;
8050 if (stream->chunks_are_samples) {
8051 cur = &samples[stream->stsc_chunk_index];
8053 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
8056 stream->stsc_chunk_index = j;
8061 qt_atom_parser_get_offset_unchecked (&stream->co_chunk,
8064 GST_LOG_OBJECT (qtdemux, "Created entry %d with offset "
8065 "%" G_GUINT64_FORMAT, j, cur->offset);
8067 if (stream->samples_per_frame * stream->bytes_per_frame) {
8069 (stream->samples_per_chunk * stream->n_channels) /
8070 stream->samples_per_frame * stream->bytes_per_frame;
8072 cur->size = stream->samples_per_chunk;
8075 GST_DEBUG_OBJECT (qtdemux,
8076 "keyframe sample %d: timestamp %" GST_TIME_FORMAT ", size %u",
8077 j, GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream,
8078 stream->stco_sample_index)), cur->size);
8080 cur->timestamp = stream->stco_sample_index;
8081 cur->duration = stream->samples_per_chunk;
8082 cur->keyframe = TRUE;
8085 stream->stco_sample_index += stream->samples_per_chunk;
8087 stream->stsc_chunk_index = j;
8089 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
8090 guint32 samples_per_chunk;
8091 guint64 chunk_offset;
8093 if (!stream->stsc_sample_index
8094 && !qt_atom_parser_get_offset (&stream->co_chunk, stream->co_size,
8095 &stream->chunk_offset))
8098 samples_per_chunk = stream->samples_per_chunk;
8099 chunk_offset = stream->chunk_offset;
8101 for (k = stream->stsc_sample_index; k < samples_per_chunk; k++) {
8102 GST_LOG_OBJECT (qtdemux, "creating entry %d with offset %"
8103 G_GUINT64_FORMAT " and size %d",
8104 (guint) (cur - samples), chunk_offset, cur->size);
8106 cur->offset = chunk_offset;
8107 chunk_offset += cur->size;
8110 if (G_UNLIKELY (cur > last)) {
8112 stream->stsc_sample_index = k + 1;
8113 stream->chunk_offset = chunk_offset;
8114 stream->stsc_chunk_index = j;
8118 stream->stsc_sample_index = 0;
8120 stream->stsc_chunk_index = j;
8122 stream->stsc_index++;
8125 if (stream->chunks_are_samples)
8129 guint32 n_sample_times;
8131 n_sample_times = stream->n_sample_times;
8134 for (i = stream->stts_index; i < n_sample_times; i++) {
8135 guint32 stts_samples;
8136 gint32 stts_duration;
8139 if (stream->stts_sample_index >= stream->stts_samples
8140 || !stream->stts_sample_index) {
8142 stream->stts_samples =
8143 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
8144 stream->stts_duration =
8145 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
8147 GST_LOG_OBJECT (qtdemux, "block %d, %u timestamps, duration %u",
8148 i, stream->stts_samples, stream->stts_duration);
8150 stream->stts_sample_index = 0;
8153 stts_samples = stream->stts_samples;
8154 stts_duration = stream->stts_duration;
8155 stts_time = stream->stts_time;
8157 for (j = stream->stts_sample_index; j < stts_samples; j++) {
8158 GST_DEBUG_OBJECT (qtdemux,
8159 "sample %d: index %d, timestamp %" GST_TIME_FORMAT,
8160 (guint) (cur - samples), j,
8161 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stts_time)));
8163 cur->timestamp = stts_time;
8164 cur->duration = stts_duration;
8166 /* avoid 32-bit wrap-around,
8167 * but still mind possible 'negative' duration */
8168 stts_time += (gint64) stts_duration;
8171 if (G_UNLIKELY (cur > last)) {
8173 stream->stts_time = stts_time;
8174 stream->stts_sample_index = j + 1;
8178 stream->stts_sample_index = 0;
8179 stream->stts_time = stts_time;
8180 stream->stts_index++;
8182 /* fill up empty timestamps with the last timestamp, this can happen when
8183 * the last samples do not decode and so we don't have timestamps for them.
8184 * We however look at the last timestamp to estimate the track length so we
8185 * need something in here. */
8186 for (; cur < last; cur++) {
8187 GST_DEBUG_OBJECT (qtdemux,
8188 "fill sample %d: timestamp %" GST_TIME_FORMAT,
8189 (guint) (cur - samples),
8190 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stream->stts_time)));
8191 cur->timestamp = stream->stts_time;
8197 /* sample sync, can be NULL */
8198 if (stream->stss_present == TRUE) {
8199 guint32 n_sample_syncs;
8201 n_sample_syncs = stream->n_sample_syncs;
8203 if (!n_sample_syncs) {
8204 GST_DEBUG_OBJECT (qtdemux, "all samples are keyframes");
8205 stream->all_keyframe = TRUE;
8207 for (i = stream->stss_index; i < n_sample_syncs; i++) {
8208 /* note that the first sample is index 1, not 0 */
8211 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stss);
8213 if (G_LIKELY (index > 0 && index <= n_samples)) {
8215 samples[index].keyframe = TRUE;
8216 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
8217 /* and exit if we have enough samples */
8218 if (G_UNLIKELY (index >= n)) {
8225 stream->stss_index = i;
8228 /* stps marks partial sync frames like open GOP I-Frames */
8229 if (stream->stps_present == TRUE) {
8230 guint32 n_sample_partial_syncs;
8232 n_sample_partial_syncs = stream->n_sample_partial_syncs;
8234 /* if there are no entries, the stss table contains the real
8236 if (n_sample_partial_syncs) {
8237 for (i = stream->stps_index; i < n_sample_partial_syncs; i++) {
8238 /* note that the first sample is index 1, not 0 */
8241 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stps);
8243 if (G_LIKELY (index > 0 && index <= n_samples)) {
8245 samples[index].keyframe = TRUE;
8246 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
8247 /* and exit if we have enough samples */
8248 if (G_UNLIKELY (index >= n)) {
8255 stream->stps_index = i;
8259 /* no stss, all samples are keyframes */
8260 stream->all_keyframe = TRUE;
8261 GST_DEBUG_OBJECT (qtdemux, "setting all keyframes");
8266 /* composition time to sample */
8267 if (stream->ctts_present == TRUE) {
8268 guint32 n_composition_times;
8270 gint32 ctts_soffset;
8272 /* Fill in the pts_offsets */
8274 n_composition_times = stream->n_composition_times;
8276 for (i = stream->ctts_index; i < n_composition_times; i++) {
8277 if (stream->ctts_sample_index >= stream->ctts_count
8278 || !stream->ctts_sample_index) {
8279 stream->ctts_count =
8280 gst_byte_reader_get_uint32_be_unchecked (&stream->ctts);
8281 stream->ctts_soffset =
8282 gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
8283 stream->ctts_sample_index = 0;
8286 ctts_count = stream->ctts_count;
8287 ctts_soffset = stream->ctts_soffset;
8289 for (j = stream->ctts_sample_index; j < ctts_count; j++) {
8290 cur->pts_offset = ctts_soffset;
8293 if (G_UNLIKELY (cur > last)) {
8295 stream->ctts_sample_index = j + 1;
8299 stream->ctts_sample_index = 0;
8300 stream->ctts_index++;
8304 stream->stbl_index = n;
8305 /* if index has been completely parsed, free data that is no-longer needed */
8306 if (n + 1 == stream->n_samples) {
8307 gst_qtdemux_stbl_free (stream);
8308 GST_DEBUG_OBJECT (qtdemux, "parsed all available samples;");
8309 if (qtdemux->pullbased) {
8310 GST_DEBUG_OBJECT (qtdemux, "checking for more samples");
8311 while (n + 1 == stream->n_samples)
8312 if (qtdemux_add_fragmented_samples (qtdemux) != GST_FLOW_OK)
8316 GST_OBJECT_UNLOCK (qtdemux);
8323 GST_LOG_OBJECT (qtdemux,
8324 "Tried to parse up to sample %u but this sample has already been parsed",
8326 /* if fragmented, there may be more */
8327 if (qtdemux->fragmented && n == stream->stbl_index)
8329 GST_OBJECT_UNLOCK (qtdemux);
8335 GST_LOG_OBJECT (qtdemux,
8336 "Tried to parse up to sample %u but there are only %u samples", n + 1,
8338 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8339 (_("This file is corrupt and cannot be played.")), (NULL));
8344 GST_OBJECT_UNLOCK (qtdemux);
8345 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8346 (_("This file is corrupt and cannot be played.")), (NULL));
8351 /* collect all segment info for @stream.
8354 qtdemux_parse_segments (GstQTDemux * qtdemux, QtDemuxStream * stream,
8358 /* accept edts if they contain gaps at start and there is only
8359 * one media segment */
8360 gboolean allow_pushbased_edts = TRUE;
8361 gint media_segments_count = 0;
8363 /* parse and prepare segment info from the edit list */
8364 GST_DEBUG_OBJECT (qtdemux, "looking for edit list container");
8365 stream->n_segments = 0;
8366 stream->segments = NULL;
8367 if ((edts = qtdemux_tree_get_child_by_type (trak, FOURCC_edts))) {
8375 GST_DEBUG_OBJECT (qtdemux, "looking for edit list");
8376 if (!(elst = qtdemux_tree_get_child_by_type (edts, FOURCC_elst)))
8379 buffer = elst->data;
8381 n_segments = QT_UINT32 (buffer + 12);
8383 /* we might allocate a bit too much, at least allocate 1 segment */
8384 stream->segments = g_new (QtDemuxSegment, MAX (n_segments, 1));
8386 /* segments always start from 0 */
8390 for (i = 0; i < n_segments; i++) {
8393 QtDemuxSegment *segment;
8395 GstClockTime media_start = GST_CLOCK_TIME_NONE;
8397 media_time = QT_UINT32 (buffer + 20 + i * 12);
8398 duration = QT_UINT32 (buffer + 16 + i * 12);
8400 if (media_time != G_MAXUINT32)
8401 media_start = QTSTREAMTIME_TO_GSTTIME (stream, media_time);
8403 segment = &stream->segments[count++];
8405 /* time and duration expressed in global timescale */
8406 segment->time = stime;
8407 /* add non scaled values so we don't cause roundoff errors */
8408 if (duration || media_start == GST_CLOCK_TIME_NONE) {
8410 stime = QTTIME_TO_GSTTIME (qtdemux, time);
8411 segment->duration = stime - segment->time;
8413 /* zero duration does not imply media_start == media_stop
8414 * but, only specify media_start.*/
8415 stime = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
8416 if (GST_CLOCK_TIME_IS_VALID (stime) && media_time != G_MAXUINT32
8417 && stime >= media_start) {
8418 segment->duration = stime - media_start;
8420 segment->duration = GST_CLOCK_TIME_NONE;
8423 segment->stop_time = stime;
8425 segment->trak_media_start = media_time;
8426 /* media_time expressed in stream timescale */
8427 if (media_time != G_MAXUINT32) {
8428 segment->media_start = media_start;
8429 segment->media_stop = segment->media_start + segment->duration;
8430 media_segments_count++;
8432 segment->media_start = GST_CLOCK_TIME_NONE;
8433 segment->media_stop = GST_CLOCK_TIME_NONE;
8435 rate_int = GST_READ_UINT32_BE (buffer + 24 + i * 12);
8437 if (rate_int <= 1) {
8438 /* 0 is not allowed, some programs write 1 instead of the floating point
8440 GST_WARNING_OBJECT (qtdemux, "found suspicious rate %" G_GUINT32_FORMAT,
8444 segment->rate = rate_int / 65536.0;
8447 GST_DEBUG_OBJECT (qtdemux, "created segment %d time %" GST_TIME_FORMAT
8448 ", duration %" GST_TIME_FORMAT ", media_start %" GST_TIME_FORMAT
8449 " (%" G_GUINT64_FORMAT ") , media_stop %" GST_TIME_FORMAT
8450 " stop_time %" GST_TIME_FORMAT " rate %g, (%d) timescale %u",
8451 i, GST_TIME_ARGS (segment->time),
8452 GST_TIME_ARGS (segment->duration),
8453 GST_TIME_ARGS (segment->media_start), media_time,
8454 GST_TIME_ARGS (segment->media_stop),
8455 GST_TIME_ARGS (segment->stop_time), segment->rate, rate_int,
8457 if (segment->stop_time > qtdemux->segment.stop) {
8458 GST_WARNING_OBJECT (qtdemux, "Segment %d "
8459 " extends to %" GST_TIME_FORMAT
8460 " past the end of the file duration %" GST_TIME_FORMAT
8461 " it will be truncated", i, GST_TIME_ARGS (segment->stop_time),
8462 GST_TIME_ARGS (qtdemux->segment.stop));
8463 qtdemux->segment.stop = segment->stop_time;
8466 GST_DEBUG_OBJECT (qtdemux, "found %d segments", count);
8467 stream->n_segments = count;
8468 if (media_segments_count != 1)
8469 allow_pushbased_edts = FALSE;
8473 /* push based does not handle segments, so act accordingly here,
8474 * and warn if applicable */
8475 if (!qtdemux->pullbased && !allow_pushbased_edts) {
8476 GST_WARNING_OBJECT (qtdemux, "streaming; discarding edit list segments");
8477 /* remove and use default one below, we stream like it anyway */
8478 g_free (stream->segments);
8479 stream->segments = NULL;
8480 stream->n_segments = 0;
8483 /* no segments, create one to play the complete trak */
8484 if (stream->n_segments == 0) {
8485 GstClockTime stream_duration =
8486 QTSTREAMTIME_TO_GSTTIME (stream, stream->duration);
8488 if (stream->segments == NULL)
8489 stream->segments = g_new (QtDemuxSegment, 1);
8491 /* represent unknown our way */
8492 if (stream_duration == 0)
8493 stream_duration = GST_CLOCK_TIME_NONE;
8495 stream->segments[0].time = 0;
8496 stream->segments[0].stop_time = stream_duration;
8497 stream->segments[0].duration = stream_duration;
8498 stream->segments[0].media_start = 0;
8499 stream->segments[0].media_stop = stream_duration;
8500 stream->segments[0].rate = 1.0;
8501 stream->segments[0].trak_media_start = 0;
8503 GST_DEBUG_OBJECT (qtdemux, "created dummy segment %" GST_TIME_FORMAT,
8504 GST_TIME_ARGS (stream_duration));
8505 stream->n_segments = 1;
8506 stream->dummy_segment = TRUE;
8508 GST_DEBUG_OBJECT (qtdemux, "using %d segments", stream->n_segments);
8514 * Parses the stsd atom of a svq3 trak looking for
8515 * the SMI and gama atoms.
8518 qtdemux_parse_svq3_stsd_data (GstQTDemux * qtdemux, GNode * stsd,
8519 guint8 ** gamma, GstBuffer ** seqh)
8521 guint8 *_gamma = NULL;
8522 GstBuffer *_seqh = NULL;
8523 guint8 *stsd_data = stsd->data;
8524 guint32 length = QT_UINT32 (stsd_data);
8528 GST_WARNING_OBJECT (qtdemux, "stsd too short");
8534 version = QT_UINT16 (stsd_data);
8539 while (length > 8) {
8540 guint32 fourcc, size;
8542 size = QT_UINT32 (stsd_data);
8543 fourcc = QT_FOURCC (stsd_data + 4);
8544 data = stsd_data + 8;
8547 GST_WARNING_OBJECT (qtdemux, "Atom of size 0 found, aborting "
8548 "svq3 atom parsing");
8557 GST_WARNING_OBJECT (qtdemux, "Unexpected size %" G_GUINT32_FORMAT
8558 " for gama atom, expected 12", size);
8563 if (size > 16 && QT_FOURCC (data) == FOURCC_SEQH) {
8565 if (_seqh != NULL) {
8566 GST_WARNING_OBJECT (qtdemux, "Unexpected second SEQH SMI atom "
8567 " found, ignoring");
8569 seqh_size = QT_UINT32 (data + 4);
8570 if (seqh_size > 0) {
8571 _seqh = gst_buffer_new_and_alloc (seqh_size);
8572 gst_buffer_fill (_seqh, 0, data + 8, seqh_size);
8579 GST_WARNING_OBJECT (qtdemux, "Unhandled atom %" GST_FOURCC_FORMAT
8580 " in SVQ3 entry in stsd atom", GST_FOURCC_ARGS (fourcc));
8584 if (size <= length) {
8590 GST_WARNING_OBJECT (qtdemux, "SVQ3 entry too short in stsd atom");
8593 GST_WARNING_OBJECT (qtdemux, "Unexpected version for SVQ3 entry %"
8594 G_GUINT16_FORMAT, version);
8605 gst_buffer_unref (_seqh);
8610 qtdemux_get_rtsp_uri_from_hndl (GstQTDemux * qtdemux, GNode * minf)
8617 * Get 'dinf', to get its child 'dref', that might contain a 'hndl'
8618 * atom that might contain a 'data' atom with the rtsp uri.
8619 * This case was reported in bug #597497, some info about
8620 * the hndl atom can be found in TN1195
8622 dinf = qtdemux_tree_get_child_by_type (minf, FOURCC_dinf);
8623 GST_DEBUG_OBJECT (qtdemux, "Trying to obtain rtsp URI for stream trak");
8626 guint32 dref_num_entries = 0;
8627 if (qtdemux_tree_get_child_by_type_full (dinf, FOURCC_dref, &dref) &&
8628 gst_byte_reader_skip (&dref, 4) &&
8629 gst_byte_reader_get_uint32_be (&dref, &dref_num_entries)) {
8632 /* search dref entries for hndl atom */
8633 for (i = 0; i < dref_num_entries; i++) {
8634 guint32 size = 0, type;
8635 guint8 string_len = 0;
8636 if (gst_byte_reader_get_uint32_be (&dref, &size) &&
8637 qt_atom_parser_get_fourcc (&dref, &type)) {
8638 if (type == FOURCC_hndl) {
8639 GST_DEBUG_OBJECT (qtdemux, "Found hndl atom");
8641 /* skip data reference handle bytes and the
8642 * following pascal string and some extra 4
8643 * bytes I have no idea what are */
8644 if (!gst_byte_reader_skip (&dref, 4) ||
8645 !gst_byte_reader_get_uint8 (&dref, &string_len) ||
8646 !gst_byte_reader_skip (&dref, string_len + 4)) {
8647 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl atom");
8651 /* iterate over the atoms to find the data atom */
8652 while (gst_byte_reader_get_remaining (&dref) >= 8) {
8656 if (gst_byte_reader_get_uint32_be (&dref, &atom_size) &&
8657 qt_atom_parser_get_fourcc (&dref, &atom_type)) {
8658 if (atom_type == FOURCC_data) {
8659 const guint8 *uri_aux = NULL;
8661 /* found the data atom that might contain the rtsp uri */
8662 GST_DEBUG_OBJECT (qtdemux, "Found data atom inside "
8663 "hndl atom, interpreting it as an URI");
8664 if (gst_byte_reader_peek_data (&dref, atom_size - 8,
8666 if (g_strstr_len ((gchar *) uri_aux, 7, "rtsp://") != NULL)
8667 uri = g_strndup ((gchar *) uri_aux, atom_size - 8);
8669 GST_WARNING_OBJECT (qtdemux, "Data atom in hndl atom "
8670 "didn't contain a rtsp address");
8672 GST_WARNING_OBJECT (qtdemux, "Failed to get the data "
8677 /* skipping to the next entry */
8678 if (!gst_byte_reader_skip (&dref, atom_size - 8))
8681 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl child "
8688 /* skip to the next entry */
8689 if (!gst_byte_reader_skip (&dref, size - 8))
8692 GST_WARNING_OBJECT (qtdemux, "Error parsing dref atom");
8695 GST_DEBUG_OBJECT (qtdemux, "Finished parsing dref atom");
8701 #define AMR_NB_ALL_MODES 0x81ff
8702 #define AMR_WB_ALL_MODES 0x83ff
8704 qtdemux_parse_amr_bitrate (GstBuffer * buf, gboolean wb)
8706 /* The 'damr' atom is of the form:
8708 * | vendor | decoder_ver | mode_set | mode_change_period | frames/sample |
8709 * 32 b 8 b 16 b 8 b 8 b
8711 * The highest set bit of the first 7 (AMR-NB) or 8 (AMR-WB) bits of mode_set
8712 * represents the highest mode used in the stream (and thus the maximum
8713 * bitrate), with a couple of special cases as seen below.
8716 /* Map of frame type ID -> bitrate */
8717 static const guint nb_bitrates[] = {
8718 4750, 5150, 5900, 6700, 7400, 7950, 10200, 12200
8720 static const guint wb_bitrates[] = {
8721 6600, 8850, 12650, 14250, 15850, 18250, 19850, 23050, 23850
8727 gst_buffer_map (buf, &map, GST_MAP_READ);
8729 if (map.size != 0x11) {
8730 GST_DEBUG ("Atom should have size 0x11, not %" G_GSIZE_FORMAT, map.size);
8734 if (QT_FOURCC (map.data + 4) != FOURCC_damr) {
8735 GST_DEBUG ("Unknown atom in %" GST_FOURCC_FORMAT,
8736 GST_FOURCC_ARGS (QT_UINT32 (map.data + 4)));
8740 mode_set = QT_UINT16 (map.data + 13);
8742 if (mode_set == (wb ? AMR_WB_ALL_MODES : AMR_NB_ALL_MODES))
8743 max_mode = 7 + (wb ? 1 : 0);
8745 /* AMR-NB modes fo from 0-7, and AMR-WB modes go from 0-8 */
8746 max_mode = g_bit_nth_msf ((gulong) mode_set & (wb ? 0x1ff : 0xff), -1);
8748 if (max_mode == -1) {
8749 GST_DEBUG ("No mode indication was found (mode set) = %x",
8754 gst_buffer_unmap (buf, &map);
8755 return wb ? wb_bitrates[max_mode] : nb_bitrates[max_mode];
8758 gst_buffer_unmap (buf, &map);
8763 qtdemux_parse_transformation_matrix (GstQTDemux * qtdemux,
8764 GstByteReader * reader, guint32 * matrix, const gchar * atom)
8767 * 9 values of 32 bits (fixed point 16.16, except 2 5 and 8 that are 2.30)
8773 if (gst_byte_reader_get_remaining (reader) < 36)
8776 matrix[0] = gst_byte_reader_get_uint32_be_unchecked (reader);
8777 matrix[1] = gst_byte_reader_get_uint32_be_unchecked (reader);
8778 matrix[2] = gst_byte_reader_get_uint32_be_unchecked (reader);
8779 matrix[3] = gst_byte_reader_get_uint32_be_unchecked (reader);
8780 matrix[4] = gst_byte_reader_get_uint32_be_unchecked (reader);
8781 matrix[5] = gst_byte_reader_get_uint32_be_unchecked (reader);
8782 matrix[6] = gst_byte_reader_get_uint32_be_unchecked (reader);
8783 matrix[7] = gst_byte_reader_get_uint32_be_unchecked (reader);
8784 matrix[8] = gst_byte_reader_get_uint32_be_unchecked (reader);
8786 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix from atom %s", atom);
8787 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[0] >> 16,
8788 matrix[0] & 0xFFFF, matrix[1] >> 16, matrix[1] & 0xFF, matrix[2] >> 16,
8790 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[3] >> 16,
8791 matrix[3] & 0xFFFF, matrix[4] >> 16, matrix[4] & 0xFF, matrix[5] >> 16,
8793 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[6] >> 16,
8794 matrix[6] & 0xFFFF, matrix[7] >> 16, matrix[7] & 0xFF, matrix[8] >> 16,
8801 qtdemux_inspect_transformation_matrix (GstQTDemux * qtdemux,
8802 QtDemuxStream * stream, guint32 * matrix, GstTagList ** taglist)
8809 * This macro will only compare value abdegh, it expects cfi to have already
8812 #define QTCHECK_MATRIX(m,a,b,d,e) ((m)[0] == (a << 16) && (m)[1] == (b << 16) && \
8813 (m)[3] == (d << 16) && (m)[4] == (e << 16))
8815 /* only handle the cases where the last column has standard values */
8816 if (matrix[2] == 0 && matrix[5] == 0 && matrix[8] == 1 << 30) {
8817 const gchar *rotation_tag = NULL;
8819 /* no rotation needed */
8820 if (QTCHECK_MATRIX (matrix, 1, 0, 0, 1)) {
8822 } else if (QTCHECK_MATRIX (matrix, 0, 1, G_MAXUINT16, 0)) {
8823 rotation_tag = "rotate-90";
8824 } else if (QTCHECK_MATRIX (matrix, G_MAXUINT16, 0, 0, G_MAXUINT16)) {
8825 rotation_tag = "rotate-180";
8826 } else if (QTCHECK_MATRIX (matrix, 0, G_MAXUINT16, 1, 0)) {
8827 rotation_tag = "rotate-270";
8829 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
8832 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix rotation %s",
8834 if (rotation_tag != NULL) {
8835 if (*taglist == NULL)
8836 *taglist = gst_tag_list_new_empty ();
8837 gst_tag_list_add (*taglist, GST_TAG_MERGE_REPLACE,
8838 GST_TAG_IMAGE_ORIENTATION, rotation_tag, NULL);
8841 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
8845 /* Parses the boxes defined in ISO/IEC 14496-12 that enable support for
8846 * protected streams (sinf, frma, schm and schi); if the protection scheme is
8847 * Common Encryption (cenc), the function will also parse the tenc box (defined
8848 * in ISO/IEC 23001-7). @container points to the node that contains these boxes
8849 * (typically an enc[v|a|t|s] sample entry); the function will set
8850 * @original_fmt to the fourcc of the original unencrypted stream format.
8851 * Returns TRUE if successful; FALSE otherwise. */
8853 qtdemux_parse_protection_scheme_info (GstQTDemux * qtdemux,
8854 QtDemuxStream * stream, GNode * container, guint32 * original_fmt)
8861 g_return_val_if_fail (qtdemux != NULL, FALSE);
8862 g_return_val_if_fail (stream != NULL, FALSE);
8863 g_return_val_if_fail (container != NULL, FALSE);
8864 g_return_val_if_fail (original_fmt != NULL, FALSE);
8866 sinf = qtdemux_tree_get_child_by_type (container, FOURCC_sinf);
8867 if (G_UNLIKELY (!sinf)) {
8868 if (stream->protection_scheme_type == FOURCC_cenc) {
8869 GST_ERROR_OBJECT (qtdemux, "sinf box does not contain schi box, which is "
8870 "mandatory for Common Encryption");
8876 frma = qtdemux_tree_get_child_by_type (sinf, FOURCC_frma);
8877 if (G_UNLIKELY (!frma)) {
8878 GST_ERROR_OBJECT (qtdemux, "sinf box does not contain mandatory frma box");
8882 *original_fmt = QT_FOURCC ((const guint8 *) frma->data + 8);
8883 GST_DEBUG_OBJECT (qtdemux, "original stream format: '%" GST_FOURCC_FORMAT "'",
8884 GST_FOURCC_ARGS (*original_fmt));
8886 schm = qtdemux_tree_get_child_by_type (sinf, FOURCC_schm);
8888 GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schm box");
8891 stream->protection_scheme_type = QT_FOURCC ((const guint8 *) schm->data + 12);
8892 stream->protection_scheme_version =
8893 QT_UINT32 ((const guint8 *) schm->data + 16);
8895 GST_DEBUG_OBJECT (qtdemux,
8896 "protection_scheme_type: %" GST_FOURCC_FORMAT ", "
8897 "protection_scheme_version: %#010x",
8898 GST_FOURCC_ARGS (stream->protection_scheme_type),
8899 stream->protection_scheme_version);
8901 schi = qtdemux_tree_get_child_by_type (sinf, FOURCC_schi);
8903 GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schi box");
8906 if (stream->protection_scheme_type == FOURCC_cenc) {
8907 QtDemuxCencSampleSetInfo *info;
8909 const guint8 *tenc_data;
8910 guint32 isEncrypted;
8912 const guint8 *default_kid;
8915 if (G_UNLIKELY (!stream->protection_scheme_info))
8916 stream->protection_scheme_info =
8917 g_malloc0 (sizeof (QtDemuxCencSampleSetInfo));
8919 info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
8921 tenc = qtdemux_tree_get_child_by_type (schi, FOURCC_tenc);
8923 GST_ERROR_OBJECT (qtdemux, "schi box does not contain tenc box, "
8924 "which is mandatory for Common Encryption");
8927 tenc_data = (const guint8 *) tenc->data + 12;
8928 isEncrypted = QT_UINT24 (tenc_data);
8929 iv_size = QT_UINT8 (tenc_data + 3);
8930 default_kid = (tenc_data + 4);
8931 kid_buf = gst_buffer_new_allocate (NULL, 16, NULL);
8932 gst_buffer_fill (kid_buf, 0, default_kid, 16);
8933 if (info->default_properties)
8934 gst_structure_free (info->default_properties);
8935 info->default_properties =
8936 gst_structure_new ("application/x-cenc",
8937 "iv_size", G_TYPE_UINT, iv_size,
8938 "encrypted", G_TYPE_BOOLEAN, (isEncrypted == 1),
8939 "kid", GST_TYPE_BUFFER, kid_buf, NULL);
8940 GST_DEBUG_OBJECT (qtdemux, "default sample properties: "
8941 "is_encrypted=%u, iv_size=%u", isEncrypted, iv_size);
8942 gst_buffer_unref (kid_buf);
8948 * With each track we associate a new QtDemuxStream that contains all the info
8950 * traks that do not decode to something (like strm traks) will not have a pad.
8953 qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
8972 QtDemuxStream *stream = NULL;
8973 gboolean new_stream = FALSE;
8974 gchar *codec = NULL;
8975 const guint8 *stsd_data;
8976 guint16 lang_code; /* quicktime lang code or packed iso code */
8978 guint32 tkhd_flags = 0;
8979 guint8 tkhd_version = 0;
8981 guint value_size, stsd_len, len;
8985 GST_DEBUG_OBJECT (qtdemux, "parse_trak");
8987 if (!qtdemux_tree_get_child_by_type_full (trak, FOURCC_tkhd, &tkhd)
8988 || !gst_byte_reader_get_uint8 (&tkhd, &tkhd_version)
8989 || !gst_byte_reader_get_uint24_be (&tkhd, &tkhd_flags))
8992 /* pick between 64 or 32 bits */
8993 value_size = tkhd_version == 1 ? 8 : 4;
8994 if (!gst_byte_reader_skip (&tkhd, value_size * 2) ||
8995 !gst_byte_reader_get_uint32_be (&tkhd, &track_id))
8998 if (!qtdemux->got_moov) {
8999 if (qtdemux_find_stream (qtdemux, track_id))
9000 goto existing_stream;
9001 stream = _create_stream ();
9002 stream->track_id = track_id;
9005 stream = qtdemux_find_stream (qtdemux, track_id);
9007 GST_WARNING_OBJECT (qtdemux, "Stream not found, going to ignore it");
9011 /* flush samples data from this track from previous moov */
9012 gst_qtdemux_stream_flush_segments_data (qtdemux, stream);
9013 gst_qtdemux_stream_flush_samples_data (qtdemux, stream);
9015 /* need defaults for fragments */
9016 qtdemux_parse_trex (qtdemux, stream, &dummy, &dummy, &dummy);
9018 if (stream->pending_tags == NULL)
9019 stream->pending_tags = gst_tag_list_new_empty ();
9021 if ((tkhd_flags & 1) == 0)
9022 stream->disabled = TRUE;
9024 GST_LOG_OBJECT (qtdemux, "track[tkhd] version/flags/id: 0x%02x/%06x/%u",
9025 tkhd_version, tkhd_flags, stream->track_id);
9027 if (!(mdia = qtdemux_tree_get_child_by_type (trak, FOURCC_mdia)))
9030 if (!(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mdhd))) {
9031 /* be nice for some crooked mjp2 files that use mhdr for mdhd */
9032 if (qtdemux->major_brand != FOURCC_mjp2 ||
9033 !(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mhdr)))
9037 len = QT_UINT32 ((guint8 *) mdhd->data);
9038 version = QT_UINT32 ((guint8 *) mdhd->data + 8);
9039 GST_LOG_OBJECT (qtdemux, "track version/flags: %08x", version);
9040 if (version == 0x01000000) {
9043 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 28);
9044 stream->duration = QT_UINT64 ((guint8 *) mdhd->data + 32);
9045 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 36);
9049 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 20);
9050 stream->duration = QT_UINT32 ((guint8 *) mdhd->data + 24);
9051 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 28);
9054 if (lang_code < 0x400) {
9055 qtdemux_lang_map_qt_code_to_iso (stream->lang_id, lang_code);
9056 } else if (lang_code == 0x7fff) {
9057 stream->lang_id[0] = 0; /* unspecified */
9059 stream->lang_id[0] = 0x60 + ((lang_code >> 10) & 0x1F);
9060 stream->lang_id[1] = 0x60 + ((lang_code >> 5) & 0x1F);
9061 stream->lang_id[2] = 0x60 + (lang_code & 0x1F);
9062 stream->lang_id[3] = 0;
9065 GST_LOG_OBJECT (qtdemux, "track timescale: %" G_GUINT32_FORMAT,
9067 GST_LOG_OBJECT (qtdemux, "track duration: %" G_GUINT64_FORMAT,
9069 GST_LOG_OBJECT (qtdemux, "track language code/id: 0x%04x/%s",
9070 lang_code, stream->lang_id);
9072 if (G_UNLIKELY (stream->timescale == 0 || qtdemux->timescale == 0))
9075 if ((tref = qtdemux_tree_get_child_by_type (trak, FOURCC_tref))) {
9076 /* chapters track reference */
9077 GNode *chap = qtdemux_tree_get_child_by_type (tref, FOURCC_chap);
9079 gsize length = GST_READ_UINT32_BE (chap->data);
9080 if (qtdemux->chapters_track_id)
9081 GST_FIXME_OBJECT (qtdemux, "Multiple CHAP tracks");
9084 qtdemux->chapters_track_id =
9085 GST_READ_UINT32_BE ((gint8 *) chap->data + 8);
9090 /* fragmented files may have bogus duration in moov */
9091 if (!qtdemux->fragmented &&
9092 qtdemux->duration != G_MAXINT64 && stream->duration != G_MAXINT32) {
9093 guint64 tdur1, tdur2;
9095 /* don't overflow */
9096 tdur1 = stream->timescale * (guint64) qtdemux->duration;
9097 tdur2 = qtdemux->timescale * (guint64) stream->duration;
9100 * some of those trailers, nowadays, have prologue images that are
9101 * themselves vide tracks as well. I haven't really found a way to
9102 * identify those yet, except for just looking at their duration. */
9103 if (tdur1 != 0 && (tdur2 * 10 / tdur1) < 2) {
9104 GST_WARNING_OBJECT (qtdemux,
9105 "Track shorter than 20%% (%" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT
9106 " vs. %" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT ") of the stream "
9107 "found, assuming preview image or something; skipping track",
9108 stream->duration, stream->timescale, qtdemux->duration,
9109 qtdemux->timescale);
9111 gst_qtdemux_stream_free (qtdemux, stream);
9116 if (!(hdlr = qtdemux_tree_get_child_by_type (mdia, FOURCC_hdlr)))
9119 GST_LOG_OBJECT (qtdemux, "track type: %" GST_FOURCC_FORMAT,
9120 GST_FOURCC_ARGS (QT_FOURCC ((guint8 *) hdlr->data + 12)));
9122 len = QT_UINT32 ((guint8 *) hdlr->data);
9124 stream->subtype = QT_FOURCC ((guint8 *) hdlr->data + 16);
9125 GST_LOG_OBJECT (qtdemux, "track subtype: %" GST_FOURCC_FORMAT,
9126 GST_FOURCC_ARGS (stream->subtype));
9128 if (!(minf = qtdemux_tree_get_child_by_type (mdia, FOURCC_minf)))
9131 if (!(stbl = qtdemux_tree_get_child_by_type (minf, FOURCC_stbl)))
9134 /*parse svmi header if existing */
9135 svmi = qtdemux_tree_get_child_by_type (stbl, FOURCC_svmi);
9137 len = QT_UINT32 ((guint8 *) svmi->data);
9138 version = QT_UINT32 ((guint8 *) svmi->data + 8);
9140 GstVideoMultiviewMode mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
9141 GstVideoMultiviewFlags flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
9142 guint8 frame_type, frame_layout;
9144 /* MPEG-A stereo video */
9145 if (qtdemux->major_brand == FOURCC_ss02)
9146 flags |= GST_VIDEO_MULTIVIEW_FLAGS_MIXED_MONO;
9148 frame_type = QT_UINT8 ((guint8 *) svmi->data + 12);
9149 frame_layout = QT_UINT8 ((guint8 *) svmi->data + 13) & 0x01;
9150 switch (frame_type) {
9152 mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
9155 mode = GST_VIDEO_MULTIVIEW_MODE_ROW_INTERLEAVED;
9158 mode = GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME;
9161 /* mode 3 is primary/secondary view sequence, ie
9162 * left/right views in separate tracks. See section 7.2
9163 * of ISO/IEC 23000-11:2009 */
9164 GST_FIXME_OBJECT (qtdemux,
9165 "Implement stereo video in separate streams");
9168 if ((frame_layout & 0x1) == 0)
9169 flags |= GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
9171 GST_LOG_OBJECT (qtdemux,
9172 "StereoVideo: composition type: %u, is_left_first: %u",
9173 frame_type, frame_layout);
9174 stream->multiview_mode = mode;
9175 stream->multiview_flags = flags;
9180 if (!(stsd = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsd)))
9182 stsd_data = (const guint8 *) stsd->data;
9184 /* stsd should at least have one entry */
9185 stsd_len = QT_UINT32 (stsd_data);
9186 if (stsd_len < 24) {
9187 /* .. but skip stream with empty stsd produced by some Vivotek cameras */
9188 if (stream->subtype == FOURCC_vivo) {
9190 gst_qtdemux_stream_free (qtdemux, stream);
9197 GST_LOG_OBJECT (qtdemux, "stsd len: %d", stsd_len);
9199 /* and that entry should fit within stsd */
9200 len = QT_UINT32 (stsd_data + 16);
9201 if (len > stsd_len + 16)
9204 stream->fourcc = fourcc = QT_FOURCC (stsd_data + 16 + 4);
9205 GST_LOG_OBJECT (qtdemux, "stsd type: %" GST_FOURCC_FORMAT,
9206 GST_FOURCC_ARGS (stream->fourcc));
9207 GST_LOG_OBJECT (qtdemux, "stsd type len: %d", len);
9209 if ((fourcc == FOURCC_drms) || (fourcc == FOURCC_drmi))
9210 goto error_encrypted;
9212 if (fourcc == FOURCC_encv || fourcc == FOURCC_enca) {
9213 GNode *enc = qtdemux_tree_get_child_by_type (stsd, fourcc);
9214 stream->protected = TRUE;
9215 if (!qtdemux_parse_protection_scheme_info (qtdemux, stream, enc, &fourcc))
9216 GST_ERROR_OBJECT (qtdemux, "Failed to parse protection scheme info");
9219 if (stream->subtype == FOURCC_vide) {
9220 guint32 w = 0, h = 0;
9222 gint depth, palette_size, palette_count;
9224 guint32 *palette_data = NULL;
9226 stream->sampled = TRUE;
9228 /* version 1 uses some 64-bit ints */
9229 if (!gst_byte_reader_skip (&tkhd, 20 + value_size))
9232 if (!qtdemux_parse_transformation_matrix (qtdemux, &tkhd, matrix, "tkhd"))
9235 if (!gst_byte_reader_get_uint32_be (&tkhd, &w)
9236 || !gst_byte_reader_get_uint32_be (&tkhd, &h))
9239 stream->display_width = w >> 16;
9240 stream->display_height = h >> 16;
9242 qtdemux_inspect_transformation_matrix (qtdemux, stream, matrix,
9243 &stream->pending_tags);
9249 stream->width = QT_UINT16 (stsd_data + offset + 32);
9250 stream->height = QT_UINT16 (stsd_data + offset + 34);
9251 stream->fps_n = 0; /* this is filled in later */
9252 stream->fps_d = 0; /* this is filled in later */
9253 stream->bits_per_sample = QT_UINT16 (stsd_data + offset + 82);
9254 stream->color_table_id = QT_UINT16 (stsd_data + offset + 84);
9256 /* if color_table_id is 0, ctab atom must follow; however some files
9257 * produced by TMPEGEnc have color_table_id = 0 and no ctab atom, so
9258 * if color table is not present we'll correct the value */
9259 if (stream->color_table_id == 0 &&
9260 (len < 90 || QT_FOURCC (stsd_data + offset + 86) != FOURCC_ctab)) {
9261 stream->color_table_id = -1;
9264 GST_LOG_OBJECT (qtdemux, "width %d, height %d, bps %d, color table id %d",
9265 stream->width, stream->height, stream->bits_per_sample,
9266 stream->color_table_id);
9268 depth = stream->bits_per_sample;
9270 /* more than 32 bits means grayscale */
9271 gray = (depth > 32);
9272 /* low 32 bits specify the depth */
9275 /* different number of palette entries is determined by depth. */
9277 if ((depth == 1) || (depth == 2) || (depth == 4) || (depth == 8))
9278 palette_count = (1 << depth);
9279 palette_size = palette_count * 4;
9281 if (stream->color_table_id) {
9282 switch (palette_count) {
9286 palette_data = g_memdup (ff_qt_default_palette_2, palette_size);
9289 palette_data = g_memdup (ff_qt_default_palette_4, palette_size);
9293 palette_data = g_memdup (ff_qt_grayscale_palette_16, palette_size);
9295 palette_data = g_memdup (ff_qt_default_palette_16, palette_size);
9299 palette_data = g_memdup (ff_qt_grayscale_palette_256, palette_size);
9301 palette_data = g_memdup (ff_qt_default_palette_256, palette_size);
9304 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
9305 (_("The video in this file might not play correctly.")),
9306 ("unsupported palette depth %d", depth));
9310 gint i, j, start, end;
9316 start = QT_UINT32 (stsd_data + offset + 86);
9317 palette_count = QT_UINT16 (stsd_data + offset + 90);
9318 end = QT_UINT16 (stsd_data + offset + 92);
9320 GST_LOG_OBJECT (qtdemux, "start %d, end %d, palette_count %d",
9321 start, end, palette_count);
9328 if (len < 94 + (end - start) * 8)
9331 /* palette is always the same size */
9332 palette_data = g_malloc0 (256 * 4);
9333 palette_size = 256 * 4;
9335 for (j = 0, i = start; i <= end; j++, i++) {
9338 a = QT_UINT16 (stsd_data + offset + 94 + (j * 8));
9339 r = QT_UINT16 (stsd_data + offset + 96 + (j * 8));
9340 g = QT_UINT16 (stsd_data + offset + 98 + (j * 8));
9341 b = QT_UINT16 (stsd_data + offset + 100 + (j * 8));
9343 palette_data[i] = ((a & 0xff00) << 16) | ((r & 0xff00) << 8) |
9344 (g & 0xff00) | (b >> 8);
9349 gst_caps_unref (stream->caps);
9352 qtdemux_video_caps (qtdemux, stream, fourcc, stsd_data, &codec);
9353 if (G_UNLIKELY (!stream->caps)) {
9354 g_free (palette_data);
9355 goto unknown_stream;
9359 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
9360 GST_TAG_VIDEO_CODEC, codec, NULL);
9369 if (stream->rgb8_palette)
9370 gst_memory_unref (stream->rgb8_palette);
9371 stream->rgb8_palette = gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY,
9372 palette_data, palette_size, 0, palette_size, palette_data, g_free);
9374 s = gst_caps_get_structure (stream->caps, 0);
9376 /* non-raw video has a palette_data property. raw video has the palette as
9377 * an extra plane that we append to the output buffers before we push
9379 if (!gst_structure_has_name (s, "video/x-raw")) {
9382 palette = gst_buffer_new ();
9383 gst_buffer_append_memory (palette, stream->rgb8_palette);
9384 stream->rgb8_palette = NULL;
9386 gst_caps_set_simple (stream->caps, "palette_data",
9387 GST_TYPE_BUFFER, palette, NULL);
9388 gst_buffer_unref (palette);
9390 } else if (palette_count != 0) {
9391 GST_ELEMENT_WARNING (qtdemux, STREAM, NOT_IMPLEMENTED,
9392 (NULL), ("Unsupported palette depth %d", depth));
9395 GST_LOG_OBJECT (qtdemux, "frame count: %u",
9396 QT_UINT16 (stsd_data + offset + 48));
9400 /* pick 'the' stsd child */
9401 if (!stream->protected)
9402 mp4v = qtdemux_tree_get_child_by_type (stsd, fourcc);
9404 mp4v = qtdemux_tree_get_child_by_type (stsd, FOURCC_encv);
9407 esds = qtdemux_tree_get_child_by_type (mp4v, FOURCC_esds);
9408 pasp = qtdemux_tree_get_child_by_type (mp4v, FOURCC_pasp);
9412 const guint8 *pasp_data = (const guint8 *) pasp->data;
9414 stream->par_w = QT_UINT32 (pasp_data + 8);
9415 stream->par_h = QT_UINT32 (pasp_data + 12);
9422 gst_qtdemux_handle_esds (qtdemux, stream, esds, stream->pending_tags);
9429 gint len = QT_UINT32 (stsd_data) - 0x66;
9430 const guint8 *avc_data = stsd_data + 0x66;
9433 while (len >= 0x8) {
9436 if (QT_UINT32 (avc_data) <= len)
9437 size = QT_UINT32 (avc_data) - 0x8;
9442 /* No real data, so break out */
9445 switch (QT_FOURCC (avc_data + 0x4)) {
9448 /* parse, if found */
9451 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
9453 /* First 4 bytes are the length of the atom, the next 4 bytes
9454 * are the fourcc, the next 1 byte is the version, and the
9455 * subsequent bytes are profile_tier_level structure like data. */
9456 gst_codec_utils_h264_caps_set_level_and_profile (stream->caps,
9457 avc_data + 8 + 1, size - 1);
9458 buf = gst_buffer_new_and_alloc (size);
9459 gst_buffer_fill (buf, 0, avc_data + 0x8, size);
9460 gst_caps_set_simple (stream->caps,
9461 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9462 gst_buffer_unref (buf);
9470 GST_DEBUG_OBJECT (qtdemux, "found strf codec_data in stsd");
9472 /* First 4 bytes are the length of the atom, the next 4 bytes
9473 * are the fourcc, next 40 bytes are BITMAPINFOHEADER,
9474 * next 1 byte is the version, and the
9475 * subsequent bytes are sequence parameter set like data. */
9477 size -= 40; /* we'll be skipping BITMAPINFOHEADER */
9479 gst_codec_utils_h264_caps_set_level_and_profile (stream->caps,
9480 avc_data + 8 + 40 + 1, size - 1);
9482 buf = gst_buffer_new_and_alloc (size);
9483 gst_buffer_fill (buf, 0, avc_data + 8 + 40, size);
9484 gst_caps_set_simple (stream->caps,
9485 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9486 gst_buffer_unref (buf);
9492 guint avg_bitrate, max_bitrate;
9494 /* bufferSizeDB, maxBitrate and avgBitrate - 4 bytes each */
9498 max_bitrate = QT_UINT32 (avc_data + 0xc);
9499 avg_bitrate = QT_UINT32 (avc_data + 0x10);
9501 if (!max_bitrate && !avg_bitrate)
9504 /* Some muxers seem to swap the average and maximum bitrates
9505 * (I'm looking at you, YouTube), so we swap for sanity. */
9506 if (max_bitrate > 0 && max_bitrate < avg_bitrate) {
9507 guint temp = avg_bitrate;
9509 avg_bitrate = max_bitrate;
9513 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
9514 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
9515 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
9517 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
9518 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
9519 GST_TAG_BITRATE, avg_bitrate, NULL);
9530 avc_data += size + 8;
9539 gint len = QT_UINT32 (stsd_data) - 0x66;
9540 const guint8 *hevc_data = stsd_data + 0x66;
9543 while (len >= 0x8) {
9546 if (QT_UINT32 (hevc_data) <= len)
9547 size = QT_UINT32 (hevc_data) - 0x8;
9552 /* No real data, so break out */
9555 switch (QT_FOURCC (hevc_data + 0x4)) {
9558 /* parse, if found */
9561 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
9563 /* First 4 bytes are the length of the atom, the next 4 bytes
9564 * are the fourcc, the next 1 byte is the version, and the
9565 * subsequent bytes are sequence parameter set like data. */
9566 gst_codec_utils_h265_caps_set_level_tier_and_profile
9567 (stream->caps, hevc_data + 8 + 1, size - 1);
9569 buf = gst_buffer_new_and_alloc (size);
9570 gst_buffer_fill (buf, 0, hevc_data + 0x8, size);
9571 gst_caps_set_simple (stream->caps,
9572 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9573 gst_buffer_unref (buf);
9580 hevc_data += size + 8;
9591 GST_DEBUG_OBJECT (qtdemux, "found %" GST_FOURCC_FORMAT,
9592 GST_FOURCC_ARGS (fourcc));
9594 /* codec data might be in glbl extension atom */
9596 qtdemux_tree_get_child_by_type (mp4v, FOURCC_glbl) : NULL;
9602 GST_DEBUG_OBJECT (qtdemux, "found glbl data in stsd");
9604 len = QT_UINT32 (data);
9607 buf = gst_buffer_new_and_alloc (len);
9608 gst_buffer_fill (buf, 0, data + 8, len);
9609 gst_caps_set_simple (stream->caps,
9610 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9611 gst_buffer_unref (buf);
9618 /* see annex I of the jpeg2000 spec */
9619 GNode *jp2h, *ihdr, *colr, *mjp2, *field, *prefix, *cmap, *cdef;
9621 const gchar *colorspace = NULL;
9623 guint32 ncomp_map = 0;
9624 gint32 *comp_map = NULL;
9625 guint32 nchan_def = 0;
9626 gint32 *chan_def = NULL;
9628 GST_DEBUG_OBJECT (qtdemux, "found mjp2");
9629 /* some required atoms */
9630 mjp2 = qtdemux_tree_get_child_by_type (stsd, FOURCC_mjp2);
9633 jp2h = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2h);
9637 /* number of components; redundant with info in codestream, but useful
9639 ihdr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_ihdr);
9640 if (!ihdr || QT_UINT32 (ihdr->data) != 22)
9642 ncomp = QT_UINT16 (((guint8 *) ihdr->data) + 16);
9644 colr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_colr);
9647 GST_DEBUG_OBJECT (qtdemux, "found colr");
9648 /* extract colour space info */
9649 if (QT_UINT8 ((guint8 *) colr->data + 8) == 1) {
9650 switch (QT_UINT32 ((guint8 *) colr->data + 11)) {
9652 colorspace = "sRGB";
9655 colorspace = "GRAY";
9658 colorspace = "sYUV";
9666 /* colr is required, and only values 16, 17, and 18 are specified,
9667 so error if we have no colorspace */
9670 /* extract component mapping */
9671 cmap = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cmap);
9673 guint32 cmap_len = 0;
9675 cmap_len = QT_UINT32 (cmap->data);
9676 if (cmap_len >= 8) {
9677 /* normal box, subtract off header */
9679 /* cmap: { u16 cmp; u8 mtyp; u8 pcol; }* */
9680 if (cmap_len % 4 == 0) {
9681 ncomp_map = (cmap_len / 4);
9682 comp_map = g_new0 (gint32, ncomp_map);
9683 for (i = 0; i < ncomp_map; i++) {
9686 cmp = QT_UINT16 (((guint8 *) cmap->data) + 8 + i * 4);
9687 mtyp = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 2);
9688 pcol = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 3);
9689 comp_map[i] = (mtyp << 24) | (pcol << 16) | cmp;
9694 /* extract channel definitions */
9695 cdef = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cdef);
9697 guint32 cdef_len = 0;
9699 cdef_len = QT_UINT32 (cdef->data);
9700 if (cdef_len >= 10) {
9701 /* normal box, subtract off header and len */
9703 /* cdef: u16 n; { u16 cn; u16 typ; u16 asoc; }* */
9704 if (cdef_len % 6 == 0) {
9705 nchan_def = (cdef_len / 6);
9706 chan_def = g_new0 (gint32, nchan_def);
9707 for (i = 0; i < nchan_def; i++)
9709 for (i = 0; i < nchan_def; i++) {
9710 guint16 cn, typ, asoc;
9711 cn = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6);
9712 typ = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 2);
9713 asoc = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 4);
9714 if (cn < nchan_def) {
9717 chan_def[cn] = asoc;
9720 chan_def[cn] = 0; /* alpha */
9723 chan_def[cn] = -typ;
9731 gst_caps_set_simple (stream->caps,
9732 "num-components", G_TYPE_INT, ncomp, NULL);
9733 gst_caps_set_simple (stream->caps,
9734 "colorspace", G_TYPE_STRING, colorspace, NULL);
9737 GValue arr = { 0, };
9738 GValue elt = { 0, };
9740 g_value_init (&arr, GST_TYPE_ARRAY);
9741 g_value_init (&elt, G_TYPE_INT);
9742 for (i = 0; i < ncomp_map; i++) {
9743 g_value_set_int (&elt, comp_map[i]);
9744 gst_value_array_append_value (&arr, &elt);
9746 gst_structure_set_value (gst_caps_get_structure (stream->caps, 0),
9747 "component-map", &arr);
9748 g_value_unset (&elt);
9749 g_value_unset (&arr);
9754 GValue arr = { 0, };
9755 GValue elt = { 0, };
9757 g_value_init (&arr, GST_TYPE_ARRAY);
9758 g_value_init (&elt, G_TYPE_INT);
9759 for (i = 0; i < nchan_def; i++) {
9760 g_value_set_int (&elt, chan_def[i]);
9761 gst_value_array_append_value (&arr, &elt);
9763 gst_structure_set_value (gst_caps_get_structure (stream->caps, 0),
9764 "channel-definitions", &arr);
9765 g_value_unset (&elt);
9766 g_value_unset (&arr);
9770 /* some optional atoms */
9771 field = qtdemux_tree_get_child_by_type (mjp2, FOURCC_fiel);
9772 prefix = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2x);
9774 /* indicate possible fields in caps */
9776 data = (guint8 *) field->data + 8;
9778 gst_caps_set_simple (stream->caps, "fields", G_TYPE_INT,
9779 (gint) * data, NULL);
9781 /* add codec_data if provided */
9786 GST_DEBUG_OBJECT (qtdemux, "found prefix data in stsd");
9787 data = prefix->data;
9788 len = QT_UINT32 (data);
9791 buf = gst_buffer_new_and_alloc (len);
9792 gst_buffer_fill (buf, 0, data + 8, len);
9793 gst_caps_set_simple (stream->caps,
9794 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9795 gst_buffer_unref (buf);
9804 GstBuffer *seqh = NULL;
9805 guint8 *gamma_data = NULL;
9806 gint len = QT_UINT32 (stsd_data);
9808 qtdemux_parse_svq3_stsd_data (qtdemux, stsd, &gamma_data, &seqh);
9810 gst_caps_set_simple (stream->caps, "applied-gamma", G_TYPE_DOUBLE,
9811 QT_FP32 (gamma_data), NULL);
9814 /* sorry for the bad name, but we don't know what this is, other
9815 * than its own fourcc */
9816 gst_caps_set_simple (stream->caps, "seqh", GST_TYPE_BUFFER, seqh,
9820 GST_DEBUG_OBJECT (qtdemux, "found codec_data in stsd");
9821 buf = gst_buffer_new_and_alloc (len);
9822 gst_buffer_fill (buf, 0, stsd_data, len);
9823 gst_caps_set_simple (stream->caps,
9824 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9825 gst_buffer_unref (buf);
9831 gst_caps_set_simple (stream->caps,
9832 "depth", G_TYPE_INT, QT_UINT16 (stsd_data + offset + 82), NULL);
9839 GST_DEBUG_OBJECT (qtdemux, "found XiTh");
9840 xith = qtdemux_tree_get_child_by_type (stsd, FOURCC_XiTh);
9844 xdxt = qtdemux_tree_get_child_by_type (xith, FOURCC_XdxT);
9848 GST_DEBUG_OBJECT (qtdemux, "found XdxT node");
9849 /* collect the headers and store them in a stream list so that we can
9850 * send them out first */
9851 qtdemux_parse_theora_extension (qtdemux, stream, xdxt);
9861 GST_DEBUG_OBJECT (qtdemux, "parse ovc1 header");
9862 ovc1 = qtdemux_tree_get_child_by_type (stsd, FOURCC_ovc1);
9865 ovc1_data = ovc1->data;
9866 ovc1_len = QT_UINT32 (ovc1_data);
9867 if (ovc1_len <= 198) {
9868 GST_WARNING_OBJECT (qtdemux, "Too small ovc1 header, skipping");
9871 buf = gst_buffer_new_and_alloc (ovc1_len - 198);
9872 gst_buffer_fill (buf, 0, ovc1_data + 198, ovc1_len - 198);
9873 gst_caps_set_simple (stream->caps,
9874 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9875 gst_buffer_unref (buf);
9880 gint len = QT_UINT32 (stsd_data) - 0x66;
9881 const guint8 *vc1_data = stsd_data + 0x66;
9887 if (QT_UINT32 (vc1_data) <= len)
9888 size = QT_UINT32 (vc1_data) - 8;
9893 /* No real data, so break out */
9896 switch (QT_FOURCC (vc1_data + 0x4)) {
9897 case GST_MAKE_FOURCC ('d', 'v', 'c', '1'):
9901 GST_DEBUG_OBJECT (qtdemux, "found dvc1 codec_data in stsd");
9902 buf = gst_buffer_new_and_alloc (size);
9903 gst_buffer_fill (buf, 0, vc1_data + 8, size);
9904 gst_caps_set_simple (stream->caps,
9905 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9906 gst_buffer_unref (buf);
9913 vc1_data += size + 8;
9922 GST_INFO_OBJECT (qtdemux,
9923 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
9924 GST_FOURCC_ARGS (fourcc), stream->caps);
9926 } else if (stream->subtype == FOURCC_soun) {
9927 int version, samplesize;
9928 guint16 compression_id;
9929 gboolean amrwb = FALSE;
9932 /* sample description entry (16) + sound sample description v0 (20) */
9936 version = QT_UINT32 (stsd_data + offset);
9937 stream->n_channels = QT_UINT16 (stsd_data + offset + 8);
9938 samplesize = QT_UINT16 (stsd_data + offset + 10);
9939 compression_id = QT_UINT16 (stsd_data + offset + 12);
9940 stream->rate = QT_FP32 (stsd_data + offset + 16);
9942 GST_LOG_OBJECT (qtdemux, "version/rev: %08x", version);
9943 GST_LOG_OBJECT (qtdemux, "vendor: %08x",
9944 QT_UINT32 (stsd_data + offset + 4));
9945 GST_LOG_OBJECT (qtdemux, "n_channels: %d", stream->n_channels);
9946 GST_LOG_OBJECT (qtdemux, "sample_size: %d", samplesize);
9947 GST_LOG_OBJECT (qtdemux, "compression_id: %d", compression_id);
9948 GST_LOG_OBJECT (qtdemux, "packet size: %d",
9949 QT_UINT16 (stsd_data + offset + 14));
9950 GST_LOG_OBJECT (qtdemux, "sample rate: %g", stream->rate);
9952 if (compression_id == 0xfffe)
9953 stream->sampled = TRUE;
9955 /* first assume uncompressed audio */
9956 stream->bytes_per_sample = samplesize / 8;
9957 stream->samples_per_frame = stream->n_channels;
9958 stream->bytes_per_frame = stream->n_channels * stream->bytes_per_sample;
9959 stream->samples_per_packet = stream->samples_per_frame;
9960 stream->bytes_per_packet = stream->bytes_per_sample;
9964 /* Yes, these have to be hard-coded */
9967 stream->samples_per_packet = 6;
9968 stream->bytes_per_packet = 1;
9969 stream->bytes_per_frame = 1 * stream->n_channels;
9970 stream->bytes_per_sample = 1;
9971 stream->samples_per_frame = 6 * stream->n_channels;
9976 stream->samples_per_packet = 3;
9977 stream->bytes_per_packet = 1;
9978 stream->bytes_per_frame = 1 * stream->n_channels;
9979 stream->bytes_per_sample = 1;
9980 stream->samples_per_frame = 3 * stream->n_channels;
9985 stream->samples_per_packet = 64;
9986 stream->bytes_per_packet = 34;
9987 stream->bytes_per_frame = 34 * stream->n_channels;
9988 stream->bytes_per_sample = 2;
9989 stream->samples_per_frame = 64 * stream->n_channels;
9995 stream->samples_per_packet = 1;
9996 stream->bytes_per_packet = 1;
9997 stream->bytes_per_frame = 1 * stream->n_channels;
9998 stream->bytes_per_sample = 1;
9999 stream->samples_per_frame = 1 * stream->n_channels;
10004 stream->samples_per_packet = 160;
10005 stream->bytes_per_packet = 33;
10006 stream->bytes_per_frame = 33 * stream->n_channels;
10007 stream->bytes_per_sample = 2;
10008 stream->samples_per_frame = 160 * stream->n_channels;
10015 if (version == 0x00010000) {
10016 /* sample description entry (16) + sound sample description v1 (20+16) */
10027 /* only parse extra decoding config for non-pcm audio */
10028 stream->samples_per_packet = QT_UINT32 (stsd_data + offset);
10029 stream->bytes_per_packet = QT_UINT32 (stsd_data + offset + 4);
10030 stream->bytes_per_frame = QT_UINT32 (stsd_data + offset + 8);
10031 stream->bytes_per_sample = QT_UINT32 (stsd_data + offset + 12);
10033 GST_LOG_OBJECT (qtdemux, "samples/packet: %d",
10034 stream->samples_per_packet);
10035 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
10036 stream->bytes_per_packet);
10037 GST_LOG_OBJECT (qtdemux, "bytes/frame: %d",
10038 stream->bytes_per_frame);
10039 GST_LOG_OBJECT (qtdemux, "bytes/sample: %d",
10040 stream->bytes_per_sample);
10042 if (!stream->sampled && stream->bytes_per_packet) {
10043 stream->samples_per_frame = (stream->bytes_per_frame /
10044 stream->bytes_per_packet) * stream->samples_per_packet;
10045 GST_LOG_OBJECT (qtdemux, "samples/frame: %d",
10046 stream->samples_per_frame);
10051 } else if (version == 0x00020000) {
10058 /* sample description entry (16) + sound sample description v2 (56) */
10062 qtfp.val = QT_UINT64 (stsd_data + offset + 4);
10063 stream->rate = qtfp.fp;
10064 stream->n_channels = QT_UINT32 (stsd_data + offset + 12);
10066 GST_LOG_OBJECT (qtdemux, "Sound sample description Version 2");
10067 GST_LOG_OBJECT (qtdemux, "sample rate: %g", stream->rate);
10068 GST_LOG_OBJECT (qtdemux, "n_channels: %d", stream->n_channels);
10069 GST_LOG_OBJECT (qtdemux, "bits/channel: %d",
10070 QT_UINT32 (stsd_data + offset + 20));
10071 GST_LOG_OBJECT (qtdemux, "format flags: %X",
10072 QT_UINT32 (stsd_data + offset + 24));
10073 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
10074 QT_UINT32 (stsd_data + offset + 28));
10075 GST_LOG_OBJECT (qtdemux, "LPCM frames/packet: %d",
10076 QT_UINT32 (stsd_data + offset + 32));
10077 } else if (version != 0x00000) {
10078 GST_WARNING_OBJECT (qtdemux, "unknown audio STSD version %08x", version);
10082 gst_caps_unref (stream->caps);
10084 stream->caps = qtdemux_audio_caps (qtdemux, stream, fourcc,
10085 stsd_data + 32, len - 16, &codec);
10093 in24 = qtdemux_tree_get_child_by_type (stsd, FOURCC_in24);
10095 enda = qtdemux_tree_get_child_by_type (in24, FOURCC_enda);
10097 wave = qtdemux_tree_get_child_by_type (in24, FOURCC_wave);
10099 enda = qtdemux_tree_get_child_by_type (wave, FOURCC_enda);
10102 int enda_value = QT_UINT16 ((guint8 *) enda->data + 8);
10103 gst_caps_set_simple (stream->caps,
10104 "format", G_TYPE_STRING, (enda_value) ? "S24LE" : "S24BE", NULL);
10111 const guint8 *owma_data;
10112 const gchar *codec_name = NULL;
10116 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
10117 /* FIXME this should also be gst_riff_strf_auds,
10118 * but the latter one is actually missing bits-per-sample :( */
10123 gint32 nSamplesPerSec;
10124 gint32 nAvgBytesPerSec;
10125 gint16 nBlockAlign;
10126 gint16 wBitsPerSample;
10129 WAVEFORMATEX *wfex;
10131 GST_DEBUG_OBJECT (qtdemux, "parse owma");
10132 owma = qtdemux_tree_get_child_by_type (stsd, FOURCC_owma);
10135 owma_data = owma->data;
10136 owma_len = QT_UINT32 (owma_data);
10137 if (owma_len <= 54) {
10138 GST_WARNING_OBJECT (qtdemux, "Too small owma header, skipping");
10141 wfex = (WAVEFORMATEX *) (owma_data + 36);
10142 buf = gst_buffer_new_and_alloc (owma_len - 54);
10143 gst_buffer_fill (buf, 0, owma_data + 54, owma_len - 54);
10144 if (wfex->wFormatTag == 0x0161) {
10145 codec_name = "Windows Media Audio";
10147 } else if (wfex->wFormatTag == 0x0162) {
10148 codec_name = "Windows Media Audio 9 Pro";
10150 } else if (wfex->wFormatTag == 0x0163) {
10151 codec_name = "Windows Media Audio 9 Lossless";
10152 /* is that correct? gstffmpegcodecmap.c is missing it, but
10153 * fluendo codec seems to support it */
10157 gst_caps_set_simple (stream->caps,
10158 "codec_data", GST_TYPE_BUFFER, buf,
10159 "wmaversion", G_TYPE_INT, version,
10160 "block_align", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->nBlockAlign),
10161 "bitrate", G_TYPE_INT, GST_READ_UINT32_LE (&wfex->nAvgBytesPerSec),
10162 "width", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->wBitsPerSample),
10163 "depth", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->wBitsPerSample),
10165 gst_buffer_unref (buf);
10169 codec = g_strdup (codec_name);
10175 gint len = QT_UINT32 (stsd_data) - offset;
10176 const guint8 *wfex_data = stsd_data + offset;
10177 const gchar *codec_name = NULL;
10179 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
10180 /* FIXME this should also be gst_riff_strf_auds,
10181 * but the latter one is actually missing bits-per-sample :( */
10186 gint32 nSamplesPerSec;
10187 gint32 nAvgBytesPerSec;
10188 gint16 nBlockAlign;
10189 gint16 wBitsPerSample;
10194 /* FIXME: unify with similar wavformatex parsing code above */
10195 GST_DEBUG_OBJECT (qtdemux, "parse wma, looking for wfex");
10201 if (QT_UINT32 (wfex_data) <= len)
10202 size = QT_UINT32 (wfex_data) - 8;
10207 /* No real data, so break out */
10210 switch (QT_FOURCC (wfex_data + 4)) {
10211 case GST_MAKE_FOURCC ('w', 'f', 'e', 'x'):
10213 GST_DEBUG_OBJECT (qtdemux, "found wfex in stsd");
10218 wfex.wFormatTag = GST_READ_UINT16_LE (wfex_data + 8 + 0);
10219 wfex.nChannels = GST_READ_UINT16_LE (wfex_data + 8 + 2);
10220 wfex.nSamplesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 4);
10221 wfex.nAvgBytesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 8);
10222 wfex.nBlockAlign = GST_READ_UINT16_LE (wfex_data + 8 + 12);
10223 wfex.wBitsPerSample = GST_READ_UINT16_LE (wfex_data + 8 + 14);
10224 wfex.cbSize = GST_READ_UINT16_LE (wfex_data + 8 + 16);
10226 GST_LOG_OBJECT (qtdemux, "Found wfex box in stsd:");
10227 GST_LOG_OBJECT (qtdemux, "FormatTag = 0x%04x, Channels = %u, "
10228 "SamplesPerSec = %u, AvgBytesPerSec = %u, BlockAlign = %u, "
10229 "BitsPerSample = %u, Size = %u", wfex.wFormatTag,
10230 wfex.nChannels, wfex.nSamplesPerSec, wfex.nAvgBytesPerSec,
10231 wfex.nBlockAlign, wfex.wBitsPerSample, wfex.cbSize);
10233 if (wfex.wFormatTag == 0x0161) {
10234 codec_name = "Windows Media Audio";
10236 } else if (wfex.wFormatTag == 0x0162) {
10237 codec_name = "Windows Media Audio 9 Pro";
10239 } else if (wfex.wFormatTag == 0x0163) {
10240 codec_name = "Windows Media Audio 9 Lossless";
10241 /* is that correct? gstffmpegcodecmap.c is missing it, but
10242 * fluendo codec seems to support it */
10246 gst_caps_set_simple (stream->caps,
10247 "wmaversion", G_TYPE_INT, version,
10248 "block_align", G_TYPE_INT, wfex.nBlockAlign,
10249 "bitrate", G_TYPE_INT, wfex.nAvgBytesPerSec,
10250 "width", G_TYPE_INT, wfex.wBitsPerSample,
10251 "depth", G_TYPE_INT, wfex.wBitsPerSample, NULL);
10253 if (size > wfex.cbSize) {
10256 buf = gst_buffer_new_and_alloc (size - wfex.cbSize);
10257 gst_buffer_fill (buf, 0, wfex_data + 8 + wfex.cbSize,
10258 size - wfex.cbSize);
10259 gst_caps_set_simple (stream->caps,
10260 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10261 gst_buffer_unref (buf);
10263 GST_WARNING_OBJECT (qtdemux, "no codec data");
10268 codec = g_strdup (codec_name);
10276 wfex_data += size + 8;
10283 const guint8 *opus_data;
10284 guint8 *channel_mapping = NULL;
10287 guint8 channel_mapping_family;
10288 guint8 stream_count;
10289 guint8 coupled_count;
10292 opus = qtdemux_tree_get_child_by_type (stsd, FOURCC_opus);
10293 opus_data = opus->data;
10295 channels = GST_READ_UINT8 (opus_data + 45);
10296 rate = GST_READ_UINT32_LE (opus_data + 48);
10297 channel_mapping_family = GST_READ_UINT8 (opus_data + 54);
10298 stream_count = GST_READ_UINT8 (opus_data + 55);
10299 coupled_count = GST_READ_UINT8 (opus_data + 56);
10301 if (channels > 0) {
10302 channel_mapping = g_malloc (channels * sizeof (guint8));
10303 for (i = 0; i < channels; i++)
10304 channel_mapping[i] = GST_READ_UINT8 (opus_data + i + 57);
10307 stream->caps = gst_codec_utils_opus_create_caps (rate, channels,
10308 channel_mapping_family, stream_count, coupled_count,
10320 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
10321 GST_TAG_AUDIO_CODEC, codec, NULL);
10325 /* some bitrate info may have ended up in caps */
10326 s = gst_caps_get_structure (stream->caps, 0);
10327 gst_structure_get_int (s, "bitrate", &bitrate);
10329 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
10330 GST_TAG_BITRATE, bitrate, NULL);
10333 if (stream->protected && fourcc == FOURCC_mp4a)
10334 mp4a = qtdemux_tree_get_child_by_type (stsd, FOURCC_enca);
10336 mp4a = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4a);
10341 wave = qtdemux_tree_get_child_by_type (mp4a, FOURCC_wave);
10343 esds = qtdemux_tree_get_child_by_type (wave, FOURCC_esds);
10345 esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
10349 /* If the fourcc's bottom 16 bits gives 'sm', then the top
10350 16 bits is a byte-swapped wave-style codec identifier,
10351 and we can find a WAVE header internally to a 'wave' atom here.
10352 This can more clearly be thought of as 'ms' as the top 16 bits, and a
10353 codec id as the bottom 16 bits - but byte-swapped to store in QT (which
10356 if ((fourcc & 0xffff) == (('s' << 8) | 'm')) {
10357 if (len < offset + 20) {
10358 GST_WARNING_OBJECT (qtdemux, "No wave atom in MS-style audio");
10360 guint32 datalen = QT_UINT32 (stsd_data + offset + 16);
10361 const guint8 *data = stsd_data + offset + 16;
10363 GNode *waveheadernode;
10365 wavenode = g_node_new ((guint8 *) data);
10366 if (qtdemux_parse_node (qtdemux, wavenode, data, datalen)) {
10367 const guint8 *waveheader;
10370 waveheadernode = qtdemux_tree_get_child_by_type (wavenode, fourcc);
10371 if (waveheadernode) {
10372 waveheader = (const guint8 *) waveheadernode->data;
10373 headerlen = QT_UINT32 (waveheader);
10375 if (headerlen > 8) {
10376 gst_riff_strf_auds *header = NULL;
10377 GstBuffer *headerbuf;
10383 headerbuf = gst_buffer_new_and_alloc (headerlen);
10384 gst_buffer_fill (headerbuf, 0, waveheader, headerlen);
10386 if (gst_riff_parse_strf_auds (GST_ELEMENT_CAST (qtdemux),
10387 headerbuf, &header, &extra)) {
10388 gst_caps_unref (stream->caps);
10389 /* FIXME: Need to do something with the channel reorder map */
10390 stream->caps = gst_riff_create_audio_caps (header->format, NULL,
10391 header, extra, NULL, NULL, NULL);
10394 gst_buffer_unref (extra);
10399 GST_DEBUG ("Didn't find waveheadernode for this codec");
10401 g_node_destroy (wavenode);
10404 gst_qtdemux_handle_esds (qtdemux, stream, esds, stream->pending_tags);
10408 /* FIXME: what is in the chunk? */
10411 gint len = QT_UINT32 (stsd_data);
10413 /* seems to be always = 116 = 0x74 */
10419 gint len = QT_UINT32 (stsd_data);
10422 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x4C);
10424 gst_buffer_fill (buf, 0, stsd_data + 0x4C, len - 0x4C);
10425 gst_caps_set_simple (stream->caps,
10426 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10427 gst_buffer_unref (buf);
10429 gst_caps_set_simple (stream->caps,
10430 "samplesize", G_TYPE_INT, samplesize, NULL);
10435 GNode *alac, *wave = NULL;
10437 /* apparently, m4a has this atom appended directly in the stsd entry,
10438 * while mov has it in a wave atom */
10439 alac = qtdemux_tree_get_child_by_type (stsd, FOURCC_alac);
10441 /* alac now refers to stsd entry atom */
10442 wave = qtdemux_tree_get_child_by_type (alac, FOURCC_wave);
10444 alac = qtdemux_tree_get_child_by_type (wave, FOURCC_alac);
10446 alac = qtdemux_tree_get_child_by_type (alac, FOURCC_alac);
10449 const guint8 *alac_data = alac->data;
10450 gint len = QT_UINT32 (alac->data);
10454 GST_DEBUG_OBJECT (qtdemux,
10455 "discarding alac atom with unexpected len %d", len);
10457 /* codec-data contains alac atom size and prefix,
10458 * ffmpeg likes it that way, not quite gst-ish though ...*/
10459 buf = gst_buffer_new_and_alloc (len);
10460 gst_buffer_fill (buf, 0, alac->data, len);
10461 gst_caps_set_simple (stream->caps,
10462 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10463 gst_buffer_unref (buf);
10465 stream->bytes_per_frame = QT_UINT32 (alac_data + 12);
10466 stream->n_channels = QT_UINT8 (alac_data + 21);
10467 stream->rate = QT_UINT32 (alac_data + 32);
10470 gst_caps_set_simple (stream->caps,
10471 "samplesize", G_TYPE_INT, samplesize, NULL);
10479 gint len = QT_UINT32 (stsd_data);
10482 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x34);
10485 gst_buffer_fill (buf, 0, stsd_data + 0x34, len - 0x34);
10487 /* If we have enough data, let's try to get the 'damr' atom. See
10488 * the 3GPP container spec (26.244) for more details. */
10489 if ((len - 0x34) > 8 &&
10490 (bitrate = qtdemux_parse_amr_bitrate (buf, amrwb))) {
10491 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
10492 GST_TAG_MAXIMUM_BITRATE, bitrate, NULL);
10495 gst_caps_set_simple (stream->caps,
10496 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10497 gst_buffer_unref (buf);
10503 /* mp4a atom withtout ESDS; Attempt to build codec data from atom */
10504 gint len = QT_UINT32 (stsd_data);
10507 guint16 sound_version = QT_UINT16 (stsd_data + 32);
10509 if (sound_version == 1) {
10510 guint16 channels = QT_UINT16 (stsd_data + 40);
10511 guint32 time_scale = QT_UINT32 (stsd_data + 46);
10512 guint8 codec_data[2];
10514 gint profile = 2; /* FIXME: Can this be determined somehow? There doesn't seem to be anything in mp4a atom that specifis compression */
10516 gint sample_rate_index =
10517 gst_codec_utils_aac_get_index_from_sample_rate (time_scale);
10519 /* build AAC codec data */
10520 codec_data[0] = profile << 3;
10521 codec_data[0] |= ((sample_rate_index >> 1) & 0x7);
10522 codec_data[1] = (sample_rate_index & 0x01) << 7;
10523 codec_data[1] |= (channels & 0xF) << 3;
10525 buf = gst_buffer_new_and_alloc (2);
10526 gst_buffer_fill (buf, 0, codec_data, 2);
10527 gst_caps_set_simple (stream->caps,
10528 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10529 gst_buffer_unref (buf);
10535 GST_INFO_OBJECT (qtdemux,
10536 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
10540 GST_INFO_OBJECT (qtdemux,
10541 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
10542 GST_FOURCC_ARGS (fourcc), stream->caps);
10544 } else if (stream->subtype == FOURCC_strm) {
10545 if (fourcc == FOURCC_rtsp) {
10546 stream->redirect_uri = qtdemux_get_rtsp_uri_from_hndl (qtdemux, minf);
10548 GST_INFO_OBJECT (qtdemux, "unhandled stream type %" GST_FOURCC_FORMAT,
10549 GST_FOURCC_ARGS (fourcc));
10550 goto unknown_stream;
10552 stream->sampled = TRUE;
10553 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
10554 || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt) {
10556 stream->sampled = TRUE;
10557 stream->sparse = TRUE;
10560 qtdemux_sub_caps (qtdemux, stream, fourcc, stsd_data, &codec);
10562 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
10563 GST_TAG_SUBTITLE_CODEC, codec, NULL);
10568 /* hunt for sort-of codec data */
10572 GNode *mp4s = NULL;
10573 GNode *esds = NULL;
10575 /* look for palette in a stsd->mp4s->esds sub-atom */
10576 mp4s = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4s);
10578 esds = qtdemux_tree_get_child_by_type (mp4s, FOURCC_esds);
10579 if (esds == NULL) {
10581 GST_LOG_OBJECT (qtdemux, "Skipping invalid stsd: no esds child");
10585 gst_qtdemux_handle_esds (qtdemux, stream, esds, stream->pending_tags);
10589 GST_INFO_OBJECT (qtdemux,
10590 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
10593 GST_INFO_OBJECT (qtdemux,
10594 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
10595 GST_FOURCC_ARGS (fourcc), stream->caps);
10597 /* everything in 1 sample */
10598 stream->sampled = TRUE;
10601 qtdemux_generic_caps (qtdemux, stream, fourcc, stsd_data, &codec);
10603 if (stream->caps == NULL)
10604 goto unknown_stream;
10607 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
10608 GST_TAG_SUBTITLE_CODEC, codec, NULL);
10614 /* promote to sampled format */
10615 if (stream->fourcc == FOURCC_samr) {
10616 /* force mono 8000 Hz for AMR */
10617 stream->sampled = TRUE;
10618 stream->n_channels = 1;
10619 stream->rate = 8000;
10620 } else if (stream->fourcc == FOURCC_sawb) {
10621 /* force mono 16000 Hz for AMR-WB */
10622 stream->sampled = TRUE;
10623 stream->n_channels = 1;
10624 stream->rate = 16000;
10625 } else if (stream->fourcc == FOURCC_mp4a) {
10626 stream->sampled = TRUE;
10629 /* collect sample information */
10630 if (!qtdemux_stbl_init (qtdemux, stream, stbl))
10631 goto samples_failed;
10633 if (qtdemux->fragmented) {
10636 /* need all moov samples as basis; probably not many if any at all */
10637 /* prevent moof parsing taking of at this time */
10638 offset = qtdemux->moof_offset;
10639 qtdemux->moof_offset = 0;
10640 if (stream->n_samples &&
10641 !qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
10642 qtdemux->moof_offset = offset;
10643 goto samples_failed;
10645 qtdemux->moof_offset = 0;
10646 /* movie duration more reliable in this case (e.g. mehd) */
10647 if (qtdemux->segment.duration &&
10648 GST_CLOCK_TIME_IS_VALID (qtdemux->segment.duration))
10650 GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->segment.duration);
10653 /* configure segments */
10654 if (!qtdemux_parse_segments (qtdemux, stream, trak))
10655 goto segments_failed;
10657 /* add some language tag, if useful */
10658 if (stream->lang_id[0] != '\0' && strcmp (stream->lang_id, "unk") &&
10659 strcmp (stream->lang_id, "und")) {
10660 const gchar *lang_code;
10662 /* convert ISO 639-2 code to ISO 639-1 */
10663 lang_code = gst_tag_get_language_code (stream->lang_id);
10664 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
10665 GST_TAG_LANGUAGE_CODE, (lang_code) ? lang_code : stream->lang_id, NULL);
10668 /* Check for UDTA tags */
10669 if ((udta = qtdemux_tree_get_child_by_type (trak, FOURCC_udta))) {
10670 qtdemux_parse_udta (qtdemux, stream->pending_tags, udta);
10673 /* now we are ready to add the stream */
10674 if (qtdemux->n_streams >= GST_QTDEMUX_MAX_STREAMS)
10675 goto too_many_streams;
10677 if (!qtdemux->got_moov) {
10678 qtdemux->streams[qtdemux->n_streams] = stream;
10679 qtdemux->n_streams++;
10680 GST_DEBUG_OBJECT (qtdemux, "n_streams is now %d", qtdemux->n_streams);
10688 GST_INFO_OBJECT (qtdemux, "skip disabled track");
10690 gst_qtdemux_stream_free (qtdemux, stream);
10695 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
10696 (_("This file is corrupt and cannot be played.")), (NULL));
10698 gst_qtdemux_stream_free (qtdemux, stream);
10703 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT, (NULL), (NULL));
10705 gst_qtdemux_stream_free (qtdemux, stream);
10711 /* we posted an error already */
10712 /* free stbl sub-atoms */
10713 gst_qtdemux_stbl_free (stream);
10715 gst_qtdemux_stream_free (qtdemux, stream);
10720 GST_INFO_OBJECT (qtdemux, "stream with track id %i already exists",
10723 gst_qtdemux_stream_free (qtdemux, stream);
10728 GST_INFO_OBJECT (qtdemux, "unknown subtype %" GST_FOURCC_FORMAT,
10729 GST_FOURCC_ARGS (stream->subtype));
10731 gst_qtdemux_stream_free (qtdemux, stream);
10736 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
10737 (_("This file contains too many streams. Only playing first %d"),
10738 GST_QTDEMUX_MAX_STREAMS), (NULL));
10743 /* If we can estimate the overall bitrate, and don't have information about the
10744 * stream bitrate for exactly one stream, this guesses the stream bitrate as
10745 * the overall bitrate minus the sum of the bitrates of all other streams. This
10746 * should be useful for the common case where we have one audio and one video
10747 * stream and can estimate the bitrate of one, but not the other. */
10749 gst_qtdemux_guess_bitrate (GstQTDemux * qtdemux)
10751 QtDemuxStream *stream = NULL;
10752 gint64 size, sys_bitrate, sum_bitrate = 0;
10753 GstClockTime duration;
10757 if (qtdemux->fragmented)
10760 GST_DEBUG_OBJECT (qtdemux, "Looking for streams with unknown bitrate");
10762 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &size)
10764 GST_DEBUG_OBJECT (qtdemux,
10765 "Size in bytes of the stream not known - bailing");
10769 /* Subtract the header size */
10770 GST_DEBUG_OBJECT (qtdemux, "Total size %" G_GINT64_FORMAT ", header size %u",
10771 size, qtdemux->header_size);
10773 if (size < qtdemux->header_size)
10776 size = size - qtdemux->header_size;
10778 if (!gst_qtdemux_get_duration (qtdemux, &duration)) {
10779 GST_DEBUG_OBJECT (qtdemux, "Stream duration not known - bailing");
10783 for (i = 0; i < qtdemux->n_streams; i++) {
10784 switch (qtdemux->streams[i]->subtype) {
10787 GST_DEBUG_OBJECT (qtdemux, "checking bitrate for %" GST_PTR_FORMAT,
10788 qtdemux->streams[i]->caps);
10789 /* retrieve bitrate, prefer avg then max */
10791 if (qtdemux->streams[i]->pending_tags) {
10792 gst_tag_list_get_uint (qtdemux->streams[i]->pending_tags,
10793 GST_TAG_MAXIMUM_BITRATE, &bitrate);
10794 GST_DEBUG_OBJECT (qtdemux, "max-bitrate: %u", bitrate);
10795 gst_tag_list_get_uint (qtdemux->streams[i]->pending_tags,
10796 GST_TAG_NOMINAL_BITRATE, &bitrate);
10797 GST_DEBUG_OBJECT (qtdemux, "nominal-bitrate: %u", bitrate);
10798 gst_tag_list_get_uint (qtdemux->streams[i]->pending_tags,
10799 GST_TAG_BITRATE, &bitrate);
10800 GST_DEBUG_OBJECT (qtdemux, "bitrate: %u", bitrate);
10803 sum_bitrate += bitrate;
10806 GST_DEBUG_OBJECT (qtdemux,
10807 ">1 stream with unknown bitrate - bailing");
10810 stream = qtdemux->streams[i];
10814 /* For other subtypes, we assume no significant impact on bitrate */
10820 GST_DEBUG_OBJECT (qtdemux, "All stream bitrates are known");
10824 sys_bitrate = gst_util_uint64_scale (size, GST_SECOND * 8, duration);
10826 if (sys_bitrate < sum_bitrate) {
10827 /* This can happen, since sum_bitrate might be derived from maximum
10828 * bitrates and not average bitrates */
10829 GST_DEBUG_OBJECT (qtdemux,
10830 "System bitrate less than sum bitrate - bailing");
10834 bitrate = sys_bitrate - sum_bitrate;
10835 GST_DEBUG_OBJECT (qtdemux, "System bitrate = %" G_GINT64_FORMAT
10836 ", Stream bitrate = %u", sys_bitrate, bitrate);
10838 if (!stream->pending_tags)
10839 stream->pending_tags = gst_tag_list_new_empty ();
10841 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
10842 GST_TAG_BITRATE, bitrate, NULL);
10845 static GstFlowReturn
10846 qtdemux_prepare_streams (GstQTDemux * qtdemux)
10849 GstFlowReturn ret = GST_FLOW_OK;
10851 GST_DEBUG_OBJECT (qtdemux, "prepare streams");
10853 for (i = 0; ret == GST_FLOW_OK && i < qtdemux->n_streams; i++) {
10854 QtDemuxStream *stream = qtdemux->streams[i];
10855 guint32 sample_num = 0;
10857 GST_DEBUG_OBJECT (qtdemux, "stream %d, id %d, fourcc %" GST_FOURCC_FORMAT,
10858 i, stream->track_id, GST_FOURCC_ARGS (stream->fourcc));
10860 if (qtdemux->fragmented) {
10861 /* need all moov samples first */
10862 GST_OBJECT_LOCK (qtdemux);
10863 while (stream->n_samples == 0)
10864 if ((ret = qtdemux_add_fragmented_samples (qtdemux)) != GST_FLOW_OK)
10866 GST_OBJECT_UNLOCK (qtdemux);
10868 /* discard any stray moof */
10869 qtdemux->moof_offset = 0;
10872 /* prepare braking */
10873 if (ret != GST_FLOW_ERROR)
10876 /* in pull mode, we should have parsed some sample info by now;
10877 * and quite some code will not handle no samples.
10878 * in push mode, we'll just have to deal with it */
10879 if (G_UNLIKELY (qtdemux->pullbased && !stream->n_samples)) {
10880 GST_DEBUG_OBJECT (qtdemux, "no samples for stream; discarding");
10881 gst_qtdemux_remove_stream (qtdemux, i);
10886 /* parse the initial sample for use in setting the frame rate cap */
10887 while (sample_num == 0 && sample_num < stream->n_samples) {
10888 if (!qtdemux_parse_samples (qtdemux, stream, sample_num))
10892 if (stream->n_samples > 0 && stream->stbl_index >= 0) {
10893 stream->first_duration = stream->samples[0].duration;
10894 GST_LOG_OBJECT (qtdemux, "stream %d first duration %u",
10895 stream->track_id, stream->first_duration);
10902 static GstFlowReturn
10903 qtdemux_expose_streams (GstQTDemux * qtdemux)
10906 GstFlowReturn ret = GST_FLOW_OK;
10907 GSList *oldpads = NULL;
10910 GST_DEBUG_OBJECT (qtdemux, "exposing streams");
10912 for (i = 0; ret == GST_FLOW_OK && i < qtdemux->n_streams; i++) {
10913 QtDemuxStream *stream = qtdemux->streams[i];
10914 GstPad *oldpad = stream->pad;
10917 GST_DEBUG_OBJECT (qtdemux, "stream %d, id %d, fourcc %" GST_FOURCC_FORMAT,
10918 i, stream->track_id, GST_FOURCC_ARGS (stream->fourcc));
10920 if ((stream->subtype == FOURCC_text || stream->subtype == FOURCC_sbtl) &&
10921 stream->track_id == qtdemux->chapters_track_id) {
10922 /* TODO - parse chapters track and expose it as GstToc; For now just ignore it
10923 so that it doesn't look like a subtitle track */
10924 gst_qtdemux_remove_stream (qtdemux, i);
10929 /* now we have all info and can expose */
10930 list = stream->pending_tags;
10931 stream->pending_tags = NULL;
10933 oldpads = g_slist_prepend (oldpads, oldpad);
10934 if (!gst_qtdemux_add_stream (qtdemux, stream, list))
10935 return GST_FLOW_ERROR;
10938 gst_qtdemux_guess_bitrate (qtdemux);
10940 gst_element_no_more_pads (GST_ELEMENT_CAST (qtdemux));
10942 for (iter = oldpads; iter; iter = g_slist_next (iter)) {
10943 GstPad *oldpad = iter->data;
10946 event = gst_event_new_eos ();
10947 if (qtdemux->segment_seqnum)
10948 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
10950 gst_pad_push_event (oldpad, event);
10951 gst_pad_set_active (oldpad, FALSE);
10952 gst_element_remove_pad (GST_ELEMENT (qtdemux), oldpad);
10953 gst_flow_combiner_remove_pad (qtdemux->flowcombiner, oldpad);
10954 gst_object_unref (oldpad);
10957 /* check if we should post a redirect in case there is a single trak
10958 * and it is a redirecting trak */
10959 if (qtdemux->n_streams == 1 && qtdemux->streams[0]->redirect_uri != NULL) {
10962 GST_INFO_OBJECT (qtdemux, "Issuing a redirect due to a single track with "
10963 "an external content");
10964 m = gst_message_new_element (GST_OBJECT_CAST (qtdemux),
10965 gst_structure_new ("redirect",
10966 "new-location", G_TYPE_STRING, qtdemux->streams[0]->redirect_uri,
10968 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), m);
10969 qtdemux->posted_redirect = TRUE;
10972 for (i = 0; i < qtdemux->n_streams; i++) {
10973 QtDemuxStream *stream = qtdemux->streams[i];
10975 qtdemux_do_allocation (qtdemux, stream);
10978 qtdemux->exposed = TRUE;
10982 /* check if major or compatible brand is 3GP */
10983 static inline gboolean
10984 qtdemux_is_brand_3gp (GstQTDemux * qtdemux, gboolean major)
10987 return ((qtdemux->major_brand & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
10989 } else if (qtdemux->comp_brands != NULL) {
10993 gboolean res = FALSE;
10995 gst_buffer_map (qtdemux->comp_brands, &map, GST_MAP_READ);
10998 while (size >= 4) {
10999 res = res || ((QT_FOURCC (data) & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
11004 gst_buffer_unmap (qtdemux->comp_brands, &map);
11011 /* check if tag is a spec'ed 3GP tag keyword storing a string */
11012 static inline gboolean
11013 qtdemux_is_string_tag_3gp (GstQTDemux * qtdemux, guint32 fourcc)
11015 return fourcc == FOURCC_cprt || fourcc == FOURCC_gnre || fourcc == FOURCC_titl
11016 || fourcc == FOURCC_dscp || fourcc == FOURCC_perf || fourcc == FOURCC_auth
11017 || fourcc == FOURCC_albm;
11021 qtdemux_tag_add_location (GstQTDemux * qtdemux, GstTagList * taglist,
11022 const char *tag, const char *dummy, GNode * node)
11024 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
11028 gdouble longitude, latitude, altitude;
11031 len = QT_UINT32 (node->data);
11038 /* TODO: language code skipped */
11040 name = gst_tag_freeform_string_to_utf8 (data + offset, -1, env_vars);
11043 /* do not alarm in trivial case, but bail out otherwise */
11044 if (*(data + offset) != 0) {
11045 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8, "
11049 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
11050 GST_TAG_GEO_LOCATION_NAME, name, NULL);
11051 offset += strlen (name);
11055 if (len < offset + 2 + 4 + 4 + 4)
11058 /* +1 +1 = skip null-terminator and location role byte */
11060 /* table in spec says unsigned, semantics say negative has meaning ... */
11061 longitude = QT_SFP32 (data + offset);
11064 latitude = QT_SFP32 (data + offset);
11067 altitude = QT_SFP32 (data + offset);
11069 /* one invalid means all are invalid */
11070 if (longitude >= -180.0 && longitude <= 180.0 &&
11071 latitude >= -90.0 && latitude <= 90.0) {
11072 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
11073 GST_TAG_GEO_LOCATION_LATITUDE, latitude,
11074 GST_TAG_GEO_LOCATION_LONGITUDE, longitude,
11075 GST_TAG_GEO_LOCATION_ELEVATION, altitude, NULL);
11078 /* TODO: no GST_TAG_, so astronomical body and additional notes skipped */
11085 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP location");
11092 qtdemux_tag_add_year (GstQTDemux * qtdemux, GstTagList * taglist,
11093 const char *tag, const char *dummy, GNode * node)
11099 len = QT_UINT32 (node->data);
11103 y = QT_UINT16 ((guint8 *) node->data + 12);
11105 GST_DEBUG_OBJECT (qtdemux, "year: %u is not a valid year", y);
11108 GST_DEBUG_OBJECT (qtdemux, "year: %u", y);
11110 date = g_date_new_dmy (1, 1, y);
11111 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, date, NULL);
11112 g_date_free (date);
11116 qtdemux_tag_add_classification (GstQTDemux * qtdemux, GstTagList * taglist,
11117 const char *tag, const char *dummy, GNode * node)
11120 char *tag_str = NULL;
11125 len = QT_UINT32 (node->data);
11130 entity = (guint8 *) node->data + offset;
11131 if (entity[0] == 0 || entity[1] == 0 || entity[2] == 0 || entity[3] == 0) {
11132 GST_DEBUG_OBJECT (qtdemux,
11133 "classification info: %c%c%c%c invalid classification entity",
11134 entity[0], entity[1], entity[2], entity[3]);
11139 table = QT_UINT16 ((guint8 *) node->data + offset);
11141 /* Language code skipped */
11145 /* Tag format: "XXXX://Y[YYYY]/classification info string"
11146 * XXXX: classification entity, fixed length 4 chars.
11147 * Y[YYYY]: classification table, max 5 chars.
11149 tag_str = g_strdup_printf ("----://%u/%s",
11150 table, (char *) node->data + offset);
11152 /* memcpy To be sure we're preserving byte order */
11153 memcpy (tag_str, entity, 4);
11154 GST_DEBUG_OBJECT (qtdemux, "classification info: %s", tag_str);
11156 gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND, tag, tag_str, NULL);
11165 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP classification");
11171 qtdemux_tag_add_str_full (GstQTDemux * qtdemux, GstTagList * taglist,
11172 const char *tag, const char *dummy, GNode * node)
11174 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
11180 gboolean ret = TRUE;
11181 const gchar *charset = NULL;
11183 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
11185 len = QT_UINT32 (data->data);
11186 type = QT_UINT32 ((guint8 *) data->data + 8);
11187 if (type == 0x00000001 && len > 16) {
11188 s = gst_tag_freeform_string_to_utf8 ((char *) data->data + 16, len - 16,
11191 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
11192 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, s, NULL);
11195 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
11199 len = QT_UINT32 (node->data);
11200 type = QT_UINT32 ((guint8 *) node->data + 4);
11201 if ((type >> 24) == 0xa9) {
11205 /* Type starts with the (C) symbol, so the next data is a list
11206 * of (string size(16), language code(16), string) */
11208 str_len = QT_UINT16 ((guint8 *) node->data + 8);
11209 lang_code = QT_UINT16 ((guint8 *) node->data + 10);
11211 /* the string + fourcc + size + 2 16bit fields,
11212 * means that there are more tags in this atom */
11213 if (len > str_len + 8 + 4) {
11214 /* TODO how to represent the same tag in different languages? */
11215 GST_WARNING_OBJECT (qtdemux, "Ignoring metadata entry with multiple "
11216 "text alternatives, reading only first one");
11220 len = str_len + 8 + 4; /* remove trailing strings that we don't use */
11221 GST_DEBUG_OBJECT (qtdemux, "found international text tag");
11223 if (lang_code < 0x800) { /* MAC encoded string */
11226 } else if (len > 14 && qtdemux_is_string_tag_3gp (qtdemux,
11227 QT_FOURCC ((guint8 *) node->data + 4))) {
11228 guint32 type = QT_UINT32 ((guint8 *) node->data + 8);
11230 /* we go for 3GP style encoding if major brands claims so,
11231 * or if no hope for data be ok UTF-8, and compatible 3GP brand present */
11232 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
11233 (qtdemux_is_brand_3gp (qtdemux, FALSE) &&
11234 ((type & 0x00FFFFFF) == 0x0) && (type >> 24 <= 0xF))) {
11236 /* 16-bit Language code is ignored here as well */
11237 GST_DEBUG_OBJECT (qtdemux, "found 3gpp text tag");
11244 GST_DEBUG_OBJECT (qtdemux, "found normal text tag");
11245 ret = FALSE; /* may have to fallback */
11248 GError *err = NULL;
11250 s = g_convert ((gchar *) node->data + offset, len - offset, "utf8",
11251 charset, NULL, NULL, &err);
11253 GST_DEBUG_OBJECT (qtdemux, "Failed to convert string from charset %s:"
11254 " %s(%d): %s", charset, g_quark_to_string (err->domain), err->code,
11256 g_error_free (err);
11259 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
11260 len - offset, env_vars);
11263 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
11264 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, s, NULL);
11268 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
11275 qtdemux_tag_add_str (GstQTDemux * qtdemux, GstTagList * taglist,
11276 const char *tag, const char *dummy, GNode * node)
11278 qtdemux_tag_add_str_full (qtdemux, taglist, tag, dummy, node);
11282 qtdemux_tag_add_keywords (GstQTDemux * qtdemux, GstTagList * taglist,
11283 const char *tag, const char *dummy, GNode * node)
11285 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
11287 char *s, *t, *k = NULL;
11292 /* first try normal string tag if major brand not 3GP */
11293 if (!qtdemux_is_brand_3gp (qtdemux, TRUE)) {
11294 if (!qtdemux_tag_add_str_full (qtdemux, taglist, tag, dummy, node)) {
11295 /* hm, that did not work, maybe 3gpp storage in non-3gpp major brand;
11296 * let's try it 3gpp way after minor safety check */
11298 if (QT_UINT32 (data) < 15 || !qtdemux_is_brand_3gp (qtdemux, FALSE))
11304 GST_DEBUG_OBJECT (qtdemux, "found 3gpp keyword tag");
11308 len = QT_UINT32 (data);
11312 count = QT_UINT8 (data + 14);
11314 for (; count; count--) {
11317 if (offset + 1 > len)
11319 slen = QT_UINT8 (data + offset);
11321 if (offset + slen > len)
11323 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
11326 GST_DEBUG_OBJECT (qtdemux, "adding keyword %s", GST_STR_NULL (s));
11328 t = g_strjoin (",", k, s, NULL);
11336 GST_DEBUG_OBJECT (qtdemux, "failed to convert keyword to UTF-8");
11343 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (k));
11344 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, k, NULL);
11353 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP keywords");
11359 qtdemux_tag_add_num (GstQTDemux * qtdemux, GstTagList * taglist,
11360 const char *tag1, const char *tag2, GNode * node)
11367 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
11369 len = QT_UINT32 (data->data);
11370 type = QT_UINT32 ((guint8 *) data->data + 8);
11371 if (type == 0x00000000 && len >= 22) {
11372 n1 = QT_UINT16 ((guint8 *) data->data + 18);
11373 n2 = QT_UINT16 ((guint8 *) data->data + 20);
11375 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag1, n1);
11376 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, n1, NULL);
11379 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag2, n2);
11380 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag2, n2, NULL);
11387 qtdemux_tag_add_tmpo (GstQTDemux * qtdemux, GstTagList * taglist,
11388 const char *tag1, const char *dummy, GNode * node)
11395 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
11397 len = QT_UINT32 (data->data);
11398 type = QT_UINT32 ((guint8 *) data->data + 8);
11399 GST_DEBUG_OBJECT (qtdemux, "have tempo tag, type=%d,len=%d", type, len);
11400 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
11401 if ((type == 0x00000015 || type == 0x0000000f) && len >= 18) {
11402 n1 = QT_UINT16 ((guint8 *) data->data + 16);
11404 /* do not add bpm=0 */
11405 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", n1);
11406 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, (gdouble) n1,
11414 qtdemux_tag_add_uint32 (GstQTDemux * qtdemux, GstTagList * taglist,
11415 const char *tag1, const char *dummy, GNode * node)
11422 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
11424 len = QT_UINT32 (data->data);
11425 type = QT_UINT32 ((guint8 *) data->data + 8);
11426 GST_DEBUG_OBJECT (qtdemux, "have %s tag, type=%d,len=%d", tag1, type, len);
11427 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
11428 if ((type == 0x00000015 || type == 0x0000000f) && len >= 20) {
11429 num = QT_UINT32 ((guint8 *) data->data + 16);
11431 /* do not add num=0 */
11432 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", num);
11433 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, num, NULL);
11440 qtdemux_tag_add_covr (GstQTDemux * qtdemux, GstTagList * taglist,
11441 const char *tag1, const char *dummy, GNode * node)
11448 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
11450 len = QT_UINT32 (data->data);
11451 type = QT_UINT32 ((guint8 *) data->data + 8);
11452 GST_DEBUG_OBJECT (qtdemux, "have covr tag, type=%d,len=%d", type, len);
11453 if ((type == 0x0000000d || type == 0x0000000e) && len > 16) {
11455 gst_tag_image_data_to_image_sample ((guint8 *) data->data + 16,
11456 len - 16, GST_TAG_IMAGE_TYPE_NONE))) {
11457 GST_DEBUG_OBJECT (qtdemux, "adding tag size %d", len - 16);
11458 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, sample, NULL);
11459 gst_sample_unref (sample);
11466 qtdemux_tag_add_date (GstQTDemux * qtdemux, GstTagList * taglist,
11467 const char *tag, const char *dummy, GNode * node)
11474 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
11476 len = QT_UINT32 (data->data);
11477 type = QT_UINT32 ((guint8 *) data->data + 8);
11478 if (type == 0x00000001 && len > 16) {
11479 guint y, m = 1, d = 1;
11482 s = g_strndup ((char *) data->data + 16, len - 16);
11483 GST_DEBUG_OBJECT (qtdemux, "adding date '%s'", s);
11484 ret = sscanf (s, "%u-%u-%u", &y, &m, &d);
11485 if (ret >= 1 && y > 1500 && y < 3000) {
11488 date = g_date_new_dmy (d, m, y);
11489 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, date, NULL);
11490 g_date_free (date);
11492 GST_DEBUG_OBJECT (qtdemux, "could not parse date string '%s'", s);
11500 qtdemux_tag_add_gnre (GstQTDemux * qtdemux, GstTagList * taglist,
11501 const char *tag, const char *dummy, GNode * node)
11505 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
11507 /* re-route to normal string tag if major brand says so
11508 * or no data atom and compatible brand suggests so */
11509 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
11510 (qtdemux_is_brand_3gp (qtdemux, FALSE) && !data)) {
11511 qtdemux_tag_add_str (qtdemux, taglist, tag, dummy, node);
11516 guint len, type, n;
11518 len = QT_UINT32 (data->data);
11519 type = QT_UINT32 ((guint8 *) data->data + 8);
11520 if (type == 0x00000000 && len >= 18) {
11521 n = QT_UINT16 ((guint8 *) data->data + 16);
11523 const gchar *genre;
11525 genre = gst_tag_id3_genre_get (n - 1);
11526 if (genre != NULL) {
11527 GST_DEBUG_OBJECT (qtdemux, "adding %d [%s]", n, genre);
11528 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, genre, NULL);
11536 qtdemux_add_double_tag_from_str (GstQTDemux * demux, GstTagList * taglist,
11537 const gchar * tag, guint8 * data, guint32 datasize)
11542 /* make a copy to have \0 at the end */
11543 datacopy = g_strndup ((gchar *) data, datasize);
11545 /* convert the str to double */
11546 if (sscanf (datacopy, "%lf", &value) == 1) {
11547 GST_DEBUG_OBJECT (demux, "adding tag: %s [%s]", tag, datacopy);
11548 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, value, NULL);
11550 GST_WARNING_OBJECT (demux, "Failed to parse double from string: %s",
11558 qtdemux_tag_add_revdns (GstQTDemux * demux, GstTagList * taglist,
11559 const char *tag, const char *tag_bis, GNode * node)
11568 const gchar *meanstr;
11569 const gchar *namestr;
11571 /* checking the whole ---- atom size for consistency */
11572 if (QT_UINT32 (node->data) <= 4 + 12 + 12 + 16) {
11573 GST_WARNING_OBJECT (demux, "Tag ---- atom is too small, ignoring");
11577 mean = qtdemux_tree_get_child_by_type (node, FOURCC_mean);
11579 GST_WARNING_OBJECT (demux, "No 'mean' atom found");
11583 meansize = QT_UINT32 (mean->data);
11584 if (meansize <= 12) {
11585 GST_WARNING_OBJECT (demux, "Small mean atom, ignoring the whole tag");
11588 meanstr = ((gchar *) mean->data) + 12;
11591 name = qtdemux_tree_get_child_by_type (node, FOURCC_name);
11593 GST_WARNING_OBJECT (demux, "'name' atom not found, ignoring tag");
11597 namesize = QT_UINT32 (name->data);
11598 if (namesize <= 12) {
11599 GST_WARNING_OBJECT (demux, "'name' atom is too small, ignoring tag");
11602 namestr = ((gchar *) name->data) + 12;
11610 * uint24 - data type
11614 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
11616 GST_WARNING_OBJECT (demux, "No data atom in this tag");
11619 datasize = QT_UINT32 (data->data);
11620 if (datasize <= 16) {
11621 GST_WARNING_OBJECT (demux, "Data atom too small");
11624 datatype = QT_UINT32 (((gchar *) data->data) + 8) & 0xFFFFFF;
11626 if ((strncmp (meanstr, "com.apple.iTunes", meansize) == 0) ||
11627 (strncmp (meanstr, "org.hydrogenaudio.replaygain", meansize) == 0)) {
11628 static const struct
11630 const gchar name[28];
11631 const gchar tag[28];
11634 "replaygain_track_gain", GST_TAG_TRACK_GAIN}, {
11635 "replaygain_track_peak", GST_TAG_TRACK_PEAK}, {
11636 "replaygain_album_gain", GST_TAG_ALBUM_GAIN}, {
11637 "replaygain_album_peak", GST_TAG_ALBUM_PEAK}, {
11638 "MusicBrainz Track Id", GST_TAG_MUSICBRAINZ_TRACKID}, {
11639 "MusicBrainz Artist Id", GST_TAG_MUSICBRAINZ_ARTISTID}, {
11640 "MusicBrainz Album Id", GST_TAG_MUSICBRAINZ_ALBUMID}, {
11641 "MusicBrainz Album Artist Id", GST_TAG_MUSICBRAINZ_ALBUMARTISTID}
11645 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
11646 if (!g_ascii_strncasecmp (tags[i].name, namestr, namesize)) {
11647 switch (gst_tag_get_type (tags[i].tag)) {
11648 case G_TYPE_DOUBLE:
11649 qtdemux_add_double_tag_from_str (demux, taglist, tags[i].tag,
11650 ((guint8 *) data->data) + 16, datasize - 16);
11652 case G_TYPE_STRING:
11653 qtdemux_tag_add_str (demux, taglist, tags[i].tag, NULL, node);
11662 if (i == G_N_ELEMENTS (tags))
11672 #ifndef GST_DISABLE_GST_DEBUG
11674 gchar *namestr_dbg;
11675 gchar *meanstr_dbg;
11677 meanstr_dbg = g_strndup (meanstr, meansize);
11678 namestr_dbg = g_strndup (namestr, namesize);
11680 GST_WARNING_OBJECT (demux, "This tag %s:%s type:%u is not mapped, "
11681 "file a bug at bugzilla.gnome.org", meanstr_dbg, namestr_dbg, datatype);
11683 g_free (namestr_dbg);
11684 g_free (meanstr_dbg);
11691 qtdemux_tag_add_id32 (GstQTDemux * demux, GstTagList * taglist, const char *tag,
11692 const char *tag_bis, GNode * node)
11697 GstTagList *id32_taglist = NULL;
11699 GST_LOG_OBJECT (demux, "parsing ID32");
11702 len = GST_READ_UINT32_BE (data);
11704 /* need at least full box and language tag */
11708 buf = gst_buffer_new_allocate (NULL, len - 14, NULL);
11709 gst_buffer_fill (buf, 0, data + 14, len - 14);
11711 id32_taglist = gst_tag_list_from_id3v2_tag (buf);
11712 if (id32_taglist) {
11713 GST_LOG_OBJECT (demux, "parsing ok");
11714 gst_tag_list_insert (taglist, id32_taglist, GST_TAG_MERGE_KEEP);
11715 gst_tag_list_unref (id32_taglist);
11717 GST_LOG_OBJECT (demux, "parsing failed");
11720 gst_buffer_unref (buf);
11723 typedef void (*GstQTDemuxAddTagFunc) (GstQTDemux * demux, GstTagList * taglist,
11724 const char *tag, const char *tag_bis, GNode * node);
11727 FOURCC_pcst -> if media is a podcast -> bool
11728 FOURCC_cpil -> if media is part of a compilation -> bool
11729 FOURCC_pgap -> if media is part of a gapless context -> bool
11730 FOURCC_tven -> the tv episode id e.g. S01E23 -> str
11733 static const struct
11736 const gchar *gst_tag;
11737 const gchar *gst_tag_bis;
11738 const GstQTDemuxAddTagFunc func;
11741 FOURCC__nam, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
11742 FOURCC_titl, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
11743 FOURCC__grp, GST_TAG_GROUPING, NULL, qtdemux_tag_add_str}, {
11744 FOURCC__wrt, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
11745 FOURCC__ART, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
11746 FOURCC_aART, GST_TAG_ALBUM_ARTIST, NULL, qtdemux_tag_add_str}, {
11747 FOURCC_perf, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
11748 FOURCC_auth, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
11749 FOURCC__alb, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
11750 FOURCC_albm, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
11751 FOURCC_cprt, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
11752 FOURCC__cpy, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
11753 FOURCC__cmt, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
11754 FOURCC__des, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
11755 FOURCC_desc, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
11756 FOURCC_dscp, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
11757 FOURCC__lyr, GST_TAG_LYRICS, NULL, qtdemux_tag_add_str}, {
11758 FOURCC__day, GST_TAG_DATE, NULL, qtdemux_tag_add_date}, {
11759 FOURCC_yrrc, GST_TAG_DATE, NULL, qtdemux_tag_add_year}, {
11760 FOURCC__too, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
11761 FOURCC__inf, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
11762 FOURCC_trkn, GST_TAG_TRACK_NUMBER, GST_TAG_TRACK_COUNT, qtdemux_tag_add_num}, {
11763 FOURCC_disk, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
11764 qtdemux_tag_add_num}, {
11765 FOURCC_disc, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
11766 qtdemux_tag_add_num}, {
11767 FOURCC__gen, GST_TAG_GENRE, NULL, qtdemux_tag_add_str}, {
11768 FOURCC_gnre, GST_TAG_GENRE, NULL, qtdemux_tag_add_gnre}, {
11769 FOURCC_tmpo, GST_TAG_BEATS_PER_MINUTE, NULL, qtdemux_tag_add_tmpo}, {
11770 FOURCC_covr, GST_TAG_PREVIEW_IMAGE, NULL, qtdemux_tag_add_covr}, {
11771 FOURCC_sonm, GST_TAG_TITLE_SORTNAME, NULL, qtdemux_tag_add_str}, {
11772 FOURCC_soal, GST_TAG_ALBUM_SORTNAME, NULL, qtdemux_tag_add_str}, {
11773 FOURCC_soar, GST_TAG_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
11774 FOURCC_soaa, GST_TAG_ALBUM_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
11775 FOURCC_soco, GST_TAG_COMPOSER_SORTNAME, NULL, qtdemux_tag_add_str}, {
11776 FOURCC_sosn, GST_TAG_SHOW_SORTNAME, NULL, qtdemux_tag_add_str}, {
11777 FOURCC_tvsh, GST_TAG_SHOW_NAME, NULL, qtdemux_tag_add_str}, {
11778 FOURCC_tvsn, GST_TAG_SHOW_SEASON_NUMBER, NULL, qtdemux_tag_add_uint32}, {
11779 FOURCC_tves, GST_TAG_SHOW_EPISODE_NUMBER, NULL, qtdemux_tag_add_uint32}, {
11780 FOURCC_kywd, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_keywords}, {
11781 FOURCC_keyw, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_str}, {
11782 FOURCC__enc, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
11783 FOURCC_loci, GST_TAG_GEO_LOCATION_NAME, NULL, qtdemux_tag_add_location}, {
11784 FOURCC_clsf, GST_QT_DEMUX_CLASSIFICATION_TAG, NULL,
11785 qtdemux_tag_add_classification}, {
11786 FOURCC__mak, GST_TAG_DEVICE_MANUFACTURER, NULL, qtdemux_tag_add_str}, {
11787 FOURCC__mod, GST_TAG_DEVICE_MODEL, NULL, qtdemux_tag_add_str}, {
11788 FOURCC__swr, GST_TAG_APPLICATION_NAME, NULL, qtdemux_tag_add_str}, {
11790 /* This is a special case, some tags are stored in this
11791 * 'reverse dns naming', according to:
11792 * http://atomicparsley.sourceforge.net/mpeg-4files.html and
11795 FOURCC_____, "", NULL, qtdemux_tag_add_revdns}, {
11796 /* see http://www.mp4ra.org/specs.html for ID32 in meta box */
11797 FOURCC_ID32, "", NULL, qtdemux_tag_add_id32}
11800 struct _GstQtDemuxTagList
11803 GstTagList *taglist;
11805 typedef struct _GstQtDemuxTagList GstQtDemuxTagList;
11808 qtdemux_tag_add_blob (GNode * node, GstQtDemuxTagList * qtdemuxtaglist)
11814 const gchar *style;
11819 GstQTDemux *demux = qtdemuxtaglist->demux;
11820 GstTagList *taglist = qtdemuxtaglist->taglist;
11823 len = QT_UINT32 (data);
11824 buf = gst_buffer_new_and_alloc (len);
11825 gst_buffer_fill (buf, 0, data, len);
11827 /* heuristic to determine style of tag */
11828 if (QT_FOURCC (data + 4) == FOURCC_____ ||
11829 (len > 8 + 12 && QT_FOURCC (data + 12) == FOURCC_data))
11831 else if (demux->major_brand == FOURCC_qt__)
11832 style = "quicktime";
11833 /* fall back to assuming iso/3gp tag style */
11837 /* santize the name for the caps. */
11838 for (i = 0; i < 4; i++) {
11839 guint8 d = data[4 + i];
11840 if (g_ascii_isalnum (d))
11841 ndata[i] = g_ascii_tolower (d);
11846 media_type = g_strdup_printf ("application/x-gst-qt-%c%c%c%c-tag",
11847 ndata[0], ndata[1], ndata[2], ndata[3]);
11848 GST_DEBUG_OBJECT (demux, "media type %s", media_type);
11850 s = gst_structure_new (media_type, "style", G_TYPE_STRING, style, NULL);
11851 sample = gst_sample_new (buf, NULL, NULL, s);
11852 gst_buffer_unref (buf);
11853 g_free (media_type);
11855 GST_DEBUG_OBJECT (demux, "adding private tag; size %d, info %" GST_PTR_FORMAT,
11858 gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND,
11859 GST_QT_DEMUX_PRIVATE_TAG, sample, NULL);
11861 gst_sample_unref (sample);
11865 qtdemux_parse_udta (GstQTDemux * qtdemux, GstTagList * taglist, GNode * udta)
11872 GstQtDemuxTagList demuxtaglist;
11874 demuxtaglist.demux = qtdemux;
11875 demuxtaglist.taglist = taglist;
11877 meta = qtdemux_tree_get_child_by_type (udta, FOURCC_meta);
11878 if (meta != NULL) {
11879 ilst = qtdemux_tree_get_child_by_type (meta, FOURCC_ilst);
11880 if (ilst == NULL) {
11881 GST_LOG_OBJECT (qtdemux, "no ilst");
11886 GST_LOG_OBJECT (qtdemux, "no meta so using udta itself");
11890 while (i < G_N_ELEMENTS (add_funcs)) {
11891 node = qtdemux_tree_get_child_by_type (ilst, add_funcs[i].fourcc);
11895 len = QT_UINT32 (node->data);
11897 GST_DEBUG_OBJECT (qtdemux, "too small tag atom %" GST_FOURCC_FORMAT,
11898 GST_FOURCC_ARGS (add_funcs[i].fourcc));
11900 add_funcs[i].func (qtdemux, taglist, add_funcs[i].gst_tag,
11901 add_funcs[i].gst_tag_bis, node);
11903 g_node_destroy (node);
11909 /* parsed nodes have been removed, pass along remainder as blob */
11910 g_node_children_foreach (ilst, G_TRAVERSE_ALL,
11911 (GNodeForeachFunc) qtdemux_tag_add_blob, &demuxtaglist);
11913 /* parse up XMP_ node if existing */
11914 xmp_ = qtdemux_tree_get_child_by_type (udta, FOURCC_XMP_);
11915 if (xmp_ != NULL) {
11917 GstTagList *xmptaglist;
11919 buf = _gst_buffer_new_wrapped (((guint8 *) xmp_->data) + 8,
11920 QT_UINT32 ((guint8 *) xmp_->data) - 8, NULL);
11921 xmptaglist = gst_tag_list_from_xmp_buffer (buf);
11922 gst_buffer_unref (buf);
11924 qtdemux_handle_xmp_taglist (qtdemux, taglist, xmptaglist);
11926 GST_DEBUG_OBJECT (qtdemux, "No XMP_ node found");
11932 GstStructure *structure; /* helper for sort function */
11934 guint min_req_bitrate;
11935 guint min_req_qt_version;
11939 qtdemux_redirects_sort_func (gconstpointer a, gconstpointer b)
11941 GstQtReference *ref_a = (GstQtReference *) a;
11942 GstQtReference *ref_b = (GstQtReference *) b;
11944 if (ref_b->min_req_qt_version != ref_a->min_req_qt_version)
11945 return ref_b->min_req_qt_version - ref_a->min_req_qt_version;
11947 /* known bitrates go before unknown; higher bitrates go first */
11948 return ref_b->min_req_bitrate - ref_a->min_req_bitrate;
11951 /* sort the redirects and post a message for the application.
11954 qtdemux_process_redirects (GstQTDemux * qtdemux, GList * references)
11956 GstQtReference *best;
11959 GValue list_val = { 0, };
11962 g_assert (references != NULL);
11964 references = g_list_sort (references, qtdemux_redirects_sort_func);
11966 best = (GstQtReference *) references->data;
11968 g_value_init (&list_val, GST_TYPE_LIST);
11970 for (l = references; l != NULL; l = l->next) {
11971 GstQtReference *ref = (GstQtReference *) l->data;
11972 GValue struct_val = { 0, };
11974 ref->structure = gst_structure_new ("redirect",
11975 "new-location", G_TYPE_STRING, ref->location, NULL);
11977 if (ref->min_req_bitrate > 0) {
11978 gst_structure_set (ref->structure, "minimum-bitrate", G_TYPE_INT,
11979 ref->min_req_bitrate, NULL);
11982 g_value_init (&struct_val, GST_TYPE_STRUCTURE);
11983 g_value_set_boxed (&struct_val, ref->structure);
11984 gst_value_list_append_value (&list_val, &struct_val);
11985 g_value_unset (&struct_val);
11986 /* don't free anything here yet, since we need best->structure below */
11989 g_assert (best != NULL);
11990 s = gst_structure_copy (best->structure);
11992 if (g_list_length (references) > 1) {
11993 gst_structure_set_value (s, "locations", &list_val);
11996 g_value_unset (&list_val);
11998 for (l = references; l != NULL; l = l->next) {
11999 GstQtReference *ref = (GstQtReference *) l->data;
12001 gst_structure_free (ref->structure);
12002 g_free (ref->location);
12005 g_list_free (references);
12007 GST_INFO_OBJECT (qtdemux, "posting redirect message: %" GST_PTR_FORMAT, s);
12008 msg = gst_message_new_element (GST_OBJECT_CAST (qtdemux), s);
12009 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
12010 qtdemux->posted_redirect = TRUE;
12013 /* look for redirect nodes, collect all redirect information and
12017 qtdemux_parse_redirects (GstQTDemux * qtdemux)
12019 GNode *rmra, *rmda, *rdrf;
12021 rmra = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_rmra);
12023 GList *redirects = NULL;
12025 rmda = qtdemux_tree_get_child_by_type (rmra, FOURCC_rmda);
12027 GstQtReference ref = { NULL, NULL, 0, 0 };
12028 GNode *rmdr, *rmvc;
12030 if ((rmdr = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmdr))) {
12031 ref.min_req_bitrate = QT_UINT32 ((guint8 *) rmdr->data + 12);
12032 GST_LOG_OBJECT (qtdemux, "data rate atom, required bitrate = %u",
12033 ref.min_req_bitrate);
12036 if ((rmvc = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmvc))) {
12037 guint32 package = QT_FOURCC ((guint8 *) rmvc->data + 12);
12038 guint version = QT_UINT32 ((guint8 *) rmvc->data + 16);
12040 #ifndef GST_DISABLE_GST_DEBUG
12041 guint bitmask = QT_UINT32 ((guint8 *) rmvc->data + 20);
12043 guint check_type = QT_UINT16 ((guint8 *) rmvc->data + 24);
12045 GST_LOG_OBJECT (qtdemux,
12046 "version check atom [%" GST_FOURCC_FORMAT "], version=0x%08x"
12047 ", mask=%08x, check_type=%u", GST_FOURCC_ARGS (package), version,
12048 bitmask, check_type);
12049 if (package == FOURCC_qtim && check_type == 0) {
12050 ref.min_req_qt_version = version;
12054 rdrf = qtdemux_tree_get_child_by_type (rmda, FOURCC_rdrf);
12060 ref_len = QT_UINT32 ((guint8 *) rdrf->data);
12061 if (ref_len > 20) {
12062 ref_type = QT_FOURCC ((guint8 *) rdrf->data + 12);
12063 ref_data = (guint8 *) rdrf->data + 20;
12064 if (ref_type == FOURCC_alis) {
12065 guint record_len, record_version, fn_len;
12067 if (ref_len > 70) {
12068 /* MacOSX alias record, google for alias-layout.txt */
12069 record_len = QT_UINT16 (ref_data + 4);
12070 record_version = QT_UINT16 (ref_data + 4 + 2);
12071 fn_len = QT_UINT8 (ref_data + 50);
12072 if (record_len > 50 && record_version == 2 && fn_len > 0) {
12073 ref.location = g_strndup ((gchar *) ref_data + 51, fn_len);
12076 GST_WARNING_OBJECT (qtdemux, "Invalid rdrf/alis size (%u < 70)",
12079 } else if (ref_type == FOURCC_url_) {
12080 ref.location = g_strndup ((gchar *) ref_data, ref_len - 8);
12082 GST_DEBUG_OBJECT (qtdemux,
12083 "unknown rdrf reference type %" GST_FOURCC_FORMAT,
12084 GST_FOURCC_ARGS (ref_type));
12086 if (ref.location != NULL) {
12087 GST_INFO_OBJECT (qtdemux, "New location: %s", ref.location);
12089 g_list_prepend (redirects, g_memdup (&ref, sizeof (ref)));
12091 GST_WARNING_OBJECT (qtdemux,
12092 "Failed to extract redirect location from rdrf atom");
12095 GST_WARNING_OBJECT (qtdemux, "Invalid rdrf size (%u < 20)", ref_len);
12099 /* look for others */
12100 rmda = qtdemux_tree_get_sibling_by_type (rmda, FOURCC_rmda);
12103 if (redirects != NULL) {
12104 qtdemux_process_redirects (qtdemux, redirects);
12110 static GstTagList *
12111 qtdemux_add_container_format (GstQTDemux * qtdemux, GstTagList * tags)
12115 if (tags == NULL) {
12116 tags = gst_tag_list_new_empty ();
12117 gst_tag_list_set_scope (tags, GST_TAG_SCOPE_GLOBAL);
12120 if (qtdemux->major_brand == FOURCC_mjp2)
12121 fmt = "Motion JPEG 2000";
12122 else if ((qtdemux->major_brand & 0xffff) == FOURCC_3g__)
12124 else if (qtdemux->major_brand == FOURCC_qt__)
12126 else if (qtdemux->fragmented)
12129 fmt = "ISO MP4/M4A";
12131 GST_LOG_OBJECT (qtdemux, "mapped %" GST_FOURCC_FORMAT " to '%s'",
12132 GST_FOURCC_ARGS (qtdemux->major_brand), fmt);
12134 gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_CONTAINER_FORMAT,
12140 /* we have read th complete moov node now.
12141 * This function parses all of the relevant info, creates the traks and
12142 * prepares all data structures for playback
12145 qtdemux_parse_tree (GstQTDemux * qtdemux)
12151 GstClockTime duration;
12153 guint64 creation_time;
12154 GstDateTime *datetime = NULL;
12157 /* make sure we have a usable taglist */
12158 if (!qtdemux->tag_list) {
12159 qtdemux->tag_list = gst_tag_list_new_empty ();
12160 gst_tag_list_set_scope (qtdemux->tag_list, GST_TAG_SCOPE_GLOBAL);
12162 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
12165 mvhd = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvhd);
12166 if (mvhd == NULL) {
12167 GST_LOG_OBJECT (qtdemux, "No mvhd node found, looking for redirects.");
12168 return qtdemux_parse_redirects (qtdemux);
12171 version = QT_UINT8 ((guint8 *) mvhd->data + 8);
12172 if (version == 1) {
12173 creation_time = QT_UINT64 ((guint8 *) mvhd->data + 12);
12174 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 28);
12175 qtdemux->duration = QT_UINT64 ((guint8 *) mvhd->data + 32);
12176 } else if (version == 0) {
12177 creation_time = QT_UINT32 ((guint8 *) mvhd->data + 12);
12178 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 20);
12179 qtdemux->duration = QT_UINT32 ((guint8 *) mvhd->data + 24);
12181 GST_WARNING_OBJECT (qtdemux, "Unhandled mvhd version %d", version);
12185 /* Moving qt creation time (secs since 1904) to unix time */
12186 if (creation_time != 0) {
12187 /* Try to use epoch first as it should be faster and more commonly found */
12188 if (creation_time >= QTDEMUX_SECONDS_FROM_1904_TO_1970) {
12191 creation_time -= QTDEMUX_SECONDS_FROM_1904_TO_1970;
12192 /* some data cleansing sanity */
12193 g_get_current_time (&now);
12194 if (now.tv_sec + 24 * 3600 < creation_time) {
12195 GST_DEBUG_OBJECT (qtdemux, "discarding bogus future creation time");
12197 datetime = gst_date_time_new_from_unix_epoch_utc (creation_time);
12200 GDateTime *base_dt = g_date_time_new_utc (1904, 1, 1, 0, 0, 0);
12201 GDateTime *dt, *dt_local;
12203 dt = g_date_time_add_seconds (base_dt, creation_time);
12204 dt_local = g_date_time_to_local (dt);
12205 datetime = gst_date_time_new_from_g_date_time (dt_local);
12207 g_date_time_unref (base_dt);
12208 g_date_time_unref (dt);
12212 /* Use KEEP as explicit tags should have a higher priority than mvhd tag */
12213 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_KEEP, GST_TAG_DATE_TIME,
12215 gst_date_time_unref (datetime);
12218 GST_INFO_OBJECT (qtdemux, "timescale: %u", qtdemux->timescale);
12219 GST_INFO_OBJECT (qtdemux, "duration: %" G_GUINT64_FORMAT, qtdemux->duration);
12221 /* check for fragmented file and get some (default) data */
12222 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
12225 GstByteReader mehd_data;
12227 /* let track parsing or anyone know weird stuff might happen ... */
12228 qtdemux->fragmented = TRUE;
12230 /* compensate for total duration */
12231 mehd = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_mehd, &mehd_data);
12233 qtdemux_parse_mehd (qtdemux, &mehd_data);
12236 /* set duration in the segment info */
12237 gst_qtdemux_get_duration (qtdemux, &duration);
12239 qtdemux->segment.duration = duration;
12240 /* also do not exceed duration; stop is set that way post seek anyway,
12241 * and segment activation falls back to duration,
12242 * whereas loop only checks stop, so let's align this here as well */
12243 qtdemux->segment.stop = duration;
12246 /* parse all traks */
12247 trak = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_trak);
12249 qtdemux_parse_trak (qtdemux, trak);
12250 /* iterate all siblings */
12251 trak = qtdemux_tree_get_sibling_by_type (trak, FOURCC_trak);
12254 if (!qtdemux->tag_list) {
12255 GST_DEBUG_OBJECT (qtdemux, "new tag list");
12256 qtdemux->tag_list = gst_tag_list_new_empty ();
12257 gst_tag_list_set_scope (qtdemux->tag_list, GST_TAG_SCOPE_GLOBAL);
12259 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
12263 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_udta);
12265 qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
12267 GST_LOG_OBJECT (qtdemux, "No udta node found.");
12270 /* maybe also some tags in meta box */
12271 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_meta);
12273 GST_DEBUG_OBJECT (qtdemux, "Parsing meta box for tags.");
12274 qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
12276 GST_LOG_OBJECT (qtdemux, "No meta node found.");
12279 /* parse any protection system info */
12280 pssh = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_pssh);
12282 GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
12283 qtdemux_parse_pssh (qtdemux, pssh);
12284 pssh = qtdemux_tree_get_sibling_by_type (pssh, FOURCC_pssh);
12287 qtdemux->tag_list = qtdemux_add_container_format (qtdemux, qtdemux->tag_list);
12292 /* taken from ffmpeg */
12294 read_descr_size (guint8 * ptr, guint8 * end, guint8 ** end_out)
12306 len = (len << 7) | (c & 0x7f);
12314 /* this can change the codec originally present in @list */
12316 gst_qtdemux_handle_esds (GstQTDemux * qtdemux, QtDemuxStream * stream,
12317 GNode * esds, GstTagList * list)
12319 int len = QT_UINT32 (esds->data);
12320 guint8 *ptr = esds->data;
12321 guint8 *end = ptr + len;
12323 guint8 *data_ptr = NULL;
12325 guint8 object_type_id = 0;
12326 const char *codec_name = NULL;
12327 GstCaps *caps = NULL;
12329 GST_MEMDUMP_OBJECT (qtdemux, "esds", ptr, len);
12331 GST_DEBUG_OBJECT (qtdemux, "version/flags = %08x", QT_UINT32 (ptr));
12333 while (ptr + 1 < end) {
12334 tag = QT_UINT8 (ptr);
12335 GST_DEBUG_OBJECT (qtdemux, "tag = %02x", tag);
12337 len = read_descr_size (ptr, end, &ptr);
12338 GST_DEBUG_OBJECT (qtdemux, "len = %d", len);
12340 /* Check the stated amount of data is available for reading */
12341 if (len < 0 || ptr + len > end)
12345 case ES_DESCRIPTOR_TAG:
12346 GST_DEBUG_OBJECT (qtdemux, "ID %04x", QT_UINT16 (ptr));
12347 GST_DEBUG_OBJECT (qtdemux, "priority %04x", QT_UINT8 (ptr + 2));
12350 case DECODER_CONFIG_DESC_TAG:{
12351 guint max_bitrate, avg_bitrate;
12353 object_type_id = QT_UINT8 (ptr);
12354 max_bitrate = QT_UINT32 (ptr + 5);
12355 avg_bitrate = QT_UINT32 (ptr + 9);
12356 GST_DEBUG_OBJECT (qtdemux, "object_type_id %02x", object_type_id);
12357 GST_DEBUG_OBJECT (qtdemux, "stream_type %02x", QT_UINT8 (ptr + 1));
12358 GST_DEBUG_OBJECT (qtdemux, "buffer_size_db %02x", QT_UINT24 (ptr + 2));
12359 GST_DEBUG_OBJECT (qtdemux, "max bitrate %u", max_bitrate);
12360 GST_DEBUG_OBJECT (qtdemux, "avg bitrate %u", avg_bitrate);
12361 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
12362 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
12363 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
12365 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
12366 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
12367 avg_bitrate, NULL);
12372 case DECODER_SPECIFIC_INFO_TAG:
12373 GST_MEMDUMP_OBJECT (qtdemux, "data", ptr, len);
12374 if (object_type_id == 0xe0 && len == 0x40) {
12380 GST_DEBUG_OBJECT (qtdemux,
12381 "Have VOBSUB palette. Creating palette event");
12382 /* move to decConfigDescr data and read palette */
12384 for (i = 0; i < 16; i++) {
12385 clut[i] = QT_UINT32 (data);
12389 s = gst_structure_new ("application/x-gst-dvd", "event",
12390 G_TYPE_STRING, "dvd-spu-clut-change",
12391 "clut00", G_TYPE_INT, clut[0], "clut01", G_TYPE_INT, clut[1],
12392 "clut02", G_TYPE_INT, clut[2], "clut03", G_TYPE_INT, clut[3],
12393 "clut04", G_TYPE_INT, clut[4], "clut05", G_TYPE_INT, clut[5],
12394 "clut06", G_TYPE_INT, clut[6], "clut07", G_TYPE_INT, clut[7],
12395 "clut08", G_TYPE_INT, clut[8], "clut09", G_TYPE_INT, clut[9],
12396 "clut10", G_TYPE_INT, clut[10], "clut11", G_TYPE_INT, clut[11],
12397 "clut12", G_TYPE_INT, clut[12], "clut13", G_TYPE_INT, clut[13],
12398 "clut14", G_TYPE_INT, clut[14], "clut15", G_TYPE_INT, clut[15],
12401 /* store event and trigger custom processing */
12402 stream->pending_event =
12403 gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s);
12405 /* Generic codec_data handler puts it on the caps */
12412 case SL_CONFIG_DESC_TAG:
12413 GST_DEBUG_OBJECT (qtdemux, "data %02x", QT_UINT8 (ptr));
12417 GST_DEBUG_OBJECT (qtdemux, "Unknown/unhandled descriptor tag %02x",
12419 GST_MEMDUMP_OBJECT (qtdemux, "descriptor data", ptr, len);
12425 /* object_type_id in the esds atom in mp4a and mp4v tells us which codec is
12426 * in use, and should also be used to override some other parameters for some
12428 switch (object_type_id) {
12429 case 0x20: /* MPEG-4 */
12430 /* 4 bytes for the visual_object_sequence_start_code and 1 byte for the
12431 * profile_and_level_indication */
12432 if (data_ptr != NULL && data_len >= 5 &&
12433 GST_READ_UINT32_BE (data_ptr) == 0x000001b0) {
12434 gst_codec_utils_mpeg4video_caps_set_level_and_profile (stream->caps,
12435 data_ptr + 4, data_len - 4);
12437 break; /* Nothing special needed here */
12438 case 0x21: /* H.264 */
12439 codec_name = "H.264 / AVC";
12440 caps = gst_caps_new_simple ("video/x-h264",
12441 "stream-format", G_TYPE_STRING, "avc",
12442 "alignment", G_TYPE_STRING, "au", NULL);
12444 case 0x40: /* AAC (any) */
12445 case 0x66: /* AAC Main */
12446 case 0x67: /* AAC LC */
12447 case 0x68: /* AAC SSR */
12448 /* Override channels and rate based on the codec_data, as it's often
12450 /* Only do so for basic setup without HE-AAC extension */
12451 if (data_ptr && data_len == 2) {
12452 guint channels, rate;
12454 channels = gst_codec_utils_aac_get_channels (data_ptr, data_len);
12456 stream->n_channels = channels;
12458 rate = gst_codec_utils_aac_get_sample_rate (data_ptr, data_len);
12460 stream->rate = rate;
12463 /* Set level and profile if possible */
12464 if (data_ptr != NULL && data_len >= 2) {
12465 gst_codec_utils_aac_caps_set_level_and_profile (stream->caps,
12466 data_ptr, data_len);
12469 case 0x60: /* MPEG-2, various profiles */
12475 codec_name = "MPEG-2 video";
12476 caps = gst_caps_new_simple ("video/mpeg",
12477 "mpegversion", G_TYPE_INT, 2,
12478 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
12480 case 0x69: /* MPEG-2 BC audio */
12481 case 0x6B: /* MPEG-1 audio */
12482 caps = gst_caps_new_simple ("audio/mpeg",
12483 "mpegversion", G_TYPE_INT, 1, "parsed", G_TYPE_BOOLEAN, TRUE, NULL);
12484 codec_name = "MPEG-1 audio";
12486 case 0x6A: /* MPEG-1 */
12487 codec_name = "MPEG-1 video";
12488 caps = gst_caps_new_simple ("video/mpeg",
12489 "mpegversion", G_TYPE_INT, 1,
12490 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
12492 case 0x6C: /* MJPEG */
12494 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
12496 codec_name = "Motion-JPEG";
12498 case 0x6D: /* PNG */
12500 gst_caps_new_simple ("image/png", "parsed", G_TYPE_BOOLEAN, TRUE,
12502 codec_name = "PNG still images";
12504 case 0x6E: /* JPEG2000 */
12505 codec_name = "JPEG-2000";
12506 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
12508 case 0xA4: /* Dirac */
12509 codec_name = "Dirac";
12510 caps = gst_caps_new_empty_simple ("video/x-dirac");
12512 case 0xA5: /* AC3 */
12513 codec_name = "AC-3 audio";
12514 caps = gst_caps_new_simple ("audio/x-ac3",
12515 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
12517 case 0xA9: /* AC3 */
12518 codec_name = "DTS audio";
12519 caps = gst_caps_new_simple ("audio/x-dts",
12520 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
12522 case 0xE1: /* QCELP */
12523 /* QCELP, the codec_data is a riff tag (little endian) with
12524 * 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). */
12525 caps = gst_caps_new_empty_simple ("audio/qcelp");
12526 codec_name = "QCELP";
12532 /* If we have a replacement caps, then change our caps for this stream */
12534 gst_caps_unref (stream->caps);
12535 stream->caps = caps;
12538 if (codec_name && list)
12539 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
12540 GST_TAG_AUDIO_CODEC, codec_name, NULL);
12542 /* Add the codec_data attribute to caps, if we have it */
12546 buffer = gst_buffer_new_and_alloc (data_len);
12547 gst_buffer_fill (buffer, 0, data_ptr, data_len);
12549 GST_DEBUG_OBJECT (qtdemux, "setting codec_data from esds");
12550 GST_MEMDUMP_OBJECT (qtdemux, "codec_data from esds", data_ptr, data_len);
12552 gst_caps_set_simple (stream->caps, "codec_data", GST_TYPE_BUFFER,
12554 gst_buffer_unref (buffer);
12559 #define _codec(name) \
12561 if (codec_name) { \
12562 *codec_name = g_strdup (name); \
12567 qtdemux_video_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
12568 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
12570 GstCaps *caps = NULL;
12571 GstVideoFormat format = GST_VIDEO_FORMAT_UNKNOWN;
12574 case GST_MAKE_FOURCC ('p', 'n', 'g', ' '):
12575 _codec ("PNG still images");
12576 caps = gst_caps_new_empty_simple ("image/png");
12579 _codec ("JPEG still images");
12581 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
12584 case GST_MAKE_FOURCC ('m', 'j', 'p', 'a'):
12585 case GST_MAKE_FOURCC ('A', 'V', 'D', 'J'):
12586 case GST_MAKE_FOURCC ('M', 'J', 'P', 'G'):
12587 case GST_MAKE_FOURCC ('d', 'm', 'b', '1'):
12588 _codec ("Motion-JPEG");
12590 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
12593 case GST_MAKE_FOURCC ('m', 'j', 'p', 'b'):
12594 _codec ("Motion-JPEG format B");
12595 caps = gst_caps_new_empty_simple ("video/x-mjpeg-b");
12598 _codec ("JPEG-2000");
12599 /* override to what it should be according to spec, avoid palette_data */
12600 stream->bits_per_sample = 24;
12601 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
12604 _codec ("Sorensen video v.3");
12605 caps = gst_caps_new_simple ("video/x-svq",
12606 "svqversion", G_TYPE_INT, 3, NULL);
12608 case GST_MAKE_FOURCC ('s', 'v', 'q', 'i'):
12609 case GST_MAKE_FOURCC ('S', 'V', 'Q', '1'):
12610 _codec ("Sorensen video v.1");
12611 caps = gst_caps_new_simple ("video/x-svq",
12612 "svqversion", G_TYPE_INT, 1, NULL);
12614 case GST_MAKE_FOURCC ('W', 'R', 'A', 'W'):
12615 caps = gst_caps_new_empty_simple ("video/x-raw");
12616 gst_caps_set_simple (caps, "format", G_TYPE_STRING, "RGB8P", NULL);
12617 _codec ("Windows Raw RGB");
12623 bps = QT_UINT16 (stsd_data + 98);
12626 format = GST_VIDEO_FORMAT_RGB15;
12629 format = GST_VIDEO_FORMAT_RGB16;
12632 format = GST_VIDEO_FORMAT_RGB;
12635 format = GST_VIDEO_FORMAT_ARGB;
12643 case GST_MAKE_FOURCC ('y', 'v', '1', '2'):
12644 format = GST_VIDEO_FORMAT_I420;
12646 case GST_MAKE_FOURCC ('y', 'u', 'v', '2'):
12647 case GST_MAKE_FOURCC ('Y', 'u', 'v', '2'):
12648 format = GST_VIDEO_FORMAT_I420;
12651 case GST_MAKE_FOURCC ('2', 'V', 'u', 'y'):
12652 format = GST_VIDEO_FORMAT_UYVY;
12654 case GST_MAKE_FOURCC ('v', '3', '0', '8'):
12655 format = GST_VIDEO_FORMAT_v308;
12657 case GST_MAKE_FOURCC ('v', '2', '1', '6'):
12658 format = GST_VIDEO_FORMAT_v216;
12661 format = GST_VIDEO_FORMAT_v210;
12663 case GST_MAKE_FOURCC ('r', '2', '1', '0'):
12664 format = GST_VIDEO_FORMAT_r210;
12666 /* Packed YUV 4:4:4 10 bit in 32 bits, complex
12667 case GST_MAKE_FOURCC ('v', '4', '1', '0'):
12668 format = GST_VIDEO_FORMAT_v410;
12671 /* Packed YUV 4:4:4:4 8 bit in 32 bits
12672 * but different order than AYUV
12673 case GST_MAKE_FOURCC ('v', '4', '0', '8'):
12674 format = GST_VIDEO_FORMAT_v408;
12677 case GST_MAKE_FOURCC ('m', 'p', 'e', 'g'):
12678 case GST_MAKE_FOURCC ('m', 'p', 'g', '1'):
12679 _codec ("MPEG-1 video");
12680 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
12681 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
12683 case GST_MAKE_FOURCC ('h', 'd', 'v', '1'): /* HDV 720p30 */
12684 case GST_MAKE_FOURCC ('h', 'd', 'v', '2'): /* HDV 1080i60 */
12685 case GST_MAKE_FOURCC ('h', 'd', 'v', '3'): /* HDV 1080i50 */
12686 case GST_MAKE_FOURCC ('h', 'd', 'v', '4'): /* HDV 720p24 */
12687 case GST_MAKE_FOURCC ('h', 'd', 'v', '5'): /* HDV 720p25 */
12688 case GST_MAKE_FOURCC ('h', 'd', 'v', '6'): /* HDV 1080p24 */
12689 case GST_MAKE_FOURCC ('h', 'd', 'v', '7'): /* HDV 1080p25 */
12690 case GST_MAKE_FOURCC ('h', 'd', 'v', '8'): /* HDV 1080p30 */
12691 case GST_MAKE_FOURCC ('h', 'd', 'v', '9'): /* HDV 720p60 */
12692 case GST_MAKE_FOURCC ('h', 'd', 'v', 'a'): /* HDV 720p50 */
12693 case GST_MAKE_FOURCC ('m', 'x', '5', 'n'): /* MPEG2 IMX NTSC 525/60 50mb/s produced by FCP */
12694 case GST_MAKE_FOURCC ('m', 'x', '5', 'p'): /* MPEG2 IMX PAL 625/60 50mb/s produced by FCP */
12695 case GST_MAKE_FOURCC ('m', 'x', '4', 'n'): /* MPEG2 IMX NTSC 525/60 40mb/s produced by FCP */
12696 case GST_MAKE_FOURCC ('m', 'x', '4', 'p'): /* MPEG2 IMX PAL 625/60 40mb/s produced by FCP */
12697 case GST_MAKE_FOURCC ('m', 'x', '3', 'n'): /* MPEG2 IMX NTSC 525/60 30mb/s produced by FCP */
12698 case GST_MAKE_FOURCC ('m', 'x', '3', 'p'): /* MPEG2 IMX PAL 625/50 30mb/s produced by FCP */
12699 case GST_MAKE_FOURCC ('x', 'd', 'v', '1'): /* XDCAM HD 720p30 35Mb/s */
12700 case GST_MAKE_FOURCC ('x', 'd', 'v', '2'): /* XDCAM HD 1080i60 35Mb/s */
12701 case GST_MAKE_FOURCC ('x', 'd', 'v', '3'): /* XDCAM HD 1080i50 35Mb/s */
12702 case GST_MAKE_FOURCC ('x', 'd', 'v', '4'): /* XDCAM HD 720p24 35Mb/s */
12703 case GST_MAKE_FOURCC ('x', 'd', 'v', '5'): /* XDCAM HD 720p25 35Mb/s */
12704 case GST_MAKE_FOURCC ('x', 'd', 'v', '6'): /* XDCAM HD 1080p24 35Mb/s */
12705 case GST_MAKE_FOURCC ('x', 'd', 'v', '7'): /* XDCAM HD 1080p25 35Mb/s */
12706 case GST_MAKE_FOURCC ('x', 'd', 'v', '8'): /* XDCAM HD 1080p30 35Mb/s */
12707 case GST_MAKE_FOURCC ('x', 'd', 'v', '9'): /* XDCAM HD 720p60 35Mb/s */
12708 case GST_MAKE_FOURCC ('x', 'd', 'v', 'a'): /* XDCAM HD 720p50 35Mb/s */
12709 case GST_MAKE_FOURCC ('x', 'd', 'v', 'b'): /* XDCAM EX 1080i60 50Mb/s CBR */
12710 case GST_MAKE_FOURCC ('x', 'd', 'v', 'c'): /* XDCAM EX 1080i50 50Mb/s CBR */
12711 case GST_MAKE_FOURCC ('x', 'd', 'v', 'd'): /* XDCAM HD 1080p24 50Mb/s CBR */
12712 case GST_MAKE_FOURCC ('x', 'd', 'v', 'e'): /* XDCAM HD 1080p25 50Mb/s CBR */
12713 case GST_MAKE_FOURCC ('x', 'd', 'v', 'f'): /* XDCAM HD 1080p30 50Mb/s CBR */
12714 case GST_MAKE_FOURCC ('x', 'd', '5', '1'): /* XDCAM HD422 720p30 50Mb/s CBR */
12715 case GST_MAKE_FOURCC ('x', 'd', '5', '4'): /* XDCAM HD422 720p24 50Mb/s CBR */
12716 case GST_MAKE_FOURCC ('x', 'd', '5', '5'): /* XDCAM HD422 720p25 50Mb/s CBR */
12717 case GST_MAKE_FOURCC ('x', 'd', '5', '9'): /* XDCAM HD422 720p60 50Mb/s CBR */
12718 case GST_MAKE_FOURCC ('x', 'd', '5', 'a'): /* XDCAM HD422 720p50 50Mb/s CBR */
12719 case GST_MAKE_FOURCC ('x', 'd', '5', 'b'): /* XDCAM HD422 1080i50 50Mb/s CBR */
12720 case GST_MAKE_FOURCC ('x', 'd', '5', 'c'): /* XDCAM HD422 1080i50 50Mb/s CBR */
12721 case GST_MAKE_FOURCC ('x', 'd', '5', 'd'): /* XDCAM HD422 1080p24 50Mb/s CBR */
12722 case GST_MAKE_FOURCC ('x', 'd', '5', 'e'): /* XDCAM HD422 1080p25 50Mb/s CBR */
12723 case GST_MAKE_FOURCC ('x', 'd', '5', 'f'): /* XDCAM HD422 1080p30 50Mb/s CBR */
12724 case GST_MAKE_FOURCC ('x', 'd', 'h', 'd'): /* XDCAM HD 540p */
12725 case GST_MAKE_FOURCC ('x', 'd', 'h', '2'): /* XDCAM HD422 540p */
12726 case GST_MAKE_FOURCC ('A', 'V', 'm', 'p'): /* AVID IMX PAL */
12727 case GST_MAKE_FOURCC ('m', 'p', 'g', '2'): /* AVID IMX PAL */
12728 case GST_MAKE_FOURCC ('m', 'p', '2', 'v'): /* AVID IMX PAL */
12729 _codec ("MPEG-2 video");
12730 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 2,
12731 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
12733 case GST_MAKE_FOURCC ('g', 'i', 'f', ' '):
12734 _codec ("GIF still images");
12735 caps = gst_caps_new_empty_simple ("image/gif");
12738 case GST_MAKE_FOURCC ('H', '2', '6', '3'):
12740 case GST_MAKE_FOURCC ('U', '2', '6', '3'):
12742 /* ffmpeg uses the height/width props, don't know why */
12743 caps = gst_caps_new_simple ("video/x-h263",
12744 "variant", G_TYPE_STRING, "itu", NULL);
12748 _codec ("MPEG-4 video");
12749 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
12750 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
12752 case GST_MAKE_FOURCC ('3', 'i', 'v', 'd'):
12753 case GST_MAKE_FOURCC ('3', 'I', 'V', 'D'):
12754 _codec ("Microsoft MPEG-4 4.3"); /* FIXME? */
12755 caps = gst_caps_new_simple ("video/x-msmpeg",
12756 "msmpegversion", G_TYPE_INT, 43, NULL);
12758 case GST_MAKE_FOURCC ('D', 'I', 'V', '3'):
12760 caps = gst_caps_new_simple ("video/x-divx",
12761 "divxversion", G_TYPE_INT, 3, NULL);
12763 case GST_MAKE_FOURCC ('D', 'I', 'V', 'X'):
12764 case GST_MAKE_FOURCC ('d', 'i', 'v', 'x'):
12766 caps = gst_caps_new_simple ("video/x-divx",
12767 "divxversion", G_TYPE_INT, 4, NULL);
12769 case GST_MAKE_FOURCC ('D', 'X', '5', '0'):
12771 caps = gst_caps_new_simple ("video/x-divx",
12772 "divxversion", G_TYPE_INT, 5, NULL);
12775 case GST_MAKE_FOURCC ('F', 'F', 'V', '1'):
12777 caps = gst_caps_new_simple ("video/x-ffv",
12778 "ffvversion", G_TYPE_INT, 1, NULL);
12781 case GST_MAKE_FOURCC ('3', 'I', 'V', '1'):
12782 case GST_MAKE_FOURCC ('3', 'I', 'V', '2'):
12783 case GST_MAKE_FOURCC ('X', 'V', 'I', 'D'):
12784 case GST_MAKE_FOURCC ('x', 'v', 'i', 'd'):
12786 case GST_MAKE_FOURCC ('U', 'M', 'P', '4'):
12787 caps = gst_caps_new_simple ("video/mpeg",
12788 "mpegversion", G_TYPE_INT, 4, NULL);
12792 case GST_MAKE_FOURCC ('c', 'v', 'i', 'd'):
12793 _codec ("Cinepak");
12794 caps = gst_caps_new_empty_simple ("video/x-cinepak");
12796 case GST_MAKE_FOURCC ('q', 'd', 'r', 'w'):
12797 _codec ("Apple QuickDraw");
12798 caps = gst_caps_new_empty_simple ("video/x-qdrw");
12800 case GST_MAKE_FOURCC ('r', 'p', 'z', 'a'):
12801 _codec ("Apple video");
12802 caps = gst_caps_new_empty_simple ("video/x-apple-video");
12806 _codec ("H.264 / AVC");
12807 caps = gst_caps_new_simple ("video/x-h264",
12808 "stream-format", G_TYPE_STRING, "avc",
12809 "alignment", G_TYPE_STRING, "au", NULL);
12812 _codec ("H.264 / AVC");
12813 caps = gst_caps_new_simple ("video/x-h264",
12814 "stream-format", G_TYPE_STRING, "avc3",
12815 "alignment", G_TYPE_STRING, "au", NULL);
12819 _codec ("H.265 / HEVC");
12820 caps = gst_caps_new_simple ("video/x-h265",
12821 "stream-format", G_TYPE_STRING, "hvc1",
12822 "alignment", G_TYPE_STRING, "au", NULL);
12825 _codec ("H.265 / HEVC");
12826 caps = gst_caps_new_simple ("video/x-h265",
12827 "stream-format", G_TYPE_STRING, "hev1",
12828 "alignment", G_TYPE_STRING, "au", NULL);
12831 _codec ("Run-length encoding");
12832 caps = gst_caps_new_simple ("video/x-rle",
12833 "layout", G_TYPE_STRING, "quicktime", NULL);
12836 _codec ("Run-length encoding");
12837 caps = gst_caps_new_simple ("video/x-rle",
12838 "layout", G_TYPE_STRING, "microsoft", NULL);
12840 case GST_MAKE_FOURCC ('I', 'V', '3', '2'):
12841 case GST_MAKE_FOURCC ('i', 'v', '3', '2'):
12842 _codec ("Indeo Video 3");
12843 caps = gst_caps_new_simple ("video/x-indeo",
12844 "indeoversion", G_TYPE_INT, 3, NULL);
12846 case GST_MAKE_FOURCC ('I', 'V', '4', '1'):
12847 case GST_MAKE_FOURCC ('i', 'v', '4', '1'):
12848 _codec ("Intel Video 4");
12849 caps = gst_caps_new_simple ("video/x-indeo",
12850 "indeoversion", G_TYPE_INT, 4, NULL);
12854 case GST_MAKE_FOURCC ('d', 'v', 's', 'd'):
12855 case GST_MAKE_FOURCC ('D', 'V', 'S', 'D'):
12856 case GST_MAKE_FOURCC ('d', 'v', 'c', 's'):
12857 case GST_MAKE_FOURCC ('D', 'V', 'C', 'S'):
12858 case GST_MAKE_FOURCC ('d', 'v', '2', '5'):
12859 case GST_MAKE_FOURCC ('d', 'v', 'p', 'p'):
12860 _codec ("DV Video");
12861 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 25,
12862 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
12864 case FOURCC_dv5n: /* DVCPRO50 NTSC */
12865 case FOURCC_dv5p: /* DVCPRO50 PAL */
12866 _codec ("DVCPro50 Video");
12867 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 50,
12868 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
12870 case GST_MAKE_FOURCC ('d', 'v', 'h', '5'): /* DVCPRO HD 50i produced by FCP */
12871 case GST_MAKE_FOURCC ('d', 'v', 'h', '6'): /* DVCPRO HD 60i produced by FCP */
12872 _codec ("DVCProHD Video");
12873 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 100,
12874 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
12876 case GST_MAKE_FOURCC ('s', 'm', 'c', ' '):
12877 _codec ("Apple Graphics (SMC)");
12878 caps = gst_caps_new_empty_simple ("video/x-smc");
12880 case GST_MAKE_FOURCC ('V', 'P', '3', '1'):
12882 caps = gst_caps_new_empty_simple ("video/x-vp3");
12884 case GST_MAKE_FOURCC ('V', 'P', '6', 'F'):
12885 _codec ("VP6 Flash");
12886 caps = gst_caps_new_empty_simple ("video/x-vp6-flash");
12890 caps = gst_caps_new_empty_simple ("video/x-theora");
12891 /* theora uses one byte of padding in the data stream because it does not
12892 * allow 0 sized packets while theora does */
12893 stream->padding = 1;
12897 caps = gst_caps_new_empty_simple ("video/x-dirac");
12899 case GST_MAKE_FOURCC ('t', 'i', 'f', 'f'):
12900 _codec ("TIFF still images");
12901 caps = gst_caps_new_empty_simple ("image/tiff");
12903 case GST_MAKE_FOURCC ('i', 'c', 'o', 'd'):
12904 _codec ("Apple Intermediate Codec");
12905 caps = gst_caps_from_string ("video/x-apple-intermediate-codec");
12907 case GST_MAKE_FOURCC ('A', 'V', 'd', 'n'):
12908 _codec ("AVID DNxHD");
12909 caps = gst_caps_from_string ("video/x-dnxhd");
12912 _codec ("On2 VP8");
12913 caps = gst_caps_from_string ("video/x-vp8");
12916 _codec ("Apple ProRes LT");
12918 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "lt",
12922 _codec ("Apple ProRes HQ");
12924 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "hq",
12928 _codec ("Apple ProRes");
12930 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
12934 _codec ("Apple ProRes Proxy");
12936 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
12940 _codec ("Apple ProRes 4444");
12942 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
12948 caps = gst_caps_new_simple ("video/x-wmv",
12949 "wmvversion", G_TYPE_INT, 3, "format", G_TYPE_STRING, "WVC1", NULL);
12951 case GST_MAKE_FOURCC ('k', 'p', 'c', 'd'):
12954 char *s, fourstr[5];
12956 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
12957 s = g_strdup_printf ("video/x-gst-fourcc-%s", g_strstrip (fourstr));
12958 caps = gst_caps_new_empty_simple (s);
12964 if (format != GST_VIDEO_FORMAT_UNKNOWN) {
12967 gst_video_info_init (&info);
12968 gst_video_info_set_format (&info, format, stream->width, stream->height);
12970 caps = gst_video_info_to_caps (&info);
12971 *codec_name = gst_pb_utils_get_codec_description (caps);
12973 /* enable clipping for raw video streams */
12974 stream->need_clip = TRUE;
12981 qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
12982 guint32 fourcc, const guint8 * data, int len, gchar ** codec_name)
12985 const GstStructure *s;
12988 GstAudioFormat format = 0;
12991 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
12993 depth = stream->bytes_per_packet * 8;
12996 case GST_MAKE_FOURCC ('N', 'O', 'N', 'E'):
12998 /* 8-bit audio is unsigned */
13000 format = GST_AUDIO_FORMAT_U8;
13001 /* otherwise it's signed and big-endian just like 'twos' */
13003 endian = G_BIG_ENDIAN;
13010 endian = G_LITTLE_ENDIAN;
13013 format = gst_audio_format_build_integer (TRUE, endian, depth, depth);
13015 str = g_strdup_printf ("Raw %d-bit PCM audio", depth);
13019 caps = gst_caps_new_simple ("audio/x-raw",
13020 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
13021 "layout", G_TYPE_STRING, "interleaved", NULL);
13024 case GST_MAKE_FOURCC ('f', 'l', '6', '4'):
13025 _codec ("Raw 64-bit floating-point audio");
13026 caps = gst_caps_new_simple ("audio/x-raw",
13027 "format", G_TYPE_STRING, "F64BE",
13028 "layout", G_TYPE_STRING, "interleaved", NULL);
13030 case GST_MAKE_FOURCC ('f', 'l', '3', '2'):
13031 _codec ("Raw 32-bit floating-point audio");
13032 caps = gst_caps_new_simple ("audio/x-raw",
13033 "format", G_TYPE_STRING, "F32BE",
13034 "layout", G_TYPE_STRING, "interleaved", NULL);
13037 _codec ("Raw 24-bit PCM audio");
13038 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
13040 caps = gst_caps_new_simple ("audio/x-raw",
13041 "format", G_TYPE_STRING, "S24BE",
13042 "layout", G_TYPE_STRING, "interleaved", NULL);
13044 case GST_MAKE_FOURCC ('i', 'n', '3', '2'):
13045 _codec ("Raw 32-bit PCM audio");
13046 caps = gst_caps_new_simple ("audio/x-raw",
13047 "format", G_TYPE_STRING, "S32BE",
13048 "layout", G_TYPE_STRING, "interleaved", NULL);
13051 _codec ("Mu-law audio");
13052 caps = gst_caps_new_empty_simple ("audio/x-mulaw");
13055 _codec ("A-law audio");
13056 caps = gst_caps_new_empty_simple ("audio/x-alaw");
13060 _codec ("Microsoft ADPCM");
13061 /* Microsoft ADPCM-ACM code 2 */
13062 caps = gst_caps_new_simple ("audio/x-adpcm",
13063 "layout", G_TYPE_STRING, "microsoft", NULL);
13067 _codec ("DVI/IMA ADPCM");
13068 caps = gst_caps_new_simple ("audio/x-adpcm",
13069 "layout", G_TYPE_STRING, "dvi", NULL);
13073 _codec ("DVI/Intel IMA ADPCM");
13074 /* FIXME DVI/Intel IMA ADPCM/ACM code 17 */
13075 caps = gst_caps_new_simple ("audio/x-adpcm",
13076 "layout", G_TYPE_STRING, "quicktime", NULL);
13080 /* MPEG layer 3, CBR only (pre QT4.1) */
13082 _codec ("MPEG-1 layer 3");
13083 /* MPEG layer 3, CBR & VBR (QT4.1 and later) */
13084 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 3,
13085 "mpegversion", G_TYPE_INT, 1, NULL);
13088 case GST_MAKE_FOURCC ('e', 'c', '-', '3'):
13089 _codec ("EAC-3 audio");
13090 caps = gst_caps_new_simple ("audio/x-eac3",
13091 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
13092 stream->sampled = TRUE;
13094 case GST_MAKE_FOURCC ('s', 'a', 'c', '3'): // Nero Recode
13096 _codec ("AC-3 audio");
13097 caps = gst_caps_new_simple ("audio/x-ac3",
13098 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
13099 stream->sampled = TRUE;
13101 case GST_MAKE_FOURCC ('d', 't', 's', 'c'):
13102 case GST_MAKE_FOURCC ('D', 'T', 'S', ' '):
13103 _codec ("DTS audio");
13104 caps = gst_caps_new_simple ("audio/x-dts",
13105 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
13106 stream->sampled = TRUE;
13108 case GST_MAKE_FOURCC ('d', 't', 's', 'h'): // DTS-HD
13109 case GST_MAKE_FOURCC ('d', 't', 's', 'l'): // DTS-HD Lossless
13110 _codec ("DTS-HD audio");
13111 caps = gst_caps_new_simple ("audio/x-dts",
13112 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
13113 stream->sampled = TRUE;
13117 caps = gst_caps_new_simple ("audio/x-mace",
13118 "maceversion", G_TYPE_INT, 3, NULL);
13122 caps = gst_caps_new_simple ("audio/x-mace",
13123 "maceversion", G_TYPE_INT, 6, NULL);
13125 case GST_MAKE_FOURCC ('O', 'g', 'g', 'V'):
13127 caps = gst_caps_new_empty_simple ("application/ogg");
13129 case GST_MAKE_FOURCC ('d', 'v', 'c', 'a'):
13130 _codec ("DV audio");
13131 caps = gst_caps_new_empty_simple ("audio/x-dv");
13134 _codec ("MPEG-4 AAC audio");
13135 caps = gst_caps_new_simple ("audio/mpeg",
13136 "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE,
13137 "stream-format", G_TYPE_STRING, "raw", NULL);
13139 case GST_MAKE_FOURCC ('Q', 'D', 'M', 'C'):
13140 _codec ("QDesign Music");
13141 caps = gst_caps_new_empty_simple ("audio/x-qdm");
13144 _codec ("QDesign Music v.2");
13145 /* FIXME: QDesign music version 2 (no constant) */
13146 if (FALSE && data) {
13147 caps = gst_caps_new_simple ("audio/x-qdm2",
13148 "framesize", G_TYPE_INT, QT_UINT32 (data + 52),
13149 "bitrate", G_TYPE_INT, QT_UINT32 (data + 40),
13150 "blocksize", G_TYPE_INT, QT_UINT32 (data + 44), NULL);
13152 caps = gst_caps_new_empty_simple ("audio/x-qdm2");
13156 _codec ("GSM audio");
13157 caps = gst_caps_new_empty_simple ("audio/x-gsm");
13160 _codec ("AMR audio");
13161 caps = gst_caps_new_empty_simple ("audio/AMR");
13164 _codec ("AMR-WB audio");
13165 caps = gst_caps_new_empty_simple ("audio/AMR-WB");
13168 _codec ("Quicktime IMA ADPCM");
13169 caps = gst_caps_new_simple ("audio/x-adpcm",
13170 "layout", G_TYPE_STRING, "quicktime", NULL);
13173 _codec ("Apple lossless audio");
13174 caps = gst_caps_new_empty_simple ("audio/x-alac");
13176 case GST_MAKE_FOURCC ('Q', 'c', 'l', 'p'):
13177 _codec ("QualComm PureVoice");
13178 caps = gst_caps_from_string ("audio/qcelp");
13183 caps = gst_caps_new_empty_simple ("audio/x-wma");
13187 caps = gst_caps_new_empty_simple ("audio/x-opus");
13189 case GST_MAKE_FOURCC ('l', 'p', 'c', 'm'):
13194 GstAudioFormat format;
13197 FLAG_IS_FLOAT = 0x1,
13198 FLAG_IS_BIG_ENDIAN = 0x2,
13199 FLAG_IS_SIGNED = 0x4,
13200 FLAG_IS_PACKED = 0x8,
13201 FLAG_IS_ALIGNED_HIGH = 0x10,
13202 FLAG_IS_NON_INTERLEAVED = 0x20
13204 _codec ("Raw LPCM audio");
13206 if (data && len >= 56) {
13207 depth = QT_UINT32 (data + 40);
13208 flags = QT_UINT32 (data + 44);
13209 width = QT_UINT32 (data + 48) * 8 / stream->n_channels;
13211 if ((flags & FLAG_IS_FLOAT) == 0) {
13216 format = gst_audio_format_build_integer ((flags & FLAG_IS_SIGNED) ?
13217 TRUE : FALSE, (flags & FLAG_IS_BIG_ENDIAN) ?
13218 G_BIG_ENDIAN : G_LITTLE_ENDIAN, width, depth);
13219 caps = gst_caps_new_simple ("audio/x-raw",
13220 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
13221 "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
13222 "non-interleaved" : "interleaved", NULL);
13227 if (flags & FLAG_IS_BIG_ENDIAN)
13228 format = GST_AUDIO_FORMAT_F64BE;
13230 format = GST_AUDIO_FORMAT_F64LE;
13232 if (flags & FLAG_IS_BIG_ENDIAN)
13233 format = GST_AUDIO_FORMAT_F32BE;
13235 format = GST_AUDIO_FORMAT_F32LE;
13237 caps = gst_caps_new_simple ("audio/x-raw",
13238 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
13239 "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
13240 "non-interleaved" : "interleaved", NULL);
13244 case GST_MAKE_FOURCC ('q', 't', 'v', 'r'):
13248 char *s, fourstr[5];
13250 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
13251 s = g_strdup_printf ("audio/x-gst-fourcc-%s", g_strstrip (fourstr));
13252 caps = gst_caps_new_empty_simple (s);
13259 GstCaps *templ_caps =
13260 gst_static_pad_template_get_caps (&gst_qtdemux_audiosrc_template);
13261 GstCaps *intersection = gst_caps_intersect (caps, templ_caps);
13262 gst_caps_unref (caps);
13263 gst_caps_unref (templ_caps);
13264 caps = intersection;
13267 /* enable clipping for raw audio streams */
13268 s = gst_caps_get_structure (caps, 0);
13269 name = gst_structure_get_name (s);
13270 if (g_str_has_prefix (name, "audio/x-raw")) {
13271 stream->need_clip = TRUE;
13272 stream->max_buffer_size = 4096 * stream->bytes_per_frame;
13273 GST_DEBUG ("setting max buffer size to %d", stream->max_buffer_size);
13279 qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
13280 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
13284 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
13288 _codec ("DVD subtitle");
13289 caps = gst_caps_new_empty_simple ("subpicture/x-dvd");
13290 stream->need_process = TRUE;
13293 _codec ("Quicktime timed text");
13296 _codec ("3GPP timed text");
13298 caps = gst_caps_new_simple ("text/x-raw", "format", G_TYPE_STRING,
13300 /* actual text piece needs to be extracted */
13301 stream->need_process = TRUE;
13304 _codec ("XML subtitles");
13305 caps = gst_caps_new_empty_simple ("application/ttml+xml");
13309 char *s, fourstr[5];
13311 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
13312 s = g_strdup_printf ("text/x-gst-fourcc-%s", g_strstrip (fourstr));
13313 caps = gst_caps_new_empty_simple (s);
13322 qtdemux_generic_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
13323 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
13329 _codec ("MPEG 1 video");
13330 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
13331 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13341 gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux,
13342 const gchar * system_id)
13346 if (!qtdemux->protection_system_ids)
13347 qtdemux->protection_system_ids =
13348 g_ptr_array_new_with_free_func ((GDestroyNotify) g_free);
13349 /* Check whether we already have an entry for this system ID. */
13350 for (i = 0; i < qtdemux->protection_system_ids->len; ++i) {
13351 const gchar *id = g_ptr_array_index (qtdemux->protection_system_ids, i);
13352 if (g_ascii_strcasecmp (system_id, id) == 0) {
13356 GST_DEBUG_OBJECT (qtdemux, "Adding cenc protection system ID %s", system_id);
13357 g_ptr_array_add (qtdemux->protection_system_ids, g_ascii_strdown (system_id,