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 #define ABSDIFF(x, y) ( (x) > (y) ? ((x) - (y)) : ((y) - (x)) )
100 GST_DEBUG_CATEGORY (qtdemux_debug);
102 typedef struct _QtDemuxSegment QtDemuxSegment;
103 typedef struct _QtDemuxSample QtDemuxSample;
105 typedef struct _QtDemuxCencSampleSetInfo QtDemuxCencSampleSetInfo;
107 struct _QtDemuxSample
110 gint32 pts_offset; /* Add this value to timestamp to get the pts */
112 guint64 timestamp; /* DTS In mov time */
113 guint32 duration; /* In mov time */
114 gboolean keyframe; /* TRUE when this packet is a keyframe */
117 /* Macros for converting to/from timescale */
118 #define QTSTREAMTIME_TO_GSTTIME(stream, value) (gst_util_uint64_scale((value), GST_SECOND, (stream)->timescale))
119 #define GSTTIME_TO_QTSTREAMTIME(stream, value) (gst_util_uint64_scale((value), (stream)->timescale, GST_SECOND))
121 #define QTTIME_TO_GSTTIME(qtdemux, value) (gst_util_uint64_scale((value), GST_SECOND, (qtdemux)->timescale))
122 #define GSTTIME_TO_QTTIME(qtdemux, value) (gst_util_uint64_scale((value), (qtdemux)->timescale, GST_SECOND))
124 /* timestamp is the DTS */
125 #define QTSAMPLE_DTS(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp))
126 /* timestamp + offset is the PTS */
127 #define QTSAMPLE_PTS(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp + (stream)->cslg_shift + (sample)->pts_offset))
128 /* timestamp + duration - dts is the duration */
129 #define QTSAMPLE_DUR_DTS(stream, sample, dts) (QTSTREAMTIME_TO_GSTTIME ((stream), (sample)->timestamp + (sample)->duration) - (dts))
131 #define QTSAMPLE_KEYFRAME(stream,sample) ((stream)->all_keyframe || (sample)->keyframe)
134 * Quicktime has tracks and segments. A track is a continuous piece of
135 * multimedia content. The track is not always played from start to finish but
136 * instead, pieces of the track are 'cut out' and played in sequence. This is
137 * what the segments do.
139 * Inside the track we have keyframes (K) and delta frames. The track has its
140 * own timing, which starts from 0 and extends to end. The position in the track
141 * is called the media_time.
143 * The segments now describe the pieces that should be played from this track
144 * and are basically tuples of media_time/duration/rate entries. We can have
145 * multiple segments and they are all played after one another. An example:
147 * segment 1: media_time: 1 second, duration: 1 second, rate 1
148 * segment 2: media_time: 3 second, duration: 2 second, rate 2
150 * To correctly play back this track, one must play: 1 second of media starting
151 * from media_time 1 followed by 2 seconds of media starting from media_time 3
154 * Each of the segments will be played at a specific time, the first segment at
155 * time 0, the second one after the duration of the first one, etc.. Note that
156 * the time in resulting playback is not identical to the media_time of the
159 * Visually, assuming the track has 4 second of media_time:
162 * .-----------------------------------------------------------.
163 * track: | K.....K.........K........K.......K.......K...........K... |
164 * '-----------------------------------------------------------'
166 * .------------^ ^ .----------^ ^
167 * / .-------------' / .------------------'
169 * .--------------. .--------------.
170 * | segment 1 | | segment 2 |
171 * '--------------' '--------------'
173 * The challenge here is to cut out the right pieces of the track for each of
174 * the playback segments. This fortunately can easily be done with the SEGMENT
175 * events of GStreamer.
177 * For playback of segment 1, we need to provide the decoder with the keyframe
178 * (a), in the above figure, but we must instruct it only to output the decoded
179 * data between second 1 and 2. We do this with a SEGMENT event for 1 to 2, time
180 * position set to the time of the segment: 0.
182 * We then proceed to push data from keyframe (a) to frame (b). The decoder
183 * decodes but clips all before media_time 1.
185 * After finishing a segment, we push out a new SEGMENT event with the clipping
186 * boundaries of the new data.
188 * This is a good usecase for the GStreamer accumulated SEGMENT events.
191 struct _QtDemuxSegment
193 /* global time and duration, all gst time */
195 GstClockTime stop_time;
196 GstClockTime duration;
197 /* media time of trak, all gst time */
198 GstClockTime media_start;
199 GstClockTime media_stop;
201 /* Media start time in trak timescale units */
202 guint32 trak_media_start;
205 #define QTSEGMENT_IS_EMPTY(s) ((s)->media_start == GST_CLOCK_TIME_NONE)
207 /* Used with fragmented MP4 files (mfra atom) */
212 } QtDemuxRandomAccessEntry;
214 struct _QtDemuxStream
224 gboolean new_caps; /* If TRUE, caps need to be generated (by
225 * calling _configure_stream()) This happens
226 * for MSS and fragmented streams */
228 gboolean new_stream; /* signals that a stream_start is required */
229 gboolean on_keyframe; /* if this stream last pushed buffer was a
230 * keyframe. This is important to identify
231 * where to stop pushing buffers after a
232 * segment stop time */
234 /* if the stream has a redirect URI in its headers, we store it here */
241 guint64 duration; /* in timescale units */
245 gchar lang_id[4]; /* ISO 639-2T language code */
249 QtDemuxSample *samples;
250 gboolean all_keyframe; /* TRUE when all samples are keyframes (no stss) */
251 guint32 first_duration; /* duration in timescale of first sample, used for figuring out
253 guint32 n_samples_moof; /* sample count in a moof */
254 guint64 duration_moof; /* duration in timescale of a moof, used for figure out
255 * the framerate of fragmented format stream */
256 guint64 duration_last_moof;
258 guint32 offset_in_sample; /* Offset in the current sample, used for
259 * streams which have got exceedingly big
260 * sample size (such as 24s of raw audio).
261 * Only used when max_buffer_size is non-NULL */
262 guint32 max_buffer_size; /* Maximum allowed size for output buffers.
263 * Currently only set for raw audio streams*/
265 /* if we use chunks or samples */
277 /* Numerator/denominator framerate */
280 GstVideoColorimetry colorimetry;
281 guint16 bits_per_sample;
282 guint16 color_table_id;
283 GstMemory *rgb8_palette;
288 guint samples_per_packet;
289 guint samples_per_frame;
290 guint bytes_per_packet;
291 guint bytes_per_sample;
292 guint bytes_per_frame;
296 gboolean use_allocator;
297 GstAllocator *allocator;
298 GstAllocationParams params;
300 /* when a discontinuity is pending */
303 /* list of buffers to push first */
306 /* if we need to clip this buffer. This is only needed for uncompressed
310 /* buffer needs some custom processing, e.g. subtitles */
311 gboolean need_process;
313 /* current position */
314 guint32 segment_index;
315 guint32 sample_index;
316 GstClockTime time_position; /* in gst time */
317 guint64 accumulated_base;
319 /* the Gst segment we are processing out, used for clipping */
322 /* quicktime segments */
324 QtDemuxSegment *segments;
325 gboolean dummy_segment;
330 GstTagList *pending_tags;
331 gboolean send_global_tags;
333 GstEvent *pending_event;
343 gboolean chunks_are_samples; /* TRUE means treat chunks as samples */
347 GstByteReader co_chunk;
349 guint32 current_chunk;
351 guint32 samples_per_chunk;
352 guint32 stco_sample_index;
354 guint32 sample_size; /* 0 means variable sizes are stored in stsz */
357 guint32 n_samples_per_chunk;
358 guint32 stsc_chunk_index;
359 guint32 stsc_sample_index;
360 guint64 chunk_offset;
363 guint32 stts_samples;
364 guint32 n_sample_times;
365 guint32 stts_sample_index;
367 guint32 stts_duration;
369 gboolean stss_present;
370 guint32 n_sample_syncs;
373 gboolean stps_present;
374 guint32 n_sample_partial_syncs;
376 QtDemuxRandomAccessEntry *ra_entries;
379 const QtDemuxRandomAccessEntry *pending_seek;
382 gboolean ctts_present;
383 guint32 n_composition_times;
385 guint32 ctts_sample_index;
393 gboolean parsed_trex;
394 guint32 def_sample_duration;
395 guint32 def_sample_size;
396 guint32 def_sample_flags;
400 /* stereoscopic video streams */
401 GstVideoMultiviewMode multiview_mode;
402 GstVideoMultiviewFlags multiview_flags;
404 /* protected streams */
406 guint32 protection_scheme_type;
407 guint32 protection_scheme_version;
408 gpointer protection_scheme_info; /* specific to the protection scheme */
409 GQueue protection_scheme_event_queue;
412 /* Contains properties and cryptographic info for a set of samples from a
413 * track protected using Common Encryption (cenc) */
414 struct _QtDemuxCencSampleSetInfo
416 GstStructure *default_properties;
418 /* @crypto_info holds one GstStructure per sample */
419 GPtrArray *crypto_info;
423 qt_demux_state_string (enum QtDemuxState state)
426 case QTDEMUX_STATE_INITIAL:
428 case QTDEMUX_STATE_HEADER:
430 case QTDEMUX_STATE_MOVIE:
432 case QTDEMUX_STATE_BUFFER_MDAT:
433 return "<BUFFER_MDAT>";
439 static GNode *qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc);
440 static GNode *qtdemux_tree_get_child_by_type_full (GNode * node,
441 guint32 fourcc, GstByteReader * parser);
442 static GNode *qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc);
443 static GNode *qtdemux_tree_get_sibling_by_type_full (GNode * node,
444 guint32 fourcc, GstByteReader * parser);
446 static GstFlowReturn qtdemux_add_fragmented_samples (GstQTDemux * qtdemux);
448 static GstStaticPadTemplate gst_qtdemux_sink_template =
449 GST_STATIC_PAD_TEMPLATE ("sink",
452 GST_STATIC_CAPS ("video/quicktime; video/mj2; audio/x-m4a; "
456 static GstStaticPadTemplate gst_qtdemux_videosrc_template =
457 GST_STATIC_PAD_TEMPLATE ("video_%u",
460 GST_STATIC_CAPS_ANY);
462 static GstStaticPadTemplate gst_qtdemux_audiosrc_template =
463 GST_STATIC_PAD_TEMPLATE ("audio_%u",
466 GST_STATIC_CAPS_ANY);
468 static GstStaticPadTemplate gst_qtdemux_subsrc_template =
469 GST_STATIC_PAD_TEMPLATE ("subtitle_%u",
472 GST_STATIC_CAPS_ANY);
474 #define gst_qtdemux_parent_class parent_class
475 G_DEFINE_TYPE (GstQTDemux, gst_qtdemux, GST_TYPE_ELEMENT);
477 static void gst_qtdemux_dispose (GObject * object);
480 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
481 GstClockTime media_time);
483 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
484 QtDemuxStream * str, gint64 media_offset);
487 static void gst_qtdemux_set_index (GstElement * element, GstIndex * index);
488 static GstIndex *gst_qtdemux_get_index (GstElement * element);
490 static GstStateChangeReturn gst_qtdemux_change_state (GstElement * element,
491 GstStateChange transition);
492 static gboolean qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent);
493 static gboolean qtdemux_sink_activate_mode (GstPad * sinkpad,
494 GstObject * parent, GstPadMode mode, gboolean active);
496 static void gst_qtdemux_loop (GstPad * pad);
497 static GstFlowReturn gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent,
499 static gboolean gst_qtdemux_handle_sink_event (GstPad * pad, GstObject * parent,
501 static gboolean gst_qtdemux_setcaps (GstQTDemux * qtdemux, GstCaps * caps);
502 static gboolean gst_qtdemux_configure_stream (GstQTDemux * qtdemux,
503 QtDemuxStream * stream);
504 static GstFlowReturn gst_qtdemux_process_adapter (GstQTDemux * demux,
507 static gboolean qtdemux_parse_moov (GstQTDemux * qtdemux,
508 const guint8 * buffer, guint length);
509 static gboolean qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node,
510 const guint8 * buffer, guint length);
511 static gboolean qtdemux_parse_tree (GstQTDemux * qtdemux);
512 static void qtdemux_parse_udta (GstQTDemux * qtdemux, GstTagList * taglist,
515 static void gst_qtdemux_handle_esds (GstQTDemux * qtdemux,
516 QtDemuxStream * stream, GNode * esds, GstTagList * list);
517 static GstCaps *qtdemux_video_caps (GstQTDemux * qtdemux,
518 QtDemuxStream * stream, guint32 fourcc, const guint8 * stsd_data,
519 gchar ** codec_name);
520 static GstCaps *qtdemux_audio_caps (GstQTDemux * qtdemux,
521 QtDemuxStream * stream, guint32 fourcc, const guint8 * data, int len,
522 gchar ** codec_name);
523 static GstCaps *qtdemux_sub_caps (GstQTDemux * qtdemux,
524 QtDemuxStream * stream, guint32 fourcc, const guint8 * data,
525 gchar ** codec_name);
526 static GstCaps *qtdemux_generic_caps (GstQTDemux * qtdemux,
527 QtDemuxStream * stream, guint32 fourcc, const guint8 * stsd_data,
528 gchar ** codec_name);
530 static gboolean qtdemux_parse_samples (GstQTDemux * qtdemux,
531 QtDemuxStream * stream, guint32 n);
532 static GstFlowReturn qtdemux_expose_streams (GstQTDemux * qtdemux);
533 static void gst_qtdemux_stream_free (GstQTDemux * qtdemux,
534 QtDemuxStream * stream);
535 static void gst_qtdemux_stream_clear (GstQTDemux * qtdemux,
536 QtDemuxStream * stream);
537 static void gst_qtdemux_remove_stream (GstQTDemux * qtdemux, int index);
538 static GstFlowReturn qtdemux_prepare_streams (GstQTDemux * qtdemux);
539 static void qtdemux_do_allocation (GstQTDemux * qtdemux,
540 QtDemuxStream * stream);
541 static gboolean gst_qtdemux_activate_segment (GstQTDemux * qtdemux,
542 QtDemuxStream * stream, guint32 seg_idx, GstClockTime offset);
543 static gboolean gst_qtdemux_stream_update_segment (GstQTDemux * qtdemux,
544 QtDemuxStream * stream, gint seg_idx, GstClockTime offset,
545 GstClockTime * _start, GstClockTime * _stop);
546 static void gst_qtdemux_send_gap_for_segment (GstQTDemux * demux,
547 QtDemuxStream * stream, gint segment_index, GstClockTime pos);
549 static gboolean qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux);
550 static void check_update_duration (GstQTDemux * qtdemux, GstClockTime duration);
552 static gchar *qtdemux_uuid_bytes_to_string (gconstpointer uuid_bytes);
554 static GstStructure *qtdemux_get_cenc_sample_properties (GstQTDemux * qtdemux,
555 QtDemuxStream * stream, guint sample_index);
556 static void gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux,
558 static void qtdemux_gst_structure_free (GstStructure * gststructure);
561 gst_qtdemux_class_init (GstQTDemuxClass * klass)
563 GObjectClass *gobject_class;
564 GstElementClass *gstelement_class;
566 gobject_class = (GObjectClass *) klass;
567 gstelement_class = (GstElementClass *) klass;
569 parent_class = g_type_class_peek_parent (klass);
571 gobject_class->dispose = gst_qtdemux_dispose;
573 gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_qtdemux_change_state);
575 gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_qtdemux_set_index);
576 gstelement_class->get_index = GST_DEBUG_FUNCPTR (gst_qtdemux_get_index);
579 gst_tag_register_musicbrainz_tags ();
581 gst_element_class_add_static_pad_template (gstelement_class,
582 &gst_qtdemux_sink_template);
583 gst_element_class_add_static_pad_template (gstelement_class,
584 &gst_qtdemux_videosrc_template);
585 gst_element_class_add_static_pad_template (gstelement_class,
586 &gst_qtdemux_audiosrc_template);
587 gst_element_class_add_static_pad_template (gstelement_class,
588 &gst_qtdemux_subsrc_template);
589 gst_element_class_set_static_metadata (gstelement_class, "QuickTime demuxer",
591 "Demultiplex a QuickTime file into audio and video streams",
592 "David Schleef <ds@schleef.org>, Wim Taymans <wim@fluendo.com>");
594 GST_DEBUG_CATEGORY_INIT (qtdemux_debug, "qtdemux", 0, "qtdemux plugin");
599 gst_qtdemux_init (GstQTDemux * qtdemux)
602 gst_pad_new_from_static_template (&gst_qtdemux_sink_template, "sink");
603 gst_pad_set_activate_function (qtdemux->sinkpad, qtdemux_sink_activate);
604 gst_pad_set_activatemode_function (qtdemux->sinkpad,
605 qtdemux_sink_activate_mode);
606 gst_pad_set_chain_function (qtdemux->sinkpad, gst_qtdemux_chain);
607 gst_pad_set_event_function (qtdemux->sinkpad, gst_qtdemux_handle_sink_event);
608 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), qtdemux->sinkpad);
610 qtdemux->state = QTDEMUX_STATE_INITIAL;
611 qtdemux->pullbased = FALSE;
612 qtdemux->posted_redirect = FALSE;
613 qtdemux->neededbytes = 16;
615 qtdemux->adapter = gst_adapter_new ();
617 qtdemux->first_mdat = -1;
618 qtdemux->got_moov = FALSE;
619 qtdemux->mdatoffset = -1;
620 qtdemux->mdatbuffer = NULL;
621 qtdemux->restoredata_buffer = NULL;
622 qtdemux->restoredata_offset = -1;
623 qtdemux->fragment_start = -1;
624 qtdemux->fragment_start_offset = -1;
625 qtdemux->media_caps = NULL;
626 qtdemux->exposed = FALSE;
627 qtdemux->mss_mode = FALSE;
628 qtdemux->pending_newsegment = NULL;
629 qtdemux->upstream_format_is_time = FALSE;
630 qtdemux->have_group_id = FALSE;
631 qtdemux->group_id = G_MAXUINT;
632 qtdemux->cenc_aux_info_offset = 0;
633 qtdemux->cenc_aux_info_sizes = NULL;
634 qtdemux->cenc_aux_sample_count = 0;
635 qtdemux->protection_system_ids = NULL;
636 g_queue_init (&qtdemux->protection_event_queue);
637 gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
638 qtdemux->flowcombiner = gst_flow_combiner_new ();
640 GST_OBJECT_FLAG_SET (qtdemux, GST_ELEMENT_FLAG_INDEXABLE);
644 gst_qtdemux_dispose (GObject * object)
646 GstQTDemux *qtdemux = GST_QTDEMUX (object);
648 if (qtdemux->adapter) {
649 g_object_unref (G_OBJECT (qtdemux->adapter));
650 qtdemux->adapter = NULL;
652 gst_flow_combiner_free (qtdemux->flowcombiner);
653 g_queue_foreach (&qtdemux->protection_event_queue, (GFunc) gst_event_unref,
655 g_queue_clear (&qtdemux->protection_event_queue);
657 g_free (qtdemux->cenc_aux_info_sizes);
658 qtdemux->cenc_aux_info_sizes = NULL;
660 G_OBJECT_CLASS (parent_class)->dispose (object);
664 gst_qtdemux_post_no_playable_stream_error (GstQTDemux * qtdemux)
666 if (qtdemux->posted_redirect) {
667 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
668 (_("This file contains no playable streams.")),
669 ("no known streams found, a redirect message has been posted"));
671 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
672 (_("This file contains no playable streams.")),
673 ("no known streams found"));
678 _gst_buffer_new_wrapped (gpointer mem, gsize size, GFreeFunc free_func)
680 return gst_buffer_new_wrapped_full (free_func ? 0 : GST_MEMORY_FLAG_READONLY,
681 mem, size, 0, size, mem, free_func);
685 gst_qtdemux_pull_atom (GstQTDemux * qtdemux, guint64 offset, guint64 size,
692 if (G_UNLIKELY (size == 0)) {
694 GstBuffer *tmp = NULL;
696 ret = gst_qtdemux_pull_atom (qtdemux, offset, sizeof (guint32), &tmp);
697 if (ret != GST_FLOW_OK)
700 gst_buffer_map (tmp, &map, GST_MAP_READ);
701 size = QT_UINT32 (map.data);
702 GST_DEBUG_OBJECT (qtdemux, "size 0x%08" G_GINT64_MODIFIER "x", size);
704 gst_buffer_unmap (tmp, &map);
705 gst_buffer_unref (tmp);
708 /* Sanity check: catch bogus sizes (fuzzed/broken files) */
709 if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
710 if (qtdemux->state != QTDEMUX_STATE_MOVIE && qtdemux->got_moov) {
711 /* we're pulling header but already got most interesting bits,
712 * so never mind the rest (e.g. tags) (that much) */
713 GST_WARNING_OBJECT (qtdemux, "atom has bogus size %" G_GUINT64_FORMAT,
717 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
718 (_("This file is invalid and cannot be played.")),
719 ("atom has bogus size %" G_GUINT64_FORMAT, size));
720 return GST_FLOW_ERROR;
724 flow = gst_pad_pull_range (qtdemux->sinkpad, offset, size, buf);
726 if (G_UNLIKELY (flow != GST_FLOW_OK))
729 bsize = gst_buffer_get_size (*buf);
730 /* Catch short reads - we don't want any partial atoms */
731 if (G_UNLIKELY (bsize < size)) {
732 GST_WARNING_OBJECT (qtdemux,
733 "short read: %" G_GSIZE_FORMAT " < %" G_GUINT64_FORMAT, bsize, size);
734 gst_buffer_unref (*buf);
744 gst_qtdemux_src_convert (GstQTDemux * qtdemux, GstPad * pad,
745 GstFormat src_format, gint64 src_value, GstFormat dest_format,
749 QtDemuxStream *stream = gst_pad_get_element_private (pad);
752 if (stream->subtype != FOURCC_vide) {
757 switch (src_format) {
758 case GST_FORMAT_TIME:
759 switch (dest_format) {
760 case GST_FORMAT_BYTES:{
761 index = gst_qtdemux_find_index_linear (qtdemux, stream, src_value);
767 *dest_value = stream->samples[index].offset;
769 GST_DEBUG_OBJECT (qtdemux, "Format Conversion Time->Offset :%"
770 GST_TIME_FORMAT "->%" G_GUINT64_FORMAT,
771 GST_TIME_ARGS (src_value), *dest_value);
779 case GST_FORMAT_BYTES:
780 switch (dest_format) {
781 case GST_FORMAT_TIME:{
783 gst_qtdemux_find_index_for_given_media_offset_linear (qtdemux,
792 QTSTREAMTIME_TO_GSTTIME (stream,
793 stream->samples[index].timestamp);
794 GST_DEBUG_OBJECT (qtdemux,
795 "Format Conversion Offset->Time :%" G_GUINT64_FORMAT "->%"
796 GST_TIME_FORMAT, src_value, GST_TIME_ARGS (*dest_value));
815 gst_qtdemux_get_duration (GstQTDemux * qtdemux, GstClockTime * duration)
817 gboolean res = FALSE;
819 *duration = GST_CLOCK_TIME_NONE;
821 if (qtdemux->duration != 0 &&
822 qtdemux->duration != G_MAXINT64 && qtdemux->timescale != 0) {
823 *duration = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
826 *duration = GST_CLOCK_TIME_NONE;
833 gst_qtdemux_handle_src_query (GstPad * pad, GstObject * parent,
836 gboolean res = FALSE;
837 GstQTDemux *qtdemux = GST_QTDEMUX (parent);
839 GST_LOG_OBJECT (pad, "%s query", GST_QUERY_TYPE_NAME (query));
841 switch (GST_QUERY_TYPE (query)) {
842 case GST_QUERY_POSITION:{
845 gst_query_parse_position (query, &fmt, NULL);
846 if (fmt == GST_FORMAT_TIME
847 && GST_CLOCK_TIME_IS_VALID (qtdemux->segment.position)) {
848 gst_query_set_position (query, GST_FORMAT_TIME,
849 qtdemux->segment.position);
854 case GST_QUERY_DURATION:{
857 gst_query_parse_duration (query, &fmt, NULL);
858 if (fmt == GST_FORMAT_TIME) {
859 /* First try to query upstream */
860 res = gst_pad_query_default (pad, parent, query);
862 GstClockTime duration;
863 if (gst_qtdemux_get_duration (qtdemux, &duration) && duration > 0) {
864 gst_query_set_duration (query, GST_FORMAT_TIME, duration);
871 case GST_QUERY_CONVERT:{
872 GstFormat src_fmt, dest_fmt;
873 gint64 src_value, dest_value = 0;
875 gst_query_parse_convert (query, &src_fmt, &src_value, &dest_fmt, NULL);
877 res = gst_qtdemux_src_convert (qtdemux, pad,
878 src_fmt, src_value, dest_fmt, &dest_value);
880 gst_query_set_convert (query, src_fmt, src_value, dest_fmt, dest_value);
885 case GST_QUERY_FORMATS:
886 gst_query_set_formats (query, 2, GST_FORMAT_TIME, GST_FORMAT_BYTES);
889 case GST_QUERY_SEEKING:{
893 /* try upstream first */
894 res = gst_pad_query_default (pad, parent, query);
897 gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
898 if (fmt == GST_FORMAT_TIME) {
899 GstClockTime duration;
901 gst_qtdemux_get_duration (qtdemux, &duration);
903 if (!qtdemux->pullbased) {
906 /* we might be able with help from upstream */
908 q = gst_query_new_seeking (GST_FORMAT_BYTES);
909 if (gst_pad_peer_query (qtdemux->sinkpad, q)) {
910 gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL);
911 GST_LOG_OBJECT (qtdemux, "upstream BYTE seekable %d", seekable);
915 gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0, duration);
921 case GST_QUERY_SEGMENT:
926 format = qtdemux->segment.format;
929 gst_segment_to_stream_time (&qtdemux->segment, format,
930 qtdemux->segment.start);
931 if ((stop = qtdemux->segment.stop) == -1)
932 stop = qtdemux->segment.duration;
934 stop = gst_segment_to_stream_time (&qtdemux->segment, format, stop);
936 gst_query_set_segment (query, qtdemux->segment.rate, format, start, stop);
941 res = gst_pad_query_default (pad, parent, query);
949 gst_qtdemux_push_tags (GstQTDemux * qtdemux, QtDemuxStream * stream)
951 if (G_LIKELY (stream->pad)) {
952 GST_DEBUG_OBJECT (qtdemux, "Checking pad %s:%s for tags",
953 GST_DEBUG_PAD_NAME (stream->pad));
955 if (G_UNLIKELY (stream->pending_tags)) {
956 GST_DEBUG_OBJECT (qtdemux, "Sending tags %" GST_PTR_FORMAT,
957 stream->pending_tags);
958 gst_pad_push_event (stream->pad,
959 gst_event_new_tag (stream->pending_tags));
960 stream->pending_tags = NULL;
963 if (G_UNLIKELY (stream->send_global_tags && qtdemux->tag_list)) {
964 GST_DEBUG_OBJECT (qtdemux, "Sending global tags %" GST_PTR_FORMAT,
966 gst_pad_push_event (stream->pad,
967 gst_event_new_tag (gst_tag_list_ref (qtdemux->tag_list)));
968 stream->send_global_tags = FALSE;
973 /* push event on all source pads; takes ownership of the event */
975 gst_qtdemux_push_event (GstQTDemux * qtdemux, GstEvent * event)
978 gboolean has_valid_stream = FALSE;
979 GstEventType etype = GST_EVENT_TYPE (event);
981 GST_DEBUG_OBJECT (qtdemux, "pushing %s event on all source pads",
982 GST_EVENT_TYPE_NAME (event));
984 for (n = 0; n < qtdemux->n_streams; n++) {
986 QtDemuxStream *stream = qtdemux->streams[n];
987 GST_DEBUG_OBJECT (qtdemux, "pushing on pad %i", n);
989 if ((pad = stream->pad)) {
990 has_valid_stream = TRUE;
992 if (etype == GST_EVENT_EOS) {
993 /* let's not send twice */
994 if (stream->sent_eos)
996 stream->sent_eos = TRUE;
999 gst_pad_push_event (pad, gst_event_ref (event));
1003 gst_event_unref (event);
1005 /* if it is EOS and there are no pads, post an error */
1006 if (!has_valid_stream && etype == GST_EVENT_EOS) {
1007 gst_qtdemux_post_no_playable_stream_error (qtdemux);
1011 /* push a pending newsegment event, if any from the streaming thread */
1013 gst_qtdemux_push_pending_newsegment (GstQTDemux * qtdemux)
1015 if (qtdemux->pending_newsegment) {
1016 gst_qtdemux_push_event (qtdemux, qtdemux->pending_newsegment);
1017 qtdemux->pending_newsegment = NULL;
1027 find_func (QtDemuxSample * s1, gint64 * media_time, gpointer user_data)
1029 if ((gint64) s1->timestamp + s1->pts_offset > *media_time)
1031 if ((gint64) s1->timestamp + s1->pts_offset == *media_time)
1037 /* find the index of the sample that includes the data for @media_time using a
1038 * binary search. Only to be called in optimized cases of linear search below.
1040 * Returns the index of the sample.
1043 gst_qtdemux_find_index (GstQTDemux * qtdemux, QtDemuxStream * str,
1046 QtDemuxSample *result;
1049 /* convert media_time to mov format */
1051 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
1053 result = gst_util_array_binary_search (str->samples, str->stbl_index + 1,
1054 sizeof (QtDemuxSample), (GCompareDataFunc) find_func,
1055 GST_SEARCH_MODE_BEFORE, &media_time, NULL);
1057 if (G_LIKELY (result))
1058 index = result - str->samples;
1067 /* find the index of the sample that includes the data for @media_offset using a
1070 * Returns the index of the sample.
1073 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
1074 QtDemuxStream * str, gint64 media_offset)
1076 QtDemuxSample *result = str->samples;
1079 if (result == NULL || str->n_samples == 0)
1082 if (media_offset == result->offset)
1086 while (index < str->n_samples - 1) {
1087 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
1090 if (media_offset < result->offset)
1101 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
1106 /* find the index of the sample that includes the data for @media_time using a
1107 * linear search, and keeping in mind that not all samples may have been parsed
1108 * yet. If possible, it will delegate to binary search.
1110 * Returns the index of the sample.
1113 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
1114 GstClockTime media_time)
1118 QtDemuxSample *sample;
1120 /* convert media_time to mov format */
1122 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
1124 sample = str->samples;
1125 if (mov_time == sample->timestamp + sample->pts_offset)
1128 /* use faster search if requested time in already parsed range */
1129 sample = str->samples + str->stbl_index;
1130 if (str->stbl_index >= 0 &&
1131 mov_time <= (sample->timestamp + sample->pts_offset))
1132 return gst_qtdemux_find_index (qtdemux, str, media_time);
1134 while (index < str->n_samples - 1) {
1135 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
1138 sample = str->samples + index + 1;
1139 if (mov_time < (sample->timestamp + sample->pts_offset))
1149 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
1154 /* find the index of the keyframe needed to decode the sample at @index
1157 * Returns the index of the keyframe.
1160 gst_qtdemux_find_keyframe (GstQTDemux * qtdemux, QtDemuxStream * str,
1163 guint32 new_index = index;
1165 if (index >= str->n_samples) {
1166 new_index = str->n_samples;
1170 /* all keyframes, return index */
1171 if (str->all_keyframe) {
1176 /* else go back until we have a keyframe */
1178 if (str->samples[new_index].keyframe)
1188 GST_DEBUG_OBJECT (qtdemux, "searching for keyframe index before index %u "
1189 "gave %u", index, new_index);
1194 /* find the segment for @time_position for @stream
1196 * Returns the index of the segment containing @time_position.
1197 * Returns the last segment and sets the @eos variable to TRUE
1198 * if the time is beyond the end. @eos may be NULL
1201 gst_qtdemux_find_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
1202 GstClockTime time_position)
1207 GST_LOG_OBJECT (stream->pad, "finding segment for %" GST_TIME_FORMAT,
1208 GST_TIME_ARGS (time_position));
1211 for (i = 0; i < stream->n_segments; i++) {
1212 QtDemuxSegment *segment = &stream->segments[i];
1214 GST_LOG_OBJECT (stream->pad,
1215 "looking at segment %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT,
1216 GST_TIME_ARGS (segment->time), GST_TIME_ARGS (segment->stop_time));
1218 /* For the last segment we include stop_time in the last segment */
1219 if (i < stream->n_segments - 1) {
1220 if (segment->time <= time_position && time_position < segment->stop_time) {
1221 GST_LOG_OBJECT (stream->pad, "segment %d matches", i);
1226 /* Last segment always matches */
1234 /* move the stream @str to the sample position @index.
1236 * Updates @str->sample_index and marks discontinuity if needed.
1239 gst_qtdemux_move_stream (GstQTDemux * qtdemux, QtDemuxStream * str,
1242 /* no change needed */
1243 if (index == str->sample_index)
1246 GST_DEBUG_OBJECT (qtdemux, "moving to sample %u of %u", index,
1249 /* position changed, we have a discont */
1250 str->sample_index = index;
1251 str->offset_in_sample = 0;
1252 /* Each time we move in the stream we store the position where we are
1254 str->from_sample = index;
1255 str->discont = TRUE;
1259 gst_qtdemux_adjust_seek (GstQTDemux * qtdemux, gint64 desired_time,
1260 gboolean use_sparse, gint64 * key_time, gint64 * key_offset)
1263 gint64 min_byte_offset = -1;
1266 min_offset = desired_time;
1268 /* for each stream, find the index of the sample in the segment
1269 * and move back to the previous keyframe. */
1270 for (n = 0; n < qtdemux->n_streams; n++) {
1272 guint32 index, kindex;
1274 GstClockTime media_start;
1275 GstClockTime media_time;
1276 GstClockTime seg_time;
1277 QtDemuxSegment *seg;
1278 gboolean empty_segment = FALSE;
1280 str = qtdemux->streams[n];
1282 if (str->sparse && !use_sparse)
1285 seg_idx = gst_qtdemux_find_segment (qtdemux, str, desired_time);
1286 GST_DEBUG_OBJECT (qtdemux, "align segment %d", seg_idx);
1288 /* get segment and time in the segment */
1289 seg = &str->segments[seg_idx];
1290 seg_time = (desired_time - seg->time) * seg->rate;
1292 while (QTSEGMENT_IS_EMPTY (seg)) {
1294 empty_segment = TRUE;
1295 GST_DEBUG_OBJECT (str->pad, "Segment %d is empty, moving to next one",
1298 if (seg_idx == str->n_segments)
1300 seg = &str->segments[seg_idx];
1303 if (seg_idx == str->n_segments) {
1304 /* FIXME track shouldn't have the last segment as empty, but if it
1305 * happens we better handle it */
1309 /* get the media time in the segment */
1310 media_start = seg->media_start + seg_time;
1312 /* get the index of the sample with media time */
1313 index = gst_qtdemux_find_index_linear (qtdemux, str, media_start);
1314 GST_DEBUG_OBJECT (qtdemux, "sample for %" GST_TIME_FORMAT " at %u"
1315 " at offset %" G_GUINT64_FORMAT " (empty segment: %d)",
1316 GST_TIME_ARGS (media_start), index, str->samples[index].offset,
1319 if (!empty_segment) {
1320 /* find previous keyframe */
1321 kindex = gst_qtdemux_find_keyframe (qtdemux, str, index);
1323 /* if the keyframe is at a different position, we need to update the
1324 * requested seek time */
1325 if (index != kindex) {
1328 /* get timestamp of keyframe */
1329 media_time = QTSAMPLE_DTS (str, &str->samples[kindex]);
1330 GST_DEBUG_OBJECT (qtdemux,
1331 "keyframe at %u with time %" GST_TIME_FORMAT " at offset %"
1332 G_GUINT64_FORMAT, kindex, GST_TIME_ARGS (media_time),
1333 str->samples[kindex].offset);
1335 /* keyframes in the segment get a chance to change the
1336 * desired_offset. keyframes out of the segment are
1338 if (media_time >= seg->media_start) {
1339 GstClockTime seg_time;
1341 /* this keyframe is inside the segment, convert back to
1343 seg_time = (media_time - seg->media_start) + seg->time;
1344 if (seg_time < min_offset)
1345 min_offset = seg_time;
1350 if (min_byte_offset < 0 || str->samples[index].offset < min_byte_offset)
1351 min_byte_offset = str->samples[index].offset;
1355 *key_time = min_offset;
1357 *key_offset = min_byte_offset;
1361 gst_qtdemux_convert_seek (GstPad * pad, GstFormat * format,
1362 GstSeekType cur_type, gint64 * cur, GstSeekType stop_type, gint64 * stop)
1366 g_return_val_if_fail (format != NULL, FALSE);
1367 g_return_val_if_fail (cur != NULL, FALSE);
1368 g_return_val_if_fail (stop != NULL, FALSE);
1370 if (*format == GST_FORMAT_TIME)
1374 if (cur_type != GST_SEEK_TYPE_NONE)
1375 res = gst_pad_query_convert (pad, *format, *cur, GST_FORMAT_TIME, cur);
1376 if (res && stop_type != GST_SEEK_TYPE_NONE)
1377 res = gst_pad_query_convert (pad, *format, *stop, GST_FORMAT_TIME, stop);
1380 *format = GST_FORMAT_TIME;
1385 /* perform seek in push based mode:
1386 find BYTE position to move to based on time and delegate to upstream
1389 gst_qtdemux_do_push_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1394 GstSeekType cur_type, stop_type;
1395 gint64 cur, stop, key_cur;
1398 gint64 original_stop;
1401 GST_DEBUG_OBJECT (qtdemux, "doing push-based seek");
1403 gst_event_parse_seek (event, &rate, &format, &flags,
1404 &cur_type, &cur, &stop_type, &stop);
1405 seqnum = gst_event_get_seqnum (event);
1407 /* only forward streaming and seeking is possible */
1409 goto unsupported_seek;
1411 /* convert to TIME if needed and possible */
1412 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1416 /* Upstream seek in bytes will have undefined stop, but qtdemux stores
1417 * the original stop position to use when upstream pushes the new segment
1419 original_stop = stop;
1422 /* find reasonable corresponding BYTE position,
1423 * also try to mind about keyframes, since we can not go back a bit for them
1425 gst_qtdemux_adjust_seek (qtdemux, cur, FALSE, &key_cur, &byte_cur);
1430 GST_DEBUG_OBJECT (qtdemux, "Pushing BYTE seek rate %g, "
1431 "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, byte_cur,
1434 GST_OBJECT_LOCK (qtdemux);
1435 qtdemux->seek_offset = byte_cur;
1436 if (!(flags & GST_SEEK_FLAG_KEY_UNIT)) {
1437 qtdemux->push_seek_start = cur;
1439 qtdemux->push_seek_start = key_cur;
1442 if (stop_type == GST_SEEK_TYPE_NONE) {
1443 qtdemux->push_seek_stop = qtdemux->segment.stop;
1445 qtdemux->push_seek_stop = original_stop;
1447 GST_OBJECT_UNLOCK (qtdemux);
1449 /* BYTE seek event */
1450 event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type, byte_cur,
1452 gst_event_set_seqnum (event, seqnum);
1453 res = gst_pad_push_event (qtdemux->sinkpad, event);
1460 GST_DEBUG_OBJECT (qtdemux, "could not determine byte position to seek to, "
1466 GST_DEBUG_OBJECT (qtdemux, "unsupported seek, seek aborted.");
1471 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1476 /* perform the seek.
1478 * We set all segment_indexes in the streams to unknown and
1479 * adjust the time_position to the desired position. this is enough
1480 * to trigger a segment switch in the streaming thread to start
1481 * streaming from the desired position.
1483 * Keyframe seeking is a little more complicated when dealing with
1484 * segments. Ideally we want to move to the previous keyframe in
1485 * the segment but there might not be a keyframe in the segment. In
1486 * fact, none of the segments could contain a keyframe. We take a
1487 * practical approach: seek to the previous keyframe in the segment,
1488 * if there is none, seek to the beginning of the segment.
1490 * Called with STREAM_LOCK
1493 gst_qtdemux_perform_seek (GstQTDemux * qtdemux, GstSegment * segment,
1494 guint32 seqnum, GstSeekFlags flags)
1496 gint64 desired_offset;
1499 desired_offset = segment->position;
1501 GST_DEBUG_OBJECT (qtdemux, "seeking to %" GST_TIME_FORMAT,
1502 GST_TIME_ARGS (desired_offset));
1504 /* may not have enough fragmented info to do this adjustment,
1505 * and we can't scan (and probably should not) at this time with
1506 * possibly flushing upstream */
1507 if ((flags & GST_SEEK_FLAG_KEY_UNIT) && !qtdemux->fragmented) {
1510 gst_qtdemux_adjust_seek (qtdemux, desired_offset, TRUE, &min_offset, NULL);
1511 GST_DEBUG_OBJECT (qtdemux, "keyframe seek, align to %"
1512 GST_TIME_FORMAT, GST_TIME_ARGS (min_offset));
1513 desired_offset = min_offset;
1516 /* and set all streams to the final position */
1517 gst_flow_combiner_reset (qtdemux->flowcombiner);
1518 qtdemux->segment_seqnum = seqnum;
1519 for (n = 0; n < qtdemux->n_streams; n++) {
1520 QtDemuxStream *stream = qtdemux->streams[n];
1522 stream->time_position = desired_offset;
1523 stream->accumulated_base = 0;
1524 stream->sample_index = -1;
1525 stream->offset_in_sample = 0;
1526 stream->segment_index = -1;
1527 stream->sent_eos = FALSE;
1529 if (segment->flags & GST_SEEK_FLAG_FLUSH)
1530 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
1532 segment->position = desired_offset;
1533 segment->time = desired_offset;
1534 if (segment->rate >= 0) {
1535 segment->start = desired_offset;
1537 /* we stop at the end */
1538 if (segment->stop == -1)
1539 segment->stop = segment->duration;
1541 segment->stop = desired_offset;
1544 if (qtdemux->fragmented)
1545 qtdemux->fragmented_seek_pending = TRUE;
1550 /* do a seek in pull based mode */
1552 gst_qtdemux_do_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1557 GstSeekType cur_type, stop_type;
1561 GstSegment seeksegment;
1563 GstEvent *flush_event;
1566 GST_DEBUG_OBJECT (qtdemux, "doing seek with event");
1568 gst_event_parse_seek (event, &rate, &format, &flags,
1569 &cur_type, &cur, &stop_type, &stop);
1570 seqnum = gst_event_get_seqnum (event);
1572 /* we have to have a format as the segment format. Try to convert
1574 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1578 GST_DEBUG_OBJECT (qtdemux, "seek format %s", gst_format_get_name (format));
1580 GST_DEBUG_OBJECT (qtdemux, "doing seek without event");
1584 flush = flags & GST_SEEK_FLAG_FLUSH;
1586 /* stop streaming, either by flushing or by pausing the task */
1588 flush_event = gst_event_new_flush_start ();
1590 gst_event_set_seqnum (flush_event, seqnum);
1591 /* unlock upstream pull_range */
1592 gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event));
1593 /* make sure out loop function exits */
1594 gst_qtdemux_push_event (qtdemux, flush_event);
1596 /* non flushing seek, pause the task */
1597 gst_pad_pause_task (qtdemux->sinkpad);
1600 /* wait for streaming to finish */
1601 GST_PAD_STREAM_LOCK (qtdemux->sinkpad);
1603 /* copy segment, we need this because we still need the old
1604 * segment when we close the current segment. */
1605 memcpy (&seeksegment, &qtdemux->segment, sizeof (GstSegment));
1608 /* configure the segment with the seek variables */
1609 GST_DEBUG_OBJECT (qtdemux, "configuring seek");
1610 gst_segment_do_seek (&seeksegment, rate, format, flags,
1611 cur_type, cur, stop_type, stop, &update);
1614 /* now do the seek, this actually never returns FALSE */
1615 gst_qtdemux_perform_seek (qtdemux, &seeksegment, seqnum, flags);
1617 /* prepare for streaming again */
1619 flush_event = gst_event_new_flush_stop (TRUE);
1621 gst_event_set_seqnum (flush_event, seqnum);
1623 gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event));
1624 gst_qtdemux_push_event (qtdemux, flush_event);
1627 /* commit the new segment */
1628 memcpy (&qtdemux->segment, &seeksegment, sizeof (GstSegment));
1630 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
1631 GstMessage *msg = gst_message_new_segment_start (GST_OBJECT_CAST (qtdemux),
1632 qtdemux->segment.format, qtdemux->segment.position);
1634 gst_message_set_seqnum (msg, seqnum);
1635 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
1638 /* restart streaming, NEWSEGMENT will be sent from the streaming thread. */
1639 gst_pad_start_task (qtdemux->sinkpad, (GstTaskFunction) gst_qtdemux_loop,
1640 qtdemux->sinkpad, NULL);
1642 GST_PAD_STREAM_UNLOCK (qtdemux->sinkpad);
1649 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1655 qtdemux_ensure_index (GstQTDemux * qtdemux)
1659 GST_DEBUG_OBJECT (qtdemux, "collecting all metadata for all streams");
1661 /* Build complete index */
1662 for (i = 0; i < qtdemux->n_streams; i++) {
1663 QtDemuxStream *stream = qtdemux->streams[i];
1665 if (!qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1))
1673 GST_LOG_OBJECT (qtdemux,
1674 "Building complete index of stream %u for seeking failed!", i);
1680 gst_qtdemux_handle_src_event (GstPad * pad, GstObject * parent,
1683 gboolean res = TRUE;
1684 GstQTDemux *qtdemux = GST_QTDEMUX (parent);
1686 switch (GST_EVENT_TYPE (event)) {
1687 case GST_EVENT_SEEK:
1689 #ifndef GST_DISABLE_GST_DEBUG
1690 GstClockTime ts = gst_util_get_timestamp ();
1693 if (qtdemux->upstream_format_is_time && qtdemux->fragmented) {
1694 /* seek should be handled by upstream, we might need to re-download fragments */
1695 GST_DEBUG_OBJECT (qtdemux,
1696 "let upstream handle seek for fragmented playback");
1700 /* Build complete index for seeking;
1701 * if not a fragmented file at least */
1702 if (!qtdemux->fragmented)
1703 if (!qtdemux_ensure_index (qtdemux))
1705 #ifndef GST_DISABLE_GST_DEBUG
1706 ts = gst_util_get_timestamp () - ts;
1707 GST_INFO_OBJECT (qtdemux,
1708 "Time taken to parse index %" GST_TIME_FORMAT, GST_TIME_ARGS (ts));
1711 if (qtdemux->pullbased) {
1712 res = gst_qtdemux_do_seek (qtdemux, pad, event);
1713 } else if (gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (event))) {
1714 GST_DEBUG_OBJECT (qtdemux, "Upstream successfully seeked");
1716 } else if (qtdemux->state == QTDEMUX_STATE_MOVIE && qtdemux->n_streams
1717 && !qtdemux->fragmented) {
1718 res = gst_qtdemux_do_push_seek (qtdemux, pad, event);
1720 GST_DEBUG_OBJECT (qtdemux,
1721 "ignoring seek in push mode in current state");
1724 gst_event_unref (event);
1728 res = gst_pad_event_default (pad, parent, event);
1738 GST_ERROR_OBJECT (qtdemux, "Index failed");
1739 gst_event_unref (event);
1745 /* stream/index return sample that is min/max w.r.t. byte position,
1746 * time is min/max w.r.t. time of samples,
1747 * the latter need not be time of the former sample */
1749 gst_qtdemux_find_sample (GstQTDemux * qtdemux, gint64 byte_pos, gboolean fw,
1750 gboolean set, QtDemuxStream ** _stream, gint * _index, gint64 * _time)
1753 gint64 time, min_time;
1754 QtDemuxStream *stream;
1760 for (n = 0; n < qtdemux->n_streams; ++n) {
1763 gboolean set_sample;
1765 str = qtdemux->streams[n];
1772 i = str->n_samples - 1;
1776 for (; (i >= 0) && (i < str->n_samples); i += inc) {
1777 if (str->samples[i].size == 0)
1780 if (fw && (str->samples[i].offset < byte_pos))
1783 if (!fw && (str->samples[i].offset + str->samples[i].size > byte_pos))
1786 /* move stream to first available sample */
1788 gst_qtdemux_move_stream (qtdemux, str, i);
1792 /* avoid index from sparse streams since they might be far away */
1794 /* determine min/max time */
1795 time = QTSAMPLE_PTS (str, &str->samples[i]);
1796 if (min_time == -1 || (!fw && time > min_time) ||
1797 (fw && time < min_time)) {
1801 /* determine stream with leading sample, to get its position */
1803 (fw && (str->samples[i].offset < stream->samples[index].offset)) ||
1804 (!fw && (str->samples[i].offset > stream->samples[index].offset))) {
1812 /* no sample for this stream, mark eos */
1814 gst_qtdemux_move_stream (qtdemux, str, str->n_samples);
1825 static QtDemuxStream *
1826 _create_stream (void)
1828 QtDemuxStream *stream;
1830 stream = g_new0 (QtDemuxStream, 1);
1831 /* new streams always need a discont */
1832 stream->discont = TRUE;
1833 /* we enable clipping for raw audio/video streams */
1834 stream->need_clip = FALSE;
1835 stream->need_process = FALSE;
1836 stream->segment_index = -1;
1837 stream->time_position = 0;
1838 stream->sample_index = -1;
1839 stream->offset_in_sample = 0;
1840 stream->new_stream = TRUE;
1841 stream->multiview_mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
1842 stream->multiview_flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
1843 stream->protected = FALSE;
1844 stream->protection_scheme_type = 0;
1845 stream->protection_scheme_version = 0;
1846 stream->protection_scheme_info = NULL;
1847 stream->n_samples_moof = 0;
1848 stream->duration_moof = 0;
1849 stream->duration_last_moof = 0;
1850 g_queue_init (&stream->protection_scheme_event_queue);
1855 gst_qtdemux_setcaps (GstQTDemux * demux, GstCaps * caps)
1857 GstStructure *structure;
1858 const gchar *variant;
1859 const GstCaps *mediacaps = NULL;
1861 GST_DEBUG_OBJECT (demux, "Sink set caps: %" GST_PTR_FORMAT, caps);
1863 structure = gst_caps_get_structure (caps, 0);
1864 variant = gst_structure_get_string (structure, "variant");
1866 if (variant && strcmp (variant, "mss-fragmented") == 0) {
1867 QtDemuxStream *stream;
1868 const GValue *value;
1870 demux->fragmented = TRUE;
1871 demux->mss_mode = TRUE;
1873 if (demux->n_streams > 1) {
1874 /* can't do this, we can only renegotiate for another mss format */
1878 value = gst_structure_get_value (structure, "media-caps");
1881 const GValue *timescale_v;
1883 /* TODO update when stream changes during playback */
1885 if (demux->n_streams == 0) {
1886 stream = _create_stream ();
1887 demux->streams[demux->n_streams] = stream;
1888 demux->n_streams = 1;
1890 stream = demux->streams[0];
1893 timescale_v = gst_structure_get_value (structure, "timescale");
1895 stream->timescale = g_value_get_uint64 (timescale_v);
1897 /* default mss timescale */
1898 stream->timescale = 10000000;
1900 demux->timescale = stream->timescale;
1902 mediacaps = gst_value_get_caps (value);
1903 if (!stream->caps || !gst_caps_is_equal_fixed (mediacaps, stream->caps)) {
1904 GST_DEBUG_OBJECT (demux, "We have a new caps %" GST_PTR_FORMAT,
1906 stream->new_caps = TRUE;
1908 gst_caps_replace (&stream->caps, (GstCaps *) mediacaps);
1909 structure = gst_caps_get_structure (mediacaps, 0);
1910 if (g_str_has_prefix (gst_structure_get_name (structure), "video")) {
1911 stream->subtype = FOURCC_vide;
1913 gst_structure_get_int (structure, "width", &stream->width);
1914 gst_structure_get_int (structure, "height", &stream->height);
1915 gst_structure_get_fraction (structure, "framerate", &stream->fps_n,
1917 } else if (g_str_has_prefix (gst_structure_get_name (structure), "audio")) {
1919 stream->subtype = FOURCC_soun;
1920 gst_structure_get_int (structure, "channels", &stream->n_channels);
1921 gst_structure_get_int (structure, "rate", &rate);
1922 stream->rate = rate;
1925 gst_caps_replace (&demux->media_caps, (GstCaps *) mediacaps);
1927 demux->mss_mode = FALSE;
1934 gst_qtdemux_reset (GstQTDemux * qtdemux, gboolean hard)
1938 GST_DEBUG_OBJECT (qtdemux, "Resetting demux");
1939 gst_pad_stop_task (qtdemux->sinkpad);
1941 if (hard || qtdemux->upstream_format_is_time) {
1942 qtdemux->state = QTDEMUX_STATE_INITIAL;
1943 qtdemux->neededbytes = 16;
1944 qtdemux->todrop = 0;
1945 qtdemux->pullbased = FALSE;
1946 qtdemux->posted_redirect = FALSE;
1947 qtdemux->first_mdat = -1;
1948 qtdemux->header_size = 0;
1949 qtdemux->mdatoffset = -1;
1950 qtdemux->restoredata_offset = -1;
1951 if (qtdemux->mdatbuffer)
1952 gst_buffer_unref (qtdemux->mdatbuffer);
1953 if (qtdemux->restoredata_buffer)
1954 gst_buffer_unref (qtdemux->restoredata_buffer);
1955 qtdemux->mdatbuffer = NULL;
1956 qtdemux->restoredata_buffer = NULL;
1957 qtdemux->mdatleft = 0;
1958 if (qtdemux->comp_brands)
1959 gst_buffer_unref (qtdemux->comp_brands);
1960 qtdemux->comp_brands = NULL;
1961 qtdemux->last_moov_offset = -1;
1962 if (qtdemux->moov_node)
1963 g_node_destroy (qtdemux->moov_node);
1964 qtdemux->moov_node = NULL;
1965 qtdemux->moov_node_compressed = NULL;
1966 if (qtdemux->tag_list)
1967 gst_mini_object_unref (GST_MINI_OBJECT_CAST (qtdemux->tag_list));
1968 qtdemux->tag_list = NULL;
1970 if (qtdemux->element_index)
1971 gst_object_unref (qtdemux->element_index);
1972 qtdemux->element_index = NULL;
1974 qtdemux->major_brand = 0;
1975 if (qtdemux->pending_newsegment)
1976 gst_event_unref (qtdemux->pending_newsegment);
1977 qtdemux->pending_newsegment = NULL;
1978 qtdemux->upstream_format_is_time = FALSE;
1979 qtdemux->upstream_seekable = FALSE;
1980 qtdemux->upstream_size = 0;
1982 qtdemux->fragment_start = -1;
1983 qtdemux->fragment_start_offset = -1;
1984 qtdemux->duration = 0;
1985 qtdemux->moof_offset = 0;
1986 qtdemux->chapters_track_id = 0;
1987 qtdemux->have_group_id = FALSE;
1988 qtdemux->group_id = G_MAXUINT;
1990 g_queue_foreach (&qtdemux->protection_event_queue, (GFunc) gst_event_unref,
1992 g_queue_clear (&qtdemux->protection_event_queue);
1994 qtdemux->offset = 0;
1995 gst_adapter_clear (qtdemux->adapter);
1996 gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
1997 qtdemux->segment_seqnum = 0;
2000 for (n = 0; n < qtdemux->n_streams; n++) {
2001 gst_qtdemux_stream_free (qtdemux, qtdemux->streams[n]);
2002 qtdemux->streams[n] = NULL;
2004 qtdemux->n_streams = 0;
2005 qtdemux->n_video_streams = 0;
2006 qtdemux->n_audio_streams = 0;
2007 qtdemux->n_sub_streams = 0;
2008 qtdemux->exposed = FALSE;
2009 qtdemux->fragmented = FALSE;
2010 qtdemux->mss_mode = FALSE;
2011 gst_caps_replace (&qtdemux->media_caps, NULL);
2012 qtdemux->timescale = 0;
2013 qtdemux->got_moov = FALSE;
2014 if (qtdemux->protection_system_ids) {
2015 g_ptr_array_free (qtdemux->protection_system_ids, TRUE);
2016 qtdemux->protection_system_ids = NULL;
2018 } else if (qtdemux->mss_mode) {
2019 gst_flow_combiner_reset (qtdemux->flowcombiner);
2020 for (n = 0; n < qtdemux->n_streams; n++)
2021 gst_qtdemux_stream_clear (qtdemux, qtdemux->streams[n]);
2023 gst_flow_combiner_reset (qtdemux->flowcombiner);
2024 for (n = 0; n < qtdemux->n_streams; n++) {
2025 qtdemux->streams[n]->sent_eos = FALSE;
2026 qtdemux->streams[n]->time_position = 0;
2027 qtdemux->streams[n]->accumulated_base = 0;
2029 if (!qtdemux->pending_newsegment) {
2030 qtdemux->pending_newsegment = gst_event_new_segment (&qtdemux->segment);
2031 if (qtdemux->segment_seqnum)
2032 gst_event_set_seqnum (qtdemux->pending_newsegment,
2033 qtdemux->segment_seqnum);
2039 /* Maps the @segment to the qt edts internal segments and pushes
2040 * the correspnding segment event.
2042 * If it ends up being at a empty segment, a gap will be pushed and the next
2043 * edts segment will be activated in sequence.
2045 * To be used in push-mode only */
2047 gst_qtdemux_map_and_push_segments (GstQTDemux * qtdemux, GstSegment * segment)
2051 for (n = 0; n < qtdemux->n_streams; n++) {
2052 QtDemuxStream *stream = qtdemux->streams[n];
2054 stream->time_position = segment->start;
2056 /* in push mode we should be guaranteed that we will have empty segments
2057 * at the beginning and then one segment after, other scenarios are not
2058 * supported and are discarded when parsing the edts */
2059 for (i = 0; i < stream->n_segments; i++) {
2060 if (stream->segments[i].stop_time > segment->start) {
2061 gst_qtdemux_activate_segment (qtdemux, stream, i,
2062 stream->time_position);
2063 if (QTSEGMENT_IS_EMPTY (&stream->segments[i])) {
2064 /* push the empty segment and move to the next one */
2065 gst_qtdemux_send_gap_for_segment (qtdemux, stream, i,
2066 stream->time_position);
2070 g_assert (i == stream->n_segments - 1);
2077 gst_qtdemux_handle_sink_event (GstPad * sinkpad, GstObject * parent,
2080 GstQTDemux *demux = GST_QTDEMUX (parent);
2081 gboolean res = TRUE;
2083 GST_LOG_OBJECT (demux, "handling %s event", GST_EVENT_TYPE_NAME (event));
2085 switch (GST_EVENT_TYPE (event)) {
2086 case GST_EVENT_SEGMENT:
2089 QtDemuxStream *stream;
2093 /* some debug output */
2094 gst_event_copy_segment (event, &segment);
2095 GST_DEBUG_OBJECT (demux, "received newsegment %" GST_SEGMENT_FORMAT,
2098 /* erase any previously set segment */
2099 gst_event_replace (&demux->pending_newsegment, NULL);
2101 if (segment.format == GST_FORMAT_TIME) {
2102 GST_DEBUG_OBJECT (demux, "new pending_newsegment");
2103 gst_event_replace (&demux->pending_newsegment, event);
2104 demux->upstream_format_is_time = TRUE;
2106 GST_DEBUG_OBJECT (demux, "Not storing upstream newsegment, "
2107 "not in time format");
2109 /* chain will send initial newsegment after pads have been added */
2110 if (demux->state != QTDEMUX_STATE_MOVIE || !demux->n_streams) {
2111 GST_DEBUG_OBJECT (demux, "still starting, eating event");
2116 /* check if this matches a time seek we received previously
2117 * FIXME for backwards compatibility reasons we use the
2118 * seek_offset here to compare. In the future we might want to
2119 * change this to use the seqnum as it uniquely should identify
2120 * the segment that corresponds to the seek. */
2121 GST_DEBUG_OBJECT (demux, "Stored seek offset: %" G_GINT64_FORMAT
2122 ", received segment offset %" G_GINT64_FORMAT,
2123 demux->seek_offset, segment.start);
2124 if (segment.format == GST_FORMAT_BYTES
2125 && demux->seek_offset == segment.start) {
2126 GST_OBJECT_LOCK (demux);
2127 offset = segment.start;
2129 segment.format = GST_FORMAT_TIME;
2130 segment.start = demux->push_seek_start;
2131 segment.stop = demux->push_seek_stop;
2132 GST_DEBUG_OBJECT (demux, "Replaced segment with stored seek "
2133 "segment %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT,
2134 GST_TIME_ARGS (segment.start), GST_TIME_ARGS (segment.stop));
2135 GST_OBJECT_UNLOCK (demux);
2138 /* we only expect a BYTE segment, e.g. following a seek */
2139 if (segment.format == GST_FORMAT_BYTES) {
2140 if (GST_CLOCK_TIME_IS_VALID (segment.start)) {
2141 offset = segment.start;
2143 gst_qtdemux_find_sample (demux, segment.start, TRUE, FALSE, NULL,
2144 NULL, (gint64 *) & segment.start);
2145 if ((gint64) segment.start < 0)
2148 if (GST_CLOCK_TIME_IS_VALID (segment.stop)) {
2149 gst_qtdemux_find_sample (demux, segment.stop, FALSE, FALSE, NULL,
2150 NULL, (gint64 *) & segment.stop);
2151 /* keyframe seeking should already arrange for start >= stop,
2152 * but make sure in other rare cases */
2153 segment.stop = MAX (segment.stop, segment.start);
2155 } else if (segment.format == GST_FORMAT_TIME) {
2156 /* push all data on the adapter before starting this
2158 gst_qtdemux_process_adapter (demux, TRUE);
2160 GST_DEBUG_OBJECT (demux, "unsupported segment format, ignoring");
2164 /* We shouldn't modify upstream driven TIME FORMAT segment */
2165 if (!demux->upstream_format_is_time) {
2166 /* accept upstream's notion of segment and distribute along */
2167 segment.format = GST_FORMAT_TIME;
2168 segment.position = segment.time = segment.start;
2169 segment.duration = demux->segment.duration;
2170 segment.base = gst_segment_to_running_time (&demux->segment,
2171 GST_FORMAT_TIME, demux->segment.position);
2174 gst_segment_copy_into (&segment, &demux->segment);
2175 GST_DEBUG_OBJECT (demux, "Pushing newseg %" GST_SEGMENT_FORMAT, &segment);
2177 /* map segment to internal qt segments and push on each stream */
2178 if (demux->n_streams) {
2179 if (demux->fragmented) {
2180 GstEvent *segment_event = gst_event_new_segment (&segment);
2182 gst_event_replace (&demux->pending_newsegment, NULL);
2183 gst_event_set_seqnum (segment_event, demux->segment_seqnum);
2184 gst_qtdemux_push_event (demux, segment_event);
2186 gst_event_replace (&demux->pending_newsegment, NULL);
2187 gst_qtdemux_map_and_push_segments (demux, &segment);
2191 /* clear leftover in current segment, if any */
2192 gst_adapter_clear (demux->adapter);
2194 /* set up streaming thread */
2195 demux->offset = offset;
2196 if (demux->upstream_format_is_time) {
2197 GST_DEBUG_OBJECT (demux, "Upstream is driving in time format, "
2198 "set values to restart reading from a new atom");
2199 demux->neededbytes = 16;
2202 gst_qtdemux_find_sample (demux, offset, TRUE, TRUE, &stream, &idx,
2205 demux->todrop = stream->samples[idx].offset - offset;
2206 demux->neededbytes = demux->todrop + stream->samples[idx].size;
2208 /* set up for EOS */
2209 demux->neededbytes = -1;
2214 gst_event_unref (event);
2218 case GST_EVENT_FLUSH_START:
2220 if (gst_event_get_seqnum (event) == demux->offset_seek_seqnum) {
2221 gst_event_unref (event);
2226 case GST_EVENT_FLUSH_STOP:
2230 dur = demux->segment.duration;
2231 gst_qtdemux_reset (demux, FALSE);
2232 demux->segment.duration = dur;
2234 if (gst_event_get_seqnum (event) == demux->offset_seek_seqnum) {
2235 gst_event_unref (event);
2241 /* If we are in push mode, and get an EOS before we've seen any streams,
2242 * then error out - we have nowhere to send the EOS */
2243 if (!demux->pullbased) {
2245 gboolean has_valid_stream = FALSE;
2246 for (i = 0; i < demux->n_streams; i++) {
2247 if (demux->streams[i]->pad != NULL) {
2248 has_valid_stream = TRUE;
2252 if (!has_valid_stream)
2253 gst_qtdemux_post_no_playable_stream_error (demux);
2255 GST_DEBUG_OBJECT (demux, "Data still available after EOS: %u",
2256 (guint) gst_adapter_available (demux->adapter));
2257 if (gst_qtdemux_process_adapter (demux, TRUE) != GST_FLOW_OK) {
2263 case GST_EVENT_CAPS:{
2264 GstCaps *caps = NULL;
2266 gst_event_parse_caps (event, &caps);
2267 gst_qtdemux_setcaps (demux, caps);
2269 gst_event_unref (event);
2272 case GST_EVENT_PROTECTION:
2274 const gchar *system_id = NULL;
2276 gst_event_parse_protection (event, &system_id, NULL, NULL);
2277 GST_DEBUG_OBJECT (demux, "Received protection event for system ID %s",
2279 gst_qtdemux_append_protection_system_id (demux, system_id);
2280 /* save the event for later, for source pads that have not been created */
2281 g_queue_push_tail (&demux->protection_event_queue, gst_event_ref (event));
2282 /* send it to all pads that already exist */
2283 gst_qtdemux_push_event (demux, event);
2291 res = gst_pad_event_default (demux->sinkpad, parent, event) & res;
2299 gst_qtdemux_set_index (GstElement * element, GstIndex * index)
2301 GstQTDemux *demux = GST_QTDEMUX (element);
2303 GST_OBJECT_LOCK (demux);
2304 if (demux->element_index)
2305 gst_object_unref (demux->element_index);
2307 demux->element_index = gst_object_ref (index);
2309 demux->element_index = NULL;
2311 GST_OBJECT_UNLOCK (demux);
2312 /* object lock might be taken again */
2314 gst_index_get_writer_id (index, GST_OBJECT (element), &demux->index_id);
2315 GST_DEBUG_OBJECT (demux, "Set index %" GST_PTR_FORMAT "for writer id %d",
2316 demux->element_index, demux->index_id);
2320 gst_qtdemux_get_index (GstElement * element)
2322 GstIndex *result = NULL;
2323 GstQTDemux *demux = GST_QTDEMUX (element);
2325 GST_OBJECT_LOCK (demux);
2326 if (demux->element_index)
2327 result = gst_object_ref (demux->element_index);
2328 GST_OBJECT_UNLOCK (demux);
2330 GST_DEBUG_OBJECT (demux, "Returning index %" GST_PTR_FORMAT, result);
2337 gst_qtdemux_stbl_free (QtDemuxStream * stream)
2339 g_free ((gpointer) stream->stco.data);
2340 stream->stco.data = NULL;
2341 g_free ((gpointer) stream->stsz.data);
2342 stream->stsz.data = NULL;
2343 g_free ((gpointer) stream->stsc.data);
2344 stream->stsc.data = NULL;
2345 g_free ((gpointer) stream->stts.data);
2346 stream->stts.data = NULL;
2347 g_free ((gpointer) stream->stss.data);
2348 stream->stss.data = NULL;
2349 g_free ((gpointer) stream->stps.data);
2350 stream->stps.data = NULL;
2351 g_free ((gpointer) stream->ctts.data);
2352 stream->ctts.data = NULL;
2356 gst_qtdemux_stream_flush_segments_data (GstQTDemux * qtdemux,
2357 QtDemuxStream * stream)
2359 g_free (stream->segments);
2360 stream->segments = NULL;
2361 stream->segment_index = -1;
2362 stream->accumulated_base = 0;
2366 gst_qtdemux_stream_flush_samples_data (GstQTDemux * qtdemux,
2367 QtDemuxStream * stream)
2369 g_free (stream->samples);
2370 stream->samples = NULL;
2371 gst_qtdemux_stbl_free (stream);
2374 g_free (stream->ra_entries);
2375 stream->ra_entries = NULL;
2376 stream->n_ra_entries = 0;
2378 stream->sample_index = -1;
2379 stream->stbl_index = -1;
2380 stream->n_samples = 0;
2381 stream->time_position = 0;
2383 stream->n_samples_moof = 0;
2384 stream->duration_moof = 0;
2385 stream->duration_last_moof = 0;
2389 gst_qtdemux_stream_clear (GstQTDemux * qtdemux, QtDemuxStream * stream)
2391 if (stream->allocator)
2392 gst_object_unref (stream->allocator);
2393 while (stream->buffers) {
2394 gst_buffer_unref (GST_BUFFER_CAST (stream->buffers->data));
2395 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
2397 if (stream->rgb8_palette) {
2398 gst_memory_unref (stream->rgb8_palette);
2399 stream->rgb8_palette = NULL;
2402 if (stream->pending_tags)
2403 gst_tag_list_unref (stream->pending_tags);
2404 stream->pending_tags = NULL;
2405 g_free (stream->redirect_uri);
2406 stream->redirect_uri = NULL;
2407 stream->sent_eos = FALSE;
2408 stream->sparse = FALSE;
2409 stream->protected = FALSE;
2410 if (stream->protection_scheme_info) {
2411 if (stream->protection_scheme_type == FOURCC_cenc) {
2412 QtDemuxCencSampleSetInfo *info =
2413 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
2414 if (info->default_properties)
2415 gst_structure_free (info->default_properties);
2416 if (info->crypto_info)
2417 g_ptr_array_free (info->crypto_info, TRUE);
2419 g_free (stream->protection_scheme_info);
2420 stream->protection_scheme_info = NULL;
2422 stream->protection_scheme_type = 0;
2423 stream->protection_scheme_version = 0;
2424 g_queue_foreach (&stream->protection_scheme_event_queue,
2425 (GFunc) gst_event_unref, NULL);
2426 g_queue_clear (&stream->protection_scheme_event_queue);
2427 gst_qtdemux_stream_flush_segments_data (qtdemux, stream);
2428 gst_qtdemux_stream_flush_samples_data (qtdemux, stream);
2432 gst_qtdemux_stream_free (GstQTDemux * qtdemux, QtDemuxStream * stream)
2434 gst_qtdemux_stream_clear (qtdemux, stream);
2436 gst_caps_unref (stream->caps);
2437 stream->caps = NULL;
2439 gst_element_remove_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
2440 gst_flow_combiner_remove_pad (qtdemux->flowcombiner, stream->pad);
2446 gst_qtdemux_remove_stream (GstQTDemux * qtdemux, int i)
2448 g_assert (i >= 0 && i < qtdemux->n_streams && qtdemux->streams[i] != NULL);
2450 gst_qtdemux_stream_free (qtdemux, qtdemux->streams[i]);
2451 qtdemux->streams[i] = qtdemux->streams[qtdemux->n_streams - 1];
2452 qtdemux->streams[qtdemux->n_streams - 1] = NULL;
2453 qtdemux->n_streams--;
2456 static GstStateChangeReturn
2457 gst_qtdemux_change_state (GstElement * element, GstStateChange transition)
2459 GstQTDemux *qtdemux = GST_QTDEMUX (element);
2460 GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
2462 switch (transition) {
2463 case GST_STATE_CHANGE_PAUSED_TO_READY:
2469 result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
2471 switch (transition) {
2472 case GST_STATE_CHANGE_PAUSED_TO_READY:{
2473 gst_qtdemux_reset (qtdemux, TRUE);
2484 qtdemux_parse_ftyp (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2486 /* counts as header data */
2487 qtdemux->header_size += length;
2489 /* only consider at least a sufficiently complete ftyp atom */
2493 qtdemux->major_brand = QT_FOURCC (buffer + 8);
2494 GST_DEBUG_OBJECT (qtdemux, "major brand: %" GST_FOURCC_FORMAT,
2495 GST_FOURCC_ARGS (qtdemux->major_brand));
2496 if (qtdemux->comp_brands)
2497 gst_buffer_unref (qtdemux->comp_brands);
2498 buf = qtdemux->comp_brands = gst_buffer_new_and_alloc (length - 16);
2499 gst_buffer_fill (buf, 0, buffer + 16, length - 16);
2504 qtdemux_handle_xmp_taglist (GstQTDemux * qtdemux, GstTagList * taglist,
2505 GstTagList * xmptaglist)
2507 /* Strip out bogus fields */
2509 if (gst_tag_list_get_scope (taglist) == GST_TAG_SCOPE_GLOBAL) {
2510 gst_tag_list_remove_tag (xmptaglist, GST_TAG_VIDEO_CODEC);
2511 gst_tag_list_remove_tag (xmptaglist, GST_TAG_AUDIO_CODEC);
2513 gst_tag_list_remove_tag (xmptaglist, GST_TAG_CONTAINER_FORMAT);
2516 GST_DEBUG_OBJECT (qtdemux, "Found XMP tags %" GST_PTR_FORMAT, xmptaglist);
2518 /* prioritize native tags using _KEEP mode */
2519 gst_tag_list_insert (taglist, xmptaglist, GST_TAG_MERGE_KEEP);
2520 gst_tag_list_unref (xmptaglist);
2525 qtdemux_parse_piff (GstQTDemux * qtdemux, const guint8 * buffer, gint length,
2533 QtDemuxStream *stream;
2534 GstStructure *structure;
2535 QtDemuxCencSampleSetInfo *ss_info = NULL;
2536 const gchar *system_id;
2537 gboolean uses_sub_sample_encryption = FALSE;
2539 if (qtdemux->n_streams == 0)
2542 stream = qtdemux->streams[0];
2544 structure = gst_caps_get_structure (stream->caps, 0);
2545 if (!gst_structure_has_name (structure, "application/x-cenc")) {
2546 GST_WARNING_OBJECT (qtdemux,
2547 "Attempting PIFF box parsing on an unencrypted stream.");
2551 gst_structure_get (structure, GST_PROTECTION_SYSTEM_ID_CAPS_FIELD,
2552 G_TYPE_STRING, &system_id, NULL);
2553 gst_qtdemux_append_protection_system_id (qtdemux, system_id);
2555 stream->protected = TRUE;
2556 stream->protection_scheme_type = FOURCC_cenc;
2558 if (!stream->protection_scheme_info)
2559 stream->protection_scheme_info = g_new0 (QtDemuxCencSampleSetInfo, 1);
2561 ss_info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
2563 if (ss_info->default_properties)
2564 gst_structure_free (ss_info->default_properties);
2566 ss_info->default_properties =
2567 gst_structure_new ("application/x-cenc",
2568 "iv_size", G_TYPE_UINT, iv_size, "encrypted", G_TYPE_BOOLEAN, TRUE, NULL);
2570 if (ss_info->crypto_info) {
2571 GST_LOG_OBJECT (qtdemux, "unreffing existing crypto_info");
2572 g_ptr_array_free (ss_info->crypto_info, TRUE);
2573 ss_info->crypto_info = NULL;
2577 gst_byte_reader_init (&br, buffer + offset + 16, length - offset - 16);
2579 if (!gst_byte_reader_get_uint8 (&br, &version)) {
2580 GST_ERROR_OBJECT (qtdemux, "Error getting box's version field");
2584 if (!gst_byte_reader_get_uint24_be (&br, &flags)) {
2585 GST_ERROR_OBJECT (qtdemux, "Error getting box's flags field");
2589 if ((flags & 0x000001)) {
2590 guint32 algorithm_id = 0;
2593 gboolean is_encrypted = TRUE;
2595 if (!gst_byte_reader_get_uint24_le (&br, &algorithm_id)) {
2596 GST_ERROR_OBJECT (qtdemux, "Error getting box's algorithm ID field");
2601 if (algorithm_id == 0) {
2602 is_encrypted = FALSE;
2603 } else if (algorithm_id == 1) {
2604 /* FIXME: maybe store this in properties? */
2605 GST_DEBUG_OBJECT (qtdemux, "AES 128-bits CTR encrypted stream");
2606 } else if (algorithm_id == 2) {
2607 /* FIXME: maybe store this in properties? */
2608 GST_DEBUG_OBJECT (qtdemux, "AES 128-bits CBC encrypted stream");
2611 if (!gst_byte_reader_get_uint8 (&br, &iv_size))
2614 if (!gst_byte_reader_get_data (&br, 16, &kid))
2617 kid_buf = gst_buffer_new_allocate (NULL, 16, NULL);
2618 gst_buffer_fill (kid_buf, 0, kid, 16);
2619 if (ss_info->default_properties)
2620 gst_structure_free (ss_info->default_properties);
2621 ss_info->default_properties =
2622 gst_structure_new ("application/x-cenc",
2623 "iv_size", G_TYPE_UINT, iv_size,
2624 "encrypted", G_TYPE_BOOLEAN, is_encrypted,
2625 "kid", GST_TYPE_BUFFER, kid_buf, NULL);
2626 GST_DEBUG_OBJECT (qtdemux, "default sample properties: "
2627 "is_encrypted=%u, iv_size=%u", is_encrypted, iv_size);
2628 gst_buffer_unref (kid_buf);
2629 } else if ((flags & 0x000002)) {
2630 uses_sub_sample_encryption = TRUE;
2633 if (!gst_byte_reader_get_uint32_be (&br, &qtdemux->cenc_aux_sample_count)) {
2634 GST_ERROR_OBJECT (qtdemux, "Error getting box's sample count field");
2638 ss_info->crypto_info =
2639 g_ptr_array_new_full (qtdemux->cenc_aux_sample_count,
2640 (GDestroyNotify) qtdemux_gst_structure_free);
2642 for (i = 0; i < qtdemux->cenc_aux_sample_count; ++i) {
2643 GstStructure *properties;
2647 properties = qtdemux_get_cenc_sample_properties (qtdemux, stream, i);
2648 if (properties == NULL) {
2649 GST_ERROR_OBJECT (qtdemux, "failed to get properties for sample %u", i);
2653 if (!gst_byte_reader_dup_data (&br, iv_size, &data)) {
2654 GST_ERROR_OBJECT (qtdemux, "IV data not present for sample %u", i);
2655 gst_structure_free (properties);
2658 buf = gst_buffer_new_wrapped (data, iv_size);
2659 gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL);
2660 gst_buffer_unref (buf);
2662 if (uses_sub_sample_encryption) {
2663 guint16 n_subsamples;
2665 if (!gst_byte_reader_get_uint16_be (&br, &n_subsamples)
2666 || n_subsamples == 0) {
2667 GST_ERROR_OBJECT (qtdemux,
2668 "failed to get subsample count for sample %u", i);
2669 gst_structure_free (properties);
2672 GST_LOG_OBJECT (qtdemux, "subsample count: %u", n_subsamples);
2673 if (!gst_byte_reader_dup_data (&br, n_subsamples * 6, &data)) {
2674 GST_ERROR_OBJECT (qtdemux, "failed to get subsample data for sample %u",
2676 gst_structure_free (properties);
2679 buf = gst_buffer_new_wrapped (data, n_subsamples * 6);
2680 gst_structure_set (properties,
2681 "subsample_count", G_TYPE_UINT, n_subsamples,
2682 "subsamples", GST_TYPE_BUFFER, buf, NULL);
2683 gst_buffer_unref (buf);
2685 gst_structure_set (properties, "subsample_count", G_TYPE_UINT, 0, NULL);
2688 g_ptr_array_add (ss_info->crypto_info, properties);
2693 qtdemux_parse_uuid (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2695 static const guint8 xmp_uuid[] = { 0xBE, 0x7A, 0xCF, 0xCB,
2696 0x97, 0xA9, 0x42, 0xE8,
2697 0x9C, 0x71, 0x99, 0x94,
2698 0x91, 0xE3, 0xAF, 0xAC
2700 static const guint8 playready_uuid[] = {
2701 0xd0, 0x8a, 0x4f, 0x18, 0x10, 0xf3, 0x4a, 0x82,
2702 0xb6, 0xc8, 0x32, 0xd8, 0xab, 0xa1, 0x83, 0xd3
2705 static const guint8 piff_sample_encryption_uuid[] = {
2706 0xa2, 0x39, 0x4f, 0x52, 0x5a, 0x9b, 0x4f, 0x14,
2707 0xa2, 0x44, 0x6c, 0x42, 0x7c, 0x64, 0x8d, 0xf4
2712 /* counts as header data */
2713 qtdemux->header_size += length;
2715 offset = (QT_UINT32 (buffer) == 0) ? 16 : 8;
2717 if (length <= offset + 16) {
2718 GST_DEBUG_OBJECT (qtdemux, "uuid atom is too short, skipping");
2722 if (memcmp (buffer + offset, xmp_uuid, 16) == 0) {
2724 GstTagList *taglist;
2726 buf = _gst_buffer_new_wrapped ((guint8 *) buffer + offset + 16,
2727 length - offset - 16, NULL);
2728 taglist = gst_tag_list_from_xmp_buffer (buf);
2729 gst_buffer_unref (buf);
2731 qtdemux_handle_xmp_taglist (qtdemux, qtdemux->tag_list, taglist);
2733 } else if (memcmp (buffer + offset, playready_uuid, 16) == 0) {
2735 const gunichar2 *s_utf16;
2738 len = GST_READ_UINT16_LE (buffer + offset + 0x30);
2739 s_utf16 = (const gunichar2 *) (buffer + offset + 0x32);
2740 contents = g_utf16_to_utf8 (s_utf16, len / 2, NULL, NULL, NULL);
2741 GST_ERROR_OBJECT (qtdemux, "contents: %s", contents);
2745 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT,
2746 (_("Cannot play stream because it is encrypted with PlayReady DRM.")),
2748 } else if (memcmp (buffer + offset, piff_sample_encryption_uuid, 16) == 0) {
2749 qtdemux_parse_piff (qtdemux, buffer, length, offset);
2751 GST_DEBUG_OBJECT (qtdemux, "Ignoring unknown uuid: %08x-%08x-%08x-%08x",
2752 GST_READ_UINT32_LE (buffer + offset),
2753 GST_READ_UINT32_LE (buffer + offset + 4),
2754 GST_READ_UINT32_LE (buffer + offset + 8),
2755 GST_READ_UINT32_LE (buffer + offset + 12));
2760 qtdemux_parse_sidx (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2762 GstSidxParser sidx_parser;
2763 GstIsoffParserResult res;
2766 gst_isoff_qt_sidx_parser_init (&sidx_parser);
2769 gst_isoff_qt_sidx_parser_add_data (&sidx_parser, buffer, length,
2771 GST_DEBUG_OBJECT (qtdemux, "sidx parse result: %d", res);
2772 if (res == GST_ISOFF_QT_PARSER_DONE) {
2773 check_update_duration (qtdemux, sidx_parser.cumulative_pts);
2775 gst_isoff_qt_sidx_parser_clear (&sidx_parser);
2778 /* caller verifies at least 8 bytes in buf */
2780 extract_initial_length_and_fourcc (const guint8 * data, guint size,
2781 guint64 * plength, guint32 * pfourcc)
2786 length = QT_UINT32 (data);
2787 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
2788 fourcc = QT_FOURCC (data + 4);
2789 GST_DEBUG ("atom type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
2792 length = G_MAXUINT64;
2793 } else if (length == 1 && size >= 16) {
2794 /* this means we have an extended size, which is the 64 bit value of
2795 * the next 8 bytes */
2796 length = QT_UINT64 (data + 8);
2797 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
2807 qtdemux_parse_mehd (GstQTDemux * qtdemux, GstByteReader * br)
2809 guint32 version = 0;
2810 GstClockTime duration = 0;
2812 if (!gst_byte_reader_get_uint32_be (br, &version))
2817 if (!gst_byte_reader_get_uint64_be (br, &duration))
2822 if (!gst_byte_reader_get_uint32_be (br, &dur))
2827 GST_INFO_OBJECT (qtdemux, "mehd duration: %" G_GUINT64_FORMAT, duration);
2828 qtdemux->duration = duration;
2834 GST_DEBUG_OBJECT (qtdemux, "parsing mehd failed");
2840 qtdemux_parse_trex (GstQTDemux * qtdemux, QtDemuxStream * stream,
2841 guint32 * ds_duration, guint32 * ds_size, guint32 * ds_flags)
2843 if (!stream->parsed_trex && qtdemux->moov_node) {
2845 GstByteReader trex_data;
2847 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
2849 trex = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_trex,
2852 guint32 id = 0, dur = 0, size = 0, flags = 0, dummy = 0;
2854 /* skip version/flags */
2855 if (!gst_byte_reader_skip (&trex_data, 4))
2857 if (!gst_byte_reader_get_uint32_be (&trex_data, &id))
2859 if (id != stream->track_id)
2861 /* sample description index; ignore */
2862 if (!gst_byte_reader_get_uint32_be (&trex_data, &dummy))
2864 if (!gst_byte_reader_get_uint32_be (&trex_data, &dur))
2866 if (!gst_byte_reader_get_uint32_be (&trex_data, &size))
2868 if (!gst_byte_reader_get_uint32_be (&trex_data, &flags))
2871 GST_DEBUG_OBJECT (qtdemux, "fragment defaults for stream %d; "
2872 "duration %d, size %d, flags 0x%x", stream->track_id,
2875 stream->parsed_trex = TRUE;
2876 stream->def_sample_duration = dur;
2877 stream->def_sample_size = size;
2878 stream->def_sample_flags = flags;
2881 /* iterate all siblings */
2882 trex = qtdemux_tree_get_sibling_by_type_full (trex, FOURCC_trex,
2888 *ds_duration = stream->def_sample_duration;
2889 *ds_size = stream->def_sample_size;
2890 *ds_flags = stream->def_sample_flags;
2892 /* even then, above values are better than random ... */
2893 if (G_UNLIKELY (!stream->parsed_trex)) {
2894 GST_WARNING_OBJECT (qtdemux,
2895 "failed to find fragment defaults for stream %d", stream->track_id);
2902 /* This method should be called whenever a more accurate duration might
2903 * have been found. It will update all relevant variables if/where needed
2906 check_update_duration (GstQTDemux * qtdemux, GstClockTime duration)
2910 GstClockTime prevdur;
2912 movdur = GSTTIME_TO_QTTIME (qtdemux, duration);
2914 if (movdur > qtdemux->duration) {
2915 prevdur = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
2916 GST_DEBUG_OBJECT (qtdemux,
2917 "Updating total duration to %" GST_TIME_FORMAT " was %" GST_TIME_FORMAT,
2918 GST_TIME_ARGS (duration), GST_TIME_ARGS (prevdur));
2919 qtdemux->duration = movdur;
2920 GST_DEBUG_OBJECT (qtdemux,
2921 "qtdemux->segment.duration: %" GST_TIME_FORMAT " .stop: %"
2922 GST_TIME_FORMAT, GST_TIME_ARGS (qtdemux->segment.duration),
2923 GST_TIME_ARGS (qtdemux->segment.stop));
2924 if (qtdemux->segment.duration == prevdur) {
2925 /* If the current segment has duration/stop identical to previous duration
2926 * update them also (because they were set at that point in time with
2927 * the wrong duration */
2928 /* We convert the value *from* the timescale version to avoid rounding errors */
2929 GstClockTime fixeddur = QTTIME_TO_GSTTIME (qtdemux, movdur);
2930 GST_DEBUG_OBJECT (qtdemux, "Updated segment.duration and segment.stop");
2931 qtdemux->segment.duration = fixeddur;
2932 qtdemux->segment.stop = fixeddur;
2935 for (i = 0; i < qtdemux->n_streams; i++) {
2936 QtDemuxStream *stream = qtdemux->streams[i];
2938 movdur = GSTTIME_TO_QTSTREAMTIME (stream, duration);
2939 if (movdur > stream->duration) {
2940 GST_DEBUG_OBJECT (qtdemux,
2941 "Updating stream #%d duration to %" GST_TIME_FORMAT, i,
2942 GST_TIME_ARGS (duration));
2943 stream->duration = movdur;
2944 if (stream->dummy_segment) {
2945 /* Update all dummy values to new duration */
2946 stream->segments[0].stop_time = duration;
2947 stream->segments[0].duration = duration;
2948 stream->segments[0].media_stop = duration;
2950 /* let downstream know we possibly have a new stop time */
2951 if (stream->segment_index != -1) {
2954 if (qtdemux->segment.rate >= 0) {
2955 pos = stream->segment.start;
2957 pos = stream->segment.stop;
2960 gst_qtdemux_stream_update_segment (qtdemux, stream,
2961 stream->segment_index, pos, NULL, NULL);
2970 qtdemux_parse_trun (GstQTDemux * qtdemux, GstByteReader * trun,
2971 QtDemuxStream * stream, guint32 d_sample_duration, guint32 d_sample_size,
2972 guint32 d_sample_flags, gint64 moof_offset, gint64 moof_length,
2973 gint64 * base_offset, gint64 * running_offset, gint64 decode_ts)
2975 GstClockTime gst_ts = GST_CLOCK_TIME_NONE;
2977 gint32 data_offset = 0;
2978 guint32 flags = 0, first_flags = 0, samples_count = 0;
2981 guint entry_size, dur_offset, size_offset, flags_offset = 0, ct_offset = 0;
2982 QtDemuxSample *sample;
2983 gboolean ismv = FALSE;
2984 gint64 initial_offset;
2986 GST_LOG_OBJECT (qtdemux, "parsing trun stream %d; "
2987 "default dur %d, size %d, flags 0x%x, base offset %" G_GINT64_FORMAT ", "
2988 "decode ts %" G_GINT64_FORMAT, stream->track_id, d_sample_duration,
2989 d_sample_size, d_sample_flags, *base_offset, decode_ts);
2991 if (stream->pending_seek && moof_offset < stream->pending_seek->moof_offset) {
2992 GST_INFO_OBJECT (stream->pad, "skipping trun before seek target fragment");
2996 /* presence of stss or not can't really tell us much,
2997 * and flags and so on tend to be marginally reliable in these files */
2998 if (stream->subtype == FOURCC_soun) {
2999 GST_DEBUG_OBJECT (qtdemux,
3000 "sound track in fragmented file; marking all keyframes");
3001 stream->all_keyframe = TRUE;
3004 if (!gst_byte_reader_skip (trun, 1) ||
3005 !gst_byte_reader_get_uint24_be (trun, &flags))
3008 if (!gst_byte_reader_get_uint32_be (trun, &samples_count))
3011 if (flags & TR_DATA_OFFSET) {
3012 /* note this is really signed */
3013 if (!gst_byte_reader_get_int32_be (trun, &data_offset))
3015 GST_LOG_OBJECT (qtdemux, "trun data offset %d", data_offset);
3016 /* default base offset = first byte of moof */
3017 if (*base_offset == -1) {
3018 GST_LOG_OBJECT (qtdemux, "base_offset at moof");
3019 *base_offset = moof_offset;
3021 *running_offset = *base_offset + data_offset;
3023 /* if no offset at all, that would mean data starts at moof start,
3024 * which is a bit wrong and is ismv crappy way, so compensate
3025 * assuming data is in mdat following moof */
3026 if (*base_offset == -1) {
3027 *base_offset = moof_offset + moof_length + 8;
3028 GST_LOG_OBJECT (qtdemux, "base_offset assumed in mdat after moof");
3031 if (*running_offset == -1)
3032 *running_offset = *base_offset;
3035 GST_LOG_OBJECT (qtdemux, "running offset now %" G_GINT64_FORMAT,
3037 GST_LOG_OBJECT (qtdemux, "trun offset %d, flags 0x%x, entries %d",
3038 data_offset, flags, samples_count);
3040 if (flags & TR_FIRST_SAMPLE_FLAGS) {
3041 if (G_UNLIKELY (flags & TR_SAMPLE_FLAGS)) {
3042 GST_DEBUG_OBJECT (qtdemux,
3043 "invalid flags; SAMPLE and FIRST_SAMPLE present, discarding latter");
3044 flags ^= TR_FIRST_SAMPLE_FLAGS;
3046 if (!gst_byte_reader_get_uint32_be (trun, &first_flags))
3048 GST_LOG_OBJECT (qtdemux, "first flags: 0x%x", first_flags);
3052 /* FIXME ? spec says other bits should also be checked to determine
3053 * entry size (and prefix size for that matter) */
3055 dur_offset = size_offset = 0;
3056 if (flags & TR_SAMPLE_DURATION) {
3057 GST_LOG_OBJECT (qtdemux, "entry duration present");
3058 dur_offset = entry_size;
3061 if (flags & TR_SAMPLE_SIZE) {
3062 GST_LOG_OBJECT (qtdemux, "entry size present");
3063 size_offset = entry_size;
3066 if (flags & TR_SAMPLE_FLAGS) {
3067 GST_LOG_OBJECT (qtdemux, "entry flags present");
3068 flags_offset = entry_size;
3071 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
3072 GST_LOG_OBJECT (qtdemux, "entry ct offset present");
3073 ct_offset = entry_size;
3077 if (!qt_atom_parser_has_chunks (trun, samples_count, entry_size))
3079 data = (guint8 *) gst_byte_reader_peek_data_unchecked (trun);
3081 if (stream->n_samples + samples_count >=
3082 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample))
3085 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
3086 stream->n_samples + samples_count, (guint) sizeof (QtDemuxSample),
3087 (stream->n_samples + samples_count) *
3088 sizeof (QtDemuxSample) / (1024.0 * 1024.0));
3090 /* create a new array of samples if it's the first sample parsed */
3091 if (stream->n_samples == 0) {
3092 g_assert (stream->samples == NULL);
3093 stream->samples = g_try_new0 (QtDemuxSample, samples_count);
3094 /* or try to reallocate it with space enough to insert the new samples */
3096 stream->samples = g_try_renew (QtDemuxSample, stream->samples,
3097 stream->n_samples + samples_count);
3098 if (stream->samples == NULL)
3101 if (qtdemux->fragment_start != -1) {
3102 timestamp = GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->fragment_start);
3103 qtdemux->fragment_start = -1;
3105 if (stream->n_samples == 0) {
3106 if (decode_ts > 0) {
3107 timestamp = decode_ts;
3108 } else if (stream->pending_seek != NULL) {
3109 /* if we don't have a timestamp from a tfdt box, we'll use the one
3110 * from the mfra seek table */
3111 GST_INFO_OBJECT (stream->pad, "pending seek ts = %" GST_TIME_FORMAT,
3112 GST_TIME_ARGS (stream->pending_seek->ts));
3114 /* FIXME: this is not fully correct, the timestamp refers to the random
3115 * access sample refered to in the tfra entry, which may not necessarily
3116 * be the first sample in the tfrag/trun (but hopefully/usually is) */
3117 timestamp = GSTTIME_TO_QTSTREAMTIME (stream, stream->pending_seek->ts);
3122 gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
3123 GST_INFO_OBJECT (stream->pad, "first sample ts %" GST_TIME_FORMAT,
3124 GST_TIME_ARGS (gst_ts));
3126 /* subsequent fragments extend stream */
3128 stream->samples[stream->n_samples - 1].timestamp +
3129 stream->samples[stream->n_samples - 1].duration;
3131 /* If this is a GST_FORMAT_BYTES stream and there's a significant
3132 * difference (1 sec.) between decode_ts and timestamp, prefer the
3134 if (!qtdemux->upstream_format_is_time
3135 && ABSDIFF (decode_ts, timestamp) >
3136 MAX (stream->duration_last_moof / 2,
3137 GSTTIME_TO_QTSTREAMTIME (stream, GST_SECOND))) {
3138 GST_INFO_OBJECT (qtdemux,
3139 "decode_ts (%" GST_TIME_FORMAT ") and timestamp (%" GST_TIME_FORMAT
3140 ") are significantly different (more than %" GST_TIME_FORMAT
3141 "), using decode_ts",
3142 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, decode_ts)),
3143 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, timestamp)),
3144 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream,
3145 MAX (stream->duration_last_moof / 2,
3146 GSTTIME_TO_QTSTREAMTIME (stream, GST_SECOND)))));
3147 timestamp = decode_ts;
3150 gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
3151 GST_INFO_OBJECT (qtdemux, "first sample ts %" GST_TIME_FORMAT
3152 " (extends previous samples)", GST_TIME_ARGS (gst_ts));
3156 initial_offset = *running_offset;
3158 sample = stream->samples + stream->n_samples;
3159 for (i = 0; i < samples_count; i++) {
3160 guint32 dur, size, sflags, ct;
3162 /* first read sample data */
3163 if (flags & TR_SAMPLE_DURATION) {
3164 dur = QT_UINT32 (data + dur_offset);
3166 dur = d_sample_duration;
3168 if (flags & TR_SAMPLE_SIZE) {
3169 size = QT_UINT32 (data + size_offset);
3171 size = d_sample_size;
3173 if (flags & TR_FIRST_SAMPLE_FLAGS) {
3175 sflags = first_flags;
3177 sflags = d_sample_flags;
3179 } else if (flags & TR_SAMPLE_FLAGS) {
3180 sflags = QT_UINT32 (data + flags_offset);
3182 sflags = d_sample_flags;
3184 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
3185 ct = QT_UINT32 (data + ct_offset);
3191 /* fill the sample information */
3192 sample->offset = *running_offset;
3193 sample->pts_offset = ct;
3194 sample->size = size;
3195 sample->timestamp = timestamp;
3196 sample->duration = dur;
3197 /* sample-is-difference-sample */
3198 /* ismv seems to use 0x40 for keyframe, 0xc0 for non-keyframe,
3199 * now idea how it relates to bitfield other than massive LE/BE confusion */
3200 sample->keyframe = ismv ? ((sflags & 0xff) == 0x40) : !(sflags & 0x10000);
3201 *running_offset += size;
3203 stream->duration_moof += dur;
3207 /* Update total duration if needed */
3208 check_update_duration (qtdemux, QTSTREAMTIME_TO_GSTTIME (stream, timestamp));
3210 /* Pre-emptively figure out size of mdat based on trun information.
3211 * If the [mdat] atom is effectivelly read, it will be replaced by the actual
3212 * size, else we will still be able to use this when dealing with gap'ed
3214 qtdemux->mdatleft = *running_offset - initial_offset;
3216 stream->n_samples += samples_count;
3217 stream->n_samples_moof += samples_count;
3219 if (stream->pending_seek != NULL)
3220 stream->pending_seek = NULL;
3226 GST_WARNING_OBJECT (qtdemux, "failed to parse trun");
3231 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
3237 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
3238 "be larger than %uMB (broken file?)", stream->n_samples,
3239 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
3244 /* find stream with @id */
3245 static inline QtDemuxStream *
3246 qtdemux_find_stream (GstQTDemux * qtdemux, guint32 id)
3248 QtDemuxStream *stream;
3252 if (G_UNLIKELY (!id)) {
3253 GST_DEBUG_OBJECT (qtdemux, "invalid track id 0");
3257 /* try to get it fast and simple */
3258 if (G_LIKELY (id <= qtdemux->n_streams)) {
3259 stream = qtdemux->streams[id - 1];
3260 if (G_LIKELY (stream->track_id == id))
3264 /* linear search otherwise */
3265 for (i = 0; i < qtdemux->n_streams; i++) {
3266 stream = qtdemux->streams[i];
3267 if (stream->track_id == id)
3270 if (qtdemux->mss_mode) {
3271 /* mss should have only 1 stream anyway */
3272 return qtdemux->streams[0];
3279 qtdemux_parse_mfhd (GstQTDemux * qtdemux, GstByteReader * mfhd,
3280 guint32 * fragment_number)
3282 if (!gst_byte_reader_skip (mfhd, 4))
3284 if (!gst_byte_reader_get_uint32_be (mfhd, fragment_number))
3289 GST_WARNING_OBJECT (qtdemux, "Failed to parse mfhd atom");
3295 qtdemux_parse_tfhd (GstQTDemux * qtdemux, GstByteReader * tfhd,
3296 QtDemuxStream ** stream, guint32 * default_sample_duration,
3297 guint32 * default_sample_size, guint32 * default_sample_flags,
3298 gint64 * base_offset)
3301 guint32 track_id = 0;
3303 if (!gst_byte_reader_skip (tfhd, 1) ||
3304 !gst_byte_reader_get_uint24_be (tfhd, &flags))
3307 if (!gst_byte_reader_get_uint32_be (tfhd, &track_id))
3310 *stream = qtdemux_find_stream (qtdemux, track_id);
3311 if (G_UNLIKELY (!*stream))
3312 goto unknown_stream;
3314 if (flags & TF_DEFAULT_BASE_IS_MOOF)
3315 *base_offset = qtdemux->moof_offset;
3317 if (flags & TF_BASE_DATA_OFFSET)
3318 if (!gst_byte_reader_get_uint64_be (tfhd, (guint64 *) base_offset))
3321 /* obtain stream defaults */
3322 qtdemux_parse_trex (qtdemux, *stream,
3323 default_sample_duration, default_sample_size, default_sample_flags);
3325 /* FIXME: Handle TF_SAMPLE_DESCRIPTION_INDEX properly */
3326 if (flags & TF_SAMPLE_DESCRIPTION_INDEX)
3327 if (!gst_byte_reader_skip (tfhd, 4))
3330 if (flags & TF_DEFAULT_SAMPLE_DURATION)
3331 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_duration))
3334 if (flags & TF_DEFAULT_SAMPLE_SIZE)
3335 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_size))
3338 if (flags & TF_DEFAULT_SAMPLE_FLAGS)
3339 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_flags))
3346 GST_WARNING_OBJECT (qtdemux, "invalid track fragment header");
3351 GST_DEBUG_OBJECT (qtdemux, "unknown stream in tfhd");
3357 qtdemux_parse_tfdt (GstQTDemux * qtdemux, GstByteReader * br,
3358 guint64 * decode_time)
3360 guint32 version = 0;
3362 if (!gst_byte_reader_get_uint32_be (br, &version))
3367 if (!gst_byte_reader_get_uint64_be (br, decode_time))
3370 guint32 dec_time = 0;
3371 if (!gst_byte_reader_get_uint32_be (br, &dec_time))
3373 *decode_time = dec_time;
3376 GST_INFO_OBJECT (qtdemux, "Track fragment decode time: %" G_GUINT64_FORMAT,
3383 GST_DEBUG_OBJECT (qtdemux, "parsing tfdt failed");
3388 /* Returns a pointer to a GstStructure containing the properties of
3389 * the stream sample identified by @sample_index. The caller must unref
3390 * the returned object after use. Returns NULL if unsuccessful. */
3391 static GstStructure *
3392 qtdemux_get_cenc_sample_properties (GstQTDemux * qtdemux,
3393 QtDemuxStream * stream, guint sample_index)
3395 QtDemuxCencSampleSetInfo *info = NULL;
3397 g_return_val_if_fail (stream != NULL, NULL);
3398 g_return_val_if_fail (stream->protected, NULL);
3399 g_return_val_if_fail (stream->protection_scheme_info != NULL, NULL);
3401 info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
3403 /* Currently, cenc properties for groups of samples are not supported, so
3404 * simply return a copy of the default sample properties */
3405 return gst_structure_copy (info->default_properties);
3408 /* Parses the sizes of sample auxiliary information contained within a stream,
3409 * as given in a saiz box. Returns array of sample_count guint8 size values,
3410 * or NULL on failure */
3412 qtdemux_parse_saiz (GstQTDemux * qtdemux, QtDemuxStream * stream,
3413 GstByteReader * br, guint32 * sample_count)
3417 guint8 default_info_size;
3419 g_return_val_if_fail (qtdemux != NULL, NULL);
3420 g_return_val_if_fail (stream != NULL, NULL);
3421 g_return_val_if_fail (br != NULL, NULL);
3422 g_return_val_if_fail (sample_count != NULL, NULL);
3424 if (!gst_byte_reader_get_uint32_be (br, &flags))
3428 /* aux_info_type and aux_info_type_parameter are ignored */
3429 if (!gst_byte_reader_skip (br, 8))
3433 if (!gst_byte_reader_get_uint8 (br, &default_info_size))
3435 GST_DEBUG_OBJECT (qtdemux, "default_info_size: %u", default_info_size);
3437 if (!gst_byte_reader_get_uint32_be (br, sample_count))
3439 GST_DEBUG_OBJECT (qtdemux, "sample_count: %u", *sample_count);
3442 if (default_info_size == 0) {
3443 if (!gst_byte_reader_dup_data (br, *sample_count, &info_sizes)) {
3447 info_sizes = g_new (guint8, *sample_count);
3448 memset (info_sizes, default_info_size, *sample_count);
3454 /* Parses the offset of sample auxiliary information contained within a stream,
3455 * as given in a saio box. Returns TRUE if successful; FALSE otherwise. */
3457 qtdemux_parse_saio (GstQTDemux * qtdemux, QtDemuxStream * stream,
3458 GstByteReader * br, guint32 * info_type, guint32 * info_type_parameter,
3463 guint32 aux_info_type = 0;
3464 guint32 aux_info_type_parameter = 0;
3465 guint32 entry_count;
3468 const guint8 *aux_info_type_data = NULL;
3470 g_return_val_if_fail (qtdemux != NULL, FALSE);
3471 g_return_val_if_fail (stream != NULL, FALSE);
3472 g_return_val_if_fail (br != NULL, FALSE);
3473 g_return_val_if_fail (offset != NULL, FALSE);
3475 if (!gst_byte_reader_get_uint8 (br, &version))
3478 if (!gst_byte_reader_get_uint24_be (br, &flags))
3483 if (!gst_byte_reader_get_data (br, 4, &aux_info_type_data))
3485 aux_info_type = QT_FOURCC (aux_info_type_data);
3487 if (!gst_byte_reader_get_uint32_be (br, &aux_info_type_parameter))
3489 } else if (stream->protected) {
3490 aux_info_type = stream->protection_scheme_type;
3492 aux_info_type = stream->fourcc;
3496 *info_type = aux_info_type;
3497 if (info_type_parameter)
3498 *info_type_parameter = aux_info_type_parameter;
3500 GST_DEBUG_OBJECT (qtdemux, "aux_info_type: '%" GST_FOURCC_FORMAT "', "
3501 "aux_info_type_parameter: %#06x",
3502 GST_FOURCC_ARGS (aux_info_type), aux_info_type_parameter);
3504 if (!gst_byte_reader_get_uint32_be (br, &entry_count))
3507 if (entry_count != 1) {
3508 GST_ERROR_OBJECT (qtdemux, "multiple offsets are not supported");
3513 if (!gst_byte_reader_get_uint32_be (br, &off_32))
3515 *offset = (guint64) off_32;
3517 if (!gst_byte_reader_get_uint64_be (br, &off_64))
3522 GST_DEBUG_OBJECT (qtdemux, "offset: %" G_GUINT64_FORMAT, *offset);
3527 qtdemux_gst_structure_free (GstStructure * gststructure)
3530 gst_structure_free (gststructure);
3534 /* Parses auxiliary information relating to samples protected using Common
3535 * Encryption (cenc); the format of this information is defined in
3536 * ISO/IEC 23001-7. Returns TRUE if successful; FALSE otherwise. */
3538 qtdemux_parse_cenc_aux_info (GstQTDemux * qtdemux, QtDemuxStream * stream,
3539 GstByteReader * br, guint8 * info_sizes, guint32 sample_count)
3541 QtDemuxCencSampleSetInfo *ss_info = NULL;
3545 g_return_val_if_fail (qtdemux != NULL, FALSE);
3546 g_return_val_if_fail (stream != NULL, FALSE);
3547 g_return_val_if_fail (br != NULL, FALSE);
3548 g_return_val_if_fail (stream->protected, FALSE);
3549 g_return_val_if_fail (stream->protection_scheme_info != NULL, FALSE);
3551 ss_info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
3553 if (ss_info->crypto_info) {
3554 GST_LOG_OBJECT (qtdemux, "unreffing existing crypto_info");
3555 g_ptr_array_free (ss_info->crypto_info, TRUE);
3558 ss_info->crypto_info =
3559 g_ptr_array_new_full (sample_count,
3560 (GDestroyNotify) qtdemux_gst_structure_free);
3562 for (i = 0; i < sample_count; ++i) {
3563 GstStructure *properties;
3564 guint16 n_subsamples = 0;
3569 properties = qtdemux_get_cenc_sample_properties (qtdemux, stream, i);
3570 if (properties == NULL) {
3571 GST_ERROR_OBJECT (qtdemux, "failed to get properties for sample %u", i);
3574 if (!gst_structure_get_uint (properties, "iv_size", &iv_size)) {
3575 GST_ERROR_OBJECT (qtdemux, "failed to get iv_size for sample %u", i);
3576 gst_structure_free (properties);
3579 if (!gst_byte_reader_dup_data (br, iv_size, &data)) {
3580 GST_ERROR_OBJECT (qtdemux, "failed to get IV for sample %u", i);
3581 gst_structure_free (properties);
3584 buf = gst_buffer_new_wrapped (data, iv_size);
3585 gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL);
3586 gst_buffer_unref (buf);
3587 size = info_sizes[i];
3588 if (size > iv_size) {
3589 if (!gst_byte_reader_get_uint16_be (br, &n_subsamples)
3590 || !(n_subsamples > 0)) {
3591 gst_structure_free (properties);
3592 GST_ERROR_OBJECT (qtdemux,
3593 "failed to get subsample count for sample %u", i);
3596 GST_LOG_OBJECT (qtdemux, "subsample count: %u", n_subsamples);
3597 if (!gst_byte_reader_dup_data (br, n_subsamples * 6, &data)) {
3598 GST_ERROR_OBJECT (qtdemux, "failed to get subsample data for sample %u",
3600 gst_structure_free (properties);
3603 buf = gst_buffer_new_wrapped (data, n_subsamples * 6);
3605 gst_structure_free (properties);
3608 gst_structure_set (properties,
3609 "subsample_count", G_TYPE_UINT, n_subsamples,
3610 "subsamples", GST_TYPE_BUFFER, buf, NULL);
3611 gst_buffer_unref (buf);
3613 gst_structure_set (properties, "subsample_count", G_TYPE_UINT, 0, NULL);
3615 g_ptr_array_add (ss_info->crypto_info, properties);
3620 /* Converts a UUID in raw byte form to a string representation, as defined in
3621 * RFC 4122. The caller takes ownership of the returned string and is
3622 * responsible for freeing it after use. */
3624 qtdemux_uuid_bytes_to_string (gconstpointer uuid_bytes)
3626 const guint8 *uuid = (const guint8 *) uuid_bytes;
3628 return g_strdup_printf ("%02x%02x%02x%02x-%02x%02x-%02x%02x-"
3629 "%02x%02x-%02x%02x%02x%02x%02x%02x",
3630 uuid[0], uuid[1], uuid[2], uuid[3],
3631 uuid[4], uuid[5], uuid[6], uuid[7],
3632 uuid[8], uuid[9], uuid[10], uuid[11],
3633 uuid[12], uuid[13], uuid[14], uuid[15]);
3636 /* Parses a Protection System Specific Header box (pssh), as defined in the
3637 * Common Encryption (cenc) standard (ISO/IEC 23001-7), which contains
3638 * information needed by a specific content protection system in order to
3639 * decrypt cenc-protected tracks. Returns TRUE if successful; FALSE
3642 qtdemux_parse_pssh (GstQTDemux * qtdemux, GNode * node)
3644 gchar *sysid_string;
3645 guint32 pssh_size = QT_UINT32 (node->data);
3646 GstBuffer *pssh = NULL;
3647 GstEvent *event = NULL;
3648 guint32 parent_box_type;
3651 if (G_UNLIKELY (pssh_size < 32U)) {
3652 GST_ERROR_OBJECT (qtdemux, "invalid box size");
3657 qtdemux_uuid_bytes_to_string ((const guint8 *) node->data + 12);
3659 gst_qtdemux_append_protection_system_id (qtdemux, sysid_string);
3661 pssh = gst_buffer_new_wrapped (g_memdup (node->data, pssh_size), pssh_size);
3662 GST_LOG_OBJECT (qtdemux, "cenc pssh size: %" G_GSIZE_FORMAT,
3663 gst_buffer_get_size (pssh));
3665 parent_box_type = QT_FOURCC ((const guint8 *) node->parent->data + 4);
3667 /* Push an event containing the pssh box onto the queues of all streams. */
3668 event = gst_event_new_protection (sysid_string, pssh,
3669 (parent_box_type == FOURCC_moov) ? "isobmff/moov" : "isobmff/moof");
3670 for (i = 0; i < qtdemux->n_streams; ++i) {
3671 g_queue_push_tail (&qtdemux->streams[i]->protection_scheme_event_queue,
3672 gst_event_ref (event));
3674 g_free (sysid_string);
3675 gst_event_unref (event);
3676 gst_buffer_unref (pssh);
3681 qtdemux_parse_moof (GstQTDemux * qtdemux, const guint8 * buffer, guint length,
3682 guint64 moof_offset, QtDemuxStream * stream)
3684 GNode *moof_node, *traf_node, *tfhd_node, *trun_node, *tfdt_node, *mfhd_node;
3686 GstByteReader mfhd_data, trun_data, tfhd_data, tfdt_data;
3687 GNode *saiz_node, *saio_node, *pssh_node;
3688 GstByteReader saiz_data, saio_data;
3689 guint32 ds_size = 0, ds_duration = 0, ds_flags = 0;
3690 gint64 base_offset, running_offset;
3693 /* NOTE @stream ignored */
3695 moof_node = g_node_new ((guint8 *) buffer);
3696 qtdemux_parse_node (qtdemux, moof_node, buffer, length);
3697 qtdemux_node_dump (qtdemux, moof_node);
3699 /* Get fragment number from mfhd and check it's valid */
3701 qtdemux_tree_get_child_by_type_full (moof_node, FOURCC_mfhd, &mfhd_data);
3702 if (mfhd_node == NULL)
3704 if (!qtdemux_parse_mfhd (qtdemux, &mfhd_data, &frag_num))
3706 GST_DEBUG_OBJECT (qtdemux, "Fragment #%d", frag_num);
3708 /* unknown base_offset to start with */
3709 base_offset = running_offset = -1;
3710 traf_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_traf);
3712 guint64 decode_time = 0;
3714 /* Fragment Header node */
3716 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfhd,
3720 if (!qtdemux_parse_tfhd (qtdemux, &tfhd_data, &stream, &ds_duration,
3721 &ds_size, &ds_flags, &base_offset))
3724 /* The following code assumes at most a single set of sample auxiliary
3725 * data in the fragment (consisting of a saiz box and a corresponding saio
3726 * box); in theory, however, there could be multiple sets of sample
3727 * auxiliary data in a fragment. */
3729 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saiz,
3732 guint32 info_type = 0;
3734 guint32 info_type_parameter = 0;
3736 g_free (qtdemux->cenc_aux_info_sizes);
3738 qtdemux->cenc_aux_info_sizes =
3739 qtdemux_parse_saiz (qtdemux, stream, &saiz_data,
3740 &qtdemux->cenc_aux_sample_count);
3741 if (qtdemux->cenc_aux_info_sizes == NULL) {
3742 GST_ERROR_OBJECT (qtdemux, "failed to parse saiz box");
3746 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saio,
3749 GST_ERROR_OBJECT (qtdemux, "saiz box without a corresponding saio box");
3750 g_free (qtdemux->cenc_aux_info_sizes);
3751 qtdemux->cenc_aux_info_sizes = NULL;
3755 if (G_UNLIKELY (!qtdemux_parse_saio (qtdemux, stream, &saio_data,
3756 &info_type, &info_type_parameter, &offset))) {
3757 GST_ERROR_OBJECT (qtdemux, "failed to parse saio box");
3758 g_free (qtdemux->cenc_aux_info_sizes);
3759 qtdemux->cenc_aux_info_sizes = NULL;
3762 if (base_offset > -1 && base_offset > qtdemux->moof_offset)
3763 offset += (guint64) (base_offset - qtdemux->moof_offset);
3764 if (info_type == FOURCC_cenc && info_type_parameter == 0U) {
3766 if (offset > length) {
3767 GST_DEBUG_OBJECT (qtdemux, "cenc auxiliary info stored out of moof");
3768 qtdemux->cenc_aux_info_offset = offset;
3770 gst_byte_reader_init (&br, buffer + offset, length - offset);
3771 if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
3772 qtdemux->cenc_aux_info_sizes,
3773 qtdemux->cenc_aux_sample_count)) {
3774 GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
3775 g_free (qtdemux->cenc_aux_info_sizes);
3776 qtdemux->cenc_aux_info_sizes = NULL;
3784 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfdt,
3787 /* We'll use decode_time to interpolate timestamps
3788 * in case the input timestamps are missing */
3789 qtdemux_parse_tfdt (qtdemux, &tfdt_data, &decode_time);
3791 GST_DEBUG_OBJECT (qtdemux, "decode time %" G_GINT64_FORMAT
3792 " (%" GST_TIME_FORMAT ")", decode_time,
3793 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, decode_time)));
3795 /* Discard the fragment buffer timestamp info to avoid using it.
3796 * Rely on tfdt instead as it is more accurate than the timestamp
3797 * that is fetched from a manifest/playlist and is usually
3799 qtdemux->fragment_start = -1;
3802 if (G_UNLIKELY (!stream)) {
3803 /* we lost track of offset, we'll need to regain it,
3804 * but can delay complaining until later or avoid doing so altogether */
3808 if (G_UNLIKELY (base_offset < -1))
3811 if (qtdemux->upstream_format_is_time)
3812 gst_qtdemux_stream_flush_samples_data (qtdemux, stream);
3814 /* initialise moof sample data */
3815 stream->n_samples_moof = 0;
3816 stream->duration_last_moof = stream->duration_moof;
3817 stream->duration_moof = 0;
3819 /* Track Run node */
3821 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_trun,
3824 qtdemux_parse_trun (qtdemux, &trun_data, stream,
3825 ds_duration, ds_size, ds_flags, moof_offset, length, &base_offset,
3826 &running_offset, decode_time);
3827 /* iterate all siblings */
3828 trun_node = qtdemux_tree_get_sibling_by_type_full (trun_node, FOURCC_trun,
3832 uuid_node = qtdemux_tree_get_child_by_type (traf_node, FOURCC_uuid);
3834 guint8 *uuid_buffer = (guint8 *) uuid_node->data;
3835 guint32 box_length = QT_UINT32 (uuid_buffer);
3837 qtdemux_parse_uuid (qtdemux, uuid_buffer, box_length);
3840 /* if no new base_offset provided for next traf,
3841 * base is end of current traf */
3842 base_offset = running_offset;
3843 running_offset = -1;
3845 if (stream->n_samples_moof && stream->duration_moof)
3846 stream->new_caps = TRUE;
3849 /* iterate all siblings */
3850 traf_node = qtdemux_tree_get_sibling_by_type (traf_node, FOURCC_traf);
3853 /* parse any protection system info */
3854 pssh_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_pssh);
3856 GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
3857 qtdemux_parse_pssh (qtdemux, pssh_node);
3858 pssh_node = qtdemux_tree_get_sibling_by_type (pssh_node, FOURCC_pssh);
3861 g_node_destroy (moof_node);
3866 GST_DEBUG_OBJECT (qtdemux, "missing tfhd box");
3871 GST_DEBUG_OBJECT (qtdemux, "Missing mfhd box");
3876 GST_DEBUG_OBJECT (qtdemux, "lost offset");
3881 g_node_destroy (moof_node);
3882 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
3883 (_("This file is corrupt and cannot be played.")), (NULL));
3889 /* might be used if some day we actually use mfra & co
3890 * for random access to fragments,
3891 * but that will require quite some modifications and much less relying
3892 * on a sample array */
3896 qtdemux_parse_tfra (GstQTDemux * qtdemux, GNode * tfra_node)
3898 QtDemuxStream *stream;
3899 guint32 ver_flags, track_id, len, num_entries, i;
3900 guint value_size, traf_size, trun_size, sample_size;
3901 guint64 time = 0, moof_offset = 0;
3903 GstBuffer *buf = NULL;
3908 gst_byte_reader_init (&tfra, tfra_node->data, QT_UINT32 (tfra_node->data));
3910 if (!gst_byte_reader_skip (&tfra, 8))
3913 if (!gst_byte_reader_get_uint32_be (&tfra, &ver_flags))
3916 if (!gst_byte_reader_get_uint32_be (&tfra, &track_id)
3917 || !gst_byte_reader_get_uint32_be (&tfra, &len)
3918 || !gst_byte_reader_get_uint32_be (&tfra, &num_entries))
3921 GST_DEBUG_OBJECT (qtdemux, "parsing tfra box for track id %u", track_id);
3923 stream = qtdemux_find_stream (qtdemux, track_id);
3925 goto unknown_trackid;
3927 value_size = ((ver_flags >> 24) == 1) ? sizeof (guint64) : sizeof (guint32);
3928 sample_size = (len & 3) + 1;
3929 trun_size = ((len & 12) >> 2) + 1;
3930 traf_size = ((len & 48) >> 4) + 1;
3932 GST_DEBUG_OBJECT (qtdemux, "%u entries, sizes: value %u, traf %u, trun %u, "
3933 "sample %u", num_entries, value_size, traf_size, trun_size, sample_size);
3935 if (num_entries == 0)
3938 if (!qt_atom_parser_has_chunks (&tfra, num_entries,
3939 value_size + value_size + traf_size + trun_size + sample_size))
3942 g_free (stream->ra_entries);
3943 stream->ra_entries = g_new (QtDemuxRandomAccessEntry, num_entries);
3944 stream->n_ra_entries = num_entries;
3946 for (i = 0; i < num_entries; i++) {
3947 qt_atom_parser_get_offset (&tfra, value_size, &time);
3948 qt_atom_parser_get_offset (&tfra, value_size, &moof_offset);
3949 qt_atom_parser_get_uint_with_size_unchecked (&tfra, traf_size);
3950 qt_atom_parser_get_uint_with_size_unchecked (&tfra, trun_size);
3951 qt_atom_parser_get_uint_with_size_unchecked (&tfra, sample_size);
3953 time = QTSTREAMTIME_TO_GSTTIME (stream, time);
3955 GST_LOG_OBJECT (qtdemux, "fragment time: %" GST_TIME_FORMAT ", "
3956 " moof_offset: %" G_GUINT64_FORMAT, GST_TIME_ARGS (time), moof_offset);
3958 stream->ra_entries[i].ts = time;
3959 stream->ra_entries[i].moof_offset = moof_offset;
3961 /* don't want to go through the entire file and read all moofs at startup */
3963 ret = gst_qtdemux_pull_atom (qtdemux, moof_offset, 0, &buf);
3964 if (ret != GST_FLOW_OK)
3966 qtdemux_parse_moof (qtdemux, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf),
3967 moof_offset, stream);
3968 gst_buffer_unref (buf);
3972 check_update_duration (qtdemux, time);
3979 GST_WARNING_OBJECT (qtdemux, "Couldn't find stream for track %u", track_id);
3984 GST_WARNING_OBJECT (qtdemux, "broken traf box, ignoring");
3989 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
3995 qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux)
3997 GstMapInfo mfro_map = GST_MAP_INFO_INIT;
3998 GstMapInfo mfra_map = GST_MAP_INFO_INIT;
3999 GstBuffer *mfro = NULL, *mfra = NULL;
4001 gboolean ret = FALSE;
4002 GNode *mfra_node, *tfra_node;
4003 guint64 mfra_offset = 0;
4004 guint32 fourcc, mfra_size;
4007 /* query upstream size in bytes */
4008 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &len))
4009 goto size_query_failed;
4011 /* mfro box should be at the very end of the file */
4012 flow = gst_qtdemux_pull_atom (qtdemux, len - 16, 16, &mfro);
4013 if (flow != GST_FLOW_OK)
4016 gst_buffer_map (mfro, &mfro_map, GST_MAP_READ);
4018 fourcc = QT_FOURCC (mfro_map.data + 4);
4019 if (fourcc != FOURCC_mfro)
4022 GST_INFO_OBJECT (qtdemux, "Found mfro box");
4023 if (mfro_map.size < 16)
4024 goto invalid_mfro_size;
4026 mfra_size = QT_UINT32 (mfro_map.data + 12);
4027 if (mfra_size >= len)
4028 goto invalid_mfra_size;
4030 mfra_offset = len - mfra_size;
4032 GST_INFO_OBJECT (qtdemux, "mfra offset: %" G_GUINT64_FORMAT ", size %u",
4033 mfra_offset, mfra_size);
4035 /* now get and parse mfra box */
4036 flow = gst_qtdemux_pull_atom (qtdemux, mfra_offset, mfra_size, &mfra);
4037 if (flow != GST_FLOW_OK)
4040 gst_buffer_map (mfra, &mfra_map, GST_MAP_READ);
4042 mfra_node = g_node_new ((guint8 *) mfra_map.data);
4043 qtdemux_parse_node (qtdemux, mfra_node, mfra_map.data, mfra_map.size);
4045 tfra_node = qtdemux_tree_get_child_by_type (mfra_node, FOURCC_tfra);
4048 qtdemux_parse_tfra (qtdemux, tfra_node);
4049 /* iterate all siblings */
4050 tfra_node = qtdemux_tree_get_sibling_by_type (tfra_node, FOURCC_tfra);
4052 g_node_destroy (mfra_node);
4054 GST_INFO_OBJECT (qtdemux, "parsed movie fragment random access box (mfra)");
4060 if (mfro_map.memory != NULL)
4061 gst_buffer_unmap (mfro, &mfro_map);
4062 gst_buffer_unref (mfro);
4065 if (mfra_map.memory != NULL)
4066 gst_buffer_unmap (mfra, &mfra_map);
4067 gst_buffer_unref (mfra);
4074 GST_WARNING_OBJECT (qtdemux, "could not query upstream size");
4079 GST_WARNING_OBJECT (qtdemux, "mfro size is too small");
4084 GST_WARNING_OBJECT (qtdemux, "mfra_size in mfro box is invalid");
4089 GST_WARNING_OBJECT (qtdemux, "bogus mfra offset or size, broken file");
4095 add_offset (guint64 offset, guint64 advance)
4097 /* Avoid 64-bit overflow by clamping */
4098 if (offset > G_MAXUINT64 - advance)
4100 return offset + advance;
4103 static GstFlowReturn
4104 gst_qtdemux_loop_state_header (GstQTDemux * qtdemux)
4108 GstBuffer *buf = NULL;
4109 GstFlowReturn ret = GST_FLOW_OK;
4110 guint64 cur_offset = qtdemux->offset;
4113 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, 16, &buf);
4114 if (G_UNLIKELY (ret != GST_FLOW_OK))
4116 gst_buffer_map (buf, &map, GST_MAP_READ);
4117 if (G_LIKELY (map.size >= 8))
4118 extract_initial_length_and_fourcc (map.data, map.size, &length, &fourcc);
4119 gst_buffer_unmap (buf, &map);
4120 gst_buffer_unref (buf);
4122 /* maybe we already got most we needed, so only consider this eof */
4123 if (G_UNLIKELY (length == 0)) {
4124 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
4125 (_("Invalid atom size.")),
4126 ("Header atom '%" GST_FOURCC_FORMAT "' has empty length",
4127 GST_FOURCC_ARGS (fourcc)));
4134 /* record for later parsing when needed */
4135 if (!qtdemux->moof_offset) {
4136 qtdemux->moof_offset = qtdemux->offset;
4138 if (qtdemux_pull_mfro_mfra (qtdemux)) {
4141 qtdemux->offset += length; /* skip moof and keep going */
4143 if (qtdemux->got_moov) {
4144 GST_INFO_OBJECT (qtdemux, "moof header, got moov, done with headers");
4155 GST_LOG_OBJECT (qtdemux,
4156 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
4157 GST_FOURCC_ARGS (fourcc), cur_offset);
4158 qtdemux->offset = add_offset (qtdemux->offset, length);
4163 GstBuffer *moov = NULL;
4165 if (qtdemux->got_moov) {
4166 GST_DEBUG_OBJECT (qtdemux, "Skipping moov atom as we have one already");
4167 qtdemux->offset = add_offset (qtdemux->offset, length);
4171 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, length, &moov);
4172 if (ret != GST_FLOW_OK)
4174 gst_buffer_map (moov, &map, GST_MAP_READ);
4176 if (length != map.size) {
4177 /* Some files have a 'moov' atom at the end of the file which contains
4178 * a terminal 'free' atom where the body of the atom is missing.
4179 * Check for, and permit, this special case.
4181 if (map.size >= 8) {
4182 guint8 *final_data = map.data + (map.size - 8);
4183 guint32 final_length = QT_UINT32 (final_data);
4184 guint32 final_fourcc = QT_FOURCC (final_data + 4);
4186 if (final_fourcc == FOURCC_free
4187 && map.size + final_length - 8 == length) {
4188 /* Ok, we've found that special case. Allocate a new buffer with
4189 * that free atom actually present. */
4190 GstBuffer *newmoov = gst_buffer_new_and_alloc (length);
4191 gst_buffer_fill (newmoov, 0, map.data, map.size);
4192 gst_buffer_memset (newmoov, map.size, 0, final_length - 8);
4193 gst_buffer_unmap (moov, &map);
4194 gst_buffer_unref (moov);
4196 gst_buffer_map (moov, &map, GST_MAP_READ);
4201 if (length != map.size) {
4202 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4203 (_("This file is incomplete and cannot be played.")),
4204 ("We got less than expected (received %" G_GSIZE_FORMAT
4205 ", wanted %u, offset %" G_GUINT64_FORMAT ")", map.size,
4206 (guint) length, cur_offset));
4207 gst_buffer_unmap (moov, &map);
4208 gst_buffer_unref (moov);
4209 ret = GST_FLOW_ERROR;
4212 qtdemux->offset += length;
4214 qtdemux_parse_moov (qtdemux, map.data, length);
4215 qtdemux_node_dump (qtdemux, qtdemux->moov_node);
4217 qtdemux_parse_tree (qtdemux);
4218 g_node_destroy (qtdemux->moov_node);
4219 gst_buffer_unmap (moov, &map);
4220 gst_buffer_unref (moov);
4221 qtdemux->moov_node = NULL;
4222 qtdemux->got_moov = TRUE;
4228 GstBuffer *ftyp = NULL;
4230 /* extract major brand; might come in handy for ISO vs QT issues */
4231 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &ftyp);
4232 if (ret != GST_FLOW_OK)
4234 qtdemux->offset += length;
4235 gst_buffer_map (ftyp, &map, GST_MAP_READ);
4236 qtdemux_parse_ftyp (qtdemux, map.data, map.size);
4237 gst_buffer_unmap (ftyp, &map);
4238 gst_buffer_unref (ftyp);
4243 GstBuffer *uuid = NULL;
4245 /* uuid are extension atoms */
4246 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &uuid);
4247 if (ret != GST_FLOW_OK)
4249 qtdemux->offset += length;
4250 gst_buffer_map (uuid, &map, GST_MAP_READ);
4251 qtdemux_parse_uuid (qtdemux, map.data, map.size);
4252 gst_buffer_unmap (uuid, &map);
4253 gst_buffer_unref (uuid);
4258 GstBuffer *sidx = NULL;
4259 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &sidx);
4260 if (ret != GST_FLOW_OK)
4262 qtdemux->offset += length;
4263 gst_buffer_map (sidx, &map, GST_MAP_READ);
4264 qtdemux_parse_sidx (qtdemux, map.data, map.size);
4265 gst_buffer_unmap (sidx, &map);
4266 gst_buffer_unref (sidx);
4271 GstBuffer *unknown = NULL;
4273 GST_LOG_OBJECT (qtdemux,
4274 "unknown %08x '%" GST_FOURCC_FORMAT "' of size %" G_GUINT64_FORMAT
4275 " at %" G_GUINT64_FORMAT, fourcc, GST_FOURCC_ARGS (fourcc), length,
4277 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &unknown);
4278 if (ret != GST_FLOW_OK)
4280 gst_buffer_map (unknown, &map, GST_MAP_READ);
4281 GST_MEMDUMP ("Unknown tag", map.data, map.size);
4282 gst_buffer_unmap (unknown, &map);
4283 gst_buffer_unref (unknown);
4284 qtdemux->offset += length;
4290 if (ret == GST_FLOW_EOS && (qtdemux->got_moov || qtdemux->media_caps)) {
4291 /* digested all data, show what we have */
4292 qtdemux_prepare_streams (qtdemux);
4293 ret = qtdemux_expose_streams (qtdemux);
4295 qtdemux->state = QTDEMUX_STATE_MOVIE;
4296 GST_DEBUG_OBJECT (qtdemux, "switching state to STATE_MOVIE (%d)",
4303 /* Seeks to the previous keyframe of the indexed stream and
4304 * aligns other streams with respect to the keyframe timestamp
4305 * of indexed stream. Only called in case of Reverse Playback
4307 static GstFlowReturn
4308 gst_qtdemux_seek_to_previous_keyframe (GstQTDemux * qtdemux)
4311 guint32 seg_idx = 0, k_index = 0;
4312 guint32 ref_seg_idx, ref_k_index;
4313 GstClockTime k_pos = 0, last_stop = 0;
4314 QtDemuxSegment *seg = NULL;
4315 QtDemuxStream *ref_str = NULL;
4316 guint64 seg_media_start_mov; /* segment media start time in mov format */
4319 /* Now we choose an arbitrary stream, get the previous keyframe timestamp
4320 * and finally align all the other streams on that timestamp with their
4321 * respective keyframes */
4322 for (n = 0; n < qtdemux->n_streams; n++) {
4323 QtDemuxStream *str = qtdemux->streams[n];
4325 /* No candidate yet, take the first stream */
4331 /* So that stream has a segment, we prefer video streams */
4332 if (str->subtype == FOURCC_vide) {
4338 if (G_UNLIKELY (!ref_str)) {
4339 GST_DEBUG_OBJECT (qtdemux, "couldn't find any stream");
4343 if (G_UNLIKELY (!ref_str->from_sample)) {
4344 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of the file");
4348 /* So that stream has been playing from from_sample to to_sample. We will
4349 * get the timestamp of the previous sample and search for a keyframe before
4350 * that. For audio streams we do an arbitrary jump in the past (10 samples) */
4351 if (ref_str->subtype == FOURCC_vide) {
4352 k_index = gst_qtdemux_find_keyframe (qtdemux, ref_str,
4353 ref_str->from_sample - 1);
4355 if (ref_str->from_sample >= 10)
4356 k_index = ref_str->from_sample - 10;
4362 ref_str->samples[k_index].timestamp +
4363 ref_str->samples[k_index].pts_offset;
4365 /* get current segment for that stream */
4366 seg = &ref_str->segments[ref_str->segment_index];
4367 /* Use segment start in original timescale for comparisons */
4368 seg_media_start_mov = seg->trak_media_start;
4370 GST_LOG_OBJECT (qtdemux, "keyframe index %u ts %" G_GUINT64_FORMAT
4371 " seg start %" G_GUINT64_FORMAT " %" GST_TIME_FORMAT "\n",
4372 k_index, target_ts, seg_media_start_mov,
4373 GST_TIME_ARGS (seg->media_start));
4375 /* Crawl back through segments to find the one containing this I frame */
4376 while (target_ts < seg_media_start_mov) {
4377 GST_DEBUG_OBJECT (qtdemux,
4378 "keyframe position (sample %u) is out of segment %u " " target %"
4379 G_GUINT64_FORMAT " seg start %" G_GUINT64_FORMAT, k_index,
4380 ref_str->segment_index, target_ts, seg_media_start_mov);
4382 if (G_UNLIKELY (!ref_str->segment_index)) {
4383 /* Reached first segment, let's consider it's EOS */
4386 ref_str->segment_index--;
4387 seg = &ref_str->segments[ref_str->segment_index];
4388 /* Use segment start in original timescale for comparisons */
4389 seg_media_start_mov = seg->trak_media_start;
4391 /* Calculate time position of the keyframe and where we should stop */
4393 QTSTREAMTIME_TO_GSTTIME (ref_str,
4394 target_ts - seg->trak_media_start) + seg->time;
4396 QTSTREAMTIME_TO_GSTTIME (ref_str,
4397 ref_str->samples[ref_str->from_sample].timestamp -
4398 seg->trak_media_start) + seg->time;
4400 GST_DEBUG_OBJECT (qtdemux, "preferred stream played from sample %u, "
4401 "now going to sample %u (pts %" GST_TIME_FORMAT ")", ref_str->from_sample,
4402 k_index, GST_TIME_ARGS (k_pos));
4404 /* Set last_stop with the keyframe timestamp we pushed of that stream */
4405 qtdemux->segment.position = last_stop;
4406 GST_DEBUG_OBJECT (qtdemux, "last_stop now is %" GST_TIME_FORMAT,
4407 GST_TIME_ARGS (last_stop));
4409 if (G_UNLIKELY (last_stop < qtdemux->segment.start)) {
4410 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of segment");
4414 ref_seg_idx = ref_str->segment_index;
4415 ref_k_index = k_index;
4417 /* Align them all on this */
4418 for (n = 0; n < qtdemux->n_streams; n++) {
4420 GstClockTime seg_time = 0;
4421 QtDemuxStream *str = qtdemux->streams[n];
4423 /* aligning reference stream again might lead to backing up to yet another
4424 * keyframe (due to timestamp rounding issues),
4425 * potentially putting more load on downstream; so let's try to avoid */
4426 if (str == ref_str) {
4427 seg_idx = ref_seg_idx;
4428 seg = &str->segments[seg_idx];
4429 k_index = ref_k_index;
4430 GST_DEBUG_OBJECT (qtdemux, "reference stream %d segment %d, "
4431 "sample at index %d", n, ref_str->segment_index, k_index);
4433 seg_idx = gst_qtdemux_find_segment (qtdemux, str, k_pos);
4434 GST_DEBUG_OBJECT (qtdemux,
4435 "stream %d align segment %d for keyframe pos %" GST_TIME_FORMAT, n,
4436 seg_idx, GST_TIME_ARGS (k_pos));
4438 /* get segment and time in the segment */
4439 seg = &str->segments[seg_idx];
4440 seg_time = k_pos - seg->time;
4442 /* get the media time in the segment.
4443 * No adjustment for empty "filler" segments */
4444 if (seg->media_start != GST_CLOCK_TIME_NONE)
4445 seg_time += seg->media_start;
4447 /* get the index of the sample with media time */
4448 index = gst_qtdemux_find_index_linear (qtdemux, str, seg_time);
4449 GST_DEBUG_OBJECT (qtdemux,
4450 "stream %d sample for %" GST_TIME_FORMAT " at %u", n,
4451 GST_TIME_ARGS (seg_time), index);
4453 /* find previous keyframe */
4454 k_index = gst_qtdemux_find_keyframe (qtdemux, str, index);
4457 /* Remember until where we want to go */
4458 str->to_sample = str->from_sample - 1;
4459 /* Define our time position */
4461 str->samples[k_index].timestamp + str->samples[k_index].pts_offset;
4462 str->time_position = QTSTREAMTIME_TO_GSTTIME (str, target_ts) + seg->time;
4463 if (seg->media_start != GST_CLOCK_TIME_NONE)
4464 str->time_position -= seg->media_start;
4466 /* Now seek back in time */
4467 gst_qtdemux_move_stream (qtdemux, str, k_index);
4468 GST_DEBUG_OBJECT (qtdemux, "stream %d keyframe at %u, time position %"
4469 GST_TIME_FORMAT " playing from sample %u to %u", n, k_index,
4470 GST_TIME_ARGS (str->time_position), str->from_sample, str->to_sample);
4476 return GST_FLOW_EOS;
4480 * Gets the current qt segment start, stop and position for the
4481 * given time offset. This is used in update_segment()
4484 gst_qtdemux_stream_segment_get_boundaries (GstQTDemux * qtdemux,
4485 QtDemuxStream * stream, GstClockTime offset,
4486 GstClockTime * _start, GstClockTime * _stop, GstClockTime * _time)
4488 GstClockTime seg_time;
4489 GstClockTime start, stop, time;
4490 QtDemuxSegment *segment;
4492 segment = &stream->segments[stream->segment_index];
4494 /* get time in this segment */
4495 seg_time = (offset - segment->time) * segment->rate;
4497 GST_LOG_OBJECT (stream->pad, "seg_time %" GST_TIME_FORMAT,
4498 GST_TIME_ARGS (seg_time));
4500 if (G_UNLIKELY (seg_time > segment->duration)) {
4501 GST_LOG_OBJECT (stream->pad,
4502 "seg_time > segment->duration %" GST_TIME_FORMAT,
4503 GST_TIME_ARGS (segment->duration));
4504 seg_time = segment->duration;
4507 /* qtdemux->segment.stop is in outside-time-realm, whereas
4508 * segment->media_stop is in track-time-realm.
4510 * In order to compare the two, we need to bring segment.stop
4511 * into the track-time-realm
4513 * FIXME - does this comment still hold? Don't see any conversion here */
4515 stop = qtdemux->segment.stop;
4516 if (stop == GST_CLOCK_TIME_NONE)
4517 stop = qtdemux->segment.duration;
4518 if (stop == GST_CLOCK_TIME_NONE)
4519 stop = segment->media_stop;
4522 MIN (segment->media_stop, stop - segment->time + segment->media_start);
4524 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
4525 start = segment->time + seg_time;
4527 stop = start - seg_time + segment->duration;
4528 } else if (qtdemux->segment.rate >= 0) {
4529 start = MIN (segment->media_start + seg_time, stop);
4532 if (segment->media_start >= qtdemux->segment.start) {
4533 time = segment->time;
4535 time = segment->time + (qtdemux->segment.start - segment->media_start);
4538 start = MAX (segment->media_start, qtdemux->segment.start);
4539 stop = MIN (segment->media_start + seg_time, stop);
4548 * Updates the qt segment used for the stream and pushes a new segment event
4549 * downstream on this stream's pad.
4552 gst_qtdemux_stream_update_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
4553 gint seg_idx, GstClockTime offset, GstClockTime * _start,
4554 GstClockTime * _stop)
4556 QtDemuxSegment *segment;
4557 GstClockTime start = 0, stop = GST_CLOCK_TIME_NONE, time = 0;
4561 /* update the current segment */
4562 stream->segment_index = seg_idx;
4564 /* get the segment */
4565 segment = &stream->segments[seg_idx];
4567 if (G_UNLIKELY (offset < segment->time)) {
4568 GST_WARNING_OBJECT (stream->pad, "offset < segment->time %" GST_TIME_FORMAT,
4569 GST_TIME_ARGS (segment->time));
4573 /* segment lies beyond total indicated duration */
4574 if (G_UNLIKELY (qtdemux->segment.duration != GST_CLOCK_TIME_NONE &&
4575 segment->time > qtdemux->segment.duration)) {
4576 GST_WARNING_OBJECT (stream->pad, "file duration %" GST_TIME_FORMAT
4577 " < segment->time %" GST_TIME_FORMAT,
4578 GST_TIME_ARGS (qtdemux->segment.duration),
4579 GST_TIME_ARGS (segment->time));
4583 gst_qtdemux_stream_segment_get_boundaries (qtdemux, stream, offset,
4584 &start, &stop, &time);
4586 GST_DEBUG_OBJECT (stream->pad, "new segment %d from %" GST_TIME_FORMAT
4587 " to %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT, seg_idx,
4588 GST_TIME_ARGS (start), GST_TIME_ARGS (stop), GST_TIME_ARGS (time));
4590 /* combine global rate with that of the segment */
4591 rate = segment->rate * qtdemux->segment.rate;
4593 /* Copy flags from main segment */
4594 stream->segment.flags = qtdemux->segment.flags;
4596 /* update the segment values used for clipping */
4597 stream->segment.offset = qtdemux->segment.offset;
4598 stream->segment.base = qtdemux->segment.base + stream->accumulated_base;
4599 stream->segment.applied_rate = qtdemux->segment.applied_rate;
4600 stream->segment.rate = rate;
4601 stream->segment.start = start + QTSTREAMTIME_TO_GSTTIME (stream,
4602 stream->cslg_shift);
4603 stream->segment.stop = stop + QTSTREAMTIME_TO_GSTTIME (stream,
4604 stream->cslg_shift);
4605 stream->segment.time = time;
4606 stream->segment.position = stream->segment.start;
4608 GST_DEBUG_OBJECT (stream->pad, "New segment: %" GST_SEGMENT_FORMAT,
4611 /* now prepare and send the segment */
4613 event = gst_event_new_segment (&stream->segment);
4614 if (qtdemux->segment_seqnum) {
4615 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
4617 gst_pad_push_event (stream->pad, event);
4618 /* assume we can send more data now */
4619 GST_PAD_LAST_FLOW_RETURN (stream->pad) = GST_FLOW_OK;
4620 /* clear to send tags on this pad now */
4621 gst_qtdemux_push_tags (qtdemux, stream);
4632 /* activate the given segment number @seg_idx of @stream at time @offset.
4633 * @offset is an absolute global position over all the segments.
4635 * This will push out a NEWSEGMENT event with the right values and
4636 * position the stream index to the first decodable sample before
4640 gst_qtdemux_activate_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
4641 guint32 seg_idx, GstClockTime offset)
4643 QtDemuxSegment *segment;
4644 guint32 index, kf_index;
4645 GstClockTime start = 0, stop = GST_CLOCK_TIME_NONE;
4647 GST_LOG_OBJECT (stream->pad, "activate segment %d, offset %" GST_TIME_FORMAT,
4648 seg_idx, GST_TIME_ARGS (offset));
4650 if (!gst_qtdemux_stream_update_segment (qtdemux, stream, seg_idx, offset,
4654 segment = &stream->segments[stream->segment_index];
4656 /* in the fragmented case, we pick a fragment that starts before our
4657 * desired position and rely on downstream to wait for a keyframe
4658 * (FIXME: doesn't seem to work so well with ismv and wmv, as no parser; the
4659 * tfra entries tells us which trun/sample the key unit is in, but we don't
4660 * make use of this additional information at the moment) */
4661 if (qtdemux->fragmented) {
4662 stream->to_sample = G_MAXUINT32;
4666 /* We don't need to look for a sample in push-based */
4667 if (!qtdemux->pullbased)
4670 /* and move to the keyframe before the indicated media time of the
4672 if (G_LIKELY (!QTSEGMENT_IS_EMPTY (segment))) {
4673 if (qtdemux->segment.rate >= 0) {
4674 index = gst_qtdemux_find_index_linear (qtdemux, stream, start);
4675 stream->to_sample = G_MAXUINT32;
4676 GST_DEBUG_OBJECT (stream->pad,
4677 "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
4678 GST_TIME_FORMAT, GST_TIME_ARGS (start), index,
4679 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
4681 index = gst_qtdemux_find_index_linear (qtdemux, stream, stop);
4682 stream->to_sample = index;
4683 GST_DEBUG_OBJECT (stream->pad,
4684 "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
4685 GST_TIME_FORMAT, GST_TIME_ARGS (stop), index,
4686 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
4689 GST_DEBUG_OBJECT (stream->pad, "No need to look for keyframe, "
4690 "this is an empty segment");
4694 /* gst_qtdemux_parse_sample () called from gst_qtdemux_find_index_linear ()
4695 * encountered an error and printed a message so we return appropriately */
4699 /* we're at the right spot */
4700 if (index == stream->sample_index) {
4701 GST_DEBUG_OBJECT (stream->pad, "we are at the right index");
4705 /* find keyframe of the target index */
4706 kf_index = gst_qtdemux_find_keyframe (qtdemux, stream, index);
4709 /* indent does stupid stuff with stream->samples[].timestamp */
4711 /* if we move forwards, we don't have to go back to the previous
4712 * keyframe since we already sent that. We can also just jump to
4713 * the keyframe right before the target index if there is one. */
4714 if (index > stream->sample_index) {
4715 /* moving forwards check if we move past a keyframe */
4716 if (kf_index > stream->sample_index) {
4717 GST_DEBUG_OBJECT (stream->pad,
4718 "moving forwards to keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" )", kf_index,
4719 GST_TIME_ARGS (QTSAMPLE_PTS(stream, &stream->samples[kf_index])),
4720 GST_TIME_ARGS (QTSAMPLE_DTS(stream, &stream->samples[kf_index])));
4721 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
4723 GST_DEBUG_OBJECT (stream->pad,
4724 "moving forwards, keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" ) already sent", kf_index,
4725 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[kf_index])),
4726 GST_TIME_ARGS (QTSAMPLE_DTS (stream, &stream->samples[kf_index])));
4729 GST_DEBUG_OBJECT (stream->pad,
4730 "moving backwards to keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" )", kf_index,
4731 GST_TIME_ARGS (QTSAMPLE_PTS(stream, &stream->samples[kf_index])),
4732 GST_TIME_ARGS (QTSAMPLE_DTS(stream, &stream->samples[kf_index])));
4733 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
4741 /* prepare to get the current sample of @stream, getting essential values.
4743 * This function will also prepare and send the segment when needed.
4745 * Return FALSE if the stream is EOS.
4750 gst_qtdemux_prepare_current_sample (GstQTDemux * qtdemux,
4751 QtDemuxStream * stream, gboolean * empty, guint64 * offset, guint * size,
4752 GstClockTime * dts, GstClockTime * pts, GstClockTime * duration,
4753 gboolean * keyframe)
4755 QtDemuxSample *sample;
4756 GstClockTime time_position;
4759 g_return_val_if_fail (stream != NULL, FALSE);
4761 time_position = stream->time_position;
4762 if (G_UNLIKELY (time_position == GST_CLOCK_TIME_NONE))
4765 seg_idx = stream->segment_index;
4766 if (G_UNLIKELY (seg_idx == -1)) {
4767 /* find segment corresponding to time_position if we are looking
4769 seg_idx = gst_qtdemux_find_segment (qtdemux, stream, time_position);
4772 /* different segment, activate it, sample_index will be set. */
4773 if (G_UNLIKELY (stream->segment_index != seg_idx))
4774 gst_qtdemux_activate_segment (qtdemux, stream, seg_idx, time_position);
4776 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (&stream->segments[stream->
4778 QtDemuxSegment *seg = &stream->segments[stream->segment_index];
4780 GST_LOG_OBJECT (qtdemux, "Empty segment activated,"
4781 " prepare empty sample");
4784 *pts = *dts = time_position;
4785 *duration = seg->duration - (time_position - seg->time);
4792 if (stream->sample_index == -1)
4793 stream->sample_index = 0;
4795 GST_LOG_OBJECT (qtdemux, "segment active, index = %u of %u",
4796 stream->sample_index, stream->n_samples);
4798 if (G_UNLIKELY (stream->sample_index >= stream->n_samples)) {
4799 if (!qtdemux->fragmented)
4802 GST_INFO_OBJECT (qtdemux, "out of samples, trying to add more");
4806 GST_OBJECT_LOCK (qtdemux);
4807 flow = qtdemux_add_fragmented_samples (qtdemux);
4808 GST_OBJECT_UNLOCK (qtdemux);
4810 if (flow != GST_FLOW_OK)
4813 while (stream->sample_index >= stream->n_samples);
4816 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
4817 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
4818 stream->sample_index);
4822 /* now get the info for the sample we're at */
4823 sample = &stream->samples[stream->sample_index];
4825 *dts = QTSAMPLE_DTS (stream, sample);
4826 *pts = QTSAMPLE_PTS (stream, sample);
4827 *offset = sample->offset;
4828 *size = sample->size;
4829 *duration = QTSAMPLE_DUR_DTS (stream, sample, *dts);
4830 *keyframe = QTSAMPLE_KEYFRAME (stream, sample);
4837 stream->time_position = GST_CLOCK_TIME_NONE;
4842 /* move to the next sample in @stream.
4844 * Moves to the next segment when needed.
4847 gst_qtdemux_advance_sample (GstQTDemux * qtdemux, QtDemuxStream * stream)
4849 QtDemuxSample *sample;
4850 QtDemuxSegment *segment;
4852 /* get current segment */
4853 segment = &stream->segments[stream->segment_index];
4855 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
4856 GST_DEBUG_OBJECT (qtdemux, "Empty segment, no samples to advance");
4860 if (G_UNLIKELY (stream->sample_index >= stream->to_sample)) {
4861 /* Mark the stream as EOS */
4862 GST_DEBUG_OBJECT (qtdemux,
4863 "reached max allowed sample %u, mark EOS", stream->to_sample);
4864 stream->time_position = GST_CLOCK_TIME_NONE;
4868 /* move to next sample */
4869 stream->sample_index++;
4870 stream->offset_in_sample = 0;
4872 /* reached the last sample, we need the next segment */
4873 if (G_UNLIKELY (stream->sample_index >= stream->n_samples))
4876 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
4877 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
4878 stream->sample_index);
4882 /* get next sample */
4883 sample = &stream->samples[stream->sample_index];
4885 /* see if we are past the segment */
4886 if (G_UNLIKELY (QTSAMPLE_DTS (stream, sample) >= segment->media_stop))
4889 if (QTSAMPLE_DTS (stream, sample) >= segment->media_start) {
4890 /* inside the segment, update time_position, looks very familiar to
4891 * GStreamer segments, doesn't it? */
4892 stream->time_position =
4893 QTSAMPLE_DTS (stream, sample) - segment->media_start + segment->time;
4895 /* not yet in segment, time does not yet increment. This means
4896 * that we are still prerolling keyframes to the decoder so it can
4897 * decode the first sample of the segment. */
4898 stream->time_position = segment->time;
4902 /* move to the next segment */
4905 GST_DEBUG_OBJECT (qtdemux, "segment %d ended ", stream->segment_index);
4907 if (stream->segment_index == stream->n_segments - 1) {
4908 /* are we at the end of the last segment, we're EOS */
4909 stream->time_position = GST_CLOCK_TIME_NONE;
4911 /* else we're only at the end of the current segment */
4912 stream->time_position = segment->stop_time;
4914 /* make sure we select a new segment */
4916 /* accumulate previous segments */
4917 if (GST_CLOCK_TIME_IS_VALID (stream->segment.stop))
4918 stream->accumulated_base +=
4919 (stream->segment.stop -
4920 stream->segment.start) / ABS (stream->segment.rate);
4922 stream->segment_index = -1;
4927 gst_qtdemux_sync_streams (GstQTDemux * demux)
4931 if (demux->n_streams <= 1)
4934 for (i = 0; i < demux->n_streams; i++) {
4935 QtDemuxStream *stream;
4936 GstClockTime end_time;
4938 stream = demux->streams[i];
4943 /* TODO advance time on subtitle streams here, if any some day */
4945 /* some clips/trailers may have unbalanced streams at the end,
4946 * so send EOS on shorter stream to prevent stalling others */
4948 /* do not mess with EOS if SEGMENT seeking */
4949 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT)
4952 if (demux->pullbased) {
4953 /* loop mode is sample time based */
4954 if (!STREAM_IS_EOS (stream))
4957 /* push mode is byte position based */
4958 if (stream->n_samples &&
4959 stream->samples[stream->n_samples - 1].offset >= demux->offset)
4963 if (stream->sent_eos)
4966 /* only act if some gap */
4967 end_time = stream->segments[stream->n_segments - 1].stop_time;
4968 GST_LOG_OBJECT (demux, "current position: %" GST_TIME_FORMAT
4969 ", stream end: %" GST_TIME_FORMAT,
4970 GST_TIME_ARGS (demux->segment.position), GST_TIME_ARGS (end_time));
4971 if (GST_CLOCK_TIME_IS_VALID (end_time)
4972 && (end_time + 2 * GST_SECOND < demux->segment.position)) {
4975 GST_DEBUG_OBJECT (demux, "sending EOS for stream %s",
4976 GST_PAD_NAME (stream->pad));
4977 stream->sent_eos = TRUE;
4978 event = gst_event_new_eos ();
4979 if (demux->segment_seqnum)
4980 gst_event_set_seqnum (event, demux->segment_seqnum);
4981 gst_pad_push_event (stream->pad, event);
4986 /* EOS and NOT_LINKED need to be combined. This means that we return:
4988 * GST_FLOW_NOT_LINKED: when all pads NOT_LINKED.
4989 * GST_FLOW_EOS: when all pads EOS or NOT_LINKED.
4991 static GstFlowReturn
4992 gst_qtdemux_combine_flows (GstQTDemux * demux, QtDemuxStream * stream,
4995 GST_LOG_OBJECT (demux, "flow return: %s", gst_flow_get_name (ret));
4998 ret = gst_flow_combiner_update_pad_flow (demux->flowcombiner, stream->pad,
5001 ret = gst_flow_combiner_update_flow (demux->flowcombiner, ret);
5003 GST_LOG_OBJECT (demux, "combined flow return: %s", gst_flow_get_name (ret));
5007 /* the input buffer metadata must be writable. Returns NULL when the buffer is
5008 * completely clipped
5010 * Should be used only with raw buffers */
5012 gst_qtdemux_clip_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
5015 guint64 start, stop, cstart, cstop, diff;
5016 GstClockTime pts, duration;
5018 gint num_rate, denom_rate;
5023 osize = size = gst_buffer_get_size (buf);
5026 /* depending on the type, setup the clip parameters */
5027 if (stream->subtype == FOURCC_soun) {
5028 frame_size = stream->bytes_per_frame;
5029 num_rate = GST_SECOND;
5030 denom_rate = (gint) stream->rate;
5032 } else if (stream->subtype == FOURCC_vide) {
5034 num_rate = stream->fps_n;
5035 denom_rate = stream->fps_d;
5040 if (frame_size <= 0)
5041 goto bad_frame_size;
5043 /* we can only clip if we have a valid pts */
5044 pts = GST_BUFFER_PTS (buf);
5045 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (pts)))
5048 duration = GST_BUFFER_DURATION (buf);
5050 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (duration))) {
5052 gst_util_uint64_scale_int (size / frame_size, num_rate, denom_rate);
5056 stop = start + duration;
5058 if (G_UNLIKELY (!gst_segment_clip (&stream->segment,
5059 GST_FORMAT_TIME, start, stop, &cstart, &cstop)))
5062 /* see if some clipping happened */
5063 diff = cstart - start;
5069 /* bring clipped time to samples and to bytes */
5070 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
5073 GST_DEBUG_OBJECT (qtdemux,
5074 "clipping start to %" GST_TIME_FORMAT " %"
5075 G_GUINT64_FORMAT " bytes", GST_TIME_ARGS (cstart), diff);
5081 diff = stop - cstop;
5086 /* bring clipped time to samples and then to bytes */
5087 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
5089 GST_DEBUG_OBJECT (qtdemux,
5090 "clipping stop to %" GST_TIME_FORMAT " %" G_GUINT64_FORMAT
5091 " bytes", GST_TIME_ARGS (cstop), diff);
5096 if (offset != 0 || size != osize)
5097 gst_buffer_resize (buf, offset, size);
5099 GST_BUFFER_DTS (buf) = GST_CLOCK_TIME_NONE;
5100 GST_BUFFER_PTS (buf) = pts;
5101 GST_BUFFER_DURATION (buf) = duration;
5105 /* dropped buffer */
5108 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
5113 GST_DEBUG_OBJECT (qtdemux, "bad frame size");
5118 GST_DEBUG_OBJECT (qtdemux, "no pts on buffer");
5123 GST_DEBUG_OBJECT (qtdemux, "clipped buffer");
5124 gst_buffer_unref (buf);
5129 /* the input buffer metadata must be writable,
5130 * but time/duration etc not yet set and need not be preserved */
5132 gst_qtdemux_process_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
5139 /* not many cases for now */
5140 if (G_UNLIKELY (stream->fourcc == FOURCC_mp4s)) {
5141 /* send a one time dvd clut event */
5142 if (stream->pending_event && stream->pad)
5143 gst_pad_push_event (stream->pad, stream->pending_event);
5144 stream->pending_event = NULL;
5147 if (G_UNLIKELY (stream->subtype != FOURCC_text
5148 && stream->subtype != FOURCC_sbtl &&
5149 stream->subtype != FOURCC_subp)) {
5153 gst_buffer_map (buf, &map, GST_MAP_READ);
5155 /* empty buffer is sent to terminate previous subtitle */
5156 if (map.size <= 2) {
5157 gst_buffer_unmap (buf, &map);
5158 gst_buffer_unref (buf);
5161 if (stream->subtype == FOURCC_subp) {
5162 /* That's all the processing needed for subpictures */
5163 gst_buffer_unmap (buf, &map);
5167 nsize = GST_READ_UINT16_BE (map.data);
5168 nsize = MIN (nsize, map.size - 2);
5170 GST_LOG_OBJECT (qtdemux, "3GPP timed text subtitle: %d/%" G_GSIZE_FORMAT "",
5173 /* takes care of UTF-8 validation or UTF-16 recognition,
5174 * no other encoding expected */
5175 str = gst_tag_freeform_string_to_utf8 ((gchar *) map.data + 2, nsize, NULL);
5176 gst_buffer_unmap (buf, &map);
5178 gst_buffer_unref (buf);
5179 buf = _gst_buffer_new_wrapped (str, strlen (str), g_free);
5181 /* this should not really happen unless the subtitle is corrupted */
5182 gst_buffer_unref (buf);
5186 /* FIXME ? convert optional subsequent style info to markup */
5191 /* Sets a buffer's attributes properly and pushes it downstream.
5192 * Also checks for additional actions and custom processing that may
5193 * need to be done first.
5195 static GstFlowReturn
5196 gst_qtdemux_decorate_and_push_buffer (GstQTDemux * qtdemux,
5197 QtDemuxStream * stream, GstBuffer * buf,
5198 GstClockTime dts, GstClockTime pts, GstClockTime duration,
5199 gboolean keyframe, GstClockTime position, guint64 byte_position)
5201 GstFlowReturn ret = GST_FLOW_OK;
5203 /* offset the timestamps according to the edit list */
5205 if (G_UNLIKELY (stream->fourcc == FOURCC_rtsp)) {
5209 gst_buffer_map (buf, &map, GST_MAP_READ);
5210 url = g_strndup ((gchar *) map.data, map.size);
5211 gst_buffer_unmap (buf, &map);
5212 if (url != NULL && strlen (url) != 0) {
5213 /* we have RTSP redirect now */
5214 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
5215 gst_message_new_element (GST_OBJECT_CAST (qtdemux),
5216 gst_structure_new ("redirect",
5217 "new-location", G_TYPE_STRING, url, NULL)));
5218 qtdemux->posted_redirect = TRUE;
5220 GST_WARNING_OBJECT (qtdemux, "Redirect URI of stream is empty, not "
5226 /* position reporting */
5227 if (qtdemux->segment.rate >= 0) {
5228 qtdemux->segment.position = position;
5229 gst_qtdemux_sync_streams (qtdemux);
5232 if (G_UNLIKELY (!stream->pad)) {
5233 GST_DEBUG_OBJECT (qtdemux, "No output pad for stream, ignoring");
5234 gst_buffer_unref (buf);
5238 /* send out pending buffers */
5239 while (stream->buffers) {
5240 GstBuffer *buffer = (GstBuffer *) stream->buffers->data;
5242 if (G_UNLIKELY (stream->discont)) {
5243 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
5244 GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
5245 stream->discont = FALSE;
5247 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
5250 gst_pad_push (stream->pad, buffer);
5252 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
5255 /* we're going to modify the metadata */
5256 buf = gst_buffer_make_writable (buf);
5258 if (G_UNLIKELY (stream->need_process))
5259 buf = gst_qtdemux_process_buffer (qtdemux, stream, buf);
5265 GST_BUFFER_DTS (buf) = dts;
5266 GST_BUFFER_PTS (buf) = pts;
5267 GST_BUFFER_DURATION (buf) = duration;
5268 GST_BUFFER_OFFSET (buf) = -1;
5269 GST_BUFFER_OFFSET_END (buf) = -1;
5271 if (G_UNLIKELY (stream->rgb8_palette))
5272 gst_buffer_append_memory (buf, gst_memory_ref (stream->rgb8_palette));
5274 if (G_UNLIKELY (stream->padding)) {
5275 gst_buffer_resize (buf, stream->padding, -1);
5278 if (G_UNLIKELY (qtdemux->element_index)) {
5279 GstClockTime stream_time;
5282 gst_segment_to_stream_time (&stream->segment, GST_FORMAT_TIME,
5284 if (GST_CLOCK_TIME_IS_VALID (stream_time)) {
5285 GST_LOG_OBJECT (qtdemux,
5286 "adding association %" GST_TIME_FORMAT "-> %"
5287 G_GUINT64_FORMAT, GST_TIME_ARGS (stream_time), byte_position);
5288 gst_index_add_association (qtdemux->element_index,
5290 keyframe ? GST_ASSOCIATION_FLAG_KEY_UNIT :
5291 GST_ASSOCIATION_FLAG_DELTA_UNIT, GST_FORMAT_TIME, stream_time,
5292 GST_FORMAT_BYTES, byte_position, NULL);
5297 if (stream->need_clip)
5298 buf = gst_qtdemux_clip_buffer (qtdemux, stream, buf);
5300 if (G_UNLIKELY (buf == NULL))
5303 if (G_UNLIKELY (stream->discont)) {
5304 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
5305 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
5306 stream->discont = FALSE;
5308 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
5312 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
5313 stream->on_keyframe = FALSE;
5315 stream->on_keyframe = TRUE;
5319 GST_LOG_OBJECT (qtdemux,
5320 "Pushing buffer with dts %" GST_TIME_FORMAT ", pts %" GST_TIME_FORMAT
5321 ", duration %" GST_TIME_FORMAT " on pad %s", GST_TIME_ARGS (dts),
5322 GST_TIME_ARGS (pts), GST_TIME_ARGS (duration),
5323 GST_PAD_NAME (stream->pad));
5325 if (stream->protected && stream->protection_scheme_type == FOURCC_cenc) {
5326 GstStructure *crypto_info;
5327 QtDemuxCencSampleSetInfo *info =
5328 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
5332 while ((event = g_queue_pop_head (&stream->protection_scheme_event_queue))) {
5333 gst_pad_push_event (stream->pad, event);
5336 if (info->crypto_info == NULL) {
5337 GST_DEBUG_OBJECT (qtdemux, "cenc metadata hasn't been parsed yet");
5338 gst_buffer_unref (buf);
5342 index = stream->sample_index - (stream->n_samples - info->crypto_info->len);
5343 if (G_LIKELY (index >= 0 && index < info->crypto_info->len)) {
5344 /* steal structure from array */
5345 crypto_info = g_ptr_array_index (info->crypto_info, index);
5346 g_ptr_array_index (info->crypto_info, index) = NULL;
5347 GST_LOG_OBJECT (qtdemux, "attaching cenc metadata [%u]", index);
5348 if (!crypto_info || !gst_buffer_add_protection_meta (buf, crypto_info))
5349 GST_ERROR_OBJECT (qtdemux, "failed to attach cenc metadata to buffer");
5353 ret = gst_pad_push (stream->pad, buf);
5355 if (GST_CLOCK_TIME_IS_VALID (pts) && GST_CLOCK_TIME_IS_VALID (duration)) {
5356 /* mark position in stream, we'll need this to know when to send GAP event */
5357 stream->segment.position = pts + duration;
5364 static const QtDemuxRandomAccessEntry *
5365 gst_qtdemux_stream_seek_fragment (GstQTDemux * qtdemux, QtDemuxStream * stream,
5366 GstClockTime pos, gboolean after)
5368 QtDemuxRandomAccessEntry *entries = stream->ra_entries;
5369 guint n_entries = stream->n_ra_entries;
5372 /* we assume the table is sorted */
5373 for (i = 0; i < n_entries; ++i) {
5374 if (entries[i].ts > pos)
5378 /* FIXME: maybe save first moof_offset somewhere instead, but for now it's
5379 * probably okay to assume that the index lists the very first fragment */
5386 return &entries[i - 1];
5390 gst_qtdemux_do_fragmented_seek (GstQTDemux * qtdemux)
5392 const QtDemuxRandomAccessEntry *best_entry = NULL;
5395 GST_OBJECT_LOCK (qtdemux);
5397 g_assert (qtdemux->n_streams > 0);
5399 for (i = 0; i < qtdemux->n_streams; i++) {
5400 const QtDemuxRandomAccessEntry *entry;
5401 QtDemuxStream *stream;
5402 gboolean is_audio_or_video;
5404 stream = qtdemux->streams[i];
5406 g_free (stream->samples);
5407 stream->samples = NULL;
5408 stream->n_samples = 0;
5409 stream->stbl_index = -1; /* no samples have yet been parsed */
5410 stream->sample_index = -1;
5412 if (stream->ra_entries == NULL)
5415 if (stream->subtype == FOURCC_vide || stream->subtype == FOURCC_soun)
5416 is_audio_or_video = TRUE;
5418 is_audio_or_video = FALSE;
5421 gst_qtdemux_stream_seek_fragment (qtdemux, stream,
5422 stream->time_position, !is_audio_or_video);
5424 GST_INFO_OBJECT (stream->pad, "%" GST_TIME_FORMAT " at offset "
5425 "%" G_GUINT64_FORMAT, GST_TIME_ARGS (entry->ts), entry->moof_offset);
5427 stream->pending_seek = entry;
5429 /* decide position to jump to just based on audio/video tracks, not subs */
5430 if (!is_audio_or_video)
5433 if (best_entry == NULL || entry->moof_offset < best_entry->moof_offset)
5437 if (best_entry == NULL) {
5438 GST_OBJECT_UNLOCK (qtdemux);
5442 GST_INFO_OBJECT (qtdemux, "seek to %" GST_TIME_FORMAT ", best fragment "
5443 "moof offset: %" G_GUINT64_FORMAT ", ts %" GST_TIME_FORMAT,
5444 GST_TIME_ARGS (qtdemux->streams[0]->time_position),
5445 best_entry->moof_offset, GST_TIME_ARGS (best_entry->ts));
5447 qtdemux->moof_offset = best_entry->moof_offset;
5449 qtdemux_add_fragmented_samples (qtdemux);
5451 GST_OBJECT_UNLOCK (qtdemux);
5455 static GstFlowReturn
5456 gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux)
5458 GstFlowReturn ret = GST_FLOW_OK;
5459 GstBuffer *buf = NULL;
5460 QtDemuxStream *stream;
5461 GstClockTime min_time;
5463 GstClockTime dts = GST_CLOCK_TIME_NONE;
5464 GstClockTime pts = GST_CLOCK_TIME_NONE;
5465 GstClockTime duration = 0;
5466 gboolean keyframe = FALSE;
5467 guint sample_size = 0;
5473 gst_qtdemux_push_pending_newsegment (qtdemux);
5475 if (qtdemux->fragmented_seek_pending) {
5476 GST_INFO_OBJECT (qtdemux, "pending fragmented seek");
5477 gst_qtdemux_do_fragmented_seek (qtdemux);
5478 GST_INFO_OBJECT (qtdemux, "fragmented seek done!");
5479 qtdemux->fragmented_seek_pending = FALSE;
5482 /* Figure out the next stream sample to output, min_time is expressed in
5483 * global time and runs over the edit list segments. */
5484 min_time = G_MAXUINT64;
5486 for (i = 0; i < qtdemux->n_streams; i++) {
5487 GstClockTime position;
5489 stream = qtdemux->streams[i];
5490 position = stream->time_position;
5492 /* position of -1 is EOS */
5493 if (position != GST_CLOCK_TIME_NONE && position < min_time) {
5494 min_time = position;
5499 if (G_UNLIKELY (index == -1)) {
5500 GST_DEBUG_OBJECT (qtdemux, "all streams are EOS");
5504 /* check for segment end */
5505 if (G_UNLIKELY (qtdemux->segment.stop != -1
5506 && ((qtdemux->segment.rate >= 0 && qtdemux->segment.stop <= min_time)
5507 || (qtdemux->segment.rate < 0
5508 && qtdemux->segment.start > min_time))
5509 && qtdemux->streams[index]->on_keyframe)) {
5510 GST_DEBUG_OBJECT (qtdemux, "we reached the end of our segment.");
5511 qtdemux->streams[index]->time_position = GST_CLOCK_TIME_NONE;
5515 /* gap events for subtitle streams */
5516 for (i = 0; i < qtdemux->n_streams; i++) {
5517 stream = qtdemux->streams[i];
5518 if (stream->pad && (stream->subtype == FOURCC_subp
5519 || stream->subtype == FOURCC_text
5520 || stream->subtype == FOURCC_sbtl)) {
5521 /* send one second gap events until the stream catches up */
5522 /* gaps can only be sent after segment is activated (segment.stop is no longer -1) */
5523 while (GST_CLOCK_TIME_IS_VALID (stream->segment.stop) &&
5524 GST_CLOCK_TIME_IS_VALID (stream->segment.position) &&
5525 stream->segment.position + GST_SECOND < min_time) {
5527 gst_event_new_gap (stream->segment.position, GST_SECOND);
5528 gst_pad_push_event (stream->pad, gap);
5529 stream->segment.position += GST_SECOND;
5534 stream = qtdemux->streams[index];
5535 if (stream->new_caps) {
5536 gst_qtdemux_configure_stream (qtdemux, stream);
5537 qtdemux_do_allocation (qtdemux, stream);
5540 /* fetch info for the current sample of this stream */
5541 if (G_UNLIKELY (!gst_qtdemux_prepare_current_sample (qtdemux, stream, &empty,
5542 &offset, &sample_size, &dts, &pts, &duration, &keyframe)))
5545 /* If we're doing a keyframe-only trickmode, only push keyframes on video streams */
5546 if (G_UNLIKELY (qtdemux->
5547 segment.flags & GST_SEGMENT_FLAG_TRICKMODE_KEY_UNITS)) {
5548 if (stream->subtype == FOURCC_vide && !keyframe) {
5549 GST_LOG_OBJECT (qtdemux, "Skipping non-keyframe on stream %d", index);
5554 GST_DEBUG_OBJECT (qtdemux,
5555 "pushing from stream %d, empty %d offset %" G_GUINT64_FORMAT
5556 ", size %d, dts=%" GST_TIME_FORMAT ", pts=%" GST_TIME_FORMAT
5557 ", duration %" GST_TIME_FORMAT, index, empty, offset, sample_size,
5558 GST_TIME_ARGS (dts), GST_TIME_ARGS (pts), GST_TIME_ARGS (duration));
5560 if (G_UNLIKELY (empty)) {
5561 /* empty segment, push a gap and move to the next one */
5562 gst_pad_push_event (stream->pad, gst_event_new_gap (pts, duration));
5563 stream->segment.position = pts + duration;
5567 /* hmm, empty sample, skip and move to next sample */
5568 if (G_UNLIKELY (sample_size <= 0))
5571 /* last pushed sample was out of boundary, goto next sample */
5572 if (G_UNLIKELY (GST_PAD_LAST_FLOW_RETURN (stream->pad) == GST_FLOW_EOS))
5575 if (stream->max_buffer_size == 0 || sample_size <= stream->max_buffer_size) {
5578 GST_DEBUG_OBJECT (qtdemux,
5579 "size %d larger than stream max_buffer_size %d, trimming",
5580 sample_size, stream->max_buffer_size);
5582 MIN (sample_size - stream->offset_in_sample, stream->max_buffer_size);
5585 if (qtdemux->cenc_aux_info_offset > 0) {
5588 GstBuffer *aux_info = NULL;
5590 /* pull the data stored before the sample */
5592 gst_qtdemux_pull_atom (qtdemux, qtdemux->offset,
5593 offset + stream->offset_in_sample - qtdemux->offset, &aux_info);
5594 if (G_UNLIKELY (ret != GST_FLOW_OK))
5596 gst_buffer_map (aux_info, &map, GST_MAP_READ);
5597 GST_DEBUG_OBJECT (qtdemux, "parsing cenc auxiliary info");
5598 gst_byte_reader_init (&br, map.data + 8, map.size);
5599 if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
5600 qtdemux->cenc_aux_info_sizes, qtdemux->cenc_aux_sample_count)) {
5601 GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
5602 gst_buffer_unmap (aux_info, &map);
5603 gst_buffer_unref (aux_info);
5604 ret = GST_FLOW_ERROR;
5607 gst_buffer_unmap (aux_info, &map);
5608 gst_buffer_unref (aux_info);
5611 GST_LOG_OBJECT (qtdemux, "reading %d bytes @ %" G_GUINT64_FORMAT, size,
5614 if (stream->use_allocator) {
5615 /* if we have a per-stream allocator, use it */
5616 buf = gst_buffer_new_allocate (stream->allocator, size, &stream->params);
5619 ret = gst_qtdemux_pull_atom (qtdemux, offset + stream->offset_in_sample,
5621 if (G_UNLIKELY (ret != GST_FLOW_OK))
5624 if (size != sample_size) {
5625 pts += gst_util_uint64_scale_int (GST_SECOND,
5626 stream->offset_in_sample / stream->bytes_per_frame, stream->timescale);
5627 dts += gst_util_uint64_scale_int (GST_SECOND,
5628 stream->offset_in_sample / stream->bytes_per_frame, stream->timescale);
5629 duration = gst_util_uint64_scale_int (GST_SECOND,
5630 size / stream->bytes_per_frame, stream->timescale);
5633 ret = gst_qtdemux_decorate_and_push_buffer (qtdemux, stream, buf,
5634 dts, pts, duration, keyframe, min_time, offset);
5636 if (size != sample_size) {
5637 QtDemuxSample *sample = &stream->samples[stream->sample_index];
5638 QtDemuxSegment *segment = &stream->segments[stream->segment_index];
5640 GstClockTime time_position = QTSTREAMTIME_TO_GSTTIME (stream,
5641 sample->timestamp + stream->offset_in_sample / stream->bytes_per_frame);
5642 if (time_position >= segment->media_start) {
5643 /* inside the segment, update time_position, looks very familiar to
5644 * GStreamer segments, doesn't it? */
5645 stream->time_position = (time_position - segment->media_start) +
5648 /* not yet in segment, time does not yet increment. This means
5649 * that we are still prerolling keyframes to the decoder so it can
5650 * decode the first sample of the segment. */
5651 stream->time_position = segment->time;
5656 ret = gst_qtdemux_combine_flows (qtdemux, stream, ret);
5657 /* ignore unlinked, we will not push on the pad anymore and we will EOS when
5658 * we have no more data for the pad to push */
5659 if (ret == GST_FLOW_EOS)
5662 stream->offset_in_sample += size;
5663 if (stream->offset_in_sample >= sample_size) {
5664 gst_qtdemux_advance_sample (qtdemux, stream);
5669 gst_qtdemux_advance_sample (qtdemux, stream);
5677 GST_DEBUG_OBJECT (qtdemux, "No samples left for any streams - EOS");
5683 GST_DEBUG_OBJECT (qtdemux, "No samples left for stream");
5684 /* EOS will be raised if all are EOS */
5691 gst_qtdemux_loop (GstPad * pad)
5693 GstQTDemux *qtdemux;
5697 qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
5699 cur_offset = qtdemux->offset;
5700 GST_LOG_OBJECT (qtdemux, "loop at position %" G_GUINT64_FORMAT ", state %s",
5701 cur_offset, qt_demux_state_string (qtdemux->state));
5703 switch (qtdemux->state) {
5704 case QTDEMUX_STATE_INITIAL:
5705 case QTDEMUX_STATE_HEADER:
5706 ret = gst_qtdemux_loop_state_header (qtdemux);
5708 case QTDEMUX_STATE_MOVIE:
5709 ret = gst_qtdemux_loop_state_movie (qtdemux);
5710 if (qtdemux->segment.rate < 0 && ret == GST_FLOW_EOS) {
5711 ret = gst_qtdemux_seek_to_previous_keyframe (qtdemux);
5719 /* if something went wrong, pause */
5720 if (ret != GST_FLOW_OK)
5724 gst_object_unref (qtdemux);
5730 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
5731 (NULL), ("streaming stopped, invalid state"));
5732 gst_pad_pause_task (pad);
5733 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
5738 const gchar *reason = gst_flow_get_name (ret);
5740 GST_LOG_OBJECT (qtdemux, "pausing task, reason %s", reason);
5742 gst_pad_pause_task (pad);
5744 /* fatal errors need special actions */
5746 if (ret == GST_FLOW_EOS) {
5747 if (qtdemux->n_streams == 0) {
5748 /* we have no streams, post an error */
5749 gst_qtdemux_post_no_playable_stream_error (qtdemux);
5751 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
5754 if ((stop = qtdemux->segment.stop) == -1)
5755 stop = qtdemux->segment.duration;
5757 if (qtdemux->segment.rate >= 0) {
5758 GstMessage *message;
5761 GST_LOG_OBJECT (qtdemux, "Sending segment done, at end of segment");
5762 message = gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
5763 GST_FORMAT_TIME, stop);
5764 event = gst_event_new_segment_done (GST_FORMAT_TIME, stop);
5765 if (qtdemux->segment_seqnum) {
5766 gst_message_set_seqnum (message, qtdemux->segment_seqnum);
5767 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
5769 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), message);
5770 gst_qtdemux_push_event (qtdemux, event);
5772 GstMessage *message;
5775 /* For Reverse Playback */
5776 GST_LOG_OBJECT (qtdemux, "Sending segment done, at start of segment");
5777 message = gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
5778 GST_FORMAT_TIME, qtdemux->segment.start);
5779 event = gst_event_new_segment_done (GST_FORMAT_TIME,
5780 qtdemux->segment.start);
5781 if (qtdemux->segment_seqnum) {
5782 gst_message_set_seqnum (message, qtdemux->segment_seqnum);
5783 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
5785 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), message);
5786 gst_qtdemux_push_event (qtdemux, event);
5791 GST_LOG_OBJECT (qtdemux, "Sending EOS at end of segment");
5792 event = gst_event_new_eos ();
5793 if (qtdemux->segment_seqnum)
5794 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
5795 gst_qtdemux_push_event (qtdemux, event);
5797 } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
5798 GST_ELEMENT_FLOW_ERROR (qtdemux, ret);
5799 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
5808 * Returns if there are samples to be played.
5811 has_next_entry (GstQTDemux * demux)
5813 QtDemuxStream *stream;
5816 GST_DEBUG_OBJECT (demux, "Checking if there are samples not played yet");
5818 for (i = 0; i < demux->n_streams; i++) {
5819 stream = demux->streams[i];
5821 if (stream->sample_index == -1) {
5822 stream->sample_index = 0;
5823 stream->offset_in_sample = 0;
5826 if (stream->sample_index >= stream->n_samples) {
5827 GST_LOG_OBJECT (demux, "stream %d samples exhausted", i);
5830 GST_DEBUG_OBJECT (demux, "Found a sample");
5834 GST_DEBUG_OBJECT (demux, "There wasn't any next sample");
5841 * Returns the size of the first entry at the current offset.
5842 * If -1, there are none (which means EOS or empty file).
5845 next_entry_size (GstQTDemux * demux)
5847 QtDemuxStream *stream;
5850 guint64 smalloffs = (guint64) - 1;
5851 QtDemuxSample *sample;
5853 GST_LOG_OBJECT (demux, "Finding entry at offset %" G_GUINT64_FORMAT,
5856 for (i = 0; i < demux->n_streams; i++) {
5857 stream = demux->streams[i];
5859 if (stream->sample_index == -1) {
5860 stream->sample_index = 0;
5861 stream->offset_in_sample = 0;
5864 if (stream->sample_index >= stream->n_samples) {
5865 GST_LOG_OBJECT (demux, "stream %d samples exhausted", i);
5869 if (!qtdemux_parse_samples (demux, stream, stream->sample_index)) {
5870 GST_LOG_OBJECT (demux, "Parsing of index %u from stbl atom failed!",
5871 stream->sample_index);
5875 sample = &stream->samples[stream->sample_index];
5877 GST_LOG_OBJECT (demux,
5878 "Checking Stream %d (sample_index:%d / offset:%" G_GUINT64_FORMAT
5879 " / size:%" G_GUINT32_FORMAT ")", i, stream->sample_index,
5880 sample->offset, sample->size);
5882 if (((smalloffs == -1)
5883 || (sample->offset < smalloffs)) && (sample->size)) {
5885 smalloffs = sample->offset;
5889 GST_LOG_OBJECT (demux,
5890 "stream %d offset %" G_GUINT64_FORMAT " demux->offset :%"
5891 G_GUINT64_FORMAT, smallidx, smalloffs, demux->offset);
5896 stream = demux->streams[smallidx];
5897 sample = &stream->samples[stream->sample_index];
5899 if (sample->offset >= demux->offset) {
5900 demux->todrop = sample->offset - demux->offset;
5901 return sample->size + demux->todrop;
5904 GST_DEBUG_OBJECT (demux,
5905 "There wasn't any entry at offset %" G_GUINT64_FORMAT, demux->offset);
5910 gst_qtdemux_post_progress (GstQTDemux * demux, gint num, gint denom)
5912 gint perc = (gint) ((gdouble) num * 100.0 / (gdouble) denom);
5914 gst_element_post_message (GST_ELEMENT_CAST (demux),
5915 gst_message_new_element (GST_OBJECT_CAST (demux),
5916 gst_structure_new ("progress", "percent", G_TYPE_INT, perc, NULL)));
5920 qtdemux_seek_offset (GstQTDemux * demux, guint64 offset)
5925 GST_DEBUG_OBJECT (demux, "Seeking to %" G_GUINT64_FORMAT, offset);
5928 gst_event_new_seek (1.0, GST_FORMAT_BYTES,
5929 GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset,
5930 GST_SEEK_TYPE_NONE, -1);
5932 /* store seqnum to drop flush events, they don't need to reach downstream */
5933 demux->offset_seek_seqnum = gst_event_get_seqnum (event);
5934 res = gst_pad_push_event (demux->sinkpad, event);
5935 demux->offset_seek_seqnum = 0;
5940 /* check for seekable upstream, above and beyond a mere query */
5942 gst_qtdemux_check_seekability (GstQTDemux * demux)
5945 gboolean seekable = FALSE;
5946 gint64 start = -1, stop = -1;
5948 if (demux->upstream_size)
5951 query = gst_query_new_seeking (GST_FORMAT_BYTES);
5952 if (!gst_pad_peer_query (demux->sinkpad, query)) {
5953 GST_DEBUG_OBJECT (demux, "seeking query failed");
5957 gst_query_parse_seeking (query, NULL, &seekable, &start, &stop);
5959 /* try harder to query upstream size if we didn't get it the first time */
5960 if (seekable && stop == -1) {
5961 GST_DEBUG_OBJECT (demux, "doing duration query to fix up unset stop");
5962 gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &stop);
5965 /* if upstream doesn't know the size, it's likely that it's not seekable in
5966 * practice even if it technically may be seekable */
5967 if (seekable && (start != 0 || stop <= start)) {
5968 GST_DEBUG_OBJECT (demux, "seekable but unknown start/stop -> disable");
5973 gst_query_unref (query);
5975 GST_DEBUG_OBJECT (demux, "seekable: %d (%" G_GUINT64_FORMAT " - %"
5976 G_GUINT64_FORMAT ")", seekable, start, stop);
5977 demux->upstream_seekable = seekable;
5978 demux->upstream_size = seekable ? stop : -1;
5982 gst_qtdemux_drop_data (GstQTDemux * demux, gint bytes)
5984 g_return_if_fail (bytes <= demux->todrop);
5986 GST_LOG_OBJECT (demux, "Dropping %d bytes", bytes);
5987 gst_adapter_flush (demux->adapter, bytes);
5988 demux->neededbytes -= bytes;
5989 demux->offset += bytes;
5990 demux->todrop -= bytes;
5994 gst_qtdemux_check_send_pending_segment (GstQTDemux * demux)
5996 if (G_UNLIKELY (demux->pending_newsegment)) {
5999 gst_qtdemux_push_pending_newsegment (demux);
6000 /* clear to send tags on all streams */
6001 for (i = 0; i < demux->n_streams; i++) {
6002 QtDemuxStream *stream;
6003 stream = demux->streams[i];
6004 gst_qtdemux_push_tags (demux, stream);
6005 if (stream->sparse) {
6006 GST_INFO_OBJECT (demux, "Sending gap event on stream %d", i);
6007 gst_pad_push_event (stream->pad,
6008 gst_event_new_gap (stream->segment.position, GST_CLOCK_TIME_NONE));
6015 gst_qtdemux_send_gap_for_segment (GstQTDemux * demux,
6016 QtDemuxStream * stream, gint segment_index, GstClockTime pos)
6018 GstClockTime ts, dur;
6023 stream->segments[segment_index].duration - (pos -
6024 stream->segments[segment_index].time);
6025 gap = gst_event_new_gap (ts, dur);
6026 stream->time_position += dur;
6028 GST_DEBUG_OBJECT (stream->pad, "Pushing gap for empty "
6029 "segment: %" GST_PTR_FORMAT, gap);
6030 gst_pad_push_event (stream->pad, gap);
6034 gst_qtdemux_stream_send_initial_gap_segments (GstQTDemux * demux,
6035 QtDemuxStream * stream)
6039 /* Push any initial gap segments before proceeding to the
6041 for (i = 0; i < stream->n_segments; i++) {
6042 gst_qtdemux_activate_segment (demux, stream, i, stream->time_position);
6044 if (QTSEGMENT_IS_EMPTY (&stream->segments[i])) {
6045 gst_qtdemux_send_gap_for_segment (demux, stream, i,
6046 stream->time_position);
6048 /* Only support empty segment at the beginning followed by
6049 * one non-empty segment, this was checked when parsing the
6050 * edts atom, arriving here is unexpected */
6051 g_assert (i + 1 == stream->n_segments);
6057 static GstFlowReturn
6058 gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent, GstBuffer * inbuf)
6062 demux = GST_QTDEMUX (parent);
6064 GST_DEBUG_OBJECT (demux,
6065 "Received buffer pts:%" GST_TIME_FORMAT " dts:%" GST_TIME_FORMAT
6066 " offset:%" G_GUINT64_FORMAT " size:%" G_GSIZE_FORMAT " demux offset:%"
6067 G_GUINT64_FORMAT, GST_TIME_ARGS (GST_BUFFER_PTS (inbuf)),
6068 GST_TIME_ARGS (GST_BUFFER_DTS (inbuf)), GST_BUFFER_OFFSET (inbuf),
6069 gst_buffer_get_size (inbuf), demux->offset);
6071 if (GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_DISCONT)) {
6072 gboolean is_gap_input = FALSE;
6075 GST_DEBUG_OBJECT (demux, "Got DISCONT, marking all streams as DISCONT");
6077 for (i = 0; i < demux->n_streams; i++) {
6078 demux->streams[i]->discont = TRUE;
6081 /* Check if we can land back on our feet in the case where upstream is
6082 * handling the seeking/pushing of samples with gaps in between (like
6083 * in the case of trick-mode DASH for example) */
6084 if (demux->upstream_format_is_time
6085 && GST_BUFFER_OFFSET (inbuf) != GST_BUFFER_OFFSET_NONE) {
6087 for (i = 0; i < demux->n_streams; i++) {
6089 GST_LOG_OBJECT (demux,
6090 "Stream #%d , checking if offset %" G_GUINT64_FORMAT
6091 " is a sample start", i, GST_BUFFER_OFFSET (inbuf));
6093 gst_qtdemux_find_index_for_given_media_offset_linear (demux,
6094 demux->streams[i], GST_BUFFER_OFFSET (inbuf));
6096 QtDemuxSample *sample = &demux->streams[i]->samples[res];
6097 GST_LOG_OBJECT (demux,
6098 "Checking if sample %d from stream %d is valid (offset:%"
6099 G_GUINT64_FORMAT " size:%" G_GUINT32_FORMAT ")", res, i,
6100 sample->offset, sample->size);
6101 if (sample->offset == GST_BUFFER_OFFSET (inbuf)) {
6102 GST_LOG_OBJECT (demux,
6103 "new buffer corresponds to a valid sample : %" G_GUINT32_FORMAT,
6105 is_gap_input = TRUE;
6106 /* We can go back to standard playback mode */
6107 demux->state = QTDEMUX_STATE_MOVIE;
6108 /* Remember which sample this stream is at */
6109 demux->streams[i]->sample_index = res;
6110 /* Finally update all push-based values to the expected values */
6111 demux->neededbytes = demux->streams[i]->samples[res].size;
6113 demux->offset = GST_BUFFER_OFFSET (inbuf);
6117 if (!is_gap_input) {
6118 /* Reset state if it's a real discont */
6119 demux->neededbytes = 16;
6120 demux->state = QTDEMUX_STATE_INITIAL;
6121 demux->offset = GST_BUFFER_OFFSET (inbuf);
6124 /* Reverse fragmented playback, need to flush all we have before
6125 * consuming a new fragment.
6126 * The samples array have the timestamps calculated by accumulating the
6127 * durations but this won't work for reverse playback of fragments as
6128 * the timestamps of a subsequent fragment should be smaller than the
6129 * previously received one. */
6130 if (!is_gap_input && demux->fragmented && demux->segment.rate < 0) {
6131 gst_qtdemux_process_adapter (demux, TRUE);
6132 for (i = 0; i < demux->n_streams; i++)
6133 gst_qtdemux_stream_flush_samples_data (demux, demux->streams[i]);
6137 gst_adapter_push (demux->adapter, inbuf);
6139 GST_DEBUG_OBJECT (demux,
6140 "pushing in inbuf %p, neededbytes:%u, available:%" G_GSIZE_FORMAT, inbuf,
6141 demux->neededbytes, gst_adapter_available (demux->adapter));
6143 return gst_qtdemux_process_adapter (demux, FALSE);
6146 static GstFlowReturn
6147 gst_qtdemux_process_adapter (GstQTDemux * demux, gboolean force)
6149 GstFlowReturn ret = GST_FLOW_OK;
6151 /* we never really mean to buffer that much */
6152 if (demux->neededbytes == -1) {
6156 while (((gst_adapter_available (demux->adapter)) >= demux->neededbytes) &&
6157 (ret == GST_FLOW_OK || (ret == GST_FLOW_NOT_LINKED && force))) {
6159 #ifndef GST_DISABLE_GST_DEBUG
6161 guint64 discont_offset, distance_from_discont;
6163 discont_offset = gst_adapter_offset_at_discont (demux->adapter);
6164 distance_from_discont =
6165 gst_adapter_distance_from_discont (demux->adapter);
6167 GST_DEBUG_OBJECT (demux,
6168 "state:%s , demux->neededbytes:%d, demux->offset:%" G_GUINT64_FORMAT
6169 " adapter offset :%" G_GUINT64_FORMAT " (+ %" G_GUINT64_FORMAT
6170 " bytes)", qt_demux_state_string (demux->state), demux->neededbytes,
6171 demux->offset, discont_offset, distance_from_discont);
6175 switch (demux->state) {
6176 case QTDEMUX_STATE_INITIAL:{
6181 gst_qtdemux_check_seekability (demux);
6183 data = gst_adapter_map (demux->adapter, demux->neededbytes);
6185 /* get fourcc/length, set neededbytes */
6186 extract_initial_length_and_fourcc ((guint8 *) data, demux->neededbytes,
6188 gst_adapter_unmap (demux->adapter);
6190 GST_DEBUG_OBJECT (demux, "Peeking found [%" GST_FOURCC_FORMAT "] "
6191 "size: %" G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), size);
6193 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
6194 (_("This file is invalid and cannot be played.")),
6195 ("initial atom '%" GST_FOURCC_FORMAT "' has empty length",
6196 GST_FOURCC_ARGS (fourcc)));
6197 ret = GST_FLOW_ERROR;
6200 if (fourcc == FOURCC_mdat) {
6201 gint next_entry = next_entry_size (demux);
6202 if (demux->n_streams > 0 && (next_entry != -1 || !demux->fragmented)) {
6203 /* we have the headers, start playback */
6204 demux->state = QTDEMUX_STATE_MOVIE;
6205 demux->neededbytes = next_entry;
6206 demux->mdatleft = size;
6208 /* no headers yet, try to get them */
6211 guint64 old, target;
6214 old = demux->offset;
6215 target = old + size;
6217 /* try to jump over the atom with a seek */
6218 /* only bother if it seems worth doing so,
6219 * and avoids possible upstream/server problems */
6220 if (demux->upstream_seekable &&
6221 demux->upstream_size > 4 * (1 << 20)) {
6222 res = qtdemux_seek_offset (demux, target);
6224 GST_DEBUG_OBJECT (demux, "skipping seek");
6229 GST_DEBUG_OBJECT (demux, "seek success");
6230 /* remember the offset fo the first mdat so we can seek back to it
6231 * after we have the headers */
6232 if (fourcc == FOURCC_mdat && demux->first_mdat == -1) {
6233 demux->first_mdat = old;
6234 GST_DEBUG_OBJECT (demux, "first mdat at %" G_GUINT64_FORMAT,
6237 /* seek worked, continue reading */
6238 demux->offset = target;
6239 demux->neededbytes = 16;
6240 demux->state = QTDEMUX_STATE_INITIAL;
6242 /* seek failed, need to buffer */
6243 demux->offset = old;
6244 GST_DEBUG_OBJECT (demux, "seek failed/skipped");
6245 /* there may be multiple mdat (or alike) buffers */
6247 if (demux->mdatbuffer)
6248 bs = gst_buffer_get_size (demux->mdatbuffer);
6251 if (size + bs > 10 * (1 << 20))
6253 demux->state = QTDEMUX_STATE_BUFFER_MDAT;
6254 demux->neededbytes = size;
6255 if (!demux->mdatbuffer)
6256 demux->mdatoffset = demux->offset;
6259 } else if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
6260 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
6261 (_("This file is invalid and cannot be played.")),
6262 ("atom %" GST_FOURCC_FORMAT " has bogus size %" G_GUINT64_FORMAT,
6263 GST_FOURCC_ARGS (fourcc), size));
6264 ret = GST_FLOW_ERROR;
6267 /* this means we already started buffering and still no moov header,
6268 * let's continue buffering everything till we get moov */
6269 if (demux->mdatbuffer && !(fourcc == FOURCC_moov
6270 || fourcc == FOURCC_moof))
6272 demux->neededbytes = size;
6273 demux->state = QTDEMUX_STATE_HEADER;
6277 case QTDEMUX_STATE_HEADER:{
6281 GST_DEBUG_OBJECT (demux, "In header");
6283 data = gst_adapter_map (demux->adapter, demux->neededbytes);
6285 /* parse the header */
6286 extract_initial_length_and_fourcc (data, demux->neededbytes, NULL,
6288 if (fourcc == FOURCC_moov) {
6291 /* in usual fragmented setup we could try to scan for more
6292 * and end up at the the moov (after mdat) again */
6293 if (demux->got_moov && demux->n_streams > 0 &&
6295 || demux->last_moov_offset == demux->offset)) {
6296 GST_DEBUG_OBJECT (demux,
6297 "Skipping moov atom as we have (this) one already");
6299 GST_DEBUG_OBJECT (demux, "Parsing [moov]");
6301 if (demux->got_moov && demux->fragmented) {
6302 GST_DEBUG_OBJECT (demux,
6303 "Got a second moov, clean up data from old one");
6304 if (demux->moov_node)
6305 g_node_destroy (demux->moov_node);
6306 demux->moov_node = NULL;
6307 demux->moov_node_compressed = NULL;
6309 /* prepare newsegment to send when streaming actually starts */
6310 if (!demux->pending_newsegment) {
6311 demux->pending_newsegment =
6312 gst_event_new_segment (&demux->segment);
6313 if (demux->segment_seqnum)
6314 gst_event_set_seqnum (demux->pending_newsegment,
6315 demux->segment_seqnum);
6319 demux->last_moov_offset = demux->offset;
6321 qtdemux_parse_moov (demux, data, demux->neededbytes);
6322 qtdemux_node_dump (demux, demux->moov_node);
6323 qtdemux_parse_tree (demux);
6324 qtdemux_prepare_streams (demux);
6325 if (!demux->got_moov)
6326 qtdemux_expose_streams (demux);
6329 for (n = 0; n < demux->n_streams; n++) {
6330 QtDemuxStream *stream = demux->streams[n];
6332 gst_qtdemux_configure_stream (demux, stream);
6336 demux->got_moov = TRUE;
6337 gst_qtdemux_check_send_pending_segment (demux);
6339 /* fragmented streams headers shouldn't contain edts atoms */
6340 if (!demux->fragmented) {
6341 for (n = 0; n < demux->n_streams; n++) {
6342 gst_qtdemux_stream_send_initial_gap_segments (demux,
6347 g_node_destroy (demux->moov_node);
6348 demux->moov_node = NULL;
6349 GST_DEBUG_OBJECT (demux, "Finished parsing the header");
6351 } else if (fourcc == FOURCC_moof) {
6352 if ((demux->got_moov || demux->media_caps) && demux->fragmented) {
6354 GstClockTime prev_pts;
6355 guint64 prev_offset;
6356 guint64 adapter_discont_offset, adapter_discont_dist;
6358 GST_DEBUG_OBJECT (demux, "Parsing [moof]");
6361 * The timestamp of the moof buffer is relevant as some scenarios
6362 * won't have the initial timestamp in the atoms. Whenever a new
6363 * buffer has started, we get that buffer's PTS and use it as a base
6364 * timestamp for the trun entries.
6366 * To keep track of the current buffer timestamp and starting point
6367 * we use gst_adapter_prev_pts that gives us the PTS and the distance
6368 * from the beggining of the buffer, with the distance and demux->offset
6369 * we know if it is still the same buffer or not.
6371 prev_pts = gst_adapter_prev_pts (demux->adapter, &dist);
6372 prev_offset = demux->offset - dist;
6373 if (demux->fragment_start_offset == -1
6374 || prev_offset > demux->fragment_start_offset) {
6375 demux->fragment_start_offset = prev_offset;
6376 demux->fragment_start = prev_pts;
6377 GST_DEBUG_OBJECT (demux,
6378 "New fragment start found at: %" G_GUINT64_FORMAT " : %"
6379 GST_TIME_FORMAT, demux->fragment_start_offset,
6380 GST_TIME_ARGS (demux->fragment_start));
6383 /* We can't use prev_offset() here because this would require
6384 * upstream to set consistent and correct offsets on all buffers
6385 * since the discont. Nothing ever did that in the past and we
6386 * would break backwards compatibility here then.
6387 * Instead take the offset we had at the last discont and count
6388 * the bytes from there. This works with old code as there would
6389 * be no discont between moov and moof, and also works with
6390 * adaptivedemux which correctly sets offset and will set the
6391 * DISCONT flag accordingly when needed.
6393 * We also only do this for upstream TIME segments as otherwise
6394 * there are potential backwards compatibility problems with
6395 * seeking in PUSH mode and upstream providing inconsistent
6397 adapter_discont_offset =
6398 gst_adapter_offset_at_discont (demux->adapter);
6399 adapter_discont_dist =
6400 gst_adapter_distance_from_discont (demux->adapter);
6402 GST_DEBUG_OBJECT (demux,
6403 "demux offset %" G_GUINT64_FORMAT " adapter offset %"
6404 G_GUINT64_FORMAT " (+ %" G_GUINT64_FORMAT " bytes)",
6405 demux->offset, adapter_discont_offset, adapter_discont_dist);
6407 if (demux->upstream_format_is_time) {
6408 demux->moof_offset = adapter_discont_offset;
6409 if (demux->moof_offset != GST_BUFFER_OFFSET_NONE)
6410 demux->moof_offset += adapter_discont_dist;
6411 if (demux->moof_offset == GST_BUFFER_OFFSET_NONE)
6412 demux->moof_offset = demux->offset;
6414 demux->moof_offset = demux->offset;
6417 if (!qtdemux_parse_moof (demux, data, demux->neededbytes,
6418 demux->moof_offset, NULL)) {
6419 gst_adapter_unmap (demux->adapter);
6420 ret = GST_FLOW_ERROR;
6423 /* in MSS we need to expose the pads after the first moof as we won't get a moov */
6424 if (demux->mss_mode && !demux->exposed) {
6425 if (!demux->pending_newsegment) {
6426 GST_DEBUG_OBJECT (demux, "new pending_newsegment");
6427 demux->pending_newsegment =
6428 gst_event_new_segment (&demux->segment);
6429 if (demux->segment_seqnum)
6430 gst_event_set_seqnum (demux->pending_newsegment,
6431 demux->segment_seqnum);
6433 qtdemux_expose_streams (demux);
6436 GST_DEBUG_OBJECT (demux, "Discarding [moof]");
6438 } else if (fourcc == FOURCC_ftyp) {
6439 GST_DEBUG_OBJECT (demux, "Parsing [ftyp]");
6440 qtdemux_parse_ftyp (demux, data, demux->neededbytes);
6441 } else if (fourcc == FOURCC_uuid) {
6442 GST_DEBUG_OBJECT (demux, "Parsing [uuid]");
6443 qtdemux_parse_uuid (demux, data, demux->neededbytes);
6444 } else if (fourcc == FOURCC_sidx) {
6445 GST_DEBUG_OBJECT (demux, "Parsing [sidx]");
6446 qtdemux_parse_sidx (demux, data, demux->neededbytes);
6448 GST_WARNING_OBJECT (demux,
6449 "Unknown fourcc while parsing header : %" GST_FOURCC_FORMAT,
6450 GST_FOURCC_ARGS (fourcc));
6451 /* Let's jump that one and go back to initial state */
6453 gst_adapter_unmap (demux->adapter);
6456 if (demux->mdatbuffer && demux->n_streams) {
6457 gsize remaining_data_size = 0;
6459 /* the mdat was before the header */
6460 GST_DEBUG_OBJECT (demux, "We have n_streams:%d and mdatbuffer:%p",
6461 demux->n_streams, demux->mdatbuffer);
6462 /* restore our adapter/offset view of things with upstream;
6463 * put preceding buffered data ahead of current moov data.
6464 * This should also handle evil mdat, moov, mdat cases and alike */
6465 gst_adapter_flush (demux->adapter, demux->neededbytes);
6467 /* Store any remaining data after the mdat for later usage */
6468 remaining_data_size = gst_adapter_available (demux->adapter);
6469 if (remaining_data_size > 0) {
6470 g_assert (demux->restoredata_buffer == NULL);
6471 demux->restoredata_buffer =
6472 gst_adapter_take_buffer (demux->adapter, remaining_data_size);
6473 demux->restoredata_offset = demux->offset + demux->neededbytes;
6474 GST_DEBUG_OBJECT (demux,
6475 "Stored %" G_GSIZE_FORMAT " post mdat bytes at offset %"
6476 G_GUINT64_FORMAT, remaining_data_size,
6477 demux->restoredata_offset);
6480 gst_adapter_push (demux->adapter, demux->mdatbuffer);
6481 demux->mdatbuffer = NULL;
6482 demux->offset = demux->mdatoffset;
6483 demux->neededbytes = next_entry_size (demux);
6484 demux->state = QTDEMUX_STATE_MOVIE;
6485 demux->mdatleft = gst_adapter_available (demux->adapter);
6487 GST_DEBUG_OBJECT (demux, "Carrying on normally");
6488 gst_adapter_flush (demux->adapter, demux->neededbytes);
6490 /* only go back to the mdat if there are samples to play */
6491 if (demux->got_moov && demux->first_mdat != -1
6492 && has_next_entry (demux)) {
6495 /* we need to seek back */
6496 res = qtdemux_seek_offset (demux, demux->first_mdat);
6498 demux->offset = demux->first_mdat;
6500 GST_DEBUG_OBJECT (demux, "Seek back failed");
6503 demux->offset += demux->neededbytes;
6505 demux->neededbytes = 16;
6506 demux->state = QTDEMUX_STATE_INITIAL;
6511 case QTDEMUX_STATE_BUFFER_MDAT:{
6515 GST_DEBUG_OBJECT (demux, "Got our buffer at offset %" G_GUINT64_FORMAT,
6517 buf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
6518 gst_buffer_extract (buf, 0, fourcc, 4);
6519 GST_DEBUG_OBJECT (demux, "mdatbuffer starts with %" GST_FOURCC_FORMAT,
6520 GST_FOURCC_ARGS (QT_FOURCC (fourcc)));
6521 if (demux->mdatbuffer)
6522 demux->mdatbuffer = gst_buffer_append (demux->mdatbuffer, buf);
6524 demux->mdatbuffer = buf;
6525 demux->offset += demux->neededbytes;
6526 demux->neededbytes = 16;
6527 demux->state = QTDEMUX_STATE_INITIAL;
6528 gst_qtdemux_post_progress (demux, 1, 1);
6532 case QTDEMUX_STATE_MOVIE:{
6533 QtDemuxStream *stream = NULL;
6534 QtDemuxSample *sample;
6536 GstClockTime dts, pts, duration;
6539 GST_DEBUG_OBJECT (demux,
6540 "BEGIN // in MOVIE for offset %" G_GUINT64_FORMAT, demux->offset);
6542 if (demux->fragmented) {
6543 GST_DEBUG_OBJECT (demux, "mdat remaining %" G_GUINT64_FORMAT,
6545 if (G_LIKELY (demux->todrop < demux->mdatleft)) {
6546 /* if needed data starts within this atom,
6547 * then it should not exceed this atom */
6548 if (G_UNLIKELY (demux->neededbytes > demux->mdatleft)) {
6549 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
6550 (_("This file is invalid and cannot be played.")),
6551 ("sample data crosses atom boundary"));
6552 ret = GST_FLOW_ERROR;
6555 demux->mdatleft -= demux->neededbytes;
6557 GST_DEBUG_OBJECT (demux, "data atom emptied; resuming atom scan");
6558 /* so we are dropping more than left in this atom */
6559 gst_qtdemux_drop_data (demux, demux->mdatleft);
6560 demux->mdatleft = 0;
6562 /* need to resume atom parsing so we do not miss any other pieces */
6563 demux->state = QTDEMUX_STATE_INITIAL;
6564 demux->neededbytes = 16;
6566 /* check if there was any stored post mdat data from previous buffers */
6567 if (demux->restoredata_buffer) {
6568 g_assert (gst_adapter_available (demux->adapter) == 0);
6570 gst_adapter_push (demux->adapter, demux->restoredata_buffer);
6571 demux->restoredata_buffer = NULL;
6572 demux->offset = demux->restoredata_offset;
6579 if (demux->todrop) {
6580 if (demux->cenc_aux_info_offset > 0) {
6584 GST_DEBUG_OBJECT (demux, "parsing cenc auxiliary info");
6585 data = gst_adapter_map (demux->adapter, demux->todrop);
6586 gst_byte_reader_init (&br, data + 8, demux->todrop);
6587 if (!qtdemux_parse_cenc_aux_info (demux, demux->streams[0], &br,
6588 demux->cenc_aux_info_sizes, demux->cenc_aux_sample_count)) {
6589 GST_ERROR_OBJECT (demux, "failed to parse cenc auxiliary info");
6590 ret = GST_FLOW_ERROR;
6591 gst_adapter_unmap (demux->adapter);
6592 g_free (demux->cenc_aux_info_sizes);
6593 demux->cenc_aux_info_sizes = NULL;
6596 demux->cenc_aux_info_offset = 0;
6597 g_free (demux->cenc_aux_info_sizes);
6598 demux->cenc_aux_info_sizes = NULL;
6599 gst_adapter_unmap (demux->adapter);
6601 gst_qtdemux_drop_data (demux, demux->todrop);
6605 /* initial newsegment sent here after having added pads,
6606 * possible others in sink_event */
6607 gst_qtdemux_check_send_pending_segment (demux);
6609 /* Figure out which stream this packet belongs to */
6610 for (i = 0; i < demux->n_streams; i++) {
6611 stream = demux->streams[i];
6612 if (stream->sample_index >= stream->n_samples)
6614 GST_LOG_OBJECT (demux,
6615 "Checking stream %d (sample_index:%d / offset:%" G_GUINT64_FORMAT
6616 " / size:%d)", i, stream->sample_index,
6617 stream->samples[stream->sample_index].offset,
6618 stream->samples[stream->sample_index].size);
6620 if (stream->samples[stream->sample_index].offset == demux->offset)
6624 if (G_UNLIKELY (stream == NULL || i == demux->n_streams))
6625 goto unknown_stream;
6627 if (stream->new_caps) {
6628 gst_qtdemux_configure_stream (demux, stream);
6631 /* Put data in a buffer, set timestamps, caps, ... */
6632 sample = &stream->samples[stream->sample_index];
6634 if (G_LIKELY (!(STREAM_IS_EOS (stream)))) {
6635 GST_DEBUG_OBJECT (demux, "stream : %" GST_FOURCC_FORMAT,
6636 GST_FOURCC_ARGS (stream->fourcc));
6638 dts = QTSAMPLE_DTS (stream, sample);
6639 pts = QTSAMPLE_PTS (stream, sample);
6640 duration = QTSAMPLE_DUR_DTS (stream, sample, dts);
6641 keyframe = QTSAMPLE_KEYFRAME (stream, sample);
6643 /* check for segment end */
6644 if (G_UNLIKELY (demux->segment.stop != -1
6645 && demux->segment.stop <= pts && stream->on_keyframe)) {
6646 GST_DEBUG_OBJECT (demux, "we reached the end of our segment.");
6647 stream->time_position = GST_CLOCK_TIME_NONE; /* this means EOS */
6649 /* skip this data, stream is EOS */
6650 gst_adapter_flush (demux->adapter, demux->neededbytes);
6652 /* check if all streams are eos */
6654 for (i = 0; i < demux->n_streams; i++) {
6655 if (!STREAM_IS_EOS (demux->streams[i])) {
6661 if (ret == GST_FLOW_EOS) {
6662 GST_DEBUG_OBJECT (demux, "All streams are EOS, signal upstream");
6669 gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
6671 /* FIXME: should either be an assert or a plain check */
6672 g_return_val_if_fail (outbuf != NULL, GST_FLOW_ERROR);
6674 ret = gst_qtdemux_decorate_and_push_buffer (demux, stream, outbuf,
6675 dts, pts, duration, keyframe, dts, demux->offset);
6679 ret = gst_qtdemux_combine_flows (demux, stream, ret);
6680 if (ret != GST_FLOW_OK && ret != GST_FLOW_NOT_LINKED)
6681 goto non_ok_unlinked_flow;
6683 /* skip this data, stream is EOS */
6684 gst_adapter_flush (demux->adapter, demux->neededbytes);
6687 stream->sample_index++;
6688 stream->offset_in_sample = 0;
6690 /* update current offset and figure out size of next buffer */
6691 GST_LOG_OBJECT (demux, "increasing offset %" G_GUINT64_FORMAT " by %u",
6692 demux->offset, demux->neededbytes);
6693 demux->offset += demux->neededbytes;
6694 GST_LOG_OBJECT (demux, "offset is now %" G_GUINT64_FORMAT,
6697 if ((demux->neededbytes = next_entry_size (demux)) == -1) {
6698 if (demux->fragmented) {
6699 GST_DEBUG_OBJECT (demux, "(temporarily) out of fragmented samples");
6700 /* there may be more to follow, only finish this atom */
6701 demux->todrop = demux->mdatleft;
6702 demux->neededbytes = demux->todrop;
6714 /* when buffering movie data, at least show user something is happening */
6715 if (ret == GST_FLOW_OK && demux->state == QTDEMUX_STATE_BUFFER_MDAT &&
6716 gst_adapter_available (demux->adapter) <= demux->neededbytes) {
6717 gst_qtdemux_post_progress (demux, gst_adapter_available (demux->adapter),
6718 demux->neededbytes);
6725 non_ok_unlinked_flow:
6727 GST_DEBUG_OBJECT (demux, "Stopping, combined return flow %s",
6728 gst_flow_get_name (ret));
6733 GST_ELEMENT_ERROR (demux, STREAM, FAILED, (NULL), ("unknown stream found"));
6734 ret = GST_FLOW_ERROR;
6739 GST_DEBUG_OBJECT (demux, "no next entry, EOS");
6745 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
6746 (NULL), ("qtdemuxer invalid state %d", demux->state));
6747 ret = GST_FLOW_ERROR;
6752 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
6753 (NULL), ("no 'moov' atom within the first 10 MB"));
6754 ret = GST_FLOW_ERROR;
6760 qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent)
6765 query = gst_query_new_scheduling ();
6767 if (!gst_pad_peer_query (sinkpad, query)) {
6768 gst_query_unref (query);
6772 pull_mode = gst_query_has_scheduling_mode_with_flags (query,
6773 GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
6774 gst_query_unref (query);
6779 GST_DEBUG_OBJECT (sinkpad, "activating pull");
6780 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
6784 GST_DEBUG_OBJECT (sinkpad, "activating push");
6785 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
6790 qtdemux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
6791 GstPadMode mode, gboolean active)
6794 GstQTDemux *demux = GST_QTDEMUX (parent);
6797 case GST_PAD_MODE_PUSH:
6798 demux->pullbased = FALSE;
6801 case GST_PAD_MODE_PULL:
6803 demux->pullbased = TRUE;
6804 res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_qtdemux_loop,
6807 res = gst_pad_stop_task (sinkpad);
6819 qtdemux_zalloc (void *opaque, unsigned int items, unsigned int size)
6821 return g_malloc (items * size);
6825 qtdemux_zfree (void *opaque, void *addr)
6831 qtdemux_inflate (void *z_buffer, guint z_length, guint length)
6837 z = g_new0 (z_stream, 1);
6838 z->zalloc = qtdemux_zalloc;
6839 z->zfree = qtdemux_zfree;
6842 z->next_in = z_buffer;
6843 z->avail_in = z_length;
6845 buffer = (guint8 *) g_malloc (length);
6846 ret = inflateInit (z);
6847 while (z->avail_in > 0) {
6848 if (z->avail_out == 0) {
6850 buffer = (guint8 *) g_realloc (buffer, length);
6851 z->next_out = buffer + z->total_out;
6852 z->avail_out = 1024;
6854 ret = inflate (z, Z_SYNC_FLUSH);
6858 if (ret != Z_STREAM_END) {
6859 g_warning ("inflate() returned %d", ret);
6865 #endif /* HAVE_ZLIB */
6868 qtdemux_parse_moov (GstQTDemux * qtdemux, const guint8 * buffer, guint length)
6872 qtdemux->moov_node = g_node_new ((guint8 *) buffer);
6874 /* counts as header data */
6875 qtdemux->header_size += length;
6877 GST_DEBUG_OBJECT (qtdemux, "parsing 'moov' atom");
6878 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buffer, length);
6880 cmov = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_cmov);
6886 dcom = qtdemux_tree_get_child_by_type (cmov, FOURCC_dcom);
6887 cmvd = qtdemux_tree_get_child_by_type (cmov, FOURCC_cmvd);
6888 if (dcom == NULL || cmvd == NULL)
6889 goto invalid_compression;
6891 method = QT_FOURCC ((guint8 *) dcom->data + 8);
6895 guint uncompressed_length;
6896 guint compressed_length;
6899 uncompressed_length = QT_UINT32 ((guint8 *) cmvd->data + 8);
6900 compressed_length = QT_UINT32 ((guint8 *) cmvd->data + 4) - 12;
6901 GST_LOG ("length = %u", uncompressed_length);
6904 (guint8 *) qtdemux_inflate ((guint8 *) cmvd->data + 12,
6905 compressed_length, uncompressed_length);
6907 qtdemux->moov_node_compressed = qtdemux->moov_node;
6908 qtdemux->moov_node = g_node_new (buf);
6910 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buf,
6911 uncompressed_length);
6914 #endif /* HAVE_ZLIB */
6916 GST_WARNING_OBJECT (qtdemux, "unknown or unhandled header compression "
6917 "type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (method));
6924 invalid_compression:
6926 GST_ERROR_OBJECT (qtdemux, "invalid compressed header");
6932 qtdemux_parse_container (GstQTDemux * qtdemux, GNode * node, const guint8 * buf,
6935 while (G_UNLIKELY (buf < end)) {
6939 if (G_UNLIKELY (buf + 4 > end)) {
6940 GST_LOG_OBJECT (qtdemux, "buffer overrun");
6943 len = QT_UINT32 (buf);
6944 if (G_UNLIKELY (len == 0)) {
6945 GST_LOG_OBJECT (qtdemux, "empty container");
6948 if (G_UNLIKELY (len < 8)) {
6949 GST_WARNING_OBJECT (qtdemux, "length too short (%d < 8)", len);
6952 if (G_UNLIKELY (len > (end - buf))) {
6953 GST_WARNING_OBJECT (qtdemux, "length too long (%d > %d)", len,
6954 (gint) (end - buf));
6958 child = g_node_new ((guint8 *) buf);
6959 g_node_append (node, child);
6960 GST_LOG_OBJECT (qtdemux, "adding new node of len %d", len);
6961 qtdemux_parse_node (qtdemux, child, buf, len);
6969 qtdemux_parse_theora_extension (GstQTDemux * qtdemux, QtDemuxStream * stream,
6972 int len = QT_UINT32 (xdxt->data);
6973 guint8 *buf = xdxt->data;
6974 guint8 *end = buf + len;
6977 /* skip size and type */
6985 size = QT_UINT32 (buf);
6986 type = QT_FOURCC (buf + 4);
6988 GST_LOG_OBJECT (qtdemux, "%p %p", buf, end);
6990 if (buf + size > end || size <= 0)
6996 GST_WARNING_OBJECT (qtdemux, "have cookie %" GST_FOURCC_FORMAT,
6997 GST_FOURCC_ARGS (type));
7001 buffer = gst_buffer_new_and_alloc (size);
7002 gst_buffer_fill (buffer, 0, buf, size);
7003 stream->buffers = g_slist_append (stream->buffers, buffer);
7004 GST_LOG_OBJECT (qtdemux, "parsing theora header");
7007 buffer = gst_buffer_new_and_alloc (size);
7008 gst_buffer_fill (buffer, 0, buf, size);
7009 stream->buffers = g_slist_append (stream->buffers, buffer);
7010 GST_LOG_OBJECT (qtdemux, "parsing theora comment");
7013 buffer = gst_buffer_new_and_alloc (size);
7014 gst_buffer_fill (buffer, 0, buf, size);
7015 stream->buffers = g_slist_append (stream->buffers, buffer);
7016 GST_LOG_OBJECT (qtdemux, "parsing theora codebook");
7019 GST_WARNING_OBJECT (qtdemux,
7020 "unknown theora cookie %" GST_FOURCC_FORMAT,
7021 GST_FOURCC_ARGS (type));
7030 qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node, const guint8 * buffer,
7034 guint32 node_length = 0;
7035 const QtNodeType *type;
7038 GST_LOG_OBJECT (qtdemux, "qtdemux_parse buffer %p length %u", buffer, length);
7040 if (G_UNLIKELY (length < 8))
7041 goto not_enough_data;
7043 node_length = QT_UINT32 (buffer);
7044 fourcc = QT_FOURCC (buffer + 4);
7046 /* ignore empty nodes */
7047 if (G_UNLIKELY (fourcc == 0 || node_length == 8))
7050 type = qtdemux_type_get (fourcc);
7052 end = buffer + length;
7054 GST_LOG_OBJECT (qtdemux,
7055 "parsing '%" GST_FOURCC_FORMAT "', length=%u, name '%s'",
7056 GST_FOURCC_ARGS (fourcc), node_length, type->name);
7058 if (node_length > length)
7059 goto broken_atom_size;
7061 if (type->flags & QT_FLAG_CONTAINER) {
7062 qtdemux_parse_container (qtdemux, node, buffer + 8, end);
7067 if (node_length < 20) {
7068 GST_LOG_OBJECT (qtdemux, "skipping small stsd box");
7071 GST_DEBUG_OBJECT (qtdemux,
7072 "parsing stsd (sample table, sample description) atom");
7073 /* Skip over 8 byte atom hdr + 1 byte version, 3 bytes flags, 4 byte num_entries */
7074 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
7084 /* also read alac (or whatever) in stead of mp4a in the following,
7085 * since a similar layout is used in other cases as well */
7086 if (fourcc == FOURCC_mp4a)
7091 /* There are two things we might encounter here: a true mp4a atom, and
7092 an mp4a entry in an stsd atom. The latter is what we're interested
7093 in, and it looks like an atom, but isn't really one. The true mp4a
7094 atom is short, so we detect it based on length here. */
7095 if (length < min_size) {
7096 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
7097 GST_FOURCC_ARGS (fourcc));
7101 /* 'version' here is the sound sample description version. Types 0 and
7102 1 are documented in the QTFF reference, but type 2 is not: it's
7103 described in Apple header files instead (struct SoundDescriptionV2
7105 version = QT_UINT16 (buffer + 16);
7107 GST_DEBUG_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT " version 0x%08x",
7108 GST_FOURCC_ARGS (fourcc), version);
7110 /* parse any esds descriptors */
7122 GST_WARNING_OBJECT (qtdemux,
7123 "unhandled %" GST_FOURCC_FORMAT " version 0x%08x",
7124 GST_FOURCC_ARGS (fourcc), version);
7129 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
7146 /* codec_data is contained inside these atoms, which all have
7147 * the same format. */
7149 GST_DEBUG_OBJECT (qtdemux, "parsing in %" GST_FOURCC_FORMAT,
7150 GST_FOURCC_ARGS (fourcc));
7151 version = QT_UINT32 (buffer + 16);
7152 GST_DEBUG_OBJECT (qtdemux, "version %08x", version);
7153 if (1 || version == 0x00000000) {
7154 buf = buffer + 0x32;
7156 /* FIXME Quicktime uses PASCAL string while
7157 * the iso format uses C strings. Check the file
7158 * type before attempting to parse the string here. */
7159 tlen = QT_UINT8 (buf);
7160 GST_DEBUG_OBJECT (qtdemux, "tlen = %d", tlen);
7162 GST_DEBUG_OBJECT (qtdemux, "string = %.*s", tlen, (char *) buf);
7163 /* the string has a reserved space of 32 bytes so skip
7164 * the remaining 31 */
7166 buf += 4; /* and 4 bytes reserved */
7168 GST_MEMDUMP_OBJECT (qtdemux, "mp4v", buf, end - buf);
7170 qtdemux_parse_container (qtdemux, node, buf, end);
7176 GST_MEMDUMP_OBJECT (qtdemux, "H264", buffer, end - buffer);
7177 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
7182 GST_MEMDUMP_OBJECT (qtdemux, "avc1", buffer, end - buffer);
7183 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
7188 GST_MEMDUMP_OBJECT (qtdemux, "avc3", buffer, end - buffer);
7189 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
7194 GST_MEMDUMP_OBJECT (qtdemux, "H265", buffer, end - buffer);
7195 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
7200 GST_MEMDUMP_OBJECT (qtdemux, "hvc1", buffer, end - buffer);
7201 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
7206 GST_MEMDUMP_OBJECT (qtdemux, "hev1", buffer, end - buffer);
7207 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
7212 qtdemux_parse_container (qtdemux, node, buffer + 86, end);
7217 GST_DEBUG_OBJECT (qtdemux, "parsing meta atom");
7218 qtdemux_parse_container (qtdemux, node, buffer + 12, end);
7223 GST_MEMDUMP_OBJECT (qtdemux, "mp4s", buffer, end - buffer);
7224 /* Skip 8 byte header, plus 8 byte version + flags + entry_count */
7225 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
7233 version = QT_UINT32 (buffer + 12);
7234 GST_DEBUG_OBJECT (qtdemux, "parsing XiTh atom version 0x%08x", version);
7241 GST_DEBUG_OBJECT (qtdemux, "unknown version 0x%08x", version);
7246 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
7251 qtdemux_parse_container (qtdemux, node, buffer + 0x34, end);
7256 qtdemux_parse_uuid (qtdemux, buffer, end - buffer);
7261 qtdemux_parse_container (qtdemux, node, buffer + 86, end);
7266 qtdemux_parse_container (qtdemux, node, buffer + 36, end);
7270 if (!strcmp (type->name, "unknown"))
7271 GST_MEMDUMP ("Unknown tag", buffer + 4, end - buffer - 4);
7275 GST_LOG_OBJECT (qtdemux, "parsed '%" GST_FOURCC_FORMAT "'",
7276 GST_FOURCC_ARGS (fourcc));
7282 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
7283 (_("This file is corrupt and cannot be played.")),
7284 ("Not enough data for an atom header, got only %u bytes", length));
7289 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
7290 (_("This file is corrupt and cannot be played.")),
7291 ("Atom '%" GST_FOURCC_FORMAT "' has size of %u bytes, but we have only "
7292 "%u bytes available.", GST_FOURCC_ARGS (fourcc), node_length,
7299 qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc)
7303 guint32 child_fourcc;
7305 for (child = g_node_first_child (node); child;
7306 child = g_node_next_sibling (child)) {
7307 buffer = (guint8 *) child->data;
7309 child_fourcc = QT_FOURCC (buffer + 4);
7311 if (G_UNLIKELY (child_fourcc == fourcc)) {
7319 qtdemux_tree_get_child_by_type_full (GNode * node, guint32 fourcc,
7320 GstByteReader * parser)
7324 guint32 child_fourcc, child_len;
7326 for (child = g_node_first_child (node); child;
7327 child = g_node_next_sibling (child)) {
7328 buffer = (guint8 *) child->data;
7330 child_len = QT_UINT32 (buffer);
7331 child_fourcc = QT_FOURCC (buffer + 4);
7333 if (G_UNLIKELY (child_fourcc == fourcc)) {
7334 if (G_UNLIKELY (child_len < (4 + 4)))
7336 /* FIXME: must verify if atom length < parent atom length */
7337 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
7345 qtdemux_tree_get_sibling_by_type_full (GNode * node, guint32 fourcc,
7346 GstByteReader * parser)
7350 guint32 child_fourcc, child_len;
7352 for (child = g_node_next_sibling (node); child;
7353 child = g_node_next_sibling (child)) {
7354 buffer = (guint8 *) child->data;
7356 child_fourcc = QT_FOURCC (buffer + 4);
7358 if (child_fourcc == fourcc) {
7360 child_len = QT_UINT32 (buffer);
7361 if (G_UNLIKELY (child_len < (4 + 4)))
7363 /* FIXME: must verify if atom length < parent atom length */
7364 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
7373 qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc)
7375 return qtdemux_tree_get_sibling_by_type_full (node, fourcc, NULL);
7379 qtdemux_do_allocation (GstQTDemux * qtdemux, QtDemuxStream * stream)
7381 /* FIXME: This can only reliably work if demuxers have a
7382 * separate streaming thread per srcpad. This should be
7383 * done in a demuxer base class, which integrates parts
7386 * https://bugzilla.gnome.org/show_bug.cgi?id=701856
7391 query = gst_query_new_allocation (stream->caps, FALSE);
7393 if (!gst_pad_peer_query (stream->pad, query)) {
7394 /* not a problem, just debug a little */
7395 GST_DEBUG_OBJECT (qtdemux, "peer ALLOCATION query failed");
7398 if (stream->allocator)
7399 gst_object_unref (stream->allocator);
7401 if (gst_query_get_n_allocation_params (query) > 0) {
7402 /* try the allocator */
7403 gst_query_parse_nth_allocation_param (query, 0, &stream->allocator,
7405 stream->use_allocator = TRUE;
7407 stream->allocator = NULL;
7408 gst_allocation_params_init (&stream->params);
7409 stream->use_allocator = FALSE;
7411 gst_query_unref (query);
7416 gst_qtdemux_configure_protected_caps (GstQTDemux * qtdemux,
7417 QtDemuxStream * stream)
7420 const gchar *selected_system;
7422 g_return_val_if_fail (qtdemux != NULL, FALSE);
7423 g_return_val_if_fail (stream != NULL, FALSE);
7424 g_return_val_if_fail (gst_caps_get_size (stream->caps) == 1, FALSE);
7426 if (stream->protection_scheme_type != FOURCC_cenc) {
7427 GST_ERROR_OBJECT (qtdemux, "unsupported protection scheme");
7430 if (qtdemux->protection_system_ids == NULL) {
7431 GST_ERROR_OBJECT (qtdemux, "stream is protected using cenc, but no "
7432 "cenc protection system information has been found");
7435 g_ptr_array_add (qtdemux->protection_system_ids, NULL);
7436 selected_system = gst_protection_select_system ((const gchar **)
7437 qtdemux->protection_system_ids->pdata);
7438 g_ptr_array_remove_index (qtdemux->protection_system_ids,
7439 qtdemux->protection_system_ids->len - 1);
7440 if (!selected_system) {
7441 GST_ERROR_OBJECT (qtdemux, "stream is protected, but no "
7442 "suitable decryptor element has been found");
7446 s = gst_caps_get_structure (stream->caps, 0);
7447 if (!gst_structure_has_name (s, "application/x-cenc")) {
7448 gst_structure_set (s,
7449 "original-media-type", G_TYPE_STRING, gst_structure_get_name (s),
7450 GST_PROTECTION_SYSTEM_ID_CAPS_FIELD, G_TYPE_STRING, selected_system,
7452 gst_structure_set_name (s, "application/x-cenc");
7458 gst_qtdemux_configure_stream (GstQTDemux * qtdemux, QtDemuxStream * stream)
7460 if (stream->subtype == FOURCC_vide) {
7461 /* fps is calculated base on the duration of the average framerate since
7462 * qt does not have a fixed framerate. */
7463 gboolean fps_available = TRUE;
7465 if ((stream->n_samples == 1) && (stream->first_duration == 0)) {
7470 if (stream->duration == 0 || stream->n_samples < 2) {
7471 stream->fps_n = stream->timescale;
7473 fps_available = FALSE;
7475 GstClockTime avg_duration;
7479 /* duration and n_samples can be updated for fragmented format
7480 * so, framerate of fragmented format is calculated using data in a moof */
7481 if (qtdemux->fragmented && stream->n_samples_moof > 0
7482 && stream->duration_moof > 0) {
7483 n_samples = stream->n_samples_moof;
7484 duration = stream->duration_moof;
7486 n_samples = stream->n_samples;
7487 duration = stream->duration;
7490 /* Calculate a framerate, ignoring the first sample which is sometimes truncated */
7491 /* stream->duration is guint64, timescale, n_samples are guint32 */
7493 gst_util_uint64_scale_round (duration -
7494 stream->first_duration, GST_SECOND,
7495 (guint64) (stream->timescale) * (n_samples - 1));
7497 GST_LOG_OBJECT (qtdemux,
7498 "Calculating avg sample duration based on stream (or moof) duration %"
7500 " minus first sample %u, leaving %d samples gives %"
7501 GST_TIME_FORMAT, duration, stream->first_duration,
7502 n_samples - 1, GST_TIME_ARGS (avg_duration));
7504 gst_video_guess_framerate (avg_duration, &stream->fps_n,
7507 GST_DEBUG_OBJECT (qtdemux,
7508 "Calculating framerate, timescale %u gave fps_n %d fps_d %d",
7509 stream->timescale, stream->fps_n, stream->fps_d);
7514 stream->caps = gst_caps_make_writable (stream->caps);
7516 gst_caps_set_simple (stream->caps,
7517 "width", G_TYPE_INT, stream->width,
7518 "height", G_TYPE_INT, stream->height, NULL);
7520 /* set framerate if calculated framerate is reliable */
7521 if (fps_available) {
7522 gst_caps_set_simple (stream->caps,
7523 "framerate", GST_TYPE_FRACTION, stream->fps_n, stream->fps_d, NULL);
7526 /* calculate pixel-aspect-ratio using display width and height */
7527 GST_DEBUG_OBJECT (qtdemux,
7528 "video size %dx%d, target display size %dx%d", stream->width,
7529 stream->height, stream->display_width, stream->display_height);
7530 /* qt file might have pasp atom */
7531 if (stream->par_w > 0 && stream->par_h > 0) {
7532 GST_DEBUG_OBJECT (qtdemux, "par %d:%d", stream->par_w, stream->par_h);
7533 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
7534 GST_TYPE_FRACTION, stream->par_w, stream->par_h, NULL);
7535 } else if (stream->display_width > 0 && stream->display_height > 0 &&
7536 stream->width > 0 && stream->height > 0) {
7539 /* calculate the pixel aspect ratio using the display and pixel w/h */
7540 n = stream->display_width * stream->height;
7541 d = stream->display_height * stream->width;
7544 GST_DEBUG_OBJECT (qtdemux, "setting PAR to %d/%d", n, d);
7547 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
7548 GST_TYPE_FRACTION, stream->par_w, stream->par_h, NULL);
7551 /* Create incomplete colorimetry here if needed */
7552 if (stream->colorimetry.range ||
7553 stream->colorimetry.matrix ||
7554 stream->colorimetry.transfer || stream->colorimetry.primaries) {
7555 gchar *colorimetry =
7556 gst_video_colorimetry_to_string (&stream->colorimetry);
7557 gst_caps_set_simple (stream->caps, "colorimetry", G_TYPE_STRING,
7559 g_free (colorimetry);
7562 if (stream->multiview_mode != GST_VIDEO_MULTIVIEW_MODE_NONE) {
7563 guint par_w = 1, par_h = 1;
7565 if (stream->par_w > 0 && stream->par_h > 0) {
7566 par_w = stream->par_w;
7567 par_h = stream->par_h;
7570 if (gst_video_multiview_guess_half_aspect (stream->multiview_mode,
7571 stream->width, stream->height, par_w, par_h)) {
7572 stream->multiview_flags |= GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT;
7575 gst_caps_set_simple (stream->caps,
7576 "multiview-mode", G_TYPE_STRING,
7577 gst_video_multiview_mode_to_caps_string (stream->multiview_mode),
7578 "multiview-flags", GST_TYPE_VIDEO_MULTIVIEW_FLAGSET,
7579 stream->multiview_flags, GST_FLAG_SET_MASK_EXACT, NULL);
7584 else if (stream->subtype == FOURCC_soun) {
7586 stream->caps = gst_caps_make_writable (stream->caps);
7587 if (stream->rate > 0)
7588 gst_caps_set_simple (stream->caps,
7589 "rate", G_TYPE_INT, (int) stream->rate, NULL);
7590 if (stream->n_channels > 0)
7591 gst_caps_set_simple (stream->caps,
7592 "channels", G_TYPE_INT, stream->n_channels, NULL);
7593 if (stream->n_channels > 2) {
7594 /* FIXME: Need to parse the 'chan' atom to get channel layouts
7595 * correctly; this is just the minimum we can do - assume
7596 * we don't actually have any channel positions. */
7597 gst_caps_set_simple (stream->caps,
7598 "channel-mask", GST_TYPE_BITMASK, G_GUINT64_CONSTANT (0), NULL);
7604 GstCaps *prev_caps = NULL;
7606 GST_PAD_ELEMENT_PRIVATE (stream->pad) = stream;
7607 gst_pad_set_event_function (stream->pad, gst_qtdemux_handle_src_event);
7608 gst_pad_set_query_function (stream->pad, gst_qtdemux_handle_src_query);
7609 gst_pad_set_active (stream->pad, TRUE);
7611 gst_pad_use_fixed_caps (stream->pad);
7613 if (stream->protected) {
7614 if (!gst_qtdemux_configure_protected_caps (qtdemux, stream)) {
7615 GST_ERROR_OBJECT (qtdemux,
7616 "Failed to configure protected stream caps.");
7621 if (stream->new_stream) {
7624 GstStreamFlags stream_flags;
7627 gst_pad_get_sticky_event (qtdemux->sinkpad, GST_EVENT_STREAM_START,
7630 if (gst_event_parse_group_id (event, &qtdemux->group_id))
7631 qtdemux->have_group_id = TRUE;
7633 qtdemux->have_group_id = FALSE;
7634 gst_event_unref (event);
7635 } else if (!qtdemux->have_group_id) {
7636 qtdemux->have_group_id = TRUE;
7637 qtdemux->group_id = gst_util_group_id_next ();
7640 stream->new_stream = FALSE;
7642 gst_pad_create_stream_id_printf (stream->pad,
7643 GST_ELEMENT_CAST (qtdemux), "%03u", stream->track_id);
7644 event = gst_event_new_stream_start (stream_id);
7645 if (qtdemux->have_group_id)
7646 gst_event_set_group_id (event, qtdemux->group_id);
7647 stream_flags = GST_STREAM_FLAG_NONE;
7648 if (stream->disabled)
7649 stream_flags |= GST_STREAM_FLAG_UNSELECT;
7651 stream_flags |= GST_STREAM_FLAG_SPARSE;
7652 gst_event_set_stream_flags (event, stream_flags);
7653 gst_pad_push_event (stream->pad, event);
7657 prev_caps = gst_pad_get_current_caps (stream->pad);
7659 if (!prev_caps || !gst_caps_is_equal_fixed (prev_caps, stream->caps)) {
7660 GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT, stream->caps);
7661 gst_pad_set_caps (stream->pad, stream->caps);
7663 GST_DEBUG_OBJECT (qtdemux, "ignore duplicated caps");
7667 gst_caps_unref (prev_caps);
7668 stream->new_caps = FALSE;
7674 gst_qtdemux_add_stream (GstQTDemux * qtdemux,
7675 QtDemuxStream * stream, GstTagList * list)
7677 gboolean ret = TRUE;
7678 /* consistent default for push based mode */
7679 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
7681 if (stream->subtype == FOURCC_vide) {
7682 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
7685 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
7688 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
7689 gst_object_unref (stream->pad);
7695 qtdemux->n_video_streams++;
7696 } else if (stream->subtype == FOURCC_soun) {
7697 gchar *name = g_strdup_printf ("audio_%u", qtdemux->n_audio_streams);
7700 gst_pad_new_from_static_template (&gst_qtdemux_audiosrc_template, name);
7702 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
7703 gst_object_unref (stream->pad);
7708 qtdemux->n_audio_streams++;
7709 } else if (stream->subtype == FOURCC_strm) {
7710 GST_DEBUG_OBJECT (qtdemux, "stream type, not creating pad");
7711 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
7712 || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt) {
7713 gchar *name = g_strdup_printf ("subtitle_%u", qtdemux->n_sub_streams);
7716 gst_pad_new_from_static_template (&gst_qtdemux_subsrc_template, name);
7718 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
7719 gst_object_unref (stream->pad);
7724 qtdemux->n_sub_streams++;
7725 } else if (stream->caps) {
7726 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
7729 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
7731 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
7732 gst_object_unref (stream->pad);
7737 qtdemux->n_video_streams++;
7739 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
7746 GST_DEBUG_OBJECT (qtdemux, "adding pad %s %p to qtdemux %p",
7747 GST_OBJECT_NAME (stream->pad), stream->pad, qtdemux);
7748 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
7749 gst_flow_combiner_add_pad (qtdemux->flowcombiner, stream->pad);
7751 if (stream->pending_tags)
7752 gst_tag_list_unref (stream->pending_tags);
7753 stream->pending_tags = list;
7755 /* global tags go on each pad anyway */
7756 stream->send_global_tags = TRUE;
7757 /* send upstream GST_EVENT_PROTECTION events that were received before
7758 this source pad was created */
7759 for (l = qtdemux->protection_event_queue.head; l != NULL; l = l->next)
7760 gst_pad_push_event (stream->pad, gst_event_ref (l->data));
7764 gst_tag_list_unref (list);
7768 /* find next atom with @fourcc starting at @offset */
7769 static GstFlowReturn
7770 qtdemux_find_atom (GstQTDemux * qtdemux, guint64 * offset,
7771 guint64 * length, guint32 fourcc)
7777 GST_LOG_OBJECT (qtdemux, "finding fourcc %" GST_FOURCC_FORMAT " at offset %"
7778 G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), *offset);
7784 ret = gst_pad_pull_range (qtdemux->sinkpad, *offset, 16, &buf);
7785 if (G_UNLIKELY (ret != GST_FLOW_OK))
7787 if (G_UNLIKELY (gst_buffer_get_size (buf) != 16)) {
7790 gst_buffer_unref (buf);
7793 gst_buffer_map (buf, &map, GST_MAP_READ);
7794 extract_initial_length_and_fourcc (map.data, 16, length, &lfourcc);
7795 gst_buffer_unmap (buf, &map);
7796 gst_buffer_unref (buf);
7798 if (G_UNLIKELY (*length == 0)) {
7799 GST_DEBUG_OBJECT (qtdemux, "invalid length 0");
7800 ret = GST_FLOW_ERROR;
7804 if (lfourcc == fourcc) {
7805 GST_DEBUG_OBJECT (qtdemux, "found fourcc at offset %" G_GUINT64_FORMAT,
7809 GST_LOG_OBJECT (qtdemux,
7810 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
7811 GST_FOURCC_ARGS (fourcc), *offset);
7820 /* might simply have had last one */
7821 GST_DEBUG_OBJECT (qtdemux, "fourcc not found");
7826 /* should only do something in pull mode */
7827 /* call with OBJECT lock */
7828 static GstFlowReturn
7829 qtdemux_add_fragmented_samples (GstQTDemux * qtdemux)
7831 guint64 length, offset;
7832 GstBuffer *buf = NULL;
7833 GstFlowReturn ret = GST_FLOW_OK;
7834 GstFlowReturn res = GST_FLOW_OK;
7837 offset = qtdemux->moof_offset;
7838 GST_DEBUG_OBJECT (qtdemux, "next moof at offset %" G_GUINT64_FORMAT, offset);
7841 GST_DEBUG_OBJECT (qtdemux, "no next moof");
7842 return GST_FLOW_EOS;
7845 /* best not do pull etc with lock held */
7846 GST_OBJECT_UNLOCK (qtdemux);
7848 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
7849 if (ret != GST_FLOW_OK)
7852 ret = gst_qtdemux_pull_atom (qtdemux, offset, length, &buf);
7853 if (G_UNLIKELY (ret != GST_FLOW_OK))
7855 gst_buffer_map (buf, &map, GST_MAP_READ);
7856 if (!qtdemux_parse_moof (qtdemux, map.data, map.size, offset, NULL)) {
7857 gst_buffer_unmap (buf, &map);
7858 gst_buffer_unref (buf);
7863 gst_buffer_unmap (buf, &map);
7864 gst_buffer_unref (buf);
7868 /* look for next moof */
7869 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
7870 if (G_UNLIKELY (ret != GST_FLOW_OK))
7874 GST_OBJECT_LOCK (qtdemux);
7876 qtdemux->moof_offset = offset;
7882 GST_DEBUG_OBJECT (qtdemux, "failed to parse moof");
7884 res = GST_FLOW_ERROR;
7889 /* maybe upstream temporarily flushing */
7890 if (ret != GST_FLOW_FLUSHING) {
7891 GST_DEBUG_OBJECT (qtdemux, "no next moof");
7894 GST_DEBUG_OBJECT (qtdemux, "upstream WRONG_STATE");
7895 /* resume at current position next time */
7902 /* initialise bytereaders for stbl sub-atoms */
7904 qtdemux_stbl_init (GstQTDemux * qtdemux, QtDemuxStream * stream, GNode * stbl)
7906 stream->stbl_index = -1; /* no samples have yet been parsed */
7907 stream->sample_index = -1;
7909 /* time-to-sample atom */
7910 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stts, &stream->stts))
7913 /* copy atom data into a new buffer for later use */
7914 stream->stts.data = g_memdup (stream->stts.data, stream->stts.size);
7916 /* skip version + flags */
7917 if (!gst_byte_reader_skip (&stream->stts, 1 + 3) ||
7918 !gst_byte_reader_get_uint32_be (&stream->stts, &stream->n_sample_times))
7920 GST_LOG_OBJECT (qtdemux, "%u timestamp blocks", stream->n_sample_times);
7922 /* make sure there's enough data */
7923 if (!qt_atom_parser_has_chunks (&stream->stts, stream->n_sample_times, 8)) {
7924 stream->n_sample_times = gst_byte_reader_get_remaining (&stream->stts) / 8;
7925 GST_LOG_OBJECT (qtdemux, "overriding to %u timestamp blocks",
7926 stream->n_sample_times);
7927 if (!stream->n_sample_times)
7931 /* sync sample atom */
7932 stream->stps_present = FALSE;
7933 if ((stream->stss_present =
7934 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stss,
7935 &stream->stss) ? TRUE : FALSE) == TRUE) {
7936 /* copy atom data into a new buffer for later use */
7937 stream->stss.data = g_memdup (stream->stss.data, stream->stss.size);
7939 /* skip version + flags */
7940 if (!gst_byte_reader_skip (&stream->stss, 1 + 3) ||
7941 !gst_byte_reader_get_uint32_be (&stream->stss, &stream->n_sample_syncs))
7944 if (stream->n_sample_syncs) {
7945 /* make sure there's enough data */
7946 if (!qt_atom_parser_has_chunks (&stream->stss, stream->n_sample_syncs, 4))
7950 /* partial sync sample atom */
7951 if ((stream->stps_present =
7952 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stps,
7953 &stream->stps) ? TRUE : FALSE) == TRUE) {
7954 /* copy atom data into a new buffer for later use */
7955 stream->stps.data = g_memdup (stream->stps.data, stream->stps.size);
7957 /* skip version + flags */
7958 if (!gst_byte_reader_skip (&stream->stps, 1 + 3) ||
7959 !gst_byte_reader_get_uint32_be (&stream->stps,
7960 &stream->n_sample_partial_syncs))
7963 /* if there are no entries, the stss table contains the real
7965 if (stream->n_sample_partial_syncs) {
7966 /* make sure there's enough data */
7967 if (!qt_atom_parser_has_chunks (&stream->stps,
7968 stream->n_sample_partial_syncs, 4))
7975 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsz, &stream->stsz))
7978 /* copy atom data into a new buffer for later use */
7979 stream->stsz.data = g_memdup (stream->stsz.data, stream->stsz.size);
7981 /* skip version + flags */
7982 if (!gst_byte_reader_skip (&stream->stsz, 1 + 3) ||
7983 !gst_byte_reader_get_uint32_be (&stream->stsz, &stream->sample_size))
7986 if (!gst_byte_reader_get_uint32_be (&stream->stsz, &stream->n_samples))
7989 if (!stream->n_samples)
7992 /* sample-to-chunk atom */
7993 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsc, &stream->stsc))
7996 /* copy atom data into a new buffer for later use */
7997 stream->stsc.data = g_memdup (stream->stsc.data, stream->stsc.size);
7999 /* skip version + flags */
8000 if (!gst_byte_reader_skip (&stream->stsc, 1 + 3) ||
8001 !gst_byte_reader_get_uint32_be (&stream->stsc,
8002 &stream->n_samples_per_chunk))
8005 GST_DEBUG_OBJECT (qtdemux, "n_samples_per_chunk %u",
8006 stream->n_samples_per_chunk);
8008 /* make sure there's enough data */
8009 if (!qt_atom_parser_has_chunks (&stream->stsc, stream->n_samples_per_chunk,
8015 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stco, &stream->stco))
8016 stream->co_size = sizeof (guint32);
8017 else if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_co64,
8019 stream->co_size = sizeof (guint64);
8023 /* copy atom data into a new buffer for later use */
8024 stream->stco.data = g_memdup (stream->stco.data, stream->stco.size);
8026 /* skip version + flags */
8027 if (!gst_byte_reader_skip (&stream->stco, 1 + 3))
8030 /* chunks_are_samples == TRUE means treat chunks as samples */
8031 stream->chunks_are_samples = stream->sample_size && !stream->sampled;
8032 if (stream->chunks_are_samples) {
8033 /* treat chunks as samples */
8034 if (!gst_byte_reader_get_uint32_be (&stream->stco, &stream->n_samples))
8037 /* skip number of entries */
8038 if (!gst_byte_reader_skip (&stream->stco, 4))
8041 /* make sure there are enough data in the stsz atom */
8042 if (!stream->sample_size) {
8043 /* different sizes for each sample */
8044 if (!qt_atom_parser_has_chunks (&stream->stsz, stream->n_samples, 4))
8049 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
8050 stream->n_samples, (guint) sizeof (QtDemuxSample),
8051 stream->n_samples * sizeof (QtDemuxSample) / (1024.0 * 1024.0));
8053 if (stream->n_samples >=
8054 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample)) {
8055 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
8056 "be larger than %uMB (broken file?)", stream->n_samples,
8057 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
8061 g_assert (stream->samples == NULL);
8062 stream->samples = g_try_new0 (QtDemuxSample, stream->n_samples);
8063 if (!stream->samples) {
8064 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
8069 /* composition time-to-sample */
8070 if ((stream->ctts_present =
8071 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_ctts,
8072 &stream->ctts) ? TRUE : FALSE) == TRUE) {
8073 GstByteReader cslg = GST_BYTE_READER_INIT (NULL, 0);
8075 /* copy atom data into a new buffer for later use */
8076 stream->ctts.data = g_memdup (stream->ctts.data, stream->ctts.size);
8078 /* skip version + flags */
8079 if (!gst_byte_reader_skip (&stream->ctts, 1 + 3)
8080 || !gst_byte_reader_get_uint32_be (&stream->ctts,
8081 &stream->n_composition_times))
8084 /* make sure there's enough data */
8085 if (!qt_atom_parser_has_chunks (&stream->ctts, stream->n_composition_times,
8089 /* This is optional, if missing we iterate the ctts */
8090 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_cslg, &cslg)) {
8091 if (!gst_byte_reader_skip (&cslg, 1 + 3)
8092 || !gst_byte_reader_get_uint32_be (&cslg, &stream->cslg_shift)) {
8093 g_free ((gpointer) cslg.data);
8097 gint32 cslg_least = 0;
8098 guint num_entries, pos;
8101 pos = gst_byte_reader_get_pos (&stream->ctts);
8102 num_entries = stream->n_composition_times;
8104 stream->cslg_shift = 0;
8106 for (i = 0; i < num_entries; i++) {
8109 gst_byte_reader_skip_unchecked (&stream->ctts, 4);
8110 offset = gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
8112 if (offset < cslg_least)
8113 cslg_least = offset;
8117 stream->cslg_shift = ABS (cslg_least);
8119 stream->cslg_shift = 0;
8121 /* reset the reader so we can generate sample table */
8122 gst_byte_reader_set_pos (&stream->ctts, pos);
8125 /* Ensure the cslg_shift value is consistent so we can use it
8126 * unconditionnally to produce TS and Segment */
8127 stream->cslg_shift = 0;
8134 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8135 (_("This file is corrupt and cannot be played.")), (NULL));
8140 gst_qtdemux_stbl_free (stream);
8141 if (!qtdemux->fragmented) {
8142 /* not quite good */
8143 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
8146 /* may pick up samples elsewhere */
8152 /* collect samples from the next sample to be parsed up to sample @n for @stream
8153 * by reading the info from @stbl
8155 * This code can be executed from both the streaming thread and the seeking
8156 * thread so it takes the object lock to protect itself
8159 qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream, guint32 n)
8162 QtDemuxSample *samples, *first, *cur, *last;
8163 guint32 n_samples_per_chunk;
8166 GST_LOG_OBJECT (qtdemux, "parsing samples for stream fourcc %"
8167 GST_FOURCC_FORMAT ", pad %s", GST_FOURCC_ARGS (stream->fourcc),
8168 stream->pad ? GST_PAD_NAME (stream->pad) : "(NULL)");
8170 n_samples = stream->n_samples;
8173 goto out_of_samples;
8175 GST_OBJECT_LOCK (qtdemux);
8176 if (n <= stream->stbl_index)
8177 goto already_parsed;
8179 GST_DEBUG_OBJECT (qtdemux, "parsing up to sample %u", n);
8181 if (!stream->stsz.data) {
8182 /* so we already parsed and passed all the moov samples;
8183 * onto fragmented ones */
8184 g_assert (qtdemux->fragmented);
8188 /* pointer to the sample table */
8189 samples = stream->samples;
8191 /* starts from -1, moves to the next sample index to parse */
8192 stream->stbl_index++;
8194 /* keep track of the first and last sample to fill */
8195 first = &samples[stream->stbl_index];
8198 if (!stream->chunks_are_samples) {
8199 /* set the sample sizes */
8200 if (stream->sample_size == 0) {
8201 /* different sizes for each sample */
8202 for (cur = first; cur <= last; cur++) {
8203 cur->size = gst_byte_reader_get_uint32_be_unchecked (&stream->stsz);
8204 GST_LOG_OBJECT (qtdemux, "sample %d has size %u",
8205 (guint) (cur - samples), cur->size);
8208 /* samples have the same size */
8209 GST_LOG_OBJECT (qtdemux, "all samples have size %u", stream->sample_size);
8210 for (cur = first; cur <= last; cur++)
8211 cur->size = stream->sample_size;
8215 n_samples_per_chunk = stream->n_samples_per_chunk;
8218 for (i = stream->stsc_index; i < n_samples_per_chunk; i++) {
8221 if (stream->stsc_chunk_index >= stream->last_chunk
8222 || stream->stsc_chunk_index < stream->first_chunk) {
8223 stream->first_chunk =
8224 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
8225 stream->samples_per_chunk =
8226 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
8227 gst_byte_reader_skip_unchecked (&stream->stsc, 4);
8229 /* chunk numbers are counted from 1 it seems */
8230 if (G_UNLIKELY (stream->first_chunk == 0))
8233 --stream->first_chunk;
8235 /* the last chunk of each entry is calculated by taking the first chunk
8236 * of the next entry; except if there is no next, where we fake it with
8238 if (G_UNLIKELY (i == (stream->n_samples_per_chunk - 1))) {
8239 stream->last_chunk = G_MAXUINT32;
8241 stream->last_chunk =
8242 gst_byte_reader_peek_uint32_be_unchecked (&stream->stsc);
8243 if (G_UNLIKELY (stream->last_chunk == 0))
8246 --stream->last_chunk;
8249 GST_LOG_OBJECT (qtdemux,
8250 "entry %d has first_chunk %d, last_chunk %d, samples_per_chunk %d", i,
8251 stream->first_chunk, stream->last_chunk, stream->samples_per_chunk);
8253 if (G_UNLIKELY (stream->last_chunk < stream->first_chunk))
8256 if (stream->last_chunk != G_MAXUINT32) {
8257 if (!qt_atom_parser_peek_sub (&stream->stco,
8258 stream->first_chunk * stream->co_size,
8259 (stream->last_chunk - stream->first_chunk) * stream->co_size,
8264 stream->co_chunk = stream->stco;
8265 if (!gst_byte_reader_skip (&stream->co_chunk,
8266 stream->first_chunk * stream->co_size))
8270 stream->stsc_chunk_index = stream->first_chunk;
8273 last_chunk = stream->last_chunk;
8275 if (stream->chunks_are_samples) {
8276 cur = &samples[stream->stsc_chunk_index];
8278 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
8281 stream->stsc_chunk_index = j;
8286 qt_atom_parser_get_offset_unchecked (&stream->co_chunk,
8289 GST_LOG_OBJECT (qtdemux, "Created entry %d with offset "
8290 "%" G_GUINT64_FORMAT, j, cur->offset);
8292 if (stream->samples_per_frame * stream->bytes_per_frame) {
8294 (stream->samples_per_chunk * stream->n_channels) /
8295 stream->samples_per_frame * stream->bytes_per_frame;
8297 cur->size = stream->samples_per_chunk;
8300 GST_DEBUG_OBJECT (qtdemux,
8301 "keyframe sample %d: timestamp %" GST_TIME_FORMAT ", size %u",
8302 j, GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream,
8303 stream->stco_sample_index)), cur->size);
8305 cur->timestamp = stream->stco_sample_index;
8306 cur->duration = stream->samples_per_chunk;
8307 cur->keyframe = TRUE;
8310 stream->stco_sample_index += stream->samples_per_chunk;
8312 stream->stsc_chunk_index = j;
8314 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
8315 guint32 samples_per_chunk;
8316 guint64 chunk_offset;
8318 if (!stream->stsc_sample_index
8319 && !qt_atom_parser_get_offset (&stream->co_chunk, stream->co_size,
8320 &stream->chunk_offset))
8323 samples_per_chunk = stream->samples_per_chunk;
8324 chunk_offset = stream->chunk_offset;
8326 for (k = stream->stsc_sample_index; k < samples_per_chunk; k++) {
8327 GST_LOG_OBJECT (qtdemux, "creating entry %d with offset %"
8328 G_GUINT64_FORMAT " and size %d",
8329 (guint) (cur - samples), chunk_offset, cur->size);
8331 cur->offset = chunk_offset;
8332 chunk_offset += cur->size;
8335 if (G_UNLIKELY (cur > last)) {
8337 stream->stsc_sample_index = k + 1;
8338 stream->chunk_offset = chunk_offset;
8339 stream->stsc_chunk_index = j;
8343 stream->stsc_sample_index = 0;
8345 stream->stsc_chunk_index = j;
8347 stream->stsc_index++;
8350 if (stream->chunks_are_samples)
8354 guint32 n_sample_times;
8356 n_sample_times = stream->n_sample_times;
8359 for (i = stream->stts_index; i < n_sample_times; i++) {
8360 guint32 stts_samples;
8361 gint32 stts_duration;
8364 if (stream->stts_sample_index >= stream->stts_samples
8365 || !stream->stts_sample_index) {
8367 stream->stts_samples =
8368 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
8369 stream->stts_duration =
8370 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
8372 GST_LOG_OBJECT (qtdemux, "block %d, %u timestamps, duration %u",
8373 i, stream->stts_samples, stream->stts_duration);
8375 stream->stts_sample_index = 0;
8378 stts_samples = stream->stts_samples;
8379 stts_duration = stream->stts_duration;
8380 stts_time = stream->stts_time;
8382 for (j = stream->stts_sample_index; j < stts_samples; j++) {
8383 GST_DEBUG_OBJECT (qtdemux,
8384 "sample %d: index %d, timestamp %" GST_TIME_FORMAT,
8385 (guint) (cur - samples), j,
8386 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stts_time)));
8388 cur->timestamp = stts_time;
8389 cur->duration = stts_duration;
8391 /* avoid 32-bit wrap-around,
8392 * but still mind possible 'negative' duration */
8393 stts_time += (gint64) stts_duration;
8396 if (G_UNLIKELY (cur > last)) {
8398 stream->stts_time = stts_time;
8399 stream->stts_sample_index = j + 1;
8403 stream->stts_sample_index = 0;
8404 stream->stts_time = stts_time;
8405 stream->stts_index++;
8407 /* fill up empty timestamps with the last timestamp, this can happen when
8408 * the last samples do not decode and so we don't have timestamps for them.
8409 * We however look at the last timestamp to estimate the track length so we
8410 * need something in here. */
8411 for (; cur < last; cur++) {
8412 GST_DEBUG_OBJECT (qtdemux,
8413 "fill sample %d: timestamp %" GST_TIME_FORMAT,
8414 (guint) (cur - samples),
8415 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stream->stts_time)));
8416 cur->timestamp = stream->stts_time;
8422 /* sample sync, can be NULL */
8423 if (stream->stss_present == TRUE) {
8424 guint32 n_sample_syncs;
8426 n_sample_syncs = stream->n_sample_syncs;
8428 if (!n_sample_syncs) {
8429 GST_DEBUG_OBJECT (qtdemux, "all samples are keyframes");
8430 stream->all_keyframe = TRUE;
8432 for (i = stream->stss_index; i < n_sample_syncs; i++) {
8433 /* note that the first sample is index 1, not 0 */
8436 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stss);
8438 if (G_LIKELY (index > 0 && index <= n_samples)) {
8440 samples[index].keyframe = TRUE;
8441 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
8442 /* and exit if we have enough samples */
8443 if (G_UNLIKELY (index >= n)) {
8450 stream->stss_index = i;
8453 /* stps marks partial sync frames like open GOP I-Frames */
8454 if (stream->stps_present == TRUE) {
8455 guint32 n_sample_partial_syncs;
8457 n_sample_partial_syncs = stream->n_sample_partial_syncs;
8459 /* if there are no entries, the stss table contains the real
8461 if (n_sample_partial_syncs) {
8462 for (i = stream->stps_index; i < n_sample_partial_syncs; i++) {
8463 /* note that the first sample is index 1, not 0 */
8466 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stps);
8468 if (G_LIKELY (index > 0 && index <= n_samples)) {
8470 samples[index].keyframe = TRUE;
8471 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
8472 /* and exit if we have enough samples */
8473 if (G_UNLIKELY (index >= n)) {
8480 stream->stps_index = i;
8484 /* no stss, all samples are keyframes */
8485 stream->all_keyframe = TRUE;
8486 GST_DEBUG_OBJECT (qtdemux, "setting all keyframes");
8491 /* composition time to sample */
8492 if (stream->ctts_present == TRUE) {
8493 guint32 n_composition_times;
8495 gint32 ctts_soffset;
8497 /* Fill in the pts_offsets */
8499 n_composition_times = stream->n_composition_times;
8501 for (i = stream->ctts_index; i < n_composition_times; i++) {
8502 if (stream->ctts_sample_index >= stream->ctts_count
8503 || !stream->ctts_sample_index) {
8504 stream->ctts_count =
8505 gst_byte_reader_get_uint32_be_unchecked (&stream->ctts);
8506 stream->ctts_soffset =
8507 gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
8508 stream->ctts_sample_index = 0;
8511 ctts_count = stream->ctts_count;
8512 ctts_soffset = stream->ctts_soffset;
8514 for (j = stream->ctts_sample_index; j < ctts_count; j++) {
8515 cur->pts_offset = ctts_soffset;
8518 if (G_UNLIKELY (cur > last)) {
8520 stream->ctts_sample_index = j + 1;
8524 stream->ctts_sample_index = 0;
8525 stream->ctts_index++;
8529 stream->stbl_index = n;
8530 /* if index has been completely parsed, free data that is no-longer needed */
8531 if (n + 1 == stream->n_samples) {
8532 gst_qtdemux_stbl_free (stream);
8533 GST_DEBUG_OBJECT (qtdemux, "parsed all available samples;");
8534 if (qtdemux->pullbased) {
8535 GST_DEBUG_OBJECT (qtdemux, "checking for more samples");
8536 while (n + 1 == stream->n_samples)
8537 if (qtdemux_add_fragmented_samples (qtdemux) != GST_FLOW_OK)
8541 GST_OBJECT_UNLOCK (qtdemux);
8548 GST_LOG_OBJECT (qtdemux,
8549 "Tried to parse up to sample %u but this sample has already been parsed",
8551 /* if fragmented, there may be more */
8552 if (qtdemux->fragmented && n == stream->stbl_index)
8554 GST_OBJECT_UNLOCK (qtdemux);
8560 GST_LOG_OBJECT (qtdemux,
8561 "Tried to parse up to sample %u but there are only %u samples", n + 1,
8563 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8564 (_("This file is corrupt and cannot be played.")), (NULL));
8569 GST_OBJECT_UNLOCK (qtdemux);
8570 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8571 (_("This file is corrupt and cannot be played.")), (NULL));
8576 /* collect all segment info for @stream.
8579 qtdemux_parse_segments (GstQTDemux * qtdemux, QtDemuxStream * stream,
8583 /* accept edts if they contain gaps at start and there is only
8584 * one media segment */
8585 gboolean allow_pushbased_edts = TRUE;
8586 gint media_segments_count = 0;
8588 /* parse and prepare segment info from the edit list */
8589 GST_DEBUG_OBJECT (qtdemux, "looking for edit list container");
8590 stream->n_segments = 0;
8591 stream->segments = NULL;
8592 if ((edts = qtdemux_tree_get_child_by_type (trak, FOURCC_edts))) {
8595 gint i, count, entry_size;
8601 GST_DEBUG_OBJECT (qtdemux, "looking for edit list");
8602 if (!(elst = qtdemux_tree_get_child_by_type (edts, FOURCC_elst)))
8605 buffer = elst->data;
8607 version = QT_UINT8 (buffer + 8);
8608 entry_size = (version == 1) ? 20 : 12;
8610 n_segments = QT_UINT32 (buffer + 12);
8612 /* we might allocate a bit too much, at least allocate 1 segment */
8613 stream->segments = g_new (QtDemuxSegment, MAX (n_segments, 1));
8615 /* segments always start from 0 */
8619 for (i = 0; i < n_segments; i++) {
8622 gboolean time_valid = TRUE;
8623 QtDemuxSegment *segment;
8625 GstClockTime media_start = GST_CLOCK_TIME_NONE;
8628 media_time = QT_UINT64 (buffer + 24 + i * entry_size);
8629 duration = QT_UINT64 (buffer + 16 + i * entry_size);
8630 if (media_time == G_MAXUINT64)
8633 media_time = QT_UINT32 (buffer + 20 + i * entry_size);
8634 duration = QT_UINT32 (buffer + 16 + i * entry_size);
8635 if (media_time == G_MAXUINT32)
8640 media_start = QTSTREAMTIME_TO_GSTTIME (stream, media_time);
8642 segment = &stream->segments[count++];
8644 /* time and duration expressed in global timescale */
8645 segment->time = stime;
8646 /* add non scaled values so we don't cause roundoff errors */
8647 if (duration || media_start == GST_CLOCK_TIME_NONE) {
8649 stime = QTTIME_TO_GSTTIME (qtdemux, time);
8650 segment->duration = stime - segment->time;
8652 /* zero duration does not imply media_start == media_stop
8653 * but, only specify media_start.*/
8654 stime = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
8655 if (GST_CLOCK_TIME_IS_VALID (stime) && time_valid
8656 && stime >= media_start) {
8657 segment->duration = stime - media_start;
8659 segment->duration = GST_CLOCK_TIME_NONE;
8662 segment->stop_time = stime;
8664 segment->trak_media_start = media_time;
8665 /* media_time expressed in stream timescale */
8667 segment->media_start = media_start;
8668 segment->media_stop = segment->media_start + segment->duration;
8669 media_segments_count++;
8671 segment->media_start = GST_CLOCK_TIME_NONE;
8672 segment->media_stop = GST_CLOCK_TIME_NONE;
8675 QT_UINT32 (buffer + ((version == 1) ? 32 : 24) + i * entry_size);
8677 if (rate_int <= 1) {
8678 /* 0 is not allowed, some programs write 1 instead of the floating point
8680 GST_WARNING_OBJECT (qtdemux, "found suspicious rate %" G_GUINT32_FORMAT,
8684 segment->rate = rate_int / 65536.0;
8687 GST_DEBUG_OBJECT (qtdemux, "created segment %d time %" GST_TIME_FORMAT
8688 ", duration %" GST_TIME_FORMAT ", media_start %" GST_TIME_FORMAT
8689 " (%" G_GUINT64_FORMAT ") , media_stop %" GST_TIME_FORMAT
8690 " stop_time %" GST_TIME_FORMAT " rate %g, (%d) timescale %u",
8691 i, GST_TIME_ARGS (segment->time),
8692 GST_TIME_ARGS (segment->duration),
8693 GST_TIME_ARGS (segment->media_start), media_time,
8694 GST_TIME_ARGS (segment->media_stop),
8695 GST_TIME_ARGS (segment->stop_time), segment->rate, rate_int,
8697 if (segment->stop_time > qtdemux->segment.stop) {
8698 GST_WARNING_OBJECT (qtdemux, "Segment %d "
8699 " extends to %" GST_TIME_FORMAT
8700 " past the end of the file duration %" GST_TIME_FORMAT
8701 " it will be truncated", i, GST_TIME_ARGS (segment->stop_time),
8702 GST_TIME_ARGS (qtdemux->segment.stop));
8703 qtdemux->segment.stop = segment->stop_time;
8706 GST_DEBUG_OBJECT (qtdemux, "found %d segments", count);
8707 stream->n_segments = count;
8708 if (media_segments_count != 1)
8709 allow_pushbased_edts = FALSE;
8713 /* push based does not handle segments, so act accordingly here,
8714 * and warn if applicable */
8715 if (!qtdemux->pullbased && !allow_pushbased_edts) {
8716 GST_WARNING_OBJECT (qtdemux, "streaming; discarding edit list segments");
8717 /* remove and use default one below, we stream like it anyway */
8718 g_free (stream->segments);
8719 stream->segments = NULL;
8720 stream->n_segments = 0;
8723 /* no segments, create one to play the complete trak */
8724 if (stream->n_segments == 0) {
8725 GstClockTime stream_duration =
8726 QTSTREAMTIME_TO_GSTTIME (stream, stream->duration);
8728 if (stream->segments == NULL)
8729 stream->segments = g_new (QtDemuxSegment, 1);
8731 /* represent unknown our way */
8732 if (stream_duration == 0)
8733 stream_duration = GST_CLOCK_TIME_NONE;
8735 stream->segments[0].time = 0;
8736 stream->segments[0].stop_time = stream_duration;
8737 stream->segments[0].duration = stream_duration;
8738 stream->segments[0].media_start = 0;
8739 stream->segments[0].media_stop = stream_duration;
8740 stream->segments[0].rate = 1.0;
8741 stream->segments[0].trak_media_start = 0;
8743 GST_DEBUG_OBJECT (qtdemux, "created dummy segment %" GST_TIME_FORMAT,
8744 GST_TIME_ARGS (stream_duration));
8745 stream->n_segments = 1;
8746 stream->dummy_segment = TRUE;
8748 GST_DEBUG_OBJECT (qtdemux, "using %d segments", stream->n_segments);
8754 * Parses the stsd atom of a svq3 trak looking for
8755 * the SMI and gama atoms.
8758 qtdemux_parse_svq3_stsd_data (GstQTDemux * qtdemux, GNode * stsd,
8759 guint8 ** gamma, GstBuffer ** seqh)
8761 guint8 *_gamma = NULL;
8762 GstBuffer *_seqh = NULL;
8763 guint8 *stsd_data = stsd->data;
8764 guint32 length = QT_UINT32 (stsd_data);
8768 GST_WARNING_OBJECT (qtdemux, "stsd too short");
8774 version = QT_UINT16 (stsd_data);
8779 while (length > 8) {
8780 guint32 fourcc, size;
8782 size = QT_UINT32 (stsd_data);
8783 fourcc = QT_FOURCC (stsd_data + 4);
8784 data = stsd_data + 8;
8787 GST_WARNING_OBJECT (qtdemux, "Atom of size 0 found, aborting "
8788 "svq3 atom parsing");
8797 GST_WARNING_OBJECT (qtdemux, "Unexpected size %" G_GUINT32_FORMAT
8798 " for gama atom, expected 12", size);
8803 if (size > 16 && QT_FOURCC (data) == FOURCC_SEQH) {
8805 if (_seqh != NULL) {
8806 GST_WARNING_OBJECT (qtdemux, "Unexpected second SEQH SMI atom "
8807 " found, ignoring");
8809 seqh_size = QT_UINT32 (data + 4);
8810 if (seqh_size > 0) {
8811 _seqh = gst_buffer_new_and_alloc (seqh_size);
8812 gst_buffer_fill (_seqh, 0, data + 8, seqh_size);
8819 GST_WARNING_OBJECT (qtdemux, "Unhandled atom %" GST_FOURCC_FORMAT
8820 " in SVQ3 entry in stsd atom", GST_FOURCC_ARGS (fourcc));
8824 if (size <= length) {
8830 GST_WARNING_OBJECT (qtdemux, "SVQ3 entry too short in stsd atom");
8833 GST_WARNING_OBJECT (qtdemux, "Unexpected version for SVQ3 entry %"
8834 G_GUINT16_FORMAT, version);
8845 gst_buffer_unref (_seqh);
8850 qtdemux_get_rtsp_uri_from_hndl (GstQTDemux * qtdemux, GNode * minf)
8857 * Get 'dinf', to get its child 'dref', that might contain a 'hndl'
8858 * atom that might contain a 'data' atom with the rtsp uri.
8859 * This case was reported in bug #597497, some info about
8860 * the hndl atom can be found in TN1195
8862 dinf = qtdemux_tree_get_child_by_type (minf, FOURCC_dinf);
8863 GST_DEBUG_OBJECT (qtdemux, "Trying to obtain rtsp URI for stream trak");
8866 guint32 dref_num_entries = 0;
8867 if (qtdemux_tree_get_child_by_type_full (dinf, FOURCC_dref, &dref) &&
8868 gst_byte_reader_skip (&dref, 4) &&
8869 gst_byte_reader_get_uint32_be (&dref, &dref_num_entries)) {
8872 /* search dref entries for hndl atom */
8873 for (i = 0; i < dref_num_entries; i++) {
8874 guint32 size = 0, type;
8875 guint8 string_len = 0;
8876 if (gst_byte_reader_get_uint32_be (&dref, &size) &&
8877 qt_atom_parser_get_fourcc (&dref, &type)) {
8878 if (type == FOURCC_hndl) {
8879 GST_DEBUG_OBJECT (qtdemux, "Found hndl atom");
8881 /* skip data reference handle bytes and the
8882 * following pascal string and some extra 4
8883 * bytes I have no idea what are */
8884 if (!gst_byte_reader_skip (&dref, 4) ||
8885 !gst_byte_reader_get_uint8 (&dref, &string_len) ||
8886 !gst_byte_reader_skip (&dref, string_len + 4)) {
8887 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl atom");
8891 /* iterate over the atoms to find the data atom */
8892 while (gst_byte_reader_get_remaining (&dref) >= 8) {
8896 if (gst_byte_reader_get_uint32_be (&dref, &atom_size) &&
8897 qt_atom_parser_get_fourcc (&dref, &atom_type)) {
8898 if (atom_type == FOURCC_data) {
8899 const guint8 *uri_aux = NULL;
8901 /* found the data atom that might contain the rtsp uri */
8902 GST_DEBUG_OBJECT (qtdemux, "Found data atom inside "
8903 "hndl atom, interpreting it as an URI");
8904 if (gst_byte_reader_peek_data (&dref, atom_size - 8,
8906 if (g_strstr_len ((gchar *) uri_aux, 7, "rtsp://") != NULL)
8907 uri = g_strndup ((gchar *) uri_aux, atom_size - 8);
8909 GST_WARNING_OBJECT (qtdemux, "Data atom in hndl atom "
8910 "didn't contain a rtsp address");
8912 GST_WARNING_OBJECT (qtdemux, "Failed to get the data "
8917 /* skipping to the next entry */
8918 if (!gst_byte_reader_skip (&dref, atom_size - 8))
8921 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl child "
8928 /* skip to the next entry */
8929 if (!gst_byte_reader_skip (&dref, size - 8))
8932 GST_WARNING_OBJECT (qtdemux, "Error parsing dref atom");
8935 GST_DEBUG_OBJECT (qtdemux, "Finished parsing dref atom");
8941 #define AMR_NB_ALL_MODES 0x81ff
8942 #define AMR_WB_ALL_MODES 0x83ff
8944 qtdemux_parse_amr_bitrate (GstBuffer * buf, gboolean wb)
8946 /* The 'damr' atom is of the form:
8948 * | vendor | decoder_ver | mode_set | mode_change_period | frames/sample |
8949 * 32 b 8 b 16 b 8 b 8 b
8951 * The highest set bit of the first 7 (AMR-NB) or 8 (AMR-WB) bits of mode_set
8952 * represents the highest mode used in the stream (and thus the maximum
8953 * bitrate), with a couple of special cases as seen below.
8956 /* Map of frame type ID -> bitrate */
8957 static const guint nb_bitrates[] = {
8958 4750, 5150, 5900, 6700, 7400, 7950, 10200, 12200
8960 static const guint wb_bitrates[] = {
8961 6600, 8850, 12650, 14250, 15850, 18250, 19850, 23050, 23850
8967 gst_buffer_map (buf, &map, GST_MAP_READ);
8969 if (map.size != 0x11) {
8970 GST_DEBUG ("Atom should have size 0x11, not %" G_GSIZE_FORMAT, map.size);
8974 if (QT_FOURCC (map.data + 4) != FOURCC_damr) {
8975 GST_DEBUG ("Unknown atom in %" GST_FOURCC_FORMAT,
8976 GST_FOURCC_ARGS (QT_UINT32 (map.data + 4)));
8980 mode_set = QT_UINT16 (map.data + 13);
8982 if (mode_set == (wb ? AMR_WB_ALL_MODES : AMR_NB_ALL_MODES))
8983 max_mode = 7 + (wb ? 1 : 0);
8985 /* AMR-NB modes fo from 0-7, and AMR-WB modes go from 0-8 */
8986 max_mode = g_bit_nth_msf ((gulong) mode_set & (wb ? 0x1ff : 0xff), -1);
8988 if (max_mode == -1) {
8989 GST_DEBUG ("No mode indication was found (mode set) = %x",
8994 gst_buffer_unmap (buf, &map);
8995 return wb ? wb_bitrates[max_mode] : nb_bitrates[max_mode];
8998 gst_buffer_unmap (buf, &map);
9003 qtdemux_parse_transformation_matrix (GstQTDemux * qtdemux,
9004 GstByteReader * reader, guint32 * matrix, const gchar * atom)
9007 * 9 values of 32 bits (fixed point 16.16, except 2 5 and 8 that are 2.30)
9013 if (gst_byte_reader_get_remaining (reader) < 36)
9016 matrix[0] = gst_byte_reader_get_uint32_be_unchecked (reader);
9017 matrix[1] = gst_byte_reader_get_uint32_be_unchecked (reader);
9018 matrix[2] = gst_byte_reader_get_uint32_be_unchecked (reader);
9019 matrix[3] = gst_byte_reader_get_uint32_be_unchecked (reader);
9020 matrix[4] = gst_byte_reader_get_uint32_be_unchecked (reader);
9021 matrix[5] = gst_byte_reader_get_uint32_be_unchecked (reader);
9022 matrix[6] = gst_byte_reader_get_uint32_be_unchecked (reader);
9023 matrix[7] = gst_byte_reader_get_uint32_be_unchecked (reader);
9024 matrix[8] = gst_byte_reader_get_uint32_be_unchecked (reader);
9026 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix from atom %s", atom);
9027 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[0] >> 16,
9028 matrix[0] & 0xFFFF, matrix[1] >> 16, matrix[1] & 0xFF, matrix[2] >> 16,
9030 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[3] >> 16,
9031 matrix[3] & 0xFFFF, matrix[4] >> 16, matrix[4] & 0xFF, matrix[5] >> 16,
9033 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[6] >> 16,
9034 matrix[6] & 0xFFFF, matrix[7] >> 16, matrix[7] & 0xFF, matrix[8] >> 16,
9041 qtdemux_inspect_transformation_matrix (GstQTDemux * qtdemux,
9042 QtDemuxStream * stream, guint32 * matrix, GstTagList ** taglist)
9049 * This macro will only compare value abdegh, it expects cfi to have already
9052 #define QTCHECK_MATRIX(m,a,b,d,e) ((m)[0] == (a << 16) && (m)[1] == (b << 16) && \
9053 (m)[3] == (d << 16) && (m)[4] == (e << 16))
9055 /* only handle the cases where the last column has standard values */
9056 if (matrix[2] == 0 && matrix[5] == 0 && matrix[8] == 1 << 30) {
9057 const gchar *rotation_tag = NULL;
9059 /* no rotation needed */
9060 if (QTCHECK_MATRIX (matrix, 1, 0, 0, 1)) {
9062 } else if (QTCHECK_MATRIX (matrix, 0, 1, G_MAXUINT16, 0)) {
9063 rotation_tag = "rotate-90";
9064 } else if (QTCHECK_MATRIX (matrix, G_MAXUINT16, 0, 0, G_MAXUINT16)) {
9065 rotation_tag = "rotate-180";
9066 } else if (QTCHECK_MATRIX (matrix, 0, G_MAXUINT16, 1, 0)) {
9067 rotation_tag = "rotate-270";
9069 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
9072 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix rotation %s",
9074 if (rotation_tag != NULL) {
9075 if (*taglist == NULL)
9076 *taglist = gst_tag_list_new_empty ();
9077 gst_tag_list_add (*taglist, GST_TAG_MERGE_REPLACE,
9078 GST_TAG_IMAGE_ORIENTATION, rotation_tag, NULL);
9081 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
9085 /* Parses the boxes defined in ISO/IEC 14496-12 that enable support for
9086 * protected streams (sinf, frma, schm and schi); if the protection scheme is
9087 * Common Encryption (cenc), the function will also parse the tenc box (defined
9088 * in ISO/IEC 23001-7). @container points to the node that contains these boxes
9089 * (typically an enc[v|a|t|s] sample entry); the function will set
9090 * @original_fmt to the fourcc of the original unencrypted stream format.
9091 * Returns TRUE if successful; FALSE otherwise. */
9093 qtdemux_parse_protection_scheme_info (GstQTDemux * qtdemux,
9094 QtDemuxStream * stream, GNode * container, guint32 * original_fmt)
9101 g_return_val_if_fail (qtdemux != NULL, FALSE);
9102 g_return_val_if_fail (stream != NULL, FALSE);
9103 g_return_val_if_fail (container != NULL, FALSE);
9104 g_return_val_if_fail (original_fmt != NULL, FALSE);
9106 sinf = qtdemux_tree_get_child_by_type (container, FOURCC_sinf);
9107 if (G_UNLIKELY (!sinf)) {
9108 if (stream->protection_scheme_type == FOURCC_cenc) {
9109 GST_ERROR_OBJECT (qtdemux, "sinf box does not contain schi box, which is "
9110 "mandatory for Common Encryption");
9116 frma = qtdemux_tree_get_child_by_type (sinf, FOURCC_frma);
9117 if (G_UNLIKELY (!frma)) {
9118 GST_ERROR_OBJECT (qtdemux, "sinf box does not contain mandatory frma box");
9122 *original_fmt = QT_FOURCC ((const guint8 *) frma->data + 8);
9123 GST_DEBUG_OBJECT (qtdemux, "original stream format: '%" GST_FOURCC_FORMAT "'",
9124 GST_FOURCC_ARGS (*original_fmt));
9126 schm = qtdemux_tree_get_child_by_type (sinf, FOURCC_schm);
9128 GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schm box");
9131 stream->protection_scheme_type = QT_FOURCC ((const guint8 *) schm->data + 12);
9132 stream->protection_scheme_version =
9133 QT_UINT32 ((const guint8 *) schm->data + 16);
9135 GST_DEBUG_OBJECT (qtdemux,
9136 "protection_scheme_type: %" GST_FOURCC_FORMAT ", "
9137 "protection_scheme_version: %#010x",
9138 GST_FOURCC_ARGS (stream->protection_scheme_type),
9139 stream->protection_scheme_version);
9141 schi = qtdemux_tree_get_child_by_type (sinf, FOURCC_schi);
9143 GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schi box");
9146 if (stream->protection_scheme_type == FOURCC_cenc) {
9147 QtDemuxCencSampleSetInfo *info;
9149 const guint8 *tenc_data;
9150 guint32 isEncrypted;
9152 const guint8 *default_kid;
9155 if (G_UNLIKELY (!stream->protection_scheme_info))
9156 stream->protection_scheme_info =
9157 g_malloc0 (sizeof (QtDemuxCencSampleSetInfo));
9159 info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
9161 tenc = qtdemux_tree_get_child_by_type (schi, FOURCC_tenc);
9163 GST_ERROR_OBJECT (qtdemux, "schi box does not contain tenc box, "
9164 "which is mandatory for Common Encryption");
9167 tenc_data = (const guint8 *) tenc->data + 12;
9168 isEncrypted = QT_UINT24 (tenc_data);
9169 iv_size = QT_UINT8 (tenc_data + 3);
9170 default_kid = (tenc_data + 4);
9171 kid_buf = gst_buffer_new_allocate (NULL, 16, NULL);
9172 gst_buffer_fill (kid_buf, 0, default_kid, 16);
9173 if (info->default_properties)
9174 gst_structure_free (info->default_properties);
9175 info->default_properties =
9176 gst_structure_new ("application/x-cenc",
9177 "iv_size", G_TYPE_UINT, iv_size,
9178 "encrypted", G_TYPE_BOOLEAN, (isEncrypted == 1),
9179 "kid", GST_TYPE_BUFFER, kid_buf, NULL);
9180 GST_DEBUG_OBJECT (qtdemux, "default sample properties: "
9181 "is_encrypted=%u, iv_size=%u", isEncrypted, iv_size);
9182 gst_buffer_unref (kid_buf);
9188 * With each track we associate a new QtDemuxStream that contains all the info
9190 * traks that do not decode to something (like strm traks) will not have a pad.
9193 qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
9213 QtDemuxStream *stream = NULL;
9214 gboolean new_stream = FALSE;
9215 gchar *codec = NULL;
9216 const guint8 *stsd_data;
9217 guint16 lang_code; /* quicktime lang code or packed iso code */
9219 guint32 tkhd_flags = 0;
9220 guint8 tkhd_version = 0;
9222 guint value_size, stsd_len, len;
9226 GST_DEBUG_OBJECT (qtdemux, "parse_trak");
9228 if (!qtdemux_tree_get_child_by_type_full (trak, FOURCC_tkhd, &tkhd)
9229 || !gst_byte_reader_get_uint8 (&tkhd, &tkhd_version)
9230 || !gst_byte_reader_get_uint24_be (&tkhd, &tkhd_flags))
9233 /* pick between 64 or 32 bits */
9234 value_size = tkhd_version == 1 ? 8 : 4;
9235 if (!gst_byte_reader_skip (&tkhd, value_size * 2) ||
9236 !gst_byte_reader_get_uint32_be (&tkhd, &track_id))
9239 if (!qtdemux->got_moov) {
9240 if (qtdemux_find_stream (qtdemux, track_id))
9241 goto existing_stream;
9242 stream = _create_stream ();
9243 stream->track_id = track_id;
9246 stream = qtdemux_find_stream (qtdemux, track_id);
9248 GST_WARNING_OBJECT (qtdemux, "Stream not found, going to ignore it");
9252 /* flush samples data from this track from previous moov */
9253 gst_qtdemux_stream_flush_segments_data (qtdemux, stream);
9254 gst_qtdemux_stream_flush_samples_data (qtdemux, stream);
9256 /* need defaults for fragments */
9257 qtdemux_parse_trex (qtdemux, stream, &dummy, &dummy, &dummy);
9259 if (stream->pending_tags == NULL)
9260 stream->pending_tags = gst_tag_list_new_empty ();
9262 if ((tkhd_flags & 1) == 0)
9263 stream->disabled = TRUE;
9265 GST_LOG_OBJECT (qtdemux, "track[tkhd] version/flags/id: 0x%02x/%06x/%u",
9266 tkhd_version, tkhd_flags, stream->track_id);
9268 if (!(mdia = qtdemux_tree_get_child_by_type (trak, FOURCC_mdia)))
9271 if (!(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mdhd))) {
9272 /* be nice for some crooked mjp2 files that use mhdr for mdhd */
9273 if (qtdemux->major_brand != FOURCC_mjp2 ||
9274 !(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mhdr)))
9278 len = QT_UINT32 ((guint8 *) mdhd->data);
9279 version = QT_UINT32 ((guint8 *) mdhd->data + 8);
9280 GST_LOG_OBJECT (qtdemux, "track version/flags: %08x", version);
9281 if (version == 0x01000000) {
9284 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 28);
9285 stream->duration = QT_UINT64 ((guint8 *) mdhd->data + 32);
9286 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 36);
9290 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 20);
9291 stream->duration = QT_UINT32 ((guint8 *) mdhd->data + 24);
9292 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 28);
9295 if (lang_code < 0x400) {
9296 qtdemux_lang_map_qt_code_to_iso (stream->lang_id, lang_code);
9297 } else if (lang_code == 0x7fff) {
9298 stream->lang_id[0] = 0; /* unspecified */
9300 stream->lang_id[0] = 0x60 + ((lang_code >> 10) & 0x1F);
9301 stream->lang_id[1] = 0x60 + ((lang_code >> 5) & 0x1F);
9302 stream->lang_id[2] = 0x60 + (lang_code & 0x1F);
9303 stream->lang_id[3] = 0;
9306 GST_LOG_OBJECT (qtdemux, "track timescale: %" G_GUINT32_FORMAT,
9308 GST_LOG_OBJECT (qtdemux, "track duration: %" G_GUINT64_FORMAT,
9310 GST_LOG_OBJECT (qtdemux, "track language code/id: 0x%04x/%s",
9311 lang_code, stream->lang_id);
9313 if (G_UNLIKELY (stream->timescale == 0 || qtdemux->timescale == 0))
9316 if ((tref = qtdemux_tree_get_child_by_type (trak, FOURCC_tref))) {
9317 /* chapters track reference */
9318 GNode *chap = qtdemux_tree_get_child_by_type (tref, FOURCC_chap);
9320 gsize length = GST_READ_UINT32_BE (chap->data);
9321 if (qtdemux->chapters_track_id)
9322 GST_FIXME_OBJECT (qtdemux, "Multiple CHAP tracks");
9325 qtdemux->chapters_track_id =
9326 GST_READ_UINT32_BE ((gint8 *) chap->data + 8);
9331 /* fragmented files may have bogus duration in moov */
9332 if (!qtdemux->fragmented &&
9333 qtdemux->duration != G_MAXINT64 && stream->duration != G_MAXINT32) {
9334 guint64 tdur1, tdur2;
9336 /* don't overflow */
9337 tdur1 = stream->timescale * (guint64) qtdemux->duration;
9338 tdur2 = qtdemux->timescale * (guint64) stream->duration;
9341 * some of those trailers, nowadays, have prologue images that are
9342 * themselves video tracks as well. I haven't really found a way to
9343 * identify those yet, except for just looking at their duration. */
9344 if (tdur1 != 0 && (tdur2 * 10 / tdur1) < 2) {
9345 GST_WARNING_OBJECT (qtdemux,
9346 "Track shorter than 20%% (%" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT
9347 " vs. %" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT ") of the stream "
9348 "found, assuming preview image or something; skipping track",
9349 stream->duration, stream->timescale, qtdemux->duration,
9350 qtdemux->timescale);
9352 gst_qtdemux_stream_free (qtdemux, stream);
9357 if (!(hdlr = qtdemux_tree_get_child_by_type (mdia, FOURCC_hdlr)))
9360 GST_LOG_OBJECT (qtdemux, "track type: %" GST_FOURCC_FORMAT,
9361 GST_FOURCC_ARGS (QT_FOURCC ((guint8 *) hdlr->data + 12)));
9363 len = QT_UINT32 ((guint8 *) hdlr->data);
9365 stream->subtype = QT_FOURCC ((guint8 *) hdlr->data + 16);
9366 GST_LOG_OBJECT (qtdemux, "track subtype: %" GST_FOURCC_FORMAT,
9367 GST_FOURCC_ARGS (stream->subtype));
9369 if (!(minf = qtdemux_tree_get_child_by_type (mdia, FOURCC_minf)))
9372 if (!(stbl = qtdemux_tree_get_child_by_type (minf, FOURCC_stbl)))
9375 /*parse svmi header if existing */
9376 svmi = qtdemux_tree_get_child_by_type (stbl, FOURCC_svmi);
9378 len = QT_UINT32 ((guint8 *) svmi->data);
9379 version = QT_UINT32 ((guint8 *) svmi->data + 8);
9381 GstVideoMultiviewMode mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
9382 GstVideoMultiviewFlags flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
9383 guint8 frame_type, frame_layout;
9385 /* MPEG-A stereo video */
9386 if (qtdemux->major_brand == FOURCC_ss02)
9387 flags |= GST_VIDEO_MULTIVIEW_FLAGS_MIXED_MONO;
9389 frame_type = QT_UINT8 ((guint8 *) svmi->data + 12);
9390 frame_layout = QT_UINT8 ((guint8 *) svmi->data + 13) & 0x01;
9391 switch (frame_type) {
9393 mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
9396 mode = GST_VIDEO_MULTIVIEW_MODE_ROW_INTERLEAVED;
9399 mode = GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME;
9402 /* mode 3 is primary/secondary view sequence, ie
9403 * left/right views in separate tracks. See section 7.2
9404 * of ISO/IEC 23000-11:2009 */
9405 GST_FIXME_OBJECT (qtdemux,
9406 "Implement stereo video in separate streams");
9409 if ((frame_layout & 0x1) == 0)
9410 flags |= GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
9412 GST_LOG_OBJECT (qtdemux,
9413 "StereoVideo: composition type: %u, is_left_first: %u",
9414 frame_type, frame_layout);
9415 stream->multiview_mode = mode;
9416 stream->multiview_flags = flags;
9421 if (!(stsd = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsd)))
9423 stsd_data = (const guint8 *) stsd->data;
9425 /* stsd should at least have one entry */
9426 stsd_len = QT_UINT32 (stsd_data);
9427 if (stsd_len < 24) {
9428 /* .. but skip stream with empty stsd produced by some Vivotek cameras */
9429 if (stream->subtype == FOURCC_vivo) {
9431 gst_qtdemux_stream_free (qtdemux, stream);
9438 GST_LOG_OBJECT (qtdemux, "stsd len: %d", stsd_len);
9440 /* and that entry should fit within stsd */
9441 len = QT_UINT32 (stsd_data + 16);
9442 if (len > stsd_len + 16)
9445 stream->fourcc = fourcc = QT_FOURCC (stsd_data + 16 + 4);
9446 GST_LOG_OBJECT (qtdemux, "stsd type: %" GST_FOURCC_FORMAT,
9447 GST_FOURCC_ARGS (stream->fourcc));
9448 GST_LOG_OBJECT (qtdemux, "stsd type len: %d", len);
9450 if ((fourcc == FOURCC_drms) || (fourcc == FOURCC_drmi))
9451 goto error_encrypted;
9453 if (fourcc == FOURCC_encv || fourcc == FOURCC_enca) {
9454 GNode *enc = qtdemux_tree_get_child_by_type (stsd, fourcc);
9455 stream->protected = TRUE;
9456 if (!qtdemux_parse_protection_scheme_info (qtdemux, stream, enc, &fourcc))
9457 GST_ERROR_OBJECT (qtdemux, "Failed to parse protection scheme info");
9460 if (stream->subtype == FOURCC_vide) {
9461 guint32 w = 0, h = 0;
9463 gint depth, palette_size, palette_count;
9465 guint32 *palette_data = NULL;
9467 stream->sampled = TRUE;
9469 /* version 1 uses some 64-bit ints */
9470 if (!gst_byte_reader_skip (&tkhd, 20 + value_size))
9473 if (!qtdemux_parse_transformation_matrix (qtdemux, &tkhd, matrix, "tkhd"))
9476 if (!gst_byte_reader_get_uint32_be (&tkhd, &w)
9477 || !gst_byte_reader_get_uint32_be (&tkhd, &h))
9480 stream->display_width = w >> 16;
9481 stream->display_height = h >> 16;
9483 qtdemux_inspect_transformation_matrix (qtdemux, stream, matrix,
9484 &stream->pending_tags);
9490 stream->width = QT_UINT16 (stsd_data + offset + 32);
9491 stream->height = QT_UINT16 (stsd_data + offset + 34);
9492 stream->fps_n = 0; /* this is filled in later */
9493 stream->fps_d = 0; /* this is filled in later */
9494 stream->bits_per_sample = QT_UINT16 (stsd_data + offset + 82);
9495 stream->color_table_id = QT_UINT16 (stsd_data + offset + 84);
9497 /* if color_table_id is 0, ctab atom must follow; however some files
9498 * produced by TMPEGEnc have color_table_id = 0 and no ctab atom, so
9499 * if color table is not present we'll correct the value */
9500 if (stream->color_table_id == 0 &&
9501 (len < 90 || QT_FOURCC (stsd_data + offset + 86) != FOURCC_ctab)) {
9502 stream->color_table_id = -1;
9505 GST_LOG_OBJECT (qtdemux, "width %d, height %d, bps %d, color table id %d",
9506 stream->width, stream->height, stream->bits_per_sample,
9507 stream->color_table_id);
9509 depth = stream->bits_per_sample;
9511 /* more than 32 bits means grayscale */
9512 gray = (depth > 32);
9513 /* low 32 bits specify the depth */
9516 /* different number of palette entries is determined by depth. */
9518 if ((depth == 1) || (depth == 2) || (depth == 4) || (depth == 8))
9519 palette_count = (1 << depth);
9520 palette_size = palette_count * 4;
9522 if (stream->color_table_id) {
9523 switch (palette_count) {
9527 palette_data = g_memdup (ff_qt_default_palette_2, palette_size);
9530 palette_data = g_memdup (ff_qt_default_palette_4, palette_size);
9534 palette_data = g_memdup (ff_qt_grayscale_palette_16, palette_size);
9536 palette_data = g_memdup (ff_qt_default_palette_16, palette_size);
9540 palette_data = g_memdup (ff_qt_grayscale_palette_256, palette_size);
9542 palette_data = g_memdup (ff_qt_default_palette_256, palette_size);
9545 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
9546 (_("The video in this file might not play correctly.")),
9547 ("unsupported palette depth %d", depth));
9551 gint i, j, start, end;
9557 start = QT_UINT32 (stsd_data + offset + 86);
9558 palette_count = QT_UINT16 (stsd_data + offset + 90);
9559 end = QT_UINT16 (stsd_data + offset + 92);
9561 GST_LOG_OBJECT (qtdemux, "start %d, end %d, palette_count %d",
9562 start, end, palette_count);
9569 if (len < 94 + (end - start) * 8)
9572 /* palette is always the same size */
9573 palette_data = g_malloc0 (256 * 4);
9574 palette_size = 256 * 4;
9576 for (j = 0, i = start; i <= end; j++, i++) {
9579 a = QT_UINT16 (stsd_data + offset + 94 + (j * 8));
9580 r = QT_UINT16 (stsd_data + offset + 96 + (j * 8));
9581 g = QT_UINT16 (stsd_data + offset + 98 + (j * 8));
9582 b = QT_UINT16 (stsd_data + offset + 100 + (j * 8));
9584 palette_data[i] = ((a & 0xff00) << 16) | ((r & 0xff00) << 8) |
9585 (g & 0xff00) | (b >> 8);
9590 gst_caps_unref (stream->caps);
9593 qtdemux_video_caps (qtdemux, stream, fourcc, stsd_data, &codec);
9594 if (G_UNLIKELY (!stream->caps)) {
9595 g_free (palette_data);
9596 goto unknown_stream;
9600 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
9601 GST_TAG_VIDEO_CODEC, codec, NULL);
9610 if (stream->rgb8_palette)
9611 gst_memory_unref (stream->rgb8_palette);
9612 stream->rgb8_palette = gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY,
9613 palette_data, palette_size, 0, palette_size, palette_data, g_free);
9615 s = gst_caps_get_structure (stream->caps, 0);
9617 /* non-raw video has a palette_data property. raw video has the palette as
9618 * an extra plane that we append to the output buffers before we push
9620 if (!gst_structure_has_name (s, "video/x-raw")) {
9623 palette = gst_buffer_new ();
9624 gst_buffer_append_memory (palette, stream->rgb8_palette);
9625 stream->rgb8_palette = NULL;
9627 gst_caps_set_simple (stream->caps, "palette_data",
9628 GST_TYPE_BUFFER, palette, NULL);
9629 gst_buffer_unref (palette);
9631 } else if (palette_count != 0) {
9632 GST_ELEMENT_WARNING (qtdemux, STREAM, NOT_IMPLEMENTED,
9633 (NULL), ("Unsupported palette depth %d", depth));
9636 GST_LOG_OBJECT (qtdemux, "frame count: %u",
9637 QT_UINT16 (stsd_data + offset + 48));
9642 /* pick 'the' stsd child */
9643 if (!stream->protected)
9644 mp4v = qtdemux_tree_get_child_by_type (stsd, fourcc);
9646 mp4v = qtdemux_tree_get_child_by_type (stsd, FOURCC_encv);
9649 esds = qtdemux_tree_get_child_by_type (mp4v, FOURCC_esds);
9650 pasp = qtdemux_tree_get_child_by_type (mp4v, FOURCC_pasp);
9651 colr = qtdemux_tree_get_child_by_type (mp4v, FOURCC_colr);
9655 const guint8 *pasp_data = (const guint8 *) pasp->data;
9657 stream->par_w = QT_UINT32 (pasp_data + 8);
9658 stream->par_h = QT_UINT32 (pasp_data + 12);
9665 const guint8 *colr_data = (const guint8 *) colr->data;
9666 gint len = QT_UINT32 (colr_data);
9668 if (len == 19 || len == 18) {
9669 guint32 color_type = GST_READ_UINT32_LE (colr_data + 8);
9671 if (color_type == FOURCC_nclx || color_type == FOURCC_nclc) {
9672 guint16 primaries = GST_READ_UINT16_BE (colr_data + 12);
9673 guint16 transfer_function = GST_READ_UINT16_BE (colr_data + 14);
9674 guint16 matrix = GST_READ_UINT16_BE (colr_data + 16);
9675 gboolean full_range = len == 19 ? colr_data[17] >> 7 : FALSE;
9677 switch (primaries) {
9679 stream->colorimetry.primaries = GST_VIDEO_COLOR_PRIMARIES_BT709;
9682 stream->colorimetry.primaries = GST_VIDEO_COLOR_PRIMARIES_BT470BG;
9685 stream->colorimetry.primaries =
9686 GST_VIDEO_COLOR_PRIMARIES_SMPTE170M;
9689 stream->colorimetry.primaries = GST_VIDEO_COLOR_PRIMARIES_BT2020;
9695 switch (transfer_function) {
9697 stream->colorimetry.transfer = GST_VIDEO_TRANSFER_BT709;
9700 stream->colorimetry.transfer = GST_VIDEO_TRANSFER_SMPTE240M;
9708 stream->colorimetry.matrix = GST_VIDEO_COLOR_MATRIX_BT709;
9711 stream->colorimetry.matrix = GST_VIDEO_COLOR_MATRIX_BT601;
9714 stream->colorimetry.matrix = GST_VIDEO_COLOR_MATRIX_SMPTE240M;
9717 stream->colorimetry.matrix = GST_VIDEO_COLOR_MATRIX_BT2020;
9723 stream->colorimetry.range =
9724 full_range ? GST_VIDEO_COLOR_RANGE_0_255 :
9725 GST_VIDEO_COLOR_RANGE_16_235;
9727 GST_DEBUG_OBJECT (qtdemux, "Unsupported color type");
9730 GST_WARNING_OBJECT (qtdemux, "Invalid colr atom size");
9735 gst_qtdemux_handle_esds (qtdemux, stream, esds, stream->pending_tags);
9742 gint len = QT_UINT32 (stsd_data) - 0x66;
9743 const guint8 *avc_data = stsd_data + 0x66;
9746 while (len >= 0x8) {
9749 if (QT_UINT32 (avc_data) <= len)
9750 size = QT_UINT32 (avc_data) - 0x8;
9755 /* No real data, so break out */
9758 switch (QT_FOURCC (avc_data + 0x4)) {
9761 /* parse, if found */
9764 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
9766 /* First 4 bytes are the length of the atom, the next 4 bytes
9767 * are the fourcc, the next 1 byte is the version, and the
9768 * subsequent bytes are profile_tier_level structure like data. */
9769 gst_codec_utils_h264_caps_set_level_and_profile (stream->caps,
9770 avc_data + 8 + 1, size - 1);
9771 buf = gst_buffer_new_and_alloc (size);
9772 gst_buffer_fill (buf, 0, avc_data + 0x8, size);
9773 gst_caps_set_simple (stream->caps,
9774 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9775 gst_buffer_unref (buf);
9783 GST_DEBUG_OBJECT (qtdemux, "found strf codec_data in stsd");
9785 /* First 4 bytes are the length of the atom, the next 4 bytes
9786 * are the fourcc, next 40 bytes are BITMAPINFOHEADER,
9787 * next 1 byte is the version, and the
9788 * subsequent bytes are sequence parameter set like data. */
9790 size -= 40; /* we'll be skipping BITMAPINFOHEADER */
9792 gst_codec_utils_h264_caps_set_level_and_profile (stream->caps,
9793 avc_data + 8 + 40 + 1, size - 1);
9795 buf = gst_buffer_new_and_alloc (size);
9796 gst_buffer_fill (buf, 0, avc_data + 8 + 40, size);
9797 gst_caps_set_simple (stream->caps,
9798 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9799 gst_buffer_unref (buf);
9805 guint avg_bitrate, max_bitrate;
9807 /* bufferSizeDB, maxBitrate and avgBitrate - 4 bytes each */
9811 max_bitrate = QT_UINT32 (avc_data + 0xc);
9812 avg_bitrate = QT_UINT32 (avc_data + 0x10);
9814 if (!max_bitrate && !avg_bitrate)
9817 /* Some muxers seem to swap the average and maximum bitrates
9818 * (I'm looking at you, YouTube), so we swap for sanity. */
9819 if (max_bitrate > 0 && max_bitrate < avg_bitrate) {
9820 guint temp = avg_bitrate;
9822 avg_bitrate = max_bitrate;
9826 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
9827 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
9828 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
9830 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
9831 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
9832 GST_TAG_BITRATE, avg_bitrate, NULL);
9843 avc_data += size + 8;
9852 gint len = QT_UINT32 (stsd_data) - 0x66;
9853 const guint8 *hevc_data = stsd_data + 0x66;
9856 while (len >= 0x8) {
9859 if (QT_UINT32 (hevc_data) <= len)
9860 size = QT_UINT32 (hevc_data) - 0x8;
9865 /* No real data, so break out */
9868 switch (QT_FOURCC (hevc_data + 0x4)) {
9871 /* parse, if found */
9874 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
9876 /* First 4 bytes are the length of the atom, the next 4 bytes
9877 * are the fourcc, the next 1 byte is the version, and the
9878 * subsequent bytes are sequence parameter set like data. */
9879 gst_codec_utils_h265_caps_set_level_tier_and_profile
9880 (stream->caps, hevc_data + 8 + 1, size - 1);
9882 buf = gst_buffer_new_and_alloc (size);
9883 gst_buffer_fill (buf, 0, hevc_data + 0x8, size);
9884 gst_caps_set_simple (stream->caps,
9885 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9886 gst_buffer_unref (buf);
9893 hevc_data += size + 8;
9904 GST_DEBUG_OBJECT (qtdemux, "found %" GST_FOURCC_FORMAT,
9905 GST_FOURCC_ARGS (fourcc));
9907 /* codec data might be in glbl extension atom */
9909 qtdemux_tree_get_child_by_type (mp4v, FOURCC_glbl) : NULL;
9915 GST_DEBUG_OBJECT (qtdemux, "found glbl data in stsd");
9917 len = QT_UINT32 (data);
9920 buf = gst_buffer_new_and_alloc (len);
9921 gst_buffer_fill (buf, 0, data + 8, len);
9922 gst_caps_set_simple (stream->caps,
9923 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9924 gst_buffer_unref (buf);
9931 /* see annex I of the jpeg2000 spec */
9932 GNode *jp2h, *ihdr, *colr, *mjp2, *field, *prefix, *cmap, *cdef;
9934 const gchar *colorspace = NULL;
9936 guint32 ncomp_map = 0;
9937 gint32 *comp_map = NULL;
9938 guint32 nchan_def = 0;
9939 gint32 *chan_def = NULL;
9941 GST_DEBUG_OBJECT (qtdemux, "found mjp2");
9942 /* some required atoms */
9943 mjp2 = qtdemux_tree_get_child_by_type (stsd, FOURCC_mjp2);
9946 jp2h = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2h);
9950 /* number of components; redundant with info in codestream, but useful
9952 ihdr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_ihdr);
9953 if (!ihdr || QT_UINT32 (ihdr->data) != 22)
9955 ncomp = QT_UINT16 (((guint8 *) ihdr->data) + 16);
9957 colr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_colr);
9960 GST_DEBUG_OBJECT (qtdemux, "found colr");
9961 /* extract colour space info */
9962 if (QT_UINT8 ((guint8 *) colr->data + 8) == 1) {
9963 switch (QT_UINT32 ((guint8 *) colr->data + 11)) {
9965 colorspace = "sRGB";
9968 colorspace = "GRAY";
9971 colorspace = "sYUV";
9979 /* colr is required, and only values 16, 17, and 18 are specified,
9980 so error if we have no colorspace */
9983 /* extract component mapping */
9984 cmap = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cmap);
9986 guint32 cmap_len = 0;
9988 cmap_len = QT_UINT32 (cmap->data);
9989 if (cmap_len >= 8) {
9990 /* normal box, subtract off header */
9992 /* cmap: { u16 cmp; u8 mtyp; u8 pcol; }* */
9993 if (cmap_len % 4 == 0) {
9994 ncomp_map = (cmap_len / 4);
9995 comp_map = g_new0 (gint32, ncomp_map);
9996 for (i = 0; i < ncomp_map; i++) {
9999 cmp = QT_UINT16 (((guint8 *) cmap->data) + 8 + i * 4);
10000 mtyp = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 2);
10001 pcol = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 3);
10002 comp_map[i] = (mtyp << 24) | (pcol << 16) | cmp;
10007 /* extract channel definitions */
10008 cdef = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cdef);
10010 guint32 cdef_len = 0;
10012 cdef_len = QT_UINT32 (cdef->data);
10013 if (cdef_len >= 10) {
10014 /* normal box, subtract off header and len */
10016 /* cdef: u16 n; { u16 cn; u16 typ; u16 asoc; }* */
10017 if (cdef_len % 6 == 0) {
10018 nchan_def = (cdef_len / 6);
10019 chan_def = g_new0 (gint32, nchan_def);
10020 for (i = 0; i < nchan_def; i++)
10022 for (i = 0; i < nchan_def; i++) {
10023 guint16 cn, typ, asoc;
10024 cn = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6);
10025 typ = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 2);
10026 asoc = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 4);
10027 if (cn < nchan_def) {
10030 chan_def[cn] = asoc;
10033 chan_def[cn] = 0; /* alpha */
10036 chan_def[cn] = -typ;
10044 gst_caps_set_simple (stream->caps,
10045 "num-components", G_TYPE_INT, ncomp, NULL);
10046 gst_caps_set_simple (stream->caps,
10047 "colorspace", G_TYPE_STRING, colorspace, NULL);
10050 GValue arr = { 0, };
10051 GValue elt = { 0, };
10053 g_value_init (&arr, GST_TYPE_ARRAY);
10054 g_value_init (&elt, G_TYPE_INT);
10055 for (i = 0; i < ncomp_map; i++) {
10056 g_value_set_int (&elt, comp_map[i]);
10057 gst_value_array_append_value (&arr, &elt);
10059 gst_structure_set_value (gst_caps_get_structure (stream->caps, 0),
10060 "component-map", &arr);
10061 g_value_unset (&elt);
10062 g_value_unset (&arr);
10067 GValue arr = { 0, };
10068 GValue elt = { 0, };
10070 g_value_init (&arr, GST_TYPE_ARRAY);
10071 g_value_init (&elt, G_TYPE_INT);
10072 for (i = 0; i < nchan_def; i++) {
10073 g_value_set_int (&elt, chan_def[i]);
10074 gst_value_array_append_value (&arr, &elt);
10076 gst_structure_set_value (gst_caps_get_structure (stream->caps, 0),
10077 "channel-definitions", &arr);
10078 g_value_unset (&elt);
10079 g_value_unset (&arr);
10083 /* some optional atoms */
10084 field = qtdemux_tree_get_child_by_type (mjp2, FOURCC_fiel);
10085 prefix = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2x);
10087 /* indicate possible fields in caps */
10089 data = (guint8 *) field->data + 8;
10091 gst_caps_set_simple (stream->caps, "fields", G_TYPE_INT,
10092 (gint) * data, NULL);
10094 /* add codec_data if provided */
10099 GST_DEBUG_OBJECT (qtdemux, "found prefix data in stsd");
10100 data = prefix->data;
10101 len = QT_UINT32 (data);
10104 buf = gst_buffer_new_and_alloc (len);
10105 gst_buffer_fill (buf, 0, data + 8, len);
10106 gst_caps_set_simple (stream->caps,
10107 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10108 gst_buffer_unref (buf);
10115 /* https://developer.apple.com/standards/qtff-2001.pdf,
10116 * page 92, "Video Sample Description", under table 3.1 */
10119 const off_t compressor_offset =
10120 16 + 4 + 4 * 3 + 2 * 2 + 2 * 4 + 4 + 2;
10121 const off_t min_size = compressor_offset + 32 + 2 + 2;
10124 guint16 color_table_id = 0;
10127 GST_DEBUG_OBJECT (qtdemux, "found jpeg");
10129 /* recover information on interlaced/progressive */
10130 jpeg = qtdemux_tree_get_child_by_type (stsd, FOURCC_jpeg);
10134 len = QT_UINT32 (jpeg->data);
10135 GST_DEBUG_OBJECT (qtdemux, "Found jpeg: len %u, need %lu", len,
10137 if (len >= min_size) {
10138 gst_byte_reader_init (&br, jpeg->data, len);
10140 gst_byte_reader_skip (&br, compressor_offset + 32 + 2);
10141 gst_byte_reader_get_uint16_le (&br, &color_table_id);
10142 if (color_table_id != 0) {
10143 /* the spec says there can be concatenated chunks in the data, and we want
10144 * to find one called field. Walk through them. */
10145 off_t offset = min_size;
10146 while (offset + 8 < len) {
10148 ok = gst_byte_reader_get_uint32_le (&br, &size);
10149 ok &= gst_byte_reader_get_uint32_le (&br, &tag);
10150 if (!ok || size < 8) {
10151 GST_WARNING_OBJECT (qtdemux,
10152 "Failed to walk optional chunk list");
10155 GST_DEBUG_OBJECT (qtdemux,
10156 "Found optional %4.4s chunk, size %u", (const char *) &tag,
10158 if (tag == FOURCC_fiel) {
10159 guint8 n_fields, ordering;
10160 gst_byte_reader_get_uint8 (&br, &n_fields);
10161 gst_byte_reader_get_uint8 (&br, &ordering);
10162 if (n_fields == 1 || n_fields == 2) {
10163 GST_DEBUG_OBJECT (qtdemux,
10164 "Found fiel tag with %u fields, ordering %u", n_fields,
10167 gst_caps_set_simple (stream->caps, "interlace-mode",
10168 G_TYPE_STRING, "interleaved", NULL);
10170 GST_WARNING_OBJECT (qtdemux,
10171 "Found fiel tag with invalid fields (%u)", n_fields);
10177 GST_DEBUG_OBJECT (qtdemux,
10178 "Color table ID is 0, not trying to get interlacedness");
10181 GST_WARNING_OBJECT (qtdemux,
10182 "Length of jpeg chunk is too small, not trying to get interlacedness");
10191 GstBuffer *seqh = NULL;
10192 guint8 *gamma_data = NULL;
10193 gint len = QT_UINT32 (stsd_data);
10195 qtdemux_parse_svq3_stsd_data (qtdemux, stsd, &gamma_data, &seqh);
10197 gst_caps_set_simple (stream->caps, "applied-gamma", G_TYPE_DOUBLE,
10198 QT_FP32 (gamma_data), NULL);
10201 /* sorry for the bad name, but we don't know what this is, other
10202 * than its own fourcc */
10203 gst_caps_set_simple (stream->caps, "seqh", GST_TYPE_BUFFER, seqh,
10207 GST_DEBUG_OBJECT (qtdemux, "found codec_data in stsd");
10208 buf = gst_buffer_new_and_alloc (len);
10209 gst_buffer_fill (buf, 0, stsd_data, len);
10210 gst_caps_set_simple (stream->caps,
10211 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10212 gst_buffer_unref (buf);
10218 gst_caps_set_simple (stream->caps,
10219 "depth", G_TYPE_INT, QT_UINT16 (stsd_data + offset + 82), NULL);
10224 GNode *xith, *xdxt;
10226 GST_DEBUG_OBJECT (qtdemux, "found XiTh");
10227 xith = qtdemux_tree_get_child_by_type (stsd, FOURCC_XiTh);
10231 xdxt = qtdemux_tree_get_child_by_type (xith, FOURCC_XdxT);
10235 GST_DEBUG_OBJECT (qtdemux, "found XdxT node");
10236 /* collect the headers and store them in a stream list so that we can
10237 * send them out first */
10238 qtdemux_parse_theora_extension (qtdemux, stream, xdxt);
10248 GST_DEBUG_OBJECT (qtdemux, "parse ovc1 header");
10249 ovc1 = qtdemux_tree_get_child_by_type (stsd, FOURCC_ovc1);
10252 ovc1_data = ovc1->data;
10253 ovc1_len = QT_UINT32 (ovc1_data);
10254 if (ovc1_len <= 198) {
10255 GST_WARNING_OBJECT (qtdemux, "Too small ovc1 header, skipping");
10258 buf = gst_buffer_new_and_alloc (ovc1_len - 198);
10259 gst_buffer_fill (buf, 0, ovc1_data + 198, ovc1_len - 198);
10260 gst_caps_set_simple (stream->caps,
10261 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10262 gst_buffer_unref (buf);
10267 gint len = QT_UINT32 (stsd_data) - 0x66;
10268 const guint8 *vc1_data = stsd_data + 0x66;
10274 if (QT_UINT32 (vc1_data) <= len)
10275 size = QT_UINT32 (vc1_data) - 8;
10280 /* No real data, so break out */
10283 switch (QT_FOURCC (vc1_data + 0x4)) {
10284 case GST_MAKE_FOURCC ('d', 'v', 'c', '1'):
10288 GST_DEBUG_OBJECT (qtdemux, "found dvc1 codec_data in stsd");
10289 buf = gst_buffer_new_and_alloc (size);
10290 gst_buffer_fill (buf, 0, vc1_data + 8, size);
10291 gst_caps_set_simple (stream->caps,
10292 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10293 gst_buffer_unref (buf);
10300 vc1_data += size + 8;
10309 GST_INFO_OBJECT (qtdemux,
10310 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
10311 GST_FOURCC_ARGS (fourcc), stream->caps);
10313 } else if (stream->subtype == FOURCC_soun) {
10314 int version, samplesize;
10315 guint16 compression_id;
10316 gboolean amrwb = FALSE;
10319 /* sample description entry (16) + sound sample description v0 (20) */
10323 version = QT_UINT32 (stsd_data + offset);
10324 stream->n_channels = QT_UINT16 (stsd_data + offset + 8);
10325 samplesize = QT_UINT16 (stsd_data + offset + 10);
10326 compression_id = QT_UINT16 (stsd_data + offset + 12);
10327 stream->rate = QT_FP32 (stsd_data + offset + 16);
10329 GST_LOG_OBJECT (qtdemux, "version/rev: %08x", version);
10330 GST_LOG_OBJECT (qtdemux, "vendor: %08x",
10331 QT_UINT32 (stsd_data + offset + 4));
10332 GST_LOG_OBJECT (qtdemux, "n_channels: %d", stream->n_channels);
10333 GST_LOG_OBJECT (qtdemux, "sample_size: %d", samplesize);
10334 GST_LOG_OBJECT (qtdemux, "compression_id: %d", compression_id);
10335 GST_LOG_OBJECT (qtdemux, "packet size: %d",
10336 QT_UINT16 (stsd_data + offset + 14));
10337 GST_LOG_OBJECT (qtdemux, "sample rate: %g", stream->rate);
10339 if (compression_id == 0xfffe)
10340 stream->sampled = TRUE;
10342 /* first assume uncompressed audio */
10343 stream->bytes_per_sample = samplesize / 8;
10344 stream->samples_per_frame = stream->n_channels;
10345 stream->bytes_per_frame = stream->n_channels * stream->bytes_per_sample;
10346 stream->samples_per_packet = stream->samples_per_frame;
10347 stream->bytes_per_packet = stream->bytes_per_sample;
10351 /* Yes, these have to be hard-coded */
10354 stream->samples_per_packet = 6;
10355 stream->bytes_per_packet = 1;
10356 stream->bytes_per_frame = 1 * stream->n_channels;
10357 stream->bytes_per_sample = 1;
10358 stream->samples_per_frame = 6 * stream->n_channels;
10363 stream->samples_per_packet = 3;
10364 stream->bytes_per_packet = 1;
10365 stream->bytes_per_frame = 1 * stream->n_channels;
10366 stream->bytes_per_sample = 1;
10367 stream->samples_per_frame = 3 * stream->n_channels;
10372 stream->samples_per_packet = 64;
10373 stream->bytes_per_packet = 34;
10374 stream->bytes_per_frame = 34 * stream->n_channels;
10375 stream->bytes_per_sample = 2;
10376 stream->samples_per_frame = 64 * stream->n_channels;
10382 stream->samples_per_packet = 1;
10383 stream->bytes_per_packet = 1;
10384 stream->bytes_per_frame = 1 * stream->n_channels;
10385 stream->bytes_per_sample = 1;
10386 stream->samples_per_frame = 1 * stream->n_channels;
10391 stream->samples_per_packet = 160;
10392 stream->bytes_per_packet = 33;
10393 stream->bytes_per_frame = 33 * stream->n_channels;
10394 stream->bytes_per_sample = 2;
10395 stream->samples_per_frame = 160 * stream->n_channels;
10402 if (version == 0x00010000) {
10403 /* sample description entry (16) + sound sample description v1 (20+16) */
10414 /* only parse extra decoding config for non-pcm audio */
10415 stream->samples_per_packet = QT_UINT32 (stsd_data + offset);
10416 stream->bytes_per_packet = QT_UINT32 (stsd_data + offset + 4);
10417 stream->bytes_per_frame = QT_UINT32 (stsd_data + offset + 8);
10418 stream->bytes_per_sample = QT_UINT32 (stsd_data + offset + 12);
10420 GST_LOG_OBJECT (qtdemux, "samples/packet: %d",
10421 stream->samples_per_packet);
10422 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
10423 stream->bytes_per_packet);
10424 GST_LOG_OBJECT (qtdemux, "bytes/frame: %d",
10425 stream->bytes_per_frame);
10426 GST_LOG_OBJECT (qtdemux, "bytes/sample: %d",
10427 stream->bytes_per_sample);
10429 if (!stream->sampled && stream->bytes_per_packet) {
10430 stream->samples_per_frame = (stream->bytes_per_frame /
10431 stream->bytes_per_packet) * stream->samples_per_packet;
10432 GST_LOG_OBJECT (qtdemux, "samples/frame: %d",
10433 stream->samples_per_frame);
10438 } else if (version == 0x00020000) {
10445 /* sample description entry (16) + sound sample description v2 (56) */
10449 qtfp.val = QT_UINT64 (stsd_data + offset + 4);
10450 stream->rate = qtfp.fp;
10451 stream->n_channels = QT_UINT32 (stsd_data + offset + 12);
10453 GST_LOG_OBJECT (qtdemux, "Sound sample description Version 2");
10454 GST_LOG_OBJECT (qtdemux, "sample rate: %g", stream->rate);
10455 GST_LOG_OBJECT (qtdemux, "n_channels: %d", stream->n_channels);
10456 GST_LOG_OBJECT (qtdemux, "bits/channel: %d",
10457 QT_UINT32 (stsd_data + offset + 20));
10458 GST_LOG_OBJECT (qtdemux, "format flags: %X",
10459 QT_UINT32 (stsd_data + offset + 24));
10460 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
10461 QT_UINT32 (stsd_data + offset + 28));
10462 GST_LOG_OBJECT (qtdemux, "LPCM frames/packet: %d",
10463 QT_UINT32 (stsd_data + offset + 32));
10464 } else if (version != 0x00000) {
10465 GST_WARNING_OBJECT (qtdemux, "unknown audio STSD version %08x", version);
10469 gst_caps_unref (stream->caps);
10471 stream->caps = qtdemux_audio_caps (qtdemux, stream, fourcc,
10472 stsd_data + 32, len - 16, &codec);
10480 in24 = qtdemux_tree_get_child_by_type (stsd, FOURCC_in24);
10482 enda = qtdemux_tree_get_child_by_type (in24, FOURCC_enda);
10484 wave = qtdemux_tree_get_child_by_type (in24, FOURCC_wave);
10486 enda = qtdemux_tree_get_child_by_type (wave, FOURCC_enda);
10489 int enda_value = QT_UINT16 ((guint8 *) enda->data + 8);
10490 gst_caps_set_simple (stream->caps,
10491 "format", G_TYPE_STRING, (enda_value) ? "S24LE" : "S24BE", NULL);
10498 const guint8 *owma_data;
10499 const gchar *codec_name = NULL;
10503 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
10504 /* FIXME this should also be gst_riff_strf_auds,
10505 * but the latter one is actually missing bits-per-sample :( */
10510 gint32 nSamplesPerSec;
10511 gint32 nAvgBytesPerSec;
10512 gint16 nBlockAlign;
10513 gint16 wBitsPerSample;
10516 WAVEFORMATEX *wfex;
10518 GST_DEBUG_OBJECT (qtdemux, "parse owma");
10519 owma = qtdemux_tree_get_child_by_type (stsd, FOURCC_owma);
10522 owma_data = owma->data;
10523 owma_len = QT_UINT32 (owma_data);
10524 if (owma_len <= 54) {
10525 GST_WARNING_OBJECT (qtdemux, "Too small owma header, skipping");
10528 wfex = (WAVEFORMATEX *) (owma_data + 36);
10529 buf = gst_buffer_new_and_alloc (owma_len - 54);
10530 gst_buffer_fill (buf, 0, owma_data + 54, owma_len - 54);
10531 if (wfex->wFormatTag == 0x0161) {
10532 codec_name = "Windows Media Audio";
10534 } else if (wfex->wFormatTag == 0x0162) {
10535 codec_name = "Windows Media Audio 9 Pro";
10537 } else if (wfex->wFormatTag == 0x0163) {
10538 codec_name = "Windows Media Audio 9 Lossless";
10539 /* is that correct? gstffmpegcodecmap.c is missing it, but
10540 * fluendo codec seems to support it */
10544 gst_caps_set_simple (stream->caps,
10545 "codec_data", GST_TYPE_BUFFER, buf,
10546 "wmaversion", G_TYPE_INT, version,
10547 "block_align", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->nBlockAlign),
10548 "bitrate", G_TYPE_INT, GST_READ_UINT32_LE (&wfex->nAvgBytesPerSec),
10549 "width", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->wBitsPerSample),
10550 "depth", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->wBitsPerSample),
10552 gst_buffer_unref (buf);
10556 codec = g_strdup (codec_name);
10562 gint len = QT_UINT32 (stsd_data) - offset;
10563 const guint8 *wfex_data = stsd_data + offset;
10564 const gchar *codec_name = NULL;
10566 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
10567 /* FIXME this should also be gst_riff_strf_auds,
10568 * but the latter one is actually missing bits-per-sample :( */
10573 gint32 nSamplesPerSec;
10574 gint32 nAvgBytesPerSec;
10575 gint16 nBlockAlign;
10576 gint16 wBitsPerSample;
10581 /* FIXME: unify with similar wavformatex parsing code above */
10582 GST_DEBUG_OBJECT (qtdemux, "parse wma, looking for wfex");
10588 if (QT_UINT32 (wfex_data) <= len)
10589 size = QT_UINT32 (wfex_data) - 8;
10594 /* No real data, so break out */
10597 switch (QT_FOURCC (wfex_data + 4)) {
10598 case GST_MAKE_FOURCC ('w', 'f', 'e', 'x'):
10600 GST_DEBUG_OBJECT (qtdemux, "found wfex in stsd");
10605 wfex.wFormatTag = GST_READ_UINT16_LE (wfex_data + 8 + 0);
10606 wfex.nChannels = GST_READ_UINT16_LE (wfex_data + 8 + 2);
10607 wfex.nSamplesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 4);
10608 wfex.nAvgBytesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 8);
10609 wfex.nBlockAlign = GST_READ_UINT16_LE (wfex_data + 8 + 12);
10610 wfex.wBitsPerSample = GST_READ_UINT16_LE (wfex_data + 8 + 14);
10611 wfex.cbSize = GST_READ_UINT16_LE (wfex_data + 8 + 16);
10613 GST_LOG_OBJECT (qtdemux, "Found wfex box in stsd:");
10614 GST_LOG_OBJECT (qtdemux, "FormatTag = 0x%04x, Channels = %u, "
10615 "SamplesPerSec = %u, AvgBytesPerSec = %u, BlockAlign = %u, "
10616 "BitsPerSample = %u, Size = %u", wfex.wFormatTag,
10617 wfex.nChannels, wfex.nSamplesPerSec, wfex.nAvgBytesPerSec,
10618 wfex.nBlockAlign, wfex.wBitsPerSample, wfex.cbSize);
10620 if (wfex.wFormatTag == 0x0161) {
10621 codec_name = "Windows Media Audio";
10623 } else if (wfex.wFormatTag == 0x0162) {
10624 codec_name = "Windows Media Audio 9 Pro";
10626 } else if (wfex.wFormatTag == 0x0163) {
10627 codec_name = "Windows Media Audio 9 Lossless";
10628 /* is that correct? gstffmpegcodecmap.c is missing it, but
10629 * fluendo codec seems to support it */
10633 gst_caps_set_simple (stream->caps,
10634 "wmaversion", G_TYPE_INT, version,
10635 "block_align", G_TYPE_INT, wfex.nBlockAlign,
10636 "bitrate", G_TYPE_INT, wfex.nAvgBytesPerSec,
10637 "width", G_TYPE_INT, wfex.wBitsPerSample,
10638 "depth", G_TYPE_INT, wfex.wBitsPerSample, NULL);
10640 if (size > wfex.cbSize) {
10643 buf = gst_buffer_new_and_alloc (size - wfex.cbSize);
10644 gst_buffer_fill (buf, 0, wfex_data + 8 + wfex.cbSize,
10645 size - wfex.cbSize);
10646 gst_caps_set_simple (stream->caps,
10647 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10648 gst_buffer_unref (buf);
10650 GST_WARNING_OBJECT (qtdemux, "no codec data");
10655 codec = g_strdup (codec_name);
10663 wfex_data += size + 8;
10670 const guint8 *opus_data;
10671 guint8 *channel_mapping = NULL;
10674 guint8 channel_mapping_family;
10675 guint8 stream_count;
10676 guint8 coupled_count;
10679 opus = qtdemux_tree_get_child_by_type (stsd, FOURCC_opus);
10680 opus_data = opus->data;
10682 channels = GST_READ_UINT8 (opus_data + 45);
10683 rate = GST_READ_UINT32_LE (opus_data + 48);
10684 channel_mapping_family = GST_READ_UINT8 (opus_data + 54);
10685 stream_count = GST_READ_UINT8 (opus_data + 55);
10686 coupled_count = GST_READ_UINT8 (opus_data + 56);
10688 if (channels > 0) {
10689 channel_mapping = g_malloc (channels * sizeof (guint8));
10690 for (i = 0; i < channels; i++)
10691 channel_mapping[i] = GST_READ_UINT8 (opus_data + i + 57);
10694 stream->caps = gst_codec_utils_opus_create_caps (rate, channels,
10695 channel_mapping_family, stream_count, coupled_count,
10707 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
10708 GST_TAG_AUDIO_CODEC, codec, NULL);
10712 /* some bitrate info may have ended up in caps */
10713 s = gst_caps_get_structure (stream->caps, 0);
10714 gst_structure_get_int (s, "bitrate", &bitrate);
10716 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
10717 GST_TAG_BITRATE, bitrate, NULL);
10720 if (stream->protected && fourcc == FOURCC_mp4a)
10721 mp4a = qtdemux_tree_get_child_by_type (stsd, FOURCC_enca);
10723 mp4a = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4a);
10728 wave = qtdemux_tree_get_child_by_type (mp4a, FOURCC_wave);
10730 esds = qtdemux_tree_get_child_by_type (wave, FOURCC_esds);
10732 esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
10736 /* If the fourcc's bottom 16 bits gives 'sm', then the top
10737 16 bits is a byte-swapped wave-style codec identifier,
10738 and we can find a WAVE header internally to a 'wave' atom here.
10739 This can more clearly be thought of as 'ms' as the top 16 bits, and a
10740 codec id as the bottom 16 bits - but byte-swapped to store in QT (which
10743 if ((fourcc & 0xffff) == (('s' << 8) | 'm')) {
10744 if (len < offset + 20) {
10745 GST_WARNING_OBJECT (qtdemux, "No wave atom in MS-style audio");
10747 guint32 datalen = QT_UINT32 (stsd_data + offset + 16);
10748 const guint8 *data = stsd_data + offset + 16;
10750 GNode *waveheadernode;
10752 wavenode = g_node_new ((guint8 *) data);
10753 if (qtdemux_parse_node (qtdemux, wavenode, data, datalen)) {
10754 const guint8 *waveheader;
10757 waveheadernode = qtdemux_tree_get_child_by_type (wavenode, fourcc);
10758 if (waveheadernode) {
10759 waveheader = (const guint8 *) waveheadernode->data;
10760 headerlen = QT_UINT32 (waveheader);
10762 if (headerlen > 8) {
10763 gst_riff_strf_auds *header = NULL;
10764 GstBuffer *headerbuf;
10770 headerbuf = gst_buffer_new_and_alloc (headerlen);
10771 gst_buffer_fill (headerbuf, 0, waveheader, headerlen);
10773 if (gst_riff_parse_strf_auds (GST_ELEMENT_CAST (qtdemux),
10774 headerbuf, &header, &extra)) {
10775 gst_caps_unref (stream->caps);
10776 /* FIXME: Need to do something with the channel reorder map */
10777 stream->caps = gst_riff_create_audio_caps (header->format, NULL,
10778 header, extra, NULL, NULL, NULL);
10781 gst_buffer_unref (extra);
10786 GST_DEBUG ("Didn't find waveheadernode for this codec");
10788 g_node_destroy (wavenode);
10791 gst_qtdemux_handle_esds (qtdemux, stream, esds, stream->pending_tags);
10795 /* FIXME: what is in the chunk? */
10798 gint len = QT_UINT32 (stsd_data);
10800 /* seems to be always = 116 = 0x74 */
10806 gint len = QT_UINT32 (stsd_data);
10809 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x4C);
10811 gst_buffer_fill (buf, 0, stsd_data + 0x4C, len - 0x4C);
10812 gst_caps_set_simple (stream->caps,
10813 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10814 gst_buffer_unref (buf);
10816 gst_caps_set_simple (stream->caps,
10817 "samplesize", G_TYPE_INT, samplesize, NULL);
10822 GNode *alac, *wave = NULL;
10824 /* apparently, m4a has this atom appended directly in the stsd entry,
10825 * while mov has it in a wave atom */
10826 alac = qtdemux_tree_get_child_by_type (stsd, FOURCC_alac);
10828 /* alac now refers to stsd entry atom */
10829 wave = qtdemux_tree_get_child_by_type (alac, FOURCC_wave);
10831 alac = qtdemux_tree_get_child_by_type (wave, FOURCC_alac);
10833 alac = qtdemux_tree_get_child_by_type (alac, FOURCC_alac);
10836 const guint8 *alac_data = alac->data;
10837 gint len = QT_UINT32 (alac->data);
10841 GST_DEBUG_OBJECT (qtdemux,
10842 "discarding alac atom with unexpected len %d", len);
10844 /* codec-data contains alac atom size and prefix,
10845 * ffmpeg likes it that way, not quite gst-ish though ...*/
10846 buf = gst_buffer_new_and_alloc (len);
10847 gst_buffer_fill (buf, 0, alac->data, len);
10848 gst_caps_set_simple (stream->caps,
10849 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10850 gst_buffer_unref (buf);
10852 stream->bytes_per_frame = QT_UINT32 (alac_data + 12);
10853 stream->n_channels = QT_UINT8 (alac_data + 21);
10854 stream->rate = QT_UINT32 (alac_data + 32);
10857 gst_caps_set_simple (stream->caps,
10858 "samplesize", G_TYPE_INT, samplesize, NULL);
10866 gint len = QT_UINT32 (stsd_data);
10869 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x34);
10872 gst_buffer_fill (buf, 0, stsd_data + 0x34, len - 0x34);
10874 /* If we have enough data, let's try to get the 'damr' atom. See
10875 * the 3GPP container spec (26.244) for more details. */
10876 if ((len - 0x34) > 8 &&
10877 (bitrate = qtdemux_parse_amr_bitrate (buf, amrwb))) {
10878 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
10879 GST_TAG_MAXIMUM_BITRATE, bitrate, NULL);
10882 gst_caps_set_simple (stream->caps,
10883 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10884 gst_buffer_unref (buf);
10890 /* mp4a atom withtout ESDS; Attempt to build codec data from atom */
10891 gint len = QT_UINT32 (stsd_data);
10894 guint16 sound_version = QT_UINT16 (stsd_data + 32);
10896 if (sound_version == 1) {
10897 guint16 channels = QT_UINT16 (stsd_data + 40);
10898 guint32 time_scale = QT_UINT32 (stsd_data + 46);
10899 guint8 codec_data[2];
10901 gint profile = 2; /* FIXME: Can this be determined somehow? There doesn't seem to be anything in mp4a atom that specifis compression */
10903 gint sample_rate_index =
10904 gst_codec_utils_aac_get_index_from_sample_rate (time_scale);
10906 /* build AAC codec data */
10907 codec_data[0] = profile << 3;
10908 codec_data[0] |= ((sample_rate_index >> 1) & 0x7);
10909 codec_data[1] = (sample_rate_index & 0x01) << 7;
10910 codec_data[1] |= (channels & 0xF) << 3;
10912 buf = gst_buffer_new_and_alloc (2);
10913 gst_buffer_fill (buf, 0, codec_data, 2);
10914 gst_caps_set_simple (stream->caps,
10915 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10916 gst_buffer_unref (buf);
10922 GST_INFO_OBJECT (qtdemux,
10923 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
10927 GST_INFO_OBJECT (qtdemux,
10928 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
10929 GST_FOURCC_ARGS (fourcc), stream->caps);
10931 } else if (stream->subtype == FOURCC_strm) {
10932 if (fourcc == FOURCC_rtsp) {
10933 stream->redirect_uri = qtdemux_get_rtsp_uri_from_hndl (qtdemux, minf);
10935 GST_INFO_OBJECT (qtdemux, "unhandled stream type %" GST_FOURCC_FORMAT,
10936 GST_FOURCC_ARGS (fourcc));
10937 goto unknown_stream;
10939 stream->sampled = TRUE;
10940 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
10941 || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt) {
10943 stream->sampled = TRUE;
10944 stream->sparse = TRUE;
10947 qtdemux_sub_caps (qtdemux, stream, fourcc, stsd_data, &codec);
10949 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
10950 GST_TAG_SUBTITLE_CODEC, codec, NULL);
10955 /* hunt for sort-of codec data */
10959 GNode *mp4s = NULL;
10960 GNode *esds = NULL;
10962 /* look for palette in a stsd->mp4s->esds sub-atom */
10963 mp4s = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4s);
10965 esds = qtdemux_tree_get_child_by_type (mp4s, FOURCC_esds);
10966 if (esds == NULL) {
10968 GST_LOG_OBJECT (qtdemux, "Skipping invalid stsd: no esds child");
10972 gst_qtdemux_handle_esds (qtdemux, stream, esds, stream->pending_tags);
10976 GST_INFO_OBJECT (qtdemux,
10977 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
10980 GST_INFO_OBJECT (qtdemux,
10981 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
10982 GST_FOURCC_ARGS (fourcc), stream->caps);
10984 /* everything in 1 sample */
10985 stream->sampled = TRUE;
10988 qtdemux_generic_caps (qtdemux, stream, fourcc, stsd_data, &codec);
10990 if (stream->caps == NULL)
10991 goto unknown_stream;
10994 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
10995 GST_TAG_SUBTITLE_CODEC, codec, NULL);
11001 /* promote to sampled format */
11002 if (stream->fourcc == FOURCC_samr) {
11003 /* force mono 8000 Hz for AMR */
11004 stream->sampled = TRUE;
11005 stream->n_channels = 1;
11006 stream->rate = 8000;
11007 } else if (stream->fourcc == FOURCC_sawb) {
11008 /* force mono 16000 Hz for AMR-WB */
11009 stream->sampled = TRUE;
11010 stream->n_channels = 1;
11011 stream->rate = 16000;
11012 } else if (stream->fourcc == FOURCC_mp4a) {
11013 stream->sampled = TRUE;
11016 /* collect sample information */
11017 if (!qtdemux_stbl_init (qtdemux, stream, stbl))
11018 goto samples_failed;
11020 if (qtdemux->fragmented) {
11023 /* need all moov samples as basis; probably not many if any at all */
11024 /* prevent moof parsing taking of at this time */
11025 offset = qtdemux->moof_offset;
11026 qtdemux->moof_offset = 0;
11027 if (stream->n_samples &&
11028 !qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
11029 qtdemux->moof_offset = offset;
11030 goto samples_failed;
11032 qtdemux->moof_offset = 0;
11033 /* movie duration more reliable in this case (e.g. mehd) */
11034 if (qtdemux->segment.duration &&
11035 GST_CLOCK_TIME_IS_VALID (qtdemux->segment.duration))
11037 GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->segment.duration);
11040 /* configure segments */
11041 if (!qtdemux_parse_segments (qtdemux, stream, trak))
11042 goto segments_failed;
11044 /* add some language tag, if useful */
11045 if (stream->lang_id[0] != '\0' && strcmp (stream->lang_id, "unk") &&
11046 strcmp (stream->lang_id, "und")) {
11047 const gchar *lang_code;
11049 /* convert ISO 639-2 code to ISO 639-1 */
11050 lang_code = gst_tag_get_language_code (stream->lang_id);
11051 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
11052 GST_TAG_LANGUAGE_CODE, (lang_code) ? lang_code : stream->lang_id, NULL);
11055 /* Check for UDTA tags */
11056 if ((udta = qtdemux_tree_get_child_by_type (trak, FOURCC_udta))) {
11057 qtdemux_parse_udta (qtdemux, stream->pending_tags, udta);
11060 /* now we are ready to add the stream */
11061 if (qtdemux->n_streams >= GST_QTDEMUX_MAX_STREAMS)
11062 goto too_many_streams;
11064 if (!qtdemux->got_moov) {
11065 qtdemux->streams[qtdemux->n_streams] = stream;
11066 qtdemux->n_streams++;
11067 GST_DEBUG_OBJECT (qtdemux, "n_streams is now %d", qtdemux->n_streams);
11075 GST_INFO_OBJECT (qtdemux, "skip disabled track");
11077 gst_qtdemux_stream_free (qtdemux, stream);
11082 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
11083 (_("This file is corrupt and cannot be played.")), (NULL));
11085 gst_qtdemux_stream_free (qtdemux, stream);
11090 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT, (NULL), (NULL));
11092 gst_qtdemux_stream_free (qtdemux, stream);
11098 /* we posted an error already */
11099 /* free stbl sub-atoms */
11100 gst_qtdemux_stbl_free (stream);
11102 gst_qtdemux_stream_free (qtdemux, stream);
11107 GST_INFO_OBJECT (qtdemux, "stream with track id %i already exists",
11110 gst_qtdemux_stream_free (qtdemux, stream);
11115 GST_INFO_OBJECT (qtdemux, "unknown subtype %" GST_FOURCC_FORMAT,
11116 GST_FOURCC_ARGS (stream->subtype));
11118 gst_qtdemux_stream_free (qtdemux, stream);
11123 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
11124 (_("This file contains too many streams. Only playing first %d"),
11125 GST_QTDEMUX_MAX_STREAMS), (NULL));
11130 /* If we can estimate the overall bitrate, and don't have information about the
11131 * stream bitrate for exactly one stream, this guesses the stream bitrate as
11132 * the overall bitrate minus the sum of the bitrates of all other streams. This
11133 * should be useful for the common case where we have one audio and one video
11134 * stream and can estimate the bitrate of one, but not the other. */
11136 gst_qtdemux_guess_bitrate (GstQTDemux * qtdemux)
11138 QtDemuxStream *stream = NULL;
11139 gint64 size, sys_bitrate, sum_bitrate = 0;
11140 GstClockTime duration;
11144 if (qtdemux->fragmented)
11147 GST_DEBUG_OBJECT (qtdemux, "Looking for streams with unknown bitrate");
11149 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &size)
11151 GST_DEBUG_OBJECT (qtdemux,
11152 "Size in bytes of the stream not known - bailing");
11156 /* Subtract the header size */
11157 GST_DEBUG_OBJECT (qtdemux, "Total size %" G_GINT64_FORMAT ", header size %u",
11158 size, qtdemux->header_size);
11160 if (size < qtdemux->header_size)
11163 size = size - qtdemux->header_size;
11165 if (!gst_qtdemux_get_duration (qtdemux, &duration)) {
11166 GST_DEBUG_OBJECT (qtdemux, "Stream duration not known - bailing");
11170 for (i = 0; i < qtdemux->n_streams; i++) {
11171 switch (qtdemux->streams[i]->subtype) {
11174 GST_DEBUG_OBJECT (qtdemux, "checking bitrate for %" GST_PTR_FORMAT,
11175 qtdemux->streams[i]->caps);
11176 /* retrieve bitrate, prefer avg then max */
11178 if (qtdemux->streams[i]->pending_tags) {
11179 gst_tag_list_get_uint (qtdemux->streams[i]->pending_tags,
11180 GST_TAG_MAXIMUM_BITRATE, &bitrate);
11181 GST_DEBUG_OBJECT (qtdemux, "max-bitrate: %u", bitrate);
11182 gst_tag_list_get_uint (qtdemux->streams[i]->pending_tags,
11183 GST_TAG_NOMINAL_BITRATE, &bitrate);
11184 GST_DEBUG_OBJECT (qtdemux, "nominal-bitrate: %u", bitrate);
11185 gst_tag_list_get_uint (qtdemux->streams[i]->pending_tags,
11186 GST_TAG_BITRATE, &bitrate);
11187 GST_DEBUG_OBJECT (qtdemux, "bitrate: %u", bitrate);
11190 sum_bitrate += bitrate;
11193 GST_DEBUG_OBJECT (qtdemux,
11194 ">1 stream with unknown bitrate - bailing");
11197 stream = qtdemux->streams[i];
11201 /* For other subtypes, we assume no significant impact on bitrate */
11207 GST_DEBUG_OBJECT (qtdemux, "All stream bitrates are known");
11211 sys_bitrate = gst_util_uint64_scale (size, GST_SECOND * 8, duration);
11213 if (sys_bitrate < sum_bitrate) {
11214 /* This can happen, since sum_bitrate might be derived from maximum
11215 * bitrates and not average bitrates */
11216 GST_DEBUG_OBJECT (qtdemux,
11217 "System bitrate less than sum bitrate - bailing");
11221 bitrate = sys_bitrate - sum_bitrate;
11222 GST_DEBUG_OBJECT (qtdemux, "System bitrate = %" G_GINT64_FORMAT
11223 ", Stream bitrate = %u", sys_bitrate, bitrate);
11225 if (!stream->pending_tags)
11226 stream->pending_tags = gst_tag_list_new_empty ();
11228 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
11229 GST_TAG_BITRATE, bitrate, NULL);
11232 static GstFlowReturn
11233 qtdemux_prepare_streams (GstQTDemux * qtdemux)
11236 GstFlowReturn ret = GST_FLOW_OK;
11238 GST_DEBUG_OBJECT (qtdemux, "prepare streams");
11240 for (i = 0; ret == GST_FLOW_OK && i < qtdemux->n_streams; i++) {
11241 QtDemuxStream *stream = qtdemux->streams[i];
11242 guint32 sample_num = 0;
11244 GST_DEBUG_OBJECT (qtdemux, "stream %d, id %d, fourcc %" GST_FOURCC_FORMAT,
11245 i, stream->track_id, GST_FOURCC_ARGS (stream->fourcc));
11247 if (qtdemux->fragmented) {
11248 /* need all moov samples first */
11249 GST_OBJECT_LOCK (qtdemux);
11250 while (stream->n_samples == 0)
11251 if ((ret = qtdemux_add_fragmented_samples (qtdemux)) != GST_FLOW_OK)
11253 GST_OBJECT_UNLOCK (qtdemux);
11255 /* discard any stray moof */
11256 qtdemux->moof_offset = 0;
11259 /* prepare braking */
11260 if (ret != GST_FLOW_ERROR)
11263 /* in pull mode, we should have parsed some sample info by now;
11264 * and quite some code will not handle no samples.
11265 * in push mode, we'll just have to deal with it */
11266 if (G_UNLIKELY (qtdemux->pullbased && !stream->n_samples)) {
11267 GST_DEBUG_OBJECT (qtdemux, "no samples for stream; discarding");
11268 gst_qtdemux_remove_stream (qtdemux, i);
11273 /* parse the initial sample for use in setting the frame rate cap */
11274 while (sample_num == 0 && sample_num < stream->n_samples) {
11275 if (!qtdemux_parse_samples (qtdemux, stream, sample_num))
11279 if (stream->n_samples > 0 && stream->stbl_index >= 0) {
11280 stream->first_duration = stream->samples[0].duration;
11281 GST_LOG_OBJECT (qtdemux, "stream %d first duration %u",
11282 stream->track_id, stream->first_duration);
11289 static GstFlowReturn
11290 qtdemux_expose_streams (GstQTDemux * qtdemux)
11293 GstFlowReturn ret = GST_FLOW_OK;
11294 GSList *oldpads = NULL;
11297 GST_DEBUG_OBJECT (qtdemux, "exposing streams");
11299 for (i = 0; ret == GST_FLOW_OK && i < qtdemux->n_streams; i++) {
11300 QtDemuxStream *stream = qtdemux->streams[i];
11301 GstPad *oldpad = stream->pad;
11304 GST_DEBUG_OBJECT (qtdemux, "stream %d, id %d, fourcc %" GST_FOURCC_FORMAT,
11305 i, stream->track_id, GST_FOURCC_ARGS (stream->fourcc));
11307 if ((stream->subtype == FOURCC_text || stream->subtype == FOURCC_sbtl) &&
11308 stream->track_id == qtdemux->chapters_track_id) {
11309 /* TODO - parse chapters track and expose it as GstToc; For now just ignore it
11310 so that it doesn't look like a subtitle track */
11311 gst_qtdemux_remove_stream (qtdemux, i);
11316 /* now we have all info and can expose */
11317 list = stream->pending_tags;
11318 stream->pending_tags = NULL;
11320 oldpads = g_slist_prepend (oldpads, oldpad);
11321 if (!gst_qtdemux_add_stream (qtdemux, stream, list))
11322 return GST_FLOW_ERROR;
11325 gst_qtdemux_guess_bitrate (qtdemux);
11327 gst_element_no_more_pads (GST_ELEMENT_CAST (qtdemux));
11329 for (iter = oldpads; iter; iter = g_slist_next (iter)) {
11330 GstPad *oldpad = iter->data;
11333 event = gst_event_new_eos ();
11334 if (qtdemux->segment_seqnum)
11335 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
11337 gst_pad_push_event (oldpad, event);
11338 gst_pad_set_active (oldpad, FALSE);
11339 gst_element_remove_pad (GST_ELEMENT (qtdemux), oldpad);
11340 gst_flow_combiner_remove_pad (qtdemux->flowcombiner, oldpad);
11341 gst_object_unref (oldpad);
11344 /* check if we should post a redirect in case there is a single trak
11345 * and it is a redirecting trak */
11346 if (qtdemux->n_streams == 1 && qtdemux->streams[0]->redirect_uri != NULL) {
11349 GST_INFO_OBJECT (qtdemux, "Issuing a redirect due to a single track with "
11350 "an external content");
11351 m = gst_message_new_element (GST_OBJECT_CAST (qtdemux),
11352 gst_structure_new ("redirect",
11353 "new-location", G_TYPE_STRING, qtdemux->streams[0]->redirect_uri,
11355 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), m);
11356 qtdemux->posted_redirect = TRUE;
11359 for (i = 0; i < qtdemux->n_streams; i++) {
11360 QtDemuxStream *stream = qtdemux->streams[i];
11362 qtdemux_do_allocation (qtdemux, stream);
11365 qtdemux->exposed = TRUE;
11369 /* check if major or compatible brand is 3GP */
11370 static inline gboolean
11371 qtdemux_is_brand_3gp (GstQTDemux * qtdemux, gboolean major)
11374 return ((qtdemux->major_brand & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
11376 } else if (qtdemux->comp_brands != NULL) {
11380 gboolean res = FALSE;
11382 gst_buffer_map (qtdemux->comp_brands, &map, GST_MAP_READ);
11385 while (size >= 4) {
11386 res = res || ((QT_FOURCC (data) & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
11391 gst_buffer_unmap (qtdemux->comp_brands, &map);
11398 /* check if tag is a spec'ed 3GP tag keyword storing a string */
11399 static inline gboolean
11400 qtdemux_is_string_tag_3gp (GstQTDemux * qtdemux, guint32 fourcc)
11402 return fourcc == FOURCC_cprt || fourcc == FOURCC_gnre || fourcc == FOURCC_titl
11403 || fourcc == FOURCC_dscp || fourcc == FOURCC_perf || fourcc == FOURCC_auth
11404 || fourcc == FOURCC_albm;
11408 qtdemux_tag_add_location (GstQTDemux * qtdemux, GstTagList * taglist,
11409 const char *tag, const char *dummy, GNode * node)
11411 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
11415 gdouble longitude, latitude, altitude;
11418 len = QT_UINT32 (node->data);
11425 /* TODO: language code skipped */
11427 name = gst_tag_freeform_string_to_utf8 (data + offset, -1, env_vars);
11430 /* do not alarm in trivial case, but bail out otherwise */
11431 if (*(data + offset) != 0) {
11432 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8, "
11436 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
11437 GST_TAG_GEO_LOCATION_NAME, name, NULL);
11438 offset += strlen (name);
11442 if (len < offset + 2 + 4 + 4 + 4)
11445 /* +1 +1 = skip null-terminator and location role byte */
11447 /* table in spec says unsigned, semantics say negative has meaning ... */
11448 longitude = QT_SFP32 (data + offset);
11451 latitude = QT_SFP32 (data + offset);
11454 altitude = QT_SFP32 (data + offset);
11456 /* one invalid means all are invalid */
11457 if (longitude >= -180.0 && longitude <= 180.0 &&
11458 latitude >= -90.0 && latitude <= 90.0) {
11459 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
11460 GST_TAG_GEO_LOCATION_LATITUDE, latitude,
11461 GST_TAG_GEO_LOCATION_LONGITUDE, longitude,
11462 GST_TAG_GEO_LOCATION_ELEVATION, altitude, NULL);
11465 /* TODO: no GST_TAG_, so astronomical body and additional notes skipped */
11472 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP location");
11479 qtdemux_tag_add_year (GstQTDemux * qtdemux, GstTagList * taglist,
11480 const char *tag, const char *dummy, GNode * node)
11486 len = QT_UINT32 (node->data);
11490 y = QT_UINT16 ((guint8 *) node->data + 12);
11492 GST_DEBUG_OBJECT (qtdemux, "year: %u is not a valid year", y);
11495 GST_DEBUG_OBJECT (qtdemux, "year: %u", y);
11497 date = g_date_new_dmy (1, 1, y);
11498 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, date, NULL);
11499 g_date_free (date);
11503 qtdemux_tag_add_classification (GstQTDemux * qtdemux, GstTagList * taglist,
11504 const char *tag, const char *dummy, GNode * node)
11507 char *tag_str = NULL;
11512 len = QT_UINT32 (node->data);
11517 entity = (guint8 *) node->data + offset;
11518 if (entity[0] == 0 || entity[1] == 0 || entity[2] == 0 || entity[3] == 0) {
11519 GST_DEBUG_OBJECT (qtdemux,
11520 "classification info: %c%c%c%c invalid classification entity",
11521 entity[0], entity[1], entity[2], entity[3]);
11526 table = QT_UINT16 ((guint8 *) node->data + offset);
11528 /* Language code skipped */
11532 /* Tag format: "XXXX://Y[YYYY]/classification info string"
11533 * XXXX: classification entity, fixed length 4 chars.
11534 * Y[YYYY]: classification table, max 5 chars.
11536 tag_str = g_strdup_printf ("----://%u/%s",
11537 table, (char *) node->data + offset);
11539 /* memcpy To be sure we're preserving byte order */
11540 memcpy (tag_str, entity, 4);
11541 GST_DEBUG_OBJECT (qtdemux, "classification info: %s", tag_str);
11543 gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND, tag, tag_str, NULL);
11552 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP classification");
11558 qtdemux_tag_add_str_full (GstQTDemux * qtdemux, GstTagList * taglist,
11559 const char *tag, const char *dummy, GNode * node)
11561 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
11567 gboolean ret = TRUE;
11568 const gchar *charset = NULL;
11570 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
11572 len = QT_UINT32 (data->data);
11573 type = QT_UINT32 ((guint8 *) data->data + 8);
11574 if (type == 0x00000001 && len > 16) {
11575 s = gst_tag_freeform_string_to_utf8 ((char *) data->data + 16, len - 16,
11578 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
11579 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, s, NULL);
11582 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
11586 len = QT_UINT32 (node->data);
11587 type = QT_UINT32 ((guint8 *) node->data + 4);
11588 if ((type >> 24) == 0xa9) {
11592 /* Type starts with the (C) symbol, so the next data is a list
11593 * of (string size(16), language code(16), string) */
11595 str_len = QT_UINT16 ((guint8 *) node->data + 8);
11596 lang_code = QT_UINT16 ((guint8 *) node->data + 10);
11598 /* the string + fourcc + size + 2 16bit fields,
11599 * means that there are more tags in this atom */
11600 if (len > str_len + 8 + 4) {
11601 /* TODO how to represent the same tag in different languages? */
11602 GST_WARNING_OBJECT (qtdemux, "Ignoring metadata entry with multiple "
11603 "text alternatives, reading only first one");
11607 len = str_len + 8 + 4; /* remove trailing strings that we don't use */
11608 GST_DEBUG_OBJECT (qtdemux, "found international text tag");
11610 if (lang_code < 0x800) { /* MAC encoded string */
11613 } else if (len > 14 && qtdemux_is_string_tag_3gp (qtdemux,
11614 QT_FOURCC ((guint8 *) node->data + 4))) {
11615 guint32 type = QT_UINT32 ((guint8 *) node->data + 8);
11617 /* we go for 3GP style encoding if major brands claims so,
11618 * or if no hope for data be ok UTF-8, and compatible 3GP brand present */
11619 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
11620 (qtdemux_is_brand_3gp (qtdemux, FALSE) &&
11621 ((type & 0x00FFFFFF) == 0x0) && (type >> 24 <= 0xF))) {
11623 /* 16-bit Language code is ignored here as well */
11624 GST_DEBUG_OBJECT (qtdemux, "found 3gpp text tag");
11631 GST_DEBUG_OBJECT (qtdemux, "found normal text tag");
11632 ret = FALSE; /* may have to fallback */
11635 GError *err = NULL;
11637 s = g_convert ((gchar *) node->data + offset, len - offset, "utf8",
11638 charset, NULL, NULL, &err);
11640 GST_DEBUG_OBJECT (qtdemux, "Failed to convert string from charset %s:"
11641 " %s(%d): %s", charset, g_quark_to_string (err->domain), err->code,
11643 g_error_free (err);
11646 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
11647 len - offset, env_vars);
11650 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
11651 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, s, NULL);
11655 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
11662 qtdemux_tag_add_str (GstQTDemux * qtdemux, GstTagList * taglist,
11663 const char *tag, const char *dummy, GNode * node)
11665 qtdemux_tag_add_str_full (qtdemux, taglist, tag, dummy, node);
11669 qtdemux_tag_add_keywords (GstQTDemux * qtdemux, GstTagList * taglist,
11670 const char *tag, const char *dummy, GNode * node)
11672 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
11674 char *s, *t, *k = NULL;
11679 /* first try normal string tag if major brand not 3GP */
11680 if (!qtdemux_is_brand_3gp (qtdemux, TRUE)) {
11681 if (!qtdemux_tag_add_str_full (qtdemux, taglist, tag, dummy, node)) {
11682 /* hm, that did not work, maybe 3gpp storage in non-3gpp major brand;
11683 * let's try it 3gpp way after minor safety check */
11685 if (QT_UINT32 (data) < 15 || !qtdemux_is_brand_3gp (qtdemux, FALSE))
11691 GST_DEBUG_OBJECT (qtdemux, "found 3gpp keyword tag");
11695 len = QT_UINT32 (data);
11699 count = QT_UINT8 (data + 14);
11701 for (; count; count--) {
11704 if (offset + 1 > len)
11706 slen = QT_UINT8 (data + offset);
11708 if (offset + slen > len)
11710 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
11713 GST_DEBUG_OBJECT (qtdemux, "adding keyword %s", GST_STR_NULL (s));
11715 t = g_strjoin (",", k, s, NULL);
11723 GST_DEBUG_OBJECT (qtdemux, "failed to convert keyword to UTF-8");
11730 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (k));
11731 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, k, NULL);
11740 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP keywords");
11746 qtdemux_tag_add_num (GstQTDemux * qtdemux, GstTagList * taglist,
11747 const char *tag1, const char *tag2, GNode * node)
11754 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
11756 len = QT_UINT32 (data->data);
11757 type = QT_UINT32 ((guint8 *) data->data + 8);
11758 if (type == 0x00000000 && len >= 22) {
11759 n1 = QT_UINT16 ((guint8 *) data->data + 18);
11760 n2 = QT_UINT16 ((guint8 *) data->data + 20);
11762 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag1, n1);
11763 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, n1, NULL);
11766 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag2, n2);
11767 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag2, n2, NULL);
11774 qtdemux_tag_add_tmpo (GstQTDemux * qtdemux, GstTagList * taglist,
11775 const char *tag1, const char *dummy, GNode * node)
11782 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
11784 len = QT_UINT32 (data->data);
11785 type = QT_UINT32 ((guint8 *) data->data + 8);
11786 GST_DEBUG_OBJECT (qtdemux, "have tempo tag, type=%d,len=%d", type, len);
11787 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
11788 if ((type == 0x00000015 || type == 0x0000000f) && len >= 18) {
11789 n1 = QT_UINT16 ((guint8 *) data->data + 16);
11791 /* do not add bpm=0 */
11792 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", n1);
11793 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, (gdouble) n1,
11801 qtdemux_tag_add_uint32 (GstQTDemux * qtdemux, GstTagList * taglist,
11802 const char *tag1, const char *dummy, GNode * node)
11809 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
11811 len = QT_UINT32 (data->data);
11812 type = QT_UINT32 ((guint8 *) data->data + 8);
11813 GST_DEBUG_OBJECT (qtdemux, "have %s tag, type=%d,len=%d", tag1, type, len);
11814 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
11815 if ((type == 0x00000015 || type == 0x0000000f) && len >= 20) {
11816 num = QT_UINT32 ((guint8 *) data->data + 16);
11818 /* do not add num=0 */
11819 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", num);
11820 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, num, NULL);
11827 qtdemux_tag_add_covr (GstQTDemux * qtdemux, GstTagList * taglist,
11828 const char *tag1, const char *dummy, GNode * node)
11835 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
11837 len = QT_UINT32 (data->data);
11838 type = QT_UINT32 ((guint8 *) data->data + 8);
11839 GST_DEBUG_OBJECT (qtdemux, "have covr tag, type=%d,len=%d", type, len);
11840 if ((type == 0x0000000d || type == 0x0000000e) && len > 16) {
11842 gst_tag_image_data_to_image_sample ((guint8 *) data->data + 16,
11843 len - 16, GST_TAG_IMAGE_TYPE_NONE))) {
11844 GST_DEBUG_OBJECT (qtdemux, "adding tag size %d", len - 16);
11845 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, sample, NULL);
11846 gst_sample_unref (sample);
11853 qtdemux_tag_add_date (GstQTDemux * qtdemux, GstTagList * taglist,
11854 const char *tag, const char *dummy, GNode * node)
11861 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
11863 len = QT_UINT32 (data->data);
11864 type = QT_UINT32 ((guint8 *) data->data + 8);
11865 if (type == 0x00000001 && len > 16) {
11866 guint y, m = 1, d = 1;
11869 s = g_strndup ((char *) data->data + 16, len - 16);
11870 GST_DEBUG_OBJECT (qtdemux, "adding date '%s'", s);
11871 ret = sscanf (s, "%u-%u-%u", &y, &m, &d);
11872 if (ret >= 1 && y > 1500 && y < 3000) {
11875 date = g_date_new_dmy (d, m, y);
11876 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, date, NULL);
11877 g_date_free (date);
11879 GST_DEBUG_OBJECT (qtdemux, "could not parse date string '%s'", s);
11887 qtdemux_tag_add_gnre (GstQTDemux * qtdemux, GstTagList * taglist,
11888 const char *tag, const char *dummy, GNode * node)
11892 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
11894 /* re-route to normal string tag if major brand says so
11895 * or no data atom and compatible brand suggests so */
11896 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
11897 (qtdemux_is_brand_3gp (qtdemux, FALSE) && !data)) {
11898 qtdemux_tag_add_str (qtdemux, taglist, tag, dummy, node);
11903 guint len, type, n;
11905 len = QT_UINT32 (data->data);
11906 type = QT_UINT32 ((guint8 *) data->data + 8);
11907 if (type == 0x00000000 && len >= 18) {
11908 n = QT_UINT16 ((guint8 *) data->data + 16);
11910 const gchar *genre;
11912 genre = gst_tag_id3_genre_get (n - 1);
11913 if (genre != NULL) {
11914 GST_DEBUG_OBJECT (qtdemux, "adding %d [%s]", n, genre);
11915 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, genre, NULL);
11923 qtdemux_add_double_tag_from_str (GstQTDemux * demux, GstTagList * taglist,
11924 const gchar * tag, guint8 * data, guint32 datasize)
11929 /* make a copy to have \0 at the end */
11930 datacopy = g_strndup ((gchar *) data, datasize);
11932 /* convert the str to double */
11933 if (sscanf (datacopy, "%lf", &value) == 1) {
11934 GST_DEBUG_OBJECT (demux, "adding tag: %s [%s]", tag, datacopy);
11935 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, value, NULL);
11937 GST_WARNING_OBJECT (demux, "Failed to parse double from string: %s",
11945 qtdemux_tag_add_revdns (GstQTDemux * demux, GstTagList * taglist,
11946 const char *tag, const char *tag_bis, GNode * node)
11955 const gchar *meanstr;
11956 const gchar *namestr;
11958 /* checking the whole ---- atom size for consistency */
11959 if (QT_UINT32 (node->data) <= 4 + 12 + 12 + 16) {
11960 GST_WARNING_OBJECT (demux, "Tag ---- atom is too small, ignoring");
11964 mean = qtdemux_tree_get_child_by_type (node, FOURCC_mean);
11966 GST_WARNING_OBJECT (demux, "No 'mean' atom found");
11970 meansize = QT_UINT32 (mean->data);
11971 if (meansize <= 12) {
11972 GST_WARNING_OBJECT (demux, "Small mean atom, ignoring the whole tag");
11975 meanstr = ((gchar *) mean->data) + 12;
11978 name = qtdemux_tree_get_child_by_type (node, FOURCC_name);
11980 GST_WARNING_OBJECT (demux, "'name' atom not found, ignoring tag");
11984 namesize = QT_UINT32 (name->data);
11985 if (namesize <= 12) {
11986 GST_WARNING_OBJECT (demux, "'name' atom is too small, ignoring tag");
11989 namestr = ((gchar *) name->data) + 12;
11997 * uint24 - data type
12001 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12003 GST_WARNING_OBJECT (demux, "No data atom in this tag");
12006 datasize = QT_UINT32 (data->data);
12007 if (datasize <= 16) {
12008 GST_WARNING_OBJECT (demux, "Data atom too small");
12011 datatype = QT_UINT32 (((gchar *) data->data) + 8) & 0xFFFFFF;
12013 if ((strncmp (meanstr, "com.apple.iTunes", meansize) == 0) ||
12014 (strncmp (meanstr, "org.hydrogenaudio.replaygain", meansize) == 0)) {
12015 static const struct
12017 const gchar name[28];
12018 const gchar tag[28];
12021 "replaygain_track_gain", GST_TAG_TRACK_GAIN}, {
12022 "replaygain_track_peak", GST_TAG_TRACK_PEAK}, {
12023 "replaygain_album_gain", GST_TAG_ALBUM_GAIN}, {
12024 "replaygain_album_peak", GST_TAG_ALBUM_PEAK}, {
12025 "MusicBrainz Track Id", GST_TAG_MUSICBRAINZ_TRACKID}, {
12026 "MusicBrainz Artist Id", GST_TAG_MUSICBRAINZ_ARTISTID}, {
12027 "MusicBrainz Album Id", GST_TAG_MUSICBRAINZ_ALBUMID}, {
12028 "MusicBrainz Album Artist Id", GST_TAG_MUSICBRAINZ_ALBUMARTISTID}
12032 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
12033 if (!g_ascii_strncasecmp (tags[i].name, namestr, namesize)) {
12034 switch (gst_tag_get_type (tags[i].tag)) {
12035 case G_TYPE_DOUBLE:
12036 qtdemux_add_double_tag_from_str (demux, taglist, tags[i].tag,
12037 ((guint8 *) data->data) + 16, datasize - 16);
12039 case G_TYPE_STRING:
12040 qtdemux_tag_add_str (demux, taglist, tags[i].tag, NULL, node);
12049 if (i == G_N_ELEMENTS (tags))
12059 #ifndef GST_DISABLE_GST_DEBUG
12061 gchar *namestr_dbg;
12062 gchar *meanstr_dbg;
12064 meanstr_dbg = g_strndup (meanstr, meansize);
12065 namestr_dbg = g_strndup (namestr, namesize);
12067 GST_WARNING_OBJECT (demux, "This tag %s:%s type:%u is not mapped, "
12068 "file a bug at bugzilla.gnome.org", meanstr_dbg, namestr_dbg, datatype);
12070 g_free (namestr_dbg);
12071 g_free (meanstr_dbg);
12078 qtdemux_tag_add_id32 (GstQTDemux * demux, GstTagList * taglist, const char *tag,
12079 const char *tag_bis, GNode * node)
12084 GstTagList *id32_taglist = NULL;
12086 GST_LOG_OBJECT (demux, "parsing ID32");
12089 len = GST_READ_UINT32_BE (data);
12091 /* need at least full box and language tag */
12095 buf = gst_buffer_new_allocate (NULL, len - 14, NULL);
12096 gst_buffer_fill (buf, 0, data + 14, len - 14);
12098 id32_taglist = gst_tag_list_from_id3v2_tag (buf);
12099 if (id32_taglist) {
12100 GST_LOG_OBJECT (demux, "parsing ok");
12101 gst_tag_list_insert (taglist, id32_taglist, GST_TAG_MERGE_KEEP);
12102 gst_tag_list_unref (id32_taglist);
12104 GST_LOG_OBJECT (demux, "parsing failed");
12107 gst_buffer_unref (buf);
12110 typedef void (*GstQTDemuxAddTagFunc) (GstQTDemux * demux, GstTagList * taglist,
12111 const char *tag, const char *tag_bis, GNode * node);
12114 FOURCC_pcst -> if media is a podcast -> bool
12115 FOURCC_cpil -> if media is part of a compilation -> bool
12116 FOURCC_pgap -> if media is part of a gapless context -> bool
12117 FOURCC_tven -> the tv episode id e.g. S01E23 -> str
12120 static const struct
12123 const gchar *gst_tag;
12124 const gchar *gst_tag_bis;
12125 const GstQTDemuxAddTagFunc func;
12128 FOURCC__nam, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
12129 FOURCC_titl, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
12130 FOURCC__grp, GST_TAG_GROUPING, NULL, qtdemux_tag_add_str}, {
12131 FOURCC__wrt, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
12132 FOURCC__ART, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
12133 FOURCC_aART, GST_TAG_ALBUM_ARTIST, NULL, qtdemux_tag_add_str}, {
12134 FOURCC_perf, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
12135 FOURCC_auth, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
12136 FOURCC__alb, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
12137 FOURCC_albm, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
12138 FOURCC_cprt, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
12139 FOURCC__cpy, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
12140 FOURCC__cmt, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
12141 FOURCC__des, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
12142 FOURCC_desc, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
12143 FOURCC_dscp, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
12144 FOURCC__lyr, GST_TAG_LYRICS, NULL, qtdemux_tag_add_str}, {
12145 FOURCC__day, GST_TAG_DATE, NULL, qtdemux_tag_add_date}, {
12146 FOURCC_yrrc, GST_TAG_DATE, NULL, qtdemux_tag_add_year}, {
12147 FOURCC__too, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
12148 FOURCC__inf, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
12149 FOURCC_trkn, GST_TAG_TRACK_NUMBER, GST_TAG_TRACK_COUNT, qtdemux_tag_add_num}, {
12150 FOURCC_disk, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
12151 qtdemux_tag_add_num}, {
12152 FOURCC_disc, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
12153 qtdemux_tag_add_num}, {
12154 FOURCC__gen, GST_TAG_GENRE, NULL, qtdemux_tag_add_str}, {
12155 FOURCC_gnre, GST_TAG_GENRE, NULL, qtdemux_tag_add_gnre}, {
12156 FOURCC_tmpo, GST_TAG_BEATS_PER_MINUTE, NULL, qtdemux_tag_add_tmpo}, {
12157 FOURCC_covr, GST_TAG_PREVIEW_IMAGE, NULL, qtdemux_tag_add_covr}, {
12158 FOURCC_sonm, GST_TAG_TITLE_SORTNAME, NULL, qtdemux_tag_add_str}, {
12159 FOURCC_soal, GST_TAG_ALBUM_SORTNAME, NULL, qtdemux_tag_add_str}, {
12160 FOURCC_soar, GST_TAG_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
12161 FOURCC_soaa, GST_TAG_ALBUM_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
12162 FOURCC_soco, GST_TAG_COMPOSER_SORTNAME, NULL, qtdemux_tag_add_str}, {
12163 FOURCC_sosn, GST_TAG_SHOW_SORTNAME, NULL, qtdemux_tag_add_str}, {
12164 FOURCC_tvsh, GST_TAG_SHOW_NAME, NULL, qtdemux_tag_add_str}, {
12165 FOURCC_tvsn, GST_TAG_SHOW_SEASON_NUMBER, NULL, qtdemux_tag_add_uint32}, {
12166 FOURCC_tves, GST_TAG_SHOW_EPISODE_NUMBER, NULL, qtdemux_tag_add_uint32}, {
12167 FOURCC_kywd, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_keywords}, {
12168 FOURCC_keyw, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_str}, {
12169 FOURCC__enc, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
12170 FOURCC_loci, GST_TAG_GEO_LOCATION_NAME, NULL, qtdemux_tag_add_location}, {
12171 FOURCC_clsf, GST_QT_DEMUX_CLASSIFICATION_TAG, NULL,
12172 qtdemux_tag_add_classification}, {
12173 FOURCC__mak, GST_TAG_DEVICE_MANUFACTURER, NULL, qtdemux_tag_add_str}, {
12174 FOURCC__mod, GST_TAG_DEVICE_MODEL, NULL, qtdemux_tag_add_str}, {
12175 FOURCC__swr, GST_TAG_APPLICATION_NAME, NULL, qtdemux_tag_add_str}, {
12177 /* This is a special case, some tags are stored in this
12178 * 'reverse dns naming', according to:
12179 * http://atomicparsley.sourceforge.net/mpeg-4files.html and
12182 FOURCC_____, "", NULL, qtdemux_tag_add_revdns}, {
12183 /* see http://www.mp4ra.org/specs.html for ID32 in meta box */
12184 FOURCC_ID32, "", NULL, qtdemux_tag_add_id32}
12187 struct _GstQtDemuxTagList
12190 GstTagList *taglist;
12192 typedef struct _GstQtDemuxTagList GstQtDemuxTagList;
12195 qtdemux_tag_add_blob (GNode * node, GstQtDemuxTagList * qtdemuxtaglist)
12201 const gchar *style;
12206 GstQTDemux *demux = qtdemuxtaglist->demux;
12207 GstTagList *taglist = qtdemuxtaglist->taglist;
12210 len = QT_UINT32 (data);
12211 buf = gst_buffer_new_and_alloc (len);
12212 gst_buffer_fill (buf, 0, data, len);
12214 /* heuristic to determine style of tag */
12215 if (QT_FOURCC (data + 4) == FOURCC_____ ||
12216 (len > 8 + 12 && QT_FOURCC (data + 12) == FOURCC_data))
12218 else if (demux->major_brand == FOURCC_qt__)
12219 style = "quicktime";
12220 /* fall back to assuming iso/3gp tag style */
12224 /* santize the name for the caps. */
12225 for (i = 0; i < 4; i++) {
12226 guint8 d = data[4 + i];
12227 if (g_ascii_isalnum (d))
12228 ndata[i] = g_ascii_tolower (d);
12233 media_type = g_strdup_printf ("application/x-gst-qt-%c%c%c%c-tag",
12234 ndata[0], ndata[1], ndata[2], ndata[3]);
12235 GST_DEBUG_OBJECT (demux, "media type %s", media_type);
12237 s = gst_structure_new (media_type, "style", G_TYPE_STRING, style, NULL);
12238 sample = gst_sample_new (buf, NULL, NULL, s);
12239 gst_buffer_unref (buf);
12240 g_free (media_type);
12242 GST_DEBUG_OBJECT (demux, "adding private tag; size %d, info %" GST_PTR_FORMAT,
12245 gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND,
12246 GST_QT_DEMUX_PRIVATE_TAG, sample, NULL);
12248 gst_sample_unref (sample);
12252 qtdemux_parse_udta (GstQTDemux * qtdemux, GstTagList * taglist, GNode * udta)
12259 GstQtDemuxTagList demuxtaglist;
12261 demuxtaglist.demux = qtdemux;
12262 demuxtaglist.taglist = taglist;
12264 meta = qtdemux_tree_get_child_by_type (udta, FOURCC_meta);
12265 if (meta != NULL) {
12266 ilst = qtdemux_tree_get_child_by_type (meta, FOURCC_ilst);
12267 if (ilst == NULL) {
12268 GST_LOG_OBJECT (qtdemux, "no ilst");
12273 GST_LOG_OBJECT (qtdemux, "no meta so using udta itself");
12277 while (i < G_N_ELEMENTS (add_funcs)) {
12278 node = qtdemux_tree_get_child_by_type (ilst, add_funcs[i].fourcc);
12282 len = QT_UINT32 (node->data);
12284 GST_DEBUG_OBJECT (qtdemux, "too small tag atom %" GST_FOURCC_FORMAT,
12285 GST_FOURCC_ARGS (add_funcs[i].fourcc));
12287 add_funcs[i].func (qtdemux, taglist, add_funcs[i].gst_tag,
12288 add_funcs[i].gst_tag_bis, node);
12290 g_node_destroy (node);
12296 /* parsed nodes have been removed, pass along remainder as blob */
12297 g_node_children_foreach (ilst, G_TRAVERSE_ALL,
12298 (GNodeForeachFunc) qtdemux_tag_add_blob, &demuxtaglist);
12300 /* parse up XMP_ node if existing */
12301 xmp_ = qtdemux_tree_get_child_by_type (udta, FOURCC_XMP_);
12302 if (xmp_ != NULL) {
12304 GstTagList *xmptaglist;
12306 buf = _gst_buffer_new_wrapped (((guint8 *) xmp_->data) + 8,
12307 QT_UINT32 ((guint8 *) xmp_->data) - 8, NULL);
12308 xmptaglist = gst_tag_list_from_xmp_buffer (buf);
12309 gst_buffer_unref (buf);
12311 qtdemux_handle_xmp_taglist (qtdemux, taglist, xmptaglist);
12313 GST_DEBUG_OBJECT (qtdemux, "No XMP_ node found");
12319 GstStructure *structure; /* helper for sort function */
12321 guint min_req_bitrate;
12322 guint min_req_qt_version;
12326 qtdemux_redirects_sort_func (gconstpointer a, gconstpointer b)
12328 GstQtReference *ref_a = (GstQtReference *) a;
12329 GstQtReference *ref_b = (GstQtReference *) b;
12331 if (ref_b->min_req_qt_version != ref_a->min_req_qt_version)
12332 return ref_b->min_req_qt_version - ref_a->min_req_qt_version;
12334 /* known bitrates go before unknown; higher bitrates go first */
12335 return ref_b->min_req_bitrate - ref_a->min_req_bitrate;
12338 /* sort the redirects and post a message for the application.
12341 qtdemux_process_redirects (GstQTDemux * qtdemux, GList * references)
12343 GstQtReference *best;
12346 GValue list_val = { 0, };
12349 g_assert (references != NULL);
12351 references = g_list_sort (references, qtdemux_redirects_sort_func);
12353 best = (GstQtReference *) references->data;
12355 g_value_init (&list_val, GST_TYPE_LIST);
12357 for (l = references; l != NULL; l = l->next) {
12358 GstQtReference *ref = (GstQtReference *) l->data;
12359 GValue struct_val = { 0, };
12361 ref->structure = gst_structure_new ("redirect",
12362 "new-location", G_TYPE_STRING, ref->location, NULL);
12364 if (ref->min_req_bitrate > 0) {
12365 gst_structure_set (ref->structure, "minimum-bitrate", G_TYPE_INT,
12366 ref->min_req_bitrate, NULL);
12369 g_value_init (&struct_val, GST_TYPE_STRUCTURE);
12370 g_value_set_boxed (&struct_val, ref->structure);
12371 gst_value_list_append_value (&list_val, &struct_val);
12372 g_value_unset (&struct_val);
12373 /* don't free anything here yet, since we need best->structure below */
12376 g_assert (best != NULL);
12377 s = gst_structure_copy (best->structure);
12379 if (g_list_length (references) > 1) {
12380 gst_structure_set_value (s, "locations", &list_val);
12383 g_value_unset (&list_val);
12385 for (l = references; l != NULL; l = l->next) {
12386 GstQtReference *ref = (GstQtReference *) l->data;
12388 gst_structure_free (ref->structure);
12389 g_free (ref->location);
12392 g_list_free (references);
12394 GST_INFO_OBJECT (qtdemux, "posting redirect message: %" GST_PTR_FORMAT, s);
12395 msg = gst_message_new_element (GST_OBJECT_CAST (qtdemux), s);
12396 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
12397 qtdemux->posted_redirect = TRUE;
12400 /* look for redirect nodes, collect all redirect information and
12404 qtdemux_parse_redirects (GstQTDemux * qtdemux)
12406 GNode *rmra, *rmda, *rdrf;
12408 rmra = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_rmra);
12410 GList *redirects = NULL;
12412 rmda = qtdemux_tree_get_child_by_type (rmra, FOURCC_rmda);
12414 GstQtReference ref = { NULL, NULL, 0, 0 };
12415 GNode *rmdr, *rmvc;
12417 if ((rmdr = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmdr))) {
12418 ref.min_req_bitrate = QT_UINT32 ((guint8 *) rmdr->data + 12);
12419 GST_LOG_OBJECT (qtdemux, "data rate atom, required bitrate = %u",
12420 ref.min_req_bitrate);
12423 if ((rmvc = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmvc))) {
12424 guint32 package = QT_FOURCC ((guint8 *) rmvc->data + 12);
12425 guint version = QT_UINT32 ((guint8 *) rmvc->data + 16);
12427 #ifndef GST_DISABLE_GST_DEBUG
12428 guint bitmask = QT_UINT32 ((guint8 *) rmvc->data + 20);
12430 guint check_type = QT_UINT16 ((guint8 *) rmvc->data + 24);
12432 GST_LOG_OBJECT (qtdemux,
12433 "version check atom [%" GST_FOURCC_FORMAT "], version=0x%08x"
12434 ", mask=%08x, check_type=%u", GST_FOURCC_ARGS (package), version,
12435 bitmask, check_type);
12436 if (package == FOURCC_qtim && check_type == 0) {
12437 ref.min_req_qt_version = version;
12441 rdrf = qtdemux_tree_get_child_by_type (rmda, FOURCC_rdrf);
12447 ref_len = QT_UINT32 ((guint8 *) rdrf->data);
12448 if (ref_len > 20) {
12449 ref_type = QT_FOURCC ((guint8 *) rdrf->data + 12);
12450 ref_data = (guint8 *) rdrf->data + 20;
12451 if (ref_type == FOURCC_alis) {
12452 guint record_len, record_version, fn_len;
12454 if (ref_len > 70) {
12455 /* MacOSX alias record, google for alias-layout.txt */
12456 record_len = QT_UINT16 (ref_data + 4);
12457 record_version = QT_UINT16 (ref_data + 4 + 2);
12458 fn_len = QT_UINT8 (ref_data + 50);
12459 if (record_len > 50 && record_version == 2 && fn_len > 0) {
12460 ref.location = g_strndup ((gchar *) ref_data + 51, fn_len);
12463 GST_WARNING_OBJECT (qtdemux, "Invalid rdrf/alis size (%u < 70)",
12466 } else if (ref_type == FOURCC_url_) {
12467 ref.location = g_strndup ((gchar *) ref_data, ref_len - 8);
12469 GST_DEBUG_OBJECT (qtdemux,
12470 "unknown rdrf reference type %" GST_FOURCC_FORMAT,
12471 GST_FOURCC_ARGS (ref_type));
12473 if (ref.location != NULL) {
12474 GST_INFO_OBJECT (qtdemux, "New location: %s", ref.location);
12476 g_list_prepend (redirects, g_memdup (&ref, sizeof (ref)));
12478 GST_WARNING_OBJECT (qtdemux,
12479 "Failed to extract redirect location from rdrf atom");
12482 GST_WARNING_OBJECT (qtdemux, "Invalid rdrf size (%u < 20)", ref_len);
12486 /* look for others */
12487 rmda = qtdemux_tree_get_sibling_by_type (rmda, FOURCC_rmda);
12490 if (redirects != NULL) {
12491 qtdemux_process_redirects (qtdemux, redirects);
12497 static GstTagList *
12498 qtdemux_add_container_format (GstQTDemux * qtdemux, GstTagList * tags)
12502 if (tags == NULL) {
12503 tags = gst_tag_list_new_empty ();
12504 gst_tag_list_set_scope (tags, GST_TAG_SCOPE_GLOBAL);
12507 if (qtdemux->major_brand == FOURCC_mjp2)
12508 fmt = "Motion JPEG 2000";
12509 else if ((qtdemux->major_brand & 0xffff) == FOURCC_3g__)
12511 else if (qtdemux->major_brand == FOURCC_qt__)
12513 else if (qtdemux->fragmented)
12516 fmt = "ISO MP4/M4A";
12518 GST_LOG_OBJECT (qtdemux, "mapped %" GST_FOURCC_FORMAT " to '%s'",
12519 GST_FOURCC_ARGS (qtdemux->major_brand), fmt);
12521 gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_CONTAINER_FORMAT,
12527 /* we have read the complete moov node now.
12528 * This function parses all of the relevant info, creates the traks and
12529 * prepares all data structures for playback
12532 qtdemux_parse_tree (GstQTDemux * qtdemux)
12538 GstClockTime duration;
12540 guint64 creation_time;
12541 GstDateTime *datetime = NULL;
12544 /* make sure we have a usable taglist */
12545 if (!qtdemux->tag_list) {
12546 qtdemux->tag_list = gst_tag_list_new_empty ();
12547 gst_tag_list_set_scope (qtdemux->tag_list, GST_TAG_SCOPE_GLOBAL);
12549 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
12552 mvhd = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvhd);
12553 if (mvhd == NULL) {
12554 GST_LOG_OBJECT (qtdemux, "No mvhd node found, looking for redirects.");
12555 return qtdemux_parse_redirects (qtdemux);
12558 version = QT_UINT8 ((guint8 *) mvhd->data + 8);
12559 if (version == 1) {
12560 creation_time = QT_UINT64 ((guint8 *) mvhd->data + 12);
12561 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 28);
12562 qtdemux->duration = QT_UINT64 ((guint8 *) mvhd->data + 32);
12563 } else if (version == 0) {
12564 creation_time = QT_UINT32 ((guint8 *) mvhd->data + 12);
12565 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 20);
12566 qtdemux->duration = QT_UINT32 ((guint8 *) mvhd->data + 24);
12568 GST_WARNING_OBJECT (qtdemux, "Unhandled mvhd version %d", version);
12572 /* Moving qt creation time (secs since 1904) to unix time */
12573 if (creation_time != 0) {
12574 /* Try to use epoch first as it should be faster and more commonly found */
12575 if (creation_time >= QTDEMUX_SECONDS_FROM_1904_TO_1970) {
12578 creation_time -= QTDEMUX_SECONDS_FROM_1904_TO_1970;
12579 /* some data cleansing sanity */
12580 g_get_current_time (&now);
12581 if (now.tv_sec + 24 * 3600 < creation_time) {
12582 GST_DEBUG_OBJECT (qtdemux, "discarding bogus future creation time");
12584 datetime = gst_date_time_new_from_unix_epoch_utc (creation_time);
12587 GDateTime *base_dt = g_date_time_new_utc (1904, 1, 1, 0, 0, 0);
12588 GDateTime *dt, *dt_local;
12590 dt = g_date_time_add_seconds (base_dt, creation_time);
12591 dt_local = g_date_time_to_local (dt);
12592 datetime = gst_date_time_new_from_g_date_time (dt_local);
12594 g_date_time_unref (base_dt);
12595 g_date_time_unref (dt);
12599 /* Use KEEP as explicit tags should have a higher priority than mvhd tag */
12600 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_KEEP, GST_TAG_DATE_TIME,
12602 gst_date_time_unref (datetime);
12605 GST_INFO_OBJECT (qtdemux, "timescale: %u", qtdemux->timescale);
12606 GST_INFO_OBJECT (qtdemux, "duration: %" G_GUINT64_FORMAT, qtdemux->duration);
12608 /* check for fragmented file and get some (default) data */
12609 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
12612 GstByteReader mehd_data;
12614 /* let track parsing or anyone know weird stuff might happen ... */
12615 qtdemux->fragmented = TRUE;
12617 /* compensate for total duration */
12618 mehd = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_mehd, &mehd_data);
12620 qtdemux_parse_mehd (qtdemux, &mehd_data);
12623 /* set duration in the segment info */
12624 gst_qtdemux_get_duration (qtdemux, &duration);
12626 qtdemux->segment.duration = duration;
12627 /* also do not exceed duration; stop is set that way post seek anyway,
12628 * and segment activation falls back to duration,
12629 * whereas loop only checks stop, so let's align this here as well */
12630 qtdemux->segment.stop = duration;
12633 /* parse all traks */
12634 trak = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_trak);
12636 qtdemux_parse_trak (qtdemux, trak);
12637 /* iterate all siblings */
12638 trak = qtdemux_tree_get_sibling_by_type (trak, FOURCC_trak);
12641 if (!qtdemux->tag_list) {
12642 GST_DEBUG_OBJECT (qtdemux, "new tag list");
12643 qtdemux->tag_list = gst_tag_list_new_empty ();
12644 gst_tag_list_set_scope (qtdemux->tag_list, GST_TAG_SCOPE_GLOBAL);
12646 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
12650 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_udta);
12652 qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
12654 GST_LOG_OBJECT (qtdemux, "No udta node found.");
12657 /* maybe also some tags in meta box */
12658 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_meta);
12660 GST_DEBUG_OBJECT (qtdemux, "Parsing meta box for tags.");
12661 qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
12663 GST_LOG_OBJECT (qtdemux, "No meta node found.");
12666 /* parse any protection system info */
12667 pssh = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_pssh);
12669 GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
12670 qtdemux_parse_pssh (qtdemux, pssh);
12671 pssh = qtdemux_tree_get_sibling_by_type (pssh, FOURCC_pssh);
12674 qtdemux->tag_list = qtdemux_add_container_format (qtdemux, qtdemux->tag_list);
12679 /* taken from ffmpeg */
12681 read_descr_size (guint8 * ptr, guint8 * end, guint8 ** end_out)
12693 len = (len << 7) | (c & 0x7f);
12701 /* this can change the codec originally present in @list */
12703 gst_qtdemux_handle_esds (GstQTDemux * qtdemux, QtDemuxStream * stream,
12704 GNode * esds, GstTagList * list)
12706 int len = QT_UINT32 (esds->data);
12707 guint8 *ptr = esds->data;
12708 guint8 *end = ptr + len;
12710 guint8 *data_ptr = NULL;
12712 guint8 object_type_id = 0;
12713 const char *codec_name = NULL;
12714 GstCaps *caps = NULL;
12716 GST_MEMDUMP_OBJECT (qtdemux, "esds", ptr, len);
12718 GST_DEBUG_OBJECT (qtdemux, "version/flags = %08x", QT_UINT32 (ptr));
12720 while (ptr + 1 < end) {
12721 tag = QT_UINT8 (ptr);
12722 GST_DEBUG_OBJECT (qtdemux, "tag = %02x", tag);
12724 len = read_descr_size (ptr, end, &ptr);
12725 GST_DEBUG_OBJECT (qtdemux, "len = %d", len);
12727 /* Check the stated amount of data is available for reading */
12728 if (len < 0 || ptr + len > end)
12732 case ES_DESCRIPTOR_TAG:
12733 GST_DEBUG_OBJECT (qtdemux, "ID %04x", QT_UINT16 (ptr));
12734 GST_DEBUG_OBJECT (qtdemux, "priority %04x", QT_UINT8 (ptr + 2));
12737 case DECODER_CONFIG_DESC_TAG:{
12738 guint max_bitrate, avg_bitrate;
12740 object_type_id = QT_UINT8 (ptr);
12741 max_bitrate = QT_UINT32 (ptr + 5);
12742 avg_bitrate = QT_UINT32 (ptr + 9);
12743 GST_DEBUG_OBJECT (qtdemux, "object_type_id %02x", object_type_id);
12744 GST_DEBUG_OBJECT (qtdemux, "stream_type %02x", QT_UINT8 (ptr + 1));
12745 GST_DEBUG_OBJECT (qtdemux, "buffer_size_db %02x", QT_UINT24 (ptr + 2));
12746 GST_DEBUG_OBJECT (qtdemux, "max bitrate %u", max_bitrate);
12747 GST_DEBUG_OBJECT (qtdemux, "avg bitrate %u", avg_bitrate);
12748 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
12749 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
12750 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
12752 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
12753 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
12754 avg_bitrate, NULL);
12759 case DECODER_SPECIFIC_INFO_TAG:
12760 GST_MEMDUMP_OBJECT (qtdemux, "data", ptr, len);
12761 if (object_type_id == 0xe0 && len == 0x40) {
12767 GST_DEBUG_OBJECT (qtdemux,
12768 "Have VOBSUB palette. Creating palette event");
12769 /* move to decConfigDescr data and read palette */
12771 for (i = 0; i < 16; i++) {
12772 clut[i] = QT_UINT32 (data);
12776 s = gst_structure_new ("application/x-gst-dvd", "event",
12777 G_TYPE_STRING, "dvd-spu-clut-change",
12778 "clut00", G_TYPE_INT, clut[0], "clut01", G_TYPE_INT, clut[1],
12779 "clut02", G_TYPE_INT, clut[2], "clut03", G_TYPE_INT, clut[3],
12780 "clut04", G_TYPE_INT, clut[4], "clut05", G_TYPE_INT, clut[5],
12781 "clut06", G_TYPE_INT, clut[6], "clut07", G_TYPE_INT, clut[7],
12782 "clut08", G_TYPE_INT, clut[8], "clut09", G_TYPE_INT, clut[9],
12783 "clut10", G_TYPE_INT, clut[10], "clut11", G_TYPE_INT, clut[11],
12784 "clut12", G_TYPE_INT, clut[12], "clut13", G_TYPE_INT, clut[13],
12785 "clut14", G_TYPE_INT, clut[14], "clut15", G_TYPE_INT, clut[15],
12788 /* store event and trigger custom processing */
12789 stream->pending_event =
12790 gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s);
12792 /* Generic codec_data handler puts it on the caps */
12799 case SL_CONFIG_DESC_TAG:
12800 GST_DEBUG_OBJECT (qtdemux, "data %02x", QT_UINT8 (ptr));
12804 GST_DEBUG_OBJECT (qtdemux, "Unknown/unhandled descriptor tag %02x",
12806 GST_MEMDUMP_OBJECT (qtdemux, "descriptor data", ptr, len);
12812 /* object_type_id in the esds atom in mp4a and mp4v tells us which codec is
12813 * in use, and should also be used to override some other parameters for some
12815 switch (object_type_id) {
12816 case 0x20: /* MPEG-4 */
12817 /* 4 bytes for the visual_object_sequence_start_code and 1 byte for the
12818 * profile_and_level_indication */
12819 if (data_ptr != NULL && data_len >= 5 &&
12820 GST_READ_UINT32_BE (data_ptr) == 0x000001b0) {
12821 gst_codec_utils_mpeg4video_caps_set_level_and_profile (stream->caps,
12822 data_ptr + 4, data_len - 4);
12824 break; /* Nothing special needed here */
12825 case 0x21: /* H.264 */
12826 codec_name = "H.264 / AVC";
12827 caps = gst_caps_new_simple ("video/x-h264",
12828 "stream-format", G_TYPE_STRING, "avc",
12829 "alignment", G_TYPE_STRING, "au", NULL);
12831 case 0x40: /* AAC (any) */
12832 case 0x66: /* AAC Main */
12833 case 0x67: /* AAC LC */
12834 case 0x68: /* AAC SSR */
12835 /* Override channels and rate based on the codec_data, as it's often
12837 /* Only do so for basic setup without HE-AAC extension */
12838 if (data_ptr && data_len == 2) {
12839 guint channels, rate;
12841 channels = gst_codec_utils_aac_get_channels (data_ptr, data_len);
12843 stream->n_channels = channels;
12845 rate = gst_codec_utils_aac_get_sample_rate (data_ptr, data_len);
12847 stream->rate = rate;
12850 /* Set level and profile if possible */
12851 if (data_ptr != NULL && data_len >= 2) {
12852 gst_codec_utils_aac_caps_set_level_and_profile (stream->caps,
12853 data_ptr, data_len);
12855 const gchar *profile_str = NULL;
12858 guint8 *codec_data;
12859 gint rate_idx, profile;
12861 /* No codec_data, let's invent something.
12862 * FIXME: This is wrong for SBR! */
12864 GST_WARNING_OBJECT (qtdemux, "No codec_data for AAC available");
12866 buffer = gst_buffer_new_and_alloc (2);
12867 gst_buffer_map (buffer, &map, GST_MAP_WRITE);
12868 codec_data = map.data;
12871 gst_codec_utils_aac_get_index_from_sample_rate (stream->rate);
12873 switch (object_type_id) {
12875 profile_str = "main";
12879 profile_str = "lc";
12883 profile_str = "ssr";
12891 codec_data[0] = ((profile + 1) << 3) | ((rate_idx & 0xE) >> 1);
12892 codec_data[1] = ((rate_idx & 0x1) << 7) | (stream->n_channels << 3);
12894 gst_buffer_unmap (buffer, &map);
12895 gst_caps_set_simple (stream->caps, "codec_data", GST_TYPE_BUFFER,
12897 gst_buffer_unref (buffer);
12900 gst_caps_set_simple (stream->caps, "profile", G_TYPE_STRING,
12901 profile_str, NULL);
12905 case 0x60: /* MPEG-2, various profiles */
12911 codec_name = "MPEG-2 video";
12912 caps = gst_caps_new_simple ("video/mpeg",
12913 "mpegversion", G_TYPE_INT, 2,
12914 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
12916 case 0x69: /* MPEG-2 BC audio */
12917 case 0x6B: /* MPEG-1 audio */
12918 caps = gst_caps_new_simple ("audio/mpeg",
12919 "mpegversion", G_TYPE_INT, 1, "parsed", G_TYPE_BOOLEAN, TRUE, NULL);
12920 codec_name = "MPEG-1 audio";
12922 case 0x6A: /* MPEG-1 */
12923 codec_name = "MPEG-1 video";
12924 caps = gst_caps_new_simple ("video/mpeg",
12925 "mpegversion", G_TYPE_INT, 1,
12926 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
12928 case 0x6C: /* MJPEG */
12930 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
12932 codec_name = "Motion-JPEG";
12934 case 0x6D: /* PNG */
12936 gst_caps_new_simple ("image/png", "parsed", G_TYPE_BOOLEAN, TRUE,
12938 codec_name = "PNG still images";
12940 case 0x6E: /* JPEG2000 */
12941 codec_name = "JPEG-2000";
12942 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
12944 case 0xA4: /* Dirac */
12945 codec_name = "Dirac";
12946 caps = gst_caps_new_empty_simple ("video/x-dirac");
12948 case 0xA5: /* AC3 */
12949 codec_name = "AC-3 audio";
12950 caps = gst_caps_new_simple ("audio/x-ac3",
12951 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
12953 case 0xA9: /* AC3 */
12954 codec_name = "DTS audio";
12955 caps = gst_caps_new_simple ("audio/x-dts",
12956 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
12958 case 0xE1: /* QCELP */
12959 /* QCELP, the codec_data is a riff tag (little endian) with
12960 * 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). */
12961 caps = gst_caps_new_empty_simple ("audio/qcelp");
12962 codec_name = "QCELP";
12968 /* If we have a replacement caps, then change our caps for this stream */
12970 gst_caps_unref (stream->caps);
12971 stream->caps = caps;
12974 if (codec_name && list)
12975 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
12976 GST_TAG_AUDIO_CODEC, codec_name, NULL);
12978 /* Add the codec_data attribute to caps, if we have it */
12982 buffer = gst_buffer_new_and_alloc (data_len);
12983 gst_buffer_fill (buffer, 0, data_ptr, data_len);
12985 GST_DEBUG_OBJECT (qtdemux, "setting codec_data from esds");
12986 GST_MEMDUMP_OBJECT (qtdemux, "codec_data from esds", data_ptr, data_len);
12988 gst_caps_set_simple (stream->caps, "codec_data", GST_TYPE_BUFFER,
12990 gst_buffer_unref (buffer);
12995 #define _codec(name) \
12997 if (codec_name) { \
12998 *codec_name = g_strdup (name); \
13003 qtdemux_video_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
13004 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
13006 GstCaps *caps = NULL;
13007 GstVideoFormat format = GST_VIDEO_FORMAT_UNKNOWN;
13010 case GST_MAKE_FOURCC ('p', 'n', 'g', ' '):
13011 _codec ("PNG still images");
13012 caps = gst_caps_new_empty_simple ("image/png");
13015 _codec ("JPEG still images");
13017 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
13020 case GST_MAKE_FOURCC ('m', 'j', 'p', 'a'):
13021 case GST_MAKE_FOURCC ('A', 'V', 'D', 'J'):
13022 case GST_MAKE_FOURCC ('M', 'J', 'P', 'G'):
13023 case GST_MAKE_FOURCC ('d', 'm', 'b', '1'):
13024 _codec ("Motion-JPEG");
13026 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
13029 case GST_MAKE_FOURCC ('m', 'j', 'p', 'b'):
13030 _codec ("Motion-JPEG format B");
13031 caps = gst_caps_new_empty_simple ("video/x-mjpeg-b");
13034 _codec ("JPEG-2000");
13035 /* override to what it should be according to spec, avoid palette_data */
13036 stream->bits_per_sample = 24;
13037 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
13040 _codec ("Sorensen video v.3");
13041 caps = gst_caps_new_simple ("video/x-svq",
13042 "svqversion", G_TYPE_INT, 3, NULL);
13044 case GST_MAKE_FOURCC ('s', 'v', 'q', 'i'):
13045 case GST_MAKE_FOURCC ('S', 'V', 'Q', '1'):
13046 _codec ("Sorensen video v.1");
13047 caps = gst_caps_new_simple ("video/x-svq",
13048 "svqversion", G_TYPE_INT, 1, NULL);
13050 case GST_MAKE_FOURCC ('W', 'R', 'A', 'W'):
13051 caps = gst_caps_new_empty_simple ("video/x-raw");
13052 gst_caps_set_simple (caps, "format", G_TYPE_STRING, "RGB8P", NULL);
13053 _codec ("Windows Raw RGB");
13059 bps = QT_UINT16 (stsd_data + 98);
13062 format = GST_VIDEO_FORMAT_RGB15;
13065 format = GST_VIDEO_FORMAT_RGB16;
13068 format = GST_VIDEO_FORMAT_RGB;
13071 format = GST_VIDEO_FORMAT_ARGB;
13079 case GST_MAKE_FOURCC ('y', 'v', '1', '2'):
13080 format = GST_VIDEO_FORMAT_I420;
13082 case GST_MAKE_FOURCC ('y', 'u', 'v', '2'):
13083 case GST_MAKE_FOURCC ('Y', 'u', 'v', '2'):
13084 format = GST_VIDEO_FORMAT_I420;
13087 case GST_MAKE_FOURCC ('2', 'V', 'u', 'y'):
13088 format = GST_VIDEO_FORMAT_UYVY;
13090 case GST_MAKE_FOURCC ('v', '3', '0', '8'):
13091 format = GST_VIDEO_FORMAT_v308;
13093 case GST_MAKE_FOURCC ('v', '2', '1', '6'):
13094 format = GST_VIDEO_FORMAT_v216;
13097 format = GST_VIDEO_FORMAT_v210;
13099 case GST_MAKE_FOURCC ('r', '2', '1', '0'):
13100 format = GST_VIDEO_FORMAT_r210;
13102 /* Packed YUV 4:4:4 10 bit in 32 bits, complex
13103 case GST_MAKE_FOURCC ('v', '4', '1', '0'):
13104 format = GST_VIDEO_FORMAT_v410;
13107 /* Packed YUV 4:4:4:4 8 bit in 32 bits
13108 * but different order than AYUV
13109 case GST_MAKE_FOURCC ('v', '4', '0', '8'):
13110 format = GST_VIDEO_FORMAT_v408;
13113 case GST_MAKE_FOURCC ('m', 'p', 'e', 'g'):
13114 case GST_MAKE_FOURCC ('m', 'p', 'g', '1'):
13115 _codec ("MPEG-1 video");
13116 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
13117 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13119 case GST_MAKE_FOURCC ('h', 'd', 'v', '1'): /* HDV 720p30 */
13120 case GST_MAKE_FOURCC ('h', 'd', 'v', '2'): /* HDV 1080i60 */
13121 case GST_MAKE_FOURCC ('h', 'd', 'v', '3'): /* HDV 1080i50 */
13122 case GST_MAKE_FOURCC ('h', 'd', 'v', '4'): /* HDV 720p24 */
13123 case GST_MAKE_FOURCC ('h', 'd', 'v', '5'): /* HDV 720p25 */
13124 case GST_MAKE_FOURCC ('h', 'd', 'v', '6'): /* HDV 1080p24 */
13125 case GST_MAKE_FOURCC ('h', 'd', 'v', '7'): /* HDV 1080p25 */
13126 case GST_MAKE_FOURCC ('h', 'd', 'v', '8'): /* HDV 1080p30 */
13127 case GST_MAKE_FOURCC ('h', 'd', 'v', '9'): /* HDV 720p60 */
13128 case GST_MAKE_FOURCC ('h', 'd', 'v', 'a'): /* HDV 720p50 */
13129 case GST_MAKE_FOURCC ('m', 'x', '5', 'n'): /* MPEG2 IMX NTSC 525/60 50mb/s produced by FCP */
13130 case GST_MAKE_FOURCC ('m', 'x', '5', 'p'): /* MPEG2 IMX PAL 625/60 50mb/s produced by FCP */
13131 case GST_MAKE_FOURCC ('m', 'x', '4', 'n'): /* MPEG2 IMX NTSC 525/60 40mb/s produced by FCP */
13132 case GST_MAKE_FOURCC ('m', 'x', '4', 'p'): /* MPEG2 IMX PAL 625/60 40mb/s produced by FCP */
13133 case GST_MAKE_FOURCC ('m', 'x', '3', 'n'): /* MPEG2 IMX NTSC 525/60 30mb/s produced by FCP */
13134 case GST_MAKE_FOURCC ('m', 'x', '3', 'p'): /* MPEG2 IMX PAL 625/50 30mb/s produced by FCP */
13135 case GST_MAKE_FOURCC ('x', 'd', 'v', '1'): /* XDCAM HD 720p30 35Mb/s */
13136 case GST_MAKE_FOURCC ('x', 'd', 'v', '2'): /* XDCAM HD 1080i60 35Mb/s */
13137 case GST_MAKE_FOURCC ('x', 'd', 'v', '3'): /* XDCAM HD 1080i50 35Mb/s */
13138 case GST_MAKE_FOURCC ('x', 'd', 'v', '4'): /* XDCAM HD 720p24 35Mb/s */
13139 case GST_MAKE_FOURCC ('x', 'd', 'v', '5'): /* XDCAM HD 720p25 35Mb/s */
13140 case GST_MAKE_FOURCC ('x', 'd', 'v', '6'): /* XDCAM HD 1080p24 35Mb/s */
13141 case GST_MAKE_FOURCC ('x', 'd', 'v', '7'): /* XDCAM HD 1080p25 35Mb/s */
13142 case GST_MAKE_FOURCC ('x', 'd', 'v', '8'): /* XDCAM HD 1080p30 35Mb/s */
13143 case GST_MAKE_FOURCC ('x', 'd', 'v', '9'): /* XDCAM HD 720p60 35Mb/s */
13144 case GST_MAKE_FOURCC ('x', 'd', 'v', 'a'): /* XDCAM HD 720p50 35Mb/s */
13145 case GST_MAKE_FOURCC ('x', 'd', 'v', 'b'): /* XDCAM EX 1080i60 50Mb/s CBR */
13146 case GST_MAKE_FOURCC ('x', 'd', 'v', 'c'): /* XDCAM EX 1080i50 50Mb/s CBR */
13147 case GST_MAKE_FOURCC ('x', 'd', 'v', 'd'): /* XDCAM HD 1080p24 50Mb/s CBR */
13148 case GST_MAKE_FOURCC ('x', 'd', 'v', 'e'): /* XDCAM HD 1080p25 50Mb/s CBR */
13149 case GST_MAKE_FOURCC ('x', 'd', 'v', 'f'): /* XDCAM HD 1080p30 50Mb/s CBR */
13150 case GST_MAKE_FOURCC ('x', 'd', '5', '1'): /* XDCAM HD422 720p30 50Mb/s CBR */
13151 case GST_MAKE_FOURCC ('x', 'd', '5', '4'): /* XDCAM HD422 720p24 50Mb/s CBR */
13152 case GST_MAKE_FOURCC ('x', 'd', '5', '5'): /* XDCAM HD422 720p25 50Mb/s CBR */
13153 case GST_MAKE_FOURCC ('x', 'd', '5', '9'): /* XDCAM HD422 720p60 50Mb/s CBR */
13154 case GST_MAKE_FOURCC ('x', 'd', '5', 'a'): /* XDCAM HD422 720p50 50Mb/s CBR */
13155 case GST_MAKE_FOURCC ('x', 'd', '5', 'b'): /* XDCAM HD422 1080i50 50Mb/s CBR */
13156 case GST_MAKE_FOURCC ('x', 'd', '5', 'c'): /* XDCAM HD422 1080i50 50Mb/s CBR */
13157 case GST_MAKE_FOURCC ('x', 'd', '5', 'd'): /* XDCAM HD422 1080p24 50Mb/s CBR */
13158 case GST_MAKE_FOURCC ('x', 'd', '5', 'e'): /* XDCAM HD422 1080p25 50Mb/s CBR */
13159 case GST_MAKE_FOURCC ('x', 'd', '5', 'f'): /* XDCAM HD422 1080p30 50Mb/s CBR */
13160 case GST_MAKE_FOURCC ('x', 'd', 'h', 'd'): /* XDCAM HD 540p */
13161 case GST_MAKE_FOURCC ('x', 'd', 'h', '2'): /* XDCAM HD422 540p */
13162 case GST_MAKE_FOURCC ('A', 'V', 'm', 'p'): /* AVID IMX PAL */
13163 case GST_MAKE_FOURCC ('m', 'p', 'g', '2'): /* AVID IMX PAL */
13164 case GST_MAKE_FOURCC ('m', 'p', '2', 'v'): /* AVID IMX PAL */
13165 _codec ("MPEG-2 video");
13166 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 2,
13167 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13169 case GST_MAKE_FOURCC ('g', 'i', 'f', ' '):
13170 _codec ("GIF still images");
13171 caps = gst_caps_new_empty_simple ("image/gif");
13174 case GST_MAKE_FOURCC ('H', '2', '6', '3'):
13176 case GST_MAKE_FOURCC ('U', '2', '6', '3'):
13178 /* ffmpeg uses the height/width props, don't know why */
13179 caps = gst_caps_new_simple ("video/x-h263",
13180 "variant", G_TYPE_STRING, "itu", NULL);
13184 _codec ("MPEG-4 video");
13185 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
13186 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13188 case GST_MAKE_FOURCC ('3', 'i', 'v', 'd'):
13189 case GST_MAKE_FOURCC ('3', 'I', 'V', 'D'):
13190 _codec ("Microsoft MPEG-4 4.3"); /* FIXME? */
13191 caps = gst_caps_new_simple ("video/x-msmpeg",
13192 "msmpegversion", G_TYPE_INT, 43, NULL);
13194 case GST_MAKE_FOURCC ('D', 'I', 'V', '3'):
13196 caps = gst_caps_new_simple ("video/x-divx",
13197 "divxversion", G_TYPE_INT, 3, NULL);
13199 case GST_MAKE_FOURCC ('D', 'I', 'V', 'X'):
13200 case GST_MAKE_FOURCC ('d', 'i', 'v', 'x'):
13202 caps = gst_caps_new_simple ("video/x-divx",
13203 "divxversion", G_TYPE_INT, 4, NULL);
13205 case GST_MAKE_FOURCC ('D', 'X', '5', '0'):
13207 caps = gst_caps_new_simple ("video/x-divx",
13208 "divxversion", G_TYPE_INT, 5, NULL);
13211 case GST_MAKE_FOURCC ('F', 'F', 'V', '1'):
13213 caps = gst_caps_new_simple ("video/x-ffv",
13214 "ffvversion", G_TYPE_INT, 1, NULL);
13217 case GST_MAKE_FOURCC ('3', 'I', 'V', '1'):
13218 case GST_MAKE_FOURCC ('3', 'I', 'V', '2'):
13219 case GST_MAKE_FOURCC ('X', 'V', 'I', 'D'):
13220 case GST_MAKE_FOURCC ('x', 'v', 'i', 'd'):
13222 case GST_MAKE_FOURCC ('U', 'M', 'P', '4'):
13223 caps = gst_caps_new_simple ("video/mpeg",
13224 "mpegversion", G_TYPE_INT, 4, NULL);
13228 case GST_MAKE_FOURCC ('c', 'v', 'i', 'd'):
13229 _codec ("Cinepak");
13230 caps = gst_caps_new_empty_simple ("video/x-cinepak");
13232 case GST_MAKE_FOURCC ('q', 'd', 'r', 'w'):
13233 _codec ("Apple QuickDraw");
13234 caps = gst_caps_new_empty_simple ("video/x-qdrw");
13236 case GST_MAKE_FOURCC ('r', 'p', 'z', 'a'):
13237 _codec ("Apple video");
13238 caps = gst_caps_new_empty_simple ("video/x-apple-video");
13242 _codec ("H.264 / AVC");
13243 caps = gst_caps_new_simple ("video/x-h264",
13244 "stream-format", G_TYPE_STRING, "avc",
13245 "alignment", G_TYPE_STRING, "au", NULL);
13248 _codec ("H.264 / AVC");
13249 caps = gst_caps_new_simple ("video/x-h264",
13250 "stream-format", G_TYPE_STRING, "avc3",
13251 "alignment", G_TYPE_STRING, "au", NULL);
13255 _codec ("H.265 / HEVC");
13256 caps = gst_caps_new_simple ("video/x-h265",
13257 "stream-format", G_TYPE_STRING, "hvc1",
13258 "alignment", G_TYPE_STRING, "au", NULL);
13261 _codec ("H.265 / HEVC");
13262 caps = gst_caps_new_simple ("video/x-h265",
13263 "stream-format", G_TYPE_STRING, "hev1",
13264 "alignment", G_TYPE_STRING, "au", NULL);
13267 _codec ("Run-length encoding");
13268 caps = gst_caps_new_simple ("video/x-rle",
13269 "layout", G_TYPE_STRING, "quicktime", NULL);
13272 _codec ("Run-length encoding");
13273 caps = gst_caps_new_simple ("video/x-rle",
13274 "layout", G_TYPE_STRING, "microsoft", NULL);
13276 case GST_MAKE_FOURCC ('I', 'V', '3', '2'):
13277 case GST_MAKE_FOURCC ('i', 'v', '3', '2'):
13278 _codec ("Indeo Video 3");
13279 caps = gst_caps_new_simple ("video/x-indeo",
13280 "indeoversion", G_TYPE_INT, 3, NULL);
13282 case GST_MAKE_FOURCC ('I', 'V', '4', '1'):
13283 case GST_MAKE_FOURCC ('i', 'v', '4', '1'):
13284 _codec ("Intel Video 4");
13285 caps = gst_caps_new_simple ("video/x-indeo",
13286 "indeoversion", G_TYPE_INT, 4, NULL);
13290 case GST_MAKE_FOURCC ('d', 'v', 's', 'd'):
13291 case GST_MAKE_FOURCC ('D', 'V', 'S', 'D'):
13292 case GST_MAKE_FOURCC ('d', 'v', 'c', 's'):
13293 case GST_MAKE_FOURCC ('D', 'V', 'C', 'S'):
13294 case GST_MAKE_FOURCC ('d', 'v', '2', '5'):
13295 case GST_MAKE_FOURCC ('d', 'v', 'p', 'p'):
13296 _codec ("DV Video");
13297 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 25,
13298 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13300 case FOURCC_dv5n: /* DVCPRO50 NTSC */
13301 case FOURCC_dv5p: /* DVCPRO50 PAL */
13302 _codec ("DVCPro50 Video");
13303 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 50,
13304 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13306 case GST_MAKE_FOURCC ('d', 'v', 'h', '5'): /* DVCPRO HD 50i produced by FCP */
13307 case GST_MAKE_FOURCC ('d', 'v', 'h', '6'): /* DVCPRO HD 60i produced by FCP */
13308 _codec ("DVCProHD Video");
13309 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 100,
13310 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13312 case GST_MAKE_FOURCC ('s', 'm', 'c', ' '):
13313 _codec ("Apple Graphics (SMC)");
13314 caps = gst_caps_new_empty_simple ("video/x-smc");
13316 case GST_MAKE_FOURCC ('V', 'P', '3', '1'):
13318 caps = gst_caps_new_empty_simple ("video/x-vp3");
13320 case GST_MAKE_FOURCC ('V', 'P', '6', 'F'):
13321 _codec ("VP6 Flash");
13322 caps = gst_caps_new_empty_simple ("video/x-vp6-flash");
13326 caps = gst_caps_new_empty_simple ("video/x-theora");
13327 /* theora uses one byte of padding in the data stream because it does not
13328 * allow 0 sized packets while theora does */
13329 stream->padding = 1;
13333 caps = gst_caps_new_empty_simple ("video/x-dirac");
13335 case GST_MAKE_FOURCC ('t', 'i', 'f', 'f'):
13336 _codec ("TIFF still images");
13337 caps = gst_caps_new_empty_simple ("image/tiff");
13339 case GST_MAKE_FOURCC ('i', 'c', 'o', 'd'):
13340 _codec ("Apple Intermediate Codec");
13341 caps = gst_caps_from_string ("video/x-apple-intermediate-codec");
13343 case GST_MAKE_FOURCC ('A', 'V', 'd', 'n'):
13344 _codec ("AVID DNxHD");
13345 caps = gst_caps_from_string ("video/x-dnxhd");
13348 _codec ("On2 VP8");
13349 caps = gst_caps_from_string ("video/x-vp8");
13352 _codec ("Apple ProRes LT");
13354 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "lt",
13358 _codec ("Apple ProRes HQ");
13360 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "hq",
13364 _codec ("Apple ProRes");
13366 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
13370 _codec ("Apple ProRes Proxy");
13372 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
13376 _codec ("Apple ProRes 4444");
13378 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
13382 _codec ("Apple ProRes 4444 XQ");
13384 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
13390 caps = gst_caps_new_simple ("video/x-wmv",
13391 "wmvversion", G_TYPE_INT, 3, "format", G_TYPE_STRING, "WVC1", NULL);
13393 case GST_MAKE_FOURCC ('k', 'p', 'c', 'd'):
13396 char *s, fourstr[5];
13398 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
13399 s = g_strdup_printf ("video/x-gst-fourcc-%s", g_strstrip (fourstr));
13400 caps = gst_caps_new_empty_simple (s);
13406 if (format != GST_VIDEO_FORMAT_UNKNOWN) {
13409 gst_video_info_init (&info);
13410 gst_video_info_set_format (&info, format, stream->width, stream->height);
13412 caps = gst_video_info_to_caps (&info);
13413 *codec_name = gst_pb_utils_get_codec_description (caps);
13415 /* enable clipping for raw video streams */
13416 stream->need_clip = TRUE;
13423 qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
13424 guint32 fourcc, const guint8 * data, int len, gchar ** codec_name)
13427 const GstStructure *s;
13430 GstAudioFormat format = 0;
13433 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
13435 depth = stream->bytes_per_packet * 8;
13438 case GST_MAKE_FOURCC ('N', 'O', 'N', 'E'):
13440 /* 8-bit audio is unsigned */
13442 format = GST_AUDIO_FORMAT_U8;
13443 /* otherwise it's signed and big-endian just like 'twos' */
13445 endian = G_BIG_ENDIAN;
13452 endian = G_LITTLE_ENDIAN;
13455 format = gst_audio_format_build_integer (TRUE, endian, depth, depth);
13457 str = g_strdup_printf ("Raw %d-bit PCM audio", depth);
13461 caps = gst_caps_new_simple ("audio/x-raw",
13462 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
13463 "layout", G_TYPE_STRING, "interleaved", NULL);
13466 case GST_MAKE_FOURCC ('f', 'l', '6', '4'):
13467 _codec ("Raw 64-bit floating-point audio");
13468 caps = gst_caps_new_simple ("audio/x-raw",
13469 "format", G_TYPE_STRING, "F64BE",
13470 "layout", G_TYPE_STRING, "interleaved", NULL);
13472 case GST_MAKE_FOURCC ('f', 'l', '3', '2'):
13473 _codec ("Raw 32-bit floating-point audio");
13474 caps = gst_caps_new_simple ("audio/x-raw",
13475 "format", G_TYPE_STRING, "F32BE",
13476 "layout", G_TYPE_STRING, "interleaved", NULL);
13479 _codec ("Raw 24-bit PCM audio");
13480 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
13482 caps = gst_caps_new_simple ("audio/x-raw",
13483 "format", G_TYPE_STRING, "S24BE",
13484 "layout", G_TYPE_STRING, "interleaved", NULL);
13486 case GST_MAKE_FOURCC ('i', 'n', '3', '2'):
13487 _codec ("Raw 32-bit PCM audio");
13488 caps = gst_caps_new_simple ("audio/x-raw",
13489 "format", G_TYPE_STRING, "S32BE",
13490 "layout", G_TYPE_STRING, "interleaved", NULL);
13493 _codec ("Mu-law audio");
13494 caps = gst_caps_new_empty_simple ("audio/x-mulaw");
13497 _codec ("A-law audio");
13498 caps = gst_caps_new_empty_simple ("audio/x-alaw");
13502 _codec ("Microsoft ADPCM");
13503 /* Microsoft ADPCM-ACM code 2 */
13504 caps = gst_caps_new_simple ("audio/x-adpcm",
13505 "layout", G_TYPE_STRING, "microsoft", NULL);
13509 _codec ("DVI/IMA ADPCM");
13510 caps = gst_caps_new_simple ("audio/x-adpcm",
13511 "layout", G_TYPE_STRING, "dvi", NULL);
13515 _codec ("DVI/Intel IMA ADPCM");
13516 /* FIXME DVI/Intel IMA ADPCM/ACM code 17 */
13517 caps = gst_caps_new_simple ("audio/x-adpcm",
13518 "layout", G_TYPE_STRING, "quicktime", NULL);
13522 /* MPEG layer 3, CBR only (pre QT4.1) */
13524 _codec ("MPEG-1 layer 3");
13525 /* MPEG layer 3, CBR & VBR (QT4.1 and later) */
13526 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 3,
13527 "mpegversion", G_TYPE_INT, 1, NULL);
13530 case GST_MAKE_FOURCC ('e', 'c', '-', '3'):
13531 _codec ("EAC-3 audio");
13532 caps = gst_caps_new_simple ("audio/x-eac3",
13533 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
13534 stream->sampled = TRUE;
13536 case GST_MAKE_FOURCC ('s', 'a', 'c', '3'): // Nero Recode
13538 _codec ("AC-3 audio");
13539 caps = gst_caps_new_simple ("audio/x-ac3",
13540 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
13541 stream->sampled = TRUE;
13543 case GST_MAKE_FOURCC ('d', 't', 's', 'c'):
13544 case GST_MAKE_FOURCC ('D', 'T', 'S', ' '):
13545 _codec ("DTS audio");
13546 caps = gst_caps_new_simple ("audio/x-dts",
13547 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
13548 stream->sampled = TRUE;
13550 case GST_MAKE_FOURCC ('d', 't', 's', 'h'): // DTS-HD
13551 case GST_MAKE_FOURCC ('d', 't', 's', 'l'): // DTS-HD Lossless
13552 _codec ("DTS-HD audio");
13553 caps = gst_caps_new_simple ("audio/x-dts",
13554 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
13555 stream->sampled = TRUE;
13559 caps = gst_caps_new_simple ("audio/x-mace",
13560 "maceversion", G_TYPE_INT, 3, NULL);
13564 caps = gst_caps_new_simple ("audio/x-mace",
13565 "maceversion", G_TYPE_INT, 6, NULL);
13567 case GST_MAKE_FOURCC ('O', 'g', 'g', 'V'):
13569 caps = gst_caps_new_empty_simple ("application/ogg");
13571 case GST_MAKE_FOURCC ('d', 'v', 'c', 'a'):
13572 _codec ("DV audio");
13573 caps = gst_caps_new_empty_simple ("audio/x-dv");
13576 _codec ("MPEG-4 AAC audio");
13577 caps = gst_caps_new_simple ("audio/mpeg",
13578 "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE,
13579 "stream-format", G_TYPE_STRING, "raw", NULL);
13581 case GST_MAKE_FOURCC ('Q', 'D', 'M', 'C'):
13582 _codec ("QDesign Music");
13583 caps = gst_caps_new_empty_simple ("audio/x-qdm");
13586 _codec ("QDesign Music v.2");
13587 /* FIXME: QDesign music version 2 (no constant) */
13588 if (FALSE && data) {
13589 caps = gst_caps_new_simple ("audio/x-qdm2",
13590 "framesize", G_TYPE_INT, QT_UINT32 (data + 52),
13591 "bitrate", G_TYPE_INT, QT_UINT32 (data + 40),
13592 "blocksize", G_TYPE_INT, QT_UINT32 (data + 44), NULL);
13594 caps = gst_caps_new_empty_simple ("audio/x-qdm2");
13598 _codec ("GSM audio");
13599 caps = gst_caps_new_empty_simple ("audio/x-gsm");
13602 _codec ("AMR audio");
13603 caps = gst_caps_new_empty_simple ("audio/AMR");
13606 _codec ("AMR-WB audio");
13607 caps = gst_caps_new_empty_simple ("audio/AMR-WB");
13610 _codec ("Quicktime IMA ADPCM");
13611 caps = gst_caps_new_simple ("audio/x-adpcm",
13612 "layout", G_TYPE_STRING, "quicktime", NULL);
13615 _codec ("Apple lossless audio");
13616 caps = gst_caps_new_empty_simple ("audio/x-alac");
13618 case GST_MAKE_FOURCC ('Q', 'c', 'l', 'p'):
13619 _codec ("QualComm PureVoice");
13620 caps = gst_caps_from_string ("audio/qcelp");
13625 caps = gst_caps_new_empty_simple ("audio/x-wma");
13629 caps = gst_caps_new_empty_simple ("audio/x-opus");
13631 case GST_MAKE_FOURCC ('l', 'p', 'c', 'm'):
13636 GstAudioFormat format;
13639 FLAG_IS_FLOAT = 0x1,
13640 FLAG_IS_BIG_ENDIAN = 0x2,
13641 FLAG_IS_SIGNED = 0x4,
13642 FLAG_IS_PACKED = 0x8,
13643 FLAG_IS_ALIGNED_HIGH = 0x10,
13644 FLAG_IS_NON_INTERLEAVED = 0x20
13646 _codec ("Raw LPCM audio");
13648 if (data && len >= 56) {
13649 depth = QT_UINT32 (data + 40);
13650 flags = QT_UINT32 (data + 44);
13651 width = QT_UINT32 (data + 48) * 8 / stream->n_channels;
13653 if ((flags & FLAG_IS_FLOAT) == 0) {
13658 format = gst_audio_format_build_integer ((flags & FLAG_IS_SIGNED) ?
13659 TRUE : FALSE, (flags & FLAG_IS_BIG_ENDIAN) ?
13660 G_BIG_ENDIAN : G_LITTLE_ENDIAN, width, depth);
13661 caps = gst_caps_new_simple ("audio/x-raw",
13662 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
13663 "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
13664 "non-interleaved" : "interleaved", NULL);
13669 if (flags & FLAG_IS_BIG_ENDIAN)
13670 format = GST_AUDIO_FORMAT_F64BE;
13672 format = GST_AUDIO_FORMAT_F64LE;
13674 if (flags & FLAG_IS_BIG_ENDIAN)
13675 format = GST_AUDIO_FORMAT_F32BE;
13677 format = GST_AUDIO_FORMAT_F32LE;
13679 caps = gst_caps_new_simple ("audio/x-raw",
13680 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
13681 "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
13682 "non-interleaved" : "interleaved", NULL);
13686 case GST_MAKE_FOURCC ('q', 't', 'v', 'r'):
13690 char *s, fourstr[5];
13692 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
13693 s = g_strdup_printf ("audio/x-gst-fourcc-%s", g_strstrip (fourstr));
13694 caps = gst_caps_new_empty_simple (s);
13701 GstCaps *templ_caps =
13702 gst_static_pad_template_get_caps (&gst_qtdemux_audiosrc_template);
13703 GstCaps *intersection = gst_caps_intersect (caps, templ_caps);
13704 gst_caps_unref (caps);
13705 gst_caps_unref (templ_caps);
13706 caps = intersection;
13709 /* enable clipping for raw audio streams */
13710 s = gst_caps_get_structure (caps, 0);
13711 name = gst_structure_get_name (s);
13712 if (g_str_has_prefix (name, "audio/x-raw")) {
13713 stream->need_clip = TRUE;
13714 stream->max_buffer_size = 4096 * stream->bytes_per_frame;
13715 GST_DEBUG ("setting max buffer size to %d", stream->max_buffer_size);
13721 qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
13722 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
13726 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
13730 _codec ("DVD subtitle");
13731 caps = gst_caps_new_empty_simple ("subpicture/x-dvd");
13732 stream->need_process = TRUE;
13735 _codec ("Quicktime timed text");
13738 _codec ("3GPP timed text");
13740 caps = gst_caps_new_simple ("text/x-raw", "format", G_TYPE_STRING,
13742 /* actual text piece needs to be extracted */
13743 stream->need_process = TRUE;
13746 _codec ("XML subtitles");
13747 caps = gst_caps_new_empty_simple ("application/ttml+xml");
13751 char *s, fourstr[5];
13753 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
13754 s = g_strdup_printf ("text/x-gst-fourcc-%s", g_strstrip (fourstr));
13755 caps = gst_caps_new_empty_simple (s);
13764 qtdemux_generic_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
13765 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
13771 _codec ("MPEG 1 video");
13772 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
13773 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13783 gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux,
13784 const gchar * system_id)
13788 if (!qtdemux->protection_system_ids)
13789 qtdemux->protection_system_ids =
13790 g_ptr_array_new_with_free_func ((GDestroyNotify) g_free);
13791 /* Check whether we already have an entry for this system ID. */
13792 for (i = 0; i < qtdemux->protection_system_ids->len; ++i) {
13793 const gchar *id = g_ptr_array_index (qtdemux->protection_system_ids, i);
13794 if (g_ascii_strcasecmp (system_id, id) == 0) {
13798 GST_DEBUG_OBJECT (qtdemux, "Adding cenc protection system ID %s", system_id);
13799 g_ptr_array_add (qtdemux->protection_system_ids, g_ascii_strdown (system_id,