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 _QtDemuxSegment QtDemuxSegment;
101 typedef struct _QtDemuxSample QtDemuxSample;
103 typedef struct _QtDemuxCencSampleSetInfo QtDemuxCencSampleSetInfo;
105 struct _QtDemuxSample
108 gint32 pts_offset; /* Add this value to timestamp to get the pts */
110 guint64 timestamp; /* DTS In mov time */
111 guint32 duration; /* In mov time */
112 gboolean keyframe; /* TRUE when this packet is a keyframe */
115 /* Macros for converting to/from timescale */
116 #define QTSTREAMTIME_TO_GSTTIME(stream, value) (gst_util_uint64_scale((value), GST_SECOND, (stream)->timescale))
117 #define GSTTIME_TO_QTSTREAMTIME(stream, value) (gst_util_uint64_scale((value), (stream)->timescale, GST_SECOND))
119 #define QTTIME_TO_GSTTIME(qtdemux, value) (gst_util_uint64_scale((value), GST_SECOND, (qtdemux)->timescale))
120 #define GSTTIME_TO_QTTIME(qtdemux, value) (gst_util_uint64_scale((value), (qtdemux)->timescale, GST_SECOND))
122 /* timestamp is the DTS */
123 #define QTSAMPLE_DTS(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp))
124 /* timestamp + offset is the PTS */
125 #define QTSAMPLE_PTS(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp + (stream)->cslg_shift + (sample)->pts_offset))
126 /* timestamp + duration - dts is the duration */
127 #define QTSAMPLE_DUR_DTS(stream, sample, dts) (QTSTREAMTIME_TO_GSTTIME ((stream), (sample)->timestamp + (sample)->duration) - (dts))
129 #define QTSAMPLE_KEYFRAME(stream,sample) ((stream)->all_keyframe || (sample)->keyframe)
132 * Quicktime has tracks and segments. A track is a continuous piece of
133 * multimedia content. The track is not always played from start to finish but
134 * instead, pieces of the track are 'cut out' and played in sequence. This is
135 * what the segments do.
137 * Inside the track we have keyframes (K) and delta frames. The track has its
138 * own timing, which starts from 0 and extends to end. The position in the track
139 * is called the media_time.
141 * The segments now describe the pieces that should be played from this track
142 * and are basically tuples of media_time/duration/rate entries. We can have
143 * multiple segments and they are all played after one another. An example:
145 * segment 1: media_time: 1 second, duration: 1 second, rate 1
146 * segment 2: media_time: 3 second, duration: 2 second, rate 2
148 * To correctly play back this track, one must play: 1 second of media starting
149 * from media_time 1 followed by 2 seconds of media starting from media_time 3
152 * Each of the segments will be played at a specific time, the first segment at
153 * time 0, the second one after the duration of the first one, etc.. Note that
154 * the time in resulting playback is not identical to the media_time of the
157 * Visually, assuming the track has 4 second of media_time:
160 * .-----------------------------------------------------------.
161 * track: | K.....K.........K........K.......K.......K...........K... |
162 * '-----------------------------------------------------------'
164 * .------------^ ^ .----------^ ^
165 * / .-------------' / .------------------'
167 * .--------------. .--------------.
168 * | segment 1 | | segment 2 |
169 * '--------------' '--------------'
171 * The challenge here is to cut out the right pieces of the track for each of
172 * the playback segments. This fortunately can easily be done with the SEGMENT
173 * events of GStreamer.
175 * For playback of segment 1, we need to provide the decoder with the keyframe
176 * (a), in the above figure, but we must instruct it only to output the decoded
177 * data between second 1 and 2. We do this with a SEGMENT event for 1 to 2, time
178 * position set to the time of the segment: 0.
180 * We then proceed to push data from keyframe (a) to frame (b). The decoder
181 * decodes but clips all before media_time 1.
183 * After finishing a segment, we push out a new SEGMENT event with the clipping
184 * boundaries of the new data.
186 * This is a good usecase for the GStreamer accumulated SEGMENT events.
189 struct _QtDemuxSegment
191 /* global time and duration, all gst time */
193 GstClockTime stop_time;
194 GstClockTime duration;
195 /* media time of trak, all gst time */
196 GstClockTime media_start;
197 GstClockTime media_stop;
199 /* Media start time in trak timescale units */
200 guint32 trak_media_start;
203 #define QTSEGMENT_IS_EMPTY(s) ((s)->media_start == GST_CLOCK_TIME_NONE)
205 /* Used with fragmented MP4 files (mfra atom) */
210 } QtDemuxRandomAccessEntry;
212 struct _QtDemuxStream
222 gboolean new_caps; /* If TRUE, caps need to be generated (by
223 * calling _configure_stream()) This happens
224 * for MSS and fragmented streams */
226 gboolean new_stream; /* signals that a stream_start is required */
227 gboolean on_keyframe; /* if this stream last pushed buffer was a
228 * keyframe. This is important to identify
229 * where to stop pushing buffers after a
230 * segment stop time */
232 /* if the stream has a redirect URI in its headers, we store it here */
239 guint64 duration; /* in timescale units */
243 gchar lang_id[4]; /* ISO 639-2T language code */
247 QtDemuxSample *samples;
248 gboolean all_keyframe; /* TRUE when all samples are keyframes (no stss) */
249 guint32 first_duration; /* duration in timescale of first sample, used for figuring out
251 guint32 n_samples_moof; /* sample count in a moof */
252 guint64 duration_moof; /* duration in timescale of a moof, used for figure out
253 * the framerate of fragmented format stream */
255 guint32 offset_in_sample; /* Offset in the current sample, used for
256 * streams which have got exceedingly big
257 * sample size (such as 24s of raw audio).
258 * Only used when max_buffer_size is non-NULL */
259 guint32 max_buffer_size; /* Maximum allowed size for output buffers.
260 * Currently only set for raw audio streams*/
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);
533 static void gst_qtdemux_send_gap_for_segment (GstQTDemux * demux,
534 QtDemuxStream * stream, gint segment_index, GstClockTime pos);
536 static gboolean qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux);
537 static void check_update_duration (GstQTDemux * qtdemux, GstClockTime duration);
539 static gchar *qtdemux_uuid_bytes_to_string (gconstpointer uuid_bytes);
541 static GstStructure *qtdemux_get_cenc_sample_properties (GstQTDemux * qtdemux,
542 QtDemuxStream * stream, guint sample_index);
543 static void gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux,
545 static void qtdemux_gst_structure_free (GstStructure * gststructure);
548 gst_qtdemux_class_init (GstQTDemuxClass * klass)
550 GObjectClass *gobject_class;
551 GstElementClass *gstelement_class;
553 gobject_class = (GObjectClass *) klass;
554 gstelement_class = (GstElementClass *) klass;
556 parent_class = g_type_class_peek_parent (klass);
558 gobject_class->dispose = gst_qtdemux_dispose;
560 gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_qtdemux_change_state);
562 gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_qtdemux_set_index);
563 gstelement_class->get_index = GST_DEBUG_FUNCPTR (gst_qtdemux_get_index);
566 gst_tag_register_musicbrainz_tags ();
568 gst_element_class_add_static_pad_template (gstelement_class,
569 &gst_qtdemux_sink_template);
570 gst_element_class_add_static_pad_template (gstelement_class,
571 &gst_qtdemux_videosrc_template);
572 gst_element_class_add_static_pad_template (gstelement_class,
573 &gst_qtdemux_audiosrc_template);
574 gst_element_class_add_static_pad_template (gstelement_class,
575 &gst_qtdemux_subsrc_template);
576 gst_element_class_set_static_metadata (gstelement_class, "QuickTime demuxer",
578 "Demultiplex a QuickTime file into audio and video streams",
579 "David Schleef <ds@schleef.org>, Wim Taymans <wim@fluendo.com>");
581 GST_DEBUG_CATEGORY_INIT (qtdemux_debug, "qtdemux", 0, "qtdemux plugin");
586 gst_qtdemux_init (GstQTDemux * qtdemux)
589 gst_pad_new_from_static_template (&gst_qtdemux_sink_template, "sink");
590 gst_pad_set_activate_function (qtdemux->sinkpad, qtdemux_sink_activate);
591 gst_pad_set_activatemode_function (qtdemux->sinkpad,
592 qtdemux_sink_activate_mode);
593 gst_pad_set_chain_function (qtdemux->sinkpad, gst_qtdemux_chain);
594 gst_pad_set_event_function (qtdemux->sinkpad, gst_qtdemux_handle_sink_event);
595 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), qtdemux->sinkpad);
597 qtdemux->state = QTDEMUX_STATE_INITIAL;
598 qtdemux->pullbased = FALSE;
599 qtdemux->posted_redirect = FALSE;
600 qtdemux->neededbytes = 16;
602 qtdemux->adapter = gst_adapter_new ();
604 qtdemux->first_mdat = -1;
605 qtdemux->got_moov = FALSE;
606 qtdemux->mdatoffset = -1;
607 qtdemux->mdatbuffer = NULL;
608 qtdemux->restoredata_buffer = NULL;
609 qtdemux->restoredata_offset = -1;
610 qtdemux->fragment_start = -1;
611 qtdemux->fragment_start_offset = -1;
612 qtdemux->media_caps = NULL;
613 qtdemux->exposed = FALSE;
614 qtdemux->mss_mode = FALSE;
615 qtdemux->pending_newsegment = NULL;
616 qtdemux->upstream_format_is_time = FALSE;
617 qtdemux->have_group_id = FALSE;
618 qtdemux->group_id = G_MAXUINT;
619 qtdemux->cenc_aux_info_offset = 0;
620 qtdemux->cenc_aux_info_sizes = NULL;
621 qtdemux->cenc_aux_sample_count = 0;
622 qtdemux->protection_system_ids = NULL;
623 g_queue_init (&qtdemux->protection_event_queue);
624 gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
625 qtdemux->flowcombiner = gst_flow_combiner_new ();
627 GST_OBJECT_FLAG_SET (qtdemux, GST_ELEMENT_FLAG_INDEXABLE);
631 gst_qtdemux_dispose (GObject * object)
633 GstQTDemux *qtdemux = GST_QTDEMUX (object);
635 if (qtdemux->adapter) {
636 g_object_unref (G_OBJECT (qtdemux->adapter));
637 qtdemux->adapter = NULL;
639 gst_flow_combiner_free (qtdemux->flowcombiner);
640 g_queue_foreach (&qtdemux->protection_event_queue, (GFunc) gst_event_unref,
642 g_queue_clear (&qtdemux->protection_event_queue);
644 g_free (qtdemux->cenc_aux_info_sizes);
645 qtdemux->cenc_aux_info_sizes = NULL;
647 G_OBJECT_CLASS (parent_class)->dispose (object);
651 gst_qtdemux_post_no_playable_stream_error (GstQTDemux * qtdemux)
653 if (qtdemux->posted_redirect) {
654 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
655 (_("This file contains no playable streams.")),
656 ("no known streams found, a redirect message has been posted"));
658 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
659 (_("This file contains no playable streams.")),
660 ("no known streams found"));
665 _gst_buffer_new_wrapped (gpointer mem, gsize size, GFreeFunc free_func)
667 return gst_buffer_new_wrapped_full (free_func ? 0 : GST_MEMORY_FLAG_READONLY,
668 mem, size, 0, size, mem, free_func);
672 gst_qtdemux_pull_atom (GstQTDemux * qtdemux, guint64 offset, guint64 size,
679 if (G_UNLIKELY (size == 0)) {
681 GstBuffer *tmp = NULL;
683 ret = gst_qtdemux_pull_atom (qtdemux, offset, sizeof (guint32), &tmp);
684 if (ret != GST_FLOW_OK)
687 gst_buffer_map (tmp, &map, GST_MAP_READ);
688 size = QT_UINT32 (map.data);
689 GST_DEBUG_OBJECT (qtdemux, "size 0x%08" G_GINT64_MODIFIER "x", size);
691 gst_buffer_unmap (tmp, &map);
692 gst_buffer_unref (tmp);
695 /* Sanity check: catch bogus sizes (fuzzed/broken files) */
696 if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
697 if (qtdemux->state != QTDEMUX_STATE_MOVIE && qtdemux->got_moov) {
698 /* we're pulling header but already got most interesting bits,
699 * so never mind the rest (e.g. tags) (that much) */
700 GST_WARNING_OBJECT (qtdemux, "atom has bogus size %" G_GUINT64_FORMAT,
704 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
705 (_("This file is invalid and cannot be played.")),
706 ("atom has bogus size %" G_GUINT64_FORMAT, size));
707 return GST_FLOW_ERROR;
711 flow = gst_pad_pull_range (qtdemux->sinkpad, offset, size, buf);
713 if (G_UNLIKELY (flow != GST_FLOW_OK))
716 bsize = gst_buffer_get_size (*buf);
717 /* Catch short reads - we don't want any partial atoms */
718 if (G_UNLIKELY (bsize < size)) {
719 GST_WARNING_OBJECT (qtdemux,
720 "short read: %" G_GSIZE_FORMAT " < %" G_GUINT64_FORMAT, bsize, size);
721 gst_buffer_unref (*buf);
731 gst_qtdemux_src_convert (GstQTDemux * qtdemux, GstPad * pad,
732 GstFormat src_format, gint64 src_value, GstFormat dest_format,
736 QtDemuxStream *stream = gst_pad_get_element_private (pad);
739 if (stream->subtype != FOURCC_vide) {
744 switch (src_format) {
745 case GST_FORMAT_TIME:
746 switch (dest_format) {
747 case GST_FORMAT_BYTES:{
748 index = gst_qtdemux_find_index_linear (qtdemux, stream, src_value);
754 *dest_value = stream->samples[index].offset;
756 GST_DEBUG_OBJECT (qtdemux, "Format Conversion Time->Offset :%"
757 GST_TIME_FORMAT "->%" G_GUINT64_FORMAT,
758 GST_TIME_ARGS (src_value), *dest_value);
766 case GST_FORMAT_BYTES:
767 switch (dest_format) {
768 case GST_FORMAT_TIME:{
770 gst_qtdemux_find_index_for_given_media_offset_linear (qtdemux,
779 QTSTREAMTIME_TO_GSTTIME (stream,
780 stream->samples[index].timestamp);
781 GST_DEBUG_OBJECT (qtdemux,
782 "Format Conversion Offset->Time :%" G_GUINT64_FORMAT "->%"
783 GST_TIME_FORMAT, src_value, GST_TIME_ARGS (*dest_value));
802 gst_qtdemux_get_duration (GstQTDemux * qtdemux, GstClockTime * duration)
804 gboolean res = FALSE;
806 *duration = GST_CLOCK_TIME_NONE;
808 if (qtdemux->duration != 0 &&
809 qtdemux->duration != G_MAXINT64 && qtdemux->timescale != 0) {
810 *duration = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
813 *duration = GST_CLOCK_TIME_NONE;
820 gst_qtdemux_handle_src_query (GstPad * pad, GstObject * parent,
823 gboolean res = FALSE;
824 GstQTDemux *qtdemux = GST_QTDEMUX (parent);
826 GST_LOG_OBJECT (pad, "%s query", GST_QUERY_TYPE_NAME (query));
828 switch (GST_QUERY_TYPE (query)) {
829 case GST_QUERY_POSITION:{
832 gst_query_parse_position (query, &fmt, NULL);
833 if (fmt == GST_FORMAT_TIME
834 && GST_CLOCK_TIME_IS_VALID (qtdemux->segment.position)) {
835 gst_query_set_position (query, GST_FORMAT_TIME,
836 qtdemux->segment.position);
841 case GST_QUERY_DURATION:{
844 gst_query_parse_duration (query, &fmt, NULL);
845 if (fmt == GST_FORMAT_TIME) {
846 /* First try to query upstream */
847 res = gst_pad_query_default (pad, parent, query);
849 GstClockTime duration;
850 if (gst_qtdemux_get_duration (qtdemux, &duration) && duration > 0) {
851 gst_query_set_duration (query, GST_FORMAT_TIME, duration);
858 case GST_QUERY_CONVERT:{
859 GstFormat src_fmt, dest_fmt;
860 gint64 src_value, dest_value = 0;
862 gst_query_parse_convert (query, &src_fmt, &src_value, &dest_fmt, NULL);
864 res = gst_qtdemux_src_convert (qtdemux, pad,
865 src_fmt, src_value, dest_fmt, &dest_value);
867 gst_query_set_convert (query, src_fmt, src_value, dest_fmt, dest_value);
872 case GST_QUERY_FORMATS:
873 gst_query_set_formats (query, 2, GST_FORMAT_TIME, GST_FORMAT_BYTES);
876 case GST_QUERY_SEEKING:{
880 /* try upstream first */
881 res = gst_pad_query_default (pad, parent, query);
884 gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
885 if (fmt == GST_FORMAT_TIME) {
886 GstClockTime duration;
888 gst_qtdemux_get_duration (qtdemux, &duration);
890 if (!qtdemux->pullbased) {
893 /* we might be able with help from upstream */
895 q = gst_query_new_seeking (GST_FORMAT_BYTES);
896 if (gst_pad_peer_query (qtdemux->sinkpad, q)) {
897 gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL);
898 GST_LOG_OBJECT (qtdemux, "upstream BYTE seekable %d", seekable);
902 gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0, duration);
908 case GST_QUERY_SEGMENT:
913 format = qtdemux->segment.format;
916 gst_segment_to_stream_time (&qtdemux->segment, format,
917 qtdemux->segment.start);
918 if ((stop = qtdemux->segment.stop) == -1)
919 stop = qtdemux->segment.duration;
921 stop = gst_segment_to_stream_time (&qtdemux->segment, format, stop);
923 gst_query_set_segment (query, qtdemux->segment.rate, format, start, stop);
928 res = gst_pad_query_default (pad, parent, query);
936 gst_qtdemux_push_tags (GstQTDemux * qtdemux, QtDemuxStream * stream)
938 if (G_LIKELY (stream->pad)) {
939 GST_DEBUG_OBJECT (qtdemux, "Checking pad %s:%s for tags",
940 GST_DEBUG_PAD_NAME (stream->pad));
942 if (G_UNLIKELY (stream->pending_tags)) {
943 GST_DEBUG_OBJECT (qtdemux, "Sending tags %" GST_PTR_FORMAT,
944 stream->pending_tags);
945 gst_pad_push_event (stream->pad,
946 gst_event_new_tag (stream->pending_tags));
947 stream->pending_tags = NULL;
950 if (G_UNLIKELY (stream->send_global_tags && qtdemux->tag_list)) {
951 GST_DEBUG_OBJECT (qtdemux, "Sending global tags %" GST_PTR_FORMAT,
953 gst_pad_push_event (stream->pad,
954 gst_event_new_tag (gst_tag_list_ref (qtdemux->tag_list)));
955 stream->send_global_tags = FALSE;
960 /* push event on all source pads; takes ownership of the event */
962 gst_qtdemux_push_event (GstQTDemux * qtdemux, GstEvent * event)
965 gboolean has_valid_stream = FALSE;
966 GstEventType etype = GST_EVENT_TYPE (event);
968 GST_DEBUG_OBJECT (qtdemux, "pushing %s event on all source pads",
969 GST_EVENT_TYPE_NAME (event));
971 for (n = 0; n < qtdemux->n_streams; n++) {
973 QtDemuxStream *stream = qtdemux->streams[n];
974 GST_DEBUG_OBJECT (qtdemux, "pushing on pad %i", n);
976 if ((pad = stream->pad)) {
977 has_valid_stream = TRUE;
979 if (etype == GST_EVENT_EOS) {
980 /* let's not send twice */
981 if (stream->sent_eos)
983 stream->sent_eos = TRUE;
986 gst_pad_push_event (pad, gst_event_ref (event));
990 gst_event_unref (event);
992 /* if it is EOS and there are no pads, post an error */
993 if (!has_valid_stream && etype == GST_EVENT_EOS) {
994 gst_qtdemux_post_no_playable_stream_error (qtdemux);
998 /* push a pending newsegment event, if any from the streaming thread */
1000 gst_qtdemux_push_pending_newsegment (GstQTDemux * qtdemux)
1002 if (qtdemux->pending_newsegment) {
1003 gst_qtdemux_push_event (qtdemux, qtdemux->pending_newsegment);
1004 qtdemux->pending_newsegment = NULL;
1014 find_func (QtDemuxSample * s1, gint64 * media_time, gpointer user_data)
1016 if ((gint64) s1->timestamp + s1->pts_offset > *media_time)
1018 if ((gint64) s1->timestamp + s1->pts_offset == *media_time)
1024 /* find the index of the sample that includes the data for @media_time using a
1025 * binary search. Only to be called in optimized cases of linear search below.
1027 * Returns the index of the sample.
1030 gst_qtdemux_find_index (GstQTDemux * qtdemux, QtDemuxStream * str,
1033 QtDemuxSample *result;
1036 /* convert media_time to mov format */
1038 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
1040 result = gst_util_array_binary_search (str->samples, str->stbl_index + 1,
1041 sizeof (QtDemuxSample), (GCompareDataFunc) find_func,
1042 GST_SEARCH_MODE_BEFORE, &media_time, NULL);
1044 if (G_LIKELY (result))
1045 index = result - str->samples;
1054 /* find the index of the sample that includes the data for @media_offset using a
1057 * Returns the index of the sample.
1060 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
1061 QtDemuxStream * str, gint64 media_offset)
1063 QtDemuxSample *result = str->samples;
1066 if (result == NULL || str->n_samples == 0)
1069 if (media_offset == result->offset)
1073 while (index < str->n_samples - 1) {
1074 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
1077 if (media_offset < result->offset)
1088 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
1093 /* find the index of the sample that includes the data for @media_time using a
1094 * linear search, and keeping in mind that not all samples may have been parsed
1095 * yet. If possible, it will delegate to binary search.
1097 * Returns the index of the sample.
1100 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
1101 GstClockTime media_time)
1105 QtDemuxSample *sample;
1107 /* convert media_time to mov format */
1109 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
1111 sample = str->samples;
1112 if (mov_time == sample->timestamp + sample->pts_offset)
1115 /* use faster search if requested time in already parsed range */
1116 sample = str->samples + str->stbl_index;
1117 if (str->stbl_index >= 0 &&
1118 mov_time <= (sample->timestamp + sample->pts_offset))
1119 return gst_qtdemux_find_index (qtdemux, str, media_time);
1121 while (index < str->n_samples - 1) {
1122 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
1125 sample = str->samples + index + 1;
1126 if (mov_time < (sample->timestamp + sample->pts_offset))
1136 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
1141 /* find the index of the keyframe needed to decode the sample at @index
1144 * Returns the index of the keyframe.
1147 gst_qtdemux_find_keyframe (GstQTDemux * qtdemux, QtDemuxStream * str,
1150 guint32 new_index = index;
1152 if (index >= str->n_samples) {
1153 new_index = str->n_samples;
1157 /* all keyframes, return index */
1158 if (str->all_keyframe) {
1163 /* else go back until we have a keyframe */
1165 if (str->samples[new_index].keyframe)
1175 GST_DEBUG_OBJECT (qtdemux, "searching for keyframe index before index %u "
1176 "gave %u", index, new_index);
1181 /* find the segment for @time_position for @stream
1183 * Returns the index of the segment containing @time_position.
1184 * Returns the last segment and sets the @eos variable to TRUE
1185 * if the time is beyond the end. @eos may be NULL
1188 gst_qtdemux_find_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
1189 GstClockTime time_position)
1194 GST_LOG_OBJECT (stream->pad, "finding segment for %" GST_TIME_FORMAT,
1195 GST_TIME_ARGS (time_position));
1198 for (i = 0; i < stream->n_segments; i++) {
1199 QtDemuxSegment *segment = &stream->segments[i];
1201 GST_LOG_OBJECT (stream->pad,
1202 "looking at segment %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT,
1203 GST_TIME_ARGS (segment->time), GST_TIME_ARGS (segment->stop_time));
1205 /* For the last segment we include stop_time in the last segment */
1206 if (i < stream->n_segments - 1) {
1207 if (segment->time <= time_position && time_position < segment->stop_time) {
1208 GST_LOG_OBJECT (stream->pad, "segment %d matches", i);
1213 /* Last segment always matches */
1221 /* move the stream @str to the sample position @index.
1223 * Updates @str->sample_index and marks discontinuity if needed.
1226 gst_qtdemux_move_stream (GstQTDemux * qtdemux, QtDemuxStream * str,
1229 /* no change needed */
1230 if (index == str->sample_index)
1233 GST_DEBUG_OBJECT (qtdemux, "moving to sample %u of %u", index,
1236 /* position changed, we have a discont */
1237 str->sample_index = index;
1238 str->offset_in_sample = 0;
1239 /* Each time we move in the stream we store the position where we are
1241 str->from_sample = index;
1242 str->discont = TRUE;
1246 gst_qtdemux_adjust_seek (GstQTDemux * qtdemux, gint64 desired_time,
1247 gboolean use_sparse, gint64 * key_time, gint64 * key_offset)
1250 gint64 min_byte_offset = -1;
1253 min_offset = desired_time;
1255 /* for each stream, find the index of the sample in the segment
1256 * and move back to the previous keyframe. */
1257 for (n = 0; n < qtdemux->n_streams; n++) {
1259 guint32 index, kindex;
1261 GstClockTime media_start;
1262 GstClockTime media_time;
1263 GstClockTime seg_time;
1264 QtDemuxSegment *seg;
1265 gboolean empty_segment = FALSE;
1267 str = qtdemux->streams[n];
1269 if (str->sparse && !use_sparse)
1272 seg_idx = gst_qtdemux_find_segment (qtdemux, str, desired_time);
1273 GST_DEBUG_OBJECT (qtdemux, "align segment %d", seg_idx);
1275 /* get segment and time in the segment */
1276 seg = &str->segments[seg_idx];
1277 seg_time = (desired_time - seg->time) * seg->rate;
1279 while (QTSEGMENT_IS_EMPTY (seg)) {
1281 empty_segment = TRUE;
1282 GST_DEBUG_OBJECT (str->pad, "Segment %d is empty, moving to next one",
1285 if (seg_idx == str->n_segments)
1287 seg = &str->segments[seg_idx];
1290 if (seg_idx == str->n_segments) {
1291 /* FIXME track shouldn't have the last segment as empty, but if it
1292 * happens we better handle it */
1296 /* get the media time in the segment */
1297 media_start = seg->media_start + seg_time;
1299 /* get the index of the sample with media time */
1300 index = gst_qtdemux_find_index_linear (qtdemux, str, media_start);
1301 GST_DEBUG_OBJECT (qtdemux, "sample for %" GST_TIME_FORMAT " at %u"
1302 " at offset %" G_GUINT64_FORMAT " (empty segment: %d)",
1303 GST_TIME_ARGS (media_start), index, str->samples[index].offset,
1306 if (!empty_segment) {
1307 /* find previous keyframe */
1308 kindex = gst_qtdemux_find_keyframe (qtdemux, str, index);
1310 /* if the keyframe is at a different position, we need to update the
1311 * requested seek time */
1312 if (index != kindex) {
1315 /* get timestamp of keyframe */
1316 media_time = QTSAMPLE_DTS (str, &str->samples[kindex]);
1317 GST_DEBUG_OBJECT (qtdemux,
1318 "keyframe at %u with time %" GST_TIME_FORMAT " at offset %"
1319 G_GUINT64_FORMAT, kindex, GST_TIME_ARGS (media_time),
1320 str->samples[kindex].offset);
1322 /* keyframes in the segment get a chance to change the
1323 * desired_offset. keyframes out of the segment are
1325 if (media_time >= seg->media_start) {
1326 GstClockTime seg_time;
1328 /* this keyframe is inside the segment, convert back to
1330 seg_time = (media_time - seg->media_start) + seg->time;
1331 if (seg_time < min_offset)
1332 min_offset = seg_time;
1337 if (min_byte_offset < 0 || str->samples[index].offset < min_byte_offset)
1338 min_byte_offset = str->samples[index].offset;
1342 *key_time = min_offset;
1344 *key_offset = min_byte_offset;
1348 gst_qtdemux_convert_seek (GstPad * pad, GstFormat * format,
1349 GstSeekType cur_type, gint64 * cur, GstSeekType stop_type, gint64 * stop)
1353 g_return_val_if_fail (format != NULL, FALSE);
1354 g_return_val_if_fail (cur != NULL, FALSE);
1355 g_return_val_if_fail (stop != NULL, FALSE);
1357 if (*format == GST_FORMAT_TIME)
1361 if (cur_type != GST_SEEK_TYPE_NONE)
1362 res = gst_pad_query_convert (pad, *format, *cur, GST_FORMAT_TIME, cur);
1363 if (res && stop_type != GST_SEEK_TYPE_NONE)
1364 res = gst_pad_query_convert (pad, *format, *stop, GST_FORMAT_TIME, stop);
1367 *format = GST_FORMAT_TIME;
1372 /* perform seek in push based mode:
1373 find BYTE position to move to based on time and delegate to upstream
1376 gst_qtdemux_do_push_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1381 GstSeekType cur_type, stop_type;
1382 gint64 cur, stop, key_cur;
1385 gint64 original_stop;
1388 GST_DEBUG_OBJECT (qtdemux, "doing push-based seek");
1390 gst_event_parse_seek (event, &rate, &format, &flags,
1391 &cur_type, &cur, &stop_type, &stop);
1392 seqnum = gst_event_get_seqnum (event);
1394 /* only forward streaming and seeking is possible */
1396 goto unsupported_seek;
1398 /* convert to TIME if needed and possible */
1399 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1403 /* Upstream seek in bytes will have undefined stop, but qtdemux stores
1404 * the original stop position to use when upstream pushes the new segment
1406 original_stop = stop;
1409 /* find reasonable corresponding BYTE position,
1410 * also try to mind about keyframes, since we can not go back a bit for them
1412 gst_qtdemux_adjust_seek (qtdemux, cur, FALSE, &key_cur, &byte_cur);
1417 GST_DEBUG_OBJECT (qtdemux, "Pushing BYTE seek rate %g, "
1418 "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, byte_cur,
1421 GST_OBJECT_LOCK (qtdemux);
1422 qtdemux->seek_offset = byte_cur;
1423 if (!(flags & GST_SEEK_FLAG_KEY_UNIT)) {
1424 qtdemux->push_seek_start = cur;
1426 qtdemux->push_seek_start = key_cur;
1429 if (stop_type == GST_SEEK_TYPE_NONE) {
1430 qtdemux->push_seek_stop = qtdemux->segment.stop;
1432 qtdemux->push_seek_stop = original_stop;
1434 GST_OBJECT_UNLOCK (qtdemux);
1436 /* BYTE seek event */
1437 event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type, byte_cur,
1439 gst_event_set_seqnum (event, seqnum);
1440 res = gst_pad_push_event (qtdemux->sinkpad, event);
1447 GST_DEBUG_OBJECT (qtdemux, "could not determine byte position to seek to, "
1453 GST_DEBUG_OBJECT (qtdemux, "unsupported seek, seek aborted.");
1458 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1463 /* perform the seek.
1465 * We set all segment_indexes in the streams to unknown and
1466 * adjust the time_position to the desired position. this is enough
1467 * to trigger a segment switch in the streaming thread to start
1468 * streaming from the desired position.
1470 * Keyframe seeking is a little more complicated when dealing with
1471 * segments. Ideally we want to move to the previous keyframe in
1472 * the segment but there might not be a keyframe in the segment. In
1473 * fact, none of the segments could contain a keyframe. We take a
1474 * practical approach: seek to the previous keyframe in the segment,
1475 * if there is none, seek to the beginning of the segment.
1477 * Called with STREAM_LOCK
1480 gst_qtdemux_perform_seek (GstQTDemux * qtdemux, GstSegment * segment,
1481 guint32 seqnum, GstSeekFlags flags)
1483 gint64 desired_offset;
1486 desired_offset = segment->position;
1488 GST_DEBUG_OBJECT (qtdemux, "seeking to %" GST_TIME_FORMAT,
1489 GST_TIME_ARGS (desired_offset));
1491 /* may not have enough fragmented info to do this adjustment,
1492 * and we can't scan (and probably should not) at this time with
1493 * possibly flushing upstream */
1494 if ((flags & GST_SEEK_FLAG_KEY_UNIT) && !qtdemux->fragmented) {
1497 gst_qtdemux_adjust_seek (qtdemux, desired_offset, TRUE, &min_offset, NULL);
1498 GST_DEBUG_OBJECT (qtdemux, "keyframe seek, align to %"
1499 GST_TIME_FORMAT, GST_TIME_ARGS (min_offset));
1500 desired_offset = min_offset;
1503 /* and set all streams to the final position */
1504 gst_flow_combiner_reset (qtdemux->flowcombiner);
1505 qtdemux->segment_seqnum = seqnum;
1506 for (n = 0; n < qtdemux->n_streams; n++) {
1507 QtDemuxStream *stream = qtdemux->streams[n];
1509 stream->time_position = desired_offset;
1510 stream->accumulated_base = 0;
1511 stream->sample_index = -1;
1512 stream->offset_in_sample = 0;
1513 stream->segment_index = -1;
1514 stream->sent_eos = FALSE;
1516 if (segment->flags & GST_SEEK_FLAG_FLUSH)
1517 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
1519 segment->position = desired_offset;
1520 segment->time = desired_offset;
1521 if (segment->rate >= 0) {
1522 segment->start = desired_offset;
1524 /* we stop at the end */
1525 if (segment->stop == -1)
1526 segment->stop = segment->duration;
1528 segment->stop = desired_offset;
1531 if (qtdemux->fragmented)
1532 qtdemux->fragmented_seek_pending = TRUE;
1537 /* do a seek in pull based mode */
1539 gst_qtdemux_do_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1544 GstSeekType cur_type, stop_type;
1548 GstSegment seeksegment;
1550 GstEvent *flush_event;
1553 GST_DEBUG_OBJECT (qtdemux, "doing seek with event");
1555 gst_event_parse_seek (event, &rate, &format, &flags,
1556 &cur_type, &cur, &stop_type, &stop);
1557 seqnum = gst_event_get_seqnum (event);
1559 /* we have to have a format as the segment format. Try to convert
1561 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1565 GST_DEBUG_OBJECT (qtdemux, "seek format %s", gst_format_get_name (format));
1567 GST_DEBUG_OBJECT (qtdemux, "doing seek without event");
1571 flush = flags & GST_SEEK_FLAG_FLUSH;
1573 /* stop streaming, either by flushing or by pausing the task */
1575 flush_event = gst_event_new_flush_start ();
1577 gst_event_set_seqnum (flush_event, seqnum);
1578 /* unlock upstream pull_range */
1579 gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event));
1580 /* make sure out loop function exits */
1581 gst_qtdemux_push_event (qtdemux, flush_event);
1583 /* non flushing seek, pause the task */
1584 gst_pad_pause_task (qtdemux->sinkpad);
1587 /* wait for streaming to finish */
1588 GST_PAD_STREAM_LOCK (qtdemux->sinkpad);
1590 /* copy segment, we need this because we still need the old
1591 * segment when we close the current segment. */
1592 memcpy (&seeksegment, &qtdemux->segment, sizeof (GstSegment));
1595 /* configure the segment with the seek variables */
1596 GST_DEBUG_OBJECT (qtdemux, "configuring seek");
1597 gst_segment_do_seek (&seeksegment, rate, format, flags,
1598 cur_type, cur, stop_type, stop, &update);
1601 /* now do the seek, this actually never returns FALSE */
1602 gst_qtdemux_perform_seek (qtdemux, &seeksegment, seqnum, flags);
1604 /* prepare for streaming again */
1606 flush_event = gst_event_new_flush_stop (TRUE);
1608 gst_event_set_seqnum (flush_event, seqnum);
1610 gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event));
1611 gst_qtdemux_push_event (qtdemux, flush_event);
1614 /* commit the new segment */
1615 memcpy (&qtdemux->segment, &seeksegment, sizeof (GstSegment));
1617 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
1618 GstMessage *msg = gst_message_new_segment_start (GST_OBJECT_CAST (qtdemux),
1619 qtdemux->segment.format, qtdemux->segment.position);
1621 gst_message_set_seqnum (msg, seqnum);
1622 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
1625 /* restart streaming, NEWSEGMENT will be sent from the streaming thread. */
1626 gst_pad_start_task (qtdemux->sinkpad, (GstTaskFunction) gst_qtdemux_loop,
1627 qtdemux->sinkpad, NULL);
1629 GST_PAD_STREAM_UNLOCK (qtdemux->sinkpad);
1636 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1642 qtdemux_ensure_index (GstQTDemux * qtdemux)
1646 GST_DEBUG_OBJECT (qtdemux, "collecting all metadata for all streams");
1648 /* Build complete index */
1649 for (i = 0; i < qtdemux->n_streams; i++) {
1650 QtDemuxStream *stream = qtdemux->streams[i];
1652 if (!qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1))
1660 GST_LOG_OBJECT (qtdemux,
1661 "Building complete index of stream %u for seeking failed!", i);
1667 gst_qtdemux_handle_src_event (GstPad * pad, GstObject * parent,
1670 gboolean res = TRUE;
1671 GstQTDemux *qtdemux = GST_QTDEMUX (parent);
1673 switch (GST_EVENT_TYPE (event)) {
1674 case GST_EVENT_SEEK:
1676 #ifndef GST_DISABLE_GST_DEBUG
1677 GstClockTime ts = gst_util_get_timestamp ();
1680 if (qtdemux->upstream_format_is_time && qtdemux->fragmented) {
1681 /* seek should be handled by upstream, we might need to re-download fragments */
1682 GST_DEBUG_OBJECT (qtdemux,
1683 "let upstream handle seek for fragmented playback");
1687 /* Build complete index for seeking;
1688 * if not a fragmented file at least */
1689 if (!qtdemux->fragmented)
1690 if (!qtdemux_ensure_index (qtdemux))
1692 #ifndef GST_DISABLE_GST_DEBUG
1693 ts = gst_util_get_timestamp () - ts;
1694 GST_INFO_OBJECT (qtdemux,
1695 "Time taken to parse index %" GST_TIME_FORMAT, GST_TIME_ARGS (ts));
1698 if (qtdemux->pullbased) {
1699 res = gst_qtdemux_do_seek (qtdemux, pad, event);
1700 } else if (gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (event))) {
1701 GST_DEBUG_OBJECT (qtdemux, "Upstream successfully seeked");
1703 } else if (qtdemux->state == QTDEMUX_STATE_MOVIE && qtdemux->n_streams
1704 && !qtdemux->fragmented) {
1705 res = gst_qtdemux_do_push_seek (qtdemux, pad, event);
1707 GST_DEBUG_OBJECT (qtdemux,
1708 "ignoring seek in push mode in current state");
1711 gst_event_unref (event);
1714 case GST_EVENT_NAVIGATION:
1716 gst_event_unref (event);
1720 res = gst_pad_event_default (pad, parent, event);
1730 GST_ERROR_OBJECT (qtdemux, "Index failed");
1731 gst_event_unref (event);
1737 /* stream/index return sample that is min/max w.r.t. byte position,
1738 * time is min/max w.r.t. time of samples,
1739 * the latter need not be time of the former sample */
1741 gst_qtdemux_find_sample (GstQTDemux * qtdemux, gint64 byte_pos, gboolean fw,
1742 gboolean set, QtDemuxStream ** _stream, gint * _index, gint64 * _time)
1745 gint64 time, min_time;
1746 QtDemuxStream *stream;
1752 for (n = 0; n < qtdemux->n_streams; ++n) {
1755 gboolean set_sample;
1757 str = qtdemux->streams[n];
1764 i = str->n_samples - 1;
1768 for (; (i >= 0) && (i < str->n_samples); i += inc) {
1769 if (str->samples[i].size == 0)
1772 if (fw && (str->samples[i].offset < byte_pos))
1775 if (!fw && (str->samples[i].offset + str->samples[i].size > byte_pos))
1778 /* move stream to first available sample */
1780 gst_qtdemux_move_stream (qtdemux, str, i);
1784 /* avoid index from sparse streams since they might be far away */
1786 /* determine min/max time */
1787 time = QTSAMPLE_PTS (str, &str->samples[i]);
1788 if (min_time == -1 || (!fw && time > min_time) ||
1789 (fw && time < min_time)) {
1793 /* determine stream with leading sample, to get its position */
1795 (fw && (str->samples[i].offset < stream->samples[index].offset)) ||
1796 (!fw && (str->samples[i].offset > stream->samples[index].offset))) {
1804 /* no sample for this stream, mark eos */
1806 gst_qtdemux_move_stream (qtdemux, str, str->n_samples);
1817 static QtDemuxStream *
1818 _create_stream (void)
1820 QtDemuxStream *stream;
1822 stream = g_new0 (QtDemuxStream, 1);
1823 /* new streams always need a discont */
1824 stream->discont = TRUE;
1825 /* we enable clipping for raw audio/video streams */
1826 stream->need_clip = FALSE;
1827 stream->need_process = FALSE;
1828 stream->segment_index = -1;
1829 stream->time_position = 0;
1830 stream->sample_index = -1;
1831 stream->offset_in_sample = 0;
1832 stream->new_stream = TRUE;
1833 stream->multiview_mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
1834 stream->multiview_flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
1835 stream->protected = FALSE;
1836 stream->protection_scheme_type = 0;
1837 stream->protection_scheme_version = 0;
1838 stream->protection_scheme_info = NULL;
1839 stream->n_samples_moof = 0;
1840 stream->duration_moof = 0;
1841 g_queue_init (&stream->protection_scheme_event_queue);
1846 gst_qtdemux_setcaps (GstQTDemux * demux, GstCaps * caps)
1848 GstStructure *structure;
1849 const gchar *variant;
1850 const GstCaps *mediacaps = NULL;
1852 GST_DEBUG_OBJECT (demux, "Sink set caps: %" GST_PTR_FORMAT, caps);
1854 structure = gst_caps_get_structure (caps, 0);
1855 variant = gst_structure_get_string (structure, "variant");
1857 if (variant && strcmp (variant, "mss-fragmented") == 0) {
1858 QtDemuxStream *stream;
1859 const GValue *value;
1861 demux->fragmented = TRUE;
1862 demux->mss_mode = TRUE;
1864 if (demux->n_streams > 1) {
1865 /* can't do this, we can only renegotiate for another mss format */
1869 value = gst_structure_get_value (structure, "media-caps");
1872 const GValue *timescale_v;
1874 /* TODO update when stream changes during playback */
1876 if (demux->n_streams == 0) {
1877 stream = _create_stream ();
1878 demux->streams[demux->n_streams] = stream;
1879 demux->n_streams = 1;
1881 stream = demux->streams[0];
1884 timescale_v = gst_structure_get_value (structure, "timescale");
1886 stream->timescale = g_value_get_uint64 (timescale_v);
1888 /* default mss timescale */
1889 stream->timescale = 10000000;
1891 demux->timescale = stream->timescale;
1893 mediacaps = gst_value_get_caps (value);
1894 if (!stream->caps || !gst_caps_is_equal_fixed (mediacaps, stream->caps)) {
1895 GST_DEBUG_OBJECT (demux, "We have a new caps %" GST_PTR_FORMAT,
1897 stream->new_caps = TRUE;
1899 gst_caps_replace (&stream->caps, (GstCaps *) mediacaps);
1900 structure = gst_caps_get_structure (mediacaps, 0);
1901 if (g_str_has_prefix (gst_structure_get_name (structure), "video")) {
1902 stream->subtype = FOURCC_vide;
1904 gst_structure_get_int (structure, "width", &stream->width);
1905 gst_structure_get_int (structure, "height", &stream->height);
1906 gst_structure_get_fraction (structure, "framerate", &stream->fps_n,
1908 } else if (g_str_has_prefix (gst_structure_get_name (structure), "audio")) {
1910 stream->subtype = FOURCC_soun;
1911 gst_structure_get_int (structure, "channels", &stream->n_channels);
1912 gst_structure_get_int (structure, "rate", &rate);
1913 stream->rate = rate;
1916 gst_caps_replace (&demux->media_caps, (GstCaps *) mediacaps);
1918 demux->mss_mode = FALSE;
1925 gst_qtdemux_reset (GstQTDemux * qtdemux, gboolean hard)
1929 GST_DEBUG_OBJECT (qtdemux, "Resetting demux");
1930 gst_pad_stop_task (qtdemux->sinkpad);
1932 if (hard || qtdemux->upstream_format_is_time) {
1933 qtdemux->state = QTDEMUX_STATE_INITIAL;
1934 qtdemux->neededbytes = 16;
1935 qtdemux->todrop = 0;
1936 qtdemux->pullbased = FALSE;
1937 qtdemux->posted_redirect = FALSE;
1938 qtdemux->first_mdat = -1;
1939 qtdemux->header_size = 0;
1940 qtdemux->mdatoffset = -1;
1941 qtdemux->restoredata_offset = -1;
1942 if (qtdemux->mdatbuffer)
1943 gst_buffer_unref (qtdemux->mdatbuffer);
1944 if (qtdemux->restoredata_buffer)
1945 gst_buffer_unref (qtdemux->restoredata_buffer);
1946 qtdemux->mdatbuffer = NULL;
1947 qtdemux->restoredata_buffer = NULL;
1948 qtdemux->mdatleft = 0;
1949 if (qtdemux->comp_brands)
1950 gst_buffer_unref (qtdemux->comp_brands);
1951 qtdemux->comp_brands = NULL;
1952 qtdemux->last_moov_offset = -1;
1953 if (qtdemux->moov_node)
1954 g_node_destroy (qtdemux->moov_node);
1955 qtdemux->moov_node = NULL;
1956 qtdemux->moov_node_compressed = NULL;
1957 if (qtdemux->tag_list)
1958 gst_mini_object_unref (GST_MINI_OBJECT_CAST (qtdemux->tag_list));
1959 qtdemux->tag_list = NULL;
1961 if (qtdemux->element_index)
1962 gst_object_unref (qtdemux->element_index);
1963 qtdemux->element_index = NULL;
1965 qtdemux->major_brand = 0;
1966 if (qtdemux->pending_newsegment)
1967 gst_event_unref (qtdemux->pending_newsegment);
1968 qtdemux->pending_newsegment = NULL;
1969 qtdemux->upstream_format_is_time = FALSE;
1970 qtdemux->upstream_seekable = FALSE;
1971 qtdemux->upstream_size = 0;
1973 qtdemux->fragment_start = -1;
1974 qtdemux->fragment_start_offset = -1;
1975 qtdemux->duration = 0;
1976 qtdemux->moof_offset = 0;
1977 qtdemux->chapters_track_id = 0;
1978 qtdemux->have_group_id = FALSE;
1979 qtdemux->group_id = G_MAXUINT;
1981 g_queue_foreach (&qtdemux->protection_event_queue, (GFunc) gst_event_unref,
1983 g_queue_clear (&qtdemux->protection_event_queue);
1985 qtdemux->offset = 0;
1986 gst_adapter_clear (qtdemux->adapter);
1987 gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
1988 qtdemux->segment_seqnum = 0;
1991 for (n = 0; n < qtdemux->n_streams; n++) {
1992 gst_qtdemux_stream_free (qtdemux, qtdemux->streams[n]);
1993 qtdemux->streams[n] = NULL;
1995 qtdemux->n_streams = 0;
1996 qtdemux->n_video_streams = 0;
1997 qtdemux->n_audio_streams = 0;
1998 qtdemux->n_sub_streams = 0;
1999 qtdemux->exposed = FALSE;
2000 qtdemux->fragmented = FALSE;
2001 qtdemux->mss_mode = FALSE;
2002 gst_caps_replace (&qtdemux->media_caps, NULL);
2003 qtdemux->timescale = 0;
2004 qtdemux->got_moov = FALSE;
2005 if (qtdemux->protection_system_ids) {
2006 g_ptr_array_free (qtdemux->protection_system_ids, TRUE);
2007 qtdemux->protection_system_ids = NULL;
2009 } else if (qtdemux->mss_mode) {
2010 gst_flow_combiner_reset (qtdemux->flowcombiner);
2011 for (n = 0; n < qtdemux->n_streams; n++)
2012 gst_qtdemux_stream_clear (qtdemux, qtdemux->streams[n]);
2014 gst_flow_combiner_reset (qtdemux->flowcombiner);
2015 for (n = 0; n < qtdemux->n_streams; n++) {
2016 qtdemux->streams[n]->sent_eos = FALSE;
2017 qtdemux->streams[n]->time_position = 0;
2018 qtdemux->streams[n]->accumulated_base = 0;
2020 if (!qtdemux->pending_newsegment) {
2021 qtdemux->pending_newsegment = gst_event_new_segment (&qtdemux->segment);
2022 if (qtdemux->segment_seqnum)
2023 gst_event_set_seqnum (qtdemux->pending_newsegment,
2024 qtdemux->segment_seqnum);
2030 /* Maps the @segment to the qt edts internal segments and pushes
2031 * the correspnding segment event.
2033 * If it ends up being at a empty segment, a gap will be pushed and the next
2034 * edts segment will be activated in sequence.
2036 * To be used in push-mode only */
2038 gst_qtdemux_map_and_push_segments (GstQTDemux * qtdemux, GstSegment * segment)
2042 for (n = 0; n < qtdemux->n_streams; n++) {
2043 QtDemuxStream *stream = qtdemux->streams[n];
2045 stream->time_position = segment->start;
2047 /* in push mode we should be guaranteed that we will have empty segments
2048 * at the beginning and then one segment after, other scenarios are not
2049 * supported and are discarded when parsing the edts */
2050 for (i = 0; i < stream->n_segments; i++) {
2051 if (stream->segments[i].stop_time > segment->start) {
2052 gst_qtdemux_activate_segment (qtdemux, stream, i,
2053 stream->time_position);
2054 if (QTSEGMENT_IS_EMPTY (&stream->segments[i])) {
2055 /* push the empty segment and move to the next one */
2056 gst_qtdemux_send_gap_for_segment (qtdemux, stream, i,
2057 stream->time_position);
2061 g_assert (i == stream->n_segments - 1);
2068 gst_qtdemux_handle_sink_event (GstPad * sinkpad, GstObject * parent,
2071 GstQTDemux *demux = GST_QTDEMUX (parent);
2072 gboolean res = TRUE;
2074 GST_LOG_OBJECT (demux, "handling %s event", GST_EVENT_TYPE_NAME (event));
2076 switch (GST_EVENT_TYPE (event)) {
2077 case GST_EVENT_SEGMENT:
2080 QtDemuxStream *stream;
2084 /* some debug output */
2085 gst_event_copy_segment (event, &segment);
2086 GST_DEBUG_OBJECT (demux, "received newsegment %" GST_SEGMENT_FORMAT,
2089 /* erase any previously set segment */
2090 gst_event_replace (&demux->pending_newsegment, NULL);
2092 if (segment.format == GST_FORMAT_TIME) {
2093 GST_DEBUG_OBJECT (demux, "new pending_newsegment");
2094 gst_event_replace (&demux->pending_newsegment, event);
2095 demux->upstream_format_is_time = TRUE;
2097 GST_DEBUG_OBJECT (demux, "Not storing upstream newsegment, "
2098 "not in time format");
2100 /* chain will send initial newsegment after pads have been added */
2101 if (demux->state != QTDEMUX_STATE_MOVIE || !demux->n_streams) {
2102 GST_DEBUG_OBJECT (demux, "still starting, eating event");
2107 /* check if this matches a time seek we received previously
2108 * FIXME for backwards compatibility reasons we use the
2109 * seek_offset here to compare. In the future we might want to
2110 * change this to use the seqnum as it uniquely should identify
2111 * the segment that corresponds to the seek. */
2112 GST_DEBUG_OBJECT (demux, "Stored seek offset: %" G_GINT64_FORMAT
2113 ", received segment offset %" G_GINT64_FORMAT,
2114 demux->seek_offset, segment.start);
2115 if (segment.format == GST_FORMAT_BYTES
2116 && demux->seek_offset == segment.start) {
2117 GST_OBJECT_LOCK (demux);
2118 offset = segment.start;
2120 segment.format = GST_FORMAT_TIME;
2121 segment.start = demux->push_seek_start;
2122 segment.stop = demux->push_seek_stop;
2123 GST_DEBUG_OBJECT (demux, "Replaced segment with stored seek "
2124 "segment %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT,
2125 GST_TIME_ARGS (segment.start), GST_TIME_ARGS (segment.stop));
2126 GST_OBJECT_UNLOCK (demux);
2129 /* we only expect a BYTE segment, e.g. following a seek */
2130 if (segment.format == GST_FORMAT_BYTES) {
2131 if (GST_CLOCK_TIME_IS_VALID (segment.start)) {
2132 offset = segment.start;
2134 gst_qtdemux_find_sample (demux, segment.start, TRUE, FALSE, NULL,
2135 NULL, (gint64 *) & segment.start);
2136 if ((gint64) segment.start < 0)
2139 if (GST_CLOCK_TIME_IS_VALID (segment.stop)) {
2140 gst_qtdemux_find_sample (demux, segment.stop, FALSE, FALSE, NULL,
2141 NULL, (gint64 *) & segment.stop);
2142 /* keyframe seeking should already arrange for start >= stop,
2143 * but make sure in other rare cases */
2144 segment.stop = MAX (segment.stop, segment.start);
2146 } else if (segment.format == GST_FORMAT_TIME) {
2147 /* push all data on the adapter before starting this
2149 gst_qtdemux_process_adapter (demux, TRUE);
2151 GST_DEBUG_OBJECT (demux, "unsupported segment format, ignoring");
2155 /* accept upstream's notion of segment and distribute along */
2156 segment.format = GST_FORMAT_TIME;
2157 segment.position = segment.time = segment.start;
2158 segment.duration = demux->segment.duration;
2159 segment.base = gst_segment_to_running_time (&demux->segment,
2160 GST_FORMAT_TIME, demux->segment.position);
2162 gst_segment_copy_into (&segment, &demux->segment);
2163 GST_DEBUG_OBJECT (demux, "Pushing newseg %" GST_SEGMENT_FORMAT, &segment);
2165 /* map segment to internal qt segments and push on each stream */
2166 if (demux->n_streams) {
2167 if (demux->fragmented) {
2168 GstEvent *segment_event = gst_event_new_segment (&segment);
2170 gst_event_replace (&demux->pending_newsegment, NULL);
2171 gst_event_set_seqnum (segment_event, demux->segment_seqnum);
2172 gst_qtdemux_push_event (demux, segment_event);
2174 gst_event_replace (&demux->pending_newsegment, NULL);
2175 gst_qtdemux_map_and_push_segments (demux, &segment);
2179 /* clear leftover in current segment, if any */
2180 gst_adapter_clear (demux->adapter);
2182 /* set up streaming thread */
2183 demux->offset = offset;
2184 if (demux->upstream_format_is_time) {
2185 GST_DEBUG_OBJECT (demux, "Upstream is driving in time format, "
2186 "set values to restart reading from a new atom");
2187 demux->neededbytes = 16;
2190 gst_qtdemux_find_sample (demux, offset, TRUE, TRUE, &stream, &idx,
2193 demux->todrop = stream->samples[idx].offset - offset;
2194 demux->neededbytes = demux->todrop + stream->samples[idx].size;
2196 /* set up for EOS */
2197 demux->neededbytes = -1;
2202 gst_event_unref (event);
2206 case GST_EVENT_FLUSH_START:
2208 if (gst_event_get_seqnum (event) == demux->offset_seek_seqnum) {
2209 gst_event_unref (event);
2214 case GST_EVENT_FLUSH_STOP:
2218 dur = demux->segment.duration;
2219 gst_qtdemux_reset (demux, FALSE);
2220 demux->segment.duration = dur;
2222 if (gst_event_get_seqnum (event) == demux->offset_seek_seqnum) {
2223 gst_event_unref (event);
2229 /* If we are in push mode, and get an EOS before we've seen any streams,
2230 * then error out - we have nowhere to send the EOS */
2231 if (!demux->pullbased) {
2233 gboolean has_valid_stream = FALSE;
2234 for (i = 0; i < demux->n_streams; i++) {
2235 if (demux->streams[i]->pad != NULL) {
2236 has_valid_stream = TRUE;
2240 if (!has_valid_stream)
2241 gst_qtdemux_post_no_playable_stream_error (demux);
2243 GST_DEBUG_OBJECT (demux, "Data still available after EOS: %u",
2244 (guint) gst_adapter_available (demux->adapter));
2245 if (gst_qtdemux_process_adapter (demux, TRUE) != GST_FLOW_OK) {
2251 case GST_EVENT_CAPS:{
2252 GstCaps *caps = NULL;
2254 gst_event_parse_caps (event, &caps);
2255 gst_qtdemux_setcaps (demux, caps);
2257 gst_event_unref (event);
2260 case GST_EVENT_PROTECTION:
2262 const gchar *system_id = NULL;
2264 gst_event_parse_protection (event, &system_id, NULL, NULL);
2265 GST_DEBUG_OBJECT (demux, "Received protection event for system ID %s",
2267 gst_qtdemux_append_protection_system_id (demux, system_id);
2268 /* save the event for later, for source pads that have not been created */
2269 g_queue_push_tail (&demux->protection_event_queue, gst_event_ref (event));
2270 /* send it to all pads that already exist */
2271 gst_qtdemux_push_event (demux, event);
2279 res = gst_pad_event_default (demux->sinkpad, parent, event) & res;
2287 gst_qtdemux_set_index (GstElement * element, GstIndex * index)
2289 GstQTDemux *demux = GST_QTDEMUX (element);
2291 GST_OBJECT_LOCK (demux);
2292 if (demux->element_index)
2293 gst_object_unref (demux->element_index);
2295 demux->element_index = gst_object_ref (index);
2297 demux->element_index = NULL;
2299 GST_OBJECT_UNLOCK (demux);
2300 /* object lock might be taken again */
2302 gst_index_get_writer_id (index, GST_OBJECT (element), &demux->index_id);
2303 GST_DEBUG_OBJECT (demux, "Set index %" GST_PTR_FORMAT "for writer id %d",
2304 demux->element_index, demux->index_id);
2308 gst_qtdemux_get_index (GstElement * element)
2310 GstIndex *result = NULL;
2311 GstQTDemux *demux = GST_QTDEMUX (element);
2313 GST_OBJECT_LOCK (demux);
2314 if (demux->element_index)
2315 result = gst_object_ref (demux->element_index);
2316 GST_OBJECT_UNLOCK (demux);
2318 GST_DEBUG_OBJECT (demux, "Returning index %" GST_PTR_FORMAT, result);
2325 gst_qtdemux_stbl_free (QtDemuxStream * stream)
2327 g_free ((gpointer) stream->stco.data);
2328 stream->stco.data = NULL;
2329 g_free ((gpointer) stream->stsz.data);
2330 stream->stsz.data = NULL;
2331 g_free ((gpointer) stream->stsc.data);
2332 stream->stsc.data = NULL;
2333 g_free ((gpointer) stream->stts.data);
2334 stream->stts.data = NULL;
2335 g_free ((gpointer) stream->stss.data);
2336 stream->stss.data = NULL;
2337 g_free ((gpointer) stream->stps.data);
2338 stream->stps.data = NULL;
2339 g_free ((gpointer) stream->ctts.data);
2340 stream->ctts.data = NULL;
2344 gst_qtdemux_stream_flush_segments_data (GstQTDemux * qtdemux,
2345 QtDemuxStream * stream)
2347 g_free (stream->segments);
2348 stream->segments = NULL;
2349 stream->segment_index = -1;
2350 stream->accumulated_base = 0;
2354 gst_qtdemux_stream_flush_samples_data (GstQTDemux * qtdemux,
2355 QtDemuxStream * stream)
2357 g_free (stream->samples);
2358 stream->samples = NULL;
2359 gst_qtdemux_stbl_free (stream);
2362 g_free (stream->ra_entries);
2363 stream->ra_entries = NULL;
2364 stream->n_ra_entries = 0;
2366 stream->sample_index = -1;
2367 stream->stbl_index = -1;
2368 stream->n_samples = 0;
2369 stream->time_position = 0;
2371 stream->n_samples_moof = 0;
2372 stream->duration_moof = 0;
2376 gst_qtdemux_stream_clear (GstQTDemux * qtdemux, QtDemuxStream * stream)
2378 if (stream->allocator)
2379 gst_object_unref (stream->allocator);
2380 while (stream->buffers) {
2381 gst_buffer_unref (GST_BUFFER_CAST (stream->buffers->data));
2382 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
2384 if (stream->rgb8_palette) {
2385 gst_memory_unref (stream->rgb8_palette);
2386 stream->rgb8_palette = NULL;
2389 if (stream->pending_tags)
2390 gst_tag_list_unref (stream->pending_tags);
2391 stream->pending_tags = NULL;
2392 g_free (stream->redirect_uri);
2393 stream->redirect_uri = NULL;
2394 stream->sent_eos = FALSE;
2395 stream->sparse = FALSE;
2396 stream->protected = FALSE;
2397 if (stream->protection_scheme_info) {
2398 if (stream->protection_scheme_type == FOURCC_cenc) {
2399 QtDemuxCencSampleSetInfo *info =
2400 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
2401 if (info->default_properties)
2402 gst_structure_free (info->default_properties);
2403 if (info->crypto_info)
2404 g_ptr_array_free (info->crypto_info, TRUE);
2406 g_free (stream->protection_scheme_info);
2407 stream->protection_scheme_info = NULL;
2409 stream->protection_scheme_type = 0;
2410 stream->protection_scheme_version = 0;
2411 g_queue_foreach (&stream->protection_scheme_event_queue,
2412 (GFunc) gst_event_unref, NULL);
2413 g_queue_clear (&stream->protection_scheme_event_queue);
2414 gst_qtdemux_stream_flush_segments_data (qtdemux, stream);
2415 gst_qtdemux_stream_flush_samples_data (qtdemux, stream);
2419 gst_qtdemux_stream_free (GstQTDemux * qtdemux, QtDemuxStream * stream)
2421 gst_qtdemux_stream_clear (qtdemux, stream);
2423 gst_caps_unref (stream->caps);
2424 stream->caps = NULL;
2426 gst_element_remove_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
2427 gst_flow_combiner_remove_pad (qtdemux->flowcombiner, stream->pad);
2433 gst_qtdemux_remove_stream (GstQTDemux * qtdemux, int i)
2435 g_assert (i >= 0 && i < qtdemux->n_streams && qtdemux->streams[i] != NULL);
2437 gst_qtdemux_stream_free (qtdemux, qtdemux->streams[i]);
2438 qtdemux->streams[i] = qtdemux->streams[qtdemux->n_streams - 1];
2439 qtdemux->streams[qtdemux->n_streams - 1] = NULL;
2440 qtdemux->n_streams--;
2443 static GstStateChangeReturn
2444 gst_qtdemux_change_state (GstElement * element, GstStateChange transition)
2446 GstQTDemux *qtdemux = GST_QTDEMUX (element);
2447 GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
2449 switch (transition) {
2450 case GST_STATE_CHANGE_PAUSED_TO_READY:
2456 result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
2458 switch (transition) {
2459 case GST_STATE_CHANGE_PAUSED_TO_READY:{
2460 gst_qtdemux_reset (qtdemux, TRUE);
2471 qtdemux_parse_ftyp (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2473 /* counts as header data */
2474 qtdemux->header_size += length;
2476 /* only consider at least a sufficiently complete ftyp atom */
2480 qtdemux->major_brand = QT_FOURCC (buffer + 8);
2481 GST_DEBUG_OBJECT (qtdemux, "major brand: %" GST_FOURCC_FORMAT,
2482 GST_FOURCC_ARGS (qtdemux->major_brand));
2483 if (qtdemux->comp_brands)
2484 gst_buffer_unref (qtdemux->comp_brands);
2485 buf = qtdemux->comp_brands = gst_buffer_new_and_alloc (length - 16);
2486 gst_buffer_fill (buf, 0, buffer + 16, length - 16);
2491 qtdemux_handle_xmp_taglist (GstQTDemux * qtdemux, GstTagList * taglist,
2492 GstTagList * xmptaglist)
2494 /* Strip out bogus fields */
2496 if (gst_tag_list_get_scope (taglist) == GST_TAG_SCOPE_GLOBAL) {
2497 gst_tag_list_remove_tag (xmptaglist, GST_TAG_VIDEO_CODEC);
2498 gst_tag_list_remove_tag (xmptaglist, GST_TAG_AUDIO_CODEC);
2500 gst_tag_list_remove_tag (xmptaglist, GST_TAG_CONTAINER_FORMAT);
2503 GST_DEBUG_OBJECT (qtdemux, "Found XMP tags %" GST_PTR_FORMAT, xmptaglist);
2505 /* prioritize native tags using _KEEP mode */
2506 gst_tag_list_insert (taglist, xmptaglist, GST_TAG_MERGE_KEEP);
2507 gst_tag_list_unref (xmptaglist);
2512 qtdemux_parse_piff (GstQTDemux * qtdemux, const guint8 * buffer, gint length,
2520 QtDemuxStream *stream;
2521 GstStructure *structure;
2522 QtDemuxCencSampleSetInfo *ss_info = NULL;
2523 const gchar *system_id;
2524 gboolean uses_sub_sample_encryption = FALSE;
2526 if (qtdemux->n_streams == 0)
2529 stream = qtdemux->streams[0];
2531 structure = gst_caps_get_structure (stream->caps, 0);
2532 if (!gst_structure_has_name (structure, "application/x-cenc")) {
2533 GST_WARNING_OBJECT (qtdemux,
2534 "Attempting PIFF box parsing on an unencrypted stream.");
2538 gst_structure_get (structure, GST_PROTECTION_SYSTEM_ID_CAPS_FIELD,
2539 G_TYPE_STRING, &system_id, NULL);
2540 gst_qtdemux_append_protection_system_id (qtdemux, system_id);
2542 stream->protected = TRUE;
2543 stream->protection_scheme_type = FOURCC_cenc;
2545 if (!stream->protection_scheme_info)
2546 stream->protection_scheme_info = g_new0 (QtDemuxCencSampleSetInfo, 1);
2548 ss_info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
2550 if (ss_info->default_properties)
2551 gst_structure_free (ss_info->default_properties);
2553 ss_info->default_properties =
2554 gst_structure_new ("application/x-cenc",
2555 "iv_size", G_TYPE_UINT, iv_size, "encrypted", G_TYPE_BOOLEAN, TRUE, NULL);
2557 if (ss_info->crypto_info) {
2558 GST_LOG_OBJECT (qtdemux, "unreffing existing crypto_info");
2559 g_ptr_array_free (ss_info->crypto_info, TRUE);
2560 ss_info->crypto_info = NULL;
2564 gst_byte_reader_init (&br, buffer + offset + 16, length - offset - 16);
2566 if (!gst_byte_reader_get_uint8 (&br, &version)) {
2567 GST_ERROR_OBJECT (qtdemux, "Error getting box's version field");
2571 if (!gst_byte_reader_get_uint24_be (&br, &flags)) {
2572 GST_ERROR_OBJECT (qtdemux, "Error getting box's flags field");
2576 if ((flags & 0x000001)) {
2577 guint32 algorithm_id = 0;
2580 gboolean is_encrypted = TRUE;
2582 if (!gst_byte_reader_get_uint24_le (&br, &algorithm_id)) {
2583 GST_ERROR_OBJECT (qtdemux, "Error getting box's algorithm ID field");
2588 if (algorithm_id == 0) {
2589 is_encrypted = FALSE;
2590 } else if (algorithm_id == 1) {
2591 /* FIXME: maybe store this in properties? */
2592 GST_DEBUG_OBJECT (qtdemux, "AES 128-bits CTR encrypted stream");
2593 } else if (algorithm_id == 2) {
2594 /* FIXME: maybe store this in properties? */
2595 GST_DEBUG_OBJECT (qtdemux, "AES 128-bits CBC encrypted stream");
2598 if (!gst_byte_reader_get_uint8 (&br, &iv_size))
2601 if (!gst_byte_reader_get_data (&br, 16, &kid))
2604 kid_buf = gst_buffer_new_allocate (NULL, 16, NULL);
2605 gst_buffer_fill (kid_buf, 0, kid, 16);
2606 if (ss_info->default_properties)
2607 gst_structure_free (ss_info->default_properties);
2608 ss_info->default_properties =
2609 gst_structure_new ("application/x-cenc",
2610 "iv_size", G_TYPE_UINT, iv_size,
2611 "encrypted", G_TYPE_BOOLEAN, is_encrypted,
2612 "kid", GST_TYPE_BUFFER, kid_buf, NULL);
2613 GST_DEBUG_OBJECT (qtdemux, "default sample properties: "
2614 "is_encrypted=%u, iv_size=%u", is_encrypted, iv_size);
2615 gst_buffer_unref (kid_buf);
2616 } else if ((flags & 0x000002)) {
2617 uses_sub_sample_encryption = TRUE;
2620 if (!gst_byte_reader_get_uint32_be (&br, &qtdemux->cenc_aux_sample_count)) {
2621 GST_ERROR_OBJECT (qtdemux, "Error getting box's sample count field");
2625 ss_info->crypto_info =
2626 g_ptr_array_new_full (qtdemux->cenc_aux_sample_count,
2627 (GDestroyNotify) qtdemux_gst_structure_free);
2629 for (i = 0; i < qtdemux->cenc_aux_sample_count; ++i) {
2630 GstStructure *properties;
2634 properties = qtdemux_get_cenc_sample_properties (qtdemux, stream, i);
2635 if (properties == NULL) {
2636 GST_ERROR_OBJECT (qtdemux, "failed to get properties for sample %u", i);
2640 if (!gst_byte_reader_dup_data (&br, iv_size, &data)) {
2641 GST_ERROR_OBJECT (qtdemux, "IV data not present for sample %u", i);
2642 gst_structure_free (properties);
2645 buf = gst_buffer_new_wrapped (data, iv_size);
2646 gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL);
2647 gst_buffer_unref (buf);
2649 if (uses_sub_sample_encryption) {
2650 guint16 n_subsamples;
2652 if (!gst_byte_reader_get_uint16_be (&br, &n_subsamples)
2653 || n_subsamples == 0) {
2654 GST_ERROR_OBJECT (qtdemux,
2655 "failed to get subsample count for sample %u", i);
2656 gst_structure_free (properties);
2659 GST_LOG_OBJECT (qtdemux, "subsample count: %u", n_subsamples);
2660 if (!gst_byte_reader_dup_data (&br, n_subsamples * 6, &data)) {
2661 GST_ERROR_OBJECT (qtdemux, "failed to get subsample data for sample %u",
2663 gst_structure_free (properties);
2666 buf = gst_buffer_new_wrapped (data, n_subsamples * 6);
2667 gst_structure_set (properties,
2668 "subsample_count", G_TYPE_UINT, n_subsamples,
2669 "subsamples", GST_TYPE_BUFFER, buf, NULL);
2670 gst_buffer_unref (buf);
2672 gst_structure_set (properties, "subsample_count", G_TYPE_UINT, 0, NULL);
2675 g_ptr_array_add (ss_info->crypto_info, properties);
2680 qtdemux_parse_uuid (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2682 static const guint8 xmp_uuid[] = { 0xBE, 0x7A, 0xCF, 0xCB,
2683 0x97, 0xA9, 0x42, 0xE8,
2684 0x9C, 0x71, 0x99, 0x94,
2685 0x91, 0xE3, 0xAF, 0xAC
2687 static const guint8 playready_uuid[] = {
2688 0xd0, 0x8a, 0x4f, 0x18, 0x10, 0xf3, 0x4a, 0x82,
2689 0xb6, 0xc8, 0x32, 0xd8, 0xab, 0xa1, 0x83, 0xd3
2692 static const guint8 piff_sample_encryption_uuid[] = {
2693 0xa2, 0x39, 0x4f, 0x52, 0x5a, 0x9b, 0x4f, 0x14,
2694 0xa2, 0x44, 0x6c, 0x42, 0x7c, 0x64, 0x8d, 0xf4
2699 /* counts as header data */
2700 qtdemux->header_size += length;
2702 offset = (QT_UINT32 (buffer) == 0) ? 16 : 8;
2704 if (length <= offset + 16) {
2705 GST_DEBUG_OBJECT (qtdemux, "uuid atom is too short, skipping");
2709 if (memcmp (buffer + offset, xmp_uuid, 16) == 0) {
2711 GstTagList *taglist;
2713 buf = _gst_buffer_new_wrapped ((guint8 *) buffer + offset + 16,
2714 length - offset - 16, NULL);
2715 taglist = gst_tag_list_from_xmp_buffer (buf);
2716 gst_buffer_unref (buf);
2718 qtdemux_handle_xmp_taglist (qtdemux, qtdemux->tag_list, taglist);
2720 } else if (memcmp (buffer + offset, playready_uuid, 16) == 0) {
2722 const gunichar2 *s_utf16;
2725 len = GST_READ_UINT16_LE (buffer + offset + 0x30);
2726 s_utf16 = (const gunichar2 *) (buffer + offset + 0x32);
2727 contents = g_utf16_to_utf8 (s_utf16, len / 2, NULL, NULL, NULL);
2728 GST_ERROR_OBJECT (qtdemux, "contents: %s", contents);
2732 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT,
2733 (_("Cannot play stream because it is encrypted with PlayReady DRM.")),
2735 } else if (memcmp (buffer + offset, piff_sample_encryption_uuid, 16) == 0) {
2736 qtdemux_parse_piff (qtdemux, buffer, length, offset);
2738 GST_DEBUG_OBJECT (qtdemux, "Ignoring unknown uuid: %08x-%08x-%08x-%08x",
2739 GST_READ_UINT32_LE (buffer + offset),
2740 GST_READ_UINT32_LE (buffer + offset + 4),
2741 GST_READ_UINT32_LE (buffer + offset + 8),
2742 GST_READ_UINT32_LE (buffer + offset + 12));
2747 qtdemux_parse_sidx (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2749 GstSidxParser sidx_parser;
2750 GstIsoffParserResult res;
2753 gst_isoff_qt_sidx_parser_init (&sidx_parser);
2756 gst_isoff_qt_sidx_parser_add_data (&sidx_parser, buffer, length,
2758 GST_DEBUG_OBJECT (qtdemux, "sidx parse result: %d", res);
2759 if (res == GST_ISOFF_QT_PARSER_DONE) {
2760 check_update_duration (qtdemux, sidx_parser.cumulative_pts);
2762 gst_isoff_qt_sidx_parser_clear (&sidx_parser);
2765 /* caller verifies at least 8 bytes in buf */
2767 extract_initial_length_and_fourcc (const guint8 * data, guint size,
2768 guint64 * plength, guint32 * pfourcc)
2773 length = QT_UINT32 (data);
2774 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
2775 fourcc = QT_FOURCC (data + 4);
2776 GST_DEBUG ("atom type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
2779 length = G_MAXUINT64;
2780 } else if (length == 1 && size >= 16) {
2781 /* this means we have an extended size, which is the 64 bit value of
2782 * the next 8 bytes */
2783 length = QT_UINT64 (data + 8);
2784 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
2794 qtdemux_parse_mehd (GstQTDemux * qtdemux, GstByteReader * br)
2796 guint32 version = 0;
2797 GstClockTime duration = 0;
2799 if (!gst_byte_reader_get_uint32_be (br, &version))
2804 if (!gst_byte_reader_get_uint64_be (br, &duration))
2809 if (!gst_byte_reader_get_uint32_be (br, &dur))
2814 GST_INFO_OBJECT (qtdemux, "mehd duration: %" G_GUINT64_FORMAT, duration);
2815 qtdemux->duration = duration;
2821 GST_DEBUG_OBJECT (qtdemux, "parsing mehd failed");
2827 qtdemux_parse_trex (GstQTDemux * qtdemux, QtDemuxStream * stream,
2828 guint32 * ds_duration, guint32 * ds_size, guint32 * ds_flags)
2830 if (!stream->parsed_trex && qtdemux->moov_node) {
2832 GstByteReader trex_data;
2834 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
2836 trex = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_trex,
2839 guint32 id = 0, dur = 0, size = 0, flags = 0, dummy = 0;
2841 /* skip version/flags */
2842 if (!gst_byte_reader_skip (&trex_data, 4))
2844 if (!gst_byte_reader_get_uint32_be (&trex_data, &id))
2846 if (id != stream->track_id)
2848 /* sample description index; ignore */
2849 if (!gst_byte_reader_get_uint32_be (&trex_data, &dummy))
2851 if (!gst_byte_reader_get_uint32_be (&trex_data, &dur))
2853 if (!gst_byte_reader_get_uint32_be (&trex_data, &size))
2855 if (!gst_byte_reader_get_uint32_be (&trex_data, &flags))
2858 GST_DEBUG_OBJECT (qtdemux, "fragment defaults for stream %d; "
2859 "duration %d, size %d, flags 0x%x", stream->track_id,
2862 stream->parsed_trex = TRUE;
2863 stream->def_sample_duration = dur;
2864 stream->def_sample_size = size;
2865 stream->def_sample_flags = flags;
2868 /* iterate all siblings */
2869 trex = qtdemux_tree_get_sibling_by_type_full (trex, FOURCC_trex,
2875 *ds_duration = stream->def_sample_duration;
2876 *ds_size = stream->def_sample_size;
2877 *ds_flags = stream->def_sample_flags;
2879 /* even then, above values are better than random ... */
2880 if (G_UNLIKELY (!stream->parsed_trex)) {
2881 GST_WARNING_OBJECT (qtdemux,
2882 "failed to find fragment defaults for stream %d", stream->track_id);
2889 /* This method should be called whenever a more accurate duration might
2890 * have been found. It will update all relevant variables if/where needed
2893 check_update_duration (GstQTDemux * qtdemux, GstClockTime duration)
2897 GstClockTime prevdur;
2899 movdur = GSTTIME_TO_QTTIME (qtdemux, duration);
2901 if (movdur > qtdemux->duration) {
2902 prevdur = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
2903 GST_DEBUG_OBJECT (qtdemux,
2904 "Updating total duration to %" GST_TIME_FORMAT " was %" GST_TIME_FORMAT,
2905 GST_TIME_ARGS (duration), GST_TIME_ARGS (prevdur));
2906 qtdemux->duration = movdur;
2907 GST_DEBUG_OBJECT (qtdemux,
2908 "qtdemux->segment.duration: %" GST_TIME_FORMAT " .stop: %"
2909 GST_TIME_FORMAT, GST_TIME_ARGS (qtdemux->segment.duration),
2910 GST_TIME_ARGS (qtdemux->segment.stop));
2911 if (qtdemux->segment.duration == prevdur) {
2912 /* If the current segment has duration/stop identical to previous duration
2913 * update them also (because they were set at that point in time with
2914 * the wrong duration */
2915 /* We convert the value *from* the timescale version to avoid rounding errors */
2916 GstClockTime fixeddur = QTTIME_TO_GSTTIME (qtdemux, movdur);
2917 GST_DEBUG_OBJECT (qtdemux, "Updated segment.duration and segment.stop");
2918 qtdemux->segment.duration = fixeddur;
2919 qtdemux->segment.stop = fixeddur;
2922 for (i = 0; i < qtdemux->n_streams; i++) {
2923 QtDemuxStream *stream = qtdemux->streams[i];
2925 movdur = GSTTIME_TO_QTSTREAMTIME (stream, duration);
2926 if (movdur > stream->duration) {
2927 GST_DEBUG_OBJECT (qtdemux,
2928 "Updating stream #%d duration to %" GST_TIME_FORMAT, i,
2929 GST_TIME_ARGS (duration));
2930 stream->duration = movdur;
2931 if (stream->dummy_segment) {
2932 /* Update all dummy values to new duration */
2933 stream->segments[0].stop_time = duration;
2934 stream->segments[0].duration = duration;
2935 stream->segments[0].media_stop = duration;
2937 /* let downstream know we possibly have a new stop time */
2938 if (stream->segment_index != -1) {
2941 if (qtdemux->segment.rate >= 0) {
2942 pos = stream->segment.start;
2944 pos = stream->segment.stop;
2947 gst_qtdemux_stream_update_segment (qtdemux, stream,
2948 stream->segment_index, pos, NULL, NULL);
2957 qtdemux_parse_trun (GstQTDemux * qtdemux, GstByteReader * trun,
2958 QtDemuxStream * stream, guint32 d_sample_duration, guint32 d_sample_size,
2959 guint32 d_sample_flags, gint64 moof_offset, gint64 moof_length,
2960 gint64 * base_offset, gint64 * running_offset, gint64 decode_ts)
2962 GstClockTime gst_ts = GST_CLOCK_TIME_NONE;
2964 gint32 data_offset = 0;
2965 guint32 flags = 0, first_flags = 0, samples_count = 0;
2968 guint entry_size, dur_offset, size_offset, flags_offset = 0, ct_offset = 0;
2969 QtDemuxSample *sample;
2970 gboolean ismv = FALSE;
2972 GST_LOG_OBJECT (qtdemux, "parsing trun stream %d; "
2973 "default dur %d, size %d, flags 0x%x, base offset %" G_GINT64_FORMAT ", "
2974 "decode ts %" G_GINT64_FORMAT, stream->track_id, d_sample_duration,
2975 d_sample_size, d_sample_flags, *base_offset, decode_ts);
2977 if (stream->pending_seek && moof_offset < stream->pending_seek->moof_offset) {
2978 GST_INFO_OBJECT (stream->pad, "skipping trun before seek target fragment");
2982 /* presence of stss or not can't really tell us much,
2983 * and flags and so on tend to be marginally reliable in these files */
2984 if (stream->subtype == FOURCC_soun) {
2985 GST_DEBUG_OBJECT (qtdemux,
2986 "sound track in fragmented file; marking all keyframes");
2987 stream->all_keyframe = TRUE;
2990 if (!gst_byte_reader_skip (trun, 1) ||
2991 !gst_byte_reader_get_uint24_be (trun, &flags))
2994 if (!gst_byte_reader_get_uint32_be (trun, &samples_count))
2997 if (flags & TR_DATA_OFFSET) {
2998 /* note this is really signed */
2999 if (!gst_byte_reader_get_int32_be (trun, &data_offset))
3001 GST_LOG_OBJECT (qtdemux, "trun data offset %d", data_offset);
3002 /* default base offset = first byte of moof */
3003 if (*base_offset == -1) {
3004 GST_LOG_OBJECT (qtdemux, "base_offset at moof");
3005 *base_offset = moof_offset;
3007 *running_offset = *base_offset + data_offset;
3009 /* if no offset at all, that would mean data starts at moof start,
3010 * which is a bit wrong and is ismv crappy way, so compensate
3011 * assuming data is in mdat following moof */
3012 if (*base_offset == -1) {
3013 *base_offset = moof_offset + moof_length + 8;
3014 GST_LOG_OBJECT (qtdemux, "base_offset assumed in mdat after moof");
3017 if (*running_offset == -1)
3018 *running_offset = *base_offset;
3021 GST_LOG_OBJECT (qtdemux, "running offset now %" G_GINT64_FORMAT,
3023 GST_LOG_OBJECT (qtdemux, "trun offset %d, flags 0x%x, entries %d",
3024 data_offset, flags, samples_count);
3026 if (flags & TR_FIRST_SAMPLE_FLAGS) {
3027 if (G_UNLIKELY (flags & TR_SAMPLE_FLAGS)) {
3028 GST_DEBUG_OBJECT (qtdemux,
3029 "invalid flags; SAMPLE and FIRST_SAMPLE present, discarding latter");
3030 flags ^= TR_FIRST_SAMPLE_FLAGS;
3032 if (!gst_byte_reader_get_uint32_be (trun, &first_flags))
3034 GST_LOG_OBJECT (qtdemux, "first flags: 0x%x", first_flags);
3038 /* FIXME ? spec says other bits should also be checked to determine
3039 * entry size (and prefix size for that matter) */
3041 dur_offset = size_offset = 0;
3042 if (flags & TR_SAMPLE_DURATION) {
3043 GST_LOG_OBJECT (qtdemux, "entry duration present");
3044 dur_offset = entry_size;
3047 if (flags & TR_SAMPLE_SIZE) {
3048 GST_LOG_OBJECT (qtdemux, "entry size present");
3049 size_offset = entry_size;
3052 if (flags & TR_SAMPLE_FLAGS) {
3053 GST_LOG_OBJECT (qtdemux, "entry flags present");
3054 flags_offset = entry_size;
3057 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
3058 GST_LOG_OBJECT (qtdemux, "entry ct offset present");
3059 ct_offset = entry_size;
3063 if (!qt_atom_parser_has_chunks (trun, samples_count, entry_size))
3065 data = (guint8 *) gst_byte_reader_peek_data_unchecked (trun);
3067 if (stream->n_samples + samples_count >=
3068 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample))
3071 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
3072 stream->n_samples + samples_count, (guint) sizeof (QtDemuxSample),
3073 (stream->n_samples + samples_count) *
3074 sizeof (QtDemuxSample) / (1024.0 * 1024.0));
3076 /* create a new array of samples if it's the first sample parsed */
3077 if (stream->n_samples == 0) {
3078 g_assert (stream->samples == NULL);
3079 stream->samples = g_try_new0 (QtDemuxSample, samples_count);
3080 /* or try to reallocate it with space enough to insert the new samples */
3082 stream->samples = g_try_renew (QtDemuxSample, stream->samples,
3083 stream->n_samples + samples_count);
3084 if (stream->samples == NULL)
3087 if (qtdemux->fragment_start != -1) {
3088 timestamp = GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->fragment_start);
3089 qtdemux->fragment_start = -1;
3091 if (stream->n_samples == 0) {
3092 if (decode_ts > 0) {
3093 timestamp = decode_ts;
3094 } else if (stream->pending_seek != NULL) {
3095 /* if we don't have a timestamp from a tfdt box, we'll use the one
3096 * from the mfra seek table */
3097 GST_INFO_OBJECT (stream->pad, "pending seek ts = %" GST_TIME_FORMAT,
3098 GST_TIME_ARGS (stream->pending_seek->ts));
3100 /* FIXME: this is not fully correct, the timestamp refers to the random
3101 * access sample refered to in the tfra entry, which may not necessarily
3102 * be the first sample in the tfrag/trun (but hopefully/usually is) */
3103 timestamp = GSTTIME_TO_QTSTREAMTIME (stream, stream->pending_seek->ts);
3108 gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
3109 GST_INFO_OBJECT (stream->pad, "first sample ts %" GST_TIME_FORMAT,
3110 GST_TIME_ARGS (gst_ts));
3112 /* subsequent fragments extend stream */
3114 stream->samples[stream->n_samples - 1].timestamp +
3115 stream->samples[stream->n_samples - 1].duration;
3117 gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
3118 GST_INFO_OBJECT (qtdemux, "first sample ts %" GST_TIME_FORMAT
3119 " (extends previous samples)", GST_TIME_ARGS (gst_ts));
3123 sample = stream->samples + stream->n_samples;
3124 for (i = 0; i < samples_count; i++) {
3125 guint32 dur, size, sflags, ct;
3127 /* first read sample data */
3128 if (flags & TR_SAMPLE_DURATION) {
3129 dur = QT_UINT32 (data + dur_offset);
3131 dur = d_sample_duration;
3133 if (flags & TR_SAMPLE_SIZE) {
3134 size = QT_UINT32 (data + size_offset);
3136 size = d_sample_size;
3138 if (flags & TR_FIRST_SAMPLE_FLAGS) {
3140 sflags = first_flags;
3142 sflags = d_sample_flags;
3144 } else if (flags & TR_SAMPLE_FLAGS) {
3145 sflags = QT_UINT32 (data + flags_offset);
3147 sflags = d_sample_flags;
3149 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
3150 ct = QT_UINT32 (data + ct_offset);
3156 /* fill the sample information */
3157 sample->offset = *running_offset;
3158 sample->pts_offset = ct;
3159 sample->size = size;
3160 sample->timestamp = timestamp;
3161 sample->duration = dur;
3162 /* sample-is-difference-sample */
3163 /* ismv seems to use 0x40 for keyframe, 0xc0 for non-keyframe,
3164 * now idea how it relates to bitfield other than massive LE/BE confusion */
3165 sample->keyframe = ismv ? ((sflags & 0xff) == 0x40) : !(sflags & 0x10000);
3166 *running_offset += size;
3168 stream->duration_moof += dur;
3172 /* Update total duration if needed */
3173 check_update_duration (qtdemux, QTSTREAMTIME_TO_GSTTIME (stream, timestamp));
3175 stream->n_samples += samples_count;
3176 stream->n_samples_moof += samples_count;
3178 if (stream->pending_seek != NULL)
3179 stream->pending_seek = NULL;
3185 GST_WARNING_OBJECT (qtdemux, "failed to parse trun");
3190 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
3196 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
3197 "be larger than %uMB (broken file?)", stream->n_samples,
3198 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
3203 /* find stream with @id */
3204 static inline QtDemuxStream *
3205 qtdemux_find_stream (GstQTDemux * qtdemux, guint32 id)
3207 QtDemuxStream *stream;
3211 if (G_UNLIKELY (!id)) {
3212 GST_DEBUG_OBJECT (qtdemux, "invalid track id 0");
3216 /* try to get it fast and simple */
3217 if (G_LIKELY (id <= qtdemux->n_streams)) {
3218 stream = qtdemux->streams[id - 1];
3219 if (G_LIKELY (stream->track_id == id))
3223 /* linear search otherwise */
3224 for (i = 0; i < qtdemux->n_streams; i++) {
3225 stream = qtdemux->streams[i];
3226 if (stream->track_id == id)
3229 if (qtdemux->mss_mode) {
3230 /* mss should have only 1 stream anyway */
3231 return qtdemux->streams[0];
3238 qtdemux_parse_mfhd (GstQTDemux * qtdemux, GstByteReader * mfhd,
3239 guint32 * fragment_number)
3241 if (!gst_byte_reader_skip (mfhd, 4))
3243 if (!gst_byte_reader_get_uint32_be (mfhd, fragment_number))
3248 GST_WARNING_OBJECT (qtdemux, "Failed to parse mfhd atom");
3254 qtdemux_parse_tfhd (GstQTDemux * qtdemux, GstByteReader * tfhd,
3255 QtDemuxStream ** stream, guint32 * default_sample_duration,
3256 guint32 * default_sample_size, guint32 * default_sample_flags,
3257 gint64 * base_offset)
3260 guint32 track_id = 0;
3262 if (!gst_byte_reader_skip (tfhd, 1) ||
3263 !gst_byte_reader_get_uint24_be (tfhd, &flags))
3266 if (!gst_byte_reader_get_uint32_be (tfhd, &track_id))
3269 *stream = qtdemux_find_stream (qtdemux, track_id);
3270 if (G_UNLIKELY (!*stream))
3271 goto unknown_stream;
3273 if (flags & TF_DEFAULT_BASE_IS_MOOF)
3274 *base_offset = qtdemux->moof_offset;
3276 if (flags & TF_BASE_DATA_OFFSET)
3277 if (!gst_byte_reader_get_uint64_be (tfhd, (guint64 *) base_offset))
3280 /* obtain stream defaults */
3281 qtdemux_parse_trex (qtdemux, *stream,
3282 default_sample_duration, default_sample_size, default_sample_flags);
3284 /* FIXME: Handle TF_SAMPLE_DESCRIPTION_INDEX properly */
3285 if (flags & TF_SAMPLE_DESCRIPTION_INDEX)
3286 if (!gst_byte_reader_skip (tfhd, 4))
3289 if (flags & TF_DEFAULT_SAMPLE_DURATION)
3290 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_duration))
3293 if (flags & TF_DEFAULT_SAMPLE_SIZE)
3294 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_size))
3297 if (flags & TF_DEFAULT_SAMPLE_FLAGS)
3298 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_flags))
3305 GST_WARNING_OBJECT (qtdemux, "invalid track fragment header");
3310 GST_DEBUG_OBJECT (qtdemux, "unknown stream in tfhd");
3316 qtdemux_parse_tfdt (GstQTDemux * qtdemux, GstByteReader * br,
3317 guint64 * decode_time)
3319 guint32 version = 0;
3321 if (!gst_byte_reader_get_uint32_be (br, &version))
3326 if (!gst_byte_reader_get_uint64_be (br, decode_time))
3329 guint32 dec_time = 0;
3330 if (!gst_byte_reader_get_uint32_be (br, &dec_time))
3332 *decode_time = dec_time;
3335 GST_INFO_OBJECT (qtdemux, "Track fragment decode time: %" G_GUINT64_FORMAT,
3342 GST_DEBUG_OBJECT (qtdemux, "parsing tfdt failed");
3347 /* Returns a pointer to a GstStructure containing the properties of
3348 * the stream sample identified by @sample_index. The caller must unref
3349 * the returned object after use. Returns NULL if unsuccessful. */
3350 static GstStructure *
3351 qtdemux_get_cenc_sample_properties (GstQTDemux * qtdemux,
3352 QtDemuxStream * stream, guint sample_index)
3354 QtDemuxCencSampleSetInfo *info = NULL;
3356 g_return_val_if_fail (stream != NULL, NULL);
3357 g_return_val_if_fail (stream->protected, NULL);
3358 g_return_val_if_fail (stream->protection_scheme_info != NULL, NULL);
3360 info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
3362 /* Currently, cenc properties for groups of samples are not supported, so
3363 * simply return a copy of the default sample properties */
3364 return gst_structure_copy (info->default_properties);
3367 /* Parses the sizes of sample auxiliary information contained within a stream,
3368 * as given in a saiz box. Returns array of sample_count guint8 size values,
3369 * or NULL on failure */
3371 qtdemux_parse_saiz (GstQTDemux * qtdemux, QtDemuxStream * stream,
3372 GstByteReader * br, guint32 * sample_count)
3376 guint8 default_info_size;
3378 g_return_val_if_fail (qtdemux != NULL, NULL);
3379 g_return_val_if_fail (stream != NULL, NULL);
3380 g_return_val_if_fail (br != NULL, NULL);
3381 g_return_val_if_fail (sample_count != NULL, NULL);
3383 if (!gst_byte_reader_get_uint32_be (br, &flags))
3387 /* aux_info_type and aux_info_type_parameter are ignored */
3388 if (!gst_byte_reader_skip (br, 8))
3392 if (!gst_byte_reader_get_uint8 (br, &default_info_size))
3394 GST_DEBUG_OBJECT (qtdemux, "default_info_size: %u", default_info_size);
3396 if (!gst_byte_reader_get_uint32_be (br, sample_count))
3398 GST_DEBUG_OBJECT (qtdemux, "sample_count: %u", *sample_count);
3401 if (default_info_size == 0) {
3402 if (!gst_byte_reader_dup_data (br, *sample_count, &info_sizes)) {
3406 info_sizes = g_new (guint8, *sample_count);
3407 memset (info_sizes, default_info_size, *sample_count);
3413 /* Parses the offset of sample auxiliary information contained within a stream,
3414 * as given in a saio box. Returns TRUE if successful; FALSE otherwise. */
3416 qtdemux_parse_saio (GstQTDemux * qtdemux, QtDemuxStream * stream,
3417 GstByteReader * br, guint32 * info_type, guint32 * info_type_parameter,
3422 guint32 aux_info_type = 0;
3423 guint32 aux_info_type_parameter = 0;
3424 guint32 entry_count;
3427 const guint8 *aux_info_type_data = NULL;
3429 g_return_val_if_fail (qtdemux != NULL, FALSE);
3430 g_return_val_if_fail (stream != NULL, FALSE);
3431 g_return_val_if_fail (br != NULL, FALSE);
3432 g_return_val_if_fail (offset != NULL, FALSE);
3434 if (!gst_byte_reader_get_uint8 (br, &version))
3437 if (!gst_byte_reader_get_uint24_be (br, &flags))
3442 if (!gst_byte_reader_get_data (br, 4, &aux_info_type_data))
3444 aux_info_type = QT_FOURCC (aux_info_type_data);
3446 if (!gst_byte_reader_get_uint32_be (br, &aux_info_type_parameter))
3448 } else if (stream->protected) {
3449 aux_info_type = stream->protection_scheme_type;
3451 aux_info_type = stream->fourcc;
3455 *info_type = aux_info_type;
3456 if (info_type_parameter)
3457 *info_type_parameter = aux_info_type_parameter;
3459 GST_DEBUG_OBJECT (qtdemux, "aux_info_type: '%" GST_FOURCC_FORMAT "', "
3460 "aux_info_type_parameter: %#06x",
3461 GST_FOURCC_ARGS (aux_info_type), aux_info_type_parameter);
3463 if (!gst_byte_reader_get_uint32_be (br, &entry_count))
3466 if (entry_count != 1) {
3467 GST_ERROR_OBJECT (qtdemux, "multiple offsets are not supported");
3472 if (!gst_byte_reader_get_uint32_be (br, &off_32))
3474 *offset = (guint64) off_32;
3476 if (!gst_byte_reader_get_uint64_be (br, &off_64))
3481 GST_DEBUG_OBJECT (qtdemux, "offset: %" G_GUINT64_FORMAT, *offset);
3486 qtdemux_gst_structure_free (GstStructure * gststructure)
3489 gst_structure_free (gststructure);
3493 /* Parses auxiliary information relating to samples protected using Common
3494 * Encryption (cenc); the format of this information is defined in
3495 * ISO/IEC 23001-7. Returns TRUE if successful; FALSE otherwise. */
3497 qtdemux_parse_cenc_aux_info (GstQTDemux * qtdemux, QtDemuxStream * stream,
3498 GstByteReader * br, guint8 * info_sizes, guint32 sample_count)
3500 QtDemuxCencSampleSetInfo *ss_info = NULL;
3504 g_return_val_if_fail (qtdemux != NULL, FALSE);
3505 g_return_val_if_fail (stream != NULL, FALSE);
3506 g_return_val_if_fail (br != NULL, FALSE);
3507 g_return_val_if_fail (stream->protected, FALSE);
3508 g_return_val_if_fail (stream->protection_scheme_info != NULL, FALSE);
3510 ss_info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
3512 if (ss_info->crypto_info) {
3513 GST_LOG_OBJECT (qtdemux, "unreffing existing crypto_info");
3514 g_ptr_array_free (ss_info->crypto_info, TRUE);
3517 ss_info->crypto_info =
3518 g_ptr_array_new_full (sample_count,
3519 (GDestroyNotify) qtdemux_gst_structure_free);
3521 for (i = 0; i < sample_count; ++i) {
3522 GstStructure *properties;
3523 guint16 n_subsamples = 0;
3528 properties = qtdemux_get_cenc_sample_properties (qtdemux, stream, i);
3529 if (properties == NULL) {
3530 GST_ERROR_OBJECT (qtdemux, "failed to get properties for sample %u", i);
3533 if (!gst_structure_get_uint (properties, "iv_size", &iv_size)) {
3534 GST_ERROR_OBJECT (qtdemux, "failed to get iv_size for sample %u", i);
3535 gst_structure_free (properties);
3538 if (!gst_byte_reader_dup_data (br, iv_size, &data)) {
3539 GST_ERROR_OBJECT (qtdemux, "failed to get IV for sample %u", i);
3540 gst_structure_free (properties);
3543 buf = gst_buffer_new_wrapped (data, iv_size);
3544 gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL);
3545 gst_buffer_unref (buf);
3546 size = info_sizes[i];
3547 if (size > iv_size) {
3548 if (!gst_byte_reader_get_uint16_be (br, &n_subsamples)
3549 || !(n_subsamples > 0)) {
3550 gst_structure_free (properties);
3551 GST_ERROR_OBJECT (qtdemux,
3552 "failed to get subsample count for sample %u", i);
3555 GST_LOG_OBJECT (qtdemux, "subsample count: %u", n_subsamples);
3556 if (!gst_byte_reader_dup_data (br, n_subsamples * 6, &data)) {
3557 GST_ERROR_OBJECT (qtdemux, "failed to get subsample data for sample %u",
3559 gst_structure_free (properties);
3562 buf = gst_buffer_new_wrapped (data, n_subsamples * 6);
3564 gst_structure_free (properties);
3567 gst_structure_set (properties,
3568 "subsample_count", G_TYPE_UINT, n_subsamples,
3569 "subsamples", GST_TYPE_BUFFER, buf, NULL);
3570 gst_buffer_unref (buf);
3572 gst_structure_set (properties, "subsample_count", G_TYPE_UINT, 0, NULL);
3574 g_ptr_array_add (ss_info->crypto_info, properties);
3579 /* Converts a UUID in raw byte form to a string representation, as defined in
3580 * RFC 4122. The caller takes ownership of the returned string and is
3581 * responsible for freeing it after use. */
3583 qtdemux_uuid_bytes_to_string (gconstpointer uuid_bytes)
3585 const guint8 *uuid = (const guint8 *) uuid_bytes;
3587 return g_strdup_printf ("%02x%02x%02x%02x-%02x%02x-%02x%02x-"
3588 "%02x%02x-%02x%02x%02x%02x%02x%02x",
3589 uuid[0], uuid[1], uuid[2], uuid[3],
3590 uuid[4], uuid[5], uuid[6], uuid[7],
3591 uuid[8], uuid[9], uuid[10], uuid[11],
3592 uuid[12], uuid[13], uuid[14], uuid[15]);
3595 /* Parses a Protection System Specific Header box (pssh), as defined in the
3596 * Common Encryption (cenc) standard (ISO/IEC 23001-7), which contains
3597 * information needed by a specific content protection system in order to
3598 * decrypt cenc-protected tracks. Returns TRUE if successful; FALSE
3601 qtdemux_parse_pssh (GstQTDemux * qtdemux, GNode * node)
3603 gchar *sysid_string;
3604 guint32 pssh_size = QT_UINT32 (node->data);
3605 GstBuffer *pssh = NULL;
3606 GstEvent *event = NULL;
3607 guint32 parent_box_type;
3610 if (G_UNLIKELY (pssh_size < 32U)) {
3611 GST_ERROR_OBJECT (qtdemux, "invalid box size");
3616 qtdemux_uuid_bytes_to_string ((const guint8 *) node->data + 12);
3618 gst_qtdemux_append_protection_system_id (qtdemux, sysid_string);
3620 pssh = gst_buffer_new_wrapped (g_memdup (node->data, pssh_size), pssh_size);
3621 GST_LOG_OBJECT (qtdemux, "cenc pssh size: %" G_GSIZE_FORMAT,
3622 gst_buffer_get_size (pssh));
3624 parent_box_type = QT_FOURCC ((const guint8 *) node->parent->data + 4);
3626 /* Push an event containing the pssh box onto the queues of all streams. */
3627 event = gst_event_new_protection (sysid_string, pssh,
3628 (parent_box_type == FOURCC_moov) ? "isobmff/moov" : "isobmff/moof");
3629 for (i = 0; i < qtdemux->n_streams; ++i) {
3630 g_queue_push_tail (&qtdemux->streams[i]->protection_scheme_event_queue,
3631 gst_event_ref (event));
3633 g_free (sysid_string);
3634 gst_event_unref (event);
3635 gst_buffer_unref (pssh);
3640 qtdemux_parse_moof (GstQTDemux * qtdemux, const guint8 * buffer, guint length,
3641 guint64 moof_offset, QtDemuxStream * stream)
3643 GNode *moof_node, *traf_node, *tfhd_node, *trun_node, *tfdt_node, *mfhd_node;
3645 GstByteReader mfhd_data, trun_data, tfhd_data, tfdt_data;
3646 GNode *saiz_node, *saio_node, *pssh_node;
3647 GstByteReader saiz_data, saio_data;
3648 guint32 ds_size = 0, ds_duration = 0, ds_flags = 0;
3649 gint64 base_offset, running_offset;
3652 /* NOTE @stream ignored */
3654 moof_node = g_node_new ((guint8 *) buffer);
3655 qtdemux_parse_node (qtdemux, moof_node, buffer, length);
3656 qtdemux_node_dump (qtdemux, moof_node);
3658 /* Get fragment number from mfhd and check it's valid */
3660 qtdemux_tree_get_child_by_type_full (moof_node, FOURCC_mfhd, &mfhd_data);
3661 if (mfhd_node == NULL)
3663 if (!qtdemux_parse_mfhd (qtdemux, &mfhd_data, &frag_num))
3665 GST_DEBUG_OBJECT (qtdemux, "Fragment #%d", frag_num);
3667 /* unknown base_offset to start with */
3668 base_offset = running_offset = -1;
3669 traf_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_traf);
3671 guint64 decode_time = 0;
3673 /* Fragment Header node */
3675 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfhd,
3679 if (!qtdemux_parse_tfhd (qtdemux, &tfhd_data, &stream, &ds_duration,
3680 &ds_size, &ds_flags, &base_offset))
3683 /* The following code assumes at most a single set of sample auxiliary
3684 * data in the fragment (consisting of a saiz box and a corresponding saio
3685 * box); in theory, however, there could be multiple sets of sample
3686 * auxiliary data in a fragment. */
3688 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saiz,
3691 guint32 info_type = 0;
3693 guint32 info_type_parameter = 0;
3695 g_free (qtdemux->cenc_aux_info_sizes);
3697 qtdemux->cenc_aux_info_sizes =
3698 qtdemux_parse_saiz (qtdemux, stream, &saiz_data,
3699 &qtdemux->cenc_aux_sample_count);
3700 if (qtdemux->cenc_aux_info_sizes == NULL) {
3701 GST_ERROR_OBJECT (qtdemux, "failed to parse saiz box");
3705 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saio,
3708 GST_ERROR_OBJECT (qtdemux, "saiz box without a corresponding saio box");
3709 g_free (qtdemux->cenc_aux_info_sizes);
3710 qtdemux->cenc_aux_info_sizes = NULL;
3714 if (G_UNLIKELY (!qtdemux_parse_saio (qtdemux, stream, &saio_data,
3715 &info_type, &info_type_parameter, &offset))) {
3716 GST_ERROR_OBJECT (qtdemux, "failed to parse saio box");
3717 g_free (qtdemux->cenc_aux_info_sizes);
3718 qtdemux->cenc_aux_info_sizes = NULL;
3721 if (base_offset > -1 && base_offset > qtdemux->moof_offset)
3722 offset += (guint64) (base_offset - qtdemux->moof_offset);
3723 if (info_type == FOURCC_cenc && info_type_parameter == 0U) {
3725 if (offset > length) {
3726 GST_DEBUG_OBJECT (qtdemux, "cenc auxiliary info stored out of moof");
3727 qtdemux->cenc_aux_info_offset = offset;
3729 gst_byte_reader_init (&br, buffer + offset, length - offset);
3730 if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
3731 qtdemux->cenc_aux_info_sizes,
3732 qtdemux->cenc_aux_sample_count)) {
3733 GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
3734 g_free (qtdemux->cenc_aux_info_sizes);
3735 qtdemux->cenc_aux_info_sizes = NULL;
3743 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfdt,
3746 GstClockTime decode_time_ts;
3748 /* We'll use decode_time to interpolate timestamps
3749 * in case the input timestamps are missing */
3750 qtdemux_parse_tfdt (qtdemux, &tfdt_data, &decode_time);
3752 decode_time_ts = QTSTREAMTIME_TO_GSTTIME (stream, decode_time);
3754 GST_DEBUG_OBJECT (qtdemux, "decode time %" G_GINT64_FORMAT
3755 " (%" GST_TIME_FORMAT ")", decode_time,
3756 GST_TIME_ARGS (decode_time_ts));
3758 /* Discard the fragment buffer timestamp info to avoid using it.
3759 * Rely on tfdt instead as it is more accurate than the timestamp
3760 * that is fetched from a manifest/playlist and is usually
3762 qtdemux->fragment_start = -1;
3765 if (G_UNLIKELY (!stream)) {
3766 /* we lost track of offset, we'll need to regain it,
3767 * but can delay complaining until later or avoid doing so altogether */
3771 if (G_UNLIKELY (base_offset < -1))
3774 if (qtdemux->upstream_format_is_time)
3775 gst_qtdemux_stream_flush_samples_data (qtdemux, stream);
3777 /* initialise moof sample data */
3778 stream->n_samples_moof = 0;
3779 stream->duration_moof = 0;
3781 /* Track Run node */
3783 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_trun,
3786 qtdemux_parse_trun (qtdemux, &trun_data, stream,
3787 ds_duration, ds_size, ds_flags, moof_offset, length, &base_offset,
3788 &running_offset, decode_time);
3789 /* iterate all siblings */
3790 trun_node = qtdemux_tree_get_sibling_by_type_full (trun_node, FOURCC_trun,
3794 uuid_node = qtdemux_tree_get_child_by_type (traf_node, FOURCC_uuid);
3796 guint8 *uuid_buffer = (guint8 *) uuid_node->data;
3797 guint32 box_length = QT_UINT32 (uuid_buffer);
3799 qtdemux_parse_uuid (qtdemux, uuid_buffer, box_length);
3802 /* if no new base_offset provided for next traf,
3803 * base is end of current traf */
3804 base_offset = running_offset;
3805 running_offset = -1;
3807 if (stream->n_samples_moof && stream->duration_moof)
3808 stream->new_caps = TRUE;
3811 /* iterate all siblings */
3812 traf_node = qtdemux_tree_get_sibling_by_type (traf_node, FOURCC_traf);
3815 /* parse any protection system info */
3816 pssh_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_pssh);
3818 GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
3819 qtdemux_parse_pssh (qtdemux, pssh_node);
3820 pssh_node = qtdemux_tree_get_sibling_by_type (pssh_node, FOURCC_pssh);
3823 g_node_destroy (moof_node);
3828 GST_DEBUG_OBJECT (qtdemux, "missing tfhd box");
3833 GST_DEBUG_OBJECT (qtdemux, "Missing mfhd box");
3838 GST_DEBUG_OBJECT (qtdemux, "lost offset");
3843 g_node_destroy (moof_node);
3844 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
3845 (_("This file is corrupt and cannot be played.")), (NULL));
3851 /* might be used if some day we actually use mfra & co
3852 * for random access to fragments,
3853 * but that will require quite some modifications and much less relying
3854 * on a sample array */
3858 qtdemux_parse_tfra (GstQTDemux * qtdemux, GNode * tfra_node)
3860 QtDemuxStream *stream;
3861 guint32 ver_flags, track_id, len, num_entries, i;
3862 guint value_size, traf_size, trun_size, sample_size;
3863 guint64 time = 0, moof_offset = 0;
3865 GstBuffer *buf = NULL;
3870 gst_byte_reader_init (&tfra, tfra_node->data, QT_UINT32 (tfra_node->data));
3872 if (!gst_byte_reader_skip (&tfra, 8))
3875 if (!gst_byte_reader_get_uint32_be (&tfra, &ver_flags))
3878 if (!gst_byte_reader_get_uint32_be (&tfra, &track_id)
3879 || !gst_byte_reader_get_uint32_be (&tfra, &len)
3880 || !gst_byte_reader_get_uint32_be (&tfra, &num_entries))
3883 GST_DEBUG_OBJECT (qtdemux, "parsing tfra box for track id %u", track_id);
3885 stream = qtdemux_find_stream (qtdemux, track_id);
3887 goto unknown_trackid;
3889 value_size = ((ver_flags >> 24) == 1) ? sizeof (guint64) : sizeof (guint32);
3890 sample_size = (len & 3) + 1;
3891 trun_size = ((len & 12) >> 2) + 1;
3892 traf_size = ((len & 48) >> 4) + 1;
3894 GST_DEBUG_OBJECT (qtdemux, "%u entries, sizes: value %u, traf %u, trun %u, "
3895 "sample %u", num_entries, value_size, traf_size, trun_size, sample_size);
3897 if (num_entries == 0)
3900 if (!qt_atom_parser_has_chunks (&tfra, num_entries,
3901 value_size + value_size + traf_size + trun_size + sample_size))
3904 g_free (stream->ra_entries);
3905 stream->ra_entries = g_new (QtDemuxRandomAccessEntry, num_entries);
3906 stream->n_ra_entries = num_entries;
3908 for (i = 0; i < num_entries; i++) {
3909 qt_atom_parser_get_offset (&tfra, value_size, &time);
3910 qt_atom_parser_get_offset (&tfra, value_size, &moof_offset);
3911 qt_atom_parser_get_uint_with_size_unchecked (&tfra, traf_size);
3912 qt_atom_parser_get_uint_with_size_unchecked (&tfra, trun_size);
3913 qt_atom_parser_get_uint_with_size_unchecked (&tfra, sample_size);
3915 time = QTSTREAMTIME_TO_GSTTIME (stream, time);
3917 GST_LOG_OBJECT (qtdemux, "fragment time: %" GST_TIME_FORMAT ", "
3918 " moof_offset: %" G_GUINT64_FORMAT, GST_TIME_ARGS (time), moof_offset);
3920 stream->ra_entries[i].ts = time;
3921 stream->ra_entries[i].moof_offset = moof_offset;
3923 /* don't want to go through the entire file and read all moofs at startup */
3925 ret = gst_qtdemux_pull_atom (qtdemux, moof_offset, 0, &buf);
3926 if (ret != GST_FLOW_OK)
3928 qtdemux_parse_moof (qtdemux, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf),
3929 moof_offset, stream);
3930 gst_buffer_unref (buf);
3934 check_update_duration (qtdemux, time);
3941 GST_WARNING_OBJECT (qtdemux, "Couldn't find stream for track %u", track_id);
3946 GST_WARNING_OBJECT (qtdemux, "broken traf box, ignoring");
3951 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
3957 qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux)
3959 GstMapInfo mfro_map = GST_MAP_INFO_INIT;
3960 GstMapInfo mfra_map = GST_MAP_INFO_INIT;
3961 GstBuffer *mfro = NULL, *mfra = NULL;
3963 gboolean ret = FALSE;
3964 GNode *mfra_node, *tfra_node;
3965 guint64 mfra_offset = 0;
3966 guint32 fourcc, mfra_size;
3969 /* query upstream size in bytes */
3970 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &len))
3971 goto size_query_failed;
3973 /* mfro box should be at the very end of the file */
3974 flow = gst_qtdemux_pull_atom (qtdemux, len - 16, 16, &mfro);
3975 if (flow != GST_FLOW_OK)
3978 gst_buffer_map (mfro, &mfro_map, GST_MAP_READ);
3980 fourcc = QT_FOURCC (mfro_map.data + 4);
3981 if (fourcc != FOURCC_mfro)
3984 GST_INFO_OBJECT (qtdemux, "Found mfro box");
3985 if (mfro_map.size < 16)
3986 goto invalid_mfro_size;
3988 mfra_size = QT_UINT32 (mfro_map.data + 12);
3989 if (mfra_size >= len)
3990 goto invalid_mfra_size;
3992 mfra_offset = len - mfra_size;
3994 GST_INFO_OBJECT (qtdemux, "mfra offset: %" G_GUINT64_FORMAT ", size %u",
3995 mfra_offset, mfra_size);
3997 /* now get and parse mfra box */
3998 flow = gst_qtdemux_pull_atom (qtdemux, mfra_offset, mfra_size, &mfra);
3999 if (flow != GST_FLOW_OK)
4002 gst_buffer_map (mfra, &mfra_map, GST_MAP_READ);
4004 mfra_node = g_node_new ((guint8 *) mfra_map.data);
4005 qtdemux_parse_node (qtdemux, mfra_node, mfra_map.data, mfra_map.size);
4007 tfra_node = qtdemux_tree_get_child_by_type (mfra_node, FOURCC_tfra);
4010 qtdemux_parse_tfra (qtdemux, tfra_node);
4011 /* iterate all siblings */
4012 tfra_node = qtdemux_tree_get_sibling_by_type (tfra_node, FOURCC_tfra);
4014 g_node_destroy (mfra_node);
4016 GST_INFO_OBJECT (qtdemux, "parsed movie fragment random access box (mfra)");
4022 if (mfro_map.memory != NULL)
4023 gst_buffer_unmap (mfro, &mfro_map);
4024 gst_buffer_unref (mfro);
4027 if (mfra_map.memory != NULL)
4028 gst_buffer_unmap (mfra, &mfra_map);
4029 gst_buffer_unref (mfra);
4036 GST_WARNING_OBJECT (qtdemux, "could not query upstream size");
4041 GST_WARNING_OBJECT (qtdemux, "mfro size is too small");
4046 GST_WARNING_OBJECT (qtdemux, "mfra_size in mfro box is invalid");
4051 GST_WARNING_OBJECT (qtdemux, "bogus mfra offset or size, broken file");
4057 add_offset (guint64 offset, guint64 advance)
4059 /* Avoid 64-bit overflow by clamping */
4060 if (offset > G_MAXUINT64 - advance)
4062 return offset + advance;
4065 static GstFlowReturn
4066 gst_qtdemux_loop_state_header (GstQTDemux * qtdemux)
4070 GstBuffer *buf = NULL;
4071 GstFlowReturn ret = GST_FLOW_OK;
4072 guint64 cur_offset = qtdemux->offset;
4075 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, 16, &buf);
4076 if (G_UNLIKELY (ret != GST_FLOW_OK))
4078 gst_buffer_map (buf, &map, GST_MAP_READ);
4079 if (G_LIKELY (map.size >= 8))
4080 extract_initial_length_and_fourcc (map.data, map.size, &length, &fourcc);
4081 gst_buffer_unmap (buf, &map);
4082 gst_buffer_unref (buf);
4084 /* maybe we already got most we needed, so only consider this eof */
4085 if (G_UNLIKELY (length == 0)) {
4086 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
4087 (_("Invalid atom size.")),
4088 ("Header atom '%" GST_FOURCC_FORMAT "' has empty length",
4089 GST_FOURCC_ARGS (fourcc)));
4096 /* record for later parsing when needed */
4097 if (!qtdemux->moof_offset) {
4098 qtdemux->moof_offset = qtdemux->offset;
4100 if (qtdemux_pull_mfro_mfra (qtdemux)) {
4103 qtdemux->offset += length; /* skip moof and keep going */
4105 if (qtdemux->got_moov) {
4106 GST_INFO_OBJECT (qtdemux, "moof header, got moov, done with headers");
4117 GST_LOG_OBJECT (qtdemux,
4118 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
4119 GST_FOURCC_ARGS (fourcc), cur_offset);
4120 qtdemux->offset = add_offset (qtdemux->offset, length);
4125 GstBuffer *moov = NULL;
4127 if (qtdemux->got_moov) {
4128 GST_DEBUG_OBJECT (qtdemux, "Skipping moov atom as we have one already");
4129 qtdemux->offset = add_offset (qtdemux->offset, length);
4133 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, length, &moov);
4134 if (ret != GST_FLOW_OK)
4136 gst_buffer_map (moov, &map, GST_MAP_READ);
4138 if (length != map.size) {
4139 /* Some files have a 'moov' atom at the end of the file which contains
4140 * a terminal 'free' atom where the body of the atom is missing.
4141 * Check for, and permit, this special case.
4143 if (map.size >= 8) {
4144 guint8 *final_data = map.data + (map.size - 8);
4145 guint32 final_length = QT_UINT32 (final_data);
4146 guint32 final_fourcc = QT_FOURCC (final_data + 4);
4148 if (final_fourcc == FOURCC_free
4149 && map.size + final_length - 8 == length) {
4150 /* Ok, we've found that special case. Allocate a new buffer with
4151 * that free atom actually present. */
4152 GstBuffer *newmoov = gst_buffer_new_and_alloc (length);
4153 gst_buffer_fill (newmoov, 0, map.data, map.size);
4154 gst_buffer_memset (newmoov, map.size, 0, final_length - 8);
4155 gst_buffer_unmap (moov, &map);
4156 gst_buffer_unref (moov);
4158 gst_buffer_map (moov, &map, GST_MAP_READ);
4163 if (length != map.size) {
4164 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4165 (_("This file is incomplete and cannot be played.")),
4166 ("We got less than expected (received %" G_GSIZE_FORMAT
4167 ", wanted %u, offset %" G_GUINT64_FORMAT ")", map.size,
4168 (guint) length, cur_offset));
4169 gst_buffer_unmap (moov, &map);
4170 gst_buffer_unref (moov);
4171 ret = GST_FLOW_ERROR;
4174 qtdemux->offset += length;
4176 qtdemux_parse_moov (qtdemux, map.data, length);
4177 qtdemux_node_dump (qtdemux, qtdemux->moov_node);
4179 qtdemux_parse_tree (qtdemux);
4180 g_node_destroy (qtdemux->moov_node);
4181 gst_buffer_unmap (moov, &map);
4182 gst_buffer_unref (moov);
4183 qtdemux->moov_node = NULL;
4184 qtdemux->got_moov = TRUE;
4190 GstBuffer *ftyp = NULL;
4192 /* extract major brand; might come in handy for ISO vs QT issues */
4193 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &ftyp);
4194 if (ret != GST_FLOW_OK)
4196 qtdemux->offset += length;
4197 gst_buffer_map (ftyp, &map, GST_MAP_READ);
4198 qtdemux_parse_ftyp (qtdemux, map.data, map.size);
4199 gst_buffer_unmap (ftyp, &map);
4200 gst_buffer_unref (ftyp);
4205 GstBuffer *uuid = NULL;
4207 /* uuid are extension atoms */
4208 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &uuid);
4209 if (ret != GST_FLOW_OK)
4211 qtdemux->offset += length;
4212 gst_buffer_map (uuid, &map, GST_MAP_READ);
4213 qtdemux_parse_uuid (qtdemux, map.data, map.size);
4214 gst_buffer_unmap (uuid, &map);
4215 gst_buffer_unref (uuid);
4220 GstBuffer *sidx = NULL;
4221 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &sidx);
4222 if (ret != GST_FLOW_OK)
4224 qtdemux->offset += length;
4225 gst_buffer_map (sidx, &map, GST_MAP_READ);
4226 qtdemux_parse_sidx (qtdemux, map.data, map.size);
4227 gst_buffer_unmap (sidx, &map);
4228 gst_buffer_unref (sidx);
4233 GstBuffer *unknown = NULL;
4235 GST_LOG_OBJECT (qtdemux,
4236 "unknown %08x '%" GST_FOURCC_FORMAT "' of size %" G_GUINT64_FORMAT
4237 " at %" G_GUINT64_FORMAT, fourcc, GST_FOURCC_ARGS (fourcc), length,
4239 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &unknown);
4240 if (ret != GST_FLOW_OK)
4242 gst_buffer_map (unknown, &map, GST_MAP_READ);
4243 GST_MEMDUMP ("Unknown tag", map.data, map.size);
4244 gst_buffer_unmap (unknown, &map);
4245 gst_buffer_unref (unknown);
4246 qtdemux->offset += length;
4252 if (ret == GST_FLOW_EOS && (qtdemux->got_moov || qtdemux->media_caps)) {
4253 /* digested all data, show what we have */
4254 qtdemux_prepare_streams (qtdemux);
4255 ret = qtdemux_expose_streams (qtdemux);
4257 qtdemux->state = QTDEMUX_STATE_MOVIE;
4258 GST_DEBUG_OBJECT (qtdemux, "switching state to STATE_MOVIE (%d)",
4265 /* Seeks to the previous keyframe of the indexed stream and
4266 * aligns other streams with respect to the keyframe timestamp
4267 * of indexed stream. Only called in case of Reverse Playback
4269 static GstFlowReturn
4270 gst_qtdemux_seek_to_previous_keyframe (GstQTDemux * qtdemux)
4273 guint32 seg_idx = 0, k_index = 0;
4274 guint32 ref_seg_idx, ref_k_index;
4275 GstClockTime k_pos = 0, last_stop = 0;
4276 QtDemuxSegment *seg = NULL;
4277 QtDemuxStream *ref_str = NULL;
4278 guint64 seg_media_start_mov; /* segment media start time in mov format */
4281 /* Now we choose an arbitrary stream, get the previous keyframe timestamp
4282 * and finally align all the other streams on that timestamp with their
4283 * respective keyframes */
4284 for (n = 0; n < qtdemux->n_streams; n++) {
4285 QtDemuxStream *str = qtdemux->streams[n];
4287 /* No candidate yet, take the first stream */
4293 /* So that stream has a segment, we prefer video streams */
4294 if (str->subtype == FOURCC_vide) {
4300 if (G_UNLIKELY (!ref_str)) {
4301 GST_DEBUG_OBJECT (qtdemux, "couldn't find any stream");
4305 if (G_UNLIKELY (!ref_str->from_sample)) {
4306 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of the file");
4310 /* So that stream has been playing from from_sample to to_sample. We will
4311 * get the timestamp of the previous sample and search for a keyframe before
4312 * that. For audio streams we do an arbitrary jump in the past (10 samples) */
4313 if (ref_str->subtype == FOURCC_vide) {
4314 k_index = gst_qtdemux_find_keyframe (qtdemux, ref_str,
4315 ref_str->from_sample - 1);
4317 if (ref_str->from_sample >= 10)
4318 k_index = ref_str->from_sample - 10;
4324 ref_str->samples[k_index].timestamp +
4325 ref_str->samples[k_index].pts_offset;
4327 /* get current segment for that stream */
4328 seg = &ref_str->segments[ref_str->segment_index];
4329 /* Use segment start in original timescale for comparisons */
4330 seg_media_start_mov = seg->trak_media_start;
4332 GST_LOG_OBJECT (qtdemux, "keyframe index %u ts %" G_GUINT64_FORMAT
4333 " seg start %" G_GUINT64_FORMAT " %" GST_TIME_FORMAT "\n",
4334 k_index, target_ts, seg_media_start_mov,
4335 GST_TIME_ARGS (seg->media_start));
4337 /* Crawl back through segments to find the one containing this I frame */
4338 while (target_ts < seg_media_start_mov) {
4339 GST_DEBUG_OBJECT (qtdemux,
4340 "keyframe position (sample %u) is out of segment %u " " target %"
4341 G_GUINT64_FORMAT " seg start %" G_GUINT64_FORMAT, k_index,
4342 ref_str->segment_index, target_ts, seg_media_start_mov);
4344 if (G_UNLIKELY (!ref_str->segment_index)) {
4345 /* Reached first segment, let's consider it's EOS */
4348 ref_str->segment_index--;
4349 seg = &ref_str->segments[ref_str->segment_index];
4350 /* Use segment start in original timescale for comparisons */
4351 seg_media_start_mov = seg->trak_media_start;
4353 /* Calculate time position of the keyframe and where we should stop */
4355 QTSTREAMTIME_TO_GSTTIME (ref_str,
4356 target_ts - seg->trak_media_start) + seg->time;
4358 QTSTREAMTIME_TO_GSTTIME (ref_str,
4359 ref_str->samples[ref_str->from_sample].timestamp -
4360 seg->trak_media_start) + seg->time;
4362 GST_DEBUG_OBJECT (qtdemux, "preferred stream played from sample %u, "
4363 "now going to sample %u (pts %" GST_TIME_FORMAT ")", ref_str->from_sample,
4364 k_index, GST_TIME_ARGS (k_pos));
4366 /* Set last_stop with the keyframe timestamp we pushed of that stream */
4367 qtdemux->segment.position = last_stop;
4368 GST_DEBUG_OBJECT (qtdemux, "last_stop now is %" GST_TIME_FORMAT,
4369 GST_TIME_ARGS (last_stop));
4371 if (G_UNLIKELY (last_stop < qtdemux->segment.start)) {
4372 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of segment");
4376 ref_seg_idx = ref_str->segment_index;
4377 ref_k_index = k_index;
4379 /* Align them all on this */
4380 for (n = 0; n < qtdemux->n_streams; n++) {
4382 GstClockTime seg_time = 0;
4383 QtDemuxStream *str = qtdemux->streams[n];
4385 /* aligning reference stream again might lead to backing up to yet another
4386 * keyframe (due to timestamp rounding issues),
4387 * potentially putting more load on downstream; so let's try to avoid */
4388 if (str == ref_str) {
4389 seg_idx = ref_seg_idx;
4390 seg = &str->segments[seg_idx];
4391 k_index = ref_k_index;
4392 GST_DEBUG_OBJECT (qtdemux, "reference stream %d segment %d, "
4393 "sample at index %d", n, ref_str->segment_index, k_index);
4395 seg_idx = gst_qtdemux_find_segment (qtdemux, str, k_pos);
4396 GST_DEBUG_OBJECT (qtdemux,
4397 "stream %d align segment %d for keyframe pos %" GST_TIME_FORMAT, n,
4398 seg_idx, GST_TIME_ARGS (k_pos));
4400 /* get segment and time in the segment */
4401 seg = &str->segments[seg_idx];
4402 seg_time = k_pos - seg->time;
4404 /* get the media time in the segment.
4405 * No adjustment for empty "filler" segments */
4406 if (seg->media_start != GST_CLOCK_TIME_NONE)
4407 seg_time += seg->media_start;
4409 /* get the index of the sample with media time */
4410 index = gst_qtdemux_find_index_linear (qtdemux, str, seg_time);
4411 GST_DEBUG_OBJECT (qtdemux,
4412 "stream %d sample for %" GST_TIME_FORMAT " at %u", n,
4413 GST_TIME_ARGS (seg_time), index);
4415 /* find previous keyframe */
4416 k_index = gst_qtdemux_find_keyframe (qtdemux, str, index);
4419 /* Remember until where we want to go */
4420 str->to_sample = str->from_sample - 1;
4421 /* Define our time position */
4423 str->samples[k_index].timestamp + str->samples[k_index].pts_offset;
4424 str->time_position = QTSTREAMTIME_TO_GSTTIME (str, target_ts) + seg->time;
4425 if (seg->media_start != GST_CLOCK_TIME_NONE)
4426 str->time_position -= seg->media_start;
4428 /* Now seek back in time */
4429 gst_qtdemux_move_stream (qtdemux, str, k_index);
4430 GST_DEBUG_OBJECT (qtdemux, "stream %d keyframe at %u, time position %"
4431 GST_TIME_FORMAT " playing from sample %u to %u", n, k_index,
4432 GST_TIME_ARGS (str->time_position), str->from_sample, str->to_sample);
4438 return GST_FLOW_EOS;
4442 * Gets the current qt segment start, stop and position for the
4443 * given time offset. This is used in update_segment()
4446 gst_qtdemux_stream_segment_get_boundaries (GstQTDemux * qtdemux,
4447 QtDemuxStream * stream, GstClockTime offset,
4448 GstClockTime * _start, GstClockTime * _stop, GstClockTime * _time)
4450 GstClockTime seg_time;
4451 GstClockTime start, stop, time;
4452 QtDemuxSegment *segment;
4454 segment = &stream->segments[stream->segment_index];
4456 /* get time in this segment */
4457 seg_time = (offset - segment->time) * segment->rate;
4459 GST_LOG_OBJECT (stream->pad, "seg_time %" GST_TIME_FORMAT,
4460 GST_TIME_ARGS (seg_time));
4462 if (G_UNLIKELY (seg_time > segment->duration)) {
4463 GST_LOG_OBJECT (stream->pad,
4464 "seg_time > segment->duration %" GST_TIME_FORMAT,
4465 GST_TIME_ARGS (segment->duration));
4466 seg_time = segment->duration;
4469 /* qtdemux->segment.stop is in outside-time-realm, whereas
4470 * segment->media_stop is in track-time-realm.
4472 * In order to compare the two, we need to bring segment.stop
4473 * into the track-time-realm
4475 * FIXME - does this comment still hold? Don't see any conversion here */
4477 stop = qtdemux->segment.stop;
4478 if (stop == GST_CLOCK_TIME_NONE)
4479 stop = qtdemux->segment.duration;
4480 if (stop == GST_CLOCK_TIME_NONE)
4481 stop = segment->media_stop;
4484 MIN (segment->media_stop, stop - segment->time + segment->media_start);
4486 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
4487 start = segment->time + seg_time;
4489 stop = start - seg_time + segment->duration;
4490 } else if (qtdemux->segment.rate >= 0) {
4491 start = MIN (segment->media_start + seg_time, stop);
4494 if (segment->media_start >= qtdemux->segment.start) {
4495 time = segment->time;
4497 time = segment->time + (qtdemux->segment.start - segment->media_start);
4500 start = MAX (segment->media_start, qtdemux->segment.start);
4501 stop = MIN (segment->media_start + seg_time, stop);
4510 * Updates the qt segment used for the stream and pushes a new segment event
4511 * downstream on this stream's pad.
4514 gst_qtdemux_stream_update_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
4515 gint seg_idx, GstClockTime offset, GstClockTime * _start,
4516 GstClockTime * _stop)
4518 QtDemuxSegment *segment;
4519 GstClockTime start = 0, stop = GST_CLOCK_TIME_NONE, time = 0;
4523 /* update the current segment */
4524 stream->segment_index = seg_idx;
4526 /* get the segment */
4527 segment = &stream->segments[seg_idx];
4529 if (G_UNLIKELY (offset < segment->time)) {
4530 GST_WARNING_OBJECT (stream->pad, "offset < segment->time %" GST_TIME_FORMAT,
4531 GST_TIME_ARGS (segment->time));
4535 /* segment lies beyond total indicated duration */
4536 if (G_UNLIKELY (qtdemux->segment.duration != GST_CLOCK_TIME_NONE &&
4537 segment->time > qtdemux->segment.duration)) {
4538 GST_WARNING_OBJECT (stream->pad, "file duration %" GST_TIME_FORMAT
4539 " < segment->time %" GST_TIME_FORMAT,
4540 GST_TIME_ARGS (qtdemux->segment.duration),
4541 GST_TIME_ARGS (segment->time));
4545 gst_qtdemux_stream_segment_get_boundaries (qtdemux, stream, offset,
4546 &start, &stop, &time);
4548 GST_DEBUG_OBJECT (stream->pad, "new segment %d from %" GST_TIME_FORMAT
4549 " to %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT, seg_idx,
4550 GST_TIME_ARGS (start), GST_TIME_ARGS (stop), GST_TIME_ARGS (time));
4552 /* combine global rate with that of the segment */
4553 rate = segment->rate * qtdemux->segment.rate;
4555 /* Copy flags from main segment */
4556 stream->segment.flags = qtdemux->segment.flags;
4558 /* update the segment values used for clipping */
4559 stream->segment.offset = qtdemux->segment.offset;
4560 stream->segment.base = qtdemux->segment.base + stream->accumulated_base;
4561 stream->segment.applied_rate = qtdemux->segment.applied_rate;
4562 stream->segment.rate = rate;
4563 stream->segment.start = start + QTSTREAMTIME_TO_GSTTIME (stream,
4564 stream->cslg_shift);
4565 stream->segment.stop = stop + QTSTREAMTIME_TO_GSTTIME (stream,
4566 stream->cslg_shift);
4567 stream->segment.time = time;
4568 stream->segment.position = stream->segment.start;
4570 GST_DEBUG_OBJECT (stream->pad, "New segment: %" GST_SEGMENT_FORMAT,
4573 /* now prepare and send the segment */
4575 event = gst_event_new_segment (&stream->segment);
4576 if (qtdemux->segment_seqnum) {
4577 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
4579 gst_pad_push_event (stream->pad, event);
4580 /* assume we can send more data now */
4581 GST_PAD_LAST_FLOW_RETURN (stream->pad) = GST_FLOW_OK;
4582 /* clear to send tags on this pad now */
4583 gst_qtdemux_push_tags (qtdemux, stream);
4594 /* activate the given segment number @seg_idx of @stream at time @offset.
4595 * @offset is an absolute global position over all the segments.
4597 * This will push out a NEWSEGMENT event with the right values and
4598 * position the stream index to the first decodable sample before
4602 gst_qtdemux_activate_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
4603 guint32 seg_idx, GstClockTime offset)
4605 QtDemuxSegment *segment;
4606 guint32 index, kf_index;
4607 GstClockTime start = 0, stop = GST_CLOCK_TIME_NONE;
4609 GST_LOG_OBJECT (stream->pad, "activate segment %d, offset %" GST_TIME_FORMAT,
4610 seg_idx, GST_TIME_ARGS (offset));
4612 if (!gst_qtdemux_stream_update_segment (qtdemux, stream, seg_idx, offset,
4616 segment = &stream->segments[stream->segment_index];
4618 /* in the fragmented case, we pick a fragment that starts before our
4619 * desired position and rely on downstream to wait for a keyframe
4620 * (FIXME: doesn't seem to work so well with ismv and wmv, as no parser; the
4621 * tfra entries tells us which trun/sample the key unit is in, but we don't
4622 * make use of this additional information at the moment) */
4623 if (qtdemux->fragmented) {
4624 stream->to_sample = G_MAXUINT32;
4628 /* We don't need to look for a sample in push-based */
4629 if (!qtdemux->pullbased)
4632 /* and move to the keyframe before the indicated media time of the
4634 if (G_LIKELY (!QTSEGMENT_IS_EMPTY (segment))) {
4635 if (qtdemux->segment.rate >= 0) {
4636 index = gst_qtdemux_find_index_linear (qtdemux, stream, start);
4637 stream->to_sample = G_MAXUINT32;
4638 GST_DEBUG_OBJECT (stream->pad,
4639 "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
4640 GST_TIME_FORMAT, GST_TIME_ARGS (start), index,
4641 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
4643 index = gst_qtdemux_find_index_linear (qtdemux, stream, stop);
4644 stream->to_sample = index;
4645 GST_DEBUG_OBJECT (stream->pad,
4646 "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
4647 GST_TIME_FORMAT, GST_TIME_ARGS (stop), index,
4648 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
4651 GST_DEBUG_OBJECT (stream->pad, "No need to look for keyframe, "
4652 "this is an empty segment");
4656 /* gst_qtdemux_parse_sample () called from gst_qtdemux_find_index_linear ()
4657 * encountered an error and printed a message so we return appropriately */
4661 /* we're at the right spot */
4662 if (index == stream->sample_index) {
4663 GST_DEBUG_OBJECT (stream->pad, "we are at the right index");
4667 /* find keyframe of the target index */
4668 kf_index = gst_qtdemux_find_keyframe (qtdemux, stream, index);
4671 /* indent does stupid stuff with stream->samples[].timestamp */
4673 /* if we move forwards, we don't have to go back to the previous
4674 * keyframe since we already sent that. We can also just jump to
4675 * the keyframe right before the target index if there is one. */
4676 if (index > stream->sample_index) {
4677 /* moving forwards check if we move past a keyframe */
4678 if (kf_index > stream->sample_index) {
4679 GST_DEBUG_OBJECT (stream->pad,
4680 "moving forwards to keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" )", kf_index,
4681 GST_TIME_ARGS (QTSAMPLE_PTS(stream, &stream->samples[kf_index])),
4682 GST_TIME_ARGS (QTSAMPLE_DTS(stream, &stream->samples[kf_index])));
4683 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
4685 GST_DEBUG_OBJECT (stream->pad,
4686 "moving forwards, keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" ) already sent", kf_index,
4687 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[kf_index])),
4688 GST_TIME_ARGS (QTSAMPLE_DTS (stream, &stream->samples[kf_index])));
4691 GST_DEBUG_OBJECT (stream->pad,
4692 "moving backwards to keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" )", kf_index,
4693 GST_TIME_ARGS (QTSAMPLE_PTS(stream, &stream->samples[kf_index])),
4694 GST_TIME_ARGS (QTSAMPLE_DTS(stream, &stream->samples[kf_index])));
4695 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
4703 /* prepare to get the current sample of @stream, getting essential values.
4705 * This function will also prepare and send the segment when needed.
4707 * Return FALSE if the stream is EOS.
4712 gst_qtdemux_prepare_current_sample (GstQTDemux * qtdemux,
4713 QtDemuxStream * stream, gboolean * empty, guint64 * offset, guint * size,
4714 GstClockTime * dts, GstClockTime * pts, GstClockTime * duration,
4715 gboolean * keyframe)
4717 QtDemuxSample *sample;
4718 GstClockTime time_position;
4721 g_return_val_if_fail (stream != NULL, FALSE);
4723 time_position = stream->time_position;
4724 if (G_UNLIKELY (time_position == GST_CLOCK_TIME_NONE))
4727 seg_idx = stream->segment_index;
4728 if (G_UNLIKELY (seg_idx == -1)) {
4729 /* find segment corresponding to time_position if we are looking
4731 seg_idx = gst_qtdemux_find_segment (qtdemux, stream, time_position);
4734 /* different segment, activate it, sample_index will be set. */
4735 if (G_UNLIKELY (stream->segment_index != seg_idx))
4736 gst_qtdemux_activate_segment (qtdemux, stream, seg_idx, time_position);
4738 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (&stream->segments[stream->
4740 QtDemuxSegment *seg = &stream->segments[stream->segment_index];
4742 GST_LOG_OBJECT (qtdemux, "Empty segment activated,"
4743 " prepare empty sample");
4746 *pts = *dts = time_position;
4747 *duration = seg->duration - (time_position - seg->time);
4754 if (stream->sample_index == -1)
4755 stream->sample_index = 0;
4757 GST_LOG_OBJECT (qtdemux, "segment active, index = %u of %u",
4758 stream->sample_index, stream->n_samples);
4760 if (G_UNLIKELY (stream->sample_index >= stream->n_samples)) {
4761 if (!qtdemux->fragmented)
4764 GST_INFO_OBJECT (qtdemux, "out of samples, trying to add more");
4768 GST_OBJECT_LOCK (qtdemux);
4769 flow = qtdemux_add_fragmented_samples (qtdemux);
4770 GST_OBJECT_UNLOCK (qtdemux);
4772 if (flow != GST_FLOW_OK)
4775 while (stream->sample_index >= stream->n_samples);
4778 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
4779 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
4780 stream->sample_index);
4784 /* now get the info for the sample we're at */
4785 sample = &stream->samples[stream->sample_index];
4787 *dts = QTSAMPLE_DTS (stream, sample);
4788 *pts = QTSAMPLE_PTS (stream, sample);
4789 *offset = sample->offset;
4790 *size = sample->size;
4791 *duration = QTSAMPLE_DUR_DTS (stream, sample, *dts);
4792 *keyframe = QTSAMPLE_KEYFRAME (stream, sample);
4799 stream->time_position = GST_CLOCK_TIME_NONE;
4804 /* move to the next sample in @stream.
4806 * Moves to the next segment when needed.
4809 gst_qtdemux_advance_sample (GstQTDemux * qtdemux, QtDemuxStream * stream)
4811 QtDemuxSample *sample;
4812 QtDemuxSegment *segment;
4814 /* get current segment */
4815 segment = &stream->segments[stream->segment_index];
4817 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
4818 GST_DEBUG_OBJECT (qtdemux, "Empty segment, no samples to advance");
4822 if (G_UNLIKELY (stream->sample_index >= stream->to_sample)) {
4823 /* Mark the stream as EOS */
4824 GST_DEBUG_OBJECT (qtdemux,
4825 "reached max allowed sample %u, mark EOS", stream->to_sample);
4826 stream->time_position = GST_CLOCK_TIME_NONE;
4830 /* move to next sample */
4831 stream->sample_index++;
4832 stream->offset_in_sample = 0;
4834 /* reached the last sample, we need the next segment */
4835 if (G_UNLIKELY (stream->sample_index >= stream->n_samples))
4838 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
4839 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
4840 stream->sample_index);
4844 /* get next sample */
4845 sample = &stream->samples[stream->sample_index];
4847 /* see if we are past the segment */
4848 if (G_UNLIKELY (QTSAMPLE_DTS (stream, sample) >= segment->media_stop))
4851 if (QTSAMPLE_DTS (stream, sample) >= segment->media_start) {
4852 /* inside the segment, update time_position, looks very familiar to
4853 * GStreamer segments, doesn't it? */
4854 stream->time_position =
4855 QTSAMPLE_DTS (stream, sample) - segment->media_start + segment->time;
4857 /* not yet in segment, time does not yet increment. This means
4858 * that we are still prerolling keyframes to the decoder so it can
4859 * decode the first sample of the segment. */
4860 stream->time_position = segment->time;
4864 /* move to the next segment */
4867 GST_DEBUG_OBJECT (qtdemux, "segment %d ended ", stream->segment_index);
4869 if (stream->segment_index == stream->n_segments - 1) {
4870 /* are we at the end of the last segment, we're EOS */
4871 stream->time_position = GST_CLOCK_TIME_NONE;
4873 /* else we're only at the end of the current segment */
4874 stream->time_position = segment->stop_time;
4876 /* make sure we select a new segment */
4878 /* accumulate previous segments */
4879 if (GST_CLOCK_TIME_IS_VALID (stream->segment.stop))
4880 stream->accumulated_base +=
4881 (stream->segment.stop -
4882 stream->segment.start) / ABS (stream->segment.rate);
4884 stream->segment_index = -1;
4889 gst_qtdemux_sync_streams (GstQTDemux * demux)
4893 if (demux->n_streams <= 1)
4896 for (i = 0; i < demux->n_streams; i++) {
4897 QtDemuxStream *stream;
4898 GstClockTime end_time;
4900 stream = demux->streams[i];
4905 /* TODO advance time on subtitle streams here, if any some day */
4907 /* some clips/trailers may have unbalanced streams at the end,
4908 * so send EOS on shorter stream to prevent stalling others */
4910 /* do not mess with EOS if SEGMENT seeking */
4911 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT)
4914 if (demux->pullbased) {
4915 /* loop mode is sample time based */
4916 if (!STREAM_IS_EOS (stream))
4919 /* push mode is byte position based */
4920 if (stream->n_samples &&
4921 stream->samples[stream->n_samples - 1].offset >= demux->offset)
4925 if (stream->sent_eos)
4928 /* only act if some gap */
4929 end_time = stream->segments[stream->n_segments - 1].stop_time;
4930 GST_LOG_OBJECT (demux, "current position: %" GST_TIME_FORMAT
4931 ", stream end: %" GST_TIME_FORMAT,
4932 GST_TIME_ARGS (demux->segment.position), GST_TIME_ARGS (end_time));
4933 if (GST_CLOCK_TIME_IS_VALID (end_time)
4934 && (end_time + 2 * GST_SECOND < demux->segment.position)) {
4937 GST_DEBUG_OBJECT (demux, "sending EOS for stream %s",
4938 GST_PAD_NAME (stream->pad));
4939 stream->sent_eos = TRUE;
4940 event = gst_event_new_eos ();
4941 if (demux->segment_seqnum)
4942 gst_event_set_seqnum (event, demux->segment_seqnum);
4943 gst_pad_push_event (stream->pad, event);
4948 /* EOS and NOT_LINKED need to be combined. This means that we return:
4950 * GST_FLOW_NOT_LINKED: when all pads NOT_LINKED.
4951 * GST_FLOW_EOS: when all pads EOS or NOT_LINKED.
4953 static GstFlowReturn
4954 gst_qtdemux_combine_flows (GstQTDemux * demux, QtDemuxStream * stream,
4957 GST_LOG_OBJECT (demux, "flow return: %s", gst_flow_get_name (ret));
4960 ret = gst_flow_combiner_update_pad_flow (demux->flowcombiner, stream->pad,
4963 ret = gst_flow_combiner_update_flow (demux->flowcombiner, ret);
4965 GST_LOG_OBJECT (demux, "combined flow return: %s", gst_flow_get_name (ret));
4969 /* the input buffer metadata must be writable. Returns NULL when the buffer is
4970 * completely clipped
4972 * Should be used only with raw buffers */
4974 gst_qtdemux_clip_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
4977 guint64 start, stop, cstart, cstop, diff;
4978 GstClockTime pts, duration;
4980 gint num_rate, denom_rate;
4985 osize = size = gst_buffer_get_size (buf);
4988 /* depending on the type, setup the clip parameters */
4989 if (stream->subtype == FOURCC_soun) {
4990 frame_size = stream->bytes_per_frame;
4991 num_rate = GST_SECOND;
4992 denom_rate = (gint) stream->rate;
4994 } else if (stream->subtype == FOURCC_vide) {
4996 num_rate = stream->fps_n;
4997 denom_rate = stream->fps_d;
5002 if (frame_size <= 0)
5003 goto bad_frame_size;
5005 /* we can only clip if we have a valid pts */
5006 pts = GST_BUFFER_PTS (buf);
5007 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (pts)))
5010 duration = GST_BUFFER_DURATION (buf);
5012 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (duration))) {
5014 gst_util_uint64_scale_int (size / frame_size, num_rate, denom_rate);
5018 stop = start + duration;
5020 if (G_UNLIKELY (!gst_segment_clip (&stream->segment,
5021 GST_FORMAT_TIME, start, stop, &cstart, &cstop)))
5024 /* see if some clipping happened */
5025 diff = cstart - start;
5031 /* bring clipped time to samples and to bytes */
5032 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
5035 GST_DEBUG_OBJECT (qtdemux,
5036 "clipping start to %" GST_TIME_FORMAT " %"
5037 G_GUINT64_FORMAT " bytes", GST_TIME_ARGS (cstart), diff);
5043 diff = stop - cstop;
5048 /* bring clipped time to samples and then to bytes */
5049 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
5051 GST_DEBUG_OBJECT (qtdemux,
5052 "clipping stop to %" GST_TIME_FORMAT " %" G_GUINT64_FORMAT
5053 " bytes", GST_TIME_ARGS (cstop), diff);
5058 if (offset != 0 || size != osize)
5059 gst_buffer_resize (buf, offset, size);
5061 GST_BUFFER_DTS (buf) = GST_CLOCK_TIME_NONE;
5062 GST_BUFFER_PTS (buf) = pts;
5063 GST_BUFFER_DURATION (buf) = duration;
5067 /* dropped buffer */
5070 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
5075 GST_DEBUG_OBJECT (qtdemux, "bad frame size");
5080 GST_DEBUG_OBJECT (qtdemux, "no pts on buffer");
5085 GST_DEBUG_OBJECT (qtdemux, "clipped buffer");
5086 gst_buffer_unref (buf);
5091 /* the input buffer metadata must be writable,
5092 * but time/duration etc not yet set and need not be preserved */
5094 gst_qtdemux_process_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
5101 /* not many cases for now */
5102 if (G_UNLIKELY (stream->fourcc == FOURCC_mp4s)) {
5103 /* send a one time dvd clut event */
5104 if (stream->pending_event && stream->pad)
5105 gst_pad_push_event (stream->pad, stream->pending_event);
5106 stream->pending_event = NULL;
5109 if (G_UNLIKELY (stream->subtype != FOURCC_text
5110 && stream->subtype != FOURCC_sbtl &&
5111 stream->subtype != FOURCC_subp)) {
5115 gst_buffer_map (buf, &map, GST_MAP_READ);
5117 /* empty buffer is sent to terminate previous subtitle */
5118 if (map.size <= 2) {
5119 gst_buffer_unmap (buf, &map);
5120 gst_buffer_unref (buf);
5123 if (stream->subtype == FOURCC_subp) {
5124 /* That's all the processing needed for subpictures */
5125 gst_buffer_unmap (buf, &map);
5129 nsize = GST_READ_UINT16_BE (map.data);
5130 nsize = MIN (nsize, map.size - 2);
5132 GST_LOG_OBJECT (qtdemux, "3GPP timed text subtitle: %d/%" G_GSIZE_FORMAT "",
5135 /* takes care of UTF-8 validation or UTF-16 recognition,
5136 * no other encoding expected */
5137 str = gst_tag_freeform_string_to_utf8 ((gchar *) map.data + 2, nsize, NULL);
5138 gst_buffer_unmap (buf, &map);
5140 gst_buffer_unref (buf);
5141 buf = _gst_buffer_new_wrapped (str, strlen (str), g_free);
5143 /* this should not really happen unless the subtitle is corrupted */
5144 gst_buffer_unref (buf);
5148 /* FIXME ? convert optional subsequent style info to markup */
5153 /* Sets a buffer's attributes properly and pushes it downstream.
5154 * Also checks for additional actions and custom processing that may
5155 * need to be done first.
5157 static GstFlowReturn
5158 gst_qtdemux_decorate_and_push_buffer (GstQTDemux * qtdemux,
5159 QtDemuxStream * stream, GstBuffer * buf,
5160 GstClockTime dts, GstClockTime pts, GstClockTime duration,
5161 gboolean keyframe, GstClockTime position, guint64 byte_position)
5163 GstFlowReturn ret = GST_FLOW_OK;
5165 /* offset the timestamps according to the edit list */
5167 if (G_UNLIKELY (stream->fourcc == FOURCC_rtsp)) {
5171 gst_buffer_map (buf, &map, GST_MAP_READ);
5172 url = g_strndup ((gchar *) map.data, map.size);
5173 gst_buffer_unmap (buf, &map);
5174 if (url != NULL && strlen (url) != 0) {
5175 /* we have RTSP redirect now */
5176 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
5177 gst_message_new_element (GST_OBJECT_CAST (qtdemux),
5178 gst_structure_new ("redirect",
5179 "new-location", G_TYPE_STRING, url, NULL)));
5180 qtdemux->posted_redirect = TRUE;
5182 GST_WARNING_OBJECT (qtdemux, "Redirect URI of stream is empty, not "
5188 /* position reporting */
5189 if (qtdemux->segment.rate >= 0) {
5190 qtdemux->segment.position = position;
5191 gst_qtdemux_sync_streams (qtdemux);
5194 if (G_UNLIKELY (!stream->pad)) {
5195 GST_DEBUG_OBJECT (qtdemux, "No output pad for stream, ignoring");
5196 gst_buffer_unref (buf);
5200 /* send out pending buffers */
5201 while (stream->buffers) {
5202 GstBuffer *buffer = (GstBuffer *) stream->buffers->data;
5204 if (G_UNLIKELY (stream->discont)) {
5205 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
5206 GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
5207 stream->discont = FALSE;
5209 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
5212 gst_pad_push (stream->pad, buffer);
5214 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
5217 /* we're going to modify the metadata */
5218 buf = gst_buffer_make_writable (buf);
5220 if (G_UNLIKELY (stream->need_process))
5221 buf = gst_qtdemux_process_buffer (qtdemux, stream, buf);
5227 GST_BUFFER_DTS (buf) = dts;
5228 GST_BUFFER_PTS (buf) = pts;
5229 GST_BUFFER_DURATION (buf) = duration;
5230 GST_BUFFER_OFFSET (buf) = -1;
5231 GST_BUFFER_OFFSET_END (buf) = -1;
5233 if (G_UNLIKELY (stream->rgb8_palette))
5234 gst_buffer_append_memory (buf, gst_memory_ref (stream->rgb8_palette));
5236 if (G_UNLIKELY (stream->padding)) {
5237 gst_buffer_resize (buf, stream->padding, -1);
5240 if (G_UNLIKELY (qtdemux->element_index)) {
5241 GstClockTime stream_time;
5244 gst_segment_to_stream_time (&stream->segment, GST_FORMAT_TIME,
5246 if (GST_CLOCK_TIME_IS_VALID (stream_time)) {
5247 GST_LOG_OBJECT (qtdemux,
5248 "adding association %" GST_TIME_FORMAT "-> %"
5249 G_GUINT64_FORMAT, GST_TIME_ARGS (stream_time), byte_position);
5250 gst_index_add_association (qtdemux->element_index,
5252 keyframe ? GST_ASSOCIATION_FLAG_KEY_UNIT :
5253 GST_ASSOCIATION_FLAG_DELTA_UNIT, GST_FORMAT_TIME, stream_time,
5254 GST_FORMAT_BYTES, byte_position, NULL);
5259 if (stream->need_clip)
5260 buf = gst_qtdemux_clip_buffer (qtdemux, stream, buf);
5262 if (G_UNLIKELY (buf == NULL))
5265 if (G_UNLIKELY (stream->discont)) {
5266 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
5267 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
5268 stream->discont = FALSE;
5270 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
5274 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
5275 stream->on_keyframe = FALSE;
5277 stream->on_keyframe = TRUE;
5281 GST_LOG_OBJECT (qtdemux,
5282 "Pushing buffer with dts %" GST_TIME_FORMAT ", pts %" GST_TIME_FORMAT
5283 ", duration %" GST_TIME_FORMAT " on pad %s", GST_TIME_ARGS (dts),
5284 GST_TIME_ARGS (pts), GST_TIME_ARGS (duration),
5285 GST_PAD_NAME (stream->pad));
5287 if (stream->protected && stream->protection_scheme_type == FOURCC_cenc) {
5288 GstStructure *crypto_info;
5289 QtDemuxCencSampleSetInfo *info =
5290 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
5294 while ((event = g_queue_pop_head (&stream->protection_scheme_event_queue))) {
5295 gst_pad_push_event (stream->pad, event);
5298 if (qtdemux->cenc_aux_info_offset > 0 && info->crypto_info == NULL) {
5299 GST_DEBUG_OBJECT (qtdemux, "cenc metadata hasn't been parsed yet");
5300 gst_buffer_unref (buf);
5304 index = stream->sample_index - (stream->n_samples - info->crypto_info->len);
5305 if (G_LIKELY (index >= 0 && index < info->crypto_info->len)) {
5306 /* steal structure from array */
5307 crypto_info = g_ptr_array_index (info->crypto_info, index);
5308 g_ptr_array_index (info->crypto_info, index) = NULL;
5309 GST_LOG_OBJECT (qtdemux, "attaching cenc metadata [%u]", index);
5310 if (!crypto_info || !gst_buffer_add_protection_meta (buf, crypto_info))
5311 GST_ERROR_OBJECT (qtdemux, "failed to attach cenc metadata to buffer");
5315 ret = gst_pad_push (stream->pad, buf);
5317 if (GST_CLOCK_TIME_IS_VALID (pts) && GST_CLOCK_TIME_IS_VALID (duration)) {
5318 /* mark position in stream, we'll need this to know when to send GAP event */
5319 stream->segment.position = pts + duration;
5326 static const QtDemuxRandomAccessEntry *
5327 gst_qtdemux_stream_seek_fragment (GstQTDemux * qtdemux, QtDemuxStream * stream,
5328 GstClockTime pos, gboolean after)
5330 QtDemuxRandomAccessEntry *entries = stream->ra_entries;
5331 guint n_entries = stream->n_ra_entries;
5334 /* we assume the table is sorted */
5335 for (i = 0; i < n_entries; ++i) {
5336 if (entries[i].ts > pos)
5340 /* FIXME: maybe save first moof_offset somewhere instead, but for now it's
5341 * probably okay to assume that the index lists the very first fragment */
5348 return &entries[i - 1];
5352 gst_qtdemux_do_fragmented_seek (GstQTDemux * qtdemux)
5354 const QtDemuxRandomAccessEntry *best_entry = NULL;
5357 GST_OBJECT_LOCK (qtdemux);
5359 g_assert (qtdemux->n_streams > 0);
5361 for (i = 0; i < qtdemux->n_streams; i++) {
5362 const QtDemuxRandomAccessEntry *entry;
5363 QtDemuxStream *stream;
5364 gboolean is_audio_or_video;
5366 stream = qtdemux->streams[i];
5368 g_free (stream->samples);
5369 stream->samples = NULL;
5370 stream->n_samples = 0;
5371 stream->stbl_index = -1; /* no samples have yet been parsed */
5372 stream->sample_index = -1;
5374 if (stream->ra_entries == NULL)
5377 if (stream->subtype == FOURCC_vide || stream->subtype == FOURCC_soun)
5378 is_audio_or_video = TRUE;
5380 is_audio_or_video = FALSE;
5383 gst_qtdemux_stream_seek_fragment (qtdemux, stream,
5384 stream->time_position, !is_audio_or_video);
5386 GST_INFO_OBJECT (stream->pad, "%" GST_TIME_FORMAT " at offset "
5387 "%" G_GUINT64_FORMAT, GST_TIME_ARGS (entry->ts), entry->moof_offset);
5389 stream->pending_seek = entry;
5391 /* decide position to jump to just based on audio/video tracks, not subs */
5392 if (!is_audio_or_video)
5395 if (best_entry == NULL || entry->moof_offset < best_entry->moof_offset)
5399 if (best_entry == NULL) {
5400 GST_OBJECT_UNLOCK (qtdemux);
5404 GST_INFO_OBJECT (qtdemux, "seek to %" GST_TIME_FORMAT ", best fragment "
5405 "moof offset: %" G_GUINT64_FORMAT ", ts %" GST_TIME_FORMAT,
5406 GST_TIME_ARGS (qtdemux->streams[0]->time_position),
5407 best_entry->moof_offset, GST_TIME_ARGS (best_entry->ts));
5409 qtdemux->moof_offset = best_entry->moof_offset;
5411 qtdemux_add_fragmented_samples (qtdemux);
5413 GST_OBJECT_UNLOCK (qtdemux);
5417 static GstFlowReturn
5418 gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux)
5420 GstFlowReturn ret = GST_FLOW_OK;
5421 GstBuffer *buf = NULL;
5422 QtDemuxStream *stream;
5423 GstClockTime min_time;
5425 GstClockTime dts = GST_CLOCK_TIME_NONE;
5426 GstClockTime pts = GST_CLOCK_TIME_NONE;
5427 GstClockTime duration = 0;
5428 gboolean keyframe = FALSE;
5429 guint sample_size = 0;
5435 gst_qtdemux_push_pending_newsegment (qtdemux);
5437 if (qtdemux->fragmented_seek_pending) {
5438 GST_INFO_OBJECT (qtdemux, "pending fragmented seek");
5439 gst_qtdemux_do_fragmented_seek (qtdemux);
5440 GST_INFO_OBJECT (qtdemux, "fragmented seek done!");
5441 qtdemux->fragmented_seek_pending = FALSE;
5444 /* Figure out the next stream sample to output, min_time is expressed in
5445 * global time and runs over the edit list segments. */
5446 min_time = G_MAXUINT64;
5448 for (i = 0; i < qtdemux->n_streams; i++) {
5449 GstClockTime position;
5451 stream = qtdemux->streams[i];
5452 position = stream->time_position;
5454 /* position of -1 is EOS */
5455 if (position != GST_CLOCK_TIME_NONE && position < min_time) {
5456 min_time = position;
5461 if (G_UNLIKELY (index == -1)) {
5462 GST_DEBUG_OBJECT (qtdemux, "all streams are EOS");
5466 /* check for segment end */
5467 if (G_UNLIKELY (qtdemux->segment.stop != -1
5468 && ((qtdemux->segment.rate >= 0 && qtdemux->segment.stop <= min_time)
5469 || (qtdemux->segment.rate < 0
5470 && qtdemux->segment.start > min_time))
5471 && qtdemux->streams[index]->on_keyframe)) {
5472 GST_DEBUG_OBJECT (qtdemux, "we reached the end of our segment.");
5473 qtdemux->streams[index]->time_position = GST_CLOCK_TIME_NONE;
5477 /* gap events for subtitle streams */
5478 for (i = 0; i < qtdemux->n_streams; i++) {
5479 stream = qtdemux->streams[i];
5480 if (stream->pad && (stream->subtype == FOURCC_subp
5481 || stream->subtype == FOURCC_text
5482 || stream->subtype == FOURCC_sbtl)) {
5483 /* send one second gap events until the stream catches up */
5484 /* gaps can only be sent after segment is activated (segment.stop is no longer -1) */
5485 while (GST_CLOCK_TIME_IS_VALID (stream->segment.stop) &&
5486 GST_CLOCK_TIME_IS_VALID (stream->segment.position) &&
5487 stream->segment.position + GST_SECOND < min_time) {
5489 gst_event_new_gap (stream->segment.position, GST_SECOND);
5490 gst_pad_push_event (stream->pad, gap);
5491 stream->segment.position += GST_SECOND;
5496 stream = qtdemux->streams[index];
5497 if (stream->new_caps) {
5498 gst_qtdemux_configure_stream (qtdemux, stream);
5499 qtdemux_do_allocation (qtdemux, stream);
5502 /* fetch info for the current sample of this stream */
5503 if (G_UNLIKELY (!gst_qtdemux_prepare_current_sample (qtdemux, stream, &empty,
5504 &offset, &sample_size, &dts, &pts, &duration, &keyframe)))
5507 /* If we're doing a keyframe-only trickmode, only push keyframes on video streams */
5508 if (G_UNLIKELY (qtdemux->
5509 segment.flags & GST_SEGMENT_FLAG_TRICKMODE_KEY_UNITS)) {
5510 if (stream->subtype == FOURCC_vide && !keyframe) {
5511 GST_LOG_OBJECT (qtdemux, "Skipping non-keyframe on stream %d", index);
5516 GST_DEBUG_OBJECT (qtdemux,
5517 "pushing from stream %d, empty %d offset %" G_GUINT64_FORMAT
5518 ", size %d, dts=%" GST_TIME_FORMAT ", pts=%" GST_TIME_FORMAT
5519 ", duration %" GST_TIME_FORMAT, index, empty, offset, sample_size,
5520 GST_TIME_ARGS (dts), GST_TIME_ARGS (pts), GST_TIME_ARGS (duration));
5522 if (G_UNLIKELY (empty)) {
5523 /* empty segment, push a gap and move to the next one */
5524 gst_pad_push_event (stream->pad, gst_event_new_gap (pts, duration));
5525 stream->segment.position = pts + duration;
5529 /* hmm, empty sample, skip and move to next sample */
5530 if (G_UNLIKELY (sample_size <= 0))
5533 /* last pushed sample was out of boundary, goto next sample */
5534 if (G_UNLIKELY (GST_PAD_LAST_FLOW_RETURN (stream->pad) == GST_FLOW_EOS))
5537 if (stream->max_buffer_size == 0 || sample_size <= stream->max_buffer_size) {
5540 GST_DEBUG_OBJECT (qtdemux,
5541 "size %d larger than stream max_buffer_size %d, trimming",
5542 sample_size, stream->max_buffer_size);
5544 MIN (sample_size - stream->offset_in_sample, stream->max_buffer_size);
5547 if (qtdemux->cenc_aux_info_offset > 0) {
5550 GstBuffer *aux_info = NULL;
5552 /* pull the data stored before the sample */
5554 gst_qtdemux_pull_atom (qtdemux, qtdemux->offset,
5555 offset + stream->offset_in_sample - qtdemux->offset, &aux_info);
5556 if (G_UNLIKELY (ret != GST_FLOW_OK))
5558 gst_buffer_map (aux_info, &map, GST_MAP_READ);
5559 GST_DEBUG_OBJECT (qtdemux, "parsing cenc auxiliary info");
5560 gst_byte_reader_init (&br, map.data + 8, map.size);
5561 if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
5562 qtdemux->cenc_aux_info_sizes, qtdemux->cenc_aux_sample_count)) {
5563 GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
5564 gst_buffer_unmap (aux_info, &map);
5565 gst_buffer_unref (aux_info);
5566 ret = GST_FLOW_ERROR;
5569 gst_buffer_unmap (aux_info, &map);
5570 gst_buffer_unref (aux_info);
5573 GST_LOG_OBJECT (qtdemux, "reading %d bytes @ %" G_GUINT64_FORMAT, size,
5576 if (stream->use_allocator) {
5577 /* if we have a per-stream allocator, use it */
5578 buf = gst_buffer_new_allocate (stream->allocator, size, &stream->params);
5581 ret = gst_qtdemux_pull_atom (qtdemux, offset + stream->offset_in_sample,
5583 if (G_UNLIKELY (ret != GST_FLOW_OK))
5586 if (size != sample_size) {
5587 pts += gst_util_uint64_scale_int (GST_SECOND,
5588 stream->offset_in_sample / stream->bytes_per_frame, stream->timescale);
5589 dts += gst_util_uint64_scale_int (GST_SECOND,
5590 stream->offset_in_sample / stream->bytes_per_frame, stream->timescale);
5591 duration = gst_util_uint64_scale_int (GST_SECOND,
5592 size / stream->bytes_per_frame, stream->timescale);
5595 ret = gst_qtdemux_decorate_and_push_buffer (qtdemux, stream, buf,
5596 dts, pts, duration, keyframe, min_time, offset);
5598 if (size != sample_size) {
5599 QtDemuxSample *sample = &stream->samples[stream->sample_index];
5600 QtDemuxSegment *segment = &stream->segments[stream->segment_index];
5602 GstClockTime time_position = QTSTREAMTIME_TO_GSTTIME (stream,
5603 sample->timestamp + stream->offset_in_sample / stream->bytes_per_frame);
5604 if (time_position >= segment->media_start) {
5605 /* inside the segment, update time_position, looks very familiar to
5606 * GStreamer segments, doesn't it? */
5607 stream->time_position = (time_position - segment->media_start) +
5610 /* not yet in segment, time does not yet increment. This means
5611 * that we are still prerolling keyframes to the decoder so it can
5612 * decode the first sample of the segment. */
5613 stream->time_position = segment->time;
5618 ret = gst_qtdemux_combine_flows (qtdemux, stream, ret);
5619 /* ignore unlinked, we will not push on the pad anymore and we will EOS when
5620 * we have no more data for the pad to push */
5621 if (ret == GST_FLOW_EOS)
5624 stream->offset_in_sample += size;
5625 if (stream->offset_in_sample >= sample_size) {
5626 gst_qtdemux_advance_sample (qtdemux, stream);
5631 gst_qtdemux_advance_sample (qtdemux, stream);
5639 GST_DEBUG_OBJECT (qtdemux, "No samples left for any streams - EOS");
5645 GST_DEBUG_OBJECT (qtdemux, "No samples left for stream");
5646 /* EOS will be raised if all are EOS */
5653 gst_qtdemux_loop (GstPad * pad)
5655 GstQTDemux *qtdemux;
5659 qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
5661 cur_offset = qtdemux->offset;
5662 GST_LOG_OBJECT (qtdemux, "loop at position %" G_GUINT64_FORMAT ", state %d",
5663 cur_offset, qtdemux->state);
5665 switch (qtdemux->state) {
5666 case QTDEMUX_STATE_INITIAL:
5667 case QTDEMUX_STATE_HEADER:
5668 ret = gst_qtdemux_loop_state_header (qtdemux);
5670 case QTDEMUX_STATE_MOVIE:
5671 ret = gst_qtdemux_loop_state_movie (qtdemux);
5672 if (qtdemux->segment.rate < 0 && ret == GST_FLOW_EOS) {
5673 ret = gst_qtdemux_seek_to_previous_keyframe (qtdemux);
5681 /* if something went wrong, pause */
5682 if (ret != GST_FLOW_OK)
5686 gst_object_unref (qtdemux);
5692 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
5693 (NULL), ("streaming stopped, invalid state"));
5694 gst_pad_pause_task (pad);
5695 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
5700 const gchar *reason = gst_flow_get_name (ret);
5702 GST_LOG_OBJECT (qtdemux, "pausing task, reason %s", reason);
5704 gst_pad_pause_task (pad);
5706 /* fatal errors need special actions */
5708 if (ret == GST_FLOW_EOS) {
5709 if (qtdemux->n_streams == 0) {
5710 /* we have no streams, post an error */
5711 gst_qtdemux_post_no_playable_stream_error (qtdemux);
5713 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
5716 if ((stop = qtdemux->segment.stop) == -1)
5717 stop = qtdemux->segment.duration;
5719 if (qtdemux->segment.rate >= 0) {
5720 GstMessage *message;
5723 GST_LOG_OBJECT (qtdemux, "Sending segment done, at end of segment");
5724 message = gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
5725 GST_FORMAT_TIME, stop);
5726 event = gst_event_new_segment_done (GST_FORMAT_TIME, stop);
5727 if (qtdemux->segment_seqnum) {
5728 gst_message_set_seqnum (message, qtdemux->segment_seqnum);
5729 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
5731 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), message);
5732 gst_qtdemux_push_event (qtdemux, event);
5734 GstMessage *message;
5737 /* For Reverse Playback */
5738 GST_LOG_OBJECT (qtdemux, "Sending segment done, at start of segment");
5739 message = gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
5740 GST_FORMAT_TIME, qtdemux->segment.start);
5741 event = gst_event_new_segment_done (GST_FORMAT_TIME,
5742 qtdemux->segment.start);
5743 if (qtdemux->segment_seqnum) {
5744 gst_message_set_seqnum (message, qtdemux->segment_seqnum);
5745 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
5747 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), message);
5748 gst_qtdemux_push_event (qtdemux, event);
5753 GST_LOG_OBJECT (qtdemux, "Sending EOS at end of segment");
5754 event = gst_event_new_eos ();
5755 if (qtdemux->segment_seqnum)
5756 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
5757 gst_qtdemux_push_event (qtdemux, event);
5759 } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
5760 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
5761 (NULL), ("streaming stopped, reason %s", reason));
5762 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
5771 * Returns if there are samples to be played.
5774 has_next_entry (GstQTDemux * demux)
5776 QtDemuxStream *stream;
5779 GST_DEBUG_OBJECT (demux, "Checking if there are samples not played yet");
5781 for (i = 0; i < demux->n_streams; i++) {
5782 stream = demux->streams[i];
5784 if (stream->sample_index == -1) {
5785 stream->sample_index = 0;
5786 stream->offset_in_sample = 0;
5789 if (stream->sample_index >= stream->n_samples) {
5790 GST_LOG_OBJECT (demux, "stream %d samples exhausted", i);
5793 GST_DEBUG_OBJECT (demux, "Found a sample");
5797 GST_DEBUG_OBJECT (demux, "There wasn't any next sample");
5804 * Returns the size of the first entry at the current offset.
5805 * If -1, there are none (which means EOS or empty file).
5808 next_entry_size (GstQTDemux * demux)
5810 QtDemuxStream *stream;
5813 guint64 smalloffs = (guint64) - 1;
5814 QtDemuxSample *sample;
5816 GST_LOG_OBJECT (demux, "Finding entry at offset %" G_GUINT64_FORMAT,
5819 for (i = 0; i < demux->n_streams; i++) {
5820 stream = demux->streams[i];
5822 if (stream->sample_index == -1) {
5823 stream->sample_index = 0;
5824 stream->offset_in_sample = 0;
5827 if (stream->sample_index >= stream->n_samples) {
5828 GST_LOG_OBJECT (demux, "stream %d samples exhausted", i);
5832 if (!qtdemux_parse_samples (demux, stream, stream->sample_index)) {
5833 GST_LOG_OBJECT (demux, "Parsing of index %u from stbl atom failed!",
5834 stream->sample_index);
5838 sample = &stream->samples[stream->sample_index];
5840 GST_LOG_OBJECT (demux,
5841 "Checking Stream %d (sample_index:%d / offset:%" G_GUINT64_FORMAT
5842 " / size:%" G_GUINT32_FORMAT ")", i, stream->sample_index,
5843 sample->offset, sample->size);
5845 if (((smalloffs == -1)
5846 || (sample->offset < smalloffs)) && (sample->size)) {
5848 smalloffs = sample->offset;
5852 GST_LOG_OBJECT (demux,
5853 "stream %d offset %" G_GUINT64_FORMAT " demux->offset :%"
5854 G_GUINT64_FORMAT, smallidx, smalloffs, demux->offset);
5859 stream = demux->streams[smallidx];
5860 sample = &stream->samples[stream->sample_index];
5862 if (sample->offset >= demux->offset) {
5863 demux->todrop = sample->offset - demux->offset;
5864 return sample->size + demux->todrop;
5867 GST_DEBUG_OBJECT (demux,
5868 "There wasn't any entry at offset %" G_GUINT64_FORMAT, demux->offset);
5873 gst_qtdemux_post_progress (GstQTDemux * demux, gint num, gint denom)
5875 gint perc = (gint) ((gdouble) num * 100.0 / (gdouble) denom);
5877 gst_element_post_message (GST_ELEMENT_CAST (demux),
5878 gst_message_new_element (GST_OBJECT_CAST (demux),
5879 gst_structure_new ("progress", "percent", G_TYPE_INT, perc, NULL)));
5883 qtdemux_seek_offset (GstQTDemux * demux, guint64 offset)
5888 GST_DEBUG_OBJECT (demux, "Seeking to %" G_GUINT64_FORMAT, offset);
5891 gst_event_new_seek (1.0, GST_FORMAT_BYTES,
5892 GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset,
5893 GST_SEEK_TYPE_NONE, -1);
5895 /* store seqnum to drop flush events, they don't need to reach downstream */
5896 demux->offset_seek_seqnum = gst_event_get_seqnum (event);
5897 res = gst_pad_push_event (demux->sinkpad, event);
5898 demux->offset_seek_seqnum = 0;
5903 /* check for seekable upstream, above and beyond a mere query */
5905 gst_qtdemux_check_seekability (GstQTDemux * demux)
5908 gboolean seekable = FALSE;
5909 gint64 start = -1, stop = -1;
5911 if (demux->upstream_size)
5914 query = gst_query_new_seeking (GST_FORMAT_BYTES);
5915 if (!gst_pad_peer_query (demux->sinkpad, query)) {
5916 GST_DEBUG_OBJECT (demux, "seeking query failed");
5920 gst_query_parse_seeking (query, NULL, &seekable, &start, &stop);
5922 /* try harder to query upstream size if we didn't get it the first time */
5923 if (seekable && stop == -1) {
5924 GST_DEBUG_OBJECT (demux, "doing duration query to fix up unset stop");
5925 gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &stop);
5928 /* if upstream doesn't know the size, it's likely that it's not seekable in
5929 * practice even if it technically may be seekable */
5930 if (seekable && (start != 0 || stop <= start)) {
5931 GST_DEBUG_OBJECT (demux, "seekable but unknown start/stop -> disable");
5936 gst_query_unref (query);
5938 GST_DEBUG_OBJECT (demux, "seekable: %d (%" G_GUINT64_FORMAT " - %"
5939 G_GUINT64_FORMAT ")", seekable, start, stop);
5940 demux->upstream_seekable = seekable;
5941 demux->upstream_size = seekable ? stop : -1;
5945 gst_qtdemux_drop_data (GstQTDemux * demux, gint bytes)
5947 g_return_if_fail (bytes <= demux->todrop);
5949 GST_LOG_OBJECT (demux, "Dropping %d bytes", bytes);
5950 gst_adapter_flush (demux->adapter, bytes);
5951 demux->neededbytes -= bytes;
5952 demux->offset += bytes;
5953 demux->todrop -= bytes;
5957 gst_qtdemux_check_send_pending_segment (GstQTDemux * demux)
5959 if (G_UNLIKELY (demux->pending_newsegment)) {
5962 gst_qtdemux_push_pending_newsegment (demux);
5963 /* clear to send tags on all streams */
5964 for (i = 0; i < demux->n_streams; i++) {
5965 QtDemuxStream *stream;
5966 stream = demux->streams[i];
5967 gst_qtdemux_push_tags (demux, stream);
5968 if (stream->sparse) {
5969 GST_INFO_OBJECT (demux, "Sending gap event on stream %d", i);
5970 gst_pad_push_event (stream->pad,
5971 gst_event_new_gap (stream->segment.position, GST_CLOCK_TIME_NONE));
5978 gst_qtdemux_send_gap_for_segment (GstQTDemux * demux,
5979 QtDemuxStream * stream, gint segment_index, GstClockTime pos)
5981 GstClockTime ts, dur;
5986 stream->segments[segment_index].duration - (pos -
5987 stream->segments[segment_index].time);
5988 gap = gst_event_new_gap (ts, dur);
5989 stream->time_position += dur;
5991 GST_DEBUG_OBJECT (stream->pad, "Pushing gap for empty "
5992 "segment: %" GST_PTR_FORMAT, gap);
5993 gst_pad_push_event (stream->pad, gap);
5997 gst_qtdemux_stream_send_initial_gap_segments (GstQTDemux * demux,
5998 QtDemuxStream * stream)
6002 /* Push any initial gap segments before proceeding to the
6004 for (i = 0; i < stream->n_segments; i++) {
6005 gst_qtdemux_activate_segment (demux, stream, i, stream->time_position);
6007 if (QTSEGMENT_IS_EMPTY (&stream->segments[i])) {
6008 gst_qtdemux_send_gap_for_segment (demux, stream, i,
6009 stream->time_position);
6011 /* Only support empty segment at the beginning followed by
6012 * one non-empty segment, this was checked when parsing the
6013 * edts atom, arriving here is unexpected */
6014 g_assert (i + 1 == stream->n_segments);
6020 static GstFlowReturn
6021 gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent, GstBuffer * inbuf)
6025 demux = GST_QTDEMUX (parent);
6027 if (GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_DISCONT)) {
6030 GST_DEBUG_OBJECT (demux, "Got DISCONT, marking all streams as DISCONT");
6032 for (i = 0; i < demux->n_streams; i++) {
6033 demux->streams[i]->discont = TRUE;
6036 /* Reverse fragmented playback, need to flush all we have before
6037 * consuming a new fragment.
6038 * The samples array have the timestamps calculated by accumulating the
6039 * durations but this won't work for reverse playback of fragments as
6040 * the timestamps of a subsequent fragment should be smaller than the
6041 * previously received one. */
6042 if (demux->fragmented && demux->segment.rate < 0) {
6043 gst_qtdemux_process_adapter (demux, TRUE);
6044 for (i = 0; i < demux->n_streams; i++)
6045 gst_qtdemux_stream_flush_samples_data (demux, demux->streams[i]);
6049 gst_adapter_push (demux->adapter, inbuf);
6051 GST_DEBUG_OBJECT (demux,
6052 "pushing in inbuf %p, neededbytes:%u, available:%" G_GSIZE_FORMAT, inbuf,
6053 demux->neededbytes, gst_adapter_available (demux->adapter));
6055 return gst_qtdemux_process_adapter (demux, FALSE);
6058 static GstFlowReturn
6059 gst_qtdemux_process_adapter (GstQTDemux * demux, gboolean force)
6061 GstFlowReturn ret = GST_FLOW_OK;
6063 /* we never really mean to buffer that much */
6064 if (demux->neededbytes == -1) {
6068 while (((gst_adapter_available (demux->adapter)) >= demux->neededbytes) &&
6069 (ret == GST_FLOW_OK || (ret == GST_FLOW_NOT_LINKED && force))) {
6071 GST_DEBUG_OBJECT (demux,
6072 "state:%d , demux->neededbytes:%d, demux->offset:%" G_GUINT64_FORMAT,
6073 demux->state, demux->neededbytes, demux->offset);
6075 switch (demux->state) {
6076 case QTDEMUX_STATE_INITIAL:{
6081 gst_qtdemux_check_seekability (demux);
6083 data = gst_adapter_map (demux->adapter, demux->neededbytes);
6085 /* get fourcc/length, set neededbytes */
6086 extract_initial_length_and_fourcc ((guint8 *) data, demux->neededbytes,
6088 gst_adapter_unmap (demux->adapter);
6090 GST_DEBUG_OBJECT (demux, "Peeking found [%" GST_FOURCC_FORMAT "] "
6091 "size: %" G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), size);
6093 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
6094 (_("This file is invalid and cannot be played.")),
6095 ("initial atom '%" GST_FOURCC_FORMAT "' has empty length",
6096 GST_FOURCC_ARGS (fourcc)));
6097 ret = GST_FLOW_ERROR;
6100 if (fourcc == FOURCC_mdat) {
6101 gint next_entry = next_entry_size (demux);
6102 if (demux->n_streams > 0 && (next_entry != -1 || !demux->fragmented)) {
6103 /* we have the headers, start playback */
6104 demux->state = QTDEMUX_STATE_MOVIE;
6105 demux->neededbytes = next_entry;
6106 demux->mdatleft = size;
6108 /* no headers yet, try to get them */
6111 guint64 old, target;
6114 old = demux->offset;
6115 target = old + size;
6117 /* try to jump over the atom with a seek */
6118 /* only bother if it seems worth doing so,
6119 * and avoids possible upstream/server problems */
6120 if (demux->upstream_seekable &&
6121 demux->upstream_size > 4 * (1 << 20)) {
6122 res = qtdemux_seek_offset (demux, target);
6124 GST_DEBUG_OBJECT (demux, "skipping seek");
6129 GST_DEBUG_OBJECT (demux, "seek success");
6130 /* remember the offset fo the first mdat so we can seek back to it
6131 * after we have the headers */
6132 if (fourcc == FOURCC_mdat && demux->first_mdat == -1) {
6133 demux->first_mdat = old;
6134 GST_DEBUG_OBJECT (demux, "first mdat at %" G_GUINT64_FORMAT,
6137 /* seek worked, continue reading */
6138 demux->offset = target;
6139 demux->neededbytes = 16;
6140 demux->state = QTDEMUX_STATE_INITIAL;
6142 /* seek failed, need to buffer */
6143 demux->offset = old;
6144 GST_DEBUG_OBJECT (demux, "seek failed/skipped");
6145 /* there may be multiple mdat (or alike) buffers */
6147 if (demux->mdatbuffer)
6148 bs = gst_buffer_get_size (demux->mdatbuffer);
6151 if (size + bs > 10 * (1 << 20))
6153 demux->state = QTDEMUX_STATE_BUFFER_MDAT;
6154 demux->neededbytes = size;
6155 if (!demux->mdatbuffer)
6156 demux->mdatoffset = demux->offset;
6159 } else if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
6160 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
6161 (_("This file is invalid and cannot be played.")),
6162 ("atom %" GST_FOURCC_FORMAT " has bogus size %" G_GUINT64_FORMAT,
6163 GST_FOURCC_ARGS (fourcc), size));
6164 ret = GST_FLOW_ERROR;
6167 /* this means we already started buffering and still no moov header,
6168 * let's continue buffering everything till we get moov */
6169 if (demux->mdatbuffer && !(fourcc == FOURCC_moov
6170 || fourcc == FOURCC_moof))
6172 demux->neededbytes = size;
6173 demux->state = QTDEMUX_STATE_HEADER;
6177 case QTDEMUX_STATE_HEADER:{
6181 GST_DEBUG_OBJECT (demux, "In header");
6183 data = gst_adapter_map (demux->adapter, demux->neededbytes);
6185 /* parse the header */
6186 extract_initial_length_and_fourcc (data, demux->neededbytes, NULL,
6188 if (fourcc == FOURCC_moov) {
6191 /* in usual fragmented setup we could try to scan for more
6192 * and end up at the the moov (after mdat) again */
6193 if (demux->got_moov && demux->n_streams > 0 &&
6195 || demux->last_moov_offset == demux->offset)) {
6196 GST_DEBUG_OBJECT (demux,
6197 "Skipping moov atom as we have (this) one already");
6199 GST_DEBUG_OBJECT (demux, "Parsing [moov]");
6201 if (demux->got_moov && demux->fragmented) {
6202 GST_DEBUG_OBJECT (demux,
6203 "Got a second moov, clean up data from old one");
6204 if (demux->moov_node)
6205 g_node_destroy (demux->moov_node);
6206 demux->moov_node = NULL;
6207 demux->moov_node_compressed = NULL;
6209 /* prepare newsegment to send when streaming actually starts */
6210 if (!demux->pending_newsegment) {
6211 demux->pending_newsegment =
6212 gst_event_new_segment (&demux->segment);
6213 if (demux->segment_seqnum)
6214 gst_event_set_seqnum (demux->pending_newsegment,
6215 demux->segment_seqnum);
6219 demux->last_moov_offset = demux->offset;
6221 qtdemux_parse_moov (demux, data, demux->neededbytes);
6222 qtdemux_node_dump (demux, demux->moov_node);
6223 qtdemux_parse_tree (demux);
6224 qtdemux_prepare_streams (demux);
6225 if (!demux->got_moov)
6226 qtdemux_expose_streams (demux);
6229 for (n = 0; n < demux->n_streams; n++) {
6230 QtDemuxStream *stream = demux->streams[n];
6232 gst_qtdemux_configure_stream (demux, stream);
6236 demux->got_moov = TRUE;
6237 gst_qtdemux_check_send_pending_segment (demux);
6239 /* fragmented streams headers shouldn't contain edts atoms */
6240 if (!demux->fragmented) {
6241 for (n = 0; n < demux->n_streams; n++) {
6242 gst_qtdemux_stream_send_initial_gap_segments (demux,
6247 g_node_destroy (demux->moov_node);
6248 demux->moov_node = NULL;
6249 GST_DEBUG_OBJECT (demux, "Finished parsing the header");
6251 } else if (fourcc == FOURCC_moof) {
6252 if ((demux->got_moov || demux->media_caps) && demux->fragmented) {
6254 GstClockTime prev_pts;
6255 guint64 prev_offset;
6257 GST_DEBUG_OBJECT (demux, "Parsing [moof]");
6260 * The timestamp of the moof buffer is relevant as some scenarios
6261 * won't have the initial timestamp in the atoms. Whenever a new
6262 * buffer has started, we get that buffer's PTS and use it as a base
6263 * timestamp for the trun entries.
6265 * To keep track of the current buffer timestamp and starting point
6266 * we use gst_adapter_prev_pts that gives us the PTS and the distance
6267 * from the beggining of the buffer, with the distance and demux->offset
6268 * we know if it is still the same buffer or not.
6270 prev_pts = gst_adapter_prev_pts (demux->adapter, &dist);
6271 prev_offset = demux->offset - dist;
6272 if (demux->fragment_start_offset == -1
6273 || prev_offset > demux->fragment_start_offset) {
6274 demux->fragment_start_offset = prev_offset;
6275 demux->fragment_start = prev_pts;
6276 GST_DEBUG_OBJECT (demux,
6277 "New fragment start found at: %" G_GUINT64_FORMAT " : %"
6278 GST_TIME_FORMAT, demux->fragment_start_offset,
6279 GST_TIME_ARGS (demux->fragment_start));
6282 demux->moof_offset = demux->offset;
6283 if (!qtdemux_parse_moof (demux, data, demux->neededbytes,
6284 demux->offset, NULL)) {
6285 gst_adapter_unmap (demux->adapter);
6286 ret = GST_FLOW_ERROR;
6289 /* in MSS we need to expose the pads after the first moof as we won't get a moov */
6290 if (demux->mss_mode && !demux->exposed) {
6291 if (!demux->pending_newsegment) {
6292 GST_DEBUG_OBJECT (demux, "new pending_newsegment");
6293 demux->pending_newsegment =
6294 gst_event_new_segment (&demux->segment);
6295 if (demux->segment_seqnum)
6296 gst_event_set_seqnum (demux->pending_newsegment,
6297 demux->segment_seqnum);
6299 qtdemux_expose_streams (demux);
6302 GST_DEBUG_OBJECT (demux, "Discarding [moof]");
6304 } else if (fourcc == FOURCC_ftyp) {
6305 GST_DEBUG_OBJECT (demux, "Parsing [ftyp]");
6306 qtdemux_parse_ftyp (demux, data, demux->neededbytes);
6307 } else if (fourcc == FOURCC_uuid) {
6308 GST_DEBUG_OBJECT (demux, "Parsing [uuid]");
6309 qtdemux_parse_uuid (demux, data, demux->neededbytes);
6310 } else if (fourcc == FOURCC_sidx) {
6311 GST_DEBUG_OBJECT (demux, "Parsing [sidx]");
6312 qtdemux_parse_sidx (demux, data, demux->neededbytes);
6314 GST_WARNING_OBJECT (demux,
6315 "Unknown fourcc while parsing header : %" GST_FOURCC_FORMAT,
6316 GST_FOURCC_ARGS (fourcc));
6317 /* Let's jump that one and go back to initial state */
6319 gst_adapter_unmap (demux->adapter);
6322 if (demux->mdatbuffer && demux->n_streams) {
6323 gsize remaining_data_size = 0;
6325 /* the mdat was before the header */
6326 GST_DEBUG_OBJECT (demux, "We have n_streams:%d and mdatbuffer:%p",
6327 demux->n_streams, demux->mdatbuffer);
6328 /* restore our adapter/offset view of things with upstream;
6329 * put preceding buffered data ahead of current moov data.
6330 * This should also handle evil mdat, moov, mdat cases and alike */
6331 gst_adapter_flush (demux->adapter, demux->neededbytes);
6333 /* Store any remaining data after the mdat for later usage */
6334 remaining_data_size = gst_adapter_available (demux->adapter);
6335 if (remaining_data_size > 0) {
6336 g_assert (demux->restoredata_buffer == NULL);
6337 demux->restoredata_buffer =
6338 gst_adapter_take_buffer (demux->adapter, remaining_data_size);
6339 demux->restoredata_offset = demux->offset + demux->neededbytes;
6340 GST_DEBUG_OBJECT (demux,
6341 "Stored %" G_GSIZE_FORMAT " post mdat bytes at offset %"
6342 G_GUINT64_FORMAT, remaining_data_size,
6343 demux->restoredata_offset);
6346 gst_adapter_push (demux->adapter, demux->mdatbuffer);
6347 demux->mdatbuffer = NULL;
6348 demux->offset = demux->mdatoffset;
6349 demux->neededbytes = next_entry_size (demux);
6350 demux->state = QTDEMUX_STATE_MOVIE;
6351 demux->mdatleft = gst_adapter_available (demux->adapter);
6353 GST_DEBUG_OBJECT (demux, "Carrying on normally");
6354 gst_adapter_flush (demux->adapter, demux->neededbytes);
6356 /* only go back to the mdat if there are samples to play */
6357 if (demux->got_moov && demux->first_mdat != -1
6358 && has_next_entry (demux)) {
6361 /* we need to seek back */
6362 res = qtdemux_seek_offset (demux, demux->first_mdat);
6364 demux->offset = demux->first_mdat;
6366 GST_DEBUG_OBJECT (demux, "Seek back failed");
6369 demux->offset += demux->neededbytes;
6371 demux->neededbytes = 16;
6372 demux->state = QTDEMUX_STATE_INITIAL;
6377 case QTDEMUX_STATE_BUFFER_MDAT:{
6381 GST_DEBUG_OBJECT (demux, "Got our buffer at offset %" G_GUINT64_FORMAT,
6383 buf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
6384 gst_buffer_extract (buf, 0, fourcc, 4);
6385 GST_DEBUG_OBJECT (demux, "mdatbuffer starts with %" GST_FOURCC_FORMAT,
6386 GST_FOURCC_ARGS (QT_FOURCC (fourcc)));
6387 if (demux->mdatbuffer)
6388 demux->mdatbuffer = gst_buffer_append (demux->mdatbuffer, buf);
6390 demux->mdatbuffer = buf;
6391 demux->offset += demux->neededbytes;
6392 demux->neededbytes = 16;
6393 demux->state = QTDEMUX_STATE_INITIAL;
6394 gst_qtdemux_post_progress (demux, 1, 1);
6398 case QTDEMUX_STATE_MOVIE:{
6399 QtDemuxStream *stream = NULL;
6400 QtDemuxSample *sample;
6402 GstClockTime dts, pts, duration;
6405 GST_DEBUG_OBJECT (demux,
6406 "BEGIN // in MOVIE for offset %" G_GUINT64_FORMAT, demux->offset);
6408 if (demux->fragmented) {
6409 GST_DEBUG_OBJECT (demux, "mdat remaining %" G_GUINT64_FORMAT,
6411 if (G_LIKELY (demux->todrop < demux->mdatleft)) {
6412 /* if needed data starts within this atom,
6413 * then it should not exceed this atom */
6414 if (G_UNLIKELY (demux->neededbytes > demux->mdatleft)) {
6415 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
6416 (_("This file is invalid and cannot be played.")),
6417 ("sample data crosses atom boundary"));
6418 ret = GST_FLOW_ERROR;
6421 demux->mdatleft -= demux->neededbytes;
6423 GST_DEBUG_OBJECT (demux, "data atom emptied; resuming atom scan");
6424 /* so we are dropping more than left in this atom */
6425 gst_qtdemux_drop_data (demux, demux->mdatleft);
6426 demux->mdatleft = 0;
6428 /* need to resume atom parsing so we do not miss any other pieces */
6429 demux->state = QTDEMUX_STATE_INITIAL;
6430 demux->neededbytes = 16;
6432 /* check if there was any stored post mdat data from previous buffers */
6433 if (demux->restoredata_buffer) {
6434 g_assert (gst_adapter_available (demux->adapter) == 0);
6436 gst_adapter_push (demux->adapter, demux->restoredata_buffer);
6437 demux->restoredata_buffer = NULL;
6438 demux->offset = demux->restoredata_offset;
6445 if (demux->todrop) {
6446 if (demux->cenc_aux_info_offset > 0) {
6450 GST_DEBUG_OBJECT (demux, "parsing cenc auxiliary info");
6451 data = gst_adapter_map (demux->adapter, demux->todrop);
6452 gst_byte_reader_init (&br, data + 8, demux->todrop);
6453 if (!qtdemux_parse_cenc_aux_info (demux, demux->streams[0], &br,
6454 demux->cenc_aux_info_sizes, demux->cenc_aux_sample_count)) {
6455 GST_ERROR_OBJECT (demux, "failed to parse cenc auxiliary info");
6456 ret = GST_FLOW_ERROR;
6457 gst_adapter_unmap (demux->adapter);
6458 g_free (demux->cenc_aux_info_sizes);
6459 demux->cenc_aux_info_sizes = NULL;
6462 demux->cenc_aux_info_offset = 0;
6463 g_free (demux->cenc_aux_info_sizes);
6464 demux->cenc_aux_info_sizes = NULL;
6465 gst_adapter_unmap (demux->adapter);
6467 gst_qtdemux_drop_data (demux, demux->todrop);
6471 /* initial newsegment sent here after having added pads,
6472 * possible others in sink_event */
6473 gst_qtdemux_check_send_pending_segment (demux);
6475 /* Figure out which stream this packet belongs to */
6476 for (i = 0; i < demux->n_streams; i++) {
6477 stream = demux->streams[i];
6478 if (stream->sample_index >= stream->n_samples)
6480 GST_LOG_OBJECT (demux,
6481 "Checking stream %d (sample_index:%d / offset:%" G_GUINT64_FORMAT
6482 " / size:%d)", i, stream->sample_index,
6483 stream->samples[stream->sample_index].offset,
6484 stream->samples[stream->sample_index].size);
6486 if (stream->samples[stream->sample_index].offset == demux->offset)
6490 if (G_UNLIKELY (stream == NULL || i == demux->n_streams))
6491 goto unknown_stream;
6493 if (stream->new_caps) {
6494 gst_qtdemux_configure_stream (demux, stream);
6497 /* Put data in a buffer, set timestamps, caps, ... */
6498 sample = &stream->samples[stream->sample_index];
6500 if (G_LIKELY (!(STREAM_IS_EOS (stream)))) {
6501 GST_DEBUG_OBJECT (demux, "stream : %" GST_FOURCC_FORMAT,
6502 GST_FOURCC_ARGS (stream->fourcc));
6504 dts = QTSAMPLE_DTS (stream, sample);
6505 pts = QTSAMPLE_PTS (stream, sample);
6506 duration = QTSAMPLE_DUR_DTS (stream, sample, dts);
6507 keyframe = QTSAMPLE_KEYFRAME (stream, sample);
6509 /* check for segment end */
6510 if (G_UNLIKELY (demux->segment.stop != -1
6511 && demux->segment.stop <= pts && stream->on_keyframe)) {
6512 GST_DEBUG_OBJECT (demux, "we reached the end of our segment.");
6513 stream->time_position = GST_CLOCK_TIME_NONE; /* this means EOS */
6515 /* skip this data, stream is EOS */
6516 gst_adapter_flush (demux->adapter, demux->neededbytes);
6518 /* check if all streams are eos */
6520 for (i = 0; i < demux->n_streams; i++) {
6521 if (!STREAM_IS_EOS (demux->streams[i])) {
6527 if (ret == GST_FLOW_EOS) {
6528 GST_DEBUG_OBJECT (demux, "All streams are EOS, signal upstream");
6535 gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
6537 /* FIXME: should either be an assert or a plain check */
6538 g_return_val_if_fail (outbuf != NULL, GST_FLOW_ERROR);
6540 ret = gst_qtdemux_decorate_and_push_buffer (demux, stream, outbuf,
6541 dts, pts, duration, keyframe, dts, demux->offset);
6545 ret = gst_qtdemux_combine_flows (demux, stream, ret);
6546 if (ret != GST_FLOW_OK && ret != GST_FLOW_NOT_LINKED)
6547 goto non_ok_unlinked_flow;
6549 /* skip this data, stream is EOS */
6550 gst_adapter_flush (demux->adapter, demux->neededbytes);
6553 stream->sample_index++;
6554 stream->offset_in_sample = 0;
6556 /* update current offset and figure out size of next buffer */
6557 GST_LOG_OBJECT (demux, "increasing offset %" G_GUINT64_FORMAT " by %u",
6558 demux->offset, demux->neededbytes);
6559 demux->offset += demux->neededbytes;
6560 GST_LOG_OBJECT (demux, "offset is now %" G_GUINT64_FORMAT,
6563 if ((demux->neededbytes = next_entry_size (demux)) == -1) {
6564 if (demux->fragmented) {
6565 GST_DEBUG_OBJECT (demux, "(temporarily) out of fragmented samples");
6566 /* there may be more to follow, only finish this atom */
6567 demux->todrop = demux->mdatleft;
6568 demux->neededbytes = demux->todrop;
6580 /* when buffering movie data, at least show user something is happening */
6581 if (ret == GST_FLOW_OK && demux->state == QTDEMUX_STATE_BUFFER_MDAT &&
6582 gst_adapter_available (demux->adapter) <= demux->neededbytes) {
6583 gst_qtdemux_post_progress (demux, gst_adapter_available (demux->adapter),
6584 demux->neededbytes);
6591 non_ok_unlinked_flow:
6593 GST_DEBUG_OBJECT (demux, "Stopping, combined return flow %s",
6594 gst_flow_get_name (ret));
6599 GST_ELEMENT_ERROR (demux, STREAM, FAILED, (NULL), ("unknown stream found"));
6600 ret = GST_FLOW_ERROR;
6605 GST_DEBUG_OBJECT (demux, "no next entry, EOS");
6611 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
6612 (NULL), ("qtdemuxer invalid state %d", demux->state));
6613 ret = GST_FLOW_ERROR;
6618 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
6619 (NULL), ("no 'moov' atom within the first 10 MB"));
6620 ret = GST_FLOW_ERROR;
6626 qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent)
6631 query = gst_query_new_scheduling ();
6633 if (!gst_pad_peer_query (sinkpad, query)) {
6634 gst_query_unref (query);
6638 pull_mode = gst_query_has_scheduling_mode_with_flags (query,
6639 GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
6640 gst_query_unref (query);
6645 GST_DEBUG_OBJECT (sinkpad, "activating pull");
6646 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
6650 GST_DEBUG_OBJECT (sinkpad, "activating push");
6651 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
6656 qtdemux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
6657 GstPadMode mode, gboolean active)
6660 GstQTDemux *demux = GST_QTDEMUX (parent);
6663 case GST_PAD_MODE_PUSH:
6664 demux->pullbased = FALSE;
6667 case GST_PAD_MODE_PULL:
6669 demux->pullbased = TRUE;
6670 res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_qtdemux_loop,
6673 res = gst_pad_stop_task (sinkpad);
6685 qtdemux_zalloc (void *opaque, unsigned int items, unsigned int size)
6687 return g_malloc (items * size);
6691 qtdemux_zfree (void *opaque, void *addr)
6697 qtdemux_inflate (void *z_buffer, guint z_length, guint length)
6703 z = g_new0 (z_stream, 1);
6704 z->zalloc = qtdemux_zalloc;
6705 z->zfree = qtdemux_zfree;
6708 z->next_in = z_buffer;
6709 z->avail_in = z_length;
6711 buffer = (guint8 *) g_malloc (length);
6712 ret = inflateInit (z);
6713 while (z->avail_in > 0) {
6714 if (z->avail_out == 0) {
6716 buffer = (guint8 *) g_realloc (buffer, length);
6717 z->next_out = buffer + z->total_out;
6718 z->avail_out = 1024;
6720 ret = inflate (z, Z_SYNC_FLUSH);
6724 if (ret != Z_STREAM_END) {
6725 g_warning ("inflate() returned %d", ret);
6731 #endif /* HAVE_ZLIB */
6734 qtdemux_parse_moov (GstQTDemux * qtdemux, const guint8 * buffer, guint length)
6738 qtdemux->moov_node = g_node_new ((guint8 *) buffer);
6740 /* counts as header data */
6741 qtdemux->header_size += length;
6743 GST_DEBUG_OBJECT (qtdemux, "parsing 'moov' atom");
6744 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buffer, length);
6746 cmov = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_cmov);
6752 dcom = qtdemux_tree_get_child_by_type (cmov, FOURCC_dcom);
6753 cmvd = qtdemux_tree_get_child_by_type (cmov, FOURCC_cmvd);
6754 if (dcom == NULL || cmvd == NULL)
6755 goto invalid_compression;
6757 method = QT_FOURCC ((guint8 *) dcom->data + 8);
6761 guint uncompressed_length;
6762 guint compressed_length;
6765 uncompressed_length = QT_UINT32 ((guint8 *) cmvd->data + 8);
6766 compressed_length = QT_UINT32 ((guint8 *) cmvd->data + 4) - 12;
6767 GST_LOG ("length = %u", uncompressed_length);
6770 (guint8 *) qtdemux_inflate ((guint8 *) cmvd->data + 12,
6771 compressed_length, uncompressed_length);
6773 qtdemux->moov_node_compressed = qtdemux->moov_node;
6774 qtdemux->moov_node = g_node_new (buf);
6776 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buf,
6777 uncompressed_length);
6780 #endif /* HAVE_ZLIB */
6782 GST_WARNING_OBJECT (qtdemux, "unknown or unhandled header compression "
6783 "type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (method));
6790 invalid_compression:
6792 GST_ERROR_OBJECT (qtdemux, "invalid compressed header");
6798 qtdemux_parse_container (GstQTDemux * qtdemux, GNode * node, const guint8 * buf,
6801 while (G_UNLIKELY (buf < end)) {
6805 if (G_UNLIKELY (buf + 4 > end)) {
6806 GST_LOG_OBJECT (qtdemux, "buffer overrun");
6809 len = QT_UINT32 (buf);
6810 if (G_UNLIKELY (len == 0)) {
6811 GST_LOG_OBJECT (qtdemux, "empty container");
6814 if (G_UNLIKELY (len < 8)) {
6815 GST_WARNING_OBJECT (qtdemux, "length too short (%d < 8)", len);
6818 if (G_UNLIKELY (len > (end - buf))) {
6819 GST_WARNING_OBJECT (qtdemux, "length too long (%d > %d)", len,
6820 (gint) (end - buf));
6824 child = g_node_new ((guint8 *) buf);
6825 g_node_append (node, child);
6826 GST_LOG_OBJECT (qtdemux, "adding new node of len %d", len);
6827 qtdemux_parse_node (qtdemux, child, buf, len);
6835 qtdemux_parse_theora_extension (GstQTDemux * qtdemux, QtDemuxStream * stream,
6838 int len = QT_UINT32 (xdxt->data);
6839 guint8 *buf = xdxt->data;
6840 guint8 *end = buf + len;
6843 /* skip size and type */
6851 size = QT_UINT32 (buf);
6852 type = QT_FOURCC (buf + 4);
6854 GST_LOG_OBJECT (qtdemux, "%p %p", buf, end);
6856 if (buf + size > end || size <= 0)
6862 GST_WARNING_OBJECT (qtdemux, "have cookie %" GST_FOURCC_FORMAT,
6863 GST_FOURCC_ARGS (type));
6867 buffer = gst_buffer_new_and_alloc (size);
6868 gst_buffer_fill (buffer, 0, buf, size);
6869 stream->buffers = g_slist_append (stream->buffers, buffer);
6870 GST_LOG_OBJECT (qtdemux, "parsing theora header");
6873 buffer = gst_buffer_new_and_alloc (size);
6874 gst_buffer_fill (buffer, 0, buf, size);
6875 stream->buffers = g_slist_append (stream->buffers, buffer);
6876 GST_LOG_OBJECT (qtdemux, "parsing theora comment");
6879 buffer = gst_buffer_new_and_alloc (size);
6880 gst_buffer_fill (buffer, 0, buf, size);
6881 stream->buffers = g_slist_append (stream->buffers, buffer);
6882 GST_LOG_OBJECT (qtdemux, "parsing theora codebook");
6885 GST_WARNING_OBJECT (qtdemux,
6886 "unknown theora cookie %" GST_FOURCC_FORMAT,
6887 GST_FOURCC_ARGS (type));
6896 qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node, const guint8 * buffer,
6900 guint32 node_length = 0;
6901 const QtNodeType *type;
6904 GST_LOG_OBJECT (qtdemux, "qtdemux_parse buffer %p length %u", buffer, length);
6906 if (G_UNLIKELY (length < 8))
6907 goto not_enough_data;
6909 node_length = QT_UINT32 (buffer);
6910 fourcc = QT_FOURCC (buffer + 4);
6912 /* ignore empty nodes */
6913 if (G_UNLIKELY (fourcc == 0 || node_length == 8))
6916 type = qtdemux_type_get (fourcc);
6918 end = buffer + length;
6920 GST_LOG_OBJECT (qtdemux,
6921 "parsing '%" GST_FOURCC_FORMAT "', length=%u, name '%s'",
6922 GST_FOURCC_ARGS (fourcc), node_length, type->name);
6924 if (node_length > length)
6925 goto broken_atom_size;
6927 if (type->flags & QT_FLAG_CONTAINER) {
6928 qtdemux_parse_container (qtdemux, node, buffer + 8, end);
6933 if (node_length < 20) {
6934 GST_LOG_OBJECT (qtdemux, "skipping small stsd box");
6937 GST_DEBUG_OBJECT (qtdemux,
6938 "parsing stsd (sample table, sample description) atom");
6939 /* Skip over 8 byte atom hdr + 1 byte version, 3 bytes flags, 4 byte num_entries */
6940 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
6950 /* also read alac (or whatever) in stead of mp4a in the following,
6951 * since a similar layout is used in other cases as well */
6952 if (fourcc == FOURCC_mp4a)
6957 /* There are two things we might encounter here: a true mp4a atom, and
6958 an mp4a entry in an stsd atom. The latter is what we're interested
6959 in, and it looks like an atom, but isn't really one. The true mp4a
6960 atom is short, so we detect it based on length here. */
6961 if (length < min_size) {
6962 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
6963 GST_FOURCC_ARGS (fourcc));
6967 /* 'version' here is the sound sample description version. Types 0 and
6968 1 are documented in the QTFF reference, but type 2 is not: it's
6969 described in Apple header files instead (struct SoundDescriptionV2
6971 version = QT_UINT16 (buffer + 16);
6973 GST_DEBUG_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT " version 0x%08x",
6974 GST_FOURCC_ARGS (fourcc), version);
6976 /* parse any esds descriptors */
6988 GST_WARNING_OBJECT (qtdemux,
6989 "unhandled %" GST_FOURCC_FORMAT " version 0x%08x",
6990 GST_FOURCC_ARGS (fourcc), version);
6995 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
7012 /* codec_data is contained inside these atoms, which all have
7013 * the same format. */
7015 GST_DEBUG_OBJECT (qtdemux, "parsing in %" GST_FOURCC_FORMAT,
7016 GST_FOURCC_ARGS (fourcc));
7017 version = QT_UINT32 (buffer + 16);
7018 GST_DEBUG_OBJECT (qtdemux, "version %08x", version);
7019 if (1 || version == 0x00000000) {
7020 buf = buffer + 0x32;
7022 /* FIXME Quicktime uses PASCAL string while
7023 * the iso format uses C strings. Check the file
7024 * type before attempting to parse the string here. */
7025 tlen = QT_UINT8 (buf);
7026 GST_DEBUG_OBJECT (qtdemux, "tlen = %d", tlen);
7028 GST_DEBUG_OBJECT (qtdemux, "string = %.*s", tlen, (char *) buf);
7029 /* the string has a reserved space of 32 bytes so skip
7030 * the remaining 31 */
7032 buf += 4; /* and 4 bytes reserved */
7034 GST_MEMDUMP_OBJECT (qtdemux, "mp4v", buf, end - buf);
7036 qtdemux_parse_container (qtdemux, node, buf, end);
7042 GST_MEMDUMP_OBJECT (qtdemux, "H264", buffer, end - buffer);
7043 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
7048 GST_MEMDUMP_OBJECT (qtdemux, "avc1", buffer, end - buffer);
7049 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
7054 GST_MEMDUMP_OBJECT (qtdemux, "avc3", buffer, end - buffer);
7055 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
7060 GST_MEMDUMP_OBJECT (qtdemux, "H265", buffer, end - buffer);
7061 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
7066 GST_MEMDUMP_OBJECT (qtdemux, "hvc1", buffer, end - buffer);
7067 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
7072 GST_MEMDUMP_OBJECT (qtdemux, "hev1", buffer, end - buffer);
7073 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
7078 qtdemux_parse_container (qtdemux, node, buffer + 86, end);
7083 GST_DEBUG_OBJECT (qtdemux, "parsing meta atom");
7084 qtdemux_parse_container (qtdemux, node, buffer + 12, end);
7089 GST_MEMDUMP_OBJECT (qtdemux, "mp4s", buffer, end - buffer);
7090 /* Skip 8 byte header, plus 8 byte version + flags + entry_count */
7091 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
7099 version = QT_UINT32 (buffer + 12);
7100 GST_DEBUG_OBJECT (qtdemux, "parsing XiTh atom version 0x%08x", version);
7107 GST_DEBUG_OBJECT (qtdemux, "unknown version 0x%08x", version);
7112 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
7117 qtdemux_parse_container (qtdemux, node, buffer + 0x34, end);
7122 qtdemux_parse_uuid (qtdemux, buffer, end - buffer);
7127 qtdemux_parse_container (qtdemux, node, buffer + 86, end);
7132 qtdemux_parse_container (qtdemux, node, buffer + 36, end);
7136 if (!strcmp (type->name, "unknown"))
7137 GST_MEMDUMP ("Unknown tag", buffer + 4, end - buffer - 4);
7141 GST_LOG_OBJECT (qtdemux, "parsed '%" GST_FOURCC_FORMAT "'",
7142 GST_FOURCC_ARGS (fourcc));
7148 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
7149 (_("This file is corrupt and cannot be played.")),
7150 ("Not enough data for an atom header, got only %u bytes", length));
7155 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
7156 (_("This file is corrupt and cannot be played.")),
7157 ("Atom '%" GST_FOURCC_FORMAT "' has size of %u bytes, but we have only "
7158 "%u bytes available.", GST_FOURCC_ARGS (fourcc), node_length,
7165 qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc)
7169 guint32 child_fourcc;
7171 for (child = g_node_first_child (node); child;
7172 child = g_node_next_sibling (child)) {
7173 buffer = (guint8 *) child->data;
7175 child_fourcc = QT_FOURCC (buffer + 4);
7177 if (G_UNLIKELY (child_fourcc == fourcc)) {
7185 qtdemux_tree_get_child_by_type_full (GNode * node, guint32 fourcc,
7186 GstByteReader * parser)
7190 guint32 child_fourcc, child_len;
7192 for (child = g_node_first_child (node); child;
7193 child = g_node_next_sibling (child)) {
7194 buffer = (guint8 *) child->data;
7196 child_len = QT_UINT32 (buffer);
7197 child_fourcc = QT_FOURCC (buffer + 4);
7199 if (G_UNLIKELY (child_fourcc == fourcc)) {
7200 if (G_UNLIKELY (child_len < (4 + 4)))
7202 /* FIXME: must verify if atom length < parent atom length */
7203 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
7211 qtdemux_tree_get_sibling_by_type_full (GNode * node, guint32 fourcc,
7212 GstByteReader * parser)
7216 guint32 child_fourcc, child_len;
7218 for (child = g_node_next_sibling (node); child;
7219 child = g_node_next_sibling (child)) {
7220 buffer = (guint8 *) child->data;
7222 child_fourcc = QT_FOURCC (buffer + 4);
7224 if (child_fourcc == fourcc) {
7226 child_len = QT_UINT32 (buffer);
7227 if (G_UNLIKELY (child_len < (4 + 4)))
7229 /* FIXME: must verify if atom length < parent atom length */
7230 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
7239 qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc)
7241 return qtdemux_tree_get_sibling_by_type_full (node, fourcc, NULL);
7245 qtdemux_do_allocation (GstQTDemux * qtdemux, QtDemuxStream * stream)
7247 /* FIXME: This can only reliably work if demuxers have a
7248 * separate streaming thread per srcpad. This should be
7249 * done in a demuxer base class, which integrates parts
7252 * https://bugzilla.gnome.org/show_bug.cgi?id=701856
7257 query = gst_query_new_allocation (stream->caps, FALSE);
7259 if (!gst_pad_peer_query (stream->pad, query)) {
7260 /* not a problem, just debug a little */
7261 GST_DEBUG_OBJECT (qtdemux, "peer ALLOCATION query failed");
7264 if (stream->allocator)
7265 gst_object_unref (stream->allocator);
7267 if (gst_query_get_n_allocation_params (query) > 0) {
7268 /* try the allocator */
7269 gst_query_parse_nth_allocation_param (query, 0, &stream->allocator,
7271 stream->use_allocator = TRUE;
7273 stream->allocator = NULL;
7274 gst_allocation_params_init (&stream->params);
7275 stream->use_allocator = FALSE;
7277 gst_query_unref (query);
7282 gst_qtdemux_configure_protected_caps (GstQTDemux * qtdemux,
7283 QtDemuxStream * stream)
7286 const gchar *selected_system;
7288 g_return_val_if_fail (qtdemux != NULL, FALSE);
7289 g_return_val_if_fail (stream != NULL, FALSE);
7290 g_return_val_if_fail (gst_caps_get_size (stream->caps) == 1, FALSE);
7292 if (stream->protection_scheme_type != FOURCC_cenc) {
7293 GST_ERROR_OBJECT (qtdemux, "unsupported protection scheme");
7296 if (qtdemux->protection_system_ids == NULL) {
7297 GST_ERROR_OBJECT (qtdemux, "stream is protected using cenc, but no "
7298 "cenc protection system information has been found");
7301 g_ptr_array_add (qtdemux->protection_system_ids, NULL);
7302 selected_system = gst_protection_select_system ((const gchar **)
7303 qtdemux->protection_system_ids->pdata);
7304 g_ptr_array_remove_index (qtdemux->protection_system_ids,
7305 qtdemux->protection_system_ids->len - 1);
7306 if (!selected_system) {
7307 GST_ERROR_OBJECT (qtdemux, "stream is protected, but no "
7308 "suitable decryptor element has been found");
7312 s = gst_caps_get_structure (stream->caps, 0);
7313 if (!gst_structure_has_name (s, "application/x-cenc")) {
7314 gst_structure_set (s,
7315 "original-media-type", G_TYPE_STRING, gst_structure_get_name (s),
7316 GST_PROTECTION_SYSTEM_ID_CAPS_FIELD, G_TYPE_STRING, selected_system,
7318 gst_structure_set_name (s, "application/x-cenc");
7324 gst_qtdemux_configure_stream (GstQTDemux * qtdemux, QtDemuxStream * stream)
7326 if (stream->subtype == FOURCC_vide) {
7327 /* fps is calculated base on the duration of the average framerate since
7328 * qt does not have a fixed framerate. */
7329 gboolean fps_available = TRUE;
7331 if ((stream->n_samples == 1) && (stream->first_duration == 0)) {
7336 if (stream->duration == 0 || stream->n_samples < 2) {
7337 stream->fps_n = stream->timescale;
7339 fps_available = FALSE;
7341 GstClockTime avg_duration;
7345 /* duration and n_samples can be updated for fragmented format
7346 * so, framerate of fragmented format is calculated using data in a moof */
7347 if (qtdemux->fragmented && stream->n_samples_moof > 0
7348 && stream->duration_moof > 0) {
7349 n_samples = stream->n_samples_moof;
7350 duration = stream->duration_moof;
7352 n_samples = stream->n_samples;
7353 duration = stream->duration;
7356 /* Calculate a framerate, ignoring the first sample which is sometimes truncated */
7357 /* stream->duration is guint64, timescale, n_samples are guint32 */
7359 gst_util_uint64_scale_round (duration -
7360 stream->first_duration, GST_SECOND,
7361 (guint64) (stream->timescale) * (n_samples - 1));
7363 GST_LOG_OBJECT (qtdemux,
7364 "Calculating avg sample duration based on stream (or moof) duration %"
7366 " minus first sample %u, leaving %d samples gives %"
7367 GST_TIME_FORMAT, duration, stream->first_duration,
7368 n_samples - 1, GST_TIME_ARGS (avg_duration));
7370 gst_video_guess_framerate (avg_duration, &stream->fps_n,
7373 GST_DEBUG_OBJECT (qtdemux,
7374 "Calculating framerate, timescale %u gave fps_n %d fps_d %d",
7375 stream->timescale, stream->fps_n, stream->fps_d);
7380 stream->caps = gst_caps_make_writable (stream->caps);
7382 gst_caps_set_simple (stream->caps,
7383 "width", G_TYPE_INT, stream->width,
7384 "height", G_TYPE_INT, stream->height, NULL);
7386 /* set framerate if calculated framerate is reliable */
7387 if (fps_available) {
7388 gst_caps_set_simple (stream->caps,
7389 "framerate", GST_TYPE_FRACTION, stream->fps_n, stream->fps_d, NULL);
7392 /* calculate pixel-aspect-ratio using display width and height */
7393 GST_DEBUG_OBJECT (qtdemux,
7394 "video size %dx%d, target display size %dx%d", stream->width,
7395 stream->height, stream->display_width, stream->display_height);
7396 /* qt file might have pasp atom */
7397 if (stream->par_w > 0 && stream->par_h > 0) {
7398 GST_DEBUG_OBJECT (qtdemux, "par %d:%d", stream->par_w, stream->par_h);
7399 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
7400 GST_TYPE_FRACTION, stream->par_w, stream->par_h, NULL);
7401 } else if (stream->display_width > 0 && stream->display_height > 0 &&
7402 stream->width > 0 && stream->height > 0) {
7405 /* calculate the pixel aspect ratio using the display and pixel w/h */
7406 n = stream->display_width * stream->height;
7407 d = stream->display_height * stream->width;
7410 GST_DEBUG_OBJECT (qtdemux, "setting PAR to %d/%d", n, d);
7413 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
7414 GST_TYPE_FRACTION, stream->par_w, stream->par_h, NULL);
7417 if (stream->multiview_mode != GST_VIDEO_MULTIVIEW_MODE_NONE) {
7418 guint par_w = 1, par_h = 1;
7420 if (stream->par_w > 0 && stream->par_h > 0) {
7421 par_w = stream->par_w;
7422 par_h = stream->par_h;
7425 if (gst_video_multiview_guess_half_aspect (stream->multiview_mode,
7426 stream->width, stream->height, par_w, par_h)) {
7427 stream->multiview_flags |= GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT;
7430 gst_caps_set_simple (stream->caps,
7431 "multiview-mode", G_TYPE_STRING,
7432 gst_video_multiview_mode_to_caps_string (stream->multiview_mode),
7433 "multiview-flags", GST_TYPE_VIDEO_MULTIVIEW_FLAGSET,
7434 stream->multiview_flags, GST_FLAG_SET_MASK_EXACT, NULL);
7439 else if (stream->subtype == FOURCC_soun) {
7441 stream->caps = gst_caps_make_writable (stream->caps);
7442 if (stream->rate > 0)
7443 gst_caps_set_simple (stream->caps,
7444 "rate", G_TYPE_INT, (int) stream->rate, NULL);
7445 if (stream->n_channels > 0)
7446 gst_caps_set_simple (stream->caps,
7447 "channels", G_TYPE_INT, stream->n_channels, NULL);
7448 if (stream->n_channels > 2) {
7449 /* FIXME: Need to parse the 'chan' atom to get channel layouts
7450 * correctly; this is just the minimum we can do - assume
7451 * we don't actually have any channel positions. */
7452 gst_caps_set_simple (stream->caps,
7453 "channel-mask", GST_TYPE_BITMASK, G_GUINT64_CONSTANT (0), NULL);
7459 GST_PAD_ELEMENT_PRIVATE (stream->pad) = stream;
7460 gst_pad_set_event_function (stream->pad, gst_qtdemux_handle_src_event);
7461 gst_pad_set_query_function (stream->pad, gst_qtdemux_handle_src_query);
7462 gst_pad_set_active (stream->pad, TRUE);
7464 gst_pad_use_fixed_caps (stream->pad);
7466 if (stream->protected) {
7467 if (!gst_qtdemux_configure_protected_caps (qtdemux, stream)) {
7468 GST_ERROR_OBJECT (qtdemux,
7469 "Failed to configure protected stream caps.");
7474 GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT, stream->caps);
7475 if (stream->new_stream) {
7478 GstStreamFlags stream_flags;
7481 gst_pad_get_sticky_event (qtdemux->sinkpad, GST_EVENT_STREAM_START,
7484 if (gst_event_parse_group_id (event, &qtdemux->group_id))
7485 qtdemux->have_group_id = TRUE;
7487 qtdemux->have_group_id = FALSE;
7488 gst_event_unref (event);
7489 } else if (!qtdemux->have_group_id) {
7490 qtdemux->have_group_id = TRUE;
7491 qtdemux->group_id = gst_util_group_id_next ();
7494 stream->new_stream = FALSE;
7496 gst_pad_create_stream_id_printf (stream->pad,
7497 GST_ELEMENT_CAST (qtdemux), "%03u", stream->track_id);
7498 event = gst_event_new_stream_start (stream_id);
7499 if (qtdemux->have_group_id)
7500 gst_event_set_group_id (event, qtdemux->group_id);
7501 stream_flags = GST_STREAM_FLAG_NONE;
7502 if (stream->disabled)
7503 stream_flags |= GST_STREAM_FLAG_UNSELECT;
7505 stream_flags |= GST_STREAM_FLAG_SPARSE;
7506 gst_event_set_stream_flags (event, stream_flags);
7507 gst_pad_push_event (stream->pad, event);
7510 gst_pad_set_caps (stream->pad, stream->caps);
7511 stream->new_caps = FALSE;
7517 gst_qtdemux_add_stream (GstQTDemux * qtdemux,
7518 QtDemuxStream * stream, GstTagList * list)
7520 gboolean ret = TRUE;
7521 /* consistent default for push based mode */
7522 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
7524 if (stream->subtype == FOURCC_vide) {
7525 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
7528 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
7531 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
7532 gst_object_unref (stream->pad);
7538 qtdemux->n_video_streams++;
7539 } else if (stream->subtype == FOURCC_soun) {
7540 gchar *name = g_strdup_printf ("audio_%u", qtdemux->n_audio_streams);
7543 gst_pad_new_from_static_template (&gst_qtdemux_audiosrc_template, name);
7545 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
7546 gst_object_unref (stream->pad);
7551 qtdemux->n_audio_streams++;
7552 } else if (stream->subtype == FOURCC_strm) {
7553 GST_DEBUG_OBJECT (qtdemux, "stream type, not creating pad");
7554 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
7555 || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt) {
7556 gchar *name = g_strdup_printf ("subtitle_%u", qtdemux->n_sub_streams);
7559 gst_pad_new_from_static_template (&gst_qtdemux_subsrc_template, name);
7561 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
7562 gst_object_unref (stream->pad);
7567 qtdemux->n_sub_streams++;
7568 } else if (stream->caps) {
7569 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
7572 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
7574 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
7575 gst_object_unref (stream->pad);
7580 qtdemux->n_video_streams++;
7582 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
7589 GST_DEBUG_OBJECT (qtdemux, "adding pad %s %p to qtdemux %p",
7590 GST_OBJECT_NAME (stream->pad), stream->pad, qtdemux);
7591 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
7592 gst_flow_combiner_add_pad (qtdemux->flowcombiner, stream->pad);
7594 if (stream->pending_tags)
7595 gst_tag_list_unref (stream->pending_tags);
7596 stream->pending_tags = list;
7598 /* global tags go on each pad anyway */
7599 stream->send_global_tags = TRUE;
7600 /* send upstream GST_EVENT_PROTECTION events that were received before
7601 this source pad was created */
7602 for (l = qtdemux->protection_event_queue.head; l != NULL; l = l->next)
7603 gst_pad_push_event (stream->pad, gst_event_ref (l->data));
7607 gst_tag_list_unref (list);
7611 /* find next atom with @fourcc starting at @offset */
7612 static GstFlowReturn
7613 qtdemux_find_atom (GstQTDemux * qtdemux, guint64 * offset,
7614 guint64 * length, guint32 fourcc)
7620 GST_LOG_OBJECT (qtdemux, "finding fourcc %" GST_FOURCC_FORMAT " at offset %"
7621 G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), *offset);
7627 ret = gst_pad_pull_range (qtdemux->sinkpad, *offset, 16, &buf);
7628 if (G_UNLIKELY (ret != GST_FLOW_OK))
7630 if (G_UNLIKELY (gst_buffer_get_size (buf) != 16)) {
7633 gst_buffer_unref (buf);
7636 gst_buffer_map (buf, &map, GST_MAP_READ);
7637 extract_initial_length_and_fourcc (map.data, 16, length, &lfourcc);
7638 gst_buffer_unmap (buf, &map);
7639 gst_buffer_unref (buf);
7641 if (G_UNLIKELY (*length == 0)) {
7642 GST_DEBUG_OBJECT (qtdemux, "invalid length 0");
7643 ret = GST_FLOW_ERROR;
7647 if (lfourcc == fourcc) {
7648 GST_DEBUG_OBJECT (qtdemux, "found fourcc at offset %" G_GUINT64_FORMAT,
7652 GST_LOG_OBJECT (qtdemux,
7653 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
7654 GST_FOURCC_ARGS (fourcc), *offset);
7663 /* might simply have had last one */
7664 GST_DEBUG_OBJECT (qtdemux, "fourcc not found");
7669 /* should only do something in pull mode */
7670 /* call with OBJECT lock */
7671 static GstFlowReturn
7672 qtdemux_add_fragmented_samples (GstQTDemux * qtdemux)
7674 guint64 length, offset;
7675 GstBuffer *buf = NULL;
7676 GstFlowReturn ret = GST_FLOW_OK;
7677 GstFlowReturn res = GST_FLOW_OK;
7680 offset = qtdemux->moof_offset;
7681 GST_DEBUG_OBJECT (qtdemux, "next moof at offset %" G_GUINT64_FORMAT, offset);
7684 GST_DEBUG_OBJECT (qtdemux, "no next moof");
7685 return GST_FLOW_EOS;
7688 /* best not do pull etc with lock held */
7689 GST_OBJECT_UNLOCK (qtdemux);
7691 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
7692 if (ret != GST_FLOW_OK)
7695 ret = gst_qtdemux_pull_atom (qtdemux, offset, length, &buf);
7696 if (G_UNLIKELY (ret != GST_FLOW_OK))
7698 gst_buffer_map (buf, &map, GST_MAP_READ);
7699 if (!qtdemux_parse_moof (qtdemux, map.data, map.size, offset, NULL)) {
7700 gst_buffer_unmap (buf, &map);
7701 gst_buffer_unref (buf);
7706 gst_buffer_unmap (buf, &map);
7707 gst_buffer_unref (buf);
7711 /* look for next moof */
7712 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
7713 if (G_UNLIKELY (ret != GST_FLOW_OK))
7717 GST_OBJECT_LOCK (qtdemux);
7719 qtdemux->moof_offset = offset;
7725 GST_DEBUG_OBJECT (qtdemux, "failed to parse moof");
7727 res = GST_FLOW_ERROR;
7732 /* maybe upstream temporarily flushing */
7733 if (ret != GST_FLOW_FLUSHING) {
7734 GST_DEBUG_OBJECT (qtdemux, "no next moof");
7737 GST_DEBUG_OBJECT (qtdemux, "upstream WRONG_STATE");
7738 /* resume at current position next time */
7745 /* initialise bytereaders for stbl sub-atoms */
7747 qtdemux_stbl_init (GstQTDemux * qtdemux, QtDemuxStream * stream, GNode * stbl)
7749 stream->stbl_index = -1; /* no samples have yet been parsed */
7750 stream->sample_index = -1;
7752 /* time-to-sample atom */
7753 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stts, &stream->stts))
7756 /* copy atom data into a new buffer for later use */
7757 stream->stts.data = g_memdup (stream->stts.data, stream->stts.size);
7759 /* skip version + flags */
7760 if (!gst_byte_reader_skip (&stream->stts, 1 + 3) ||
7761 !gst_byte_reader_get_uint32_be (&stream->stts, &stream->n_sample_times))
7763 GST_LOG_OBJECT (qtdemux, "%u timestamp blocks", stream->n_sample_times);
7765 /* make sure there's enough data */
7766 if (!qt_atom_parser_has_chunks (&stream->stts, stream->n_sample_times, 8)) {
7767 stream->n_sample_times = gst_byte_reader_get_remaining (&stream->stts) / 8;
7768 GST_LOG_OBJECT (qtdemux, "overriding to %u timestamp blocks",
7769 stream->n_sample_times);
7770 if (!stream->n_sample_times)
7774 /* sync sample atom */
7775 stream->stps_present = FALSE;
7776 if ((stream->stss_present =
7777 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stss,
7778 &stream->stss) ? TRUE : FALSE) == TRUE) {
7779 /* copy atom data into a new buffer for later use */
7780 stream->stss.data = g_memdup (stream->stss.data, stream->stss.size);
7782 /* skip version + flags */
7783 if (!gst_byte_reader_skip (&stream->stss, 1 + 3) ||
7784 !gst_byte_reader_get_uint32_be (&stream->stss, &stream->n_sample_syncs))
7787 if (stream->n_sample_syncs) {
7788 /* make sure there's enough data */
7789 if (!qt_atom_parser_has_chunks (&stream->stss, stream->n_sample_syncs, 4))
7793 /* partial sync sample atom */
7794 if ((stream->stps_present =
7795 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stps,
7796 &stream->stps) ? TRUE : FALSE) == TRUE) {
7797 /* copy atom data into a new buffer for later use */
7798 stream->stps.data = g_memdup (stream->stps.data, stream->stps.size);
7800 /* skip version + flags */
7801 if (!gst_byte_reader_skip (&stream->stps, 1 + 3) ||
7802 !gst_byte_reader_get_uint32_be (&stream->stps,
7803 &stream->n_sample_partial_syncs))
7806 /* if there are no entries, the stss table contains the real
7808 if (stream->n_sample_partial_syncs) {
7809 /* make sure there's enough data */
7810 if (!qt_atom_parser_has_chunks (&stream->stps,
7811 stream->n_sample_partial_syncs, 4))
7818 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsz, &stream->stsz))
7821 /* copy atom data into a new buffer for later use */
7822 stream->stsz.data = g_memdup (stream->stsz.data, stream->stsz.size);
7824 /* skip version + flags */
7825 if (!gst_byte_reader_skip (&stream->stsz, 1 + 3) ||
7826 !gst_byte_reader_get_uint32_be (&stream->stsz, &stream->sample_size))
7829 if (!gst_byte_reader_get_uint32_be (&stream->stsz, &stream->n_samples))
7832 if (!stream->n_samples)
7835 /* sample-to-chunk atom */
7836 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsc, &stream->stsc))
7839 /* copy atom data into a new buffer for later use */
7840 stream->stsc.data = g_memdup (stream->stsc.data, stream->stsc.size);
7842 /* skip version + flags */
7843 if (!gst_byte_reader_skip (&stream->stsc, 1 + 3) ||
7844 !gst_byte_reader_get_uint32_be (&stream->stsc,
7845 &stream->n_samples_per_chunk))
7848 GST_DEBUG_OBJECT (qtdemux, "n_samples_per_chunk %u",
7849 stream->n_samples_per_chunk);
7851 /* make sure there's enough data */
7852 if (!qt_atom_parser_has_chunks (&stream->stsc, stream->n_samples_per_chunk,
7858 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stco, &stream->stco))
7859 stream->co_size = sizeof (guint32);
7860 else if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_co64,
7862 stream->co_size = sizeof (guint64);
7866 /* copy atom data into a new buffer for later use */
7867 stream->stco.data = g_memdup (stream->stco.data, stream->stco.size);
7869 /* skip version + flags */
7870 if (!gst_byte_reader_skip (&stream->stco, 1 + 3))
7873 /* chunks_are_samples == TRUE means treat chunks as samples */
7874 stream->chunks_are_samples = stream->sample_size && !stream->sampled;
7875 if (stream->chunks_are_samples) {
7876 /* treat chunks as samples */
7877 if (!gst_byte_reader_get_uint32_be (&stream->stco, &stream->n_samples))
7880 /* skip number of entries */
7881 if (!gst_byte_reader_skip (&stream->stco, 4))
7884 /* make sure there are enough data in the stsz atom */
7885 if (!stream->sample_size) {
7886 /* different sizes for each sample */
7887 if (!qt_atom_parser_has_chunks (&stream->stsz, stream->n_samples, 4))
7892 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
7893 stream->n_samples, (guint) sizeof (QtDemuxSample),
7894 stream->n_samples * sizeof (QtDemuxSample) / (1024.0 * 1024.0));
7896 if (stream->n_samples >=
7897 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample)) {
7898 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
7899 "be larger than %uMB (broken file?)", stream->n_samples,
7900 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
7904 g_assert (stream->samples == NULL);
7905 stream->samples = g_try_new0 (QtDemuxSample, stream->n_samples);
7906 if (!stream->samples) {
7907 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
7912 /* composition time-to-sample */
7913 if ((stream->ctts_present =
7914 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_ctts,
7915 &stream->ctts) ? TRUE : FALSE) == TRUE) {
7916 GstByteReader cslg = GST_BYTE_READER_INIT (NULL, 0);
7918 /* copy atom data into a new buffer for later use */
7919 stream->ctts.data = g_memdup (stream->ctts.data, stream->ctts.size);
7921 /* skip version + flags */
7922 if (!gst_byte_reader_skip (&stream->ctts, 1 + 3)
7923 || !gst_byte_reader_get_uint32_be (&stream->ctts,
7924 &stream->n_composition_times))
7927 /* make sure there's enough data */
7928 if (!qt_atom_parser_has_chunks (&stream->ctts, stream->n_composition_times,
7932 /* This is optional, if missing we iterate the ctts */
7933 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_cslg, &cslg)) {
7934 if (!gst_byte_reader_skip (&cslg, 1 + 3)
7935 || !gst_byte_reader_get_uint32_be (&cslg, &stream->cslg_shift)) {
7936 g_free ((gpointer) cslg.data);
7940 gint32 cslg_least = 0;
7941 guint num_entries, pos;
7944 pos = gst_byte_reader_get_pos (&stream->ctts);
7945 num_entries = stream->n_composition_times;
7947 stream->cslg_shift = 0;
7949 for (i = 0; i < num_entries; i++) {
7952 gst_byte_reader_skip_unchecked (&stream->ctts, 4);
7953 offset = gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
7955 if (offset < cslg_least)
7956 cslg_least = offset;
7960 stream->cslg_shift = ABS (cslg_least);
7962 stream->cslg_shift = 0;
7964 /* reset the reader so we can generate sample table */
7965 gst_byte_reader_set_pos (&stream->ctts, pos);
7968 /* Ensure the cslg_shift value is consistent so we can use it
7969 * unconditionnally to produce TS and Segment */
7970 stream->cslg_shift = 0;
7977 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
7978 (_("This file is corrupt and cannot be played.")), (NULL));
7983 gst_qtdemux_stbl_free (stream);
7984 if (!qtdemux->fragmented) {
7985 /* not quite good */
7986 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
7989 /* may pick up samples elsewhere */
7995 /* collect samples from the next sample to be parsed up to sample @n for @stream
7996 * by reading the info from @stbl
7998 * This code can be executed from both the streaming thread and the seeking
7999 * thread so it takes the object lock to protect itself
8002 qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream, guint32 n)
8005 QtDemuxSample *samples, *first, *cur, *last;
8006 guint32 n_samples_per_chunk;
8009 GST_LOG_OBJECT (qtdemux, "parsing samples for stream fourcc %"
8010 GST_FOURCC_FORMAT ", pad %s", GST_FOURCC_ARGS (stream->fourcc),
8011 stream->pad ? GST_PAD_NAME (stream->pad) : "(NULL)");
8013 n_samples = stream->n_samples;
8016 goto out_of_samples;
8018 GST_OBJECT_LOCK (qtdemux);
8019 if (n <= stream->stbl_index)
8020 goto already_parsed;
8022 GST_DEBUG_OBJECT (qtdemux, "parsing up to sample %u", n);
8024 if (!stream->stsz.data) {
8025 /* so we already parsed and passed all the moov samples;
8026 * onto fragmented ones */
8027 g_assert (qtdemux->fragmented);
8031 /* pointer to the sample table */
8032 samples = stream->samples;
8034 /* starts from -1, moves to the next sample index to parse */
8035 stream->stbl_index++;
8037 /* keep track of the first and last sample to fill */
8038 first = &samples[stream->stbl_index];
8041 if (!stream->chunks_are_samples) {
8042 /* set the sample sizes */
8043 if (stream->sample_size == 0) {
8044 /* different sizes for each sample */
8045 for (cur = first; cur <= last; cur++) {
8046 cur->size = gst_byte_reader_get_uint32_be_unchecked (&stream->stsz);
8047 GST_LOG_OBJECT (qtdemux, "sample %d has size %u",
8048 (guint) (cur - samples), cur->size);
8051 /* samples have the same size */
8052 GST_LOG_OBJECT (qtdemux, "all samples have size %u", stream->sample_size);
8053 for (cur = first; cur <= last; cur++)
8054 cur->size = stream->sample_size;
8058 n_samples_per_chunk = stream->n_samples_per_chunk;
8061 for (i = stream->stsc_index; i < n_samples_per_chunk; i++) {
8064 if (stream->stsc_chunk_index >= stream->last_chunk
8065 || stream->stsc_chunk_index < stream->first_chunk) {
8066 stream->first_chunk =
8067 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
8068 stream->samples_per_chunk =
8069 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
8070 gst_byte_reader_skip_unchecked (&stream->stsc, 4);
8072 /* chunk numbers are counted from 1 it seems */
8073 if (G_UNLIKELY (stream->first_chunk == 0))
8076 --stream->first_chunk;
8078 /* the last chunk of each entry is calculated by taking the first chunk
8079 * of the next entry; except if there is no next, where we fake it with
8081 if (G_UNLIKELY (i == (stream->n_samples_per_chunk - 1))) {
8082 stream->last_chunk = G_MAXUINT32;
8084 stream->last_chunk =
8085 gst_byte_reader_peek_uint32_be_unchecked (&stream->stsc);
8086 if (G_UNLIKELY (stream->last_chunk == 0))
8089 --stream->last_chunk;
8092 GST_LOG_OBJECT (qtdemux,
8093 "entry %d has first_chunk %d, last_chunk %d, samples_per_chunk %d", i,
8094 stream->first_chunk, stream->last_chunk, stream->samples_per_chunk);
8096 if (G_UNLIKELY (stream->last_chunk < stream->first_chunk))
8099 if (stream->last_chunk != G_MAXUINT32) {
8100 if (!qt_atom_parser_peek_sub (&stream->stco,
8101 stream->first_chunk * stream->co_size,
8102 (stream->last_chunk - stream->first_chunk) * stream->co_size,
8107 stream->co_chunk = stream->stco;
8108 if (!gst_byte_reader_skip (&stream->co_chunk,
8109 stream->first_chunk * stream->co_size))
8113 stream->stsc_chunk_index = stream->first_chunk;
8116 last_chunk = stream->last_chunk;
8118 if (stream->chunks_are_samples) {
8119 cur = &samples[stream->stsc_chunk_index];
8121 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
8124 stream->stsc_chunk_index = j;
8129 qt_atom_parser_get_offset_unchecked (&stream->co_chunk,
8132 GST_LOG_OBJECT (qtdemux, "Created entry %d with offset "
8133 "%" G_GUINT64_FORMAT, j, cur->offset);
8135 if (stream->samples_per_frame * stream->bytes_per_frame) {
8137 (stream->samples_per_chunk * stream->n_channels) /
8138 stream->samples_per_frame * stream->bytes_per_frame;
8140 cur->size = stream->samples_per_chunk;
8143 GST_DEBUG_OBJECT (qtdemux,
8144 "keyframe sample %d: timestamp %" GST_TIME_FORMAT ", size %u",
8145 j, GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream,
8146 stream->stco_sample_index)), cur->size);
8148 cur->timestamp = stream->stco_sample_index;
8149 cur->duration = stream->samples_per_chunk;
8150 cur->keyframe = TRUE;
8153 stream->stco_sample_index += stream->samples_per_chunk;
8155 stream->stsc_chunk_index = j;
8157 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
8158 guint32 samples_per_chunk;
8159 guint64 chunk_offset;
8161 if (!stream->stsc_sample_index
8162 && !qt_atom_parser_get_offset (&stream->co_chunk, stream->co_size,
8163 &stream->chunk_offset))
8166 samples_per_chunk = stream->samples_per_chunk;
8167 chunk_offset = stream->chunk_offset;
8169 for (k = stream->stsc_sample_index; k < samples_per_chunk; k++) {
8170 GST_LOG_OBJECT (qtdemux, "creating entry %d with offset %"
8171 G_GUINT64_FORMAT " and size %d",
8172 (guint) (cur - samples), chunk_offset, cur->size);
8174 cur->offset = chunk_offset;
8175 chunk_offset += cur->size;
8178 if (G_UNLIKELY (cur > last)) {
8180 stream->stsc_sample_index = k + 1;
8181 stream->chunk_offset = chunk_offset;
8182 stream->stsc_chunk_index = j;
8186 stream->stsc_sample_index = 0;
8188 stream->stsc_chunk_index = j;
8190 stream->stsc_index++;
8193 if (stream->chunks_are_samples)
8197 guint32 n_sample_times;
8199 n_sample_times = stream->n_sample_times;
8202 for (i = stream->stts_index; i < n_sample_times; i++) {
8203 guint32 stts_samples;
8204 gint32 stts_duration;
8207 if (stream->stts_sample_index >= stream->stts_samples
8208 || !stream->stts_sample_index) {
8210 stream->stts_samples =
8211 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
8212 stream->stts_duration =
8213 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
8215 GST_LOG_OBJECT (qtdemux, "block %d, %u timestamps, duration %u",
8216 i, stream->stts_samples, stream->stts_duration);
8218 stream->stts_sample_index = 0;
8221 stts_samples = stream->stts_samples;
8222 stts_duration = stream->stts_duration;
8223 stts_time = stream->stts_time;
8225 for (j = stream->stts_sample_index; j < stts_samples; j++) {
8226 GST_DEBUG_OBJECT (qtdemux,
8227 "sample %d: index %d, timestamp %" GST_TIME_FORMAT,
8228 (guint) (cur - samples), j,
8229 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stts_time)));
8231 cur->timestamp = stts_time;
8232 cur->duration = stts_duration;
8234 /* avoid 32-bit wrap-around,
8235 * but still mind possible 'negative' duration */
8236 stts_time += (gint64) stts_duration;
8239 if (G_UNLIKELY (cur > last)) {
8241 stream->stts_time = stts_time;
8242 stream->stts_sample_index = j + 1;
8246 stream->stts_sample_index = 0;
8247 stream->stts_time = stts_time;
8248 stream->stts_index++;
8250 /* fill up empty timestamps with the last timestamp, this can happen when
8251 * the last samples do not decode and so we don't have timestamps for them.
8252 * We however look at the last timestamp to estimate the track length so we
8253 * need something in here. */
8254 for (; cur < last; cur++) {
8255 GST_DEBUG_OBJECT (qtdemux,
8256 "fill sample %d: timestamp %" GST_TIME_FORMAT,
8257 (guint) (cur - samples),
8258 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stream->stts_time)));
8259 cur->timestamp = stream->stts_time;
8265 /* sample sync, can be NULL */
8266 if (stream->stss_present == TRUE) {
8267 guint32 n_sample_syncs;
8269 n_sample_syncs = stream->n_sample_syncs;
8271 if (!n_sample_syncs) {
8272 GST_DEBUG_OBJECT (qtdemux, "all samples are keyframes");
8273 stream->all_keyframe = TRUE;
8275 for (i = stream->stss_index; i < n_sample_syncs; i++) {
8276 /* note that the first sample is index 1, not 0 */
8279 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stss);
8281 if (G_LIKELY (index > 0 && index <= n_samples)) {
8283 samples[index].keyframe = TRUE;
8284 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
8285 /* and exit if we have enough samples */
8286 if (G_UNLIKELY (index >= n)) {
8293 stream->stss_index = i;
8296 /* stps marks partial sync frames like open GOP I-Frames */
8297 if (stream->stps_present == TRUE) {
8298 guint32 n_sample_partial_syncs;
8300 n_sample_partial_syncs = stream->n_sample_partial_syncs;
8302 /* if there are no entries, the stss table contains the real
8304 if (n_sample_partial_syncs) {
8305 for (i = stream->stps_index; i < n_sample_partial_syncs; i++) {
8306 /* note that the first sample is index 1, not 0 */
8309 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stps);
8311 if (G_LIKELY (index > 0 && index <= n_samples)) {
8313 samples[index].keyframe = TRUE;
8314 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
8315 /* and exit if we have enough samples */
8316 if (G_UNLIKELY (index >= n)) {
8323 stream->stps_index = i;
8327 /* no stss, all samples are keyframes */
8328 stream->all_keyframe = TRUE;
8329 GST_DEBUG_OBJECT (qtdemux, "setting all keyframes");
8334 /* composition time to sample */
8335 if (stream->ctts_present == TRUE) {
8336 guint32 n_composition_times;
8338 gint32 ctts_soffset;
8340 /* Fill in the pts_offsets */
8342 n_composition_times = stream->n_composition_times;
8344 for (i = stream->ctts_index; i < n_composition_times; i++) {
8345 if (stream->ctts_sample_index >= stream->ctts_count
8346 || !stream->ctts_sample_index) {
8347 stream->ctts_count =
8348 gst_byte_reader_get_uint32_be_unchecked (&stream->ctts);
8349 stream->ctts_soffset =
8350 gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
8351 stream->ctts_sample_index = 0;
8354 ctts_count = stream->ctts_count;
8355 ctts_soffset = stream->ctts_soffset;
8357 for (j = stream->ctts_sample_index; j < ctts_count; j++) {
8358 cur->pts_offset = ctts_soffset;
8361 if (G_UNLIKELY (cur > last)) {
8363 stream->ctts_sample_index = j + 1;
8367 stream->ctts_sample_index = 0;
8368 stream->ctts_index++;
8372 stream->stbl_index = n;
8373 /* if index has been completely parsed, free data that is no-longer needed */
8374 if (n + 1 == stream->n_samples) {
8375 gst_qtdemux_stbl_free (stream);
8376 GST_DEBUG_OBJECT (qtdemux, "parsed all available samples;");
8377 if (qtdemux->pullbased) {
8378 GST_DEBUG_OBJECT (qtdemux, "checking for more samples");
8379 while (n + 1 == stream->n_samples)
8380 if (qtdemux_add_fragmented_samples (qtdemux) != GST_FLOW_OK)
8384 GST_OBJECT_UNLOCK (qtdemux);
8391 GST_LOG_OBJECT (qtdemux,
8392 "Tried to parse up to sample %u but this sample has already been parsed",
8394 /* if fragmented, there may be more */
8395 if (qtdemux->fragmented && n == stream->stbl_index)
8397 GST_OBJECT_UNLOCK (qtdemux);
8403 GST_LOG_OBJECT (qtdemux,
8404 "Tried to parse up to sample %u but there are only %u samples", n + 1,
8406 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8407 (_("This file is corrupt and cannot be played.")), (NULL));
8412 GST_OBJECT_UNLOCK (qtdemux);
8413 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8414 (_("This file is corrupt and cannot be played.")), (NULL));
8419 /* collect all segment info for @stream.
8422 qtdemux_parse_segments (GstQTDemux * qtdemux, QtDemuxStream * stream,
8426 /* accept edts if they contain gaps at start and there is only
8427 * one media segment */
8428 gboolean allow_pushbased_edts = TRUE;
8429 gint media_segments_count = 0;
8431 /* parse and prepare segment info from the edit list */
8432 GST_DEBUG_OBJECT (qtdemux, "looking for edit list container");
8433 stream->n_segments = 0;
8434 stream->segments = NULL;
8435 if ((edts = qtdemux_tree_get_child_by_type (trak, FOURCC_edts))) {
8438 gint i, count, entry_size;
8444 GST_DEBUG_OBJECT (qtdemux, "looking for edit list");
8445 if (!(elst = qtdemux_tree_get_child_by_type (edts, FOURCC_elst)))
8448 buffer = elst->data;
8450 version = QT_UINT8 (buffer + 8);
8451 entry_size = (version == 1) ? 20 : 12;
8453 n_segments = QT_UINT32 (buffer + 12);
8455 /* we might allocate a bit too much, at least allocate 1 segment */
8456 stream->segments = g_new (QtDemuxSegment, MAX (n_segments, 1));
8458 /* segments always start from 0 */
8462 for (i = 0; i < n_segments; i++) {
8465 gboolean time_valid = TRUE;
8466 QtDemuxSegment *segment;
8468 GstClockTime media_start = GST_CLOCK_TIME_NONE;
8471 media_time = QT_UINT64 (buffer + 24 + i * entry_size);
8472 duration = QT_UINT64 (buffer + 16 + i * entry_size);
8473 if (media_time == G_MAXUINT64)
8476 media_time = QT_UINT32 (buffer + 20 + i * entry_size);
8477 duration = QT_UINT32 (buffer + 16 + i * entry_size);
8478 if (media_time == G_MAXUINT32)
8483 media_start = QTSTREAMTIME_TO_GSTTIME (stream, media_time);
8485 segment = &stream->segments[count++];
8487 /* time and duration expressed in global timescale */
8488 segment->time = stime;
8489 /* add non scaled values so we don't cause roundoff errors */
8490 if (duration || media_start == GST_CLOCK_TIME_NONE) {
8492 stime = QTTIME_TO_GSTTIME (qtdemux, time);
8493 segment->duration = stime - segment->time;
8495 /* zero duration does not imply media_start == media_stop
8496 * but, only specify media_start.*/
8497 stime = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
8498 if (GST_CLOCK_TIME_IS_VALID (stime) && time_valid
8499 && stime >= media_start) {
8500 segment->duration = stime - media_start;
8502 segment->duration = GST_CLOCK_TIME_NONE;
8505 segment->stop_time = stime;
8507 segment->trak_media_start = media_time;
8508 /* media_time expressed in stream timescale */
8510 segment->media_start = media_start;
8511 segment->media_stop = segment->media_start + segment->duration;
8512 media_segments_count++;
8514 segment->media_start = GST_CLOCK_TIME_NONE;
8515 segment->media_stop = GST_CLOCK_TIME_NONE;
8518 QT_UINT32 (buffer + ((version == 1) ? 32 : 24) + i * entry_size);
8520 if (rate_int <= 1) {
8521 /* 0 is not allowed, some programs write 1 instead of the floating point
8523 GST_WARNING_OBJECT (qtdemux, "found suspicious rate %" G_GUINT32_FORMAT,
8527 segment->rate = rate_int / 65536.0;
8530 GST_DEBUG_OBJECT (qtdemux, "created segment %d time %" GST_TIME_FORMAT
8531 ", duration %" GST_TIME_FORMAT ", media_start %" GST_TIME_FORMAT
8532 " (%" G_GUINT64_FORMAT ") , media_stop %" GST_TIME_FORMAT
8533 " stop_time %" GST_TIME_FORMAT " rate %g, (%d) timescale %u",
8534 i, GST_TIME_ARGS (segment->time),
8535 GST_TIME_ARGS (segment->duration),
8536 GST_TIME_ARGS (segment->media_start), media_time,
8537 GST_TIME_ARGS (segment->media_stop),
8538 GST_TIME_ARGS (segment->stop_time), segment->rate, rate_int,
8540 if (segment->stop_time > qtdemux->segment.stop) {
8541 GST_WARNING_OBJECT (qtdemux, "Segment %d "
8542 " extends to %" GST_TIME_FORMAT
8543 " past the end of the file duration %" GST_TIME_FORMAT
8544 " it will be truncated", i, GST_TIME_ARGS (segment->stop_time),
8545 GST_TIME_ARGS (qtdemux->segment.stop));
8546 qtdemux->segment.stop = segment->stop_time;
8549 GST_DEBUG_OBJECT (qtdemux, "found %d segments", count);
8550 stream->n_segments = count;
8551 if (media_segments_count != 1)
8552 allow_pushbased_edts = FALSE;
8556 /* push based does not handle segments, so act accordingly here,
8557 * and warn if applicable */
8558 if (!qtdemux->pullbased && !allow_pushbased_edts) {
8559 GST_WARNING_OBJECT (qtdemux, "streaming; discarding edit list segments");
8560 /* remove and use default one below, we stream like it anyway */
8561 g_free (stream->segments);
8562 stream->segments = NULL;
8563 stream->n_segments = 0;
8566 /* no segments, create one to play the complete trak */
8567 if (stream->n_segments == 0) {
8568 GstClockTime stream_duration =
8569 QTSTREAMTIME_TO_GSTTIME (stream, stream->duration);
8571 if (stream->segments == NULL)
8572 stream->segments = g_new (QtDemuxSegment, 1);
8574 /* represent unknown our way */
8575 if (stream_duration == 0)
8576 stream_duration = GST_CLOCK_TIME_NONE;
8578 stream->segments[0].time = 0;
8579 stream->segments[0].stop_time = stream_duration;
8580 stream->segments[0].duration = stream_duration;
8581 stream->segments[0].media_start = 0;
8582 stream->segments[0].media_stop = stream_duration;
8583 stream->segments[0].rate = 1.0;
8584 stream->segments[0].trak_media_start = 0;
8586 GST_DEBUG_OBJECT (qtdemux, "created dummy segment %" GST_TIME_FORMAT,
8587 GST_TIME_ARGS (stream_duration));
8588 stream->n_segments = 1;
8589 stream->dummy_segment = TRUE;
8591 GST_DEBUG_OBJECT (qtdemux, "using %d segments", stream->n_segments);
8597 * Parses the stsd atom of a svq3 trak looking for
8598 * the SMI and gama atoms.
8601 qtdemux_parse_svq3_stsd_data (GstQTDemux * qtdemux, GNode * stsd,
8602 guint8 ** gamma, GstBuffer ** seqh)
8604 guint8 *_gamma = NULL;
8605 GstBuffer *_seqh = NULL;
8606 guint8 *stsd_data = stsd->data;
8607 guint32 length = QT_UINT32 (stsd_data);
8611 GST_WARNING_OBJECT (qtdemux, "stsd too short");
8617 version = QT_UINT16 (stsd_data);
8622 while (length > 8) {
8623 guint32 fourcc, size;
8625 size = QT_UINT32 (stsd_data);
8626 fourcc = QT_FOURCC (stsd_data + 4);
8627 data = stsd_data + 8;
8630 GST_WARNING_OBJECT (qtdemux, "Atom of size 0 found, aborting "
8631 "svq3 atom parsing");
8640 GST_WARNING_OBJECT (qtdemux, "Unexpected size %" G_GUINT32_FORMAT
8641 " for gama atom, expected 12", size);
8646 if (size > 16 && QT_FOURCC (data) == FOURCC_SEQH) {
8648 if (_seqh != NULL) {
8649 GST_WARNING_OBJECT (qtdemux, "Unexpected second SEQH SMI atom "
8650 " found, ignoring");
8652 seqh_size = QT_UINT32 (data + 4);
8653 if (seqh_size > 0) {
8654 _seqh = gst_buffer_new_and_alloc (seqh_size);
8655 gst_buffer_fill (_seqh, 0, data + 8, seqh_size);
8662 GST_WARNING_OBJECT (qtdemux, "Unhandled atom %" GST_FOURCC_FORMAT
8663 " in SVQ3 entry in stsd atom", GST_FOURCC_ARGS (fourcc));
8667 if (size <= length) {
8673 GST_WARNING_OBJECT (qtdemux, "SVQ3 entry too short in stsd atom");
8676 GST_WARNING_OBJECT (qtdemux, "Unexpected version for SVQ3 entry %"
8677 G_GUINT16_FORMAT, version);
8688 gst_buffer_unref (_seqh);
8693 qtdemux_get_rtsp_uri_from_hndl (GstQTDemux * qtdemux, GNode * minf)
8700 * Get 'dinf', to get its child 'dref', that might contain a 'hndl'
8701 * atom that might contain a 'data' atom with the rtsp uri.
8702 * This case was reported in bug #597497, some info about
8703 * the hndl atom can be found in TN1195
8705 dinf = qtdemux_tree_get_child_by_type (minf, FOURCC_dinf);
8706 GST_DEBUG_OBJECT (qtdemux, "Trying to obtain rtsp URI for stream trak");
8709 guint32 dref_num_entries = 0;
8710 if (qtdemux_tree_get_child_by_type_full (dinf, FOURCC_dref, &dref) &&
8711 gst_byte_reader_skip (&dref, 4) &&
8712 gst_byte_reader_get_uint32_be (&dref, &dref_num_entries)) {
8715 /* search dref entries for hndl atom */
8716 for (i = 0; i < dref_num_entries; i++) {
8717 guint32 size = 0, type;
8718 guint8 string_len = 0;
8719 if (gst_byte_reader_get_uint32_be (&dref, &size) &&
8720 qt_atom_parser_get_fourcc (&dref, &type)) {
8721 if (type == FOURCC_hndl) {
8722 GST_DEBUG_OBJECT (qtdemux, "Found hndl atom");
8724 /* skip data reference handle bytes and the
8725 * following pascal string and some extra 4
8726 * bytes I have no idea what are */
8727 if (!gst_byte_reader_skip (&dref, 4) ||
8728 !gst_byte_reader_get_uint8 (&dref, &string_len) ||
8729 !gst_byte_reader_skip (&dref, string_len + 4)) {
8730 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl atom");
8734 /* iterate over the atoms to find the data atom */
8735 while (gst_byte_reader_get_remaining (&dref) >= 8) {
8739 if (gst_byte_reader_get_uint32_be (&dref, &atom_size) &&
8740 qt_atom_parser_get_fourcc (&dref, &atom_type)) {
8741 if (atom_type == FOURCC_data) {
8742 const guint8 *uri_aux = NULL;
8744 /* found the data atom that might contain the rtsp uri */
8745 GST_DEBUG_OBJECT (qtdemux, "Found data atom inside "
8746 "hndl atom, interpreting it as an URI");
8747 if (gst_byte_reader_peek_data (&dref, atom_size - 8,
8749 if (g_strstr_len ((gchar *) uri_aux, 7, "rtsp://") != NULL)
8750 uri = g_strndup ((gchar *) uri_aux, atom_size - 8);
8752 GST_WARNING_OBJECT (qtdemux, "Data atom in hndl atom "
8753 "didn't contain a rtsp address");
8755 GST_WARNING_OBJECT (qtdemux, "Failed to get the data "
8760 /* skipping to the next entry */
8761 if (!gst_byte_reader_skip (&dref, atom_size - 8))
8764 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl child "
8771 /* skip to the next entry */
8772 if (!gst_byte_reader_skip (&dref, size - 8))
8775 GST_WARNING_OBJECT (qtdemux, "Error parsing dref atom");
8778 GST_DEBUG_OBJECT (qtdemux, "Finished parsing dref atom");
8784 #define AMR_NB_ALL_MODES 0x81ff
8785 #define AMR_WB_ALL_MODES 0x83ff
8787 qtdemux_parse_amr_bitrate (GstBuffer * buf, gboolean wb)
8789 /* The 'damr' atom is of the form:
8791 * | vendor | decoder_ver | mode_set | mode_change_period | frames/sample |
8792 * 32 b 8 b 16 b 8 b 8 b
8794 * The highest set bit of the first 7 (AMR-NB) or 8 (AMR-WB) bits of mode_set
8795 * represents the highest mode used in the stream (and thus the maximum
8796 * bitrate), with a couple of special cases as seen below.
8799 /* Map of frame type ID -> bitrate */
8800 static const guint nb_bitrates[] = {
8801 4750, 5150, 5900, 6700, 7400, 7950, 10200, 12200
8803 static const guint wb_bitrates[] = {
8804 6600, 8850, 12650, 14250, 15850, 18250, 19850, 23050, 23850
8810 gst_buffer_map (buf, &map, GST_MAP_READ);
8812 if (map.size != 0x11) {
8813 GST_DEBUG ("Atom should have size 0x11, not %" G_GSIZE_FORMAT, map.size);
8817 if (QT_FOURCC (map.data + 4) != FOURCC_damr) {
8818 GST_DEBUG ("Unknown atom in %" GST_FOURCC_FORMAT,
8819 GST_FOURCC_ARGS (QT_UINT32 (map.data + 4)));
8823 mode_set = QT_UINT16 (map.data + 13);
8825 if (mode_set == (wb ? AMR_WB_ALL_MODES : AMR_NB_ALL_MODES))
8826 max_mode = 7 + (wb ? 1 : 0);
8828 /* AMR-NB modes fo from 0-7, and AMR-WB modes go from 0-8 */
8829 max_mode = g_bit_nth_msf ((gulong) mode_set & (wb ? 0x1ff : 0xff), -1);
8831 if (max_mode == -1) {
8832 GST_DEBUG ("No mode indication was found (mode set) = %x",
8837 gst_buffer_unmap (buf, &map);
8838 return wb ? wb_bitrates[max_mode] : nb_bitrates[max_mode];
8841 gst_buffer_unmap (buf, &map);
8846 qtdemux_parse_transformation_matrix (GstQTDemux * qtdemux,
8847 GstByteReader * reader, guint32 * matrix, const gchar * atom)
8850 * 9 values of 32 bits (fixed point 16.16, except 2 5 and 8 that are 2.30)
8856 if (gst_byte_reader_get_remaining (reader) < 36)
8859 matrix[0] = gst_byte_reader_get_uint32_be_unchecked (reader);
8860 matrix[1] = gst_byte_reader_get_uint32_be_unchecked (reader);
8861 matrix[2] = gst_byte_reader_get_uint32_be_unchecked (reader);
8862 matrix[3] = gst_byte_reader_get_uint32_be_unchecked (reader);
8863 matrix[4] = gst_byte_reader_get_uint32_be_unchecked (reader);
8864 matrix[5] = gst_byte_reader_get_uint32_be_unchecked (reader);
8865 matrix[6] = gst_byte_reader_get_uint32_be_unchecked (reader);
8866 matrix[7] = gst_byte_reader_get_uint32_be_unchecked (reader);
8867 matrix[8] = gst_byte_reader_get_uint32_be_unchecked (reader);
8869 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix from atom %s", atom);
8870 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[0] >> 16,
8871 matrix[0] & 0xFFFF, matrix[1] >> 16, matrix[1] & 0xFF, matrix[2] >> 16,
8873 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[3] >> 16,
8874 matrix[3] & 0xFFFF, matrix[4] >> 16, matrix[4] & 0xFF, matrix[5] >> 16,
8876 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[6] >> 16,
8877 matrix[6] & 0xFFFF, matrix[7] >> 16, matrix[7] & 0xFF, matrix[8] >> 16,
8884 qtdemux_inspect_transformation_matrix (GstQTDemux * qtdemux,
8885 QtDemuxStream * stream, guint32 * matrix, GstTagList ** taglist)
8892 * This macro will only compare value abdegh, it expects cfi to have already
8895 #define QTCHECK_MATRIX(m,a,b,d,e) ((m)[0] == (a << 16) && (m)[1] == (b << 16) && \
8896 (m)[3] == (d << 16) && (m)[4] == (e << 16))
8898 /* only handle the cases where the last column has standard values */
8899 if (matrix[2] == 0 && matrix[5] == 0 && matrix[8] == 1 << 30) {
8900 const gchar *rotation_tag = NULL;
8902 /* no rotation needed */
8903 if (QTCHECK_MATRIX (matrix, 1, 0, 0, 1)) {
8905 } else if (QTCHECK_MATRIX (matrix, 0, 1, G_MAXUINT16, 0)) {
8906 rotation_tag = "rotate-90";
8907 } else if (QTCHECK_MATRIX (matrix, G_MAXUINT16, 0, 0, G_MAXUINT16)) {
8908 rotation_tag = "rotate-180";
8909 } else if (QTCHECK_MATRIX (matrix, 0, G_MAXUINT16, 1, 0)) {
8910 rotation_tag = "rotate-270";
8912 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
8915 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix rotation %s",
8917 if (rotation_tag != NULL) {
8918 if (*taglist == NULL)
8919 *taglist = gst_tag_list_new_empty ();
8920 gst_tag_list_add (*taglist, GST_TAG_MERGE_REPLACE,
8921 GST_TAG_IMAGE_ORIENTATION, rotation_tag, NULL);
8924 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
8928 /* Parses the boxes defined in ISO/IEC 14496-12 that enable support for
8929 * protected streams (sinf, frma, schm and schi); if the protection scheme is
8930 * Common Encryption (cenc), the function will also parse the tenc box (defined
8931 * in ISO/IEC 23001-7). @container points to the node that contains these boxes
8932 * (typically an enc[v|a|t|s] sample entry); the function will set
8933 * @original_fmt to the fourcc of the original unencrypted stream format.
8934 * Returns TRUE if successful; FALSE otherwise. */
8936 qtdemux_parse_protection_scheme_info (GstQTDemux * qtdemux,
8937 QtDemuxStream * stream, GNode * container, guint32 * original_fmt)
8944 g_return_val_if_fail (qtdemux != NULL, FALSE);
8945 g_return_val_if_fail (stream != NULL, FALSE);
8946 g_return_val_if_fail (container != NULL, FALSE);
8947 g_return_val_if_fail (original_fmt != NULL, FALSE);
8949 sinf = qtdemux_tree_get_child_by_type (container, FOURCC_sinf);
8950 if (G_UNLIKELY (!sinf)) {
8951 if (stream->protection_scheme_type == FOURCC_cenc) {
8952 GST_ERROR_OBJECT (qtdemux, "sinf box does not contain schi box, which is "
8953 "mandatory for Common Encryption");
8959 frma = qtdemux_tree_get_child_by_type (sinf, FOURCC_frma);
8960 if (G_UNLIKELY (!frma)) {
8961 GST_ERROR_OBJECT (qtdemux, "sinf box does not contain mandatory frma box");
8965 *original_fmt = QT_FOURCC ((const guint8 *) frma->data + 8);
8966 GST_DEBUG_OBJECT (qtdemux, "original stream format: '%" GST_FOURCC_FORMAT "'",
8967 GST_FOURCC_ARGS (*original_fmt));
8969 schm = qtdemux_tree_get_child_by_type (sinf, FOURCC_schm);
8971 GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schm box");
8974 stream->protection_scheme_type = QT_FOURCC ((const guint8 *) schm->data + 12);
8975 stream->protection_scheme_version =
8976 QT_UINT32 ((const guint8 *) schm->data + 16);
8978 GST_DEBUG_OBJECT (qtdemux,
8979 "protection_scheme_type: %" GST_FOURCC_FORMAT ", "
8980 "protection_scheme_version: %#010x",
8981 GST_FOURCC_ARGS (stream->protection_scheme_type),
8982 stream->protection_scheme_version);
8984 schi = qtdemux_tree_get_child_by_type (sinf, FOURCC_schi);
8986 GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schi box");
8989 if (stream->protection_scheme_type == FOURCC_cenc) {
8990 QtDemuxCencSampleSetInfo *info;
8992 const guint8 *tenc_data;
8993 guint32 isEncrypted;
8995 const guint8 *default_kid;
8998 if (G_UNLIKELY (!stream->protection_scheme_info))
8999 stream->protection_scheme_info =
9000 g_malloc0 (sizeof (QtDemuxCencSampleSetInfo));
9002 info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
9004 tenc = qtdemux_tree_get_child_by_type (schi, FOURCC_tenc);
9006 GST_ERROR_OBJECT (qtdemux, "schi box does not contain tenc box, "
9007 "which is mandatory for Common Encryption");
9010 tenc_data = (const guint8 *) tenc->data + 12;
9011 isEncrypted = QT_UINT24 (tenc_data);
9012 iv_size = QT_UINT8 (tenc_data + 3);
9013 default_kid = (tenc_data + 4);
9014 kid_buf = gst_buffer_new_allocate (NULL, 16, NULL);
9015 gst_buffer_fill (kid_buf, 0, default_kid, 16);
9016 if (info->default_properties)
9017 gst_structure_free (info->default_properties);
9018 info->default_properties =
9019 gst_structure_new ("application/x-cenc",
9020 "iv_size", G_TYPE_UINT, iv_size,
9021 "encrypted", G_TYPE_BOOLEAN, (isEncrypted == 1),
9022 "kid", GST_TYPE_BUFFER, kid_buf, NULL);
9023 GST_DEBUG_OBJECT (qtdemux, "default sample properties: "
9024 "is_encrypted=%u, iv_size=%u", isEncrypted, iv_size);
9025 gst_buffer_unref (kid_buf);
9031 * With each track we associate a new QtDemuxStream that contains all the info
9033 * traks that do not decode to something (like strm traks) will not have a pad.
9036 qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
9055 QtDemuxStream *stream = NULL;
9056 gboolean new_stream = FALSE;
9057 gchar *codec = NULL;
9058 const guint8 *stsd_data;
9059 guint16 lang_code; /* quicktime lang code or packed iso code */
9061 guint32 tkhd_flags = 0;
9062 guint8 tkhd_version = 0;
9064 guint value_size, stsd_len, len;
9068 GST_DEBUG_OBJECT (qtdemux, "parse_trak");
9070 if (!qtdemux_tree_get_child_by_type_full (trak, FOURCC_tkhd, &tkhd)
9071 || !gst_byte_reader_get_uint8 (&tkhd, &tkhd_version)
9072 || !gst_byte_reader_get_uint24_be (&tkhd, &tkhd_flags))
9075 /* pick between 64 or 32 bits */
9076 value_size = tkhd_version == 1 ? 8 : 4;
9077 if (!gst_byte_reader_skip (&tkhd, value_size * 2) ||
9078 !gst_byte_reader_get_uint32_be (&tkhd, &track_id))
9081 if (!qtdemux->got_moov) {
9082 if (qtdemux_find_stream (qtdemux, track_id))
9083 goto existing_stream;
9084 stream = _create_stream ();
9085 stream->track_id = track_id;
9088 stream = qtdemux_find_stream (qtdemux, track_id);
9090 GST_WARNING_OBJECT (qtdemux, "Stream not found, going to ignore it");
9094 /* flush samples data from this track from previous moov */
9095 gst_qtdemux_stream_flush_segments_data (qtdemux, stream);
9096 gst_qtdemux_stream_flush_samples_data (qtdemux, stream);
9098 /* need defaults for fragments */
9099 qtdemux_parse_trex (qtdemux, stream, &dummy, &dummy, &dummy);
9101 if (stream->pending_tags == NULL)
9102 stream->pending_tags = gst_tag_list_new_empty ();
9104 if ((tkhd_flags & 1) == 0)
9105 stream->disabled = TRUE;
9107 GST_LOG_OBJECT (qtdemux, "track[tkhd] version/flags/id: 0x%02x/%06x/%u",
9108 tkhd_version, tkhd_flags, stream->track_id);
9110 if (!(mdia = qtdemux_tree_get_child_by_type (trak, FOURCC_mdia)))
9113 if (!(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mdhd))) {
9114 /* be nice for some crooked mjp2 files that use mhdr for mdhd */
9115 if (qtdemux->major_brand != FOURCC_mjp2 ||
9116 !(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mhdr)))
9120 len = QT_UINT32 ((guint8 *) mdhd->data);
9121 version = QT_UINT32 ((guint8 *) mdhd->data + 8);
9122 GST_LOG_OBJECT (qtdemux, "track version/flags: %08x", version);
9123 if (version == 0x01000000) {
9126 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 28);
9127 stream->duration = QT_UINT64 ((guint8 *) mdhd->data + 32);
9128 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 36);
9132 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 20);
9133 stream->duration = QT_UINT32 ((guint8 *) mdhd->data + 24);
9134 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 28);
9137 if (lang_code < 0x400) {
9138 qtdemux_lang_map_qt_code_to_iso (stream->lang_id, lang_code);
9139 } else if (lang_code == 0x7fff) {
9140 stream->lang_id[0] = 0; /* unspecified */
9142 stream->lang_id[0] = 0x60 + ((lang_code >> 10) & 0x1F);
9143 stream->lang_id[1] = 0x60 + ((lang_code >> 5) & 0x1F);
9144 stream->lang_id[2] = 0x60 + (lang_code & 0x1F);
9145 stream->lang_id[3] = 0;
9148 GST_LOG_OBJECT (qtdemux, "track timescale: %" G_GUINT32_FORMAT,
9150 GST_LOG_OBJECT (qtdemux, "track duration: %" G_GUINT64_FORMAT,
9152 GST_LOG_OBJECT (qtdemux, "track language code/id: 0x%04x/%s",
9153 lang_code, stream->lang_id);
9155 if (G_UNLIKELY (stream->timescale == 0 || qtdemux->timescale == 0))
9158 if ((tref = qtdemux_tree_get_child_by_type (trak, FOURCC_tref))) {
9159 /* chapters track reference */
9160 GNode *chap = qtdemux_tree_get_child_by_type (tref, FOURCC_chap);
9162 gsize length = GST_READ_UINT32_BE (chap->data);
9163 if (qtdemux->chapters_track_id)
9164 GST_FIXME_OBJECT (qtdemux, "Multiple CHAP tracks");
9167 qtdemux->chapters_track_id =
9168 GST_READ_UINT32_BE ((gint8 *) chap->data + 8);
9173 /* fragmented files may have bogus duration in moov */
9174 if (!qtdemux->fragmented &&
9175 qtdemux->duration != G_MAXINT64 && stream->duration != G_MAXINT32) {
9176 guint64 tdur1, tdur2;
9178 /* don't overflow */
9179 tdur1 = stream->timescale * (guint64) qtdemux->duration;
9180 tdur2 = qtdemux->timescale * (guint64) stream->duration;
9183 * some of those trailers, nowadays, have prologue images that are
9184 * themselves video tracks as well. I haven't really found a way to
9185 * identify those yet, except for just looking at their duration. */
9186 if (tdur1 != 0 && (tdur2 * 10 / tdur1) < 2) {
9187 GST_WARNING_OBJECT (qtdemux,
9188 "Track shorter than 20%% (%" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT
9189 " vs. %" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT ") of the stream "
9190 "found, assuming preview image or something; skipping track",
9191 stream->duration, stream->timescale, qtdemux->duration,
9192 qtdemux->timescale);
9194 gst_qtdemux_stream_free (qtdemux, stream);
9199 if (!(hdlr = qtdemux_tree_get_child_by_type (mdia, FOURCC_hdlr)))
9202 GST_LOG_OBJECT (qtdemux, "track type: %" GST_FOURCC_FORMAT,
9203 GST_FOURCC_ARGS (QT_FOURCC ((guint8 *) hdlr->data + 12)));
9205 len = QT_UINT32 ((guint8 *) hdlr->data);
9207 stream->subtype = QT_FOURCC ((guint8 *) hdlr->data + 16);
9208 GST_LOG_OBJECT (qtdemux, "track subtype: %" GST_FOURCC_FORMAT,
9209 GST_FOURCC_ARGS (stream->subtype));
9211 if (!(minf = qtdemux_tree_get_child_by_type (mdia, FOURCC_minf)))
9214 if (!(stbl = qtdemux_tree_get_child_by_type (minf, FOURCC_stbl)))
9217 /*parse svmi header if existing */
9218 svmi = qtdemux_tree_get_child_by_type (stbl, FOURCC_svmi);
9220 len = QT_UINT32 ((guint8 *) svmi->data);
9221 version = QT_UINT32 ((guint8 *) svmi->data + 8);
9223 GstVideoMultiviewMode mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
9224 GstVideoMultiviewFlags flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
9225 guint8 frame_type, frame_layout;
9227 /* MPEG-A stereo video */
9228 if (qtdemux->major_brand == FOURCC_ss02)
9229 flags |= GST_VIDEO_MULTIVIEW_FLAGS_MIXED_MONO;
9231 frame_type = QT_UINT8 ((guint8 *) svmi->data + 12);
9232 frame_layout = QT_UINT8 ((guint8 *) svmi->data + 13) & 0x01;
9233 switch (frame_type) {
9235 mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
9238 mode = GST_VIDEO_MULTIVIEW_MODE_ROW_INTERLEAVED;
9241 mode = GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME;
9244 /* mode 3 is primary/secondary view sequence, ie
9245 * left/right views in separate tracks. See section 7.2
9246 * of ISO/IEC 23000-11:2009 */
9247 GST_FIXME_OBJECT (qtdemux,
9248 "Implement stereo video in separate streams");
9251 if ((frame_layout & 0x1) == 0)
9252 flags |= GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
9254 GST_LOG_OBJECT (qtdemux,
9255 "StereoVideo: composition type: %u, is_left_first: %u",
9256 frame_type, frame_layout);
9257 stream->multiview_mode = mode;
9258 stream->multiview_flags = flags;
9263 if (!(stsd = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsd)))
9265 stsd_data = (const guint8 *) stsd->data;
9267 /* stsd should at least have one entry */
9268 stsd_len = QT_UINT32 (stsd_data);
9269 if (stsd_len < 24) {
9270 /* .. but skip stream with empty stsd produced by some Vivotek cameras */
9271 if (stream->subtype == FOURCC_vivo) {
9273 gst_qtdemux_stream_free (qtdemux, stream);
9280 GST_LOG_OBJECT (qtdemux, "stsd len: %d", stsd_len);
9282 /* and that entry should fit within stsd */
9283 len = QT_UINT32 (stsd_data + 16);
9284 if (len > stsd_len + 16)
9287 stream->fourcc = fourcc = QT_FOURCC (stsd_data + 16 + 4);
9288 GST_LOG_OBJECT (qtdemux, "stsd type: %" GST_FOURCC_FORMAT,
9289 GST_FOURCC_ARGS (stream->fourcc));
9290 GST_LOG_OBJECT (qtdemux, "stsd type len: %d", len);
9292 if ((fourcc == FOURCC_drms) || (fourcc == FOURCC_drmi))
9293 goto error_encrypted;
9295 if (fourcc == FOURCC_encv || fourcc == FOURCC_enca) {
9296 GNode *enc = qtdemux_tree_get_child_by_type (stsd, fourcc);
9297 stream->protected = TRUE;
9298 if (!qtdemux_parse_protection_scheme_info (qtdemux, stream, enc, &fourcc))
9299 GST_ERROR_OBJECT (qtdemux, "Failed to parse protection scheme info");
9302 if (stream->subtype == FOURCC_vide) {
9303 guint32 w = 0, h = 0;
9305 gint depth, palette_size, palette_count;
9307 guint32 *palette_data = NULL;
9309 stream->sampled = TRUE;
9311 /* version 1 uses some 64-bit ints */
9312 if (!gst_byte_reader_skip (&tkhd, 20 + value_size))
9315 if (!qtdemux_parse_transformation_matrix (qtdemux, &tkhd, matrix, "tkhd"))
9318 if (!gst_byte_reader_get_uint32_be (&tkhd, &w)
9319 || !gst_byte_reader_get_uint32_be (&tkhd, &h))
9322 stream->display_width = w >> 16;
9323 stream->display_height = h >> 16;
9325 qtdemux_inspect_transformation_matrix (qtdemux, stream, matrix,
9326 &stream->pending_tags);
9332 stream->width = QT_UINT16 (stsd_data + offset + 32);
9333 stream->height = QT_UINT16 (stsd_data + offset + 34);
9334 stream->fps_n = 0; /* this is filled in later */
9335 stream->fps_d = 0; /* this is filled in later */
9336 stream->bits_per_sample = QT_UINT16 (stsd_data + offset + 82);
9337 stream->color_table_id = QT_UINT16 (stsd_data + offset + 84);
9339 /* if color_table_id is 0, ctab atom must follow; however some files
9340 * produced by TMPEGEnc have color_table_id = 0 and no ctab atom, so
9341 * if color table is not present we'll correct the value */
9342 if (stream->color_table_id == 0 &&
9343 (len < 90 || QT_FOURCC (stsd_data + offset + 86) != FOURCC_ctab)) {
9344 stream->color_table_id = -1;
9347 GST_LOG_OBJECT (qtdemux, "width %d, height %d, bps %d, color table id %d",
9348 stream->width, stream->height, stream->bits_per_sample,
9349 stream->color_table_id);
9351 depth = stream->bits_per_sample;
9353 /* more than 32 bits means grayscale */
9354 gray = (depth > 32);
9355 /* low 32 bits specify the depth */
9358 /* different number of palette entries is determined by depth. */
9360 if ((depth == 1) || (depth == 2) || (depth == 4) || (depth == 8))
9361 palette_count = (1 << depth);
9362 palette_size = palette_count * 4;
9364 if (stream->color_table_id) {
9365 switch (palette_count) {
9369 palette_data = g_memdup (ff_qt_default_palette_2, palette_size);
9372 palette_data = g_memdup (ff_qt_default_palette_4, palette_size);
9376 palette_data = g_memdup (ff_qt_grayscale_palette_16, palette_size);
9378 palette_data = g_memdup (ff_qt_default_palette_16, palette_size);
9382 palette_data = g_memdup (ff_qt_grayscale_palette_256, palette_size);
9384 palette_data = g_memdup (ff_qt_default_palette_256, palette_size);
9387 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
9388 (_("The video in this file might not play correctly.")),
9389 ("unsupported palette depth %d", depth));
9393 gint i, j, start, end;
9399 start = QT_UINT32 (stsd_data + offset + 86);
9400 palette_count = QT_UINT16 (stsd_data + offset + 90);
9401 end = QT_UINT16 (stsd_data + offset + 92);
9403 GST_LOG_OBJECT (qtdemux, "start %d, end %d, palette_count %d",
9404 start, end, palette_count);
9411 if (len < 94 + (end - start) * 8)
9414 /* palette is always the same size */
9415 palette_data = g_malloc0 (256 * 4);
9416 palette_size = 256 * 4;
9418 for (j = 0, i = start; i <= end; j++, i++) {
9421 a = QT_UINT16 (stsd_data + offset + 94 + (j * 8));
9422 r = QT_UINT16 (stsd_data + offset + 96 + (j * 8));
9423 g = QT_UINT16 (stsd_data + offset + 98 + (j * 8));
9424 b = QT_UINT16 (stsd_data + offset + 100 + (j * 8));
9426 palette_data[i] = ((a & 0xff00) << 16) | ((r & 0xff00) << 8) |
9427 (g & 0xff00) | (b >> 8);
9432 gst_caps_unref (stream->caps);
9435 qtdemux_video_caps (qtdemux, stream, fourcc, stsd_data, &codec);
9436 if (G_UNLIKELY (!stream->caps)) {
9437 g_free (palette_data);
9438 goto unknown_stream;
9442 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
9443 GST_TAG_VIDEO_CODEC, codec, NULL);
9452 if (stream->rgb8_palette)
9453 gst_memory_unref (stream->rgb8_palette);
9454 stream->rgb8_palette = gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY,
9455 palette_data, palette_size, 0, palette_size, palette_data, g_free);
9457 s = gst_caps_get_structure (stream->caps, 0);
9459 /* non-raw video has a palette_data property. raw video has the palette as
9460 * an extra plane that we append to the output buffers before we push
9462 if (!gst_structure_has_name (s, "video/x-raw")) {
9465 palette = gst_buffer_new ();
9466 gst_buffer_append_memory (palette, stream->rgb8_palette);
9467 stream->rgb8_palette = NULL;
9469 gst_caps_set_simple (stream->caps, "palette_data",
9470 GST_TYPE_BUFFER, palette, NULL);
9471 gst_buffer_unref (palette);
9473 } else if (palette_count != 0) {
9474 GST_ELEMENT_WARNING (qtdemux, STREAM, NOT_IMPLEMENTED,
9475 (NULL), ("Unsupported palette depth %d", depth));
9478 GST_LOG_OBJECT (qtdemux, "frame count: %u",
9479 QT_UINT16 (stsd_data + offset + 48));
9483 /* pick 'the' stsd child */
9484 if (!stream->protected)
9485 mp4v = qtdemux_tree_get_child_by_type (stsd, fourcc);
9487 mp4v = qtdemux_tree_get_child_by_type (stsd, FOURCC_encv);
9490 esds = qtdemux_tree_get_child_by_type (mp4v, FOURCC_esds);
9491 pasp = qtdemux_tree_get_child_by_type (mp4v, FOURCC_pasp);
9495 const guint8 *pasp_data = (const guint8 *) pasp->data;
9497 stream->par_w = QT_UINT32 (pasp_data + 8);
9498 stream->par_h = QT_UINT32 (pasp_data + 12);
9505 gst_qtdemux_handle_esds (qtdemux, stream, esds, stream->pending_tags);
9512 gint len = QT_UINT32 (stsd_data) - 0x66;
9513 const guint8 *avc_data = stsd_data + 0x66;
9516 while (len >= 0x8) {
9519 if (QT_UINT32 (avc_data) <= len)
9520 size = QT_UINT32 (avc_data) - 0x8;
9525 /* No real data, so break out */
9528 switch (QT_FOURCC (avc_data + 0x4)) {
9531 /* parse, if found */
9534 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
9536 /* First 4 bytes are the length of the atom, the next 4 bytes
9537 * are the fourcc, the next 1 byte is the version, and the
9538 * subsequent bytes are profile_tier_level structure like data. */
9539 gst_codec_utils_h264_caps_set_level_and_profile (stream->caps,
9540 avc_data + 8 + 1, size - 1);
9541 buf = gst_buffer_new_and_alloc (size);
9542 gst_buffer_fill (buf, 0, avc_data + 0x8, size);
9543 gst_caps_set_simple (stream->caps,
9544 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9545 gst_buffer_unref (buf);
9553 GST_DEBUG_OBJECT (qtdemux, "found strf codec_data in stsd");
9555 /* First 4 bytes are the length of the atom, the next 4 bytes
9556 * are the fourcc, next 40 bytes are BITMAPINFOHEADER,
9557 * next 1 byte is the version, and the
9558 * subsequent bytes are sequence parameter set like data. */
9560 size -= 40; /* we'll be skipping BITMAPINFOHEADER */
9562 gst_codec_utils_h264_caps_set_level_and_profile (stream->caps,
9563 avc_data + 8 + 40 + 1, size - 1);
9565 buf = gst_buffer_new_and_alloc (size);
9566 gst_buffer_fill (buf, 0, avc_data + 8 + 40, size);
9567 gst_caps_set_simple (stream->caps,
9568 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9569 gst_buffer_unref (buf);
9575 guint avg_bitrate, max_bitrate;
9577 /* bufferSizeDB, maxBitrate and avgBitrate - 4 bytes each */
9581 max_bitrate = QT_UINT32 (avc_data + 0xc);
9582 avg_bitrate = QT_UINT32 (avc_data + 0x10);
9584 if (!max_bitrate && !avg_bitrate)
9587 /* Some muxers seem to swap the average and maximum bitrates
9588 * (I'm looking at you, YouTube), so we swap for sanity. */
9589 if (max_bitrate > 0 && max_bitrate < avg_bitrate) {
9590 guint temp = avg_bitrate;
9592 avg_bitrate = max_bitrate;
9596 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
9597 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
9598 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
9600 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
9601 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
9602 GST_TAG_BITRATE, avg_bitrate, NULL);
9613 avc_data += size + 8;
9622 gint len = QT_UINT32 (stsd_data) - 0x66;
9623 const guint8 *hevc_data = stsd_data + 0x66;
9626 while (len >= 0x8) {
9629 if (QT_UINT32 (hevc_data) <= len)
9630 size = QT_UINT32 (hevc_data) - 0x8;
9635 /* No real data, so break out */
9638 switch (QT_FOURCC (hevc_data + 0x4)) {
9641 /* parse, if found */
9644 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
9646 /* First 4 bytes are the length of the atom, the next 4 bytes
9647 * are the fourcc, the next 1 byte is the version, and the
9648 * subsequent bytes are sequence parameter set like data. */
9649 gst_codec_utils_h265_caps_set_level_tier_and_profile
9650 (stream->caps, hevc_data + 8 + 1, size - 1);
9652 buf = gst_buffer_new_and_alloc (size);
9653 gst_buffer_fill (buf, 0, hevc_data + 0x8, size);
9654 gst_caps_set_simple (stream->caps,
9655 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9656 gst_buffer_unref (buf);
9663 hevc_data += size + 8;
9674 GST_DEBUG_OBJECT (qtdemux, "found %" GST_FOURCC_FORMAT,
9675 GST_FOURCC_ARGS (fourcc));
9677 /* codec data might be in glbl extension atom */
9679 qtdemux_tree_get_child_by_type (mp4v, FOURCC_glbl) : NULL;
9685 GST_DEBUG_OBJECT (qtdemux, "found glbl data in stsd");
9687 len = QT_UINT32 (data);
9690 buf = gst_buffer_new_and_alloc (len);
9691 gst_buffer_fill (buf, 0, data + 8, len);
9692 gst_caps_set_simple (stream->caps,
9693 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9694 gst_buffer_unref (buf);
9701 /* see annex I of the jpeg2000 spec */
9702 GNode *jp2h, *ihdr, *colr, *mjp2, *field, *prefix, *cmap, *cdef;
9704 const gchar *colorspace = NULL;
9706 guint32 ncomp_map = 0;
9707 gint32 *comp_map = NULL;
9708 guint32 nchan_def = 0;
9709 gint32 *chan_def = NULL;
9711 GST_DEBUG_OBJECT (qtdemux, "found mjp2");
9712 /* some required atoms */
9713 mjp2 = qtdemux_tree_get_child_by_type (stsd, FOURCC_mjp2);
9716 jp2h = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2h);
9720 /* number of components; redundant with info in codestream, but useful
9722 ihdr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_ihdr);
9723 if (!ihdr || QT_UINT32 (ihdr->data) != 22)
9725 ncomp = QT_UINT16 (((guint8 *) ihdr->data) + 16);
9727 colr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_colr);
9730 GST_DEBUG_OBJECT (qtdemux, "found colr");
9731 /* extract colour space info */
9732 if (QT_UINT8 ((guint8 *) colr->data + 8) == 1) {
9733 switch (QT_UINT32 ((guint8 *) colr->data + 11)) {
9735 colorspace = "sRGB";
9738 colorspace = "GRAY";
9741 colorspace = "sYUV";
9749 /* colr is required, and only values 16, 17, and 18 are specified,
9750 so error if we have no colorspace */
9753 /* extract component mapping */
9754 cmap = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cmap);
9756 guint32 cmap_len = 0;
9758 cmap_len = QT_UINT32 (cmap->data);
9759 if (cmap_len >= 8) {
9760 /* normal box, subtract off header */
9762 /* cmap: { u16 cmp; u8 mtyp; u8 pcol; }* */
9763 if (cmap_len % 4 == 0) {
9764 ncomp_map = (cmap_len / 4);
9765 comp_map = g_new0 (gint32, ncomp_map);
9766 for (i = 0; i < ncomp_map; i++) {
9769 cmp = QT_UINT16 (((guint8 *) cmap->data) + 8 + i * 4);
9770 mtyp = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 2);
9771 pcol = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 3);
9772 comp_map[i] = (mtyp << 24) | (pcol << 16) | cmp;
9777 /* extract channel definitions */
9778 cdef = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cdef);
9780 guint32 cdef_len = 0;
9782 cdef_len = QT_UINT32 (cdef->data);
9783 if (cdef_len >= 10) {
9784 /* normal box, subtract off header and len */
9786 /* cdef: u16 n; { u16 cn; u16 typ; u16 asoc; }* */
9787 if (cdef_len % 6 == 0) {
9788 nchan_def = (cdef_len / 6);
9789 chan_def = g_new0 (gint32, nchan_def);
9790 for (i = 0; i < nchan_def; i++)
9792 for (i = 0; i < nchan_def; i++) {
9793 guint16 cn, typ, asoc;
9794 cn = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6);
9795 typ = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 2);
9796 asoc = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 4);
9797 if (cn < nchan_def) {
9800 chan_def[cn] = asoc;
9803 chan_def[cn] = 0; /* alpha */
9806 chan_def[cn] = -typ;
9814 gst_caps_set_simple (stream->caps,
9815 "num-components", G_TYPE_INT, ncomp, NULL);
9816 gst_caps_set_simple (stream->caps,
9817 "colorspace", G_TYPE_STRING, colorspace, NULL);
9820 GValue arr = { 0, };
9821 GValue elt = { 0, };
9823 g_value_init (&arr, GST_TYPE_ARRAY);
9824 g_value_init (&elt, G_TYPE_INT);
9825 for (i = 0; i < ncomp_map; i++) {
9826 g_value_set_int (&elt, comp_map[i]);
9827 gst_value_array_append_value (&arr, &elt);
9829 gst_structure_set_value (gst_caps_get_structure (stream->caps, 0),
9830 "component-map", &arr);
9831 g_value_unset (&elt);
9832 g_value_unset (&arr);
9837 GValue arr = { 0, };
9838 GValue elt = { 0, };
9840 g_value_init (&arr, GST_TYPE_ARRAY);
9841 g_value_init (&elt, G_TYPE_INT);
9842 for (i = 0; i < nchan_def; i++) {
9843 g_value_set_int (&elt, chan_def[i]);
9844 gst_value_array_append_value (&arr, &elt);
9846 gst_structure_set_value (gst_caps_get_structure (stream->caps, 0),
9847 "channel-definitions", &arr);
9848 g_value_unset (&elt);
9849 g_value_unset (&arr);
9853 /* some optional atoms */
9854 field = qtdemux_tree_get_child_by_type (mjp2, FOURCC_fiel);
9855 prefix = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2x);
9857 /* indicate possible fields in caps */
9859 data = (guint8 *) field->data + 8;
9861 gst_caps_set_simple (stream->caps, "fields", G_TYPE_INT,
9862 (gint) * data, NULL);
9864 /* add codec_data if provided */
9869 GST_DEBUG_OBJECT (qtdemux, "found prefix data in stsd");
9870 data = prefix->data;
9871 len = QT_UINT32 (data);
9874 buf = gst_buffer_new_and_alloc (len);
9875 gst_buffer_fill (buf, 0, data + 8, len);
9876 gst_caps_set_simple (stream->caps,
9877 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9878 gst_buffer_unref (buf);
9887 GstBuffer *seqh = NULL;
9888 guint8 *gamma_data = NULL;
9889 gint len = QT_UINT32 (stsd_data);
9891 qtdemux_parse_svq3_stsd_data (qtdemux, stsd, &gamma_data, &seqh);
9893 gst_caps_set_simple (stream->caps, "applied-gamma", G_TYPE_DOUBLE,
9894 QT_FP32 (gamma_data), NULL);
9897 /* sorry for the bad name, but we don't know what this is, other
9898 * than its own fourcc */
9899 gst_caps_set_simple (stream->caps, "seqh", GST_TYPE_BUFFER, seqh,
9903 GST_DEBUG_OBJECT (qtdemux, "found codec_data in stsd");
9904 buf = gst_buffer_new_and_alloc (len);
9905 gst_buffer_fill (buf, 0, stsd_data, len);
9906 gst_caps_set_simple (stream->caps,
9907 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9908 gst_buffer_unref (buf);
9914 gst_caps_set_simple (stream->caps,
9915 "depth", G_TYPE_INT, QT_UINT16 (stsd_data + offset + 82), NULL);
9922 GST_DEBUG_OBJECT (qtdemux, "found XiTh");
9923 xith = qtdemux_tree_get_child_by_type (stsd, FOURCC_XiTh);
9927 xdxt = qtdemux_tree_get_child_by_type (xith, FOURCC_XdxT);
9931 GST_DEBUG_OBJECT (qtdemux, "found XdxT node");
9932 /* collect the headers and store them in a stream list so that we can
9933 * send them out first */
9934 qtdemux_parse_theora_extension (qtdemux, stream, xdxt);
9944 GST_DEBUG_OBJECT (qtdemux, "parse ovc1 header");
9945 ovc1 = qtdemux_tree_get_child_by_type (stsd, FOURCC_ovc1);
9948 ovc1_data = ovc1->data;
9949 ovc1_len = QT_UINT32 (ovc1_data);
9950 if (ovc1_len <= 198) {
9951 GST_WARNING_OBJECT (qtdemux, "Too small ovc1 header, skipping");
9954 buf = gst_buffer_new_and_alloc (ovc1_len - 198);
9955 gst_buffer_fill (buf, 0, ovc1_data + 198, ovc1_len - 198);
9956 gst_caps_set_simple (stream->caps,
9957 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9958 gst_buffer_unref (buf);
9963 gint len = QT_UINT32 (stsd_data) - 0x66;
9964 const guint8 *vc1_data = stsd_data + 0x66;
9970 if (QT_UINT32 (vc1_data) <= len)
9971 size = QT_UINT32 (vc1_data) - 8;
9976 /* No real data, so break out */
9979 switch (QT_FOURCC (vc1_data + 0x4)) {
9980 case GST_MAKE_FOURCC ('d', 'v', 'c', '1'):
9984 GST_DEBUG_OBJECT (qtdemux, "found dvc1 codec_data in stsd");
9985 buf = gst_buffer_new_and_alloc (size);
9986 gst_buffer_fill (buf, 0, vc1_data + 8, size);
9987 gst_caps_set_simple (stream->caps,
9988 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9989 gst_buffer_unref (buf);
9996 vc1_data += size + 8;
10005 GST_INFO_OBJECT (qtdemux,
10006 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
10007 GST_FOURCC_ARGS (fourcc), stream->caps);
10009 } else if (stream->subtype == FOURCC_soun) {
10010 int version, samplesize;
10011 guint16 compression_id;
10012 gboolean amrwb = FALSE;
10015 /* sample description entry (16) + sound sample description v0 (20) */
10019 version = QT_UINT32 (stsd_data + offset);
10020 stream->n_channels = QT_UINT16 (stsd_data + offset + 8);
10021 samplesize = QT_UINT16 (stsd_data + offset + 10);
10022 compression_id = QT_UINT16 (stsd_data + offset + 12);
10023 stream->rate = QT_FP32 (stsd_data + offset + 16);
10025 GST_LOG_OBJECT (qtdemux, "version/rev: %08x", version);
10026 GST_LOG_OBJECT (qtdemux, "vendor: %08x",
10027 QT_UINT32 (stsd_data + offset + 4));
10028 GST_LOG_OBJECT (qtdemux, "n_channels: %d", stream->n_channels);
10029 GST_LOG_OBJECT (qtdemux, "sample_size: %d", samplesize);
10030 GST_LOG_OBJECT (qtdemux, "compression_id: %d", compression_id);
10031 GST_LOG_OBJECT (qtdemux, "packet size: %d",
10032 QT_UINT16 (stsd_data + offset + 14));
10033 GST_LOG_OBJECT (qtdemux, "sample rate: %g", stream->rate);
10035 if (compression_id == 0xfffe)
10036 stream->sampled = TRUE;
10038 /* first assume uncompressed audio */
10039 stream->bytes_per_sample = samplesize / 8;
10040 stream->samples_per_frame = stream->n_channels;
10041 stream->bytes_per_frame = stream->n_channels * stream->bytes_per_sample;
10042 stream->samples_per_packet = stream->samples_per_frame;
10043 stream->bytes_per_packet = stream->bytes_per_sample;
10047 /* Yes, these have to be hard-coded */
10050 stream->samples_per_packet = 6;
10051 stream->bytes_per_packet = 1;
10052 stream->bytes_per_frame = 1 * stream->n_channels;
10053 stream->bytes_per_sample = 1;
10054 stream->samples_per_frame = 6 * stream->n_channels;
10059 stream->samples_per_packet = 3;
10060 stream->bytes_per_packet = 1;
10061 stream->bytes_per_frame = 1 * stream->n_channels;
10062 stream->bytes_per_sample = 1;
10063 stream->samples_per_frame = 3 * stream->n_channels;
10068 stream->samples_per_packet = 64;
10069 stream->bytes_per_packet = 34;
10070 stream->bytes_per_frame = 34 * stream->n_channels;
10071 stream->bytes_per_sample = 2;
10072 stream->samples_per_frame = 64 * stream->n_channels;
10078 stream->samples_per_packet = 1;
10079 stream->bytes_per_packet = 1;
10080 stream->bytes_per_frame = 1 * stream->n_channels;
10081 stream->bytes_per_sample = 1;
10082 stream->samples_per_frame = 1 * stream->n_channels;
10087 stream->samples_per_packet = 160;
10088 stream->bytes_per_packet = 33;
10089 stream->bytes_per_frame = 33 * stream->n_channels;
10090 stream->bytes_per_sample = 2;
10091 stream->samples_per_frame = 160 * stream->n_channels;
10098 if (version == 0x00010000) {
10099 /* sample description entry (16) + sound sample description v1 (20+16) */
10110 /* only parse extra decoding config for non-pcm audio */
10111 stream->samples_per_packet = QT_UINT32 (stsd_data + offset);
10112 stream->bytes_per_packet = QT_UINT32 (stsd_data + offset + 4);
10113 stream->bytes_per_frame = QT_UINT32 (stsd_data + offset + 8);
10114 stream->bytes_per_sample = QT_UINT32 (stsd_data + offset + 12);
10116 GST_LOG_OBJECT (qtdemux, "samples/packet: %d",
10117 stream->samples_per_packet);
10118 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
10119 stream->bytes_per_packet);
10120 GST_LOG_OBJECT (qtdemux, "bytes/frame: %d",
10121 stream->bytes_per_frame);
10122 GST_LOG_OBJECT (qtdemux, "bytes/sample: %d",
10123 stream->bytes_per_sample);
10125 if (!stream->sampled && stream->bytes_per_packet) {
10126 stream->samples_per_frame = (stream->bytes_per_frame /
10127 stream->bytes_per_packet) * stream->samples_per_packet;
10128 GST_LOG_OBJECT (qtdemux, "samples/frame: %d",
10129 stream->samples_per_frame);
10134 } else if (version == 0x00020000) {
10141 /* sample description entry (16) + sound sample description v2 (56) */
10145 qtfp.val = QT_UINT64 (stsd_data + offset + 4);
10146 stream->rate = qtfp.fp;
10147 stream->n_channels = QT_UINT32 (stsd_data + offset + 12);
10149 GST_LOG_OBJECT (qtdemux, "Sound sample description Version 2");
10150 GST_LOG_OBJECT (qtdemux, "sample rate: %g", stream->rate);
10151 GST_LOG_OBJECT (qtdemux, "n_channels: %d", stream->n_channels);
10152 GST_LOG_OBJECT (qtdemux, "bits/channel: %d",
10153 QT_UINT32 (stsd_data + offset + 20));
10154 GST_LOG_OBJECT (qtdemux, "format flags: %X",
10155 QT_UINT32 (stsd_data + offset + 24));
10156 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
10157 QT_UINT32 (stsd_data + offset + 28));
10158 GST_LOG_OBJECT (qtdemux, "LPCM frames/packet: %d",
10159 QT_UINT32 (stsd_data + offset + 32));
10160 } else if (version != 0x00000) {
10161 GST_WARNING_OBJECT (qtdemux, "unknown audio STSD version %08x", version);
10165 gst_caps_unref (stream->caps);
10167 stream->caps = qtdemux_audio_caps (qtdemux, stream, fourcc,
10168 stsd_data + 32, len - 16, &codec);
10176 in24 = qtdemux_tree_get_child_by_type (stsd, FOURCC_in24);
10178 enda = qtdemux_tree_get_child_by_type (in24, FOURCC_enda);
10180 wave = qtdemux_tree_get_child_by_type (in24, FOURCC_wave);
10182 enda = qtdemux_tree_get_child_by_type (wave, FOURCC_enda);
10185 int enda_value = QT_UINT16 ((guint8 *) enda->data + 8);
10186 gst_caps_set_simple (stream->caps,
10187 "format", G_TYPE_STRING, (enda_value) ? "S24LE" : "S24BE", NULL);
10194 const guint8 *owma_data;
10195 const gchar *codec_name = NULL;
10199 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
10200 /* FIXME this should also be gst_riff_strf_auds,
10201 * but the latter one is actually missing bits-per-sample :( */
10206 gint32 nSamplesPerSec;
10207 gint32 nAvgBytesPerSec;
10208 gint16 nBlockAlign;
10209 gint16 wBitsPerSample;
10212 WAVEFORMATEX *wfex;
10214 GST_DEBUG_OBJECT (qtdemux, "parse owma");
10215 owma = qtdemux_tree_get_child_by_type (stsd, FOURCC_owma);
10218 owma_data = owma->data;
10219 owma_len = QT_UINT32 (owma_data);
10220 if (owma_len <= 54) {
10221 GST_WARNING_OBJECT (qtdemux, "Too small owma header, skipping");
10224 wfex = (WAVEFORMATEX *) (owma_data + 36);
10225 buf = gst_buffer_new_and_alloc (owma_len - 54);
10226 gst_buffer_fill (buf, 0, owma_data + 54, owma_len - 54);
10227 if (wfex->wFormatTag == 0x0161) {
10228 codec_name = "Windows Media Audio";
10230 } else if (wfex->wFormatTag == 0x0162) {
10231 codec_name = "Windows Media Audio 9 Pro";
10233 } else if (wfex->wFormatTag == 0x0163) {
10234 codec_name = "Windows Media Audio 9 Lossless";
10235 /* is that correct? gstffmpegcodecmap.c is missing it, but
10236 * fluendo codec seems to support it */
10240 gst_caps_set_simple (stream->caps,
10241 "codec_data", GST_TYPE_BUFFER, buf,
10242 "wmaversion", G_TYPE_INT, version,
10243 "block_align", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->nBlockAlign),
10244 "bitrate", G_TYPE_INT, GST_READ_UINT32_LE (&wfex->nAvgBytesPerSec),
10245 "width", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->wBitsPerSample),
10246 "depth", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->wBitsPerSample),
10248 gst_buffer_unref (buf);
10252 codec = g_strdup (codec_name);
10258 gint len = QT_UINT32 (stsd_data) - offset;
10259 const guint8 *wfex_data = stsd_data + offset;
10260 const gchar *codec_name = NULL;
10262 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
10263 /* FIXME this should also be gst_riff_strf_auds,
10264 * but the latter one is actually missing bits-per-sample :( */
10269 gint32 nSamplesPerSec;
10270 gint32 nAvgBytesPerSec;
10271 gint16 nBlockAlign;
10272 gint16 wBitsPerSample;
10277 /* FIXME: unify with similar wavformatex parsing code above */
10278 GST_DEBUG_OBJECT (qtdemux, "parse wma, looking for wfex");
10284 if (QT_UINT32 (wfex_data) <= len)
10285 size = QT_UINT32 (wfex_data) - 8;
10290 /* No real data, so break out */
10293 switch (QT_FOURCC (wfex_data + 4)) {
10294 case GST_MAKE_FOURCC ('w', 'f', 'e', 'x'):
10296 GST_DEBUG_OBJECT (qtdemux, "found wfex in stsd");
10301 wfex.wFormatTag = GST_READ_UINT16_LE (wfex_data + 8 + 0);
10302 wfex.nChannels = GST_READ_UINT16_LE (wfex_data + 8 + 2);
10303 wfex.nSamplesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 4);
10304 wfex.nAvgBytesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 8);
10305 wfex.nBlockAlign = GST_READ_UINT16_LE (wfex_data + 8 + 12);
10306 wfex.wBitsPerSample = GST_READ_UINT16_LE (wfex_data + 8 + 14);
10307 wfex.cbSize = GST_READ_UINT16_LE (wfex_data + 8 + 16);
10309 GST_LOG_OBJECT (qtdemux, "Found wfex box in stsd:");
10310 GST_LOG_OBJECT (qtdemux, "FormatTag = 0x%04x, Channels = %u, "
10311 "SamplesPerSec = %u, AvgBytesPerSec = %u, BlockAlign = %u, "
10312 "BitsPerSample = %u, Size = %u", wfex.wFormatTag,
10313 wfex.nChannels, wfex.nSamplesPerSec, wfex.nAvgBytesPerSec,
10314 wfex.nBlockAlign, wfex.wBitsPerSample, wfex.cbSize);
10316 if (wfex.wFormatTag == 0x0161) {
10317 codec_name = "Windows Media Audio";
10319 } else if (wfex.wFormatTag == 0x0162) {
10320 codec_name = "Windows Media Audio 9 Pro";
10322 } else if (wfex.wFormatTag == 0x0163) {
10323 codec_name = "Windows Media Audio 9 Lossless";
10324 /* is that correct? gstffmpegcodecmap.c is missing it, but
10325 * fluendo codec seems to support it */
10329 gst_caps_set_simple (stream->caps,
10330 "wmaversion", G_TYPE_INT, version,
10331 "block_align", G_TYPE_INT, wfex.nBlockAlign,
10332 "bitrate", G_TYPE_INT, wfex.nAvgBytesPerSec,
10333 "width", G_TYPE_INT, wfex.wBitsPerSample,
10334 "depth", G_TYPE_INT, wfex.wBitsPerSample, NULL);
10336 if (size > wfex.cbSize) {
10339 buf = gst_buffer_new_and_alloc (size - wfex.cbSize);
10340 gst_buffer_fill (buf, 0, wfex_data + 8 + wfex.cbSize,
10341 size - wfex.cbSize);
10342 gst_caps_set_simple (stream->caps,
10343 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10344 gst_buffer_unref (buf);
10346 GST_WARNING_OBJECT (qtdemux, "no codec data");
10351 codec = g_strdup (codec_name);
10359 wfex_data += size + 8;
10366 const guint8 *opus_data;
10367 guint8 *channel_mapping = NULL;
10370 guint8 channel_mapping_family;
10371 guint8 stream_count;
10372 guint8 coupled_count;
10375 opus = qtdemux_tree_get_child_by_type (stsd, FOURCC_opus);
10376 opus_data = opus->data;
10378 channels = GST_READ_UINT8 (opus_data + 45);
10379 rate = GST_READ_UINT32_LE (opus_data + 48);
10380 channel_mapping_family = GST_READ_UINT8 (opus_data + 54);
10381 stream_count = GST_READ_UINT8 (opus_data + 55);
10382 coupled_count = GST_READ_UINT8 (opus_data + 56);
10384 if (channels > 0) {
10385 channel_mapping = g_malloc (channels * sizeof (guint8));
10386 for (i = 0; i < channels; i++)
10387 channel_mapping[i] = GST_READ_UINT8 (opus_data + i + 57);
10390 stream->caps = gst_codec_utils_opus_create_caps (rate, channels,
10391 channel_mapping_family, stream_count, coupled_count,
10403 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
10404 GST_TAG_AUDIO_CODEC, codec, NULL);
10408 /* some bitrate info may have ended up in caps */
10409 s = gst_caps_get_structure (stream->caps, 0);
10410 gst_structure_get_int (s, "bitrate", &bitrate);
10412 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
10413 GST_TAG_BITRATE, bitrate, NULL);
10416 if (stream->protected && fourcc == FOURCC_mp4a)
10417 mp4a = qtdemux_tree_get_child_by_type (stsd, FOURCC_enca);
10419 mp4a = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4a);
10424 wave = qtdemux_tree_get_child_by_type (mp4a, FOURCC_wave);
10426 esds = qtdemux_tree_get_child_by_type (wave, FOURCC_esds);
10428 esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
10432 /* If the fourcc's bottom 16 bits gives 'sm', then the top
10433 16 bits is a byte-swapped wave-style codec identifier,
10434 and we can find a WAVE header internally to a 'wave' atom here.
10435 This can more clearly be thought of as 'ms' as the top 16 bits, and a
10436 codec id as the bottom 16 bits - but byte-swapped to store in QT (which
10439 if ((fourcc & 0xffff) == (('s' << 8) | 'm')) {
10440 if (len < offset + 20) {
10441 GST_WARNING_OBJECT (qtdemux, "No wave atom in MS-style audio");
10443 guint32 datalen = QT_UINT32 (stsd_data + offset + 16);
10444 const guint8 *data = stsd_data + offset + 16;
10446 GNode *waveheadernode;
10448 wavenode = g_node_new ((guint8 *) data);
10449 if (qtdemux_parse_node (qtdemux, wavenode, data, datalen)) {
10450 const guint8 *waveheader;
10453 waveheadernode = qtdemux_tree_get_child_by_type (wavenode, fourcc);
10454 if (waveheadernode) {
10455 waveheader = (const guint8 *) waveheadernode->data;
10456 headerlen = QT_UINT32 (waveheader);
10458 if (headerlen > 8) {
10459 gst_riff_strf_auds *header = NULL;
10460 GstBuffer *headerbuf;
10466 headerbuf = gst_buffer_new_and_alloc (headerlen);
10467 gst_buffer_fill (headerbuf, 0, waveheader, headerlen);
10469 if (gst_riff_parse_strf_auds (GST_ELEMENT_CAST (qtdemux),
10470 headerbuf, &header, &extra)) {
10471 gst_caps_unref (stream->caps);
10472 /* FIXME: Need to do something with the channel reorder map */
10473 stream->caps = gst_riff_create_audio_caps (header->format, NULL,
10474 header, extra, NULL, NULL, NULL);
10477 gst_buffer_unref (extra);
10482 GST_DEBUG ("Didn't find waveheadernode for this codec");
10484 g_node_destroy (wavenode);
10487 gst_qtdemux_handle_esds (qtdemux, stream, esds, stream->pending_tags);
10491 /* FIXME: what is in the chunk? */
10494 gint len = QT_UINT32 (stsd_data);
10496 /* seems to be always = 116 = 0x74 */
10502 gint len = QT_UINT32 (stsd_data);
10505 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x4C);
10507 gst_buffer_fill (buf, 0, stsd_data + 0x4C, len - 0x4C);
10508 gst_caps_set_simple (stream->caps,
10509 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10510 gst_buffer_unref (buf);
10512 gst_caps_set_simple (stream->caps,
10513 "samplesize", G_TYPE_INT, samplesize, NULL);
10518 GNode *alac, *wave = NULL;
10520 /* apparently, m4a has this atom appended directly in the stsd entry,
10521 * while mov has it in a wave atom */
10522 alac = qtdemux_tree_get_child_by_type (stsd, FOURCC_alac);
10524 /* alac now refers to stsd entry atom */
10525 wave = qtdemux_tree_get_child_by_type (alac, FOURCC_wave);
10527 alac = qtdemux_tree_get_child_by_type (wave, FOURCC_alac);
10529 alac = qtdemux_tree_get_child_by_type (alac, FOURCC_alac);
10532 const guint8 *alac_data = alac->data;
10533 gint len = QT_UINT32 (alac->data);
10537 GST_DEBUG_OBJECT (qtdemux,
10538 "discarding alac atom with unexpected len %d", len);
10540 /* codec-data contains alac atom size and prefix,
10541 * ffmpeg likes it that way, not quite gst-ish though ...*/
10542 buf = gst_buffer_new_and_alloc (len);
10543 gst_buffer_fill (buf, 0, alac->data, len);
10544 gst_caps_set_simple (stream->caps,
10545 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10546 gst_buffer_unref (buf);
10548 stream->bytes_per_frame = QT_UINT32 (alac_data + 12);
10549 stream->n_channels = QT_UINT8 (alac_data + 21);
10550 stream->rate = QT_UINT32 (alac_data + 32);
10553 gst_caps_set_simple (stream->caps,
10554 "samplesize", G_TYPE_INT, samplesize, NULL);
10562 gint len = QT_UINT32 (stsd_data);
10565 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x34);
10568 gst_buffer_fill (buf, 0, stsd_data + 0x34, len - 0x34);
10570 /* If we have enough data, let's try to get the 'damr' atom. See
10571 * the 3GPP container spec (26.244) for more details. */
10572 if ((len - 0x34) > 8 &&
10573 (bitrate = qtdemux_parse_amr_bitrate (buf, amrwb))) {
10574 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
10575 GST_TAG_MAXIMUM_BITRATE, bitrate, NULL);
10578 gst_caps_set_simple (stream->caps,
10579 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10580 gst_buffer_unref (buf);
10586 /* mp4a atom withtout ESDS; Attempt to build codec data from atom */
10587 gint len = QT_UINT32 (stsd_data);
10590 guint16 sound_version = QT_UINT16 (stsd_data + 32);
10592 if (sound_version == 1) {
10593 guint16 channels = QT_UINT16 (stsd_data + 40);
10594 guint32 time_scale = QT_UINT32 (stsd_data + 46);
10595 guint8 codec_data[2];
10597 gint profile = 2; /* FIXME: Can this be determined somehow? There doesn't seem to be anything in mp4a atom that specifis compression */
10599 gint sample_rate_index =
10600 gst_codec_utils_aac_get_index_from_sample_rate (time_scale);
10602 /* build AAC codec data */
10603 codec_data[0] = profile << 3;
10604 codec_data[0] |= ((sample_rate_index >> 1) & 0x7);
10605 codec_data[1] = (sample_rate_index & 0x01) << 7;
10606 codec_data[1] |= (channels & 0xF) << 3;
10608 buf = gst_buffer_new_and_alloc (2);
10609 gst_buffer_fill (buf, 0, codec_data, 2);
10610 gst_caps_set_simple (stream->caps,
10611 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10612 gst_buffer_unref (buf);
10618 GST_INFO_OBJECT (qtdemux,
10619 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
10623 GST_INFO_OBJECT (qtdemux,
10624 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
10625 GST_FOURCC_ARGS (fourcc), stream->caps);
10627 } else if (stream->subtype == FOURCC_strm) {
10628 if (fourcc == FOURCC_rtsp) {
10629 stream->redirect_uri = qtdemux_get_rtsp_uri_from_hndl (qtdemux, minf);
10631 GST_INFO_OBJECT (qtdemux, "unhandled stream type %" GST_FOURCC_FORMAT,
10632 GST_FOURCC_ARGS (fourcc));
10633 goto unknown_stream;
10635 stream->sampled = TRUE;
10636 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
10637 || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt) {
10639 stream->sampled = TRUE;
10640 stream->sparse = TRUE;
10643 qtdemux_sub_caps (qtdemux, stream, fourcc, stsd_data, &codec);
10645 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
10646 GST_TAG_SUBTITLE_CODEC, codec, NULL);
10651 /* hunt for sort-of codec data */
10655 GNode *mp4s = NULL;
10656 GNode *esds = NULL;
10658 /* look for palette in a stsd->mp4s->esds sub-atom */
10659 mp4s = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4s);
10661 esds = qtdemux_tree_get_child_by_type (mp4s, FOURCC_esds);
10662 if (esds == NULL) {
10664 GST_LOG_OBJECT (qtdemux, "Skipping invalid stsd: no esds child");
10668 gst_qtdemux_handle_esds (qtdemux, stream, esds, stream->pending_tags);
10672 GST_INFO_OBJECT (qtdemux,
10673 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
10676 GST_INFO_OBJECT (qtdemux,
10677 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
10678 GST_FOURCC_ARGS (fourcc), stream->caps);
10680 /* everything in 1 sample */
10681 stream->sampled = TRUE;
10684 qtdemux_generic_caps (qtdemux, stream, fourcc, stsd_data, &codec);
10686 if (stream->caps == NULL)
10687 goto unknown_stream;
10690 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
10691 GST_TAG_SUBTITLE_CODEC, codec, NULL);
10697 /* promote to sampled format */
10698 if (stream->fourcc == FOURCC_samr) {
10699 /* force mono 8000 Hz for AMR */
10700 stream->sampled = TRUE;
10701 stream->n_channels = 1;
10702 stream->rate = 8000;
10703 } else if (stream->fourcc == FOURCC_sawb) {
10704 /* force mono 16000 Hz for AMR-WB */
10705 stream->sampled = TRUE;
10706 stream->n_channels = 1;
10707 stream->rate = 16000;
10708 } else if (stream->fourcc == FOURCC_mp4a) {
10709 stream->sampled = TRUE;
10712 /* collect sample information */
10713 if (!qtdemux_stbl_init (qtdemux, stream, stbl))
10714 goto samples_failed;
10716 if (qtdemux->fragmented) {
10719 /* need all moov samples as basis; probably not many if any at all */
10720 /* prevent moof parsing taking of at this time */
10721 offset = qtdemux->moof_offset;
10722 qtdemux->moof_offset = 0;
10723 if (stream->n_samples &&
10724 !qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
10725 qtdemux->moof_offset = offset;
10726 goto samples_failed;
10728 qtdemux->moof_offset = 0;
10729 /* movie duration more reliable in this case (e.g. mehd) */
10730 if (qtdemux->segment.duration &&
10731 GST_CLOCK_TIME_IS_VALID (qtdemux->segment.duration))
10733 GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->segment.duration);
10736 /* configure segments */
10737 if (!qtdemux_parse_segments (qtdemux, stream, trak))
10738 goto segments_failed;
10740 /* add some language tag, if useful */
10741 if (stream->lang_id[0] != '\0' && strcmp (stream->lang_id, "unk") &&
10742 strcmp (stream->lang_id, "und")) {
10743 const gchar *lang_code;
10745 /* convert ISO 639-2 code to ISO 639-1 */
10746 lang_code = gst_tag_get_language_code (stream->lang_id);
10747 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
10748 GST_TAG_LANGUAGE_CODE, (lang_code) ? lang_code : stream->lang_id, NULL);
10751 /* Check for UDTA tags */
10752 if ((udta = qtdemux_tree_get_child_by_type (trak, FOURCC_udta))) {
10753 qtdemux_parse_udta (qtdemux, stream->pending_tags, udta);
10756 /* now we are ready to add the stream */
10757 if (qtdemux->n_streams >= GST_QTDEMUX_MAX_STREAMS)
10758 goto too_many_streams;
10760 if (!qtdemux->got_moov) {
10761 qtdemux->streams[qtdemux->n_streams] = stream;
10762 qtdemux->n_streams++;
10763 GST_DEBUG_OBJECT (qtdemux, "n_streams is now %d", qtdemux->n_streams);
10771 GST_INFO_OBJECT (qtdemux, "skip disabled track");
10773 gst_qtdemux_stream_free (qtdemux, stream);
10778 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
10779 (_("This file is corrupt and cannot be played.")), (NULL));
10781 gst_qtdemux_stream_free (qtdemux, stream);
10786 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT, (NULL), (NULL));
10788 gst_qtdemux_stream_free (qtdemux, stream);
10794 /* we posted an error already */
10795 /* free stbl sub-atoms */
10796 gst_qtdemux_stbl_free (stream);
10798 gst_qtdemux_stream_free (qtdemux, stream);
10803 GST_INFO_OBJECT (qtdemux, "stream with track id %i already exists",
10806 gst_qtdemux_stream_free (qtdemux, stream);
10811 GST_INFO_OBJECT (qtdemux, "unknown subtype %" GST_FOURCC_FORMAT,
10812 GST_FOURCC_ARGS (stream->subtype));
10814 gst_qtdemux_stream_free (qtdemux, stream);
10819 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
10820 (_("This file contains too many streams. Only playing first %d"),
10821 GST_QTDEMUX_MAX_STREAMS), (NULL));
10826 /* If we can estimate the overall bitrate, and don't have information about the
10827 * stream bitrate for exactly one stream, this guesses the stream bitrate as
10828 * the overall bitrate minus the sum of the bitrates of all other streams. This
10829 * should be useful for the common case where we have one audio and one video
10830 * stream and can estimate the bitrate of one, but not the other. */
10832 gst_qtdemux_guess_bitrate (GstQTDemux * qtdemux)
10834 QtDemuxStream *stream = NULL;
10835 gint64 size, sys_bitrate, sum_bitrate = 0;
10836 GstClockTime duration;
10840 if (qtdemux->fragmented)
10843 GST_DEBUG_OBJECT (qtdemux, "Looking for streams with unknown bitrate");
10845 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &size)
10847 GST_DEBUG_OBJECT (qtdemux,
10848 "Size in bytes of the stream not known - bailing");
10852 /* Subtract the header size */
10853 GST_DEBUG_OBJECT (qtdemux, "Total size %" G_GINT64_FORMAT ", header size %u",
10854 size, qtdemux->header_size);
10856 if (size < qtdemux->header_size)
10859 size = size - qtdemux->header_size;
10861 if (!gst_qtdemux_get_duration (qtdemux, &duration)) {
10862 GST_DEBUG_OBJECT (qtdemux, "Stream duration not known - bailing");
10866 for (i = 0; i < qtdemux->n_streams; i++) {
10867 switch (qtdemux->streams[i]->subtype) {
10870 GST_DEBUG_OBJECT (qtdemux, "checking bitrate for %" GST_PTR_FORMAT,
10871 qtdemux->streams[i]->caps);
10872 /* retrieve bitrate, prefer avg then max */
10874 if (qtdemux->streams[i]->pending_tags) {
10875 gst_tag_list_get_uint (qtdemux->streams[i]->pending_tags,
10876 GST_TAG_MAXIMUM_BITRATE, &bitrate);
10877 GST_DEBUG_OBJECT (qtdemux, "max-bitrate: %u", bitrate);
10878 gst_tag_list_get_uint (qtdemux->streams[i]->pending_tags,
10879 GST_TAG_NOMINAL_BITRATE, &bitrate);
10880 GST_DEBUG_OBJECT (qtdemux, "nominal-bitrate: %u", bitrate);
10881 gst_tag_list_get_uint (qtdemux->streams[i]->pending_tags,
10882 GST_TAG_BITRATE, &bitrate);
10883 GST_DEBUG_OBJECT (qtdemux, "bitrate: %u", bitrate);
10886 sum_bitrate += bitrate;
10889 GST_DEBUG_OBJECT (qtdemux,
10890 ">1 stream with unknown bitrate - bailing");
10893 stream = qtdemux->streams[i];
10897 /* For other subtypes, we assume no significant impact on bitrate */
10903 GST_DEBUG_OBJECT (qtdemux, "All stream bitrates are known");
10907 sys_bitrate = gst_util_uint64_scale (size, GST_SECOND * 8, duration);
10909 if (sys_bitrate < sum_bitrate) {
10910 /* This can happen, since sum_bitrate might be derived from maximum
10911 * bitrates and not average bitrates */
10912 GST_DEBUG_OBJECT (qtdemux,
10913 "System bitrate less than sum bitrate - bailing");
10917 bitrate = sys_bitrate - sum_bitrate;
10918 GST_DEBUG_OBJECT (qtdemux, "System bitrate = %" G_GINT64_FORMAT
10919 ", Stream bitrate = %u", sys_bitrate, bitrate);
10921 if (!stream->pending_tags)
10922 stream->pending_tags = gst_tag_list_new_empty ();
10924 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
10925 GST_TAG_BITRATE, bitrate, NULL);
10928 static GstFlowReturn
10929 qtdemux_prepare_streams (GstQTDemux * qtdemux)
10932 GstFlowReturn ret = GST_FLOW_OK;
10934 GST_DEBUG_OBJECT (qtdemux, "prepare streams");
10936 for (i = 0; ret == GST_FLOW_OK && i < qtdemux->n_streams; i++) {
10937 QtDemuxStream *stream = qtdemux->streams[i];
10938 guint32 sample_num = 0;
10940 GST_DEBUG_OBJECT (qtdemux, "stream %d, id %d, fourcc %" GST_FOURCC_FORMAT,
10941 i, stream->track_id, GST_FOURCC_ARGS (stream->fourcc));
10943 if (qtdemux->fragmented) {
10944 /* need all moov samples first */
10945 GST_OBJECT_LOCK (qtdemux);
10946 while (stream->n_samples == 0)
10947 if ((ret = qtdemux_add_fragmented_samples (qtdemux)) != GST_FLOW_OK)
10949 GST_OBJECT_UNLOCK (qtdemux);
10951 /* discard any stray moof */
10952 qtdemux->moof_offset = 0;
10955 /* prepare braking */
10956 if (ret != GST_FLOW_ERROR)
10959 /* in pull mode, we should have parsed some sample info by now;
10960 * and quite some code will not handle no samples.
10961 * in push mode, we'll just have to deal with it */
10962 if (G_UNLIKELY (qtdemux->pullbased && !stream->n_samples)) {
10963 GST_DEBUG_OBJECT (qtdemux, "no samples for stream; discarding");
10964 gst_qtdemux_remove_stream (qtdemux, i);
10969 /* parse the initial sample for use in setting the frame rate cap */
10970 while (sample_num == 0 && sample_num < stream->n_samples) {
10971 if (!qtdemux_parse_samples (qtdemux, stream, sample_num))
10975 if (stream->n_samples > 0 && stream->stbl_index >= 0) {
10976 stream->first_duration = stream->samples[0].duration;
10977 GST_LOG_OBJECT (qtdemux, "stream %d first duration %u",
10978 stream->track_id, stream->first_duration);
10985 static GstFlowReturn
10986 qtdemux_expose_streams (GstQTDemux * qtdemux)
10989 GstFlowReturn ret = GST_FLOW_OK;
10990 GSList *oldpads = NULL;
10993 GST_DEBUG_OBJECT (qtdemux, "exposing streams");
10995 for (i = 0; ret == GST_FLOW_OK && i < qtdemux->n_streams; i++) {
10996 QtDemuxStream *stream = qtdemux->streams[i];
10997 GstPad *oldpad = stream->pad;
11000 GST_DEBUG_OBJECT (qtdemux, "stream %d, id %d, fourcc %" GST_FOURCC_FORMAT,
11001 i, stream->track_id, GST_FOURCC_ARGS (stream->fourcc));
11003 if ((stream->subtype == FOURCC_text || stream->subtype == FOURCC_sbtl) &&
11004 stream->track_id == qtdemux->chapters_track_id) {
11005 /* TODO - parse chapters track and expose it as GstToc; For now just ignore it
11006 so that it doesn't look like a subtitle track */
11007 gst_qtdemux_remove_stream (qtdemux, i);
11012 /* now we have all info and can expose */
11013 list = stream->pending_tags;
11014 stream->pending_tags = NULL;
11016 oldpads = g_slist_prepend (oldpads, oldpad);
11017 if (!gst_qtdemux_add_stream (qtdemux, stream, list))
11018 return GST_FLOW_ERROR;
11021 gst_qtdemux_guess_bitrate (qtdemux);
11023 gst_element_no_more_pads (GST_ELEMENT_CAST (qtdemux));
11025 for (iter = oldpads; iter; iter = g_slist_next (iter)) {
11026 GstPad *oldpad = iter->data;
11029 event = gst_event_new_eos ();
11030 if (qtdemux->segment_seqnum)
11031 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
11033 gst_pad_push_event (oldpad, event);
11034 gst_pad_set_active (oldpad, FALSE);
11035 gst_element_remove_pad (GST_ELEMENT (qtdemux), oldpad);
11036 gst_flow_combiner_remove_pad (qtdemux->flowcombiner, oldpad);
11037 gst_object_unref (oldpad);
11040 /* check if we should post a redirect in case there is a single trak
11041 * and it is a redirecting trak */
11042 if (qtdemux->n_streams == 1 && qtdemux->streams[0]->redirect_uri != NULL) {
11045 GST_INFO_OBJECT (qtdemux, "Issuing a redirect due to a single track with "
11046 "an external content");
11047 m = gst_message_new_element (GST_OBJECT_CAST (qtdemux),
11048 gst_structure_new ("redirect",
11049 "new-location", G_TYPE_STRING, qtdemux->streams[0]->redirect_uri,
11051 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), m);
11052 qtdemux->posted_redirect = TRUE;
11055 for (i = 0; i < qtdemux->n_streams; i++) {
11056 QtDemuxStream *stream = qtdemux->streams[i];
11058 qtdemux_do_allocation (qtdemux, stream);
11061 qtdemux->exposed = TRUE;
11065 /* check if major or compatible brand is 3GP */
11066 static inline gboolean
11067 qtdemux_is_brand_3gp (GstQTDemux * qtdemux, gboolean major)
11070 return ((qtdemux->major_brand & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
11072 } else if (qtdemux->comp_brands != NULL) {
11076 gboolean res = FALSE;
11078 gst_buffer_map (qtdemux->comp_brands, &map, GST_MAP_READ);
11081 while (size >= 4) {
11082 res = res || ((QT_FOURCC (data) & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
11087 gst_buffer_unmap (qtdemux->comp_brands, &map);
11094 /* check if tag is a spec'ed 3GP tag keyword storing a string */
11095 static inline gboolean
11096 qtdemux_is_string_tag_3gp (GstQTDemux * qtdemux, guint32 fourcc)
11098 return fourcc == FOURCC_cprt || fourcc == FOURCC_gnre || fourcc == FOURCC_titl
11099 || fourcc == FOURCC_dscp || fourcc == FOURCC_perf || fourcc == FOURCC_auth
11100 || fourcc == FOURCC_albm;
11104 qtdemux_tag_add_location (GstQTDemux * qtdemux, GstTagList * taglist,
11105 const char *tag, const char *dummy, GNode * node)
11107 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
11111 gdouble longitude, latitude, altitude;
11114 len = QT_UINT32 (node->data);
11121 /* TODO: language code skipped */
11123 name = gst_tag_freeform_string_to_utf8 (data + offset, -1, env_vars);
11126 /* do not alarm in trivial case, but bail out otherwise */
11127 if (*(data + offset) != 0) {
11128 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8, "
11132 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
11133 GST_TAG_GEO_LOCATION_NAME, name, NULL);
11134 offset += strlen (name);
11138 if (len < offset + 2 + 4 + 4 + 4)
11141 /* +1 +1 = skip null-terminator and location role byte */
11143 /* table in spec says unsigned, semantics say negative has meaning ... */
11144 longitude = QT_SFP32 (data + offset);
11147 latitude = QT_SFP32 (data + offset);
11150 altitude = QT_SFP32 (data + offset);
11152 /* one invalid means all are invalid */
11153 if (longitude >= -180.0 && longitude <= 180.0 &&
11154 latitude >= -90.0 && latitude <= 90.0) {
11155 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
11156 GST_TAG_GEO_LOCATION_LATITUDE, latitude,
11157 GST_TAG_GEO_LOCATION_LONGITUDE, longitude,
11158 GST_TAG_GEO_LOCATION_ELEVATION, altitude, NULL);
11161 /* TODO: no GST_TAG_, so astronomical body and additional notes skipped */
11168 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP location");
11175 qtdemux_tag_add_year (GstQTDemux * qtdemux, GstTagList * taglist,
11176 const char *tag, const char *dummy, GNode * node)
11182 len = QT_UINT32 (node->data);
11186 y = QT_UINT16 ((guint8 *) node->data + 12);
11188 GST_DEBUG_OBJECT (qtdemux, "year: %u is not a valid year", y);
11191 GST_DEBUG_OBJECT (qtdemux, "year: %u", y);
11193 date = g_date_new_dmy (1, 1, y);
11194 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, date, NULL);
11195 g_date_free (date);
11199 qtdemux_tag_add_classification (GstQTDemux * qtdemux, GstTagList * taglist,
11200 const char *tag, const char *dummy, GNode * node)
11203 char *tag_str = NULL;
11208 len = QT_UINT32 (node->data);
11213 entity = (guint8 *) node->data + offset;
11214 if (entity[0] == 0 || entity[1] == 0 || entity[2] == 0 || entity[3] == 0) {
11215 GST_DEBUG_OBJECT (qtdemux,
11216 "classification info: %c%c%c%c invalid classification entity",
11217 entity[0], entity[1], entity[2], entity[3]);
11222 table = QT_UINT16 ((guint8 *) node->data + offset);
11224 /* Language code skipped */
11228 /* Tag format: "XXXX://Y[YYYY]/classification info string"
11229 * XXXX: classification entity, fixed length 4 chars.
11230 * Y[YYYY]: classification table, max 5 chars.
11232 tag_str = g_strdup_printf ("----://%u/%s",
11233 table, (char *) node->data + offset);
11235 /* memcpy To be sure we're preserving byte order */
11236 memcpy (tag_str, entity, 4);
11237 GST_DEBUG_OBJECT (qtdemux, "classification info: %s", tag_str);
11239 gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND, tag, tag_str, NULL);
11248 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP classification");
11254 qtdemux_tag_add_str_full (GstQTDemux * qtdemux, GstTagList * taglist,
11255 const char *tag, const char *dummy, GNode * node)
11257 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
11263 gboolean ret = TRUE;
11264 const gchar *charset = NULL;
11266 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
11268 len = QT_UINT32 (data->data);
11269 type = QT_UINT32 ((guint8 *) data->data + 8);
11270 if (type == 0x00000001 && len > 16) {
11271 s = gst_tag_freeform_string_to_utf8 ((char *) data->data + 16, len - 16,
11274 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
11275 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, s, NULL);
11278 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
11282 len = QT_UINT32 (node->data);
11283 type = QT_UINT32 ((guint8 *) node->data + 4);
11284 if ((type >> 24) == 0xa9) {
11288 /* Type starts with the (C) symbol, so the next data is a list
11289 * of (string size(16), language code(16), string) */
11291 str_len = QT_UINT16 ((guint8 *) node->data + 8);
11292 lang_code = QT_UINT16 ((guint8 *) node->data + 10);
11294 /* the string + fourcc + size + 2 16bit fields,
11295 * means that there are more tags in this atom */
11296 if (len > str_len + 8 + 4) {
11297 /* TODO how to represent the same tag in different languages? */
11298 GST_WARNING_OBJECT (qtdemux, "Ignoring metadata entry with multiple "
11299 "text alternatives, reading only first one");
11303 len = str_len + 8 + 4; /* remove trailing strings that we don't use */
11304 GST_DEBUG_OBJECT (qtdemux, "found international text tag");
11306 if (lang_code < 0x800) { /* MAC encoded string */
11309 } else if (len > 14 && qtdemux_is_string_tag_3gp (qtdemux,
11310 QT_FOURCC ((guint8 *) node->data + 4))) {
11311 guint32 type = QT_UINT32 ((guint8 *) node->data + 8);
11313 /* we go for 3GP style encoding if major brands claims so,
11314 * or if no hope for data be ok UTF-8, and compatible 3GP brand present */
11315 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
11316 (qtdemux_is_brand_3gp (qtdemux, FALSE) &&
11317 ((type & 0x00FFFFFF) == 0x0) && (type >> 24 <= 0xF))) {
11319 /* 16-bit Language code is ignored here as well */
11320 GST_DEBUG_OBJECT (qtdemux, "found 3gpp text tag");
11327 GST_DEBUG_OBJECT (qtdemux, "found normal text tag");
11328 ret = FALSE; /* may have to fallback */
11331 GError *err = NULL;
11333 s = g_convert ((gchar *) node->data + offset, len - offset, "utf8",
11334 charset, NULL, NULL, &err);
11336 GST_DEBUG_OBJECT (qtdemux, "Failed to convert string from charset %s:"
11337 " %s(%d): %s", charset, g_quark_to_string (err->domain), err->code,
11339 g_error_free (err);
11342 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
11343 len - offset, env_vars);
11346 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
11347 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, s, NULL);
11351 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
11358 qtdemux_tag_add_str (GstQTDemux * qtdemux, GstTagList * taglist,
11359 const char *tag, const char *dummy, GNode * node)
11361 qtdemux_tag_add_str_full (qtdemux, taglist, tag, dummy, node);
11365 qtdemux_tag_add_keywords (GstQTDemux * qtdemux, GstTagList * taglist,
11366 const char *tag, const char *dummy, GNode * node)
11368 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
11370 char *s, *t, *k = NULL;
11375 /* first try normal string tag if major brand not 3GP */
11376 if (!qtdemux_is_brand_3gp (qtdemux, TRUE)) {
11377 if (!qtdemux_tag_add_str_full (qtdemux, taglist, tag, dummy, node)) {
11378 /* hm, that did not work, maybe 3gpp storage in non-3gpp major brand;
11379 * let's try it 3gpp way after minor safety check */
11381 if (QT_UINT32 (data) < 15 || !qtdemux_is_brand_3gp (qtdemux, FALSE))
11387 GST_DEBUG_OBJECT (qtdemux, "found 3gpp keyword tag");
11391 len = QT_UINT32 (data);
11395 count = QT_UINT8 (data + 14);
11397 for (; count; count--) {
11400 if (offset + 1 > len)
11402 slen = QT_UINT8 (data + offset);
11404 if (offset + slen > len)
11406 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
11409 GST_DEBUG_OBJECT (qtdemux, "adding keyword %s", GST_STR_NULL (s));
11411 t = g_strjoin (",", k, s, NULL);
11419 GST_DEBUG_OBJECT (qtdemux, "failed to convert keyword to UTF-8");
11426 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (k));
11427 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, k, NULL);
11436 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP keywords");
11442 qtdemux_tag_add_num (GstQTDemux * qtdemux, GstTagList * taglist,
11443 const char *tag1, const char *tag2, GNode * node)
11450 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
11452 len = QT_UINT32 (data->data);
11453 type = QT_UINT32 ((guint8 *) data->data + 8);
11454 if (type == 0x00000000 && len >= 22) {
11455 n1 = QT_UINT16 ((guint8 *) data->data + 18);
11456 n2 = QT_UINT16 ((guint8 *) data->data + 20);
11458 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag1, n1);
11459 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, n1, NULL);
11462 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag2, n2);
11463 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag2, n2, NULL);
11470 qtdemux_tag_add_tmpo (GstQTDemux * qtdemux, GstTagList * taglist,
11471 const char *tag1, const char *dummy, GNode * node)
11478 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
11480 len = QT_UINT32 (data->data);
11481 type = QT_UINT32 ((guint8 *) data->data + 8);
11482 GST_DEBUG_OBJECT (qtdemux, "have tempo tag, type=%d,len=%d", type, len);
11483 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
11484 if ((type == 0x00000015 || type == 0x0000000f) && len >= 18) {
11485 n1 = QT_UINT16 ((guint8 *) data->data + 16);
11487 /* do not add bpm=0 */
11488 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", n1);
11489 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, (gdouble) n1,
11497 qtdemux_tag_add_uint32 (GstQTDemux * qtdemux, GstTagList * taglist,
11498 const char *tag1, const char *dummy, GNode * node)
11505 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
11507 len = QT_UINT32 (data->data);
11508 type = QT_UINT32 ((guint8 *) data->data + 8);
11509 GST_DEBUG_OBJECT (qtdemux, "have %s tag, type=%d,len=%d", tag1, type, len);
11510 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
11511 if ((type == 0x00000015 || type == 0x0000000f) && len >= 20) {
11512 num = QT_UINT32 ((guint8 *) data->data + 16);
11514 /* do not add num=0 */
11515 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", num);
11516 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, num, NULL);
11523 qtdemux_tag_add_covr (GstQTDemux * qtdemux, GstTagList * taglist,
11524 const char *tag1, const char *dummy, GNode * node)
11531 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
11533 len = QT_UINT32 (data->data);
11534 type = QT_UINT32 ((guint8 *) data->data + 8);
11535 GST_DEBUG_OBJECT (qtdemux, "have covr tag, type=%d,len=%d", type, len);
11536 if ((type == 0x0000000d || type == 0x0000000e) && len > 16) {
11538 gst_tag_image_data_to_image_sample ((guint8 *) data->data + 16,
11539 len - 16, GST_TAG_IMAGE_TYPE_NONE))) {
11540 GST_DEBUG_OBJECT (qtdemux, "adding tag size %d", len - 16);
11541 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, sample, NULL);
11542 gst_sample_unref (sample);
11549 qtdemux_tag_add_date (GstQTDemux * qtdemux, GstTagList * taglist,
11550 const char *tag, const char *dummy, GNode * node)
11557 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
11559 len = QT_UINT32 (data->data);
11560 type = QT_UINT32 ((guint8 *) data->data + 8);
11561 if (type == 0x00000001 && len > 16) {
11562 guint y, m = 1, d = 1;
11565 s = g_strndup ((char *) data->data + 16, len - 16);
11566 GST_DEBUG_OBJECT (qtdemux, "adding date '%s'", s);
11567 ret = sscanf (s, "%u-%u-%u", &y, &m, &d);
11568 if (ret >= 1 && y > 1500 && y < 3000) {
11571 date = g_date_new_dmy (d, m, y);
11572 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, date, NULL);
11573 g_date_free (date);
11575 GST_DEBUG_OBJECT (qtdemux, "could not parse date string '%s'", s);
11583 qtdemux_tag_add_gnre (GstQTDemux * qtdemux, GstTagList * taglist,
11584 const char *tag, const char *dummy, GNode * node)
11588 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
11590 /* re-route to normal string tag if major brand says so
11591 * or no data atom and compatible brand suggests so */
11592 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
11593 (qtdemux_is_brand_3gp (qtdemux, FALSE) && !data)) {
11594 qtdemux_tag_add_str (qtdemux, taglist, tag, dummy, node);
11599 guint len, type, n;
11601 len = QT_UINT32 (data->data);
11602 type = QT_UINT32 ((guint8 *) data->data + 8);
11603 if (type == 0x00000000 && len >= 18) {
11604 n = QT_UINT16 ((guint8 *) data->data + 16);
11606 const gchar *genre;
11608 genre = gst_tag_id3_genre_get (n - 1);
11609 if (genre != NULL) {
11610 GST_DEBUG_OBJECT (qtdemux, "adding %d [%s]", n, genre);
11611 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, genre, NULL);
11619 qtdemux_add_double_tag_from_str (GstQTDemux * demux, GstTagList * taglist,
11620 const gchar * tag, guint8 * data, guint32 datasize)
11625 /* make a copy to have \0 at the end */
11626 datacopy = g_strndup ((gchar *) data, datasize);
11628 /* convert the str to double */
11629 if (sscanf (datacopy, "%lf", &value) == 1) {
11630 GST_DEBUG_OBJECT (demux, "adding tag: %s [%s]", tag, datacopy);
11631 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, value, NULL);
11633 GST_WARNING_OBJECT (demux, "Failed to parse double from string: %s",
11641 qtdemux_tag_add_revdns (GstQTDemux * demux, GstTagList * taglist,
11642 const char *tag, const char *tag_bis, GNode * node)
11651 const gchar *meanstr;
11652 const gchar *namestr;
11654 /* checking the whole ---- atom size for consistency */
11655 if (QT_UINT32 (node->data) <= 4 + 12 + 12 + 16) {
11656 GST_WARNING_OBJECT (demux, "Tag ---- atom is too small, ignoring");
11660 mean = qtdemux_tree_get_child_by_type (node, FOURCC_mean);
11662 GST_WARNING_OBJECT (demux, "No 'mean' atom found");
11666 meansize = QT_UINT32 (mean->data);
11667 if (meansize <= 12) {
11668 GST_WARNING_OBJECT (demux, "Small mean atom, ignoring the whole tag");
11671 meanstr = ((gchar *) mean->data) + 12;
11674 name = qtdemux_tree_get_child_by_type (node, FOURCC_name);
11676 GST_WARNING_OBJECT (demux, "'name' atom not found, ignoring tag");
11680 namesize = QT_UINT32 (name->data);
11681 if (namesize <= 12) {
11682 GST_WARNING_OBJECT (demux, "'name' atom is too small, ignoring tag");
11685 namestr = ((gchar *) name->data) + 12;
11693 * uint24 - data type
11697 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
11699 GST_WARNING_OBJECT (demux, "No data atom in this tag");
11702 datasize = QT_UINT32 (data->data);
11703 if (datasize <= 16) {
11704 GST_WARNING_OBJECT (demux, "Data atom too small");
11707 datatype = QT_UINT32 (((gchar *) data->data) + 8) & 0xFFFFFF;
11709 if ((strncmp (meanstr, "com.apple.iTunes", meansize) == 0) ||
11710 (strncmp (meanstr, "org.hydrogenaudio.replaygain", meansize) == 0)) {
11711 static const struct
11713 const gchar name[28];
11714 const gchar tag[28];
11717 "replaygain_track_gain", GST_TAG_TRACK_GAIN}, {
11718 "replaygain_track_peak", GST_TAG_TRACK_PEAK}, {
11719 "replaygain_album_gain", GST_TAG_ALBUM_GAIN}, {
11720 "replaygain_album_peak", GST_TAG_ALBUM_PEAK}, {
11721 "MusicBrainz Track Id", GST_TAG_MUSICBRAINZ_TRACKID}, {
11722 "MusicBrainz Artist Id", GST_TAG_MUSICBRAINZ_ARTISTID}, {
11723 "MusicBrainz Album Id", GST_TAG_MUSICBRAINZ_ALBUMID}, {
11724 "MusicBrainz Album Artist Id", GST_TAG_MUSICBRAINZ_ALBUMARTISTID}
11728 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
11729 if (!g_ascii_strncasecmp (tags[i].name, namestr, namesize)) {
11730 switch (gst_tag_get_type (tags[i].tag)) {
11731 case G_TYPE_DOUBLE:
11732 qtdemux_add_double_tag_from_str (demux, taglist, tags[i].tag,
11733 ((guint8 *) data->data) + 16, datasize - 16);
11735 case G_TYPE_STRING:
11736 qtdemux_tag_add_str (demux, taglist, tags[i].tag, NULL, node);
11745 if (i == G_N_ELEMENTS (tags))
11755 #ifndef GST_DISABLE_GST_DEBUG
11757 gchar *namestr_dbg;
11758 gchar *meanstr_dbg;
11760 meanstr_dbg = g_strndup (meanstr, meansize);
11761 namestr_dbg = g_strndup (namestr, namesize);
11763 GST_WARNING_OBJECT (demux, "This tag %s:%s type:%u is not mapped, "
11764 "file a bug at bugzilla.gnome.org", meanstr_dbg, namestr_dbg, datatype);
11766 g_free (namestr_dbg);
11767 g_free (meanstr_dbg);
11774 qtdemux_tag_add_id32 (GstQTDemux * demux, GstTagList * taglist, const char *tag,
11775 const char *tag_bis, GNode * node)
11780 GstTagList *id32_taglist = NULL;
11782 GST_LOG_OBJECT (demux, "parsing ID32");
11785 len = GST_READ_UINT32_BE (data);
11787 /* need at least full box and language tag */
11791 buf = gst_buffer_new_allocate (NULL, len - 14, NULL);
11792 gst_buffer_fill (buf, 0, data + 14, len - 14);
11794 id32_taglist = gst_tag_list_from_id3v2_tag (buf);
11795 if (id32_taglist) {
11796 GST_LOG_OBJECT (demux, "parsing ok");
11797 gst_tag_list_insert (taglist, id32_taglist, GST_TAG_MERGE_KEEP);
11798 gst_tag_list_unref (id32_taglist);
11800 GST_LOG_OBJECT (demux, "parsing failed");
11803 gst_buffer_unref (buf);
11806 typedef void (*GstQTDemuxAddTagFunc) (GstQTDemux * demux, GstTagList * taglist,
11807 const char *tag, const char *tag_bis, GNode * node);
11810 FOURCC_pcst -> if media is a podcast -> bool
11811 FOURCC_cpil -> if media is part of a compilation -> bool
11812 FOURCC_pgap -> if media is part of a gapless context -> bool
11813 FOURCC_tven -> the tv episode id e.g. S01E23 -> str
11816 static const struct
11819 const gchar *gst_tag;
11820 const gchar *gst_tag_bis;
11821 const GstQTDemuxAddTagFunc func;
11824 FOURCC__nam, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
11825 FOURCC_titl, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
11826 FOURCC__grp, GST_TAG_GROUPING, NULL, qtdemux_tag_add_str}, {
11827 FOURCC__wrt, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
11828 FOURCC__ART, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
11829 FOURCC_aART, GST_TAG_ALBUM_ARTIST, NULL, qtdemux_tag_add_str}, {
11830 FOURCC_perf, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
11831 FOURCC_auth, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
11832 FOURCC__alb, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
11833 FOURCC_albm, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
11834 FOURCC_cprt, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
11835 FOURCC__cpy, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
11836 FOURCC__cmt, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
11837 FOURCC__des, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
11838 FOURCC_desc, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
11839 FOURCC_dscp, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
11840 FOURCC__lyr, GST_TAG_LYRICS, NULL, qtdemux_tag_add_str}, {
11841 FOURCC__day, GST_TAG_DATE, NULL, qtdemux_tag_add_date}, {
11842 FOURCC_yrrc, GST_TAG_DATE, NULL, qtdemux_tag_add_year}, {
11843 FOURCC__too, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
11844 FOURCC__inf, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
11845 FOURCC_trkn, GST_TAG_TRACK_NUMBER, GST_TAG_TRACK_COUNT, qtdemux_tag_add_num}, {
11846 FOURCC_disk, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
11847 qtdemux_tag_add_num}, {
11848 FOURCC_disc, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
11849 qtdemux_tag_add_num}, {
11850 FOURCC__gen, GST_TAG_GENRE, NULL, qtdemux_tag_add_str}, {
11851 FOURCC_gnre, GST_TAG_GENRE, NULL, qtdemux_tag_add_gnre}, {
11852 FOURCC_tmpo, GST_TAG_BEATS_PER_MINUTE, NULL, qtdemux_tag_add_tmpo}, {
11853 FOURCC_covr, GST_TAG_PREVIEW_IMAGE, NULL, qtdemux_tag_add_covr}, {
11854 FOURCC_sonm, GST_TAG_TITLE_SORTNAME, NULL, qtdemux_tag_add_str}, {
11855 FOURCC_soal, GST_TAG_ALBUM_SORTNAME, NULL, qtdemux_tag_add_str}, {
11856 FOURCC_soar, GST_TAG_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
11857 FOURCC_soaa, GST_TAG_ALBUM_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
11858 FOURCC_soco, GST_TAG_COMPOSER_SORTNAME, NULL, qtdemux_tag_add_str}, {
11859 FOURCC_sosn, GST_TAG_SHOW_SORTNAME, NULL, qtdemux_tag_add_str}, {
11860 FOURCC_tvsh, GST_TAG_SHOW_NAME, NULL, qtdemux_tag_add_str}, {
11861 FOURCC_tvsn, GST_TAG_SHOW_SEASON_NUMBER, NULL, qtdemux_tag_add_uint32}, {
11862 FOURCC_tves, GST_TAG_SHOW_EPISODE_NUMBER, NULL, qtdemux_tag_add_uint32}, {
11863 FOURCC_kywd, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_keywords}, {
11864 FOURCC_keyw, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_str}, {
11865 FOURCC__enc, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
11866 FOURCC_loci, GST_TAG_GEO_LOCATION_NAME, NULL, qtdemux_tag_add_location}, {
11867 FOURCC_clsf, GST_QT_DEMUX_CLASSIFICATION_TAG, NULL,
11868 qtdemux_tag_add_classification}, {
11869 FOURCC__mak, GST_TAG_DEVICE_MANUFACTURER, NULL, qtdemux_tag_add_str}, {
11870 FOURCC__mod, GST_TAG_DEVICE_MODEL, NULL, qtdemux_tag_add_str}, {
11871 FOURCC__swr, GST_TAG_APPLICATION_NAME, NULL, qtdemux_tag_add_str}, {
11873 /* This is a special case, some tags are stored in this
11874 * 'reverse dns naming', according to:
11875 * http://atomicparsley.sourceforge.net/mpeg-4files.html and
11878 FOURCC_____, "", NULL, qtdemux_tag_add_revdns}, {
11879 /* see http://www.mp4ra.org/specs.html for ID32 in meta box */
11880 FOURCC_ID32, "", NULL, qtdemux_tag_add_id32}
11883 struct _GstQtDemuxTagList
11886 GstTagList *taglist;
11888 typedef struct _GstQtDemuxTagList GstQtDemuxTagList;
11891 qtdemux_tag_add_blob (GNode * node, GstQtDemuxTagList * qtdemuxtaglist)
11897 const gchar *style;
11902 GstQTDemux *demux = qtdemuxtaglist->demux;
11903 GstTagList *taglist = qtdemuxtaglist->taglist;
11906 len = QT_UINT32 (data);
11907 buf = gst_buffer_new_and_alloc (len);
11908 gst_buffer_fill (buf, 0, data, len);
11910 /* heuristic to determine style of tag */
11911 if (QT_FOURCC (data + 4) == FOURCC_____ ||
11912 (len > 8 + 12 && QT_FOURCC (data + 12) == FOURCC_data))
11914 else if (demux->major_brand == FOURCC_qt__)
11915 style = "quicktime";
11916 /* fall back to assuming iso/3gp tag style */
11920 /* santize the name for the caps. */
11921 for (i = 0; i < 4; i++) {
11922 guint8 d = data[4 + i];
11923 if (g_ascii_isalnum (d))
11924 ndata[i] = g_ascii_tolower (d);
11929 media_type = g_strdup_printf ("application/x-gst-qt-%c%c%c%c-tag",
11930 ndata[0], ndata[1], ndata[2], ndata[3]);
11931 GST_DEBUG_OBJECT (demux, "media type %s", media_type);
11933 s = gst_structure_new (media_type, "style", G_TYPE_STRING, style, NULL);
11934 sample = gst_sample_new (buf, NULL, NULL, s);
11935 gst_buffer_unref (buf);
11936 g_free (media_type);
11938 GST_DEBUG_OBJECT (demux, "adding private tag; size %d, info %" GST_PTR_FORMAT,
11941 gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND,
11942 GST_QT_DEMUX_PRIVATE_TAG, sample, NULL);
11944 gst_sample_unref (sample);
11948 qtdemux_parse_udta (GstQTDemux * qtdemux, GstTagList * taglist, GNode * udta)
11955 GstQtDemuxTagList demuxtaglist;
11957 demuxtaglist.demux = qtdemux;
11958 demuxtaglist.taglist = taglist;
11960 meta = qtdemux_tree_get_child_by_type (udta, FOURCC_meta);
11961 if (meta != NULL) {
11962 ilst = qtdemux_tree_get_child_by_type (meta, FOURCC_ilst);
11963 if (ilst == NULL) {
11964 GST_LOG_OBJECT (qtdemux, "no ilst");
11969 GST_LOG_OBJECT (qtdemux, "no meta so using udta itself");
11973 while (i < G_N_ELEMENTS (add_funcs)) {
11974 node = qtdemux_tree_get_child_by_type (ilst, add_funcs[i].fourcc);
11978 len = QT_UINT32 (node->data);
11980 GST_DEBUG_OBJECT (qtdemux, "too small tag atom %" GST_FOURCC_FORMAT,
11981 GST_FOURCC_ARGS (add_funcs[i].fourcc));
11983 add_funcs[i].func (qtdemux, taglist, add_funcs[i].gst_tag,
11984 add_funcs[i].gst_tag_bis, node);
11986 g_node_destroy (node);
11992 /* parsed nodes have been removed, pass along remainder as blob */
11993 g_node_children_foreach (ilst, G_TRAVERSE_ALL,
11994 (GNodeForeachFunc) qtdemux_tag_add_blob, &demuxtaglist);
11996 /* parse up XMP_ node if existing */
11997 xmp_ = qtdemux_tree_get_child_by_type (udta, FOURCC_XMP_);
11998 if (xmp_ != NULL) {
12000 GstTagList *xmptaglist;
12002 buf = _gst_buffer_new_wrapped (((guint8 *) xmp_->data) + 8,
12003 QT_UINT32 ((guint8 *) xmp_->data) - 8, NULL);
12004 xmptaglist = gst_tag_list_from_xmp_buffer (buf);
12005 gst_buffer_unref (buf);
12007 qtdemux_handle_xmp_taglist (qtdemux, taglist, xmptaglist);
12009 GST_DEBUG_OBJECT (qtdemux, "No XMP_ node found");
12015 GstStructure *structure; /* helper for sort function */
12017 guint min_req_bitrate;
12018 guint min_req_qt_version;
12022 qtdemux_redirects_sort_func (gconstpointer a, gconstpointer b)
12024 GstQtReference *ref_a = (GstQtReference *) a;
12025 GstQtReference *ref_b = (GstQtReference *) b;
12027 if (ref_b->min_req_qt_version != ref_a->min_req_qt_version)
12028 return ref_b->min_req_qt_version - ref_a->min_req_qt_version;
12030 /* known bitrates go before unknown; higher bitrates go first */
12031 return ref_b->min_req_bitrate - ref_a->min_req_bitrate;
12034 /* sort the redirects and post a message for the application.
12037 qtdemux_process_redirects (GstQTDemux * qtdemux, GList * references)
12039 GstQtReference *best;
12042 GValue list_val = { 0, };
12045 g_assert (references != NULL);
12047 references = g_list_sort (references, qtdemux_redirects_sort_func);
12049 best = (GstQtReference *) references->data;
12051 g_value_init (&list_val, GST_TYPE_LIST);
12053 for (l = references; l != NULL; l = l->next) {
12054 GstQtReference *ref = (GstQtReference *) l->data;
12055 GValue struct_val = { 0, };
12057 ref->structure = gst_structure_new ("redirect",
12058 "new-location", G_TYPE_STRING, ref->location, NULL);
12060 if (ref->min_req_bitrate > 0) {
12061 gst_structure_set (ref->structure, "minimum-bitrate", G_TYPE_INT,
12062 ref->min_req_bitrate, NULL);
12065 g_value_init (&struct_val, GST_TYPE_STRUCTURE);
12066 g_value_set_boxed (&struct_val, ref->structure);
12067 gst_value_list_append_value (&list_val, &struct_val);
12068 g_value_unset (&struct_val);
12069 /* don't free anything here yet, since we need best->structure below */
12072 g_assert (best != NULL);
12073 s = gst_structure_copy (best->structure);
12075 if (g_list_length (references) > 1) {
12076 gst_structure_set_value (s, "locations", &list_val);
12079 g_value_unset (&list_val);
12081 for (l = references; l != NULL; l = l->next) {
12082 GstQtReference *ref = (GstQtReference *) l->data;
12084 gst_structure_free (ref->structure);
12085 g_free (ref->location);
12088 g_list_free (references);
12090 GST_INFO_OBJECT (qtdemux, "posting redirect message: %" GST_PTR_FORMAT, s);
12091 msg = gst_message_new_element (GST_OBJECT_CAST (qtdemux), s);
12092 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
12093 qtdemux->posted_redirect = TRUE;
12096 /* look for redirect nodes, collect all redirect information and
12100 qtdemux_parse_redirects (GstQTDemux * qtdemux)
12102 GNode *rmra, *rmda, *rdrf;
12104 rmra = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_rmra);
12106 GList *redirects = NULL;
12108 rmda = qtdemux_tree_get_child_by_type (rmra, FOURCC_rmda);
12110 GstQtReference ref = { NULL, NULL, 0, 0 };
12111 GNode *rmdr, *rmvc;
12113 if ((rmdr = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmdr))) {
12114 ref.min_req_bitrate = QT_UINT32 ((guint8 *) rmdr->data + 12);
12115 GST_LOG_OBJECT (qtdemux, "data rate atom, required bitrate = %u",
12116 ref.min_req_bitrate);
12119 if ((rmvc = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmvc))) {
12120 guint32 package = QT_FOURCC ((guint8 *) rmvc->data + 12);
12121 guint version = QT_UINT32 ((guint8 *) rmvc->data + 16);
12123 #ifndef GST_DISABLE_GST_DEBUG
12124 guint bitmask = QT_UINT32 ((guint8 *) rmvc->data + 20);
12126 guint check_type = QT_UINT16 ((guint8 *) rmvc->data + 24);
12128 GST_LOG_OBJECT (qtdemux,
12129 "version check atom [%" GST_FOURCC_FORMAT "], version=0x%08x"
12130 ", mask=%08x, check_type=%u", GST_FOURCC_ARGS (package), version,
12131 bitmask, check_type);
12132 if (package == FOURCC_qtim && check_type == 0) {
12133 ref.min_req_qt_version = version;
12137 rdrf = qtdemux_tree_get_child_by_type (rmda, FOURCC_rdrf);
12143 ref_len = QT_UINT32 ((guint8 *) rdrf->data);
12144 if (ref_len > 20) {
12145 ref_type = QT_FOURCC ((guint8 *) rdrf->data + 12);
12146 ref_data = (guint8 *) rdrf->data + 20;
12147 if (ref_type == FOURCC_alis) {
12148 guint record_len, record_version, fn_len;
12150 if (ref_len > 70) {
12151 /* MacOSX alias record, google for alias-layout.txt */
12152 record_len = QT_UINT16 (ref_data + 4);
12153 record_version = QT_UINT16 (ref_data + 4 + 2);
12154 fn_len = QT_UINT8 (ref_data + 50);
12155 if (record_len > 50 && record_version == 2 && fn_len > 0) {
12156 ref.location = g_strndup ((gchar *) ref_data + 51, fn_len);
12159 GST_WARNING_OBJECT (qtdemux, "Invalid rdrf/alis size (%u < 70)",
12162 } else if (ref_type == FOURCC_url_) {
12163 ref.location = g_strndup ((gchar *) ref_data, ref_len - 8);
12165 GST_DEBUG_OBJECT (qtdemux,
12166 "unknown rdrf reference type %" GST_FOURCC_FORMAT,
12167 GST_FOURCC_ARGS (ref_type));
12169 if (ref.location != NULL) {
12170 GST_INFO_OBJECT (qtdemux, "New location: %s", ref.location);
12172 g_list_prepend (redirects, g_memdup (&ref, sizeof (ref)));
12174 GST_WARNING_OBJECT (qtdemux,
12175 "Failed to extract redirect location from rdrf atom");
12178 GST_WARNING_OBJECT (qtdemux, "Invalid rdrf size (%u < 20)", ref_len);
12182 /* look for others */
12183 rmda = qtdemux_tree_get_sibling_by_type (rmda, FOURCC_rmda);
12186 if (redirects != NULL) {
12187 qtdemux_process_redirects (qtdemux, redirects);
12193 static GstTagList *
12194 qtdemux_add_container_format (GstQTDemux * qtdemux, GstTagList * tags)
12198 if (tags == NULL) {
12199 tags = gst_tag_list_new_empty ();
12200 gst_tag_list_set_scope (tags, GST_TAG_SCOPE_GLOBAL);
12203 if (qtdemux->major_brand == FOURCC_mjp2)
12204 fmt = "Motion JPEG 2000";
12205 else if ((qtdemux->major_brand & 0xffff) == FOURCC_3g__)
12207 else if (qtdemux->major_brand == FOURCC_qt__)
12209 else if (qtdemux->fragmented)
12212 fmt = "ISO MP4/M4A";
12214 GST_LOG_OBJECT (qtdemux, "mapped %" GST_FOURCC_FORMAT " to '%s'",
12215 GST_FOURCC_ARGS (qtdemux->major_brand), fmt);
12217 gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_CONTAINER_FORMAT,
12223 /* we have read the complete moov node now.
12224 * This function parses all of the relevant info, creates the traks and
12225 * prepares all data structures for playback
12228 qtdemux_parse_tree (GstQTDemux * qtdemux)
12234 GstClockTime duration;
12236 guint64 creation_time;
12237 GstDateTime *datetime = NULL;
12240 /* make sure we have a usable taglist */
12241 if (!qtdemux->tag_list) {
12242 qtdemux->tag_list = gst_tag_list_new_empty ();
12243 gst_tag_list_set_scope (qtdemux->tag_list, GST_TAG_SCOPE_GLOBAL);
12245 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
12248 mvhd = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvhd);
12249 if (mvhd == NULL) {
12250 GST_LOG_OBJECT (qtdemux, "No mvhd node found, looking for redirects.");
12251 return qtdemux_parse_redirects (qtdemux);
12254 version = QT_UINT8 ((guint8 *) mvhd->data + 8);
12255 if (version == 1) {
12256 creation_time = QT_UINT64 ((guint8 *) mvhd->data + 12);
12257 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 28);
12258 qtdemux->duration = QT_UINT64 ((guint8 *) mvhd->data + 32);
12259 } else if (version == 0) {
12260 creation_time = QT_UINT32 ((guint8 *) mvhd->data + 12);
12261 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 20);
12262 qtdemux->duration = QT_UINT32 ((guint8 *) mvhd->data + 24);
12264 GST_WARNING_OBJECT (qtdemux, "Unhandled mvhd version %d", version);
12268 /* Moving qt creation time (secs since 1904) to unix time */
12269 if (creation_time != 0) {
12270 /* Try to use epoch first as it should be faster and more commonly found */
12271 if (creation_time >= QTDEMUX_SECONDS_FROM_1904_TO_1970) {
12274 creation_time -= QTDEMUX_SECONDS_FROM_1904_TO_1970;
12275 /* some data cleansing sanity */
12276 g_get_current_time (&now);
12277 if (now.tv_sec + 24 * 3600 < creation_time) {
12278 GST_DEBUG_OBJECT (qtdemux, "discarding bogus future creation time");
12280 datetime = gst_date_time_new_from_unix_epoch_utc (creation_time);
12283 GDateTime *base_dt = g_date_time_new_utc (1904, 1, 1, 0, 0, 0);
12284 GDateTime *dt, *dt_local;
12286 dt = g_date_time_add_seconds (base_dt, creation_time);
12287 dt_local = g_date_time_to_local (dt);
12288 datetime = gst_date_time_new_from_g_date_time (dt_local);
12290 g_date_time_unref (base_dt);
12291 g_date_time_unref (dt);
12295 /* Use KEEP as explicit tags should have a higher priority than mvhd tag */
12296 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_KEEP, GST_TAG_DATE_TIME,
12298 gst_date_time_unref (datetime);
12301 GST_INFO_OBJECT (qtdemux, "timescale: %u", qtdemux->timescale);
12302 GST_INFO_OBJECT (qtdemux, "duration: %" G_GUINT64_FORMAT, qtdemux->duration);
12304 /* check for fragmented file and get some (default) data */
12305 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
12308 GstByteReader mehd_data;
12310 /* let track parsing or anyone know weird stuff might happen ... */
12311 qtdemux->fragmented = TRUE;
12313 /* compensate for total duration */
12314 mehd = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_mehd, &mehd_data);
12316 qtdemux_parse_mehd (qtdemux, &mehd_data);
12319 /* set duration in the segment info */
12320 gst_qtdemux_get_duration (qtdemux, &duration);
12322 qtdemux->segment.duration = duration;
12323 /* also do not exceed duration; stop is set that way post seek anyway,
12324 * and segment activation falls back to duration,
12325 * whereas loop only checks stop, so let's align this here as well */
12326 qtdemux->segment.stop = duration;
12329 /* parse all traks */
12330 trak = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_trak);
12332 qtdemux_parse_trak (qtdemux, trak);
12333 /* iterate all siblings */
12334 trak = qtdemux_tree_get_sibling_by_type (trak, FOURCC_trak);
12337 if (!qtdemux->tag_list) {
12338 GST_DEBUG_OBJECT (qtdemux, "new tag list");
12339 qtdemux->tag_list = gst_tag_list_new_empty ();
12340 gst_tag_list_set_scope (qtdemux->tag_list, GST_TAG_SCOPE_GLOBAL);
12342 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
12346 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_udta);
12348 qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
12350 GST_LOG_OBJECT (qtdemux, "No udta node found.");
12353 /* maybe also some tags in meta box */
12354 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_meta);
12356 GST_DEBUG_OBJECT (qtdemux, "Parsing meta box for tags.");
12357 qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
12359 GST_LOG_OBJECT (qtdemux, "No meta node found.");
12362 /* parse any protection system info */
12363 pssh = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_pssh);
12365 GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
12366 qtdemux_parse_pssh (qtdemux, pssh);
12367 pssh = qtdemux_tree_get_sibling_by_type (pssh, FOURCC_pssh);
12370 qtdemux->tag_list = qtdemux_add_container_format (qtdemux, qtdemux->tag_list);
12375 /* taken from ffmpeg */
12377 read_descr_size (guint8 * ptr, guint8 * end, guint8 ** end_out)
12389 len = (len << 7) | (c & 0x7f);
12397 /* this can change the codec originally present in @list */
12399 gst_qtdemux_handle_esds (GstQTDemux * qtdemux, QtDemuxStream * stream,
12400 GNode * esds, GstTagList * list)
12402 int len = QT_UINT32 (esds->data);
12403 guint8 *ptr = esds->data;
12404 guint8 *end = ptr + len;
12406 guint8 *data_ptr = NULL;
12408 guint8 object_type_id = 0;
12409 const char *codec_name = NULL;
12410 GstCaps *caps = NULL;
12412 GST_MEMDUMP_OBJECT (qtdemux, "esds", ptr, len);
12414 GST_DEBUG_OBJECT (qtdemux, "version/flags = %08x", QT_UINT32 (ptr));
12416 while (ptr + 1 < end) {
12417 tag = QT_UINT8 (ptr);
12418 GST_DEBUG_OBJECT (qtdemux, "tag = %02x", tag);
12420 len = read_descr_size (ptr, end, &ptr);
12421 GST_DEBUG_OBJECT (qtdemux, "len = %d", len);
12423 /* Check the stated amount of data is available for reading */
12424 if (len < 0 || ptr + len > end)
12428 case ES_DESCRIPTOR_TAG:
12429 GST_DEBUG_OBJECT (qtdemux, "ID %04x", QT_UINT16 (ptr));
12430 GST_DEBUG_OBJECT (qtdemux, "priority %04x", QT_UINT8 (ptr + 2));
12433 case DECODER_CONFIG_DESC_TAG:{
12434 guint max_bitrate, avg_bitrate;
12436 object_type_id = QT_UINT8 (ptr);
12437 max_bitrate = QT_UINT32 (ptr + 5);
12438 avg_bitrate = QT_UINT32 (ptr + 9);
12439 GST_DEBUG_OBJECT (qtdemux, "object_type_id %02x", object_type_id);
12440 GST_DEBUG_OBJECT (qtdemux, "stream_type %02x", QT_UINT8 (ptr + 1));
12441 GST_DEBUG_OBJECT (qtdemux, "buffer_size_db %02x", QT_UINT24 (ptr + 2));
12442 GST_DEBUG_OBJECT (qtdemux, "max bitrate %u", max_bitrate);
12443 GST_DEBUG_OBJECT (qtdemux, "avg bitrate %u", avg_bitrate);
12444 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
12445 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
12446 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
12448 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
12449 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
12450 avg_bitrate, NULL);
12455 case DECODER_SPECIFIC_INFO_TAG:
12456 GST_MEMDUMP_OBJECT (qtdemux, "data", ptr, len);
12457 if (object_type_id == 0xe0 && len == 0x40) {
12463 GST_DEBUG_OBJECT (qtdemux,
12464 "Have VOBSUB palette. Creating palette event");
12465 /* move to decConfigDescr data and read palette */
12467 for (i = 0; i < 16; i++) {
12468 clut[i] = QT_UINT32 (data);
12472 s = gst_structure_new ("application/x-gst-dvd", "event",
12473 G_TYPE_STRING, "dvd-spu-clut-change",
12474 "clut00", G_TYPE_INT, clut[0], "clut01", G_TYPE_INT, clut[1],
12475 "clut02", G_TYPE_INT, clut[2], "clut03", G_TYPE_INT, clut[3],
12476 "clut04", G_TYPE_INT, clut[4], "clut05", G_TYPE_INT, clut[5],
12477 "clut06", G_TYPE_INT, clut[6], "clut07", G_TYPE_INT, clut[7],
12478 "clut08", G_TYPE_INT, clut[8], "clut09", G_TYPE_INT, clut[9],
12479 "clut10", G_TYPE_INT, clut[10], "clut11", G_TYPE_INT, clut[11],
12480 "clut12", G_TYPE_INT, clut[12], "clut13", G_TYPE_INT, clut[13],
12481 "clut14", G_TYPE_INT, clut[14], "clut15", G_TYPE_INT, clut[15],
12484 /* store event and trigger custom processing */
12485 stream->pending_event =
12486 gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s);
12488 /* Generic codec_data handler puts it on the caps */
12495 case SL_CONFIG_DESC_TAG:
12496 GST_DEBUG_OBJECT (qtdemux, "data %02x", QT_UINT8 (ptr));
12500 GST_DEBUG_OBJECT (qtdemux, "Unknown/unhandled descriptor tag %02x",
12502 GST_MEMDUMP_OBJECT (qtdemux, "descriptor data", ptr, len);
12508 /* object_type_id in the esds atom in mp4a and mp4v tells us which codec is
12509 * in use, and should also be used to override some other parameters for some
12511 switch (object_type_id) {
12512 case 0x20: /* MPEG-4 */
12513 /* 4 bytes for the visual_object_sequence_start_code and 1 byte for the
12514 * profile_and_level_indication */
12515 if (data_ptr != NULL && data_len >= 5 &&
12516 GST_READ_UINT32_BE (data_ptr) == 0x000001b0) {
12517 gst_codec_utils_mpeg4video_caps_set_level_and_profile (stream->caps,
12518 data_ptr + 4, data_len - 4);
12520 break; /* Nothing special needed here */
12521 case 0x21: /* H.264 */
12522 codec_name = "H.264 / AVC";
12523 caps = gst_caps_new_simple ("video/x-h264",
12524 "stream-format", G_TYPE_STRING, "avc",
12525 "alignment", G_TYPE_STRING, "au", NULL);
12527 case 0x40: /* AAC (any) */
12528 case 0x66: /* AAC Main */
12529 case 0x67: /* AAC LC */
12530 case 0x68: /* AAC SSR */
12531 /* Override channels and rate based on the codec_data, as it's often
12533 /* Only do so for basic setup without HE-AAC extension */
12534 if (data_ptr && data_len == 2) {
12535 guint channels, rate;
12537 channels = gst_codec_utils_aac_get_channels (data_ptr, data_len);
12539 stream->n_channels = channels;
12541 rate = gst_codec_utils_aac_get_sample_rate (data_ptr, data_len);
12543 stream->rate = rate;
12546 /* Set level and profile if possible */
12547 if (data_ptr != NULL && data_len >= 2) {
12548 gst_codec_utils_aac_caps_set_level_and_profile (stream->caps,
12549 data_ptr, data_len);
12552 case 0x60: /* MPEG-2, various profiles */
12558 codec_name = "MPEG-2 video";
12559 caps = gst_caps_new_simple ("video/mpeg",
12560 "mpegversion", G_TYPE_INT, 2,
12561 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
12563 case 0x69: /* MPEG-2 BC audio */
12564 case 0x6B: /* MPEG-1 audio */
12565 caps = gst_caps_new_simple ("audio/mpeg",
12566 "mpegversion", G_TYPE_INT, 1, "parsed", G_TYPE_BOOLEAN, TRUE, NULL);
12567 codec_name = "MPEG-1 audio";
12569 case 0x6A: /* MPEG-1 */
12570 codec_name = "MPEG-1 video";
12571 caps = gst_caps_new_simple ("video/mpeg",
12572 "mpegversion", G_TYPE_INT, 1,
12573 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
12575 case 0x6C: /* MJPEG */
12577 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
12579 codec_name = "Motion-JPEG";
12581 case 0x6D: /* PNG */
12583 gst_caps_new_simple ("image/png", "parsed", G_TYPE_BOOLEAN, TRUE,
12585 codec_name = "PNG still images";
12587 case 0x6E: /* JPEG2000 */
12588 codec_name = "JPEG-2000";
12589 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
12591 case 0xA4: /* Dirac */
12592 codec_name = "Dirac";
12593 caps = gst_caps_new_empty_simple ("video/x-dirac");
12595 case 0xA5: /* AC3 */
12596 codec_name = "AC-3 audio";
12597 caps = gst_caps_new_simple ("audio/x-ac3",
12598 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
12600 case 0xA9: /* AC3 */
12601 codec_name = "DTS audio";
12602 caps = gst_caps_new_simple ("audio/x-dts",
12603 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
12605 case 0xE1: /* QCELP */
12606 /* QCELP, the codec_data is a riff tag (little endian) with
12607 * 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). */
12608 caps = gst_caps_new_empty_simple ("audio/qcelp");
12609 codec_name = "QCELP";
12615 /* If we have a replacement caps, then change our caps for this stream */
12617 gst_caps_unref (stream->caps);
12618 stream->caps = caps;
12621 if (codec_name && list)
12622 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
12623 GST_TAG_AUDIO_CODEC, codec_name, NULL);
12625 /* Add the codec_data attribute to caps, if we have it */
12629 buffer = gst_buffer_new_and_alloc (data_len);
12630 gst_buffer_fill (buffer, 0, data_ptr, data_len);
12632 GST_DEBUG_OBJECT (qtdemux, "setting codec_data from esds");
12633 GST_MEMDUMP_OBJECT (qtdemux, "codec_data from esds", data_ptr, data_len);
12635 gst_caps_set_simple (stream->caps, "codec_data", GST_TYPE_BUFFER,
12637 gst_buffer_unref (buffer);
12642 #define _codec(name) \
12644 if (codec_name) { \
12645 *codec_name = g_strdup (name); \
12650 qtdemux_video_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
12651 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
12653 GstCaps *caps = NULL;
12654 GstVideoFormat format = GST_VIDEO_FORMAT_UNKNOWN;
12657 case GST_MAKE_FOURCC ('p', 'n', 'g', ' '):
12658 _codec ("PNG still images");
12659 caps = gst_caps_new_empty_simple ("image/png");
12662 _codec ("JPEG still images");
12664 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
12667 case GST_MAKE_FOURCC ('m', 'j', 'p', 'a'):
12668 case GST_MAKE_FOURCC ('A', 'V', 'D', 'J'):
12669 case GST_MAKE_FOURCC ('M', 'J', 'P', 'G'):
12670 case GST_MAKE_FOURCC ('d', 'm', 'b', '1'):
12671 _codec ("Motion-JPEG");
12673 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
12676 case GST_MAKE_FOURCC ('m', 'j', 'p', 'b'):
12677 _codec ("Motion-JPEG format B");
12678 caps = gst_caps_new_empty_simple ("video/x-mjpeg-b");
12681 _codec ("JPEG-2000");
12682 /* override to what it should be according to spec, avoid palette_data */
12683 stream->bits_per_sample = 24;
12684 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
12687 _codec ("Sorensen video v.3");
12688 caps = gst_caps_new_simple ("video/x-svq",
12689 "svqversion", G_TYPE_INT, 3, NULL);
12691 case GST_MAKE_FOURCC ('s', 'v', 'q', 'i'):
12692 case GST_MAKE_FOURCC ('S', 'V', 'Q', '1'):
12693 _codec ("Sorensen video v.1");
12694 caps = gst_caps_new_simple ("video/x-svq",
12695 "svqversion", G_TYPE_INT, 1, NULL);
12697 case GST_MAKE_FOURCC ('W', 'R', 'A', 'W'):
12698 caps = gst_caps_new_empty_simple ("video/x-raw");
12699 gst_caps_set_simple (caps, "format", G_TYPE_STRING, "RGB8P", NULL);
12700 _codec ("Windows Raw RGB");
12706 bps = QT_UINT16 (stsd_data + 98);
12709 format = GST_VIDEO_FORMAT_RGB15;
12712 format = GST_VIDEO_FORMAT_RGB16;
12715 format = GST_VIDEO_FORMAT_RGB;
12718 format = GST_VIDEO_FORMAT_ARGB;
12726 case GST_MAKE_FOURCC ('y', 'v', '1', '2'):
12727 format = GST_VIDEO_FORMAT_I420;
12729 case GST_MAKE_FOURCC ('y', 'u', 'v', '2'):
12730 case GST_MAKE_FOURCC ('Y', 'u', 'v', '2'):
12731 format = GST_VIDEO_FORMAT_I420;
12734 case GST_MAKE_FOURCC ('2', 'V', 'u', 'y'):
12735 format = GST_VIDEO_FORMAT_UYVY;
12737 case GST_MAKE_FOURCC ('v', '3', '0', '8'):
12738 format = GST_VIDEO_FORMAT_v308;
12740 case GST_MAKE_FOURCC ('v', '2', '1', '6'):
12741 format = GST_VIDEO_FORMAT_v216;
12744 format = GST_VIDEO_FORMAT_v210;
12746 case GST_MAKE_FOURCC ('r', '2', '1', '0'):
12747 format = GST_VIDEO_FORMAT_r210;
12749 /* Packed YUV 4:4:4 10 bit in 32 bits, complex
12750 case GST_MAKE_FOURCC ('v', '4', '1', '0'):
12751 format = GST_VIDEO_FORMAT_v410;
12754 /* Packed YUV 4:4:4:4 8 bit in 32 bits
12755 * but different order than AYUV
12756 case GST_MAKE_FOURCC ('v', '4', '0', '8'):
12757 format = GST_VIDEO_FORMAT_v408;
12760 case GST_MAKE_FOURCC ('m', 'p', 'e', 'g'):
12761 case GST_MAKE_FOURCC ('m', 'p', 'g', '1'):
12762 _codec ("MPEG-1 video");
12763 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
12764 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
12766 case GST_MAKE_FOURCC ('h', 'd', 'v', '1'): /* HDV 720p30 */
12767 case GST_MAKE_FOURCC ('h', 'd', 'v', '2'): /* HDV 1080i60 */
12768 case GST_MAKE_FOURCC ('h', 'd', 'v', '3'): /* HDV 1080i50 */
12769 case GST_MAKE_FOURCC ('h', 'd', 'v', '4'): /* HDV 720p24 */
12770 case GST_MAKE_FOURCC ('h', 'd', 'v', '5'): /* HDV 720p25 */
12771 case GST_MAKE_FOURCC ('h', 'd', 'v', '6'): /* HDV 1080p24 */
12772 case GST_MAKE_FOURCC ('h', 'd', 'v', '7'): /* HDV 1080p25 */
12773 case GST_MAKE_FOURCC ('h', 'd', 'v', '8'): /* HDV 1080p30 */
12774 case GST_MAKE_FOURCC ('h', 'd', 'v', '9'): /* HDV 720p60 */
12775 case GST_MAKE_FOURCC ('h', 'd', 'v', 'a'): /* HDV 720p50 */
12776 case GST_MAKE_FOURCC ('m', 'x', '5', 'n'): /* MPEG2 IMX NTSC 525/60 50mb/s produced by FCP */
12777 case GST_MAKE_FOURCC ('m', 'x', '5', 'p'): /* MPEG2 IMX PAL 625/60 50mb/s produced by FCP */
12778 case GST_MAKE_FOURCC ('m', 'x', '4', 'n'): /* MPEG2 IMX NTSC 525/60 40mb/s produced by FCP */
12779 case GST_MAKE_FOURCC ('m', 'x', '4', 'p'): /* MPEG2 IMX PAL 625/60 40mb/s produced by FCP */
12780 case GST_MAKE_FOURCC ('m', 'x', '3', 'n'): /* MPEG2 IMX NTSC 525/60 30mb/s produced by FCP */
12781 case GST_MAKE_FOURCC ('m', 'x', '3', 'p'): /* MPEG2 IMX PAL 625/50 30mb/s produced by FCP */
12782 case GST_MAKE_FOURCC ('x', 'd', 'v', '1'): /* XDCAM HD 720p30 35Mb/s */
12783 case GST_MAKE_FOURCC ('x', 'd', 'v', '2'): /* XDCAM HD 1080i60 35Mb/s */
12784 case GST_MAKE_FOURCC ('x', 'd', 'v', '3'): /* XDCAM HD 1080i50 35Mb/s */
12785 case GST_MAKE_FOURCC ('x', 'd', 'v', '4'): /* XDCAM HD 720p24 35Mb/s */
12786 case GST_MAKE_FOURCC ('x', 'd', 'v', '5'): /* XDCAM HD 720p25 35Mb/s */
12787 case GST_MAKE_FOURCC ('x', 'd', 'v', '6'): /* XDCAM HD 1080p24 35Mb/s */
12788 case GST_MAKE_FOURCC ('x', 'd', 'v', '7'): /* XDCAM HD 1080p25 35Mb/s */
12789 case GST_MAKE_FOURCC ('x', 'd', 'v', '8'): /* XDCAM HD 1080p30 35Mb/s */
12790 case GST_MAKE_FOURCC ('x', 'd', 'v', '9'): /* XDCAM HD 720p60 35Mb/s */
12791 case GST_MAKE_FOURCC ('x', 'd', 'v', 'a'): /* XDCAM HD 720p50 35Mb/s */
12792 case GST_MAKE_FOURCC ('x', 'd', 'v', 'b'): /* XDCAM EX 1080i60 50Mb/s CBR */
12793 case GST_MAKE_FOURCC ('x', 'd', 'v', 'c'): /* XDCAM EX 1080i50 50Mb/s CBR */
12794 case GST_MAKE_FOURCC ('x', 'd', 'v', 'd'): /* XDCAM HD 1080p24 50Mb/s CBR */
12795 case GST_MAKE_FOURCC ('x', 'd', 'v', 'e'): /* XDCAM HD 1080p25 50Mb/s CBR */
12796 case GST_MAKE_FOURCC ('x', 'd', 'v', 'f'): /* XDCAM HD 1080p30 50Mb/s CBR */
12797 case GST_MAKE_FOURCC ('x', 'd', '5', '1'): /* XDCAM HD422 720p30 50Mb/s CBR */
12798 case GST_MAKE_FOURCC ('x', 'd', '5', '4'): /* XDCAM HD422 720p24 50Mb/s CBR */
12799 case GST_MAKE_FOURCC ('x', 'd', '5', '5'): /* XDCAM HD422 720p25 50Mb/s CBR */
12800 case GST_MAKE_FOURCC ('x', 'd', '5', '9'): /* XDCAM HD422 720p60 50Mb/s CBR */
12801 case GST_MAKE_FOURCC ('x', 'd', '5', 'a'): /* XDCAM HD422 720p50 50Mb/s CBR */
12802 case GST_MAKE_FOURCC ('x', 'd', '5', 'b'): /* XDCAM HD422 1080i50 50Mb/s CBR */
12803 case GST_MAKE_FOURCC ('x', 'd', '5', 'c'): /* XDCAM HD422 1080i50 50Mb/s CBR */
12804 case GST_MAKE_FOURCC ('x', 'd', '5', 'd'): /* XDCAM HD422 1080p24 50Mb/s CBR */
12805 case GST_MAKE_FOURCC ('x', 'd', '5', 'e'): /* XDCAM HD422 1080p25 50Mb/s CBR */
12806 case GST_MAKE_FOURCC ('x', 'd', '5', 'f'): /* XDCAM HD422 1080p30 50Mb/s CBR */
12807 case GST_MAKE_FOURCC ('x', 'd', 'h', 'd'): /* XDCAM HD 540p */
12808 case GST_MAKE_FOURCC ('x', 'd', 'h', '2'): /* XDCAM HD422 540p */
12809 case GST_MAKE_FOURCC ('A', 'V', 'm', 'p'): /* AVID IMX PAL */
12810 case GST_MAKE_FOURCC ('m', 'p', 'g', '2'): /* AVID IMX PAL */
12811 case GST_MAKE_FOURCC ('m', 'p', '2', 'v'): /* AVID IMX PAL */
12812 _codec ("MPEG-2 video");
12813 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 2,
12814 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
12816 case GST_MAKE_FOURCC ('g', 'i', 'f', ' '):
12817 _codec ("GIF still images");
12818 caps = gst_caps_new_empty_simple ("image/gif");
12821 case GST_MAKE_FOURCC ('H', '2', '6', '3'):
12823 case GST_MAKE_FOURCC ('U', '2', '6', '3'):
12825 /* ffmpeg uses the height/width props, don't know why */
12826 caps = gst_caps_new_simple ("video/x-h263",
12827 "variant", G_TYPE_STRING, "itu", NULL);
12831 _codec ("MPEG-4 video");
12832 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
12833 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
12835 case GST_MAKE_FOURCC ('3', 'i', 'v', 'd'):
12836 case GST_MAKE_FOURCC ('3', 'I', 'V', 'D'):
12837 _codec ("Microsoft MPEG-4 4.3"); /* FIXME? */
12838 caps = gst_caps_new_simple ("video/x-msmpeg",
12839 "msmpegversion", G_TYPE_INT, 43, NULL);
12841 case GST_MAKE_FOURCC ('D', 'I', 'V', '3'):
12843 caps = gst_caps_new_simple ("video/x-divx",
12844 "divxversion", G_TYPE_INT, 3, NULL);
12846 case GST_MAKE_FOURCC ('D', 'I', 'V', 'X'):
12847 case GST_MAKE_FOURCC ('d', 'i', 'v', 'x'):
12849 caps = gst_caps_new_simple ("video/x-divx",
12850 "divxversion", G_TYPE_INT, 4, NULL);
12852 case GST_MAKE_FOURCC ('D', 'X', '5', '0'):
12854 caps = gst_caps_new_simple ("video/x-divx",
12855 "divxversion", G_TYPE_INT, 5, NULL);
12858 case GST_MAKE_FOURCC ('F', 'F', 'V', '1'):
12860 caps = gst_caps_new_simple ("video/x-ffv",
12861 "ffvversion", G_TYPE_INT, 1, NULL);
12864 case GST_MAKE_FOURCC ('3', 'I', 'V', '1'):
12865 case GST_MAKE_FOURCC ('3', 'I', 'V', '2'):
12866 case GST_MAKE_FOURCC ('X', 'V', 'I', 'D'):
12867 case GST_MAKE_FOURCC ('x', 'v', 'i', 'd'):
12869 case GST_MAKE_FOURCC ('U', 'M', 'P', '4'):
12870 caps = gst_caps_new_simple ("video/mpeg",
12871 "mpegversion", G_TYPE_INT, 4, NULL);
12875 case GST_MAKE_FOURCC ('c', 'v', 'i', 'd'):
12876 _codec ("Cinepak");
12877 caps = gst_caps_new_empty_simple ("video/x-cinepak");
12879 case GST_MAKE_FOURCC ('q', 'd', 'r', 'w'):
12880 _codec ("Apple QuickDraw");
12881 caps = gst_caps_new_empty_simple ("video/x-qdrw");
12883 case GST_MAKE_FOURCC ('r', 'p', 'z', 'a'):
12884 _codec ("Apple video");
12885 caps = gst_caps_new_empty_simple ("video/x-apple-video");
12889 _codec ("H.264 / AVC");
12890 caps = gst_caps_new_simple ("video/x-h264",
12891 "stream-format", G_TYPE_STRING, "avc",
12892 "alignment", G_TYPE_STRING, "au", NULL);
12895 _codec ("H.264 / AVC");
12896 caps = gst_caps_new_simple ("video/x-h264",
12897 "stream-format", G_TYPE_STRING, "avc3",
12898 "alignment", G_TYPE_STRING, "au", NULL);
12902 _codec ("H.265 / HEVC");
12903 caps = gst_caps_new_simple ("video/x-h265",
12904 "stream-format", G_TYPE_STRING, "hvc1",
12905 "alignment", G_TYPE_STRING, "au", NULL);
12908 _codec ("H.265 / HEVC");
12909 caps = gst_caps_new_simple ("video/x-h265",
12910 "stream-format", G_TYPE_STRING, "hev1",
12911 "alignment", G_TYPE_STRING, "au", NULL);
12914 _codec ("Run-length encoding");
12915 caps = gst_caps_new_simple ("video/x-rle",
12916 "layout", G_TYPE_STRING, "quicktime", NULL);
12919 _codec ("Run-length encoding");
12920 caps = gst_caps_new_simple ("video/x-rle",
12921 "layout", G_TYPE_STRING, "microsoft", NULL);
12923 case GST_MAKE_FOURCC ('I', 'V', '3', '2'):
12924 case GST_MAKE_FOURCC ('i', 'v', '3', '2'):
12925 _codec ("Indeo Video 3");
12926 caps = gst_caps_new_simple ("video/x-indeo",
12927 "indeoversion", G_TYPE_INT, 3, NULL);
12929 case GST_MAKE_FOURCC ('I', 'V', '4', '1'):
12930 case GST_MAKE_FOURCC ('i', 'v', '4', '1'):
12931 _codec ("Intel Video 4");
12932 caps = gst_caps_new_simple ("video/x-indeo",
12933 "indeoversion", G_TYPE_INT, 4, NULL);
12937 case GST_MAKE_FOURCC ('d', 'v', 's', 'd'):
12938 case GST_MAKE_FOURCC ('D', 'V', 'S', 'D'):
12939 case GST_MAKE_FOURCC ('d', 'v', 'c', 's'):
12940 case GST_MAKE_FOURCC ('D', 'V', 'C', 'S'):
12941 case GST_MAKE_FOURCC ('d', 'v', '2', '5'):
12942 case GST_MAKE_FOURCC ('d', 'v', 'p', 'p'):
12943 _codec ("DV Video");
12944 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 25,
12945 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
12947 case FOURCC_dv5n: /* DVCPRO50 NTSC */
12948 case FOURCC_dv5p: /* DVCPRO50 PAL */
12949 _codec ("DVCPro50 Video");
12950 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 50,
12951 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
12953 case GST_MAKE_FOURCC ('d', 'v', 'h', '5'): /* DVCPRO HD 50i produced by FCP */
12954 case GST_MAKE_FOURCC ('d', 'v', 'h', '6'): /* DVCPRO HD 60i produced by FCP */
12955 _codec ("DVCProHD Video");
12956 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 100,
12957 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
12959 case GST_MAKE_FOURCC ('s', 'm', 'c', ' '):
12960 _codec ("Apple Graphics (SMC)");
12961 caps = gst_caps_new_empty_simple ("video/x-smc");
12963 case GST_MAKE_FOURCC ('V', 'P', '3', '1'):
12965 caps = gst_caps_new_empty_simple ("video/x-vp3");
12967 case GST_MAKE_FOURCC ('V', 'P', '6', 'F'):
12968 _codec ("VP6 Flash");
12969 caps = gst_caps_new_empty_simple ("video/x-vp6-flash");
12973 caps = gst_caps_new_empty_simple ("video/x-theora");
12974 /* theora uses one byte of padding in the data stream because it does not
12975 * allow 0 sized packets while theora does */
12976 stream->padding = 1;
12980 caps = gst_caps_new_empty_simple ("video/x-dirac");
12982 case GST_MAKE_FOURCC ('t', 'i', 'f', 'f'):
12983 _codec ("TIFF still images");
12984 caps = gst_caps_new_empty_simple ("image/tiff");
12986 case GST_MAKE_FOURCC ('i', 'c', 'o', 'd'):
12987 _codec ("Apple Intermediate Codec");
12988 caps = gst_caps_from_string ("video/x-apple-intermediate-codec");
12990 case GST_MAKE_FOURCC ('A', 'V', 'd', 'n'):
12991 _codec ("AVID DNxHD");
12992 caps = gst_caps_from_string ("video/x-dnxhd");
12995 _codec ("On2 VP8");
12996 caps = gst_caps_from_string ("video/x-vp8");
12999 _codec ("Apple ProRes LT");
13001 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "lt",
13005 _codec ("Apple ProRes HQ");
13007 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "hq",
13011 _codec ("Apple ProRes");
13013 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
13017 _codec ("Apple ProRes Proxy");
13019 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
13023 _codec ("Apple ProRes 4444");
13025 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
13031 caps = gst_caps_new_simple ("video/x-wmv",
13032 "wmvversion", G_TYPE_INT, 3, "format", G_TYPE_STRING, "WVC1", NULL);
13034 case GST_MAKE_FOURCC ('k', 'p', 'c', 'd'):
13037 char *s, fourstr[5];
13039 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
13040 s = g_strdup_printf ("video/x-gst-fourcc-%s", g_strstrip (fourstr));
13041 caps = gst_caps_new_empty_simple (s);
13047 if (format != GST_VIDEO_FORMAT_UNKNOWN) {
13050 gst_video_info_init (&info);
13051 gst_video_info_set_format (&info, format, stream->width, stream->height);
13053 caps = gst_video_info_to_caps (&info);
13054 *codec_name = gst_pb_utils_get_codec_description (caps);
13056 /* enable clipping for raw video streams */
13057 stream->need_clip = TRUE;
13064 qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
13065 guint32 fourcc, const guint8 * data, int len, gchar ** codec_name)
13068 const GstStructure *s;
13071 GstAudioFormat format = 0;
13074 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
13076 depth = stream->bytes_per_packet * 8;
13079 case GST_MAKE_FOURCC ('N', 'O', 'N', 'E'):
13081 /* 8-bit audio is unsigned */
13083 format = GST_AUDIO_FORMAT_U8;
13084 /* otherwise it's signed and big-endian just like 'twos' */
13086 endian = G_BIG_ENDIAN;
13093 endian = G_LITTLE_ENDIAN;
13096 format = gst_audio_format_build_integer (TRUE, endian, depth, depth);
13098 str = g_strdup_printf ("Raw %d-bit PCM audio", depth);
13102 caps = gst_caps_new_simple ("audio/x-raw",
13103 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
13104 "layout", G_TYPE_STRING, "interleaved", NULL);
13107 case GST_MAKE_FOURCC ('f', 'l', '6', '4'):
13108 _codec ("Raw 64-bit floating-point audio");
13109 caps = gst_caps_new_simple ("audio/x-raw",
13110 "format", G_TYPE_STRING, "F64BE",
13111 "layout", G_TYPE_STRING, "interleaved", NULL);
13113 case GST_MAKE_FOURCC ('f', 'l', '3', '2'):
13114 _codec ("Raw 32-bit floating-point audio");
13115 caps = gst_caps_new_simple ("audio/x-raw",
13116 "format", G_TYPE_STRING, "F32BE",
13117 "layout", G_TYPE_STRING, "interleaved", NULL);
13120 _codec ("Raw 24-bit PCM audio");
13121 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
13123 caps = gst_caps_new_simple ("audio/x-raw",
13124 "format", G_TYPE_STRING, "S24BE",
13125 "layout", G_TYPE_STRING, "interleaved", NULL);
13127 case GST_MAKE_FOURCC ('i', 'n', '3', '2'):
13128 _codec ("Raw 32-bit PCM audio");
13129 caps = gst_caps_new_simple ("audio/x-raw",
13130 "format", G_TYPE_STRING, "S32BE",
13131 "layout", G_TYPE_STRING, "interleaved", NULL);
13134 _codec ("Mu-law audio");
13135 caps = gst_caps_new_empty_simple ("audio/x-mulaw");
13138 _codec ("A-law audio");
13139 caps = gst_caps_new_empty_simple ("audio/x-alaw");
13143 _codec ("Microsoft ADPCM");
13144 /* Microsoft ADPCM-ACM code 2 */
13145 caps = gst_caps_new_simple ("audio/x-adpcm",
13146 "layout", G_TYPE_STRING, "microsoft", NULL);
13150 _codec ("DVI/IMA ADPCM");
13151 caps = gst_caps_new_simple ("audio/x-adpcm",
13152 "layout", G_TYPE_STRING, "dvi", NULL);
13156 _codec ("DVI/Intel IMA ADPCM");
13157 /* FIXME DVI/Intel IMA ADPCM/ACM code 17 */
13158 caps = gst_caps_new_simple ("audio/x-adpcm",
13159 "layout", G_TYPE_STRING, "quicktime", NULL);
13163 /* MPEG layer 3, CBR only (pre QT4.1) */
13165 _codec ("MPEG-1 layer 3");
13166 /* MPEG layer 3, CBR & VBR (QT4.1 and later) */
13167 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 3,
13168 "mpegversion", G_TYPE_INT, 1, NULL);
13171 case GST_MAKE_FOURCC ('e', 'c', '-', '3'):
13172 _codec ("EAC-3 audio");
13173 caps = gst_caps_new_simple ("audio/x-eac3",
13174 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
13175 stream->sampled = TRUE;
13177 case GST_MAKE_FOURCC ('s', 'a', 'c', '3'): // Nero Recode
13179 _codec ("AC-3 audio");
13180 caps = gst_caps_new_simple ("audio/x-ac3",
13181 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
13182 stream->sampled = TRUE;
13184 case GST_MAKE_FOURCC ('d', 't', 's', 'c'):
13185 case GST_MAKE_FOURCC ('D', 'T', 'S', ' '):
13186 _codec ("DTS audio");
13187 caps = gst_caps_new_simple ("audio/x-dts",
13188 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
13189 stream->sampled = TRUE;
13191 case GST_MAKE_FOURCC ('d', 't', 's', 'h'): // DTS-HD
13192 case GST_MAKE_FOURCC ('d', 't', 's', 'l'): // DTS-HD Lossless
13193 _codec ("DTS-HD audio");
13194 caps = gst_caps_new_simple ("audio/x-dts",
13195 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
13196 stream->sampled = TRUE;
13200 caps = gst_caps_new_simple ("audio/x-mace",
13201 "maceversion", G_TYPE_INT, 3, NULL);
13205 caps = gst_caps_new_simple ("audio/x-mace",
13206 "maceversion", G_TYPE_INT, 6, NULL);
13208 case GST_MAKE_FOURCC ('O', 'g', 'g', 'V'):
13210 caps = gst_caps_new_empty_simple ("application/ogg");
13212 case GST_MAKE_FOURCC ('d', 'v', 'c', 'a'):
13213 _codec ("DV audio");
13214 caps = gst_caps_new_empty_simple ("audio/x-dv");
13217 _codec ("MPEG-4 AAC audio");
13218 caps = gst_caps_new_simple ("audio/mpeg",
13219 "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE,
13220 "stream-format", G_TYPE_STRING, "raw", NULL);
13222 case GST_MAKE_FOURCC ('Q', 'D', 'M', 'C'):
13223 _codec ("QDesign Music");
13224 caps = gst_caps_new_empty_simple ("audio/x-qdm");
13227 _codec ("QDesign Music v.2");
13228 /* FIXME: QDesign music version 2 (no constant) */
13229 if (FALSE && data) {
13230 caps = gst_caps_new_simple ("audio/x-qdm2",
13231 "framesize", G_TYPE_INT, QT_UINT32 (data + 52),
13232 "bitrate", G_TYPE_INT, QT_UINT32 (data + 40),
13233 "blocksize", G_TYPE_INT, QT_UINT32 (data + 44), NULL);
13235 caps = gst_caps_new_empty_simple ("audio/x-qdm2");
13239 _codec ("GSM audio");
13240 caps = gst_caps_new_empty_simple ("audio/x-gsm");
13243 _codec ("AMR audio");
13244 caps = gst_caps_new_empty_simple ("audio/AMR");
13247 _codec ("AMR-WB audio");
13248 caps = gst_caps_new_empty_simple ("audio/AMR-WB");
13251 _codec ("Quicktime IMA ADPCM");
13252 caps = gst_caps_new_simple ("audio/x-adpcm",
13253 "layout", G_TYPE_STRING, "quicktime", NULL);
13256 _codec ("Apple lossless audio");
13257 caps = gst_caps_new_empty_simple ("audio/x-alac");
13259 case GST_MAKE_FOURCC ('Q', 'c', 'l', 'p'):
13260 _codec ("QualComm PureVoice");
13261 caps = gst_caps_from_string ("audio/qcelp");
13266 caps = gst_caps_new_empty_simple ("audio/x-wma");
13270 caps = gst_caps_new_empty_simple ("audio/x-opus");
13272 case GST_MAKE_FOURCC ('l', 'p', 'c', 'm'):
13277 GstAudioFormat format;
13280 FLAG_IS_FLOAT = 0x1,
13281 FLAG_IS_BIG_ENDIAN = 0x2,
13282 FLAG_IS_SIGNED = 0x4,
13283 FLAG_IS_PACKED = 0x8,
13284 FLAG_IS_ALIGNED_HIGH = 0x10,
13285 FLAG_IS_NON_INTERLEAVED = 0x20
13287 _codec ("Raw LPCM audio");
13289 if (data && len >= 56) {
13290 depth = QT_UINT32 (data + 40);
13291 flags = QT_UINT32 (data + 44);
13292 width = QT_UINT32 (data + 48) * 8 / stream->n_channels;
13294 if ((flags & FLAG_IS_FLOAT) == 0) {
13299 format = gst_audio_format_build_integer ((flags & FLAG_IS_SIGNED) ?
13300 TRUE : FALSE, (flags & FLAG_IS_BIG_ENDIAN) ?
13301 G_BIG_ENDIAN : G_LITTLE_ENDIAN, width, depth);
13302 caps = gst_caps_new_simple ("audio/x-raw",
13303 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
13304 "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
13305 "non-interleaved" : "interleaved", NULL);
13310 if (flags & FLAG_IS_BIG_ENDIAN)
13311 format = GST_AUDIO_FORMAT_F64BE;
13313 format = GST_AUDIO_FORMAT_F64LE;
13315 if (flags & FLAG_IS_BIG_ENDIAN)
13316 format = GST_AUDIO_FORMAT_F32BE;
13318 format = GST_AUDIO_FORMAT_F32LE;
13320 caps = gst_caps_new_simple ("audio/x-raw",
13321 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
13322 "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
13323 "non-interleaved" : "interleaved", NULL);
13327 case GST_MAKE_FOURCC ('q', 't', 'v', 'r'):
13331 char *s, fourstr[5];
13333 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
13334 s = g_strdup_printf ("audio/x-gst-fourcc-%s", g_strstrip (fourstr));
13335 caps = gst_caps_new_empty_simple (s);
13342 GstCaps *templ_caps =
13343 gst_static_pad_template_get_caps (&gst_qtdemux_audiosrc_template);
13344 GstCaps *intersection = gst_caps_intersect (caps, templ_caps);
13345 gst_caps_unref (caps);
13346 gst_caps_unref (templ_caps);
13347 caps = intersection;
13350 /* enable clipping for raw audio streams */
13351 s = gst_caps_get_structure (caps, 0);
13352 name = gst_structure_get_name (s);
13353 if (g_str_has_prefix (name, "audio/x-raw")) {
13354 stream->need_clip = TRUE;
13355 stream->max_buffer_size = 4096 * stream->bytes_per_frame;
13356 GST_DEBUG ("setting max buffer size to %d", stream->max_buffer_size);
13362 qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
13363 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
13367 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
13371 _codec ("DVD subtitle");
13372 caps = gst_caps_new_empty_simple ("subpicture/x-dvd");
13373 stream->need_process = TRUE;
13376 _codec ("Quicktime timed text");
13379 _codec ("3GPP timed text");
13381 caps = gst_caps_new_simple ("text/x-raw", "format", G_TYPE_STRING,
13383 /* actual text piece needs to be extracted */
13384 stream->need_process = TRUE;
13387 _codec ("XML subtitles");
13388 caps = gst_caps_new_empty_simple ("application/ttml+xml");
13392 char *s, fourstr[5];
13394 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
13395 s = g_strdup_printf ("text/x-gst-fourcc-%s", g_strstrip (fourstr));
13396 caps = gst_caps_new_empty_simple (s);
13405 qtdemux_generic_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
13406 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
13412 _codec ("MPEG 1 video");
13413 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
13414 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13424 gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux,
13425 const gchar * system_id)
13429 if (!qtdemux->protection_system_ids)
13430 qtdemux->protection_system_ids =
13431 g_ptr_array_new_with_free_func ((GDestroyNotify) g_free);
13432 /* Check whether we already have an entry for this system ID. */
13433 for (i = 0; i < qtdemux->protection_system_ids->len; ++i) {
13434 const gchar *id = g_ptr_array_index (qtdemux->protection_system_ids, i);
13435 if (g_ascii_strcasecmp (system_id, id) == 0) {
13439 GST_DEBUG_OBJECT (qtdemux, "Adding cenc protection system ID %s", system_id);
13440 g_ptr_array_add (qtdemux->protection_system_ids, g_ascii_strdown (system_id,