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.
12 * Copyright (C) <2016> British Broadcasting Corporation
14 * This library is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU Library General Public
16 * License as published by the Free Software Foundation; either
17 * version 2 of the License, or (at your option) any later version.
19 * This library is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * Library General Public License for more details.
24 * You should have received a copy of the GNU Library General Public
25 * License along with this library; if not, write to the
26 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
27 * Boston, MA 02110-1301, USA.
31 * SECTION:element-qtdemux
33 * Demuxes a .mov file into raw or compressed audio and/or video streams.
35 * This element supports both push and pull-based scheduling, depending on the
36 * capabilities of the upstream elements.
39 * <title>Example launch line</title>
41 * 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
42 * ]| Play (parse and decode) a .mov file and try to output it to
43 * an automatically detected soundcard and videosink. If the MOV file contains
44 * compressed audio or video data, this will only work if you have the
45 * right decoder elements/plugins installed.
53 #include "gst/gst-i18n-plugin.h"
55 #include <glib/gprintf.h>
56 #include <gst/tag/tag.h>
57 #include <gst/audio/audio.h>
58 #include <gst/video/video.h>
60 #include "qtatomparser.h"
61 #include "qtdemux_types.h"
62 #include "qtdemux_dump.h"
64 #include "descriptors.h"
65 #include "qtdemux_lang.h"
67 #include "qtpalette.h"
69 #include "gst/riff/riff-media.h"
70 #include "gst/riff/riff-read.h"
72 #include <gst/pbutils/pbutils.h>
79 #include <gst/math-compat.h>
85 /* max. size considered 'sane' for non-mdat atoms */
86 #define QTDEMUX_MAX_ATOM_SIZE (25*1024*1024)
88 /* if the sample index is larger than this, something is likely wrong */
89 #define QTDEMUX_MAX_SAMPLE_INDEX_SIZE (50*1024*1024)
91 /* For converting qt creation times to unix epoch times */
92 #define QTDEMUX_SECONDS_PER_DAY (60 * 60 * 24)
93 #define QTDEMUX_LEAP_YEARS_FROM_1904_TO_1970 17
94 #define QTDEMUX_SECONDS_FROM_1904_TO_1970 (((1970 - 1904) * (guint64) 365 + \
95 QTDEMUX_LEAP_YEARS_FROM_1904_TO_1970) * QTDEMUX_SECONDS_PER_DAY)
97 #define STREAM_IS_EOS(s) (s->time_position == GST_CLOCK_TIME_NONE)
99 #define ABSDIFF(x, y) ( (x) > (y) ? ((x) - (y)) : ((y) - (x)) )
101 GST_DEBUG_CATEGORY (qtdemux_debug);
103 typedef struct _QtDemuxSegment QtDemuxSegment;
104 typedef struct _QtDemuxSample QtDemuxSample;
106 typedef struct _QtDemuxCencSampleSetInfo QtDemuxCencSampleSetInfo;
108 struct _QtDemuxSample
111 gint32 pts_offset; /* Add this value to timestamp to get the pts */
113 guint64 timestamp; /* DTS In mov time */
114 guint32 duration; /* In mov time */
115 gboolean keyframe; /* TRUE when this packet is a keyframe */
118 /* Macros for converting to/from timescale */
119 #define QTSTREAMTIME_TO_GSTTIME(stream, value) (gst_util_uint64_scale((value), GST_SECOND, (stream)->timescale))
120 #define GSTTIME_TO_QTSTREAMTIME(stream, value) (gst_util_uint64_scale((value), (stream)->timescale, GST_SECOND))
122 #define QTTIME_TO_GSTTIME(qtdemux, value) (gst_util_uint64_scale((value), GST_SECOND, (qtdemux)->timescale))
123 #define GSTTIME_TO_QTTIME(qtdemux, value) (gst_util_uint64_scale((value), (qtdemux)->timescale, GST_SECOND))
125 /* timestamp is the DTS */
126 #define QTSAMPLE_DTS(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp))
127 /* timestamp + offset + cslg_shift is the outgoing PTS */
128 #define QTSAMPLE_PTS(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp + (stream)->cslg_shift + (sample)->pts_offset))
129 /* timestamp + offset is the PTS used for internal seek calcuations */
130 #define QTSAMPLE_PTS_NO_CSLG(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp + (sample)->pts_offset))
131 /* timestamp + duration - dts is the duration */
132 #define QTSAMPLE_DUR_DTS(stream, sample, dts) (QTSTREAMTIME_TO_GSTTIME ((stream), (sample)->timestamp + (sample)->duration) - (dts))
134 #define QTSAMPLE_KEYFRAME(stream,sample) ((stream)->all_keyframe || (sample)->keyframe)
137 * Quicktime has tracks and segments. A track is a continuous piece of
138 * multimedia content. The track is not always played from start to finish but
139 * instead, pieces of the track are 'cut out' and played in sequence. This is
140 * what the segments do.
142 * Inside the track we have keyframes (K) and delta frames. The track has its
143 * own timing, which starts from 0 and extends to end. The position in the track
144 * is called the media_time.
146 * The segments now describe the pieces that should be played from this track
147 * and are basically tuples of media_time/duration/rate entries. We can have
148 * multiple segments and they are all played after one another. An example:
150 * segment 1: media_time: 1 second, duration: 1 second, rate 1
151 * segment 2: media_time: 3 second, duration: 2 second, rate 2
153 * To correctly play back this track, one must play: 1 second of media starting
154 * from media_time 1 followed by 2 seconds of media starting from media_time 3
157 * Each of the segments will be played at a specific time, the first segment at
158 * time 0, the second one after the duration of the first one, etc.. Note that
159 * the time in resulting playback is not identical to the media_time of the
162 * Visually, assuming the track has 4 second of media_time:
165 * .-----------------------------------------------------------.
166 * track: | K.....K.........K........K.......K.......K...........K... |
167 * '-----------------------------------------------------------'
169 * .------------^ ^ .----------^ ^
170 * / .-------------' / .------------------'
172 * .--------------. .--------------.
173 * | segment 1 | | segment 2 |
174 * '--------------' '--------------'
176 * The challenge here is to cut out the right pieces of the track for each of
177 * the playback segments. This fortunately can easily be done with the SEGMENT
178 * events of GStreamer.
180 * For playback of segment 1, we need to provide the decoder with the keyframe
181 * (a), in the above figure, but we must instruct it only to output the decoded
182 * data between second 1 and 2. We do this with a SEGMENT event for 1 to 2, time
183 * position set to the time of the segment: 0.
185 * We then proceed to push data from keyframe (a) to frame (b). The decoder
186 * decodes but clips all before media_time 1.
188 * After finishing a segment, we push out a new SEGMENT event with the clipping
189 * boundaries of the new data.
191 * This is a good usecase for the GStreamer accumulated SEGMENT events.
194 struct _QtDemuxSegment
196 /* global time and duration, all gst time */
198 GstClockTime stop_time;
199 GstClockTime duration;
200 /* media time of trak, all gst time */
201 GstClockTime media_start;
202 GstClockTime media_stop;
204 /* Media start time in trak timescale units */
205 guint32 trak_media_start;
208 #define QTSEGMENT_IS_EMPTY(s) ((s)->media_start == GST_CLOCK_TIME_NONE)
210 /* Used with fragmented MP4 files (mfra atom) */
215 } QtDemuxRandomAccessEntry;
217 struct _QtDemuxStream
227 gboolean new_caps; /* If TRUE, caps need to be generated (by
228 * calling _configure_stream()) This happens
229 * for MSS and fragmented streams */
231 gboolean new_stream; /* signals that a stream_start is required */
232 gboolean on_keyframe; /* if this stream last pushed buffer was a
233 * keyframe. This is important to identify
234 * where to stop pushing buffers after a
235 * segment stop time */
237 /* if the stream has a redirect URI in its headers, we store it here */
244 guint64 duration; /* in timescale units */
248 gchar lang_id[4]; /* ISO 639-2T language code */
252 QtDemuxSample *samples;
253 gboolean all_keyframe; /* TRUE when all samples are keyframes (no stss) */
254 guint32 first_duration; /* duration in timescale of first sample, used for figuring out
256 guint32 n_samples_moof; /* sample count in a moof */
257 guint64 duration_moof; /* duration in timescale of a moof, used for figure out
258 * the framerate of fragmented format stream */
259 guint64 duration_last_moof;
261 guint32 offset_in_sample; /* Offset in the current sample, used for
262 * streams which have got exceedingly big
263 * sample size (such as 24s of raw audio).
264 * Only used when max_buffer_size is non-NULL */
265 guint32 max_buffer_size; /* Maximum allowed size for output buffers.
266 * Currently only set for raw audio streams*/
268 /* if we use chunks or samples */
280 /* Numerator/denominator framerate */
283 GstVideoColorimetry colorimetry;
284 guint16 bits_per_sample;
285 guint16 color_table_id;
286 GstMemory *rgb8_palette;
287 guint interlace_mode;
293 guint samples_per_packet;
294 guint samples_per_frame;
295 guint bytes_per_packet;
296 guint bytes_per_sample;
297 guint bytes_per_frame;
301 gboolean use_allocator;
302 GstAllocator *allocator;
303 GstAllocationParams params;
307 /* when a discontinuity is pending */
310 /* list of buffers to push first */
313 /* if we need to clip this buffer. This is only needed for uncompressed
317 /* buffer needs some custom processing, e.g. subtitles */
318 gboolean need_process;
320 /* current position */
321 guint32 segment_index;
322 guint32 sample_index;
323 GstClockTime time_position; /* in gst time */
324 guint64 accumulated_base;
326 /* the Gst segment we are processing out, used for clipping */
329 /* quicktime segments */
331 QtDemuxSegment *segments;
332 gboolean dummy_segment;
337 GstTagList *pending_tags;
338 gboolean send_global_tags;
340 GstEvent *pending_event;
350 gboolean chunks_are_samples; /* TRUE means treat chunks as samples */
354 GstByteReader co_chunk;
356 guint32 current_chunk;
358 guint32 samples_per_chunk;
359 guint32 stco_sample_index;
361 guint32 sample_size; /* 0 means variable sizes are stored in stsz */
364 guint32 n_samples_per_chunk;
365 guint32 stsc_chunk_index;
366 guint32 stsc_sample_index;
367 guint64 chunk_offset;
370 guint32 stts_samples;
371 guint32 n_sample_times;
372 guint32 stts_sample_index;
374 guint32 stts_duration;
376 gboolean stss_present;
377 guint32 n_sample_syncs;
380 gboolean stps_present;
381 guint32 n_sample_partial_syncs;
383 QtDemuxRandomAccessEntry *ra_entries;
386 const QtDemuxRandomAccessEntry *pending_seek;
389 gboolean ctts_present;
390 guint32 n_composition_times;
392 guint32 ctts_sample_index;
400 gboolean parsed_trex;
401 guint32 def_sample_duration;
402 guint32 def_sample_size;
403 guint32 def_sample_flags;
407 /* stereoscopic video streams */
408 GstVideoMultiviewMode multiview_mode;
409 GstVideoMultiviewFlags multiview_flags;
411 /* protected streams */
413 guint32 protection_scheme_type;
414 guint32 protection_scheme_version;
415 gpointer protection_scheme_info; /* specific to the protection scheme */
416 GQueue protection_scheme_event_queue;
419 /* Contains properties and cryptographic info for a set of samples from a
420 * track protected using Common Encryption (cenc) */
421 struct _QtDemuxCencSampleSetInfo
423 GstStructure *default_properties;
425 /* @crypto_info holds one GstStructure per sample */
426 GPtrArray *crypto_info;
430 qt_demux_state_string (enum QtDemuxState state)
433 case QTDEMUX_STATE_INITIAL:
435 case QTDEMUX_STATE_HEADER:
437 case QTDEMUX_STATE_MOVIE:
439 case QTDEMUX_STATE_BUFFER_MDAT:
440 return "<BUFFER_MDAT>";
446 static GNode *qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc);
447 static GNode *qtdemux_tree_get_child_by_type_full (GNode * node,
448 guint32 fourcc, GstByteReader * parser);
449 static GNode *qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc);
450 static GNode *qtdemux_tree_get_sibling_by_type_full (GNode * node,
451 guint32 fourcc, GstByteReader * parser);
453 static GstFlowReturn qtdemux_add_fragmented_samples (GstQTDemux * qtdemux);
455 static GstStaticPadTemplate gst_qtdemux_sink_template =
456 GST_STATIC_PAD_TEMPLATE ("sink",
459 GST_STATIC_CAPS ("video/quicktime; video/mj2; audio/x-m4a; "
463 static GstStaticPadTemplate gst_qtdemux_videosrc_template =
464 GST_STATIC_PAD_TEMPLATE ("video_%u",
467 GST_STATIC_CAPS_ANY);
469 static GstStaticPadTemplate gst_qtdemux_audiosrc_template =
470 GST_STATIC_PAD_TEMPLATE ("audio_%u",
473 GST_STATIC_CAPS_ANY);
475 static GstStaticPadTemplate gst_qtdemux_subsrc_template =
476 GST_STATIC_PAD_TEMPLATE ("subtitle_%u",
479 GST_STATIC_CAPS_ANY);
481 #define gst_qtdemux_parent_class parent_class
482 G_DEFINE_TYPE (GstQTDemux, gst_qtdemux, GST_TYPE_ELEMENT);
484 static void gst_qtdemux_dispose (GObject * object);
487 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
488 GstClockTime media_time);
490 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
491 QtDemuxStream * str, gint64 media_offset);
494 static void gst_qtdemux_set_index (GstElement * element, GstIndex * index);
495 static GstIndex *gst_qtdemux_get_index (GstElement * element);
497 static GstStateChangeReturn gst_qtdemux_change_state (GstElement * element,
498 GstStateChange transition);
499 static gboolean qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent);
500 static gboolean qtdemux_sink_activate_mode (GstPad * sinkpad,
501 GstObject * parent, GstPadMode mode, gboolean active);
503 static void gst_qtdemux_loop (GstPad * pad);
504 static GstFlowReturn gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent,
506 static gboolean gst_qtdemux_handle_sink_event (GstPad * pad, GstObject * parent,
508 static gboolean gst_qtdemux_setcaps (GstQTDemux * qtdemux, GstCaps * caps);
509 static gboolean gst_qtdemux_configure_stream (GstQTDemux * qtdemux,
510 QtDemuxStream * stream);
511 static GstFlowReturn gst_qtdemux_process_adapter (GstQTDemux * demux,
514 static gboolean qtdemux_parse_moov (GstQTDemux * qtdemux,
515 const guint8 * buffer, guint length);
516 static gboolean qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node,
517 const guint8 * buffer, guint length);
518 static gboolean qtdemux_parse_tree (GstQTDemux * qtdemux);
519 static void qtdemux_parse_udta (GstQTDemux * qtdemux, GstTagList * taglist,
522 static void gst_qtdemux_handle_esds (GstQTDemux * qtdemux,
523 QtDemuxStream * stream, GNode * esds, GstTagList * list);
524 static GstCaps *qtdemux_video_caps (GstQTDemux * qtdemux,
525 QtDemuxStream * stream, guint32 fourcc, const guint8 * stsd_data,
526 gchar ** codec_name);
527 static GstCaps *qtdemux_audio_caps (GstQTDemux * qtdemux,
528 QtDemuxStream * stream, guint32 fourcc, const guint8 * data, int len,
529 gchar ** codec_name);
530 static GstCaps *qtdemux_sub_caps (GstQTDemux * qtdemux,
531 QtDemuxStream * stream, guint32 fourcc, const guint8 * data,
532 gchar ** codec_name);
533 static GstCaps *qtdemux_generic_caps (GstQTDemux * qtdemux,
534 QtDemuxStream * stream, guint32 fourcc, const guint8 * stsd_data,
535 gchar ** codec_name);
537 static gboolean qtdemux_parse_samples (GstQTDemux * qtdemux,
538 QtDemuxStream * stream, guint32 n);
539 static GstFlowReturn qtdemux_expose_streams (GstQTDemux * qtdemux);
540 static void gst_qtdemux_stream_free (GstQTDemux * qtdemux,
541 QtDemuxStream * stream);
542 static void gst_qtdemux_stream_clear (GstQTDemux * qtdemux,
543 QtDemuxStream * stream);
544 static void gst_qtdemux_remove_stream (GstQTDemux * qtdemux, int index);
545 static GstFlowReturn qtdemux_prepare_streams (GstQTDemux * qtdemux);
546 static void qtdemux_do_allocation (GstQTDemux * qtdemux,
547 QtDemuxStream * stream);
548 static gboolean gst_qtdemux_activate_segment (GstQTDemux * qtdemux,
549 QtDemuxStream * stream, guint32 seg_idx, GstClockTime offset);
550 static gboolean gst_qtdemux_stream_update_segment (GstQTDemux * qtdemux,
551 QtDemuxStream * stream, gint seg_idx, GstClockTime offset,
552 GstClockTime * _start, GstClockTime * _stop);
553 static void gst_qtdemux_send_gap_for_segment (GstQTDemux * demux,
554 QtDemuxStream * stream, gint segment_index, GstClockTime pos);
556 static gboolean qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux);
557 static void check_update_duration (GstQTDemux * qtdemux, GstClockTime duration);
559 static gchar *qtdemux_uuid_bytes_to_string (gconstpointer uuid_bytes);
561 static GstStructure *qtdemux_get_cenc_sample_properties (GstQTDemux * qtdemux,
562 QtDemuxStream * stream, guint sample_index);
563 static void gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux,
565 static void qtdemux_gst_structure_free (GstStructure * gststructure);
568 gst_qtdemux_class_init (GstQTDemuxClass * klass)
570 GObjectClass *gobject_class;
571 GstElementClass *gstelement_class;
573 gobject_class = (GObjectClass *) klass;
574 gstelement_class = (GstElementClass *) klass;
576 parent_class = g_type_class_peek_parent (klass);
578 gobject_class->dispose = gst_qtdemux_dispose;
580 gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_qtdemux_change_state);
582 gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_qtdemux_set_index);
583 gstelement_class->get_index = GST_DEBUG_FUNCPTR (gst_qtdemux_get_index);
586 gst_tag_register_musicbrainz_tags ();
588 gst_element_class_add_static_pad_template (gstelement_class,
589 &gst_qtdemux_sink_template);
590 gst_element_class_add_static_pad_template (gstelement_class,
591 &gst_qtdemux_videosrc_template);
592 gst_element_class_add_static_pad_template (gstelement_class,
593 &gst_qtdemux_audiosrc_template);
594 gst_element_class_add_static_pad_template (gstelement_class,
595 &gst_qtdemux_subsrc_template);
596 gst_element_class_set_static_metadata (gstelement_class, "QuickTime demuxer",
598 "Demultiplex a QuickTime file into audio and video streams",
599 "David Schleef <ds@schleef.org>, Wim Taymans <wim@fluendo.com>");
601 GST_DEBUG_CATEGORY_INIT (qtdemux_debug, "qtdemux", 0, "qtdemux plugin");
606 gst_qtdemux_init (GstQTDemux * qtdemux)
609 gst_pad_new_from_static_template (&gst_qtdemux_sink_template, "sink");
610 gst_pad_set_activate_function (qtdemux->sinkpad, qtdemux_sink_activate);
611 gst_pad_set_activatemode_function (qtdemux->sinkpad,
612 qtdemux_sink_activate_mode);
613 gst_pad_set_chain_function (qtdemux->sinkpad, gst_qtdemux_chain);
614 gst_pad_set_event_function (qtdemux->sinkpad, gst_qtdemux_handle_sink_event);
615 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), qtdemux->sinkpad);
617 qtdemux->state = QTDEMUX_STATE_INITIAL;
618 qtdemux->pullbased = FALSE;
619 qtdemux->posted_redirect = FALSE;
620 qtdemux->neededbytes = 16;
622 qtdemux->adapter = gst_adapter_new ();
624 qtdemux->first_mdat = -1;
625 qtdemux->got_moov = FALSE;
626 qtdemux->mdatoffset = -1;
627 qtdemux->mdatbuffer = NULL;
628 qtdemux->restoredata_buffer = NULL;
629 qtdemux->restoredata_offset = -1;
630 qtdemux->fragment_start = -1;
631 qtdemux->fragment_start_offset = -1;
632 qtdemux->media_caps = NULL;
633 qtdemux->exposed = FALSE;
634 qtdemux->mss_mode = FALSE;
635 qtdemux->pending_newsegment = NULL;
636 qtdemux->upstream_format_is_time = FALSE;
637 qtdemux->have_group_id = FALSE;
638 qtdemux->group_id = G_MAXUINT;
639 qtdemux->cenc_aux_info_offset = 0;
640 qtdemux->cenc_aux_info_sizes = NULL;
641 qtdemux->cenc_aux_sample_count = 0;
642 qtdemux->protection_system_ids = NULL;
643 g_queue_init (&qtdemux->protection_event_queue);
644 gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
645 qtdemux->flowcombiner = gst_flow_combiner_new ();
647 GST_OBJECT_FLAG_SET (qtdemux, GST_ELEMENT_FLAG_INDEXABLE);
651 gst_qtdemux_dispose (GObject * object)
653 GstQTDemux *qtdemux = GST_QTDEMUX (object);
655 if (qtdemux->adapter) {
656 g_object_unref (G_OBJECT (qtdemux->adapter));
657 qtdemux->adapter = NULL;
659 gst_flow_combiner_free (qtdemux->flowcombiner);
660 g_queue_foreach (&qtdemux->protection_event_queue, (GFunc) gst_event_unref,
662 g_queue_clear (&qtdemux->protection_event_queue);
664 g_free (qtdemux->cenc_aux_info_sizes);
665 qtdemux->cenc_aux_info_sizes = NULL;
667 G_OBJECT_CLASS (parent_class)->dispose (object);
671 gst_qtdemux_post_no_playable_stream_error (GstQTDemux * qtdemux)
673 if (qtdemux->posted_redirect) {
674 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
675 (_("This file contains no playable streams.")),
676 ("no known streams found, a redirect message has been posted"));
678 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
679 (_("This file contains no playable streams.")),
680 ("no known streams found"));
685 _gst_buffer_new_wrapped (gpointer mem, gsize size, GFreeFunc free_func)
687 return gst_buffer_new_wrapped_full (free_func ? 0 : GST_MEMORY_FLAG_READONLY,
688 mem, size, 0, size, mem, free_func);
692 gst_qtdemux_pull_atom (GstQTDemux * qtdemux, guint64 offset, guint64 size,
699 if (G_UNLIKELY (size == 0)) {
701 GstBuffer *tmp = NULL;
703 ret = gst_qtdemux_pull_atom (qtdemux, offset, sizeof (guint32), &tmp);
704 if (ret != GST_FLOW_OK)
707 gst_buffer_map (tmp, &map, GST_MAP_READ);
708 size = QT_UINT32 (map.data);
709 GST_DEBUG_OBJECT (qtdemux, "size 0x%08" G_GINT64_MODIFIER "x", size);
711 gst_buffer_unmap (tmp, &map);
712 gst_buffer_unref (tmp);
715 /* Sanity check: catch bogus sizes (fuzzed/broken files) */
716 if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
717 if (qtdemux->state != QTDEMUX_STATE_MOVIE && qtdemux->got_moov) {
718 /* we're pulling header but already got most interesting bits,
719 * so never mind the rest (e.g. tags) (that much) */
720 GST_WARNING_OBJECT (qtdemux, "atom has bogus size %" G_GUINT64_FORMAT,
724 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
725 (_("This file is invalid and cannot be played.")),
726 ("atom has bogus size %" G_GUINT64_FORMAT, size));
727 return GST_FLOW_ERROR;
731 flow = gst_pad_pull_range (qtdemux->sinkpad, offset, size, buf);
733 if (G_UNLIKELY (flow != GST_FLOW_OK))
736 bsize = gst_buffer_get_size (*buf);
737 /* Catch short reads - we don't want any partial atoms */
738 if (G_UNLIKELY (bsize < size)) {
739 GST_WARNING_OBJECT (qtdemux,
740 "short read: %" G_GSIZE_FORMAT " < %" G_GUINT64_FORMAT, bsize, size);
741 gst_buffer_unref (*buf);
751 gst_qtdemux_src_convert (GstQTDemux * qtdemux, GstPad * pad,
752 GstFormat src_format, gint64 src_value, GstFormat dest_format,
756 QtDemuxStream *stream = gst_pad_get_element_private (pad);
759 if (stream->subtype != FOURCC_vide) {
764 switch (src_format) {
765 case GST_FORMAT_TIME:
766 switch (dest_format) {
767 case GST_FORMAT_BYTES:{
768 index = gst_qtdemux_find_index_linear (qtdemux, stream, src_value);
774 *dest_value = stream->samples[index].offset;
776 GST_DEBUG_OBJECT (qtdemux, "Format Conversion Time->Offset :%"
777 GST_TIME_FORMAT "->%" G_GUINT64_FORMAT,
778 GST_TIME_ARGS (src_value), *dest_value);
786 case GST_FORMAT_BYTES:
787 switch (dest_format) {
788 case GST_FORMAT_TIME:{
790 gst_qtdemux_find_index_for_given_media_offset_linear (qtdemux,
799 QTSTREAMTIME_TO_GSTTIME (stream,
800 stream->samples[index].timestamp);
801 GST_DEBUG_OBJECT (qtdemux,
802 "Format Conversion Offset->Time :%" G_GUINT64_FORMAT "->%"
803 GST_TIME_FORMAT, src_value, GST_TIME_ARGS (*dest_value));
822 gst_qtdemux_get_duration (GstQTDemux * qtdemux, GstClockTime * duration)
824 gboolean res = FALSE;
826 *duration = GST_CLOCK_TIME_NONE;
828 if (qtdemux->duration != 0 &&
829 qtdemux->duration != G_MAXINT64 && qtdemux->timescale != 0) {
830 *duration = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
833 *duration = GST_CLOCK_TIME_NONE;
840 gst_qtdemux_handle_src_query (GstPad * pad, GstObject * parent,
843 gboolean res = FALSE;
844 GstQTDemux *qtdemux = GST_QTDEMUX (parent);
846 GST_LOG_OBJECT (pad, "%s query", GST_QUERY_TYPE_NAME (query));
848 switch (GST_QUERY_TYPE (query)) {
849 case GST_QUERY_POSITION:{
852 gst_query_parse_position (query, &fmt, NULL);
853 if (fmt == GST_FORMAT_TIME
854 && GST_CLOCK_TIME_IS_VALID (qtdemux->segment.position)) {
855 gst_query_set_position (query, GST_FORMAT_TIME,
856 qtdemux->segment.position);
861 case GST_QUERY_DURATION:{
864 gst_query_parse_duration (query, &fmt, NULL);
865 if (fmt == GST_FORMAT_TIME) {
866 /* First try to query upstream */
867 res = gst_pad_query_default (pad, parent, query);
869 GstClockTime duration;
870 if (gst_qtdemux_get_duration (qtdemux, &duration) && duration > 0) {
871 gst_query_set_duration (query, GST_FORMAT_TIME, duration);
878 case GST_QUERY_CONVERT:{
879 GstFormat src_fmt, dest_fmt;
880 gint64 src_value, dest_value = 0;
882 gst_query_parse_convert (query, &src_fmt, &src_value, &dest_fmt, NULL);
884 res = gst_qtdemux_src_convert (qtdemux, pad,
885 src_fmt, src_value, dest_fmt, &dest_value);
887 gst_query_set_convert (query, src_fmt, src_value, dest_fmt, dest_value);
892 case GST_QUERY_FORMATS:
893 gst_query_set_formats (query, 2, GST_FORMAT_TIME, GST_FORMAT_BYTES);
896 case GST_QUERY_SEEKING:{
900 /* try upstream first */
901 res = gst_pad_query_default (pad, parent, query);
904 gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
905 if (fmt == GST_FORMAT_TIME) {
906 GstClockTime duration;
908 gst_qtdemux_get_duration (qtdemux, &duration);
910 if (!qtdemux->pullbased) {
913 /* we might be able with help from upstream */
915 q = gst_query_new_seeking (GST_FORMAT_BYTES);
916 if (gst_pad_peer_query (qtdemux->sinkpad, q)) {
917 gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL);
918 GST_LOG_OBJECT (qtdemux, "upstream BYTE seekable %d", seekable);
922 gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0, duration);
928 case GST_QUERY_SEGMENT:
933 format = qtdemux->segment.format;
936 gst_segment_to_stream_time (&qtdemux->segment, format,
937 qtdemux->segment.start);
938 if ((stop = qtdemux->segment.stop) == -1)
939 stop = qtdemux->segment.duration;
941 stop = gst_segment_to_stream_time (&qtdemux->segment, format, stop);
943 gst_query_set_segment (query, qtdemux->segment.rate, format, start, stop);
948 res = gst_pad_query_default (pad, parent, query);
956 gst_qtdemux_push_tags (GstQTDemux * qtdemux, QtDemuxStream * stream)
958 if (G_LIKELY (stream->pad)) {
959 GST_DEBUG_OBJECT (qtdemux, "Checking pad %s:%s for tags",
960 GST_DEBUG_PAD_NAME (stream->pad));
962 if (G_UNLIKELY (stream->pending_tags)) {
963 GST_DEBUG_OBJECT (qtdemux, "Sending tags %" GST_PTR_FORMAT,
964 stream->pending_tags);
965 gst_pad_push_event (stream->pad,
966 gst_event_new_tag (stream->pending_tags));
967 stream->pending_tags = NULL;
970 if (G_UNLIKELY (stream->send_global_tags && qtdemux->tag_list)) {
971 GST_DEBUG_OBJECT (qtdemux, "Sending global tags %" GST_PTR_FORMAT,
973 gst_pad_push_event (stream->pad,
974 gst_event_new_tag (gst_tag_list_ref (qtdemux->tag_list)));
975 stream->send_global_tags = FALSE;
980 /* push event on all source pads; takes ownership of the event */
982 gst_qtdemux_push_event (GstQTDemux * qtdemux, GstEvent * event)
985 gboolean has_valid_stream = FALSE;
986 GstEventType etype = GST_EVENT_TYPE (event);
988 GST_DEBUG_OBJECT (qtdemux, "pushing %s event on all source pads",
989 GST_EVENT_TYPE_NAME (event));
991 for (n = 0; n < qtdemux->n_streams; n++) {
993 QtDemuxStream *stream = qtdemux->streams[n];
994 GST_DEBUG_OBJECT (qtdemux, "pushing on pad %i", n);
996 if ((pad = stream->pad)) {
997 has_valid_stream = TRUE;
999 if (etype == GST_EVENT_EOS) {
1000 /* let's not send twice */
1001 if (stream->sent_eos)
1003 stream->sent_eos = TRUE;
1006 gst_pad_push_event (pad, gst_event_ref (event));
1010 gst_event_unref (event);
1012 /* if it is EOS and there are no pads, post an error */
1013 if (!has_valid_stream && etype == GST_EVENT_EOS) {
1014 gst_qtdemux_post_no_playable_stream_error (qtdemux);
1018 /* push a pending newsegment event, if any from the streaming thread */
1020 gst_qtdemux_push_pending_newsegment (GstQTDemux * qtdemux)
1022 if (qtdemux->pending_newsegment) {
1023 gst_qtdemux_push_event (qtdemux, qtdemux->pending_newsegment);
1024 qtdemux->pending_newsegment = NULL;
1034 find_func (QtDemuxSample * s1, gint64 * media_time, gpointer user_data)
1036 if ((gint64) s1->timestamp + s1->pts_offset > *media_time)
1038 if ((gint64) s1->timestamp + s1->pts_offset == *media_time)
1044 /* find the index of the sample that includes the data for @media_time using a
1045 * binary search. Only to be called in optimized cases of linear search below.
1047 * Returns the index of the sample.
1050 gst_qtdemux_find_index (GstQTDemux * qtdemux, QtDemuxStream * str,
1053 QtDemuxSample *result;
1056 /* convert media_time to mov format */
1058 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
1060 result = gst_util_array_binary_search (str->samples, str->stbl_index + 1,
1061 sizeof (QtDemuxSample), (GCompareDataFunc) find_func,
1062 GST_SEARCH_MODE_BEFORE, &media_time, NULL);
1064 if (G_LIKELY (result))
1065 index = result - str->samples;
1074 /* find the index of the sample that includes the data for @media_offset using a
1077 * Returns the index of the sample.
1080 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
1081 QtDemuxStream * str, gint64 media_offset)
1083 QtDemuxSample *result = str->samples;
1086 if (result == NULL || str->n_samples == 0)
1089 if (media_offset == result->offset)
1093 while (index < str->n_samples - 1) {
1094 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
1097 if (media_offset < result->offset)
1108 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
1113 /* find the index of the sample that includes the data for @media_time using a
1114 * linear search, and keeping in mind that not all samples may have been parsed
1115 * yet. If possible, it will delegate to binary search.
1117 * Returns the index of the sample.
1120 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
1121 GstClockTime media_time)
1125 QtDemuxSample *sample;
1127 /* convert media_time to mov format */
1129 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
1131 sample = str->samples;
1132 if (mov_time == sample->timestamp + sample->pts_offset)
1135 /* use faster search if requested time in already parsed range */
1136 sample = str->samples + str->stbl_index;
1137 if (str->stbl_index >= 0 &&
1138 mov_time <= (sample->timestamp + sample->pts_offset))
1139 return gst_qtdemux_find_index (qtdemux, str, media_time);
1141 while (index < str->n_samples - 1) {
1142 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
1145 sample = str->samples + index + 1;
1146 if (mov_time < (sample->timestamp + sample->pts_offset))
1156 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
1161 /* find the index of the keyframe needed to decode the sample at @index
1162 * of stream @str, or of a subsequent keyframe (depending on @next)
1164 * Returns the index of the keyframe.
1167 gst_qtdemux_find_keyframe (GstQTDemux * qtdemux, QtDemuxStream * str,
1168 guint32 index, gboolean next)
1170 guint32 new_index = index;
1172 if (index >= str->n_samples) {
1173 new_index = str->n_samples;
1177 /* all keyframes, return index */
1178 if (str->all_keyframe) {
1183 /* else search until we have a keyframe */
1184 while (new_index < str->n_samples) {
1185 if (next && !qtdemux_parse_samples (qtdemux, str, new_index))
1188 if (str->samples[new_index].keyframe)
1200 if (new_index == str->n_samples) {
1201 GST_DEBUG_OBJECT (qtdemux, "no next keyframe");
1206 GST_DEBUG_OBJECT (qtdemux, "searching for keyframe index %s index %u "
1207 "gave %u", next ? "after" : "before", index, new_index);
1214 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", new_index);
1219 /* find the segment for @time_position for @stream
1221 * Returns the index of the segment containing @time_position.
1222 * Returns the last segment and sets the @eos variable to TRUE
1223 * if the time is beyond the end. @eos may be NULL
1226 gst_qtdemux_find_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
1227 GstClockTime time_position)
1232 GST_LOG_OBJECT (stream->pad, "finding segment for %" GST_TIME_FORMAT,
1233 GST_TIME_ARGS (time_position));
1236 for (i = 0; i < stream->n_segments; i++) {
1237 QtDemuxSegment *segment = &stream->segments[i];
1239 GST_LOG_OBJECT (stream->pad,
1240 "looking at segment %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT,
1241 GST_TIME_ARGS (segment->time), GST_TIME_ARGS (segment->stop_time));
1243 /* For the last segment we include stop_time in the last segment */
1244 if (i < stream->n_segments - 1) {
1245 if (segment->time <= time_position && time_position < segment->stop_time) {
1246 GST_LOG_OBJECT (stream->pad, "segment %d matches", i);
1251 /* Last segment always matches */
1259 /* move the stream @str to the sample position @index.
1261 * Updates @str->sample_index and marks discontinuity if needed.
1264 gst_qtdemux_move_stream (GstQTDemux * qtdemux, QtDemuxStream * str,
1267 /* no change needed */
1268 if (index == str->sample_index)
1271 GST_DEBUG_OBJECT (qtdemux, "moving to sample %u of %u", index,
1274 /* position changed, we have a discont */
1275 str->sample_index = index;
1276 str->offset_in_sample = 0;
1277 /* Each time we move in the stream we store the position where we are
1279 str->from_sample = index;
1280 str->discont = TRUE;
1284 gst_qtdemux_adjust_seek (GstQTDemux * qtdemux, gint64 desired_time,
1285 gboolean use_sparse, gboolean next, gint64 * key_time, gint64 * key_offset)
1288 gint64 min_byte_offset = -1;
1291 min_offset = desired_time;
1293 /* for each stream, find the index of the sample in the segment
1294 * and move back to the previous keyframe. */
1295 for (n = 0; n < qtdemux->n_streams; n++) {
1299 GstClockTime media_start;
1300 GstClockTime media_time;
1301 GstClockTime seg_time;
1302 QtDemuxSegment *seg;
1303 gboolean empty_segment = FALSE;
1305 str = qtdemux->streams[n];
1307 if (str->sparse && !use_sparse)
1310 seg_idx = gst_qtdemux_find_segment (qtdemux, str, desired_time);
1311 GST_DEBUG_OBJECT (qtdemux, "align segment %d", seg_idx);
1313 /* get segment and time in the segment */
1314 seg = &str->segments[seg_idx];
1315 seg_time = (desired_time - seg->time) * seg->rate;
1317 while (QTSEGMENT_IS_EMPTY (seg)) {
1319 empty_segment = TRUE;
1320 GST_DEBUG_OBJECT (str->pad, "Segment %d is empty, moving to next one",
1323 if (seg_idx == str->n_segments)
1325 seg = &str->segments[seg_idx];
1328 if (seg_idx == str->n_segments) {
1329 /* FIXME track shouldn't have the last segment as empty, but if it
1330 * happens we better handle it */
1334 /* get the media time in the segment */
1335 media_start = seg->media_start + seg_time;
1337 /* get the index of the sample with media time */
1338 index = gst_qtdemux_find_index_linear (qtdemux, str, media_start);
1339 GST_DEBUG_OBJECT (qtdemux, "sample for %" GST_TIME_FORMAT " at %u"
1340 " at offset %" G_GUINT64_FORMAT " (empty segment: %d)",
1341 GST_TIME_ARGS (media_start), index, str->samples[index].offset,
1344 /* shift to next frame if we are looking for next keyframe */
1345 if (next && QTSAMPLE_PTS_NO_CSLG (str, &str->samples[index]) < media_start
1346 && index < str->stbl_index)
1349 if (!empty_segment) {
1350 /* find previous keyframe */
1351 index = gst_qtdemux_find_keyframe (qtdemux, str, index, next);
1353 /* we will settle for one before if none found after */
1354 if (next && index == -1)
1355 index = gst_qtdemux_find_keyframe (qtdemux, str, index, FALSE);
1357 /* Snap to the start ts of the keyframe we found */
1359 /* get timestamp of keyframe */
1360 media_time = QTSAMPLE_PTS_NO_CSLG (str, &str->samples[index]);
1361 GST_DEBUG_OBJECT (qtdemux,
1362 "keyframe at %u with time %" GST_TIME_FORMAT " at offset %"
1363 G_GUINT64_FORMAT, index, GST_TIME_ARGS (media_time),
1364 str->samples[index].offset);
1366 /* keyframes in the segment get a chance to change the
1367 * desired_offset. keyframes out of the segment are
1369 if (media_time >= seg->media_start) {
1370 GstClockTime seg_time;
1372 /* this keyframe is inside the segment, convert back to
1374 seg_time = (media_time - seg->media_start) + seg->time;
1375 if ((!next && (seg_time < min_offset)) ||
1376 (next && (seg_time > min_offset)))
1377 min_offset = seg_time;
1381 if (min_byte_offset < 0 || str->samples[index].offset < min_byte_offset)
1382 min_byte_offset = str->samples[index].offset;
1386 *key_time = min_offset;
1388 *key_offset = min_byte_offset;
1392 gst_qtdemux_convert_seek (GstPad * pad, GstFormat * format,
1393 GstSeekType cur_type, gint64 * cur, GstSeekType stop_type, gint64 * stop)
1397 g_return_val_if_fail (format != NULL, FALSE);
1398 g_return_val_if_fail (cur != NULL, FALSE);
1399 g_return_val_if_fail (stop != NULL, FALSE);
1401 if (*format == GST_FORMAT_TIME)
1405 if (cur_type != GST_SEEK_TYPE_NONE)
1406 res = gst_pad_query_convert (pad, *format, *cur, GST_FORMAT_TIME, cur);
1407 if (res && stop_type != GST_SEEK_TYPE_NONE)
1408 res = gst_pad_query_convert (pad, *format, *stop, GST_FORMAT_TIME, stop);
1411 *format = GST_FORMAT_TIME;
1416 /* perform seek in push based mode:
1417 find BYTE position to move to based on time and delegate to upstream
1420 gst_qtdemux_do_push_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1425 GstSeekType cur_type, stop_type;
1426 gint64 cur, stop, key_cur;
1429 gint64 original_stop;
1432 GST_DEBUG_OBJECT (qtdemux, "doing push-based seek");
1434 gst_event_parse_seek (event, &rate, &format, &flags,
1435 &cur_type, &cur, &stop_type, &stop);
1436 seqnum = gst_event_get_seqnum (event);
1438 /* only forward streaming and seeking is possible */
1440 goto unsupported_seek;
1442 /* convert to TIME if needed and possible */
1443 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1447 /* Upstream seek in bytes will have undefined stop, but qtdemux stores
1448 * the original stop position to use when upstream pushes the new segment
1450 original_stop = stop;
1453 /* find reasonable corresponding BYTE position,
1454 * also try to mind about keyframes, since we can not go back a bit for them
1456 /* determining @next here based on SNAP_BEFORE/SNAP_AFTER should
1457 * mostly just work, but let's not yet boldly go there ... */
1458 gst_qtdemux_adjust_seek (qtdemux, cur, FALSE, FALSE, &key_cur, &byte_cur);
1463 GST_DEBUG_OBJECT (qtdemux, "Pushing BYTE seek rate %g, "
1464 "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, byte_cur,
1467 GST_OBJECT_LOCK (qtdemux);
1468 qtdemux->seek_offset = byte_cur;
1469 if (!(flags & GST_SEEK_FLAG_KEY_UNIT)) {
1470 qtdemux->push_seek_start = cur;
1472 qtdemux->push_seek_start = key_cur;
1475 if (stop_type == GST_SEEK_TYPE_NONE) {
1476 qtdemux->push_seek_stop = qtdemux->segment.stop;
1478 qtdemux->push_seek_stop = original_stop;
1480 GST_OBJECT_UNLOCK (qtdemux);
1482 /* BYTE seek event */
1483 event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type, byte_cur,
1485 gst_event_set_seqnum (event, seqnum);
1486 res = gst_pad_push_event (qtdemux->sinkpad, event);
1493 GST_DEBUG_OBJECT (qtdemux, "could not determine byte position to seek to, "
1499 GST_DEBUG_OBJECT (qtdemux, "unsupported seek, seek aborted.");
1504 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1509 /* perform the seek.
1511 * We set all segment_indexes in the streams to unknown and
1512 * adjust the time_position to the desired position. this is enough
1513 * to trigger a segment switch in the streaming thread to start
1514 * streaming from the desired position.
1516 * Keyframe seeking is a little more complicated when dealing with
1517 * segments. Ideally we want to move to the previous keyframe in
1518 * the segment but there might not be a keyframe in the segment. In
1519 * fact, none of the segments could contain a keyframe. We take a
1520 * practical approach: seek to the previous keyframe in the segment,
1521 * if there is none, seek to the beginning of the segment.
1523 * Called with STREAM_LOCK
1526 gst_qtdemux_perform_seek (GstQTDemux * qtdemux, GstSegment * segment,
1527 guint32 seqnum, GstSeekFlags flags)
1529 gint64 desired_offset;
1532 desired_offset = segment->position;
1534 GST_DEBUG_OBJECT (qtdemux, "seeking to %" GST_TIME_FORMAT,
1535 GST_TIME_ARGS (desired_offset));
1537 /* may not have enough fragmented info to do this adjustment,
1538 * and we can't scan (and probably should not) at this time with
1539 * possibly flushing upstream */
1540 if ((flags & GST_SEEK_FLAG_KEY_UNIT) && !qtdemux->fragmented) {
1542 gboolean next, before, after;
1544 before = ! !(flags & GST_SEEK_FLAG_SNAP_BEFORE);
1545 after = ! !(flags & GST_SEEK_FLAG_SNAP_AFTER);
1546 next = after && !before;
1547 if (segment->rate < 0)
1550 gst_qtdemux_adjust_seek (qtdemux, desired_offset, TRUE, next, &min_offset,
1552 GST_DEBUG_OBJECT (qtdemux, "keyframe seek, align to %"
1553 GST_TIME_FORMAT, GST_TIME_ARGS (min_offset));
1554 desired_offset = min_offset;
1557 /* and set all streams to the final position */
1558 gst_flow_combiner_reset (qtdemux->flowcombiner);
1559 qtdemux->segment_seqnum = seqnum;
1560 for (n = 0; n < qtdemux->n_streams; n++) {
1561 QtDemuxStream *stream = qtdemux->streams[n];
1563 stream->time_position = desired_offset;
1564 stream->accumulated_base = 0;
1565 stream->sample_index = -1;
1566 stream->offset_in_sample = 0;
1567 stream->segment_index = -1;
1568 stream->sent_eos = FALSE;
1570 if (segment->flags & GST_SEEK_FLAG_FLUSH)
1571 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
1573 segment->position = desired_offset;
1574 segment->time = desired_offset;
1575 if (segment->rate >= 0) {
1576 segment->start = desired_offset;
1578 /* we stop at the end */
1579 if (segment->stop == -1)
1580 segment->stop = segment->duration;
1582 segment->stop = desired_offset;
1585 if (qtdemux->fragmented)
1586 qtdemux->fragmented_seek_pending = TRUE;
1591 /* do a seek in pull based mode */
1593 gst_qtdemux_do_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1598 GstSeekType cur_type, stop_type;
1602 GstSegment seeksegment;
1604 GstEvent *flush_event;
1607 GST_DEBUG_OBJECT (qtdemux, "doing seek with event");
1609 gst_event_parse_seek (event, &rate, &format, &flags,
1610 &cur_type, &cur, &stop_type, &stop);
1611 seqnum = gst_event_get_seqnum (event);
1613 /* we have to have a format as the segment format. Try to convert
1615 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1619 GST_DEBUG_OBJECT (qtdemux, "seek format %s", gst_format_get_name (format));
1621 GST_DEBUG_OBJECT (qtdemux, "doing seek without event");
1625 flush = flags & GST_SEEK_FLAG_FLUSH;
1627 /* stop streaming, either by flushing or by pausing the task */
1629 flush_event = gst_event_new_flush_start ();
1631 gst_event_set_seqnum (flush_event, seqnum);
1632 /* unlock upstream pull_range */
1633 gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event));
1634 /* make sure out loop function exits */
1635 gst_qtdemux_push_event (qtdemux, flush_event);
1637 /* non flushing seek, pause the task */
1638 gst_pad_pause_task (qtdemux->sinkpad);
1641 /* wait for streaming to finish */
1642 GST_PAD_STREAM_LOCK (qtdemux->sinkpad);
1644 /* copy segment, we need this because we still need the old
1645 * segment when we close the current segment. */
1646 memcpy (&seeksegment, &qtdemux->segment, sizeof (GstSegment));
1649 /* configure the segment with the seek variables */
1650 GST_DEBUG_OBJECT (qtdemux, "configuring seek");
1651 gst_segment_do_seek (&seeksegment, rate, format, flags,
1652 cur_type, cur, stop_type, stop, &update);
1655 /* now do the seek, this actually never returns FALSE */
1656 gst_qtdemux_perform_seek (qtdemux, &seeksegment, seqnum, flags);
1658 /* prepare for streaming again */
1660 flush_event = gst_event_new_flush_stop (TRUE);
1662 gst_event_set_seqnum (flush_event, seqnum);
1664 gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event));
1665 gst_qtdemux_push_event (qtdemux, flush_event);
1668 /* commit the new segment */
1669 memcpy (&qtdemux->segment, &seeksegment, sizeof (GstSegment));
1671 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
1672 GstMessage *msg = gst_message_new_segment_start (GST_OBJECT_CAST (qtdemux),
1673 qtdemux->segment.format, qtdemux->segment.position);
1675 gst_message_set_seqnum (msg, seqnum);
1676 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
1679 /* restart streaming, NEWSEGMENT will be sent from the streaming thread. */
1680 gst_pad_start_task (qtdemux->sinkpad, (GstTaskFunction) gst_qtdemux_loop,
1681 qtdemux->sinkpad, NULL);
1683 GST_PAD_STREAM_UNLOCK (qtdemux->sinkpad);
1690 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1696 qtdemux_ensure_index (GstQTDemux * qtdemux)
1700 GST_DEBUG_OBJECT (qtdemux, "collecting all metadata for all streams");
1702 /* Build complete index */
1703 for (i = 0; i < qtdemux->n_streams; i++) {
1704 QtDemuxStream *stream = qtdemux->streams[i];
1706 if (!qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1))
1714 GST_LOG_OBJECT (qtdemux,
1715 "Building complete index of stream %u for seeking failed!", i);
1721 gst_qtdemux_handle_src_event (GstPad * pad, GstObject * parent,
1724 gboolean res = TRUE;
1725 GstQTDemux *qtdemux = GST_QTDEMUX (parent);
1727 switch (GST_EVENT_TYPE (event)) {
1728 case GST_EVENT_SEEK:
1730 #ifndef GST_DISABLE_GST_DEBUG
1731 GstClockTime ts = gst_util_get_timestamp ();
1734 if (qtdemux->upstream_format_is_time && qtdemux->fragmented) {
1735 /* seek should be handled by upstream, we might need to re-download fragments */
1736 GST_DEBUG_OBJECT (qtdemux,
1737 "let upstream handle seek for fragmented playback");
1741 /* Build complete index for seeking;
1742 * if not a fragmented file at least */
1743 if (!qtdemux->fragmented)
1744 if (!qtdemux_ensure_index (qtdemux))
1746 #ifndef GST_DISABLE_GST_DEBUG
1747 ts = gst_util_get_timestamp () - ts;
1748 GST_INFO_OBJECT (qtdemux,
1749 "Time taken to parse index %" GST_TIME_FORMAT, GST_TIME_ARGS (ts));
1752 if (qtdemux->pullbased) {
1753 res = gst_qtdemux_do_seek (qtdemux, pad, event);
1754 } else if (gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (event))) {
1755 GST_DEBUG_OBJECT (qtdemux, "Upstream successfully seeked");
1757 } else if (qtdemux->state == QTDEMUX_STATE_MOVIE && qtdemux->n_streams
1758 && !qtdemux->fragmented) {
1759 res = gst_qtdemux_do_push_seek (qtdemux, pad, event);
1761 GST_DEBUG_OBJECT (qtdemux,
1762 "ignoring seek in push mode in current state");
1765 gst_event_unref (event);
1769 res = gst_pad_event_default (pad, parent, event);
1779 GST_ERROR_OBJECT (qtdemux, "Index failed");
1780 gst_event_unref (event);
1786 /* stream/index return sample that is min/max w.r.t. byte position,
1787 * time is min/max w.r.t. time of samples,
1788 * the latter need not be time of the former sample */
1790 gst_qtdemux_find_sample (GstQTDemux * qtdemux, gint64 byte_pos, gboolean fw,
1791 gboolean set, QtDemuxStream ** _stream, gint * _index, gint64 * _time)
1794 gint64 time, min_time;
1795 QtDemuxStream *stream;
1801 for (n = 0; n < qtdemux->n_streams; ++n) {
1804 gboolean set_sample;
1806 str = qtdemux->streams[n];
1813 i = str->n_samples - 1;
1817 for (; (i >= 0) && (i < str->n_samples); i += inc) {
1818 if (str->samples[i].size == 0)
1821 if (fw && (str->samples[i].offset < byte_pos))
1824 if (!fw && (str->samples[i].offset + str->samples[i].size > byte_pos))
1827 /* move stream to first available sample */
1829 gst_qtdemux_move_stream (qtdemux, str, i);
1833 /* avoid index from sparse streams since they might be far away */
1835 /* determine min/max time */
1836 time = QTSAMPLE_PTS (str, &str->samples[i]);
1837 if (min_time == -1 || (!fw && time > min_time) ||
1838 (fw && time < min_time)) {
1842 /* determine stream with leading sample, to get its position */
1844 (fw && (str->samples[i].offset < stream->samples[index].offset)) ||
1845 (!fw && (str->samples[i].offset > stream->samples[index].offset))) {
1853 /* no sample for this stream, mark eos */
1855 gst_qtdemux_move_stream (qtdemux, str, str->n_samples);
1866 static QtDemuxStream *
1867 _create_stream (void)
1869 QtDemuxStream *stream;
1871 stream = g_new0 (QtDemuxStream, 1);
1872 /* new streams always need a discont */
1873 stream->discont = TRUE;
1874 /* we enable clipping for raw audio/video streams */
1875 stream->need_clip = FALSE;
1876 stream->need_process = FALSE;
1877 stream->segment_index = -1;
1878 stream->time_position = 0;
1879 stream->sample_index = -1;
1880 stream->offset_in_sample = 0;
1881 stream->new_stream = TRUE;
1882 stream->multiview_mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
1883 stream->multiview_flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
1884 stream->protected = FALSE;
1885 stream->protection_scheme_type = 0;
1886 stream->protection_scheme_version = 0;
1887 stream->protection_scheme_info = NULL;
1888 stream->n_samples_moof = 0;
1889 stream->duration_moof = 0;
1890 stream->duration_last_moof = 0;
1891 stream->alignment = 1;
1892 g_queue_init (&stream->protection_scheme_event_queue);
1897 gst_qtdemux_setcaps (GstQTDemux * demux, GstCaps * caps)
1899 GstStructure *structure;
1900 const gchar *variant;
1901 const GstCaps *mediacaps = NULL;
1903 GST_DEBUG_OBJECT (demux, "Sink set caps: %" GST_PTR_FORMAT, caps);
1905 structure = gst_caps_get_structure (caps, 0);
1906 variant = gst_structure_get_string (structure, "variant");
1908 if (variant && strcmp (variant, "mss-fragmented") == 0) {
1909 QtDemuxStream *stream;
1910 const GValue *value;
1912 demux->fragmented = TRUE;
1913 demux->mss_mode = TRUE;
1915 if (demux->n_streams > 1) {
1916 /* can't do this, we can only renegotiate for another mss format */
1920 value = gst_structure_get_value (structure, "media-caps");
1923 const GValue *timescale_v;
1925 /* TODO update when stream changes during playback */
1927 if (demux->n_streams == 0) {
1928 stream = _create_stream ();
1929 demux->streams[demux->n_streams] = stream;
1930 demux->n_streams = 1;
1932 stream = demux->streams[0];
1935 timescale_v = gst_structure_get_value (structure, "timescale");
1937 stream->timescale = g_value_get_uint64 (timescale_v);
1939 /* default mss timescale */
1940 stream->timescale = 10000000;
1942 demux->timescale = stream->timescale;
1944 mediacaps = gst_value_get_caps (value);
1945 if (!stream->caps || !gst_caps_is_equal_fixed (mediacaps, stream->caps)) {
1946 GST_DEBUG_OBJECT (demux, "We have a new caps %" GST_PTR_FORMAT,
1948 stream->new_caps = TRUE;
1950 gst_caps_replace (&stream->caps, (GstCaps *) mediacaps);
1951 structure = gst_caps_get_structure (mediacaps, 0);
1952 if (g_str_has_prefix (gst_structure_get_name (structure), "video")) {
1953 stream->subtype = FOURCC_vide;
1955 gst_structure_get_int (structure, "width", &stream->width);
1956 gst_structure_get_int (structure, "height", &stream->height);
1957 gst_structure_get_fraction (structure, "framerate", &stream->fps_n,
1959 } else if (g_str_has_prefix (gst_structure_get_name (structure), "audio")) {
1961 stream->subtype = FOURCC_soun;
1962 gst_structure_get_int (structure, "channels", &stream->n_channels);
1963 gst_structure_get_int (structure, "rate", &rate);
1964 stream->rate = rate;
1967 gst_caps_replace (&demux->media_caps, (GstCaps *) mediacaps);
1969 demux->mss_mode = FALSE;
1976 gst_qtdemux_reset (GstQTDemux * qtdemux, gboolean hard)
1980 GST_DEBUG_OBJECT (qtdemux, "Resetting demux");
1981 gst_pad_stop_task (qtdemux->sinkpad);
1983 if (hard || qtdemux->upstream_format_is_time) {
1984 qtdemux->state = QTDEMUX_STATE_INITIAL;
1985 qtdemux->neededbytes = 16;
1986 qtdemux->todrop = 0;
1987 qtdemux->pullbased = FALSE;
1988 qtdemux->posted_redirect = FALSE;
1989 qtdemux->first_mdat = -1;
1990 qtdemux->header_size = 0;
1991 qtdemux->mdatoffset = -1;
1992 qtdemux->restoredata_offset = -1;
1993 if (qtdemux->mdatbuffer)
1994 gst_buffer_unref (qtdemux->mdatbuffer);
1995 if (qtdemux->restoredata_buffer)
1996 gst_buffer_unref (qtdemux->restoredata_buffer);
1997 qtdemux->mdatbuffer = NULL;
1998 qtdemux->restoredata_buffer = NULL;
1999 qtdemux->mdatleft = 0;
2000 if (qtdemux->comp_brands)
2001 gst_buffer_unref (qtdemux->comp_brands);
2002 qtdemux->comp_brands = NULL;
2003 qtdemux->last_moov_offset = -1;
2004 if (qtdemux->moov_node_compressed) {
2005 g_node_destroy (qtdemux->moov_node_compressed);
2006 if (qtdemux->moov_node)
2007 g_free (qtdemux->moov_node->data);
2009 qtdemux->moov_node_compressed = NULL;
2010 if (qtdemux->moov_node)
2011 g_node_destroy (qtdemux->moov_node);
2012 qtdemux->moov_node = NULL;
2013 if (qtdemux->tag_list)
2014 gst_mini_object_unref (GST_MINI_OBJECT_CAST (qtdemux->tag_list));
2015 qtdemux->tag_list = NULL;
2017 if (qtdemux->element_index)
2018 gst_object_unref (qtdemux->element_index);
2019 qtdemux->element_index = NULL;
2021 qtdemux->major_brand = 0;
2022 if (qtdemux->pending_newsegment)
2023 gst_event_unref (qtdemux->pending_newsegment);
2024 qtdemux->pending_newsegment = NULL;
2025 qtdemux->upstream_format_is_time = FALSE;
2026 qtdemux->upstream_seekable = FALSE;
2027 qtdemux->upstream_size = 0;
2029 qtdemux->fragment_start = -1;
2030 qtdemux->fragment_start_offset = -1;
2031 qtdemux->duration = 0;
2032 qtdemux->moof_offset = 0;
2033 qtdemux->chapters_track_id = 0;
2034 qtdemux->have_group_id = FALSE;
2035 qtdemux->group_id = G_MAXUINT;
2037 g_queue_foreach (&qtdemux->protection_event_queue, (GFunc) gst_event_unref,
2039 g_queue_clear (&qtdemux->protection_event_queue);
2041 qtdemux->offset = 0;
2042 gst_adapter_clear (qtdemux->adapter);
2043 gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
2044 qtdemux->segment_seqnum = 0;
2047 for (n = 0; n < qtdemux->n_streams; n++) {
2048 gst_qtdemux_stream_free (qtdemux, qtdemux->streams[n]);
2049 qtdemux->streams[n] = NULL;
2051 qtdemux->n_streams = 0;
2052 qtdemux->n_video_streams = 0;
2053 qtdemux->n_audio_streams = 0;
2054 qtdemux->n_sub_streams = 0;
2055 qtdemux->exposed = FALSE;
2056 qtdemux->fragmented = FALSE;
2057 qtdemux->mss_mode = FALSE;
2058 gst_caps_replace (&qtdemux->media_caps, NULL);
2059 qtdemux->timescale = 0;
2060 qtdemux->got_moov = FALSE;
2061 if (qtdemux->protection_system_ids) {
2062 g_ptr_array_free (qtdemux->protection_system_ids, TRUE);
2063 qtdemux->protection_system_ids = NULL;
2065 } else if (qtdemux->mss_mode) {
2066 gst_flow_combiner_reset (qtdemux->flowcombiner);
2067 for (n = 0; n < qtdemux->n_streams; n++)
2068 gst_qtdemux_stream_clear (qtdemux, qtdemux->streams[n]);
2070 gst_flow_combiner_reset (qtdemux->flowcombiner);
2071 for (n = 0; n < qtdemux->n_streams; n++) {
2072 qtdemux->streams[n]->sent_eos = FALSE;
2073 qtdemux->streams[n]->time_position = 0;
2074 qtdemux->streams[n]->accumulated_base = 0;
2076 if (!qtdemux->pending_newsegment) {
2077 qtdemux->pending_newsegment = gst_event_new_segment (&qtdemux->segment);
2078 if (qtdemux->segment_seqnum)
2079 gst_event_set_seqnum (qtdemux->pending_newsegment,
2080 qtdemux->segment_seqnum);
2086 /* Maps the @segment to the qt edts internal segments and pushes
2087 * the correspnding segment event.
2089 * If it ends up being at a empty segment, a gap will be pushed and the next
2090 * edts segment will be activated in sequence.
2092 * To be used in push-mode only */
2094 gst_qtdemux_map_and_push_segments (GstQTDemux * qtdemux, GstSegment * segment)
2098 for (n = 0; n < qtdemux->n_streams; n++) {
2099 QtDemuxStream *stream = qtdemux->streams[n];
2101 stream->time_position = segment->start;
2103 /* in push mode we should be guaranteed that we will have empty segments
2104 * at the beginning and then one segment after, other scenarios are not
2105 * supported and are discarded when parsing the edts */
2106 for (i = 0; i < stream->n_segments; i++) {
2107 if (stream->segments[i].stop_time > segment->start) {
2108 gst_qtdemux_activate_segment (qtdemux, stream, i,
2109 stream->time_position);
2110 if (QTSEGMENT_IS_EMPTY (&stream->segments[i])) {
2111 /* push the empty segment and move to the next one */
2112 gst_qtdemux_send_gap_for_segment (qtdemux, stream, i,
2113 stream->time_position);
2117 g_assert (i == stream->n_segments - 1);
2124 gst_qtdemux_handle_sink_event (GstPad * sinkpad, GstObject * parent,
2127 GstQTDemux *demux = GST_QTDEMUX (parent);
2128 gboolean res = TRUE;
2130 GST_LOG_OBJECT (demux, "handling %s event", GST_EVENT_TYPE_NAME (event));
2132 switch (GST_EVENT_TYPE (event)) {
2133 case GST_EVENT_SEGMENT:
2136 QtDemuxStream *stream;
2140 /* some debug output */
2141 gst_event_copy_segment (event, &segment);
2142 GST_DEBUG_OBJECT (demux, "received newsegment %" GST_SEGMENT_FORMAT,
2145 /* erase any previously set segment */
2146 gst_event_replace (&demux->pending_newsegment, NULL);
2148 if (segment.format == GST_FORMAT_TIME) {
2149 GST_DEBUG_OBJECT (demux, "new pending_newsegment");
2150 gst_event_replace (&demux->pending_newsegment, event);
2151 demux->upstream_format_is_time = TRUE;
2153 GST_DEBUG_OBJECT (demux, "Not storing upstream newsegment, "
2154 "not in time format");
2156 /* chain will send initial newsegment after pads have been added */
2157 if (demux->state != QTDEMUX_STATE_MOVIE || !demux->n_streams) {
2158 GST_DEBUG_OBJECT (demux, "still starting, eating event");
2163 /* check if this matches a time seek we received previously
2164 * FIXME for backwards compatibility reasons we use the
2165 * seek_offset here to compare. In the future we might want to
2166 * change this to use the seqnum as it uniquely should identify
2167 * the segment that corresponds to the seek. */
2168 GST_DEBUG_OBJECT (demux, "Stored seek offset: %" G_GINT64_FORMAT
2169 ", received segment offset %" G_GINT64_FORMAT,
2170 demux->seek_offset, segment.start);
2171 if (segment.format == GST_FORMAT_BYTES
2172 && demux->seek_offset == segment.start) {
2173 GST_OBJECT_LOCK (demux);
2174 offset = segment.start;
2176 segment.format = GST_FORMAT_TIME;
2177 segment.start = demux->push_seek_start;
2178 segment.stop = demux->push_seek_stop;
2179 GST_DEBUG_OBJECT (demux, "Replaced segment with stored seek "
2180 "segment %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT,
2181 GST_TIME_ARGS (segment.start), GST_TIME_ARGS (segment.stop));
2182 GST_OBJECT_UNLOCK (demux);
2185 /* we only expect a BYTE segment, e.g. following a seek */
2186 if (segment.format == GST_FORMAT_BYTES) {
2187 if (GST_CLOCK_TIME_IS_VALID (segment.start)) {
2188 offset = segment.start;
2190 gst_qtdemux_find_sample (demux, segment.start, TRUE, FALSE, NULL,
2191 NULL, (gint64 *) & segment.start);
2192 if ((gint64) segment.start < 0)
2195 if (GST_CLOCK_TIME_IS_VALID (segment.stop)) {
2196 gst_qtdemux_find_sample (demux, segment.stop, FALSE, FALSE, NULL,
2197 NULL, (gint64 *) & segment.stop);
2198 /* keyframe seeking should already arrange for start >= stop,
2199 * but make sure in other rare cases */
2200 segment.stop = MAX (segment.stop, segment.start);
2202 } else if (segment.format == GST_FORMAT_TIME) {
2203 /* push all data on the adapter before starting this
2205 gst_qtdemux_process_adapter (demux, TRUE);
2207 GST_DEBUG_OBJECT (demux, "unsupported segment format, ignoring");
2211 /* We shouldn't modify upstream driven TIME FORMAT segment */
2212 if (!demux->upstream_format_is_time) {
2213 /* accept upstream's notion of segment and distribute along */
2214 segment.format = GST_FORMAT_TIME;
2215 segment.position = segment.time = segment.start;
2216 segment.duration = demux->segment.duration;
2217 segment.base = gst_segment_to_running_time (&demux->segment,
2218 GST_FORMAT_TIME, demux->segment.position);
2221 gst_segment_copy_into (&segment, &demux->segment);
2222 GST_DEBUG_OBJECT (demux, "Pushing newseg %" GST_SEGMENT_FORMAT, &segment);
2224 /* map segment to internal qt segments and push on each stream */
2225 if (demux->n_streams) {
2226 if (demux->fragmented) {
2227 GstEvent *segment_event = gst_event_new_segment (&segment);
2229 gst_event_replace (&demux->pending_newsegment, NULL);
2230 gst_event_set_seqnum (segment_event, demux->segment_seqnum);
2231 gst_qtdemux_push_event (demux, segment_event);
2233 gst_event_replace (&demux->pending_newsegment, NULL);
2234 gst_qtdemux_map_and_push_segments (demux, &segment);
2238 /* clear leftover in current segment, if any */
2239 gst_adapter_clear (demux->adapter);
2241 /* set up streaming thread */
2242 demux->offset = offset;
2243 if (demux->upstream_format_is_time) {
2244 GST_DEBUG_OBJECT (demux, "Upstream is driving in time format, "
2245 "set values to restart reading from a new atom");
2246 demux->neededbytes = 16;
2249 gst_qtdemux_find_sample (demux, offset, TRUE, TRUE, &stream, &idx,
2252 demux->todrop = stream->samples[idx].offset - offset;
2253 demux->neededbytes = demux->todrop + stream->samples[idx].size;
2255 /* set up for EOS */
2256 demux->neededbytes = -1;
2261 gst_event_unref (event);
2265 case GST_EVENT_FLUSH_START:
2267 if (gst_event_get_seqnum (event) == demux->offset_seek_seqnum) {
2268 gst_event_unref (event);
2273 case GST_EVENT_FLUSH_STOP:
2277 dur = demux->segment.duration;
2278 gst_qtdemux_reset (demux, FALSE);
2279 demux->segment.duration = dur;
2281 if (gst_event_get_seqnum (event) == demux->offset_seek_seqnum) {
2282 gst_event_unref (event);
2288 /* If we are in push mode, and get an EOS before we've seen any streams,
2289 * then error out - we have nowhere to send the EOS */
2290 if (!demux->pullbased) {
2292 gboolean has_valid_stream = FALSE;
2293 for (i = 0; i < demux->n_streams; i++) {
2294 if (demux->streams[i]->pad != NULL) {
2295 has_valid_stream = TRUE;
2299 if (!has_valid_stream)
2300 gst_qtdemux_post_no_playable_stream_error (demux);
2302 GST_DEBUG_OBJECT (demux, "Data still available after EOS: %u",
2303 (guint) gst_adapter_available (demux->adapter));
2304 if (gst_qtdemux_process_adapter (demux, TRUE) != GST_FLOW_OK) {
2310 case GST_EVENT_CAPS:{
2311 GstCaps *caps = NULL;
2313 gst_event_parse_caps (event, &caps);
2314 gst_qtdemux_setcaps (demux, caps);
2316 gst_event_unref (event);
2319 case GST_EVENT_PROTECTION:
2321 const gchar *system_id = NULL;
2323 gst_event_parse_protection (event, &system_id, NULL, NULL);
2324 GST_DEBUG_OBJECT (demux, "Received protection event for system ID %s",
2326 gst_qtdemux_append_protection_system_id (demux, system_id);
2327 /* save the event for later, for source pads that have not been created */
2328 g_queue_push_tail (&demux->protection_event_queue, gst_event_ref (event));
2329 /* send it to all pads that already exist */
2330 gst_qtdemux_push_event (demux, event);
2338 res = gst_pad_event_default (demux->sinkpad, parent, event) & res;
2346 gst_qtdemux_set_index (GstElement * element, GstIndex * index)
2348 GstQTDemux *demux = GST_QTDEMUX (element);
2350 GST_OBJECT_LOCK (demux);
2351 if (demux->element_index)
2352 gst_object_unref (demux->element_index);
2354 demux->element_index = gst_object_ref (index);
2356 demux->element_index = NULL;
2358 GST_OBJECT_UNLOCK (demux);
2359 /* object lock might be taken again */
2361 gst_index_get_writer_id (index, GST_OBJECT (element), &demux->index_id);
2362 GST_DEBUG_OBJECT (demux, "Set index %" GST_PTR_FORMAT "for writer id %d",
2363 demux->element_index, demux->index_id);
2367 gst_qtdemux_get_index (GstElement * element)
2369 GstIndex *result = NULL;
2370 GstQTDemux *demux = GST_QTDEMUX (element);
2372 GST_OBJECT_LOCK (demux);
2373 if (demux->element_index)
2374 result = gst_object_ref (demux->element_index);
2375 GST_OBJECT_UNLOCK (demux);
2377 GST_DEBUG_OBJECT (demux, "Returning index %" GST_PTR_FORMAT, result);
2384 gst_qtdemux_stbl_free (QtDemuxStream * stream)
2386 g_free ((gpointer) stream->stco.data);
2387 stream->stco.data = NULL;
2388 g_free ((gpointer) stream->stsz.data);
2389 stream->stsz.data = NULL;
2390 g_free ((gpointer) stream->stsc.data);
2391 stream->stsc.data = NULL;
2392 g_free ((gpointer) stream->stts.data);
2393 stream->stts.data = NULL;
2394 g_free ((gpointer) stream->stss.data);
2395 stream->stss.data = NULL;
2396 g_free ((gpointer) stream->stps.data);
2397 stream->stps.data = NULL;
2398 g_free ((gpointer) stream->ctts.data);
2399 stream->ctts.data = NULL;
2403 gst_qtdemux_stream_flush_segments_data (GstQTDemux * qtdemux,
2404 QtDemuxStream * stream)
2406 g_free (stream->segments);
2407 stream->segments = NULL;
2408 stream->segment_index = -1;
2409 stream->accumulated_base = 0;
2413 gst_qtdemux_stream_flush_samples_data (GstQTDemux * qtdemux,
2414 QtDemuxStream * stream)
2416 g_free (stream->samples);
2417 stream->samples = NULL;
2418 gst_qtdemux_stbl_free (stream);
2421 g_free (stream->ra_entries);
2422 stream->ra_entries = NULL;
2423 stream->n_ra_entries = 0;
2425 stream->sample_index = -1;
2426 stream->stbl_index = -1;
2427 stream->n_samples = 0;
2428 stream->time_position = 0;
2430 stream->n_samples_moof = 0;
2431 stream->duration_moof = 0;
2432 stream->duration_last_moof = 0;
2436 gst_qtdemux_stream_clear (GstQTDemux * qtdemux, QtDemuxStream * stream)
2438 if (stream->allocator)
2439 gst_object_unref (stream->allocator);
2440 while (stream->buffers) {
2441 gst_buffer_unref (GST_BUFFER_CAST (stream->buffers->data));
2442 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
2444 if (stream->rgb8_palette) {
2445 gst_memory_unref (stream->rgb8_palette);
2446 stream->rgb8_palette = NULL;
2449 if (stream->pending_tags)
2450 gst_tag_list_unref (stream->pending_tags);
2451 stream->pending_tags = NULL;
2452 g_free (stream->redirect_uri);
2453 stream->redirect_uri = NULL;
2454 stream->sent_eos = FALSE;
2455 stream->sparse = FALSE;
2456 stream->protected = FALSE;
2457 if (stream->protection_scheme_info) {
2458 if (stream->protection_scheme_type == FOURCC_cenc) {
2459 QtDemuxCencSampleSetInfo *info =
2460 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
2461 if (info->default_properties)
2462 gst_structure_free (info->default_properties);
2463 if (info->crypto_info)
2464 g_ptr_array_free (info->crypto_info, TRUE);
2466 g_free (stream->protection_scheme_info);
2467 stream->protection_scheme_info = NULL;
2469 stream->protection_scheme_type = 0;
2470 stream->protection_scheme_version = 0;
2471 g_queue_foreach (&stream->protection_scheme_event_queue,
2472 (GFunc) gst_event_unref, NULL);
2473 g_queue_clear (&stream->protection_scheme_event_queue);
2474 gst_qtdemux_stream_flush_segments_data (qtdemux, stream);
2475 gst_qtdemux_stream_flush_samples_data (qtdemux, stream);
2479 gst_qtdemux_stream_free (GstQTDemux * qtdemux, QtDemuxStream * stream)
2481 gst_qtdemux_stream_clear (qtdemux, stream);
2483 gst_caps_unref (stream->caps);
2484 stream->caps = NULL;
2486 gst_element_remove_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
2487 gst_flow_combiner_remove_pad (qtdemux->flowcombiner, stream->pad);
2493 gst_qtdemux_remove_stream (GstQTDemux * qtdemux, int i)
2495 g_assert (i >= 0 && i < qtdemux->n_streams && qtdemux->streams[i] != NULL);
2497 gst_qtdemux_stream_free (qtdemux, qtdemux->streams[i]);
2498 qtdemux->streams[i] = qtdemux->streams[qtdemux->n_streams - 1];
2499 qtdemux->streams[qtdemux->n_streams - 1] = NULL;
2500 qtdemux->n_streams--;
2503 static GstStateChangeReturn
2504 gst_qtdemux_change_state (GstElement * element, GstStateChange transition)
2506 GstQTDemux *qtdemux = GST_QTDEMUX (element);
2507 GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
2509 switch (transition) {
2510 case GST_STATE_CHANGE_PAUSED_TO_READY:
2516 result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
2518 switch (transition) {
2519 case GST_STATE_CHANGE_PAUSED_TO_READY:{
2520 gst_qtdemux_reset (qtdemux, TRUE);
2531 qtdemux_parse_ftyp (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2533 /* counts as header data */
2534 qtdemux->header_size += length;
2536 /* only consider at least a sufficiently complete ftyp atom */
2540 qtdemux->major_brand = QT_FOURCC (buffer + 8);
2541 GST_DEBUG_OBJECT (qtdemux, "major brand: %" GST_FOURCC_FORMAT,
2542 GST_FOURCC_ARGS (qtdemux->major_brand));
2543 if (qtdemux->comp_brands)
2544 gst_buffer_unref (qtdemux->comp_brands);
2545 buf = qtdemux->comp_brands = gst_buffer_new_and_alloc (length - 16);
2546 gst_buffer_fill (buf, 0, buffer + 16, length - 16);
2551 qtdemux_handle_xmp_taglist (GstQTDemux * qtdemux, GstTagList * taglist,
2552 GstTagList * xmptaglist)
2554 /* Strip out bogus fields */
2556 if (gst_tag_list_get_scope (taglist) == GST_TAG_SCOPE_GLOBAL) {
2557 gst_tag_list_remove_tag (xmptaglist, GST_TAG_VIDEO_CODEC);
2558 gst_tag_list_remove_tag (xmptaglist, GST_TAG_AUDIO_CODEC);
2560 gst_tag_list_remove_tag (xmptaglist, GST_TAG_CONTAINER_FORMAT);
2563 GST_DEBUG_OBJECT (qtdemux, "Found XMP tags %" GST_PTR_FORMAT, xmptaglist);
2565 /* prioritize native tags using _KEEP mode */
2566 gst_tag_list_insert (taglist, xmptaglist, GST_TAG_MERGE_KEEP);
2567 gst_tag_list_unref (xmptaglist);
2572 qtdemux_parse_piff (GstQTDemux * qtdemux, const guint8 * buffer, gint length,
2580 QtDemuxStream *stream;
2581 GstStructure *structure;
2582 QtDemuxCencSampleSetInfo *ss_info = NULL;
2583 const gchar *system_id;
2584 gboolean uses_sub_sample_encryption = FALSE;
2586 if (qtdemux->n_streams == 0)
2589 stream = qtdemux->streams[0];
2591 structure = gst_caps_get_structure (stream->caps, 0);
2592 if (!gst_structure_has_name (structure, "application/x-cenc")) {
2593 GST_WARNING_OBJECT (qtdemux,
2594 "Attempting PIFF box parsing on an unencrypted stream.");
2598 gst_structure_get (structure, GST_PROTECTION_SYSTEM_ID_CAPS_FIELD,
2599 G_TYPE_STRING, &system_id, NULL);
2600 gst_qtdemux_append_protection_system_id (qtdemux, system_id);
2602 stream->protected = TRUE;
2603 stream->protection_scheme_type = FOURCC_cenc;
2605 if (!stream->protection_scheme_info)
2606 stream->protection_scheme_info = g_new0 (QtDemuxCencSampleSetInfo, 1);
2608 ss_info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
2610 if (ss_info->default_properties)
2611 gst_structure_free (ss_info->default_properties);
2613 ss_info->default_properties =
2614 gst_structure_new ("application/x-cenc",
2615 "iv_size", G_TYPE_UINT, iv_size, "encrypted", G_TYPE_BOOLEAN, TRUE, NULL);
2617 if (ss_info->crypto_info) {
2618 GST_LOG_OBJECT (qtdemux, "unreffing existing crypto_info");
2619 g_ptr_array_free (ss_info->crypto_info, TRUE);
2620 ss_info->crypto_info = NULL;
2624 gst_byte_reader_init (&br, buffer + offset + 16, length - offset - 16);
2626 if (!gst_byte_reader_get_uint8 (&br, &version)) {
2627 GST_ERROR_OBJECT (qtdemux, "Error getting box's version field");
2631 if (!gst_byte_reader_get_uint24_be (&br, &flags)) {
2632 GST_ERROR_OBJECT (qtdemux, "Error getting box's flags field");
2636 if ((flags & 0x000001)) {
2637 guint32 algorithm_id = 0;
2640 gboolean is_encrypted = TRUE;
2642 if (!gst_byte_reader_get_uint24_le (&br, &algorithm_id)) {
2643 GST_ERROR_OBJECT (qtdemux, "Error getting box's algorithm ID field");
2648 if (algorithm_id == 0) {
2649 is_encrypted = FALSE;
2650 } else if (algorithm_id == 1) {
2651 /* FIXME: maybe store this in properties? */
2652 GST_DEBUG_OBJECT (qtdemux, "AES 128-bits CTR encrypted stream");
2653 } else if (algorithm_id == 2) {
2654 /* FIXME: maybe store this in properties? */
2655 GST_DEBUG_OBJECT (qtdemux, "AES 128-bits CBC encrypted stream");
2658 if (!gst_byte_reader_get_uint8 (&br, &iv_size))
2661 if (!gst_byte_reader_get_data (&br, 16, &kid))
2664 kid_buf = gst_buffer_new_allocate (NULL, 16, NULL);
2665 gst_buffer_fill (kid_buf, 0, kid, 16);
2666 if (ss_info->default_properties)
2667 gst_structure_free (ss_info->default_properties);
2668 ss_info->default_properties =
2669 gst_structure_new ("application/x-cenc",
2670 "iv_size", G_TYPE_UINT, iv_size,
2671 "encrypted", G_TYPE_BOOLEAN, is_encrypted,
2672 "kid", GST_TYPE_BUFFER, kid_buf, NULL);
2673 GST_DEBUG_OBJECT (qtdemux, "default sample properties: "
2674 "is_encrypted=%u, iv_size=%u", is_encrypted, iv_size);
2675 gst_buffer_unref (kid_buf);
2676 } else if ((flags & 0x000002)) {
2677 uses_sub_sample_encryption = TRUE;
2680 if (!gst_byte_reader_get_uint32_be (&br, &qtdemux->cenc_aux_sample_count)) {
2681 GST_ERROR_OBJECT (qtdemux, "Error getting box's sample count field");
2685 ss_info->crypto_info =
2686 g_ptr_array_new_full (qtdemux->cenc_aux_sample_count,
2687 (GDestroyNotify) qtdemux_gst_structure_free);
2689 for (i = 0; i < qtdemux->cenc_aux_sample_count; ++i) {
2690 GstStructure *properties;
2694 properties = qtdemux_get_cenc_sample_properties (qtdemux, stream, i);
2695 if (properties == NULL) {
2696 GST_ERROR_OBJECT (qtdemux, "failed to get properties for sample %u", i);
2700 if (!gst_byte_reader_dup_data (&br, iv_size, &data)) {
2701 GST_ERROR_OBJECT (qtdemux, "IV data not present for sample %u", i);
2702 gst_structure_free (properties);
2705 buf = gst_buffer_new_wrapped (data, iv_size);
2706 gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL);
2707 gst_buffer_unref (buf);
2709 if (uses_sub_sample_encryption) {
2710 guint16 n_subsamples;
2712 if (!gst_byte_reader_get_uint16_be (&br, &n_subsamples)
2713 || n_subsamples == 0) {
2714 GST_ERROR_OBJECT (qtdemux,
2715 "failed to get subsample count for sample %u", i);
2716 gst_structure_free (properties);
2719 GST_LOG_OBJECT (qtdemux, "subsample count: %u", n_subsamples);
2720 if (!gst_byte_reader_dup_data (&br, n_subsamples * 6, &data)) {
2721 GST_ERROR_OBJECT (qtdemux, "failed to get subsample data for sample %u",
2723 gst_structure_free (properties);
2726 buf = gst_buffer_new_wrapped (data, n_subsamples * 6);
2727 gst_structure_set (properties,
2728 "subsample_count", G_TYPE_UINT, n_subsamples,
2729 "subsamples", GST_TYPE_BUFFER, buf, NULL);
2730 gst_buffer_unref (buf);
2732 gst_structure_set (properties, "subsample_count", G_TYPE_UINT, 0, NULL);
2735 g_ptr_array_add (ss_info->crypto_info, properties);
2740 qtdemux_parse_uuid (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2742 static const guint8 xmp_uuid[] = { 0xBE, 0x7A, 0xCF, 0xCB,
2743 0x97, 0xA9, 0x42, 0xE8,
2744 0x9C, 0x71, 0x99, 0x94,
2745 0x91, 0xE3, 0xAF, 0xAC
2747 static const guint8 playready_uuid[] = {
2748 0xd0, 0x8a, 0x4f, 0x18, 0x10, 0xf3, 0x4a, 0x82,
2749 0xb6, 0xc8, 0x32, 0xd8, 0xab, 0xa1, 0x83, 0xd3
2752 static const guint8 piff_sample_encryption_uuid[] = {
2753 0xa2, 0x39, 0x4f, 0x52, 0x5a, 0x9b, 0x4f, 0x14,
2754 0xa2, 0x44, 0x6c, 0x42, 0x7c, 0x64, 0x8d, 0xf4
2759 /* counts as header data */
2760 qtdemux->header_size += length;
2762 offset = (QT_UINT32 (buffer) == 0) ? 16 : 8;
2764 if (length <= offset + 16) {
2765 GST_DEBUG_OBJECT (qtdemux, "uuid atom is too short, skipping");
2769 if (memcmp (buffer + offset, xmp_uuid, 16) == 0) {
2771 GstTagList *taglist;
2773 buf = _gst_buffer_new_wrapped ((guint8 *) buffer + offset + 16,
2774 length - offset - 16, NULL);
2775 taglist = gst_tag_list_from_xmp_buffer (buf);
2776 gst_buffer_unref (buf);
2778 qtdemux_handle_xmp_taglist (qtdemux, qtdemux->tag_list, taglist);
2780 } else if (memcmp (buffer + offset, playready_uuid, 16) == 0) {
2782 const gunichar2 *s_utf16;
2785 len = GST_READ_UINT16_LE (buffer + offset + 0x30);
2786 s_utf16 = (const gunichar2 *) (buffer + offset + 0x32);
2787 contents = g_utf16_to_utf8 (s_utf16, len / 2, NULL, NULL, NULL);
2788 GST_ERROR_OBJECT (qtdemux, "contents: %s", contents);
2792 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT,
2793 (_("Cannot play stream because it is encrypted with PlayReady DRM.")),
2795 } else if (memcmp (buffer + offset, piff_sample_encryption_uuid, 16) == 0) {
2796 qtdemux_parse_piff (qtdemux, buffer, length, offset);
2798 GST_DEBUG_OBJECT (qtdemux, "Ignoring unknown uuid: %08x-%08x-%08x-%08x",
2799 GST_READ_UINT32_LE (buffer + offset),
2800 GST_READ_UINT32_LE (buffer + offset + 4),
2801 GST_READ_UINT32_LE (buffer + offset + 8),
2802 GST_READ_UINT32_LE (buffer + offset + 12));
2807 qtdemux_parse_sidx (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2809 GstSidxParser sidx_parser;
2810 GstIsoffParserResult res;
2813 gst_isoff_qt_sidx_parser_init (&sidx_parser);
2816 gst_isoff_qt_sidx_parser_add_data (&sidx_parser, buffer, length,
2818 GST_DEBUG_OBJECT (qtdemux, "sidx parse result: %d", res);
2819 if (res == GST_ISOFF_QT_PARSER_DONE) {
2820 check_update_duration (qtdemux, sidx_parser.cumulative_pts);
2822 gst_isoff_qt_sidx_parser_clear (&sidx_parser);
2825 /* caller verifies at least 8 bytes in buf */
2827 extract_initial_length_and_fourcc (const guint8 * data, guint size,
2828 guint64 * plength, guint32 * pfourcc)
2833 length = QT_UINT32 (data);
2834 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
2835 fourcc = QT_FOURCC (data + 4);
2836 GST_DEBUG ("atom type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
2839 length = G_MAXUINT64;
2840 } else if (length == 1 && size >= 16) {
2841 /* this means we have an extended size, which is the 64 bit value of
2842 * the next 8 bytes */
2843 length = QT_UINT64 (data + 8);
2844 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
2854 qtdemux_parse_mehd (GstQTDemux * qtdemux, GstByteReader * br)
2856 guint32 version = 0;
2857 GstClockTime duration = 0;
2859 if (!gst_byte_reader_get_uint32_be (br, &version))
2864 if (!gst_byte_reader_get_uint64_be (br, &duration))
2869 if (!gst_byte_reader_get_uint32_be (br, &dur))
2874 GST_INFO_OBJECT (qtdemux, "mehd duration: %" G_GUINT64_FORMAT, duration);
2875 qtdemux->duration = duration;
2881 GST_DEBUG_OBJECT (qtdemux, "parsing mehd failed");
2887 qtdemux_parse_trex (GstQTDemux * qtdemux, QtDemuxStream * stream,
2888 guint32 * ds_duration, guint32 * ds_size, guint32 * ds_flags)
2890 if (!stream->parsed_trex && qtdemux->moov_node) {
2892 GstByteReader trex_data;
2894 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
2896 trex = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_trex,
2899 guint32 id = 0, dur = 0, size = 0, flags = 0, dummy = 0;
2901 /* skip version/flags */
2902 if (!gst_byte_reader_skip (&trex_data, 4))
2904 if (!gst_byte_reader_get_uint32_be (&trex_data, &id))
2906 if (id != stream->track_id)
2908 /* sample description index; ignore */
2909 if (!gst_byte_reader_get_uint32_be (&trex_data, &dummy))
2911 if (!gst_byte_reader_get_uint32_be (&trex_data, &dur))
2913 if (!gst_byte_reader_get_uint32_be (&trex_data, &size))
2915 if (!gst_byte_reader_get_uint32_be (&trex_data, &flags))
2918 GST_DEBUG_OBJECT (qtdemux, "fragment defaults for stream %d; "
2919 "duration %d, size %d, flags 0x%x", stream->track_id,
2922 stream->parsed_trex = TRUE;
2923 stream->def_sample_duration = dur;
2924 stream->def_sample_size = size;
2925 stream->def_sample_flags = flags;
2928 /* iterate all siblings */
2929 trex = qtdemux_tree_get_sibling_by_type_full (trex, FOURCC_trex,
2935 *ds_duration = stream->def_sample_duration;
2936 *ds_size = stream->def_sample_size;
2937 *ds_flags = stream->def_sample_flags;
2939 /* even then, above values are better than random ... */
2940 if (G_UNLIKELY (!stream->parsed_trex)) {
2941 GST_WARNING_OBJECT (qtdemux,
2942 "failed to find fragment defaults for stream %d", stream->track_id);
2949 /* This method should be called whenever a more accurate duration might
2950 * have been found. It will update all relevant variables if/where needed
2953 check_update_duration (GstQTDemux * qtdemux, GstClockTime duration)
2957 GstClockTime prevdur;
2959 movdur = GSTTIME_TO_QTTIME (qtdemux, duration);
2961 if (movdur > qtdemux->duration) {
2962 prevdur = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
2963 GST_DEBUG_OBJECT (qtdemux,
2964 "Updating total duration to %" GST_TIME_FORMAT " was %" GST_TIME_FORMAT,
2965 GST_TIME_ARGS (duration), GST_TIME_ARGS (prevdur));
2966 qtdemux->duration = movdur;
2967 GST_DEBUG_OBJECT (qtdemux,
2968 "qtdemux->segment.duration: %" GST_TIME_FORMAT " .stop: %"
2969 GST_TIME_FORMAT, GST_TIME_ARGS (qtdemux->segment.duration),
2970 GST_TIME_ARGS (qtdemux->segment.stop));
2971 if (qtdemux->segment.duration == prevdur) {
2972 /* If the current segment has duration/stop identical to previous duration
2973 * update them also (because they were set at that point in time with
2974 * the wrong duration */
2975 /* We convert the value *from* the timescale version to avoid rounding errors */
2976 GstClockTime fixeddur = QTTIME_TO_GSTTIME (qtdemux, movdur);
2977 GST_DEBUG_OBJECT (qtdemux, "Updated segment.duration and segment.stop");
2978 qtdemux->segment.duration = fixeddur;
2979 qtdemux->segment.stop = fixeddur;
2982 for (i = 0; i < qtdemux->n_streams; i++) {
2983 QtDemuxStream *stream = qtdemux->streams[i];
2985 movdur = GSTTIME_TO_QTSTREAMTIME (stream, duration);
2986 if (movdur > stream->duration) {
2987 GST_DEBUG_OBJECT (qtdemux,
2988 "Updating stream #%d duration to %" GST_TIME_FORMAT, i,
2989 GST_TIME_ARGS (duration));
2990 stream->duration = movdur;
2991 if (stream->dummy_segment) {
2992 /* Update all dummy values to new duration */
2993 stream->segments[0].stop_time = duration;
2994 stream->segments[0].duration = duration;
2995 stream->segments[0].media_stop = duration;
2997 /* let downstream know we possibly have a new stop time */
2998 if (stream->segment_index != -1) {
3001 if (qtdemux->segment.rate >= 0) {
3002 pos = stream->segment.start;
3004 pos = stream->segment.stop;
3007 gst_qtdemux_stream_update_segment (qtdemux, stream,
3008 stream->segment_index, pos, NULL, NULL);
3017 qtdemux_parse_trun (GstQTDemux * qtdemux, GstByteReader * trun,
3018 QtDemuxStream * stream, guint32 d_sample_duration, guint32 d_sample_size,
3019 guint32 d_sample_flags, gint64 moof_offset, gint64 moof_length,
3020 gint64 * base_offset, gint64 * running_offset, gint64 decode_ts)
3022 GstClockTime gst_ts = GST_CLOCK_TIME_NONE;
3024 gint32 data_offset = 0;
3025 guint32 flags = 0, first_flags = 0, samples_count = 0;
3028 guint entry_size, dur_offset, size_offset, flags_offset = 0, ct_offset = 0;
3029 QtDemuxSample *sample;
3030 gboolean ismv = FALSE;
3031 gint64 initial_offset;
3033 GST_LOG_OBJECT (qtdemux, "parsing trun stream %d; "
3034 "default dur %d, size %d, flags 0x%x, base offset %" G_GINT64_FORMAT ", "
3035 "decode ts %" G_GINT64_FORMAT, stream->track_id, d_sample_duration,
3036 d_sample_size, d_sample_flags, *base_offset, decode_ts);
3038 if (stream->pending_seek && moof_offset < stream->pending_seek->moof_offset) {
3039 GST_INFO_OBJECT (stream->pad, "skipping trun before seek target fragment");
3043 /* presence of stss or not can't really tell us much,
3044 * and flags and so on tend to be marginally reliable in these files */
3045 if (stream->subtype == FOURCC_soun) {
3046 GST_DEBUG_OBJECT (qtdemux,
3047 "sound track in fragmented file; marking all keyframes");
3048 stream->all_keyframe = TRUE;
3051 if (!gst_byte_reader_skip (trun, 1) ||
3052 !gst_byte_reader_get_uint24_be (trun, &flags))
3055 if (!gst_byte_reader_get_uint32_be (trun, &samples_count))
3058 if (flags & TR_DATA_OFFSET) {
3059 /* note this is really signed */
3060 if (!gst_byte_reader_get_int32_be (trun, &data_offset))
3062 GST_LOG_OBJECT (qtdemux, "trun data offset %d", data_offset);
3063 /* default base offset = first byte of moof */
3064 if (*base_offset == -1) {
3065 GST_LOG_OBJECT (qtdemux, "base_offset at moof");
3066 *base_offset = moof_offset;
3068 *running_offset = *base_offset + data_offset;
3070 /* if no offset at all, that would mean data starts at moof start,
3071 * which is a bit wrong and is ismv crappy way, so compensate
3072 * assuming data is in mdat following moof */
3073 if (*base_offset == -1) {
3074 *base_offset = moof_offset + moof_length + 8;
3075 GST_LOG_OBJECT (qtdemux, "base_offset assumed in mdat after moof");
3078 if (*running_offset == -1)
3079 *running_offset = *base_offset;
3082 GST_LOG_OBJECT (qtdemux, "running offset now %" G_GINT64_FORMAT,
3084 GST_LOG_OBJECT (qtdemux, "trun offset %d, flags 0x%x, entries %d",
3085 data_offset, flags, samples_count);
3087 if (flags & TR_FIRST_SAMPLE_FLAGS) {
3088 if (G_UNLIKELY (flags & TR_SAMPLE_FLAGS)) {
3089 GST_DEBUG_OBJECT (qtdemux,
3090 "invalid flags; SAMPLE and FIRST_SAMPLE present, discarding latter");
3091 flags ^= TR_FIRST_SAMPLE_FLAGS;
3093 if (!gst_byte_reader_get_uint32_be (trun, &first_flags))
3095 GST_LOG_OBJECT (qtdemux, "first flags: 0x%x", first_flags);
3099 /* FIXME ? spec says other bits should also be checked to determine
3100 * entry size (and prefix size for that matter) */
3102 dur_offset = size_offset = 0;
3103 if (flags & TR_SAMPLE_DURATION) {
3104 GST_LOG_OBJECT (qtdemux, "entry duration present");
3105 dur_offset = entry_size;
3108 if (flags & TR_SAMPLE_SIZE) {
3109 GST_LOG_OBJECT (qtdemux, "entry size present");
3110 size_offset = entry_size;
3113 if (flags & TR_SAMPLE_FLAGS) {
3114 GST_LOG_OBJECT (qtdemux, "entry flags present");
3115 flags_offset = entry_size;
3118 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
3119 GST_LOG_OBJECT (qtdemux, "entry ct offset present");
3120 ct_offset = entry_size;
3124 if (!qt_atom_parser_has_chunks (trun, samples_count, entry_size))
3126 data = (guint8 *) gst_byte_reader_peek_data_unchecked (trun);
3128 if (stream->n_samples + samples_count >=
3129 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample))
3132 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
3133 stream->n_samples + samples_count, (guint) sizeof (QtDemuxSample),
3134 (stream->n_samples + samples_count) *
3135 sizeof (QtDemuxSample) / (1024.0 * 1024.0));
3137 /* create a new array of samples if it's the first sample parsed */
3138 if (stream->n_samples == 0) {
3139 g_assert (stream->samples == NULL);
3140 stream->samples = g_try_new0 (QtDemuxSample, samples_count);
3141 /* or try to reallocate it with space enough to insert the new samples */
3143 stream->samples = g_try_renew (QtDemuxSample, stream->samples,
3144 stream->n_samples + samples_count);
3145 if (stream->samples == NULL)
3148 if (qtdemux->fragment_start != -1) {
3149 timestamp = GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->fragment_start);
3150 qtdemux->fragment_start = -1;
3152 if (stream->n_samples == 0) {
3153 if (decode_ts > 0) {
3154 timestamp = decode_ts;
3155 } else if (stream->pending_seek != NULL) {
3156 /* if we don't have a timestamp from a tfdt box, we'll use the one
3157 * from the mfra seek table */
3158 GST_INFO_OBJECT (stream->pad, "pending seek ts = %" GST_TIME_FORMAT,
3159 GST_TIME_ARGS (stream->pending_seek->ts));
3161 /* FIXME: this is not fully correct, the timestamp refers to the random
3162 * access sample refered to in the tfra entry, which may not necessarily
3163 * be the first sample in the tfrag/trun (but hopefully/usually is) */
3164 timestamp = GSTTIME_TO_QTSTREAMTIME (stream, stream->pending_seek->ts);
3169 gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
3170 GST_INFO_OBJECT (stream->pad, "first sample ts %" GST_TIME_FORMAT,
3171 GST_TIME_ARGS (gst_ts));
3173 /* subsequent fragments extend stream */
3175 stream->samples[stream->n_samples - 1].timestamp +
3176 stream->samples[stream->n_samples - 1].duration;
3178 /* If this is a GST_FORMAT_BYTES stream and there's a significant
3179 * difference (1 sec.) between decode_ts and timestamp, prefer the
3181 if (decode_ts != 0 && !qtdemux->upstream_format_is_time
3182 && ABSDIFF (decode_ts, timestamp) >
3183 MAX (stream->duration_last_moof / 2,
3184 GSTTIME_TO_QTSTREAMTIME (stream, GST_SECOND))) {
3185 GST_INFO_OBJECT (qtdemux,
3186 "decode_ts (%" GST_TIME_FORMAT ") and timestamp (%" GST_TIME_FORMAT
3187 ") are significantly different (more than %" GST_TIME_FORMAT
3188 "), using decode_ts",
3189 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, decode_ts)),
3190 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, timestamp)),
3191 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream,
3192 MAX (stream->duration_last_moof / 2,
3193 GSTTIME_TO_QTSTREAMTIME (stream, GST_SECOND)))));
3194 timestamp = decode_ts;
3197 gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
3198 GST_INFO_OBJECT (qtdemux, "first sample ts %" GST_TIME_FORMAT
3199 " (extends previous samples)", GST_TIME_ARGS (gst_ts));
3203 initial_offset = *running_offset;
3205 sample = stream->samples + stream->n_samples;
3206 for (i = 0; i < samples_count; i++) {
3207 guint32 dur, size, sflags, ct;
3209 /* first read sample data */
3210 if (flags & TR_SAMPLE_DURATION) {
3211 dur = QT_UINT32 (data + dur_offset);
3213 dur = d_sample_duration;
3215 if (flags & TR_SAMPLE_SIZE) {
3216 size = QT_UINT32 (data + size_offset);
3218 size = d_sample_size;
3220 if (flags & TR_FIRST_SAMPLE_FLAGS) {
3222 sflags = first_flags;
3224 sflags = d_sample_flags;
3226 } else if (flags & TR_SAMPLE_FLAGS) {
3227 sflags = QT_UINT32 (data + flags_offset);
3229 sflags = d_sample_flags;
3231 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
3232 ct = QT_UINT32 (data + ct_offset);
3238 /* fill the sample information */
3239 sample->offset = *running_offset;
3240 sample->pts_offset = ct;
3241 sample->size = size;
3242 sample->timestamp = timestamp;
3243 sample->duration = dur;
3244 /* sample-is-difference-sample */
3245 /* ismv seems to use 0x40 for keyframe, 0xc0 for non-keyframe,
3246 * now idea how it relates to bitfield other than massive LE/BE confusion */
3247 sample->keyframe = ismv ? ((sflags & 0xff) == 0x40) : !(sflags & 0x10000);
3248 *running_offset += size;
3250 stream->duration_moof += dur;
3254 /* Update total duration if needed */
3255 check_update_duration (qtdemux, QTSTREAMTIME_TO_GSTTIME (stream, timestamp));
3257 /* Pre-emptively figure out size of mdat based on trun information.
3258 * If the [mdat] atom is effectivelly read, it will be replaced by the actual
3259 * size, else we will still be able to use this when dealing with gap'ed
3261 qtdemux->mdatleft = *running_offset - initial_offset;
3263 stream->n_samples += samples_count;
3264 stream->n_samples_moof += samples_count;
3266 if (stream->pending_seek != NULL)
3267 stream->pending_seek = NULL;
3273 GST_WARNING_OBJECT (qtdemux, "failed to parse trun");
3278 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
3284 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
3285 "be larger than %uMB (broken file?)", stream->n_samples,
3286 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
3291 /* find stream with @id */
3292 static inline QtDemuxStream *
3293 qtdemux_find_stream (GstQTDemux * qtdemux, guint32 id)
3295 QtDemuxStream *stream;
3299 if (G_UNLIKELY (!id)) {
3300 GST_DEBUG_OBJECT (qtdemux, "invalid track id 0");
3304 /* try to get it fast and simple */
3305 if (G_LIKELY (id <= qtdemux->n_streams)) {
3306 stream = qtdemux->streams[id - 1];
3307 if (G_LIKELY (stream->track_id == id))
3311 /* linear search otherwise */
3312 for (i = 0; i < qtdemux->n_streams; i++) {
3313 stream = qtdemux->streams[i];
3314 if (stream->track_id == id)
3317 if (qtdemux->mss_mode) {
3318 /* mss should have only 1 stream anyway */
3319 return qtdemux->streams[0];
3326 qtdemux_parse_mfhd (GstQTDemux * qtdemux, GstByteReader * mfhd,
3327 guint32 * fragment_number)
3329 if (!gst_byte_reader_skip (mfhd, 4))
3331 if (!gst_byte_reader_get_uint32_be (mfhd, fragment_number))
3336 GST_WARNING_OBJECT (qtdemux, "Failed to parse mfhd atom");
3342 qtdemux_parse_tfhd (GstQTDemux * qtdemux, GstByteReader * tfhd,
3343 QtDemuxStream ** stream, guint32 * default_sample_duration,
3344 guint32 * default_sample_size, guint32 * default_sample_flags,
3345 gint64 * base_offset)
3348 guint32 track_id = 0;
3350 if (!gst_byte_reader_skip (tfhd, 1) ||
3351 !gst_byte_reader_get_uint24_be (tfhd, &flags))
3354 if (!gst_byte_reader_get_uint32_be (tfhd, &track_id))
3357 *stream = qtdemux_find_stream (qtdemux, track_id);
3358 if (G_UNLIKELY (!*stream))
3359 goto unknown_stream;
3361 if (flags & TF_DEFAULT_BASE_IS_MOOF)
3362 *base_offset = qtdemux->moof_offset;
3364 if (flags & TF_BASE_DATA_OFFSET)
3365 if (!gst_byte_reader_get_uint64_be (tfhd, (guint64 *) base_offset))
3368 /* obtain stream defaults */
3369 qtdemux_parse_trex (qtdemux, *stream,
3370 default_sample_duration, default_sample_size, default_sample_flags);
3372 /* FIXME: Handle TF_SAMPLE_DESCRIPTION_INDEX properly */
3373 if (flags & TF_SAMPLE_DESCRIPTION_INDEX)
3374 if (!gst_byte_reader_skip (tfhd, 4))
3377 if (flags & TF_DEFAULT_SAMPLE_DURATION)
3378 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_duration))
3381 if (flags & TF_DEFAULT_SAMPLE_SIZE)
3382 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_size))
3385 if (flags & TF_DEFAULT_SAMPLE_FLAGS)
3386 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_flags))
3393 GST_WARNING_OBJECT (qtdemux, "invalid track fragment header");
3398 GST_DEBUG_OBJECT (qtdemux, "unknown stream in tfhd");
3404 qtdemux_parse_tfdt (GstQTDemux * qtdemux, GstByteReader * br,
3405 guint64 * decode_time)
3407 guint32 version = 0;
3409 if (!gst_byte_reader_get_uint32_be (br, &version))
3414 if (!gst_byte_reader_get_uint64_be (br, decode_time))
3417 guint32 dec_time = 0;
3418 if (!gst_byte_reader_get_uint32_be (br, &dec_time))
3420 *decode_time = dec_time;
3423 GST_INFO_OBJECT (qtdemux, "Track fragment decode time: %" G_GUINT64_FORMAT,
3430 GST_DEBUG_OBJECT (qtdemux, "parsing tfdt failed");
3435 /* Returns a pointer to a GstStructure containing the properties of
3436 * the stream sample identified by @sample_index. The caller must unref
3437 * the returned object after use. Returns NULL if unsuccessful. */
3438 static GstStructure *
3439 qtdemux_get_cenc_sample_properties (GstQTDemux * qtdemux,
3440 QtDemuxStream * stream, guint sample_index)
3442 QtDemuxCencSampleSetInfo *info = NULL;
3444 g_return_val_if_fail (stream != NULL, NULL);
3445 g_return_val_if_fail (stream->protected, NULL);
3446 g_return_val_if_fail (stream->protection_scheme_info != NULL, NULL);
3448 info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
3450 /* Currently, cenc properties for groups of samples are not supported, so
3451 * simply return a copy of the default sample properties */
3452 return gst_structure_copy (info->default_properties);
3455 /* Parses the sizes of sample auxiliary information contained within a stream,
3456 * as given in a saiz box. Returns array of sample_count guint8 size values,
3457 * or NULL on failure */
3459 qtdemux_parse_saiz (GstQTDemux * qtdemux, QtDemuxStream * stream,
3460 GstByteReader * br, guint32 * sample_count)
3464 guint8 default_info_size;
3466 g_return_val_if_fail (qtdemux != NULL, NULL);
3467 g_return_val_if_fail (stream != NULL, NULL);
3468 g_return_val_if_fail (br != NULL, NULL);
3469 g_return_val_if_fail (sample_count != NULL, NULL);
3471 if (!gst_byte_reader_get_uint32_be (br, &flags))
3475 /* aux_info_type and aux_info_type_parameter are ignored */
3476 if (!gst_byte_reader_skip (br, 8))
3480 if (!gst_byte_reader_get_uint8 (br, &default_info_size))
3482 GST_DEBUG_OBJECT (qtdemux, "default_info_size: %u", default_info_size);
3484 if (!gst_byte_reader_get_uint32_be (br, sample_count))
3486 GST_DEBUG_OBJECT (qtdemux, "sample_count: %u", *sample_count);
3489 if (default_info_size == 0) {
3490 if (!gst_byte_reader_dup_data (br, *sample_count, &info_sizes)) {
3494 info_sizes = g_new (guint8, *sample_count);
3495 memset (info_sizes, default_info_size, *sample_count);
3501 /* Parses the offset of sample auxiliary information contained within a stream,
3502 * as given in a saio box. Returns TRUE if successful; FALSE otherwise. */
3504 qtdemux_parse_saio (GstQTDemux * qtdemux, QtDemuxStream * stream,
3505 GstByteReader * br, guint32 * info_type, guint32 * info_type_parameter,
3510 guint32 aux_info_type = 0;
3511 guint32 aux_info_type_parameter = 0;
3512 guint32 entry_count;
3515 const guint8 *aux_info_type_data = NULL;
3517 g_return_val_if_fail (qtdemux != NULL, FALSE);
3518 g_return_val_if_fail (stream != NULL, FALSE);
3519 g_return_val_if_fail (br != NULL, FALSE);
3520 g_return_val_if_fail (offset != NULL, FALSE);
3522 if (!gst_byte_reader_get_uint8 (br, &version))
3525 if (!gst_byte_reader_get_uint24_be (br, &flags))
3530 if (!gst_byte_reader_get_data (br, 4, &aux_info_type_data))
3532 aux_info_type = QT_FOURCC (aux_info_type_data);
3534 if (!gst_byte_reader_get_uint32_be (br, &aux_info_type_parameter))
3536 } else if (stream->protected) {
3537 aux_info_type = stream->protection_scheme_type;
3539 aux_info_type = stream->fourcc;
3543 *info_type = aux_info_type;
3544 if (info_type_parameter)
3545 *info_type_parameter = aux_info_type_parameter;
3547 GST_DEBUG_OBJECT (qtdemux, "aux_info_type: '%" GST_FOURCC_FORMAT "', "
3548 "aux_info_type_parameter: %#06x",
3549 GST_FOURCC_ARGS (aux_info_type), aux_info_type_parameter);
3551 if (!gst_byte_reader_get_uint32_be (br, &entry_count))
3554 if (entry_count != 1) {
3555 GST_ERROR_OBJECT (qtdemux, "multiple offsets are not supported");
3560 if (!gst_byte_reader_get_uint32_be (br, &off_32))
3562 *offset = (guint64) off_32;
3564 if (!gst_byte_reader_get_uint64_be (br, &off_64))
3569 GST_DEBUG_OBJECT (qtdemux, "offset: %" G_GUINT64_FORMAT, *offset);
3574 qtdemux_gst_structure_free (GstStructure * gststructure)
3577 gst_structure_free (gststructure);
3581 /* Parses auxiliary information relating to samples protected using Common
3582 * Encryption (cenc); the format of this information is defined in
3583 * ISO/IEC 23001-7. Returns TRUE if successful; FALSE otherwise. */
3585 qtdemux_parse_cenc_aux_info (GstQTDemux * qtdemux, QtDemuxStream * stream,
3586 GstByteReader * br, guint8 * info_sizes, guint32 sample_count)
3588 QtDemuxCencSampleSetInfo *ss_info = NULL;
3592 g_return_val_if_fail (qtdemux != NULL, FALSE);
3593 g_return_val_if_fail (stream != NULL, FALSE);
3594 g_return_val_if_fail (br != NULL, FALSE);
3595 g_return_val_if_fail (stream->protected, FALSE);
3596 g_return_val_if_fail (stream->protection_scheme_info != NULL, FALSE);
3598 ss_info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
3600 if (ss_info->crypto_info) {
3601 GST_LOG_OBJECT (qtdemux, "unreffing existing crypto_info");
3602 g_ptr_array_free (ss_info->crypto_info, TRUE);
3605 ss_info->crypto_info =
3606 g_ptr_array_new_full (sample_count,
3607 (GDestroyNotify) qtdemux_gst_structure_free);
3609 for (i = 0; i < sample_count; ++i) {
3610 GstStructure *properties;
3611 guint16 n_subsamples = 0;
3616 properties = qtdemux_get_cenc_sample_properties (qtdemux, stream, i);
3617 if (properties == NULL) {
3618 GST_ERROR_OBJECT (qtdemux, "failed to get properties for sample %u", i);
3621 if (!gst_structure_get_uint (properties, "iv_size", &iv_size)) {
3622 GST_ERROR_OBJECT (qtdemux, "failed to get iv_size for sample %u", i);
3623 gst_structure_free (properties);
3626 if (!gst_byte_reader_dup_data (br, iv_size, &data)) {
3627 GST_ERROR_OBJECT (qtdemux, "failed to get IV for sample %u", i);
3628 gst_structure_free (properties);
3631 buf = gst_buffer_new_wrapped (data, iv_size);
3632 gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL);
3633 gst_buffer_unref (buf);
3634 size = info_sizes[i];
3635 if (size > iv_size) {
3636 if (!gst_byte_reader_get_uint16_be (br, &n_subsamples)
3637 || !(n_subsamples > 0)) {
3638 gst_structure_free (properties);
3639 GST_ERROR_OBJECT (qtdemux,
3640 "failed to get subsample count for sample %u", i);
3643 GST_LOG_OBJECT (qtdemux, "subsample count: %u", n_subsamples);
3644 if (!gst_byte_reader_dup_data (br, n_subsamples * 6, &data)) {
3645 GST_ERROR_OBJECT (qtdemux, "failed to get subsample data for sample %u",
3647 gst_structure_free (properties);
3650 buf = gst_buffer_new_wrapped (data, n_subsamples * 6);
3652 gst_structure_free (properties);
3655 gst_structure_set (properties,
3656 "subsample_count", G_TYPE_UINT, n_subsamples,
3657 "subsamples", GST_TYPE_BUFFER, buf, NULL);
3658 gst_buffer_unref (buf);
3660 gst_structure_set (properties, "subsample_count", G_TYPE_UINT, 0, NULL);
3662 g_ptr_array_add (ss_info->crypto_info, properties);
3667 /* Converts a UUID in raw byte form to a string representation, as defined in
3668 * RFC 4122. The caller takes ownership of the returned string and is
3669 * responsible for freeing it after use. */
3671 qtdemux_uuid_bytes_to_string (gconstpointer uuid_bytes)
3673 const guint8 *uuid = (const guint8 *) uuid_bytes;
3675 return g_strdup_printf ("%02x%02x%02x%02x-%02x%02x-%02x%02x-"
3676 "%02x%02x-%02x%02x%02x%02x%02x%02x",
3677 uuid[0], uuid[1], uuid[2], uuid[3],
3678 uuid[4], uuid[5], uuid[6], uuid[7],
3679 uuid[8], uuid[9], uuid[10], uuid[11],
3680 uuid[12], uuid[13], uuid[14], uuid[15]);
3683 /* Parses a Protection System Specific Header box (pssh), as defined in the
3684 * Common Encryption (cenc) standard (ISO/IEC 23001-7), which contains
3685 * information needed by a specific content protection system in order to
3686 * decrypt cenc-protected tracks. Returns TRUE if successful; FALSE
3689 qtdemux_parse_pssh (GstQTDemux * qtdemux, GNode * node)
3691 gchar *sysid_string;
3692 guint32 pssh_size = QT_UINT32 (node->data);
3693 GstBuffer *pssh = NULL;
3694 GstEvent *event = NULL;
3695 guint32 parent_box_type;
3698 if (G_UNLIKELY (pssh_size < 32U)) {
3699 GST_ERROR_OBJECT (qtdemux, "invalid box size");
3704 qtdemux_uuid_bytes_to_string ((const guint8 *) node->data + 12);
3706 gst_qtdemux_append_protection_system_id (qtdemux, sysid_string);
3708 pssh = gst_buffer_new_wrapped (g_memdup (node->data, pssh_size), pssh_size);
3709 GST_LOG_OBJECT (qtdemux, "cenc pssh size: %" G_GSIZE_FORMAT,
3710 gst_buffer_get_size (pssh));
3712 parent_box_type = QT_FOURCC ((const guint8 *) node->parent->data + 4);
3714 /* Push an event containing the pssh box onto the queues of all streams. */
3715 event = gst_event_new_protection (sysid_string, pssh,
3716 (parent_box_type == FOURCC_moov) ? "isobmff/moov" : "isobmff/moof");
3717 for (i = 0; i < qtdemux->n_streams; ++i) {
3718 g_queue_push_tail (&qtdemux->streams[i]->protection_scheme_event_queue,
3719 gst_event_ref (event));
3721 g_free (sysid_string);
3722 gst_event_unref (event);
3723 gst_buffer_unref (pssh);
3728 qtdemux_parse_moof (GstQTDemux * qtdemux, const guint8 * buffer, guint length,
3729 guint64 moof_offset, QtDemuxStream * stream)
3731 GNode *moof_node, *traf_node, *tfhd_node, *trun_node, *tfdt_node, *mfhd_node;
3733 GstByteReader mfhd_data, trun_data, tfhd_data, tfdt_data;
3734 GNode *saiz_node, *saio_node, *pssh_node;
3735 GstByteReader saiz_data, saio_data;
3736 guint32 ds_size = 0, ds_duration = 0, ds_flags = 0;
3737 gint64 base_offset, running_offset;
3740 /* NOTE @stream ignored */
3742 moof_node = g_node_new ((guint8 *) buffer);
3743 qtdemux_parse_node (qtdemux, moof_node, buffer, length);
3744 qtdemux_node_dump (qtdemux, moof_node);
3746 /* Get fragment number from mfhd and check it's valid */
3748 qtdemux_tree_get_child_by_type_full (moof_node, FOURCC_mfhd, &mfhd_data);
3749 if (mfhd_node == NULL)
3751 if (!qtdemux_parse_mfhd (qtdemux, &mfhd_data, &frag_num))
3753 GST_DEBUG_OBJECT (qtdemux, "Fragment #%d", frag_num);
3755 /* unknown base_offset to start with */
3756 base_offset = running_offset = -1;
3757 traf_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_traf);
3759 guint64 decode_time = 0;
3761 /* Fragment Header node */
3763 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfhd,
3767 if (!qtdemux_parse_tfhd (qtdemux, &tfhd_data, &stream, &ds_duration,
3768 &ds_size, &ds_flags, &base_offset))
3771 /* The following code assumes at most a single set of sample auxiliary
3772 * data in the fragment (consisting of a saiz box and a corresponding saio
3773 * box); in theory, however, there could be multiple sets of sample
3774 * auxiliary data in a fragment. */
3776 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saiz,
3779 guint32 info_type = 0;
3781 guint32 info_type_parameter = 0;
3783 g_free (qtdemux->cenc_aux_info_sizes);
3785 qtdemux->cenc_aux_info_sizes =
3786 qtdemux_parse_saiz (qtdemux, stream, &saiz_data,
3787 &qtdemux->cenc_aux_sample_count);
3788 if (qtdemux->cenc_aux_info_sizes == NULL) {
3789 GST_ERROR_OBJECT (qtdemux, "failed to parse saiz box");
3793 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saio,
3796 GST_ERROR_OBJECT (qtdemux, "saiz box without a corresponding saio box");
3797 g_free (qtdemux->cenc_aux_info_sizes);
3798 qtdemux->cenc_aux_info_sizes = NULL;
3802 if (G_UNLIKELY (!qtdemux_parse_saio (qtdemux, stream, &saio_data,
3803 &info_type, &info_type_parameter, &offset))) {
3804 GST_ERROR_OBJECT (qtdemux, "failed to parse saio box");
3805 g_free (qtdemux->cenc_aux_info_sizes);
3806 qtdemux->cenc_aux_info_sizes = NULL;
3809 if (base_offset > -1 && base_offset > qtdemux->moof_offset)
3810 offset += (guint64) (base_offset - qtdemux->moof_offset);
3811 if (info_type == FOURCC_cenc && info_type_parameter == 0U) {
3813 if (offset > length) {
3814 GST_DEBUG_OBJECT (qtdemux, "cenc auxiliary info stored out of moof");
3815 qtdemux->cenc_aux_info_offset = offset;
3817 gst_byte_reader_init (&br, buffer + offset, length - offset);
3818 if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
3819 qtdemux->cenc_aux_info_sizes,
3820 qtdemux->cenc_aux_sample_count)) {
3821 GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
3822 g_free (qtdemux->cenc_aux_info_sizes);
3823 qtdemux->cenc_aux_info_sizes = NULL;
3831 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfdt,
3834 /* We'll use decode_time to interpolate timestamps
3835 * in case the input timestamps are missing */
3836 qtdemux_parse_tfdt (qtdemux, &tfdt_data, &decode_time);
3838 GST_DEBUG_OBJECT (qtdemux, "decode time %" G_GINT64_FORMAT
3839 " (%" GST_TIME_FORMAT ")", decode_time,
3840 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, decode_time)));
3842 /* Discard the fragment buffer timestamp info to avoid using it.
3843 * Rely on tfdt instead as it is more accurate than the timestamp
3844 * that is fetched from a manifest/playlist and is usually
3846 qtdemux->fragment_start = -1;
3849 if (G_UNLIKELY (!stream)) {
3850 /* we lost track of offset, we'll need to regain it,
3851 * but can delay complaining until later or avoid doing so altogether */
3855 if (G_UNLIKELY (base_offset < -1))
3858 if (qtdemux->upstream_format_is_time)
3859 gst_qtdemux_stream_flush_samples_data (qtdemux, stream);
3861 /* initialise moof sample data */
3862 stream->n_samples_moof = 0;
3863 stream->duration_last_moof = stream->duration_moof;
3864 stream->duration_moof = 0;
3866 /* Track Run node */
3868 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_trun,
3871 qtdemux_parse_trun (qtdemux, &trun_data, stream,
3872 ds_duration, ds_size, ds_flags, moof_offset, length, &base_offset,
3873 &running_offset, decode_time);
3874 /* iterate all siblings */
3875 trun_node = qtdemux_tree_get_sibling_by_type_full (trun_node, FOURCC_trun,
3879 uuid_node = qtdemux_tree_get_child_by_type (traf_node, FOURCC_uuid);
3881 guint8 *uuid_buffer = (guint8 *) uuid_node->data;
3882 guint32 box_length = QT_UINT32 (uuid_buffer);
3884 qtdemux_parse_uuid (qtdemux, uuid_buffer, box_length);
3887 /* if no new base_offset provided for next traf,
3888 * base is end of current traf */
3889 base_offset = running_offset;
3890 running_offset = -1;
3892 if (stream->n_samples_moof && stream->duration_moof)
3893 stream->new_caps = TRUE;
3896 /* iterate all siblings */
3897 traf_node = qtdemux_tree_get_sibling_by_type (traf_node, FOURCC_traf);
3900 /* parse any protection system info */
3901 pssh_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_pssh);
3903 GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
3904 qtdemux_parse_pssh (qtdemux, pssh_node);
3905 pssh_node = qtdemux_tree_get_sibling_by_type (pssh_node, FOURCC_pssh);
3908 g_node_destroy (moof_node);
3913 GST_DEBUG_OBJECT (qtdemux, "missing tfhd box");
3918 GST_DEBUG_OBJECT (qtdemux, "Missing mfhd box");
3923 GST_DEBUG_OBJECT (qtdemux, "lost offset");
3928 g_node_destroy (moof_node);
3929 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
3930 (_("This file is corrupt and cannot be played.")), (NULL));
3936 /* might be used if some day we actually use mfra & co
3937 * for random access to fragments,
3938 * but that will require quite some modifications and much less relying
3939 * on a sample array */
3943 qtdemux_parse_tfra (GstQTDemux * qtdemux, GNode * tfra_node)
3945 QtDemuxStream *stream;
3946 guint32 ver_flags, track_id, len, num_entries, i;
3947 guint value_size, traf_size, trun_size, sample_size;
3948 guint64 time = 0, moof_offset = 0;
3950 GstBuffer *buf = NULL;
3955 gst_byte_reader_init (&tfra, tfra_node->data, QT_UINT32 (tfra_node->data));
3957 if (!gst_byte_reader_skip (&tfra, 8))
3960 if (!gst_byte_reader_get_uint32_be (&tfra, &ver_flags))
3963 if (!gst_byte_reader_get_uint32_be (&tfra, &track_id)
3964 || !gst_byte_reader_get_uint32_be (&tfra, &len)
3965 || !gst_byte_reader_get_uint32_be (&tfra, &num_entries))
3968 GST_DEBUG_OBJECT (qtdemux, "parsing tfra box for track id %u", track_id);
3970 stream = qtdemux_find_stream (qtdemux, track_id);
3972 goto unknown_trackid;
3974 value_size = ((ver_flags >> 24) == 1) ? sizeof (guint64) : sizeof (guint32);
3975 sample_size = (len & 3) + 1;
3976 trun_size = ((len & 12) >> 2) + 1;
3977 traf_size = ((len & 48) >> 4) + 1;
3979 GST_DEBUG_OBJECT (qtdemux, "%u entries, sizes: value %u, traf %u, trun %u, "
3980 "sample %u", num_entries, value_size, traf_size, trun_size, sample_size);
3982 if (num_entries == 0)
3985 if (!qt_atom_parser_has_chunks (&tfra, num_entries,
3986 value_size + value_size + traf_size + trun_size + sample_size))
3989 g_free (stream->ra_entries);
3990 stream->ra_entries = g_new (QtDemuxRandomAccessEntry, num_entries);
3991 stream->n_ra_entries = num_entries;
3993 for (i = 0; i < num_entries; i++) {
3994 qt_atom_parser_get_offset (&tfra, value_size, &time);
3995 qt_atom_parser_get_offset (&tfra, value_size, &moof_offset);
3996 qt_atom_parser_get_uint_with_size_unchecked (&tfra, traf_size);
3997 qt_atom_parser_get_uint_with_size_unchecked (&tfra, trun_size);
3998 qt_atom_parser_get_uint_with_size_unchecked (&tfra, sample_size);
4000 time = QTSTREAMTIME_TO_GSTTIME (stream, time);
4002 GST_LOG_OBJECT (qtdemux, "fragment time: %" GST_TIME_FORMAT ", "
4003 " moof_offset: %" G_GUINT64_FORMAT, GST_TIME_ARGS (time), moof_offset);
4005 stream->ra_entries[i].ts = time;
4006 stream->ra_entries[i].moof_offset = moof_offset;
4008 /* don't want to go through the entire file and read all moofs at startup */
4010 ret = gst_qtdemux_pull_atom (qtdemux, moof_offset, 0, &buf);
4011 if (ret != GST_FLOW_OK)
4013 qtdemux_parse_moof (qtdemux, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf),
4014 moof_offset, stream);
4015 gst_buffer_unref (buf);
4019 check_update_duration (qtdemux, time);
4026 GST_WARNING_OBJECT (qtdemux, "Couldn't find stream for track %u", track_id);
4031 GST_WARNING_OBJECT (qtdemux, "broken traf box, ignoring");
4036 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
4042 qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux)
4044 GstMapInfo mfro_map = GST_MAP_INFO_INIT;
4045 GstMapInfo mfra_map = GST_MAP_INFO_INIT;
4046 GstBuffer *mfro = NULL, *mfra = NULL;
4048 gboolean ret = FALSE;
4049 GNode *mfra_node, *tfra_node;
4050 guint64 mfra_offset = 0;
4051 guint32 fourcc, mfra_size;
4054 /* query upstream size in bytes */
4055 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &len))
4056 goto size_query_failed;
4058 /* mfro box should be at the very end of the file */
4059 flow = gst_qtdemux_pull_atom (qtdemux, len - 16, 16, &mfro);
4060 if (flow != GST_FLOW_OK)
4063 gst_buffer_map (mfro, &mfro_map, GST_MAP_READ);
4065 fourcc = QT_FOURCC (mfro_map.data + 4);
4066 if (fourcc != FOURCC_mfro)
4069 GST_INFO_OBJECT (qtdemux, "Found mfro box");
4070 if (mfro_map.size < 16)
4071 goto invalid_mfro_size;
4073 mfra_size = QT_UINT32 (mfro_map.data + 12);
4074 if (mfra_size >= len)
4075 goto invalid_mfra_size;
4077 mfra_offset = len - mfra_size;
4079 GST_INFO_OBJECT (qtdemux, "mfra offset: %" G_GUINT64_FORMAT ", size %u",
4080 mfra_offset, mfra_size);
4082 /* now get and parse mfra box */
4083 flow = gst_qtdemux_pull_atom (qtdemux, mfra_offset, mfra_size, &mfra);
4084 if (flow != GST_FLOW_OK)
4087 gst_buffer_map (mfra, &mfra_map, GST_MAP_READ);
4089 mfra_node = g_node_new ((guint8 *) mfra_map.data);
4090 qtdemux_parse_node (qtdemux, mfra_node, mfra_map.data, mfra_map.size);
4092 tfra_node = qtdemux_tree_get_child_by_type (mfra_node, FOURCC_tfra);
4095 qtdemux_parse_tfra (qtdemux, tfra_node);
4096 /* iterate all siblings */
4097 tfra_node = qtdemux_tree_get_sibling_by_type (tfra_node, FOURCC_tfra);
4099 g_node_destroy (mfra_node);
4101 GST_INFO_OBJECT (qtdemux, "parsed movie fragment random access box (mfra)");
4107 if (mfro_map.memory != NULL)
4108 gst_buffer_unmap (mfro, &mfro_map);
4109 gst_buffer_unref (mfro);
4112 if (mfra_map.memory != NULL)
4113 gst_buffer_unmap (mfra, &mfra_map);
4114 gst_buffer_unref (mfra);
4121 GST_WARNING_OBJECT (qtdemux, "could not query upstream size");
4126 GST_WARNING_OBJECT (qtdemux, "mfro size is too small");
4131 GST_WARNING_OBJECT (qtdemux, "mfra_size in mfro box is invalid");
4136 GST_WARNING_OBJECT (qtdemux, "bogus mfra offset or size, broken file");
4142 add_offset (guint64 offset, guint64 advance)
4144 /* Avoid 64-bit overflow by clamping */
4145 if (offset > G_MAXUINT64 - advance)
4147 return offset + advance;
4150 static GstFlowReturn
4151 gst_qtdemux_loop_state_header (GstQTDemux * qtdemux)
4155 GstBuffer *buf = NULL;
4156 GstFlowReturn ret = GST_FLOW_OK;
4157 guint64 cur_offset = qtdemux->offset;
4160 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, 16, &buf);
4161 if (G_UNLIKELY (ret != GST_FLOW_OK))
4163 gst_buffer_map (buf, &map, GST_MAP_READ);
4164 if (G_LIKELY (map.size >= 8))
4165 extract_initial_length_and_fourcc (map.data, map.size, &length, &fourcc);
4166 gst_buffer_unmap (buf, &map);
4167 gst_buffer_unref (buf);
4169 /* maybe we already got most we needed, so only consider this eof */
4170 if (G_UNLIKELY (length == 0)) {
4171 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
4172 (_("Invalid atom size.")),
4173 ("Header atom '%" GST_FOURCC_FORMAT "' has empty length",
4174 GST_FOURCC_ARGS (fourcc)));
4181 /* record for later parsing when needed */
4182 if (!qtdemux->moof_offset) {
4183 qtdemux->moof_offset = qtdemux->offset;
4185 if (qtdemux_pull_mfro_mfra (qtdemux)) {
4188 qtdemux->offset += length; /* skip moof and keep going */
4190 if (qtdemux->got_moov) {
4191 GST_INFO_OBJECT (qtdemux, "moof header, got moov, done with headers");
4202 GST_LOG_OBJECT (qtdemux,
4203 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
4204 GST_FOURCC_ARGS (fourcc), cur_offset);
4205 qtdemux->offset = add_offset (qtdemux->offset, length);
4210 GstBuffer *moov = NULL;
4212 if (qtdemux->got_moov) {
4213 GST_DEBUG_OBJECT (qtdemux, "Skipping moov atom as we have one already");
4214 qtdemux->offset = add_offset (qtdemux->offset, length);
4218 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, length, &moov);
4219 if (ret != GST_FLOW_OK)
4221 gst_buffer_map (moov, &map, GST_MAP_READ);
4223 if (length != map.size) {
4224 /* Some files have a 'moov' atom at the end of the file which contains
4225 * a terminal 'free' atom where the body of the atom is missing.
4226 * Check for, and permit, this special case.
4228 if (map.size >= 8) {
4229 guint8 *final_data = map.data + (map.size - 8);
4230 guint32 final_length = QT_UINT32 (final_data);
4231 guint32 final_fourcc = QT_FOURCC (final_data + 4);
4233 if (final_fourcc == FOURCC_free
4234 && map.size + final_length - 8 == length) {
4235 /* Ok, we've found that special case. Allocate a new buffer with
4236 * that free atom actually present. */
4237 GstBuffer *newmoov = gst_buffer_new_and_alloc (length);
4238 gst_buffer_fill (newmoov, 0, map.data, map.size);
4239 gst_buffer_memset (newmoov, map.size, 0, final_length - 8);
4240 gst_buffer_unmap (moov, &map);
4241 gst_buffer_unref (moov);
4243 gst_buffer_map (moov, &map, GST_MAP_READ);
4248 if (length != map.size) {
4249 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4250 (_("This file is incomplete and cannot be played.")),
4251 ("We got less than expected (received %" G_GSIZE_FORMAT
4252 ", wanted %u, offset %" G_GUINT64_FORMAT ")", map.size,
4253 (guint) length, cur_offset));
4254 gst_buffer_unmap (moov, &map);
4255 gst_buffer_unref (moov);
4256 ret = GST_FLOW_ERROR;
4259 qtdemux->offset += length;
4261 qtdemux_parse_moov (qtdemux, map.data, length);
4262 qtdemux_node_dump (qtdemux, qtdemux->moov_node);
4264 qtdemux_parse_tree (qtdemux);
4265 if (qtdemux->moov_node_compressed) {
4266 g_node_destroy (qtdemux->moov_node_compressed);
4267 g_free (qtdemux->moov_node->data);
4269 qtdemux->moov_node_compressed = NULL;
4270 g_node_destroy (qtdemux->moov_node);
4271 qtdemux->moov_node = NULL;
4272 gst_buffer_unmap (moov, &map);
4273 gst_buffer_unref (moov);
4274 qtdemux->got_moov = TRUE;
4280 GstBuffer *ftyp = NULL;
4282 /* extract major brand; might come in handy for ISO vs QT issues */
4283 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &ftyp);
4284 if (ret != GST_FLOW_OK)
4286 qtdemux->offset += length;
4287 gst_buffer_map (ftyp, &map, GST_MAP_READ);
4288 qtdemux_parse_ftyp (qtdemux, map.data, map.size);
4289 gst_buffer_unmap (ftyp, &map);
4290 gst_buffer_unref (ftyp);
4295 GstBuffer *uuid = NULL;
4297 /* uuid are extension atoms */
4298 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &uuid);
4299 if (ret != GST_FLOW_OK)
4301 qtdemux->offset += length;
4302 gst_buffer_map (uuid, &map, GST_MAP_READ);
4303 qtdemux_parse_uuid (qtdemux, map.data, map.size);
4304 gst_buffer_unmap (uuid, &map);
4305 gst_buffer_unref (uuid);
4310 GstBuffer *sidx = NULL;
4311 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &sidx);
4312 if (ret != GST_FLOW_OK)
4314 qtdemux->offset += length;
4315 gst_buffer_map (sidx, &map, GST_MAP_READ);
4316 qtdemux_parse_sidx (qtdemux, map.data, map.size);
4317 gst_buffer_unmap (sidx, &map);
4318 gst_buffer_unref (sidx);
4323 GstBuffer *unknown = NULL;
4325 GST_LOG_OBJECT (qtdemux,
4326 "unknown %08x '%" GST_FOURCC_FORMAT "' of size %" G_GUINT64_FORMAT
4327 " at %" G_GUINT64_FORMAT, fourcc, GST_FOURCC_ARGS (fourcc), length,
4329 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &unknown);
4330 if (ret != GST_FLOW_OK)
4332 gst_buffer_map (unknown, &map, GST_MAP_READ);
4333 GST_MEMDUMP ("Unknown tag", map.data, map.size);
4334 gst_buffer_unmap (unknown, &map);
4335 gst_buffer_unref (unknown);
4336 qtdemux->offset += length;
4342 if (ret == GST_FLOW_EOS && (qtdemux->got_moov || qtdemux->media_caps)) {
4343 /* digested all data, show what we have */
4344 qtdemux_prepare_streams (qtdemux);
4345 ret = qtdemux_expose_streams (qtdemux);
4347 qtdemux->state = QTDEMUX_STATE_MOVIE;
4348 GST_DEBUG_OBJECT (qtdemux, "switching state to STATE_MOVIE (%d)",
4355 /* Seeks to the previous keyframe of the indexed stream and
4356 * aligns other streams with respect to the keyframe timestamp
4357 * of indexed stream. Only called in case of Reverse Playback
4359 static GstFlowReturn
4360 gst_qtdemux_seek_to_previous_keyframe (GstQTDemux * qtdemux)
4363 guint32 seg_idx = 0, k_index = 0;
4364 guint32 ref_seg_idx, ref_k_index;
4365 GstClockTime k_pos = 0, last_stop = 0;
4366 QtDemuxSegment *seg = NULL;
4367 QtDemuxStream *ref_str = NULL;
4368 guint64 seg_media_start_mov; /* segment media start time in mov format */
4371 /* Now we choose an arbitrary stream, get the previous keyframe timestamp
4372 * and finally align all the other streams on that timestamp with their
4373 * respective keyframes */
4374 for (n = 0; n < qtdemux->n_streams; n++) {
4375 QtDemuxStream *str = qtdemux->streams[n];
4377 /* No candidate yet, take the first stream */
4383 /* So that stream has a segment, we prefer video streams */
4384 if (str->subtype == FOURCC_vide) {
4390 if (G_UNLIKELY (!ref_str)) {
4391 GST_DEBUG_OBJECT (qtdemux, "couldn't find any stream");
4395 if (G_UNLIKELY (!ref_str->from_sample)) {
4396 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of the file");
4400 /* So that stream has been playing from from_sample to to_sample. We will
4401 * get the timestamp of the previous sample and search for a keyframe before
4402 * that. For audio streams we do an arbitrary jump in the past (10 samples) */
4403 if (ref_str->subtype == FOURCC_vide) {
4404 k_index = gst_qtdemux_find_keyframe (qtdemux, ref_str,
4405 ref_str->from_sample - 1, FALSE);
4407 if (ref_str->from_sample >= 10)
4408 k_index = ref_str->from_sample - 10;
4414 ref_str->samples[k_index].timestamp +
4415 ref_str->samples[k_index].pts_offset;
4417 /* get current segment for that stream */
4418 seg = &ref_str->segments[ref_str->segment_index];
4419 /* Use segment start in original timescale for comparisons */
4420 seg_media_start_mov = seg->trak_media_start;
4422 GST_LOG_OBJECT (qtdemux, "keyframe index %u ts %" G_GUINT64_FORMAT
4423 " seg start %" G_GUINT64_FORMAT " %" GST_TIME_FORMAT "\n",
4424 k_index, target_ts, seg_media_start_mov,
4425 GST_TIME_ARGS (seg->media_start));
4427 /* Crawl back through segments to find the one containing this I frame */
4428 while (target_ts < seg_media_start_mov) {
4429 GST_DEBUG_OBJECT (qtdemux,
4430 "keyframe position (sample %u) is out of segment %u " " target %"
4431 G_GUINT64_FORMAT " seg start %" G_GUINT64_FORMAT, k_index,
4432 ref_str->segment_index, target_ts, seg_media_start_mov);
4434 if (G_UNLIKELY (!ref_str->segment_index)) {
4435 /* Reached first segment, let's consider it's EOS */
4438 ref_str->segment_index--;
4439 seg = &ref_str->segments[ref_str->segment_index];
4440 /* Use segment start in original timescale for comparisons */
4441 seg_media_start_mov = seg->trak_media_start;
4443 /* Calculate time position of the keyframe and where we should stop */
4445 QTSTREAMTIME_TO_GSTTIME (ref_str,
4446 target_ts - seg->trak_media_start) + seg->time;
4448 QTSTREAMTIME_TO_GSTTIME (ref_str,
4449 ref_str->samples[ref_str->from_sample].timestamp -
4450 seg->trak_media_start) + seg->time;
4452 GST_DEBUG_OBJECT (qtdemux, "preferred stream played from sample %u, "
4453 "now going to sample %u (pts %" GST_TIME_FORMAT ")", ref_str->from_sample,
4454 k_index, GST_TIME_ARGS (k_pos));
4456 /* Set last_stop with the keyframe timestamp we pushed of that stream */
4457 qtdemux->segment.position = last_stop;
4458 GST_DEBUG_OBJECT (qtdemux, "last_stop now is %" GST_TIME_FORMAT,
4459 GST_TIME_ARGS (last_stop));
4461 if (G_UNLIKELY (last_stop < qtdemux->segment.start)) {
4462 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of segment");
4466 ref_seg_idx = ref_str->segment_index;
4467 ref_k_index = k_index;
4469 /* Align them all on this */
4470 for (n = 0; n < qtdemux->n_streams; n++) {
4472 GstClockTime seg_time = 0;
4473 QtDemuxStream *str = qtdemux->streams[n];
4475 /* aligning reference stream again might lead to backing up to yet another
4476 * keyframe (due to timestamp rounding issues),
4477 * potentially putting more load on downstream; so let's try to avoid */
4478 if (str == ref_str) {
4479 seg_idx = ref_seg_idx;
4480 seg = &str->segments[seg_idx];
4481 k_index = ref_k_index;
4482 GST_DEBUG_OBJECT (qtdemux, "reference stream %d segment %d, "
4483 "sample at index %d", n, ref_str->segment_index, k_index);
4485 seg_idx = gst_qtdemux_find_segment (qtdemux, str, k_pos);
4486 GST_DEBUG_OBJECT (qtdemux,
4487 "stream %d align segment %d for keyframe pos %" GST_TIME_FORMAT, n,
4488 seg_idx, GST_TIME_ARGS (k_pos));
4490 /* get segment and time in the segment */
4491 seg = &str->segments[seg_idx];
4492 seg_time = k_pos - seg->time;
4494 /* get the media time in the segment.
4495 * No adjustment for empty "filler" segments */
4496 if (seg->media_start != GST_CLOCK_TIME_NONE)
4497 seg_time += seg->media_start;
4499 /* get the index of the sample with media time */
4500 index = gst_qtdemux_find_index_linear (qtdemux, str, seg_time);
4501 GST_DEBUG_OBJECT (qtdemux,
4502 "stream %d sample for %" GST_TIME_FORMAT " at %u", n,
4503 GST_TIME_ARGS (seg_time), index);
4505 /* find previous keyframe */
4506 k_index = gst_qtdemux_find_keyframe (qtdemux, str, index, FALSE);
4509 /* Remember until where we want to go */
4510 str->to_sample = str->from_sample - 1;
4511 /* Define our time position */
4513 str->samples[k_index].timestamp + str->samples[k_index].pts_offset;
4514 str->time_position = QTSTREAMTIME_TO_GSTTIME (str, target_ts) + seg->time;
4515 if (seg->media_start != GST_CLOCK_TIME_NONE)
4516 str->time_position -= seg->media_start;
4518 /* Now seek back in time */
4519 gst_qtdemux_move_stream (qtdemux, str, k_index);
4520 GST_DEBUG_OBJECT (qtdemux, "stream %d keyframe at %u, time position %"
4521 GST_TIME_FORMAT " playing from sample %u to %u", n, k_index,
4522 GST_TIME_ARGS (str->time_position), str->from_sample, str->to_sample);
4528 return GST_FLOW_EOS;
4532 * Gets the current qt segment start, stop and position for the
4533 * given time offset. This is used in update_segment()
4536 gst_qtdemux_stream_segment_get_boundaries (GstQTDemux * qtdemux,
4537 QtDemuxStream * stream, GstClockTime offset,
4538 GstClockTime * _start, GstClockTime * _stop, GstClockTime * _time)
4540 GstClockTime seg_time;
4541 GstClockTime start, stop, time;
4542 QtDemuxSegment *segment;
4544 segment = &stream->segments[stream->segment_index];
4546 /* get time in this segment */
4547 seg_time = (offset - segment->time) * segment->rate;
4549 GST_LOG_OBJECT (stream->pad, "seg_time %" GST_TIME_FORMAT,
4550 GST_TIME_ARGS (seg_time));
4552 if (G_UNLIKELY (seg_time > segment->duration)) {
4553 GST_LOG_OBJECT (stream->pad,
4554 "seg_time > segment->duration %" GST_TIME_FORMAT,
4555 GST_TIME_ARGS (segment->duration));
4556 seg_time = segment->duration;
4559 /* qtdemux->segment.stop is in outside-time-realm, whereas
4560 * segment->media_stop is in track-time-realm.
4562 * In order to compare the two, we need to bring segment.stop
4563 * into the track-time-realm
4565 * FIXME - does this comment still hold? Don't see any conversion here */
4567 stop = qtdemux->segment.stop;
4568 if (stop == GST_CLOCK_TIME_NONE)
4569 stop = qtdemux->segment.duration;
4570 if (stop == GST_CLOCK_TIME_NONE)
4571 stop = segment->media_stop;
4574 MIN (segment->media_stop, stop - segment->time + segment->media_start);
4576 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
4577 start = segment->time + seg_time;
4579 stop = start - seg_time + segment->duration;
4580 } else if (qtdemux->segment.rate >= 0) {
4581 start = MIN (segment->media_start + seg_time, stop);
4584 if (segment->media_start >= qtdemux->segment.start) {
4585 time = segment->time;
4587 time = segment->time + (qtdemux->segment.start - segment->media_start);
4590 start = MAX (segment->media_start, qtdemux->segment.start);
4591 stop = MIN (segment->media_start + seg_time, stop);
4600 * Updates the qt segment used for the stream and pushes a new segment event
4601 * downstream on this stream's pad.
4604 gst_qtdemux_stream_update_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
4605 gint seg_idx, GstClockTime offset, GstClockTime * _start,
4606 GstClockTime * _stop)
4608 QtDemuxSegment *segment;
4609 GstClockTime start = 0, stop = GST_CLOCK_TIME_NONE, time = 0;
4613 /* update the current segment */
4614 stream->segment_index = seg_idx;
4616 /* get the segment */
4617 segment = &stream->segments[seg_idx];
4619 if (G_UNLIKELY (offset < segment->time)) {
4620 GST_WARNING_OBJECT (stream->pad, "offset < segment->time %" GST_TIME_FORMAT,
4621 GST_TIME_ARGS (segment->time));
4625 /* segment lies beyond total indicated duration */
4626 if (G_UNLIKELY (qtdemux->segment.duration != GST_CLOCK_TIME_NONE &&
4627 segment->time > qtdemux->segment.duration)) {
4628 GST_WARNING_OBJECT (stream->pad, "file duration %" GST_TIME_FORMAT
4629 " < segment->time %" GST_TIME_FORMAT,
4630 GST_TIME_ARGS (qtdemux->segment.duration),
4631 GST_TIME_ARGS (segment->time));
4635 gst_qtdemux_stream_segment_get_boundaries (qtdemux, stream, offset,
4636 &start, &stop, &time);
4638 GST_DEBUG_OBJECT (stream->pad, "new segment %d from %" GST_TIME_FORMAT
4639 " to %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT, seg_idx,
4640 GST_TIME_ARGS (start), GST_TIME_ARGS (stop), GST_TIME_ARGS (time));
4642 /* combine global rate with that of the segment */
4643 rate = segment->rate * qtdemux->segment.rate;
4645 /* Copy flags from main segment */
4646 stream->segment.flags = qtdemux->segment.flags;
4648 /* update the segment values used for clipping */
4649 stream->segment.offset = qtdemux->segment.offset;
4650 stream->segment.base = qtdemux->segment.base + stream->accumulated_base;
4651 stream->segment.applied_rate = qtdemux->segment.applied_rate;
4652 stream->segment.rate = rate;
4653 stream->segment.start = start + QTSTREAMTIME_TO_GSTTIME (stream,
4654 stream->cslg_shift);
4655 stream->segment.stop = stop + QTSTREAMTIME_TO_GSTTIME (stream,
4656 stream->cslg_shift);
4657 stream->segment.time = time;
4658 stream->segment.position = stream->segment.start;
4660 GST_DEBUG_OBJECT (stream->pad, "New segment: %" GST_SEGMENT_FORMAT,
4663 /* now prepare and send the segment */
4665 event = gst_event_new_segment (&stream->segment);
4666 if (qtdemux->segment_seqnum) {
4667 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
4669 gst_pad_push_event (stream->pad, event);
4670 /* assume we can send more data now */
4671 GST_PAD_LAST_FLOW_RETURN (stream->pad) = GST_FLOW_OK;
4672 /* clear to send tags on this pad now */
4673 gst_qtdemux_push_tags (qtdemux, stream);
4684 /* activate the given segment number @seg_idx of @stream at time @offset.
4685 * @offset is an absolute global position over all the segments.
4687 * This will push out a NEWSEGMENT event with the right values and
4688 * position the stream index to the first decodable sample before
4692 gst_qtdemux_activate_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
4693 guint32 seg_idx, GstClockTime offset)
4695 QtDemuxSegment *segment;
4696 guint32 index, kf_index;
4697 GstClockTime start = 0, stop = GST_CLOCK_TIME_NONE;
4699 GST_LOG_OBJECT (stream->pad, "activate segment %d, offset %" GST_TIME_FORMAT,
4700 seg_idx, GST_TIME_ARGS (offset));
4702 if (!gst_qtdemux_stream_update_segment (qtdemux, stream, seg_idx, offset,
4706 segment = &stream->segments[stream->segment_index];
4708 /* in the fragmented case, we pick a fragment that starts before our
4709 * desired position and rely on downstream to wait for a keyframe
4710 * (FIXME: doesn't seem to work so well with ismv and wmv, as no parser; the
4711 * tfra entries tells us which trun/sample the key unit is in, but we don't
4712 * make use of this additional information at the moment) */
4713 if (qtdemux->fragmented) {
4714 stream->to_sample = G_MAXUINT32;
4718 /* We don't need to look for a sample in push-based */
4719 if (!qtdemux->pullbased)
4722 /* and move to the keyframe before the indicated media time of the
4724 if (G_LIKELY (!QTSEGMENT_IS_EMPTY (segment))) {
4725 if (qtdemux->segment.rate >= 0) {
4726 index = gst_qtdemux_find_index_linear (qtdemux, stream, start);
4727 stream->to_sample = G_MAXUINT32;
4728 GST_DEBUG_OBJECT (stream->pad,
4729 "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
4730 GST_TIME_FORMAT, GST_TIME_ARGS (start), index,
4731 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
4733 index = gst_qtdemux_find_index_linear (qtdemux, stream, stop);
4734 stream->to_sample = index;
4735 GST_DEBUG_OBJECT (stream->pad,
4736 "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
4737 GST_TIME_FORMAT, GST_TIME_ARGS (stop), index,
4738 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
4741 GST_DEBUG_OBJECT (stream->pad, "No need to look for keyframe, "
4742 "this is an empty segment");
4746 /* gst_qtdemux_parse_sample () called from gst_qtdemux_find_index_linear ()
4747 * encountered an error and printed a message so we return appropriately */
4751 /* we're at the right spot */
4752 if (index == stream->sample_index) {
4753 GST_DEBUG_OBJECT (stream->pad, "we are at the right index");
4757 /* find keyframe of the target index */
4758 kf_index = gst_qtdemux_find_keyframe (qtdemux, stream, index, FALSE);
4761 /* indent does stupid stuff with stream->samples[].timestamp */
4763 /* if we move forwards, we don't have to go back to the previous
4764 * keyframe since we already sent that. We can also just jump to
4765 * the keyframe right before the target index if there is one. */
4766 if (index > stream->sample_index) {
4767 /* moving forwards check if we move past a keyframe */
4768 if (kf_index > stream->sample_index) {
4769 GST_DEBUG_OBJECT (stream->pad,
4770 "moving forwards to keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" )", kf_index,
4771 GST_TIME_ARGS (QTSAMPLE_PTS(stream, &stream->samples[kf_index])),
4772 GST_TIME_ARGS (QTSAMPLE_DTS(stream, &stream->samples[kf_index])));
4773 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
4775 GST_DEBUG_OBJECT (stream->pad,
4776 "moving forwards, keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" ) already sent", kf_index,
4777 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[kf_index])),
4778 GST_TIME_ARGS (QTSAMPLE_DTS (stream, &stream->samples[kf_index])));
4781 GST_DEBUG_OBJECT (stream->pad,
4782 "moving backwards to keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" )", kf_index,
4783 GST_TIME_ARGS (QTSAMPLE_PTS(stream, &stream->samples[kf_index])),
4784 GST_TIME_ARGS (QTSAMPLE_DTS(stream, &stream->samples[kf_index])));
4785 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
4793 /* prepare to get the current sample of @stream, getting essential values.
4795 * This function will also prepare and send the segment when needed.
4797 * Return FALSE if the stream is EOS.
4802 gst_qtdemux_prepare_current_sample (GstQTDemux * qtdemux,
4803 QtDemuxStream * stream, gboolean * empty, guint64 * offset, guint * size,
4804 GstClockTime * dts, GstClockTime * pts, GstClockTime * duration,
4805 gboolean * keyframe)
4807 QtDemuxSample *sample;
4808 GstClockTime time_position;
4811 g_return_val_if_fail (stream != NULL, FALSE);
4813 time_position = stream->time_position;
4814 if (G_UNLIKELY (time_position == GST_CLOCK_TIME_NONE))
4817 seg_idx = stream->segment_index;
4818 if (G_UNLIKELY (seg_idx == -1)) {
4819 /* find segment corresponding to time_position if we are looking
4821 seg_idx = gst_qtdemux_find_segment (qtdemux, stream, time_position);
4824 /* different segment, activate it, sample_index will be set. */
4825 if (G_UNLIKELY (stream->segment_index != seg_idx))
4826 gst_qtdemux_activate_segment (qtdemux, stream, seg_idx, time_position);
4828 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (&stream->segments[stream->
4830 QtDemuxSegment *seg = &stream->segments[stream->segment_index];
4832 GST_LOG_OBJECT (qtdemux, "Empty segment activated,"
4833 " prepare empty sample");
4836 *pts = *dts = time_position;
4837 *duration = seg->duration - (time_position - seg->time);
4844 if (stream->sample_index == -1)
4845 stream->sample_index = 0;
4847 GST_LOG_OBJECT (qtdemux, "segment active, index = %u of %u",
4848 stream->sample_index, stream->n_samples);
4850 if (G_UNLIKELY (stream->sample_index >= stream->n_samples)) {
4851 if (!qtdemux->fragmented)
4854 GST_INFO_OBJECT (qtdemux, "out of samples, trying to add more");
4858 GST_OBJECT_LOCK (qtdemux);
4859 flow = qtdemux_add_fragmented_samples (qtdemux);
4860 GST_OBJECT_UNLOCK (qtdemux);
4862 if (flow != GST_FLOW_OK)
4865 while (stream->sample_index >= stream->n_samples);
4868 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
4869 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
4870 stream->sample_index);
4874 /* now get the info for the sample we're at */
4875 sample = &stream->samples[stream->sample_index];
4877 *dts = QTSAMPLE_DTS (stream, sample);
4878 *pts = QTSAMPLE_PTS (stream, sample);
4879 *offset = sample->offset;
4880 *size = sample->size;
4881 *duration = QTSAMPLE_DUR_DTS (stream, sample, *dts);
4882 *keyframe = QTSAMPLE_KEYFRAME (stream, sample);
4889 stream->time_position = GST_CLOCK_TIME_NONE;
4894 /* move to the next sample in @stream.
4896 * Moves to the next segment when needed.
4899 gst_qtdemux_advance_sample (GstQTDemux * qtdemux, QtDemuxStream * stream)
4901 QtDemuxSample *sample;
4902 QtDemuxSegment *segment;
4904 /* get current segment */
4905 segment = &stream->segments[stream->segment_index];
4907 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
4908 GST_DEBUG_OBJECT (qtdemux, "Empty segment, no samples to advance");
4912 if (G_UNLIKELY (stream->sample_index >= stream->to_sample)) {
4913 /* Mark the stream as EOS */
4914 GST_DEBUG_OBJECT (qtdemux,
4915 "reached max allowed sample %u, mark EOS", stream->to_sample);
4916 stream->time_position = GST_CLOCK_TIME_NONE;
4920 /* move to next sample */
4921 stream->sample_index++;
4922 stream->offset_in_sample = 0;
4924 /* reached the last sample, we need the next segment */
4925 if (G_UNLIKELY (stream->sample_index >= stream->n_samples))
4928 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
4929 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
4930 stream->sample_index);
4934 /* get next sample */
4935 sample = &stream->samples[stream->sample_index];
4937 /* see if we are past the segment */
4938 if (G_UNLIKELY (QTSAMPLE_DTS (stream, sample) >= segment->media_stop))
4941 if (QTSAMPLE_DTS (stream, sample) >= segment->media_start) {
4942 /* inside the segment, update time_position, looks very familiar to
4943 * GStreamer segments, doesn't it? */
4944 stream->time_position =
4945 QTSAMPLE_DTS (stream, sample) - segment->media_start + segment->time;
4947 /* not yet in segment, time does not yet increment. This means
4948 * that we are still prerolling keyframes to the decoder so it can
4949 * decode the first sample of the segment. */
4950 stream->time_position = segment->time;
4954 /* move to the next segment */
4957 GST_DEBUG_OBJECT (qtdemux, "segment %d ended ", stream->segment_index);
4959 if (stream->segment_index == stream->n_segments - 1) {
4960 /* are we at the end of the last segment, we're EOS */
4961 stream->time_position = GST_CLOCK_TIME_NONE;
4963 /* else we're only at the end of the current segment */
4964 stream->time_position = segment->stop_time;
4966 /* make sure we select a new segment */
4968 /* accumulate previous segments */
4969 if (GST_CLOCK_TIME_IS_VALID (stream->segment.stop))
4970 stream->accumulated_base +=
4971 (stream->segment.stop -
4972 stream->segment.start) / ABS (stream->segment.rate);
4974 stream->segment_index = -1;
4979 gst_qtdemux_sync_streams (GstQTDemux * demux)
4983 if (demux->n_streams <= 1)
4986 for (i = 0; i < demux->n_streams; i++) {
4987 QtDemuxStream *stream;
4988 GstClockTime end_time;
4990 stream = demux->streams[i];
4995 /* TODO advance time on subtitle streams here, if any some day */
4997 /* some clips/trailers may have unbalanced streams at the end,
4998 * so send EOS on shorter stream to prevent stalling others */
5000 /* do not mess with EOS if SEGMENT seeking */
5001 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT)
5004 if (demux->pullbased) {
5005 /* loop mode is sample time based */
5006 if (!STREAM_IS_EOS (stream))
5009 /* push mode is byte position based */
5010 if (stream->n_samples &&
5011 stream->samples[stream->n_samples - 1].offset >= demux->offset)
5015 if (stream->sent_eos)
5018 /* only act if some gap */
5019 end_time = stream->segments[stream->n_segments - 1].stop_time;
5020 GST_LOG_OBJECT (demux, "current position: %" GST_TIME_FORMAT
5021 ", stream end: %" GST_TIME_FORMAT,
5022 GST_TIME_ARGS (demux->segment.position), GST_TIME_ARGS (end_time));
5023 if (GST_CLOCK_TIME_IS_VALID (end_time)
5024 && (end_time + 2 * GST_SECOND < demux->segment.position)) {
5027 GST_DEBUG_OBJECT (demux, "sending EOS for stream %s",
5028 GST_PAD_NAME (stream->pad));
5029 stream->sent_eos = TRUE;
5030 event = gst_event_new_eos ();
5031 if (demux->segment_seqnum)
5032 gst_event_set_seqnum (event, demux->segment_seqnum);
5033 gst_pad_push_event (stream->pad, event);
5038 /* EOS and NOT_LINKED need to be combined. This means that we return:
5040 * GST_FLOW_NOT_LINKED: when all pads NOT_LINKED.
5041 * GST_FLOW_EOS: when all pads EOS or NOT_LINKED.
5043 static GstFlowReturn
5044 gst_qtdemux_combine_flows (GstQTDemux * demux, QtDemuxStream * stream,
5047 GST_LOG_OBJECT (demux, "flow return: %s", gst_flow_get_name (ret));
5050 ret = gst_flow_combiner_update_pad_flow (demux->flowcombiner, stream->pad,
5053 ret = gst_flow_combiner_update_flow (demux->flowcombiner, ret);
5055 GST_LOG_OBJECT (demux, "combined flow return: %s", gst_flow_get_name (ret));
5059 /* the input buffer metadata must be writable. Returns NULL when the buffer is
5060 * completely clipped
5062 * Should be used only with raw buffers */
5064 gst_qtdemux_clip_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
5067 guint64 start, stop, cstart, cstop, diff;
5068 GstClockTime pts, duration;
5070 gint num_rate, denom_rate;
5075 osize = size = gst_buffer_get_size (buf);
5078 /* depending on the type, setup the clip parameters */
5079 if (stream->subtype == FOURCC_soun) {
5080 frame_size = stream->bytes_per_frame;
5081 num_rate = GST_SECOND;
5082 denom_rate = (gint) stream->rate;
5084 } else if (stream->subtype == FOURCC_vide) {
5086 num_rate = stream->fps_n;
5087 denom_rate = stream->fps_d;
5092 if (frame_size <= 0)
5093 goto bad_frame_size;
5095 /* we can only clip if we have a valid pts */
5096 pts = GST_BUFFER_PTS (buf);
5097 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (pts)))
5100 duration = GST_BUFFER_DURATION (buf);
5102 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (duration))) {
5104 gst_util_uint64_scale_int (size / frame_size, num_rate, denom_rate);
5108 stop = start + duration;
5110 if (G_UNLIKELY (!gst_segment_clip (&stream->segment,
5111 GST_FORMAT_TIME, start, stop, &cstart, &cstop)))
5114 /* see if some clipping happened */
5115 diff = cstart - start;
5121 /* bring clipped time to samples and to bytes */
5122 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
5125 GST_DEBUG_OBJECT (qtdemux,
5126 "clipping start to %" GST_TIME_FORMAT " %"
5127 G_GUINT64_FORMAT " bytes", GST_TIME_ARGS (cstart), diff);
5133 diff = stop - cstop;
5138 /* bring clipped time to samples and then to bytes */
5139 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
5141 GST_DEBUG_OBJECT (qtdemux,
5142 "clipping stop to %" GST_TIME_FORMAT " %" G_GUINT64_FORMAT
5143 " bytes", GST_TIME_ARGS (cstop), diff);
5148 if (offset != 0 || size != osize)
5149 gst_buffer_resize (buf, offset, size);
5151 GST_BUFFER_DTS (buf) = GST_CLOCK_TIME_NONE;
5152 GST_BUFFER_PTS (buf) = pts;
5153 GST_BUFFER_DURATION (buf) = duration;
5157 /* dropped buffer */
5160 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
5165 GST_DEBUG_OBJECT (qtdemux, "bad frame size");
5170 GST_DEBUG_OBJECT (qtdemux, "no pts on buffer");
5175 GST_DEBUG_OBJECT (qtdemux, "clipped buffer");
5176 gst_buffer_unref (buf);
5182 gst_qtdemux_align_buffer (GstQTDemux * demux,
5183 GstBuffer * buffer, gsize alignment)
5187 gst_buffer_map (buffer, &map, GST_MAP_READ);
5189 if (map.size < sizeof (guintptr)) {
5190 gst_buffer_unmap (buffer, &map);
5194 if (((guintptr) map.data) & (alignment - 1)) {
5195 GstBuffer *new_buffer;
5196 GstAllocationParams params = { 0, alignment - 1, 0, 0, };
5198 new_buffer = gst_buffer_new_allocate (NULL,
5199 gst_buffer_get_size (buffer), ¶ms);
5201 /* Copy data "by hand", so ensure alignment is kept: */
5202 gst_buffer_fill (new_buffer, 0, map.data, map.size);
5204 gst_buffer_copy_into (new_buffer, buffer, GST_BUFFER_COPY_METADATA, 0, -1);
5205 GST_DEBUG_OBJECT (demux,
5206 "We want output aligned on %" G_GSIZE_FORMAT ", reallocated",
5209 gst_buffer_unmap (buffer, &map);
5210 gst_buffer_unref (buffer);
5215 gst_buffer_unmap (buffer, &map);
5219 /* the input buffer metadata must be writable,
5220 * but time/duration etc not yet set and need not be preserved */
5222 gst_qtdemux_process_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
5229 /* not many cases for now */
5230 if (G_UNLIKELY (stream->fourcc == FOURCC_mp4s)) {
5231 /* send a one time dvd clut event */
5232 if (stream->pending_event && stream->pad)
5233 gst_pad_push_event (stream->pad, stream->pending_event);
5234 stream->pending_event = NULL;
5237 if (G_UNLIKELY (stream->subtype != FOURCC_text
5238 && stream->subtype != FOURCC_sbtl &&
5239 stream->subtype != FOURCC_subp)) {
5243 gst_buffer_map (buf, &map, GST_MAP_READ);
5245 /* empty buffer is sent to terminate previous subtitle */
5246 if (map.size <= 2) {
5247 gst_buffer_unmap (buf, &map);
5248 gst_buffer_unref (buf);
5251 if (stream->subtype == FOURCC_subp) {
5252 /* That's all the processing needed for subpictures */
5253 gst_buffer_unmap (buf, &map);
5257 nsize = GST_READ_UINT16_BE (map.data);
5258 nsize = MIN (nsize, map.size - 2);
5260 GST_LOG_OBJECT (qtdemux, "3GPP timed text subtitle: %d/%" G_GSIZE_FORMAT "",
5263 /* takes care of UTF-8 validation or UTF-16 recognition,
5264 * no other encoding expected */
5265 str = gst_tag_freeform_string_to_utf8 ((gchar *) map.data + 2, nsize, NULL);
5266 gst_buffer_unmap (buf, &map);
5268 gst_buffer_unref (buf);
5269 buf = _gst_buffer_new_wrapped (str, strlen (str), g_free);
5271 /* this should not really happen unless the subtitle is corrupted */
5272 gst_buffer_unref (buf);
5276 /* FIXME ? convert optional subsequent style info to markup */
5281 /* Sets a buffer's attributes properly and pushes it downstream.
5282 * Also checks for additional actions and custom processing that may
5283 * need to be done first.
5285 static GstFlowReturn
5286 gst_qtdemux_decorate_and_push_buffer (GstQTDemux * qtdemux,
5287 QtDemuxStream * stream, GstBuffer * buf,
5288 GstClockTime dts, GstClockTime pts, GstClockTime duration,
5289 gboolean keyframe, GstClockTime position, guint64 byte_position)
5291 GstFlowReturn ret = GST_FLOW_OK;
5293 /* offset the timestamps according to the edit list */
5295 if (G_UNLIKELY (stream->fourcc == FOURCC_rtsp)) {
5299 gst_buffer_map (buf, &map, GST_MAP_READ);
5300 url = g_strndup ((gchar *) map.data, map.size);
5301 gst_buffer_unmap (buf, &map);
5302 if (url != NULL && strlen (url) != 0) {
5303 /* we have RTSP redirect now */
5304 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
5305 gst_message_new_element (GST_OBJECT_CAST (qtdemux),
5306 gst_structure_new ("redirect",
5307 "new-location", G_TYPE_STRING, url, NULL)));
5308 qtdemux->posted_redirect = TRUE;
5310 GST_WARNING_OBJECT (qtdemux, "Redirect URI of stream is empty, not "
5316 /* position reporting */
5317 if (qtdemux->segment.rate >= 0) {
5318 qtdemux->segment.position = position;
5319 gst_qtdemux_sync_streams (qtdemux);
5322 if (G_UNLIKELY (!stream->pad)) {
5323 GST_DEBUG_OBJECT (qtdemux, "No output pad for stream, ignoring");
5324 gst_buffer_unref (buf);
5328 /* send out pending buffers */
5329 while (stream->buffers) {
5330 GstBuffer *buffer = (GstBuffer *) stream->buffers->data;
5332 if (G_UNLIKELY (stream->discont)) {
5333 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
5334 GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
5335 stream->discont = FALSE;
5337 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
5340 if (stream->alignment > 1)
5341 buffer = gst_qtdemux_align_buffer (qtdemux, buffer, stream->alignment);
5342 gst_pad_push (stream->pad, buffer);
5344 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
5347 /* we're going to modify the metadata */
5348 buf = gst_buffer_make_writable (buf);
5350 if (G_UNLIKELY (stream->need_process))
5351 buf = gst_qtdemux_process_buffer (qtdemux, stream, buf);
5357 GST_BUFFER_DTS (buf) = dts;
5358 GST_BUFFER_PTS (buf) = pts;
5359 GST_BUFFER_DURATION (buf) = duration;
5360 GST_BUFFER_OFFSET (buf) = -1;
5361 GST_BUFFER_OFFSET_END (buf) = -1;
5363 if (G_UNLIKELY (stream->rgb8_palette))
5364 gst_buffer_append_memory (buf, gst_memory_ref (stream->rgb8_palette));
5366 if (G_UNLIKELY (stream->padding)) {
5367 gst_buffer_resize (buf, stream->padding, -1);
5370 if (G_UNLIKELY (qtdemux->element_index)) {
5371 GstClockTime stream_time;
5374 gst_segment_to_stream_time (&stream->segment, GST_FORMAT_TIME,
5376 if (GST_CLOCK_TIME_IS_VALID (stream_time)) {
5377 GST_LOG_OBJECT (qtdemux,
5378 "adding association %" GST_TIME_FORMAT "-> %"
5379 G_GUINT64_FORMAT, GST_TIME_ARGS (stream_time), byte_position);
5380 gst_index_add_association (qtdemux->element_index,
5382 keyframe ? GST_ASSOCIATION_FLAG_KEY_UNIT :
5383 GST_ASSOCIATION_FLAG_DELTA_UNIT, GST_FORMAT_TIME, stream_time,
5384 GST_FORMAT_BYTES, byte_position, NULL);
5389 if (stream->need_clip)
5390 buf = gst_qtdemux_clip_buffer (qtdemux, stream, buf);
5392 if (G_UNLIKELY (buf == NULL))
5395 if (G_UNLIKELY (stream->discont)) {
5396 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
5397 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
5398 stream->discont = FALSE;
5400 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
5404 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
5405 stream->on_keyframe = FALSE;
5407 stream->on_keyframe = TRUE;
5411 GST_LOG_OBJECT (qtdemux,
5412 "Pushing buffer with dts %" GST_TIME_FORMAT ", pts %" GST_TIME_FORMAT
5413 ", duration %" GST_TIME_FORMAT " on pad %s", GST_TIME_ARGS (dts),
5414 GST_TIME_ARGS (pts), GST_TIME_ARGS (duration),
5415 GST_PAD_NAME (stream->pad));
5417 if (stream->protected && stream->protection_scheme_type == FOURCC_cenc) {
5418 GstStructure *crypto_info;
5419 QtDemuxCencSampleSetInfo *info =
5420 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
5424 while ((event = g_queue_pop_head (&stream->protection_scheme_event_queue))) {
5425 gst_pad_push_event (stream->pad, event);
5428 if (info->crypto_info == NULL) {
5429 GST_DEBUG_OBJECT (qtdemux, "cenc metadata hasn't been parsed yet");
5430 gst_buffer_unref (buf);
5434 index = stream->sample_index - (stream->n_samples - info->crypto_info->len);
5435 if (G_LIKELY (index >= 0 && index < info->crypto_info->len)) {
5436 /* steal structure from array */
5437 crypto_info = g_ptr_array_index (info->crypto_info, index);
5438 g_ptr_array_index (info->crypto_info, index) = NULL;
5439 GST_LOG_OBJECT (qtdemux, "attaching cenc metadata [%u]", index);
5440 if (!crypto_info || !gst_buffer_add_protection_meta (buf, crypto_info))
5441 GST_ERROR_OBJECT (qtdemux, "failed to attach cenc metadata to buffer");
5445 if (stream->alignment > 1)
5446 buf = gst_qtdemux_align_buffer (qtdemux, buf, stream->alignment);
5448 ret = gst_pad_push (stream->pad, buf);
5450 if (GST_CLOCK_TIME_IS_VALID (pts) && GST_CLOCK_TIME_IS_VALID (duration)) {
5451 /* mark position in stream, we'll need this to know when to send GAP event */
5452 stream->segment.position = pts + duration;
5459 static const QtDemuxRandomAccessEntry *
5460 gst_qtdemux_stream_seek_fragment (GstQTDemux * qtdemux, QtDemuxStream * stream,
5461 GstClockTime pos, gboolean after)
5463 QtDemuxRandomAccessEntry *entries = stream->ra_entries;
5464 guint n_entries = stream->n_ra_entries;
5467 /* we assume the table is sorted */
5468 for (i = 0; i < n_entries; ++i) {
5469 if (entries[i].ts > pos)
5473 /* FIXME: maybe save first moof_offset somewhere instead, but for now it's
5474 * probably okay to assume that the index lists the very first fragment */
5481 return &entries[i - 1];
5485 gst_qtdemux_do_fragmented_seek (GstQTDemux * qtdemux)
5487 const QtDemuxRandomAccessEntry *best_entry = NULL;
5490 GST_OBJECT_LOCK (qtdemux);
5492 g_assert (qtdemux->n_streams > 0);
5494 for (i = 0; i < qtdemux->n_streams; i++) {
5495 const QtDemuxRandomAccessEntry *entry;
5496 QtDemuxStream *stream;
5497 gboolean is_audio_or_video;
5499 stream = qtdemux->streams[i];
5501 g_free (stream->samples);
5502 stream->samples = NULL;
5503 stream->n_samples = 0;
5504 stream->stbl_index = -1; /* no samples have yet been parsed */
5505 stream->sample_index = -1;
5507 if (stream->ra_entries == NULL)
5510 if (stream->subtype == FOURCC_vide || stream->subtype == FOURCC_soun)
5511 is_audio_or_video = TRUE;
5513 is_audio_or_video = FALSE;
5516 gst_qtdemux_stream_seek_fragment (qtdemux, stream,
5517 stream->time_position, !is_audio_or_video);
5519 GST_INFO_OBJECT (stream->pad, "%" GST_TIME_FORMAT " at offset "
5520 "%" G_GUINT64_FORMAT, GST_TIME_ARGS (entry->ts), entry->moof_offset);
5522 stream->pending_seek = entry;
5524 /* decide position to jump to just based on audio/video tracks, not subs */
5525 if (!is_audio_or_video)
5528 if (best_entry == NULL || entry->moof_offset < best_entry->moof_offset)
5532 if (best_entry == NULL) {
5533 GST_OBJECT_UNLOCK (qtdemux);
5537 GST_INFO_OBJECT (qtdemux, "seek to %" GST_TIME_FORMAT ", best fragment "
5538 "moof offset: %" G_GUINT64_FORMAT ", ts %" GST_TIME_FORMAT,
5539 GST_TIME_ARGS (qtdemux->streams[0]->time_position),
5540 best_entry->moof_offset, GST_TIME_ARGS (best_entry->ts));
5542 qtdemux->moof_offset = best_entry->moof_offset;
5544 qtdemux_add_fragmented_samples (qtdemux);
5546 GST_OBJECT_UNLOCK (qtdemux);
5550 static GstFlowReturn
5551 gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux)
5553 GstFlowReturn ret = GST_FLOW_OK;
5554 GstBuffer *buf = NULL;
5555 QtDemuxStream *stream;
5556 GstClockTime min_time;
5558 GstClockTime dts = GST_CLOCK_TIME_NONE;
5559 GstClockTime pts = GST_CLOCK_TIME_NONE;
5560 GstClockTime duration = 0;
5561 gboolean keyframe = FALSE;
5562 guint sample_size = 0;
5568 gst_qtdemux_push_pending_newsegment (qtdemux);
5570 if (qtdemux->fragmented_seek_pending) {
5571 GST_INFO_OBJECT (qtdemux, "pending fragmented seek");
5572 gst_qtdemux_do_fragmented_seek (qtdemux);
5573 GST_INFO_OBJECT (qtdemux, "fragmented seek done!");
5574 qtdemux->fragmented_seek_pending = FALSE;
5577 /* Figure out the next stream sample to output, min_time is expressed in
5578 * global time and runs over the edit list segments. */
5579 min_time = G_MAXUINT64;
5581 for (i = 0; i < qtdemux->n_streams; i++) {
5582 GstClockTime position;
5584 stream = qtdemux->streams[i];
5585 position = stream->time_position;
5587 /* position of -1 is EOS */
5588 if (position != GST_CLOCK_TIME_NONE && position < min_time) {
5589 min_time = position;
5594 if (G_UNLIKELY (index == -1)) {
5595 GST_DEBUG_OBJECT (qtdemux, "all streams are EOS");
5599 /* check for segment end */
5600 if (G_UNLIKELY (qtdemux->segment.stop != -1
5601 && ((qtdemux->segment.rate >= 0 && qtdemux->segment.stop <= min_time)
5602 || (qtdemux->segment.rate < 0
5603 && qtdemux->segment.start > min_time))
5604 && qtdemux->streams[index]->on_keyframe)) {
5605 GST_DEBUG_OBJECT (qtdemux, "we reached the end of our segment.");
5606 qtdemux->streams[index]->time_position = GST_CLOCK_TIME_NONE;
5610 /* gap events for subtitle streams */
5611 for (i = 0; i < qtdemux->n_streams; i++) {
5612 stream = qtdemux->streams[i];
5613 if (stream->pad && (stream->subtype == FOURCC_subp
5614 || stream->subtype == FOURCC_text
5615 || stream->subtype == FOURCC_sbtl)) {
5616 /* send one second gap events until the stream catches up */
5617 /* gaps can only be sent after segment is activated (segment.stop is no longer -1) */
5618 while (GST_CLOCK_TIME_IS_VALID (stream->segment.stop) &&
5619 GST_CLOCK_TIME_IS_VALID (stream->segment.position) &&
5620 stream->segment.position + GST_SECOND < min_time) {
5622 gst_event_new_gap (stream->segment.position, GST_SECOND);
5623 gst_pad_push_event (stream->pad, gap);
5624 stream->segment.position += GST_SECOND;
5629 stream = qtdemux->streams[index];
5630 if (stream->new_caps) {
5631 gst_qtdemux_configure_stream (qtdemux, stream);
5632 qtdemux_do_allocation (qtdemux, stream);
5635 /* fetch info for the current sample of this stream */
5636 if (G_UNLIKELY (!gst_qtdemux_prepare_current_sample (qtdemux, stream, &empty,
5637 &offset, &sample_size, &dts, &pts, &duration, &keyframe)))
5640 /* If we're doing a keyframe-only trickmode, only push keyframes on video streams */
5641 if (G_UNLIKELY (qtdemux->
5642 segment.flags & GST_SEGMENT_FLAG_TRICKMODE_KEY_UNITS)) {
5643 if (stream->subtype == FOURCC_vide && !keyframe) {
5644 GST_LOG_OBJECT (qtdemux, "Skipping non-keyframe on stream %d", index);
5649 GST_DEBUG_OBJECT (qtdemux,
5650 "pushing from stream %d, empty %d offset %" G_GUINT64_FORMAT
5651 ", size %d, dts=%" GST_TIME_FORMAT ", pts=%" GST_TIME_FORMAT
5652 ", duration %" GST_TIME_FORMAT, index, empty, offset, sample_size,
5653 GST_TIME_ARGS (dts), GST_TIME_ARGS (pts), GST_TIME_ARGS (duration));
5655 if (G_UNLIKELY (empty)) {
5656 /* empty segment, push a gap and move to the next one */
5657 gst_pad_push_event (stream->pad, gst_event_new_gap (pts, duration));
5658 stream->segment.position = pts + duration;
5662 /* hmm, empty sample, skip and move to next sample */
5663 if (G_UNLIKELY (sample_size <= 0))
5666 /* last pushed sample was out of boundary, goto next sample */
5667 if (G_UNLIKELY (GST_PAD_LAST_FLOW_RETURN (stream->pad) == GST_FLOW_EOS))
5670 if (stream->max_buffer_size == 0 || sample_size <= stream->max_buffer_size) {
5673 GST_DEBUG_OBJECT (qtdemux,
5674 "size %d larger than stream max_buffer_size %d, trimming",
5675 sample_size, stream->max_buffer_size);
5677 MIN (sample_size - stream->offset_in_sample, stream->max_buffer_size);
5680 if (qtdemux->cenc_aux_info_offset > 0) {
5683 GstBuffer *aux_info = NULL;
5685 /* pull the data stored before the sample */
5687 gst_qtdemux_pull_atom (qtdemux, qtdemux->offset,
5688 offset + stream->offset_in_sample - qtdemux->offset, &aux_info);
5689 if (G_UNLIKELY (ret != GST_FLOW_OK))
5691 gst_buffer_map (aux_info, &map, GST_MAP_READ);
5692 GST_DEBUG_OBJECT (qtdemux, "parsing cenc auxiliary info");
5693 gst_byte_reader_init (&br, map.data + 8, map.size);
5694 if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
5695 qtdemux->cenc_aux_info_sizes, qtdemux->cenc_aux_sample_count)) {
5696 GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
5697 gst_buffer_unmap (aux_info, &map);
5698 gst_buffer_unref (aux_info);
5699 ret = GST_FLOW_ERROR;
5702 gst_buffer_unmap (aux_info, &map);
5703 gst_buffer_unref (aux_info);
5706 GST_LOG_OBJECT (qtdemux, "reading %d bytes @ %" G_GUINT64_FORMAT, size,
5709 if (stream->use_allocator) {
5710 /* if we have a per-stream allocator, use it */
5711 buf = gst_buffer_new_allocate (stream->allocator, size, &stream->params);
5714 ret = gst_qtdemux_pull_atom (qtdemux, offset + stream->offset_in_sample,
5716 if (G_UNLIKELY (ret != GST_FLOW_OK))
5719 if (size != sample_size) {
5720 pts += gst_util_uint64_scale_int (GST_SECOND,
5721 stream->offset_in_sample / stream->bytes_per_frame, stream->timescale);
5722 dts += gst_util_uint64_scale_int (GST_SECOND,
5723 stream->offset_in_sample / stream->bytes_per_frame, stream->timescale);
5724 duration = gst_util_uint64_scale_int (GST_SECOND,
5725 size / stream->bytes_per_frame, stream->timescale);
5728 ret = gst_qtdemux_decorate_and_push_buffer (qtdemux, stream, buf,
5729 dts, pts, duration, keyframe, min_time, offset);
5731 if (size != sample_size) {
5732 QtDemuxSample *sample = &stream->samples[stream->sample_index];
5733 QtDemuxSegment *segment = &stream->segments[stream->segment_index];
5735 GstClockTime time_position = QTSTREAMTIME_TO_GSTTIME (stream,
5736 sample->timestamp + stream->offset_in_sample / stream->bytes_per_frame);
5737 if (time_position >= segment->media_start) {
5738 /* inside the segment, update time_position, looks very familiar to
5739 * GStreamer segments, doesn't it? */
5740 stream->time_position = (time_position - segment->media_start) +
5743 /* not yet in segment, time does not yet increment. This means
5744 * that we are still prerolling keyframes to the decoder so it can
5745 * decode the first sample of the segment. */
5746 stream->time_position = segment->time;
5751 ret = gst_qtdemux_combine_flows (qtdemux, stream, ret);
5752 /* ignore unlinked, we will not push on the pad anymore and we will EOS when
5753 * we have no more data for the pad to push */
5754 if (ret == GST_FLOW_EOS)
5757 stream->offset_in_sample += size;
5758 if (stream->offset_in_sample >= sample_size) {
5759 gst_qtdemux_advance_sample (qtdemux, stream);
5764 gst_qtdemux_advance_sample (qtdemux, stream);
5772 GST_DEBUG_OBJECT (qtdemux, "No samples left for any streams - EOS");
5778 GST_DEBUG_OBJECT (qtdemux, "No samples left for stream");
5779 /* EOS will be raised if all are EOS */
5786 gst_qtdemux_loop (GstPad * pad)
5788 GstQTDemux *qtdemux;
5792 qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
5794 cur_offset = qtdemux->offset;
5795 GST_LOG_OBJECT (qtdemux, "loop at position %" G_GUINT64_FORMAT ", state %s",
5796 cur_offset, qt_demux_state_string (qtdemux->state));
5798 switch (qtdemux->state) {
5799 case QTDEMUX_STATE_INITIAL:
5800 case QTDEMUX_STATE_HEADER:
5801 ret = gst_qtdemux_loop_state_header (qtdemux);
5803 case QTDEMUX_STATE_MOVIE:
5804 ret = gst_qtdemux_loop_state_movie (qtdemux);
5805 if (qtdemux->segment.rate < 0 && ret == GST_FLOW_EOS) {
5806 ret = gst_qtdemux_seek_to_previous_keyframe (qtdemux);
5814 /* if something went wrong, pause */
5815 if (ret != GST_FLOW_OK)
5819 gst_object_unref (qtdemux);
5825 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
5826 (NULL), ("streaming stopped, invalid state"));
5827 gst_pad_pause_task (pad);
5828 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
5833 const gchar *reason = gst_flow_get_name (ret);
5835 GST_LOG_OBJECT (qtdemux, "pausing task, reason %s", reason);
5837 gst_pad_pause_task (pad);
5839 /* fatal errors need special actions */
5841 if (ret == GST_FLOW_EOS) {
5842 if (qtdemux->n_streams == 0) {
5843 /* we have no streams, post an error */
5844 gst_qtdemux_post_no_playable_stream_error (qtdemux);
5846 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
5849 if ((stop = qtdemux->segment.stop) == -1)
5850 stop = qtdemux->segment.duration;
5852 if (qtdemux->segment.rate >= 0) {
5853 GstMessage *message;
5856 GST_LOG_OBJECT (qtdemux, "Sending segment done, at end of segment");
5857 message = gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
5858 GST_FORMAT_TIME, stop);
5859 event = gst_event_new_segment_done (GST_FORMAT_TIME, stop);
5860 if (qtdemux->segment_seqnum) {
5861 gst_message_set_seqnum (message, qtdemux->segment_seqnum);
5862 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
5864 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), message);
5865 gst_qtdemux_push_event (qtdemux, event);
5867 GstMessage *message;
5870 /* For Reverse Playback */
5871 GST_LOG_OBJECT (qtdemux, "Sending segment done, at start of segment");
5872 message = gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
5873 GST_FORMAT_TIME, qtdemux->segment.start);
5874 event = gst_event_new_segment_done (GST_FORMAT_TIME,
5875 qtdemux->segment.start);
5876 if (qtdemux->segment_seqnum) {
5877 gst_message_set_seqnum (message, qtdemux->segment_seqnum);
5878 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
5880 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), message);
5881 gst_qtdemux_push_event (qtdemux, event);
5886 GST_LOG_OBJECT (qtdemux, "Sending EOS at end of segment");
5887 event = gst_event_new_eos ();
5888 if (qtdemux->segment_seqnum)
5889 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
5890 gst_qtdemux_push_event (qtdemux, event);
5892 } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
5893 GST_ELEMENT_FLOW_ERROR (qtdemux, ret);
5894 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
5903 * Returns if there are samples to be played.
5906 has_next_entry (GstQTDemux * demux)
5908 QtDemuxStream *stream;
5911 GST_DEBUG_OBJECT (demux, "Checking if there are samples not played yet");
5913 for (i = 0; i < demux->n_streams; i++) {
5914 stream = demux->streams[i];
5916 if (stream->sample_index == -1) {
5917 stream->sample_index = 0;
5918 stream->offset_in_sample = 0;
5921 if (stream->sample_index >= stream->n_samples) {
5922 GST_LOG_OBJECT (demux, "stream %d samples exhausted", i);
5925 GST_DEBUG_OBJECT (demux, "Found a sample");
5929 GST_DEBUG_OBJECT (demux, "There wasn't any next sample");
5936 * Returns the size of the first entry at the current offset.
5937 * If -1, there are none (which means EOS or empty file).
5940 next_entry_size (GstQTDemux * demux)
5942 QtDemuxStream *stream;
5945 guint64 smalloffs = (guint64) - 1;
5946 QtDemuxSample *sample;
5948 GST_LOG_OBJECT (demux, "Finding entry at offset %" G_GUINT64_FORMAT,
5951 for (i = 0; i < demux->n_streams; i++) {
5952 stream = demux->streams[i];
5954 if (stream->sample_index == -1) {
5955 stream->sample_index = 0;
5956 stream->offset_in_sample = 0;
5959 if (stream->sample_index >= stream->n_samples) {
5960 GST_LOG_OBJECT (demux, "stream %d samples exhausted", i);
5964 if (!qtdemux_parse_samples (demux, stream, stream->sample_index)) {
5965 GST_LOG_OBJECT (demux, "Parsing of index %u from stbl atom failed!",
5966 stream->sample_index);
5970 sample = &stream->samples[stream->sample_index];
5972 GST_LOG_OBJECT (demux,
5973 "Checking Stream %d (sample_index:%d / offset:%" G_GUINT64_FORMAT
5974 " / size:%" G_GUINT32_FORMAT ")", i, stream->sample_index,
5975 sample->offset, sample->size);
5977 if (((smalloffs == -1)
5978 || (sample->offset < smalloffs)) && (sample->size)) {
5980 smalloffs = sample->offset;
5984 GST_LOG_OBJECT (demux,
5985 "stream %d offset %" G_GUINT64_FORMAT " demux->offset :%"
5986 G_GUINT64_FORMAT, smallidx, smalloffs, demux->offset);
5991 stream = demux->streams[smallidx];
5992 sample = &stream->samples[stream->sample_index];
5994 if (sample->offset >= demux->offset) {
5995 demux->todrop = sample->offset - demux->offset;
5996 return sample->size + demux->todrop;
5999 GST_DEBUG_OBJECT (demux,
6000 "There wasn't any entry at offset %" G_GUINT64_FORMAT, demux->offset);
6005 gst_qtdemux_post_progress (GstQTDemux * demux, gint num, gint denom)
6007 gint perc = (gint) ((gdouble) num * 100.0 / (gdouble) denom);
6009 gst_element_post_message (GST_ELEMENT_CAST (demux),
6010 gst_message_new_element (GST_OBJECT_CAST (demux),
6011 gst_structure_new ("progress", "percent", G_TYPE_INT, perc, NULL)));
6015 qtdemux_seek_offset (GstQTDemux * demux, guint64 offset)
6020 GST_DEBUG_OBJECT (demux, "Seeking to %" G_GUINT64_FORMAT, offset);
6023 gst_event_new_seek (1.0, GST_FORMAT_BYTES,
6024 GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset,
6025 GST_SEEK_TYPE_NONE, -1);
6027 /* store seqnum to drop flush events, they don't need to reach downstream */
6028 demux->offset_seek_seqnum = gst_event_get_seqnum (event);
6029 res = gst_pad_push_event (demux->sinkpad, event);
6030 demux->offset_seek_seqnum = 0;
6035 /* check for seekable upstream, above and beyond a mere query */
6037 gst_qtdemux_check_seekability (GstQTDemux * demux)
6040 gboolean seekable = FALSE;
6041 gint64 start = -1, stop = -1;
6043 if (demux->upstream_size)
6046 query = gst_query_new_seeking (GST_FORMAT_BYTES);
6047 if (!gst_pad_peer_query (demux->sinkpad, query)) {
6048 GST_DEBUG_OBJECT (demux, "seeking query failed");
6052 gst_query_parse_seeking (query, NULL, &seekable, &start, &stop);
6054 /* try harder to query upstream size if we didn't get it the first time */
6055 if (seekable && stop == -1) {
6056 GST_DEBUG_OBJECT (demux, "doing duration query to fix up unset stop");
6057 gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &stop);
6060 /* if upstream doesn't know the size, it's likely that it's not seekable in
6061 * practice even if it technically may be seekable */
6062 if (seekable && (start != 0 || stop <= start)) {
6063 GST_DEBUG_OBJECT (demux, "seekable but unknown start/stop -> disable");
6068 gst_query_unref (query);
6070 GST_DEBUG_OBJECT (demux, "seekable: %d (%" G_GUINT64_FORMAT " - %"
6071 G_GUINT64_FORMAT ")", seekable, start, stop);
6072 demux->upstream_seekable = seekable;
6073 demux->upstream_size = seekable ? stop : -1;
6077 gst_qtdemux_drop_data (GstQTDemux * demux, gint bytes)
6079 g_return_if_fail (bytes <= demux->todrop);
6081 GST_LOG_OBJECT (demux, "Dropping %d bytes", bytes);
6082 gst_adapter_flush (demux->adapter, bytes);
6083 demux->neededbytes -= bytes;
6084 demux->offset += bytes;
6085 demux->todrop -= bytes;
6089 gst_qtdemux_check_send_pending_segment (GstQTDemux * demux)
6091 if (G_UNLIKELY (demux->pending_newsegment)) {
6094 gst_qtdemux_push_pending_newsegment (demux);
6095 /* clear to send tags on all streams */
6096 for (i = 0; i < demux->n_streams; i++) {
6097 QtDemuxStream *stream;
6098 stream = demux->streams[i];
6099 gst_qtdemux_push_tags (demux, stream);
6100 if (stream->sparse) {
6101 GST_INFO_OBJECT (demux, "Sending gap event on stream %d", i);
6102 gst_pad_push_event (stream->pad,
6103 gst_event_new_gap (stream->segment.position, GST_CLOCK_TIME_NONE));
6110 gst_qtdemux_send_gap_for_segment (GstQTDemux * demux,
6111 QtDemuxStream * stream, gint segment_index, GstClockTime pos)
6113 GstClockTime ts, dur;
6118 stream->segments[segment_index].duration - (pos -
6119 stream->segments[segment_index].time);
6120 gap = gst_event_new_gap (ts, dur);
6121 stream->time_position += dur;
6123 GST_DEBUG_OBJECT (stream->pad, "Pushing gap for empty "
6124 "segment: %" GST_PTR_FORMAT, gap);
6125 gst_pad_push_event (stream->pad, gap);
6129 gst_qtdemux_stream_send_initial_gap_segments (GstQTDemux * demux,
6130 QtDemuxStream * stream)
6134 /* Push any initial gap segments before proceeding to the
6136 for (i = 0; i < stream->n_segments; i++) {
6137 gst_qtdemux_activate_segment (demux, stream, i, stream->time_position);
6139 if (QTSEGMENT_IS_EMPTY (&stream->segments[i])) {
6140 gst_qtdemux_send_gap_for_segment (demux, stream, i,
6141 stream->time_position);
6143 /* Only support empty segment at the beginning followed by
6144 * one non-empty segment, this was checked when parsing the
6145 * edts atom, arriving here is unexpected */
6146 g_assert (i + 1 == stream->n_segments);
6152 static GstFlowReturn
6153 gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent, GstBuffer * inbuf)
6157 demux = GST_QTDEMUX (parent);
6159 GST_DEBUG_OBJECT (demux,
6160 "Received buffer pts:%" GST_TIME_FORMAT " dts:%" GST_TIME_FORMAT
6161 " offset:%" G_GUINT64_FORMAT " size:%" G_GSIZE_FORMAT " demux offset:%"
6162 G_GUINT64_FORMAT, GST_TIME_ARGS (GST_BUFFER_PTS (inbuf)),
6163 GST_TIME_ARGS (GST_BUFFER_DTS (inbuf)), GST_BUFFER_OFFSET (inbuf),
6164 gst_buffer_get_size (inbuf), demux->offset);
6166 if (GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_DISCONT)) {
6167 gboolean is_gap_input = FALSE;
6170 GST_DEBUG_OBJECT (demux, "Got DISCONT, marking all streams as DISCONT");
6172 for (i = 0; i < demux->n_streams; i++) {
6173 demux->streams[i]->discont = TRUE;
6176 /* Check if we can land back on our feet in the case where upstream is
6177 * handling the seeking/pushing of samples with gaps in between (like
6178 * in the case of trick-mode DASH for example) */
6179 if (demux->upstream_format_is_time
6180 && GST_BUFFER_OFFSET (inbuf) != GST_BUFFER_OFFSET_NONE) {
6182 for (i = 0; i < demux->n_streams; i++) {
6184 GST_LOG_OBJECT (demux,
6185 "Stream #%d , checking if offset %" G_GUINT64_FORMAT
6186 " is a sample start", i, GST_BUFFER_OFFSET (inbuf));
6188 gst_qtdemux_find_index_for_given_media_offset_linear (demux,
6189 demux->streams[i], GST_BUFFER_OFFSET (inbuf));
6191 QtDemuxSample *sample = &demux->streams[i]->samples[res];
6192 GST_LOG_OBJECT (demux,
6193 "Checking if sample %d from stream %d is valid (offset:%"
6194 G_GUINT64_FORMAT " size:%" G_GUINT32_FORMAT ")", res, i,
6195 sample->offset, sample->size);
6196 if (sample->offset == GST_BUFFER_OFFSET (inbuf)) {
6197 GST_LOG_OBJECT (demux,
6198 "new buffer corresponds to a valid sample : %" G_GUINT32_FORMAT,
6200 is_gap_input = TRUE;
6201 /* We can go back to standard playback mode */
6202 demux->state = QTDEMUX_STATE_MOVIE;
6203 /* Remember which sample this stream is at */
6204 demux->streams[i]->sample_index = res;
6205 /* Finally update all push-based values to the expected values */
6206 demux->neededbytes = demux->streams[i]->samples[res].size;
6208 demux->offset = GST_BUFFER_OFFSET (inbuf);
6212 if (!is_gap_input) {
6213 /* Reset state if it's a real discont */
6214 demux->neededbytes = 16;
6215 demux->state = QTDEMUX_STATE_INITIAL;
6216 demux->offset = GST_BUFFER_OFFSET (inbuf);
6219 /* Reverse fragmented playback, need to flush all we have before
6220 * consuming a new fragment.
6221 * The samples array have the timestamps calculated by accumulating the
6222 * durations but this won't work for reverse playback of fragments as
6223 * the timestamps of a subsequent fragment should be smaller than the
6224 * previously received one. */
6225 if (!is_gap_input && demux->fragmented && demux->segment.rate < 0) {
6226 gst_qtdemux_process_adapter (demux, TRUE);
6227 for (i = 0; i < demux->n_streams; i++)
6228 gst_qtdemux_stream_flush_samples_data (demux, demux->streams[i]);
6232 gst_adapter_push (demux->adapter, inbuf);
6234 GST_DEBUG_OBJECT (demux,
6235 "pushing in inbuf %p, neededbytes:%u, available:%" G_GSIZE_FORMAT, inbuf,
6236 demux->neededbytes, gst_adapter_available (demux->adapter));
6238 return gst_qtdemux_process_adapter (demux, FALSE);
6241 static GstFlowReturn
6242 gst_qtdemux_process_adapter (GstQTDemux * demux, gboolean force)
6244 GstFlowReturn ret = GST_FLOW_OK;
6246 /* we never really mean to buffer that much */
6247 if (demux->neededbytes == -1) {
6251 while (((gst_adapter_available (demux->adapter)) >= demux->neededbytes) &&
6252 (ret == GST_FLOW_OK || (ret == GST_FLOW_NOT_LINKED && force))) {
6254 #ifndef GST_DISABLE_GST_DEBUG
6256 guint64 discont_offset, distance_from_discont;
6258 discont_offset = gst_adapter_offset_at_discont (demux->adapter);
6259 distance_from_discont =
6260 gst_adapter_distance_from_discont (demux->adapter);
6262 GST_DEBUG_OBJECT (demux,
6263 "state:%s , demux->neededbytes:%d, demux->offset:%" G_GUINT64_FORMAT
6264 " adapter offset :%" G_GUINT64_FORMAT " (+ %" G_GUINT64_FORMAT
6265 " bytes)", qt_demux_state_string (demux->state), demux->neededbytes,
6266 demux->offset, discont_offset, distance_from_discont);
6270 switch (demux->state) {
6271 case QTDEMUX_STATE_INITIAL:{
6276 gst_qtdemux_check_seekability (demux);
6278 data = gst_adapter_map (demux->adapter, demux->neededbytes);
6280 /* get fourcc/length, set neededbytes */
6281 extract_initial_length_and_fourcc ((guint8 *) data, demux->neededbytes,
6283 gst_adapter_unmap (demux->adapter);
6285 GST_DEBUG_OBJECT (demux, "Peeking found [%" GST_FOURCC_FORMAT "] "
6286 "size: %" G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), size);
6288 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
6289 (_("This file is invalid and cannot be played.")),
6290 ("initial atom '%" GST_FOURCC_FORMAT "' has empty length",
6291 GST_FOURCC_ARGS (fourcc)));
6292 ret = GST_FLOW_ERROR;
6295 if (fourcc == FOURCC_mdat) {
6296 gint next_entry = next_entry_size (demux);
6297 if (demux->n_streams > 0 && (next_entry != -1 || !demux->fragmented)) {
6298 /* we have the headers, start playback */
6299 demux->state = QTDEMUX_STATE_MOVIE;
6300 demux->neededbytes = next_entry;
6301 demux->mdatleft = size;
6303 /* no headers yet, try to get them */
6306 guint64 old, target;
6309 old = demux->offset;
6310 target = old + size;
6312 /* try to jump over the atom with a seek */
6313 /* only bother if it seems worth doing so,
6314 * and avoids possible upstream/server problems */
6315 if (demux->upstream_seekable &&
6316 demux->upstream_size > 4 * (1 << 20)) {
6317 res = qtdemux_seek_offset (demux, target);
6319 GST_DEBUG_OBJECT (demux, "skipping seek");
6324 GST_DEBUG_OBJECT (demux, "seek success");
6325 /* remember the offset fo the first mdat so we can seek back to it
6326 * after we have the headers */
6327 if (fourcc == FOURCC_mdat && demux->first_mdat == -1) {
6328 demux->first_mdat = old;
6329 GST_DEBUG_OBJECT (demux, "first mdat at %" G_GUINT64_FORMAT,
6332 /* seek worked, continue reading */
6333 demux->offset = target;
6334 demux->neededbytes = 16;
6335 demux->state = QTDEMUX_STATE_INITIAL;
6337 /* seek failed, need to buffer */
6338 demux->offset = old;
6339 GST_DEBUG_OBJECT (demux, "seek failed/skipped");
6340 /* there may be multiple mdat (or alike) buffers */
6342 if (demux->mdatbuffer)
6343 bs = gst_buffer_get_size (demux->mdatbuffer);
6346 if (size + bs > 10 * (1 << 20))
6348 demux->state = QTDEMUX_STATE_BUFFER_MDAT;
6349 demux->neededbytes = size;
6350 if (!demux->mdatbuffer)
6351 demux->mdatoffset = demux->offset;
6354 } else if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
6355 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
6356 (_("This file is invalid and cannot be played.")),
6357 ("atom %" GST_FOURCC_FORMAT " has bogus size %" G_GUINT64_FORMAT,
6358 GST_FOURCC_ARGS (fourcc), size));
6359 ret = GST_FLOW_ERROR;
6362 /* this means we already started buffering and still no moov header,
6363 * let's continue buffering everything till we get moov */
6364 if (demux->mdatbuffer && !(fourcc == FOURCC_moov
6365 || fourcc == FOURCC_moof))
6367 demux->neededbytes = size;
6368 demux->state = QTDEMUX_STATE_HEADER;
6372 case QTDEMUX_STATE_HEADER:{
6376 GST_DEBUG_OBJECT (demux, "In header");
6378 data = gst_adapter_map (demux->adapter, demux->neededbytes);
6380 /* parse the header */
6381 extract_initial_length_and_fourcc (data, demux->neededbytes, NULL,
6383 if (fourcc == FOURCC_moov) {
6386 /* in usual fragmented setup we could try to scan for more
6387 * and end up at the the moov (after mdat) again */
6388 if (demux->got_moov && demux->n_streams > 0 &&
6390 || demux->last_moov_offset == demux->offset)) {
6391 GST_DEBUG_OBJECT (demux,
6392 "Skipping moov atom as we have (this) one already");
6394 GST_DEBUG_OBJECT (demux, "Parsing [moov]");
6396 if (demux->got_moov && demux->fragmented) {
6397 GST_DEBUG_OBJECT (demux,
6398 "Got a second moov, clean up data from old one");
6399 if (demux->moov_node_compressed) {
6400 g_node_destroy (demux->moov_node_compressed);
6401 if (demux->moov_node)
6402 g_free (demux->moov_node->data);
6404 demux->moov_node_compressed = NULL;
6405 if (demux->moov_node)
6406 g_node_destroy (demux->moov_node);
6407 demux->moov_node = NULL;
6409 /* prepare newsegment to send when streaming actually starts */
6410 if (!demux->pending_newsegment) {
6411 demux->pending_newsegment =
6412 gst_event_new_segment (&demux->segment);
6413 if (demux->segment_seqnum)
6414 gst_event_set_seqnum (demux->pending_newsegment,
6415 demux->segment_seqnum);
6419 demux->last_moov_offset = demux->offset;
6421 qtdemux_parse_moov (demux, data, demux->neededbytes);
6422 qtdemux_node_dump (demux, demux->moov_node);
6423 qtdemux_parse_tree (demux);
6424 qtdemux_prepare_streams (demux);
6425 if (!demux->got_moov)
6426 qtdemux_expose_streams (demux);
6429 for (n = 0; n < demux->n_streams; n++) {
6430 QtDemuxStream *stream = demux->streams[n];
6432 gst_qtdemux_configure_stream (demux, stream);
6436 demux->got_moov = TRUE;
6437 gst_qtdemux_check_send_pending_segment (demux);
6439 /* fragmented streams headers shouldn't contain edts atoms */
6440 if (!demux->fragmented) {
6441 for (n = 0; n < demux->n_streams; n++) {
6442 gst_qtdemux_stream_send_initial_gap_segments (demux,
6447 if (demux->moov_node_compressed) {
6448 g_node_destroy (demux->moov_node_compressed);
6449 g_free (demux->moov_node->data);
6451 demux->moov_node_compressed = NULL;
6452 g_node_destroy (demux->moov_node);
6453 demux->moov_node = NULL;
6454 GST_DEBUG_OBJECT (demux, "Finished parsing the header");
6456 } else if (fourcc == FOURCC_moof) {
6457 if ((demux->got_moov || demux->media_caps) && demux->fragmented) {
6459 GstClockTime prev_pts;
6460 guint64 prev_offset;
6461 guint64 adapter_discont_offset, adapter_discont_dist;
6463 GST_DEBUG_OBJECT (demux, "Parsing [moof]");
6466 * The timestamp of the moof buffer is relevant as some scenarios
6467 * won't have the initial timestamp in the atoms. Whenever a new
6468 * buffer has started, we get that buffer's PTS and use it as a base
6469 * timestamp for the trun entries.
6471 * To keep track of the current buffer timestamp and starting point
6472 * we use gst_adapter_prev_pts that gives us the PTS and the distance
6473 * from the beggining of the buffer, with the distance and demux->offset
6474 * we know if it is still the same buffer or not.
6476 prev_pts = gst_adapter_prev_pts (demux->adapter, &dist);
6477 prev_offset = demux->offset - dist;
6478 if (demux->fragment_start_offset == -1
6479 || prev_offset > demux->fragment_start_offset) {
6480 demux->fragment_start_offset = prev_offset;
6481 demux->fragment_start = prev_pts;
6482 GST_DEBUG_OBJECT (demux,
6483 "New fragment start found at: %" G_GUINT64_FORMAT " : %"
6484 GST_TIME_FORMAT, demux->fragment_start_offset,
6485 GST_TIME_ARGS (demux->fragment_start));
6488 /* We can't use prev_offset() here because this would require
6489 * upstream to set consistent and correct offsets on all buffers
6490 * since the discont. Nothing ever did that in the past and we
6491 * would break backwards compatibility here then.
6492 * Instead take the offset we had at the last discont and count
6493 * the bytes from there. This works with old code as there would
6494 * be no discont between moov and moof, and also works with
6495 * adaptivedemux which correctly sets offset and will set the
6496 * DISCONT flag accordingly when needed.
6498 * We also only do this for upstream TIME segments as otherwise
6499 * there are potential backwards compatibility problems with
6500 * seeking in PUSH mode and upstream providing inconsistent
6502 adapter_discont_offset =
6503 gst_adapter_offset_at_discont (demux->adapter);
6504 adapter_discont_dist =
6505 gst_adapter_distance_from_discont (demux->adapter);
6507 GST_DEBUG_OBJECT (demux,
6508 "demux offset %" G_GUINT64_FORMAT " adapter offset %"
6509 G_GUINT64_FORMAT " (+ %" G_GUINT64_FORMAT " bytes)",
6510 demux->offset, adapter_discont_offset, adapter_discont_dist);
6512 if (demux->upstream_format_is_time) {
6513 demux->moof_offset = adapter_discont_offset;
6514 if (demux->moof_offset != GST_BUFFER_OFFSET_NONE)
6515 demux->moof_offset += adapter_discont_dist;
6516 if (demux->moof_offset == GST_BUFFER_OFFSET_NONE)
6517 demux->moof_offset = demux->offset;
6519 demux->moof_offset = demux->offset;
6522 if (!qtdemux_parse_moof (demux, data, demux->neededbytes,
6523 demux->moof_offset, NULL)) {
6524 gst_adapter_unmap (demux->adapter);
6525 ret = GST_FLOW_ERROR;
6528 /* in MSS we need to expose the pads after the first moof as we won't get a moov */
6529 if (demux->mss_mode && !demux->exposed) {
6530 if (!demux->pending_newsegment) {
6531 GST_DEBUG_OBJECT (demux, "new pending_newsegment");
6532 demux->pending_newsegment =
6533 gst_event_new_segment (&demux->segment);
6534 if (demux->segment_seqnum)
6535 gst_event_set_seqnum (demux->pending_newsegment,
6536 demux->segment_seqnum);
6538 qtdemux_expose_streams (demux);
6541 GST_DEBUG_OBJECT (demux, "Discarding [moof]");
6543 } else if (fourcc == FOURCC_ftyp) {
6544 GST_DEBUG_OBJECT (demux, "Parsing [ftyp]");
6545 qtdemux_parse_ftyp (demux, data, demux->neededbytes);
6546 } else if (fourcc == FOURCC_uuid) {
6547 GST_DEBUG_OBJECT (demux, "Parsing [uuid]");
6548 qtdemux_parse_uuid (demux, data, demux->neededbytes);
6549 } else if (fourcc == FOURCC_sidx) {
6550 GST_DEBUG_OBJECT (demux, "Parsing [sidx]");
6551 qtdemux_parse_sidx (demux, data, demux->neededbytes);
6555 /* [styp] is like a [ftyp], but in fragment header. We ignore it for now
6558 /* [free] is a padding atom */
6559 GST_DEBUG_OBJECT (demux,
6560 "Skipping fourcc while parsing header : %" GST_FOURCC_FORMAT,
6561 GST_FOURCC_ARGS (fourcc));
6564 GST_WARNING_OBJECT (demux,
6565 "Unknown fourcc while parsing header : %" GST_FOURCC_FORMAT,
6566 GST_FOURCC_ARGS (fourcc));
6567 /* Let's jump that one and go back to initial state */
6571 gst_adapter_unmap (demux->adapter);
6574 if (demux->mdatbuffer && demux->n_streams) {
6575 gsize remaining_data_size = 0;
6577 /* the mdat was before the header */
6578 GST_DEBUG_OBJECT (demux, "We have n_streams:%d and mdatbuffer:%p",
6579 demux->n_streams, demux->mdatbuffer);
6580 /* restore our adapter/offset view of things with upstream;
6581 * put preceding buffered data ahead of current moov data.
6582 * This should also handle evil mdat, moov, mdat cases and alike */
6583 gst_adapter_flush (demux->adapter, demux->neededbytes);
6585 /* Store any remaining data after the mdat for later usage */
6586 remaining_data_size = gst_adapter_available (demux->adapter);
6587 if (remaining_data_size > 0) {
6588 g_assert (demux->restoredata_buffer == NULL);
6589 demux->restoredata_buffer =
6590 gst_adapter_take_buffer (demux->adapter, remaining_data_size);
6591 demux->restoredata_offset = demux->offset + demux->neededbytes;
6592 GST_DEBUG_OBJECT (demux,
6593 "Stored %" G_GSIZE_FORMAT " post mdat bytes at offset %"
6594 G_GUINT64_FORMAT, remaining_data_size,
6595 demux->restoredata_offset);
6598 gst_adapter_push (demux->adapter, demux->mdatbuffer);
6599 demux->mdatbuffer = NULL;
6600 demux->offset = demux->mdatoffset;
6601 demux->neededbytes = next_entry_size (demux);
6602 demux->state = QTDEMUX_STATE_MOVIE;
6603 demux->mdatleft = gst_adapter_available (demux->adapter);
6605 GST_DEBUG_OBJECT (demux, "Carrying on normally");
6606 gst_adapter_flush (demux->adapter, demux->neededbytes);
6608 /* only go back to the mdat if there are samples to play */
6609 if (demux->got_moov && demux->first_mdat != -1
6610 && has_next_entry (demux)) {
6613 /* we need to seek back */
6614 res = qtdemux_seek_offset (demux, demux->first_mdat);
6616 demux->offset = demux->first_mdat;
6618 GST_DEBUG_OBJECT (demux, "Seek back failed");
6621 demux->offset += demux->neededbytes;
6623 demux->neededbytes = 16;
6624 demux->state = QTDEMUX_STATE_INITIAL;
6629 case QTDEMUX_STATE_BUFFER_MDAT:{
6633 GST_DEBUG_OBJECT (demux, "Got our buffer at offset %" G_GUINT64_FORMAT,
6635 buf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
6636 gst_buffer_extract (buf, 0, fourcc, 4);
6637 GST_DEBUG_OBJECT (demux, "mdatbuffer starts with %" GST_FOURCC_FORMAT,
6638 GST_FOURCC_ARGS (QT_FOURCC (fourcc)));
6639 if (demux->mdatbuffer)
6640 demux->mdatbuffer = gst_buffer_append (demux->mdatbuffer, buf);
6642 demux->mdatbuffer = buf;
6643 demux->offset += demux->neededbytes;
6644 demux->neededbytes = 16;
6645 demux->state = QTDEMUX_STATE_INITIAL;
6646 gst_qtdemux_post_progress (demux, 1, 1);
6650 case QTDEMUX_STATE_MOVIE:{
6651 QtDemuxStream *stream = NULL;
6652 QtDemuxSample *sample;
6654 GstClockTime dts, pts, duration;
6657 GST_DEBUG_OBJECT (demux,
6658 "BEGIN // in MOVIE for offset %" G_GUINT64_FORMAT, demux->offset);
6660 if (demux->fragmented) {
6661 GST_DEBUG_OBJECT (demux, "mdat remaining %" G_GUINT64_FORMAT,
6663 if (G_LIKELY (demux->todrop < demux->mdatleft)) {
6664 /* if needed data starts within this atom,
6665 * then it should not exceed this atom */
6666 if (G_UNLIKELY (demux->neededbytes > demux->mdatleft)) {
6667 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
6668 (_("This file is invalid and cannot be played.")),
6669 ("sample data crosses atom boundary"));
6670 ret = GST_FLOW_ERROR;
6673 demux->mdatleft -= demux->neededbytes;
6675 GST_DEBUG_OBJECT (demux, "data atom emptied; resuming atom scan");
6676 /* so we are dropping more than left in this atom */
6677 gst_qtdemux_drop_data (demux, demux->mdatleft);
6678 demux->mdatleft = 0;
6680 /* need to resume atom parsing so we do not miss any other pieces */
6681 demux->state = QTDEMUX_STATE_INITIAL;
6682 demux->neededbytes = 16;
6684 /* check if there was any stored post mdat data from previous buffers */
6685 if (demux->restoredata_buffer) {
6686 g_assert (gst_adapter_available (demux->adapter) == 0);
6688 gst_adapter_push (demux->adapter, demux->restoredata_buffer);
6689 demux->restoredata_buffer = NULL;
6690 demux->offset = demux->restoredata_offset;
6697 if (demux->todrop) {
6698 if (demux->cenc_aux_info_offset > 0) {
6702 GST_DEBUG_OBJECT (demux, "parsing cenc auxiliary info");
6703 data = gst_adapter_map (demux->adapter, demux->todrop);
6704 gst_byte_reader_init (&br, data + 8, demux->todrop);
6705 if (!qtdemux_parse_cenc_aux_info (demux, demux->streams[0], &br,
6706 demux->cenc_aux_info_sizes, demux->cenc_aux_sample_count)) {
6707 GST_ERROR_OBJECT (demux, "failed to parse cenc auxiliary info");
6708 ret = GST_FLOW_ERROR;
6709 gst_adapter_unmap (demux->adapter);
6710 g_free (demux->cenc_aux_info_sizes);
6711 demux->cenc_aux_info_sizes = NULL;
6714 demux->cenc_aux_info_offset = 0;
6715 g_free (demux->cenc_aux_info_sizes);
6716 demux->cenc_aux_info_sizes = NULL;
6717 gst_adapter_unmap (demux->adapter);
6719 gst_qtdemux_drop_data (demux, demux->todrop);
6723 /* initial newsegment sent here after having added pads,
6724 * possible others in sink_event */
6725 gst_qtdemux_check_send_pending_segment (demux);
6727 /* Figure out which stream this packet belongs to */
6728 for (i = 0; i < demux->n_streams; i++) {
6729 stream = demux->streams[i];
6730 if (stream->sample_index >= stream->n_samples)
6732 GST_LOG_OBJECT (demux,
6733 "Checking stream %d (sample_index:%d / offset:%" G_GUINT64_FORMAT
6734 " / size:%d)", i, stream->sample_index,
6735 stream->samples[stream->sample_index].offset,
6736 stream->samples[stream->sample_index].size);
6738 if (stream->samples[stream->sample_index].offset == demux->offset)
6742 if (G_UNLIKELY (stream == NULL || i == demux->n_streams))
6743 goto unknown_stream;
6745 if (stream->new_caps) {
6746 gst_qtdemux_configure_stream (demux, stream);
6749 /* Put data in a buffer, set timestamps, caps, ... */
6750 sample = &stream->samples[stream->sample_index];
6752 if (G_LIKELY (!(STREAM_IS_EOS (stream)))) {
6753 GST_DEBUG_OBJECT (demux, "stream : %" GST_FOURCC_FORMAT,
6754 GST_FOURCC_ARGS (stream->fourcc));
6756 dts = QTSAMPLE_DTS (stream, sample);
6757 pts = QTSAMPLE_PTS (stream, sample);
6758 duration = QTSAMPLE_DUR_DTS (stream, sample, dts);
6759 keyframe = QTSAMPLE_KEYFRAME (stream, sample);
6761 /* check for segment end */
6762 if (G_UNLIKELY (demux->segment.stop != -1
6763 && demux->segment.stop <= pts && stream->on_keyframe)) {
6764 GST_DEBUG_OBJECT (demux, "we reached the end of our segment.");
6765 stream->time_position = GST_CLOCK_TIME_NONE; /* this means EOS */
6767 /* skip this data, stream is EOS */
6768 gst_adapter_flush (demux->adapter, demux->neededbytes);
6770 /* check if all streams are eos */
6772 for (i = 0; i < demux->n_streams; i++) {
6773 if (!STREAM_IS_EOS (demux->streams[i])) {
6779 if (ret == GST_FLOW_EOS) {
6780 GST_DEBUG_OBJECT (demux, "All streams are EOS, signal upstream");
6787 gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
6789 /* FIXME: should either be an assert or a plain check */
6790 g_return_val_if_fail (outbuf != NULL, GST_FLOW_ERROR);
6792 ret = gst_qtdemux_decorate_and_push_buffer (demux, stream, outbuf,
6793 dts, pts, duration, keyframe, dts, demux->offset);
6797 ret = gst_qtdemux_combine_flows (demux, stream, ret);
6798 if (ret != GST_FLOW_OK && ret != GST_FLOW_NOT_LINKED)
6799 goto non_ok_unlinked_flow;
6801 /* skip this data, stream is EOS */
6802 gst_adapter_flush (demux->adapter, demux->neededbytes);
6805 stream->sample_index++;
6806 stream->offset_in_sample = 0;
6808 /* update current offset and figure out size of next buffer */
6809 GST_LOG_OBJECT (demux, "increasing offset %" G_GUINT64_FORMAT " by %u",
6810 demux->offset, demux->neededbytes);
6811 demux->offset += demux->neededbytes;
6812 GST_LOG_OBJECT (demux, "offset is now %" G_GUINT64_FORMAT,
6815 if ((demux->neededbytes = next_entry_size (demux)) == -1) {
6816 if (demux->fragmented) {
6817 GST_DEBUG_OBJECT (demux, "(temporarily) out of fragmented samples");
6818 /* there may be more to follow, only finish this atom */
6819 demux->todrop = demux->mdatleft;
6820 demux->neededbytes = demux->todrop;
6832 /* when buffering movie data, at least show user something is happening */
6833 if (ret == GST_FLOW_OK && demux->state == QTDEMUX_STATE_BUFFER_MDAT &&
6834 gst_adapter_available (demux->adapter) <= demux->neededbytes) {
6835 gst_qtdemux_post_progress (demux, gst_adapter_available (demux->adapter),
6836 demux->neededbytes);
6843 non_ok_unlinked_flow:
6845 GST_DEBUG_OBJECT (demux, "Stopping, combined return flow %s",
6846 gst_flow_get_name (ret));
6851 GST_ELEMENT_ERROR (demux, STREAM, FAILED, (NULL), ("unknown stream found"));
6852 ret = GST_FLOW_ERROR;
6857 GST_DEBUG_OBJECT (demux, "no next entry, EOS");
6863 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
6864 (NULL), ("qtdemuxer invalid state %d", demux->state));
6865 ret = GST_FLOW_ERROR;
6870 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
6871 (NULL), ("no 'moov' atom within the first 10 MB"));
6872 ret = GST_FLOW_ERROR;
6878 qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent)
6883 query = gst_query_new_scheduling ();
6885 if (!gst_pad_peer_query (sinkpad, query)) {
6886 gst_query_unref (query);
6890 pull_mode = gst_query_has_scheduling_mode_with_flags (query,
6891 GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
6892 gst_query_unref (query);
6897 GST_DEBUG_OBJECT (sinkpad, "activating pull");
6898 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
6902 GST_DEBUG_OBJECT (sinkpad, "activating push");
6903 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
6908 qtdemux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
6909 GstPadMode mode, gboolean active)
6912 GstQTDemux *demux = GST_QTDEMUX (parent);
6915 case GST_PAD_MODE_PUSH:
6916 demux->pullbased = FALSE;
6919 case GST_PAD_MODE_PULL:
6921 demux->pullbased = TRUE;
6922 res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_qtdemux_loop,
6925 res = gst_pad_stop_task (sinkpad);
6937 qtdemux_inflate (void *z_buffer, guint z_length, guint * length)
6943 memset (&z, 0, sizeof (z));
6948 if ((ret = inflateInit (&z)) != Z_OK) {
6949 GST_ERROR ("inflateInit() returned %d", ret);
6953 z.next_in = z_buffer;
6954 z.avail_in = z_length;
6956 buffer = (guint8 *) g_malloc (*length);
6957 z.avail_out = *length;
6958 z.next_out = (Bytef *) buffer;
6960 ret = inflate (&z, Z_NO_FLUSH);
6961 if (ret == Z_STREAM_END) {
6963 } else if (ret != Z_OK) {
6964 GST_WARNING ("inflate() returned %d", ret);
6969 buffer = (guint8 *) g_realloc (buffer, *length);
6970 z.next_out = (Bytef *) (buffer + z.total_out);
6971 z.avail_out += 4096;
6972 } while (z.avail_in > 0);
6974 if (ret != Z_STREAM_END) {
6979 *length = z.total_out;
6986 #endif /* HAVE_ZLIB */
6989 qtdemux_parse_moov (GstQTDemux * qtdemux, const guint8 * buffer, guint length)
6993 qtdemux->moov_node = g_node_new ((guint8 *) buffer);
6995 /* counts as header data */
6996 qtdemux->header_size += length;
6998 GST_DEBUG_OBJECT (qtdemux, "parsing 'moov' atom");
6999 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buffer, length);
7001 cmov = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_cmov);
7008 dcom = qtdemux_tree_get_child_by_type (cmov, FOURCC_dcom);
7009 cmvd = qtdemux_tree_get_child_by_type (cmov, FOURCC_cmvd);
7010 if (dcom == NULL || cmvd == NULL)
7011 goto invalid_compression;
7013 dcom_len = QT_UINT32 (dcom->data);
7015 goto invalid_compression;
7017 method = QT_FOURCC ((guint8 *) dcom->data + 8);
7021 guint uncompressed_length;
7022 guint compressed_length;
7026 cmvd_len = QT_UINT32 ((guint8 *) cmvd->data);
7028 goto invalid_compression;
7030 uncompressed_length = QT_UINT32 ((guint8 *) cmvd->data + 8);
7031 compressed_length = cmvd_len - 12;
7032 GST_LOG ("length = %u", uncompressed_length);
7035 (guint8 *) qtdemux_inflate ((guint8 *) cmvd->data + 12,
7036 compressed_length, &uncompressed_length);
7039 qtdemux->moov_node_compressed = qtdemux->moov_node;
7040 qtdemux->moov_node = g_node_new (buf);
7042 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buf,
7043 uncompressed_length);
7047 #endif /* HAVE_ZLIB */
7049 GST_WARNING_OBJECT (qtdemux, "unknown or unhandled header compression "
7050 "type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (method));
7057 invalid_compression:
7059 GST_ERROR_OBJECT (qtdemux, "invalid compressed header");
7065 qtdemux_parse_container (GstQTDemux * qtdemux, GNode * node, const guint8 * buf,
7068 while (G_UNLIKELY (buf < end)) {
7072 if (G_UNLIKELY (buf + 4 > end)) {
7073 GST_LOG_OBJECT (qtdemux, "buffer overrun");
7076 len = QT_UINT32 (buf);
7077 if (G_UNLIKELY (len == 0)) {
7078 GST_LOG_OBJECT (qtdemux, "empty container");
7081 if (G_UNLIKELY (len < 8)) {
7082 GST_WARNING_OBJECT (qtdemux, "length too short (%d < 8)", len);
7085 if (G_UNLIKELY (len > (end - buf))) {
7086 GST_WARNING_OBJECT (qtdemux, "length too long (%d > %d)", len,
7087 (gint) (end - buf));
7091 child = g_node_new ((guint8 *) buf);
7092 g_node_append (node, child);
7093 GST_LOG_OBJECT (qtdemux, "adding new node of len %d", len);
7094 qtdemux_parse_node (qtdemux, child, buf, len);
7102 qtdemux_parse_theora_extension (GstQTDemux * qtdemux, QtDemuxStream * stream,
7105 int len = QT_UINT32 (xdxt->data);
7106 guint8 *buf = xdxt->data;
7107 guint8 *end = buf + len;
7110 /* skip size and type */
7118 size = QT_UINT32 (buf);
7119 type = QT_FOURCC (buf + 4);
7121 GST_LOG_OBJECT (qtdemux, "%p %p", buf, end);
7123 if (buf + size > end || size <= 0)
7129 GST_WARNING_OBJECT (qtdemux, "have cookie %" GST_FOURCC_FORMAT,
7130 GST_FOURCC_ARGS (type));
7134 buffer = gst_buffer_new_and_alloc (size);
7135 gst_buffer_fill (buffer, 0, buf, size);
7136 stream->buffers = g_slist_append (stream->buffers, buffer);
7137 GST_LOG_OBJECT (qtdemux, "parsing theora header");
7140 buffer = gst_buffer_new_and_alloc (size);
7141 gst_buffer_fill (buffer, 0, buf, size);
7142 stream->buffers = g_slist_append (stream->buffers, buffer);
7143 GST_LOG_OBJECT (qtdemux, "parsing theora comment");
7146 buffer = gst_buffer_new_and_alloc (size);
7147 gst_buffer_fill (buffer, 0, buf, size);
7148 stream->buffers = g_slist_append (stream->buffers, buffer);
7149 GST_LOG_OBJECT (qtdemux, "parsing theora codebook");
7152 GST_WARNING_OBJECT (qtdemux,
7153 "unknown theora cookie %" GST_FOURCC_FORMAT,
7154 GST_FOURCC_ARGS (type));
7163 qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node, const guint8 * buffer,
7167 guint32 node_length = 0;
7168 const QtNodeType *type;
7171 GST_LOG_OBJECT (qtdemux, "qtdemux_parse buffer %p length %u", buffer, length);
7173 if (G_UNLIKELY (length < 8))
7174 goto not_enough_data;
7176 node_length = QT_UINT32 (buffer);
7177 fourcc = QT_FOURCC (buffer + 4);
7179 /* ignore empty nodes */
7180 if (G_UNLIKELY (fourcc == 0 || node_length == 8))
7183 type = qtdemux_type_get (fourcc);
7185 end = buffer + length;
7187 GST_LOG_OBJECT (qtdemux,
7188 "parsing '%" GST_FOURCC_FORMAT "', length=%u, name '%s'",
7189 GST_FOURCC_ARGS (fourcc), node_length, type->name);
7191 if (node_length > length)
7192 goto broken_atom_size;
7194 if (type->flags & QT_FLAG_CONTAINER) {
7195 qtdemux_parse_container (qtdemux, node, buffer + 8, end);
7200 if (node_length < 20) {
7201 GST_LOG_OBJECT (qtdemux, "skipping small stsd box");
7204 GST_DEBUG_OBJECT (qtdemux,
7205 "parsing stsd (sample table, sample description) atom");
7206 /* Skip over 8 byte atom hdr + 1 byte version, 3 bytes flags, 4 byte num_entries */
7207 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
7218 /* also read alac (or whatever) in stead of mp4a in the following,
7219 * since a similar layout is used in other cases as well */
7220 if (fourcc == FOURCC_mp4a)
7222 else if (fourcc == FOURCC_fLaC)
7227 /* There are two things we might encounter here: a true mp4a atom, and
7228 an mp4a entry in an stsd atom. The latter is what we're interested
7229 in, and it looks like an atom, but isn't really one. The true mp4a
7230 atom is short, so we detect it based on length here. */
7231 if (length < min_size) {
7232 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
7233 GST_FOURCC_ARGS (fourcc));
7237 /* 'version' here is the sound sample description version. Types 0 and
7238 1 are documented in the QTFF reference, but type 2 is not: it's
7239 described in Apple header files instead (struct SoundDescriptionV2
7241 version = QT_UINT16 (buffer + 16);
7243 GST_DEBUG_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT " version 0x%08x",
7244 GST_FOURCC_ARGS (fourcc), version);
7246 /* parse any esds descriptors */
7258 GST_WARNING_OBJECT (qtdemux,
7259 "unhandled %" GST_FOURCC_FORMAT " version 0x%08x",
7260 GST_FOURCC_ARGS (fourcc), version);
7265 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
7291 /* codec_data is contained inside these atoms, which all have
7292 * the same format. */
7293 /* video sample description size is 86 bytes without extension.
7294 * node_length have to be bigger than 86 bytes because video sample
7295 * description can include extenstions such as esds, fiel, glbl, etc. */
7296 if (node_length < 86) {
7297 GST_WARNING_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT
7298 " sample description length too short (%u < 86)",
7299 GST_FOURCC_ARGS (fourcc), node_length);
7303 GST_DEBUG_OBJECT (qtdemux, "parsing in %" GST_FOURCC_FORMAT,
7304 GST_FOURCC_ARGS (fourcc));
7306 /* version (2 bytes) : this is set to 0, unless a compressor has changed
7308 * revision level (2 bytes) : must be set to 0. */
7309 version = QT_UINT32 (buffer + 16);
7310 GST_DEBUG_OBJECT (qtdemux, "version %08x", version);
7312 /* compressor name : PASCAL string and informative purposes
7313 * first byte : the number of bytes to be displayed.
7314 * it has to be less than 32 because it is reserved
7315 * space of 32 bytes total including itself. */
7316 str_len = QT_UINT8 (buffer + 50);
7318 GST_DEBUG_OBJECT (qtdemux, "compressorname = %.*s", str_len,
7319 (char *) buffer + 51);
7321 GST_WARNING_OBJECT (qtdemux,
7322 "compressorname length too big (%u > 31)", str_len);
7324 GST_MEMDUMP_OBJECT (qtdemux, "video sample description", buffer,
7326 qtdemux_parse_container (qtdemux, node, buffer + 86, end);
7331 GST_DEBUG_OBJECT (qtdemux, "parsing meta atom");
7332 qtdemux_parse_container (qtdemux, node, buffer + 12, end);
7337 GST_MEMDUMP_OBJECT (qtdemux, "mp4s", buffer, end - buffer);
7338 /* Skip 8 byte header, plus 8 byte version + flags + entry_count */
7339 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
7348 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
7349 GST_FOURCC_ARGS (fourcc));
7353 version = QT_UINT32 (buffer + 12);
7354 GST_DEBUG_OBJECT (qtdemux, "parsing XiTh atom version 0x%08x", version);
7361 GST_DEBUG_OBJECT (qtdemux, "unknown version 0x%08x", version);
7366 if (length < offset) {
7367 GST_WARNING_OBJECT (qtdemux,
7368 "skipping too small %" GST_FOURCC_FORMAT " box",
7369 GST_FOURCC_ARGS (fourcc));
7372 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
7378 qtdemux_parse_container (qtdemux, node, buffer + 0x34, end);
7383 qtdemux_parse_uuid (qtdemux, buffer, end - buffer);
7388 qtdemux_parse_container (qtdemux, node, buffer + 36, end);
7392 if (!strcmp (type->name, "unknown"))
7393 GST_MEMDUMP ("Unknown tag", buffer + 4, end - buffer - 4);
7397 GST_LOG_OBJECT (qtdemux, "parsed '%" GST_FOURCC_FORMAT "'",
7398 GST_FOURCC_ARGS (fourcc));
7404 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
7405 (_("This file is corrupt and cannot be played.")),
7406 ("Not enough data for an atom header, got only %u bytes", length));
7411 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
7412 (_("This file is corrupt and cannot be played.")),
7413 ("Atom '%" GST_FOURCC_FORMAT "' has size of %u bytes, but we have only "
7414 "%u bytes available.", GST_FOURCC_ARGS (fourcc), node_length,
7421 qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc)
7425 guint32 child_fourcc;
7427 for (child = g_node_first_child (node); child;
7428 child = g_node_next_sibling (child)) {
7429 buffer = (guint8 *) child->data;
7431 child_fourcc = QT_FOURCC (buffer + 4);
7433 if (G_UNLIKELY (child_fourcc == fourcc)) {
7441 qtdemux_tree_get_child_by_type_full (GNode * node, guint32 fourcc,
7442 GstByteReader * parser)
7446 guint32 child_fourcc, child_len;
7448 for (child = g_node_first_child (node); child;
7449 child = g_node_next_sibling (child)) {
7450 buffer = (guint8 *) child->data;
7452 child_len = QT_UINT32 (buffer);
7453 child_fourcc = QT_FOURCC (buffer + 4);
7455 if (G_UNLIKELY (child_fourcc == fourcc)) {
7456 if (G_UNLIKELY (child_len < (4 + 4)))
7458 /* FIXME: must verify if atom length < parent atom length */
7459 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
7467 qtdemux_tree_get_sibling_by_type_full (GNode * node, guint32 fourcc,
7468 GstByteReader * parser)
7472 guint32 child_fourcc, child_len;
7474 for (child = g_node_next_sibling (node); child;
7475 child = g_node_next_sibling (child)) {
7476 buffer = (guint8 *) child->data;
7478 child_fourcc = QT_FOURCC (buffer + 4);
7480 if (child_fourcc == fourcc) {
7482 child_len = QT_UINT32 (buffer);
7483 if (G_UNLIKELY (child_len < (4 + 4)))
7485 /* FIXME: must verify if atom length < parent atom length */
7486 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
7495 qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc)
7497 return qtdemux_tree_get_sibling_by_type_full (node, fourcc, NULL);
7501 qtdemux_do_allocation (GstQTDemux * qtdemux, QtDemuxStream * stream)
7503 /* FIXME: This can only reliably work if demuxers have a
7504 * separate streaming thread per srcpad. This should be
7505 * done in a demuxer base class, which integrates parts
7508 * https://bugzilla.gnome.org/show_bug.cgi?id=701856
7513 query = gst_query_new_allocation (stream->caps, FALSE);
7515 if (!gst_pad_peer_query (stream->pad, query)) {
7516 /* not a problem, just debug a little */
7517 GST_DEBUG_OBJECT (qtdemux, "peer ALLOCATION query failed");
7520 if (stream->allocator)
7521 gst_object_unref (stream->allocator);
7523 if (gst_query_get_n_allocation_params (query) > 0) {
7524 /* try the allocator */
7525 gst_query_parse_nth_allocation_param (query, 0, &stream->allocator,
7527 stream->use_allocator = TRUE;
7529 stream->allocator = NULL;
7530 gst_allocation_params_init (&stream->params);
7531 stream->use_allocator = FALSE;
7533 gst_query_unref (query);
7538 gst_qtdemux_configure_protected_caps (GstQTDemux * qtdemux,
7539 QtDemuxStream * stream)
7542 const gchar *selected_system;
7544 g_return_val_if_fail (qtdemux != NULL, FALSE);
7545 g_return_val_if_fail (stream != NULL, FALSE);
7546 g_return_val_if_fail (gst_caps_get_size (stream->caps) == 1, FALSE);
7548 if (stream->protection_scheme_type != FOURCC_cenc) {
7549 GST_ERROR_OBJECT (qtdemux, "unsupported protection scheme");
7552 if (qtdemux->protection_system_ids == NULL) {
7553 GST_ERROR_OBJECT (qtdemux, "stream is protected using cenc, but no "
7554 "cenc protection system information has been found");
7557 g_ptr_array_add (qtdemux->protection_system_ids, NULL);
7558 selected_system = gst_protection_select_system ((const gchar **)
7559 qtdemux->protection_system_ids->pdata);
7560 g_ptr_array_remove_index (qtdemux->protection_system_ids,
7561 qtdemux->protection_system_ids->len - 1);
7562 if (!selected_system) {
7563 GST_ERROR_OBJECT (qtdemux, "stream is protected, but no "
7564 "suitable decryptor element has been found");
7568 s = gst_caps_get_structure (stream->caps, 0);
7569 if (!gst_structure_has_name (s, "application/x-cenc")) {
7570 gst_structure_set (s,
7571 "original-media-type", G_TYPE_STRING, gst_structure_get_name (s),
7572 GST_PROTECTION_SYSTEM_ID_CAPS_FIELD, G_TYPE_STRING, selected_system,
7574 gst_structure_set_name (s, "application/x-cenc");
7580 gst_qtdemux_configure_stream (GstQTDemux * qtdemux, QtDemuxStream * stream)
7582 if (stream->subtype == FOURCC_vide) {
7583 /* fps is calculated base on the duration of the average framerate since
7584 * qt does not have a fixed framerate. */
7585 gboolean fps_available = TRUE;
7587 if ((stream->n_samples == 1) && (stream->first_duration == 0)) {
7592 if (stream->duration == 0 || stream->n_samples < 2) {
7593 stream->fps_n = stream->timescale;
7595 fps_available = FALSE;
7597 GstClockTime avg_duration;
7601 /* duration and n_samples can be updated for fragmented format
7602 * so, framerate of fragmented format is calculated using data in a moof */
7603 if (qtdemux->fragmented && stream->n_samples_moof > 0
7604 && stream->duration_moof > 0) {
7605 n_samples = stream->n_samples_moof;
7606 duration = stream->duration_moof;
7608 n_samples = stream->n_samples;
7609 duration = stream->duration;
7612 /* Calculate a framerate, ignoring the first sample which is sometimes truncated */
7613 /* stream->duration is guint64, timescale, n_samples are guint32 */
7615 gst_util_uint64_scale_round (duration -
7616 stream->first_duration, GST_SECOND,
7617 (guint64) (stream->timescale) * (n_samples - 1));
7619 GST_LOG_OBJECT (qtdemux,
7620 "Calculating avg sample duration based on stream (or moof) duration %"
7622 " minus first sample %u, leaving %d samples gives %"
7623 GST_TIME_FORMAT, duration, stream->first_duration,
7624 n_samples - 1, GST_TIME_ARGS (avg_duration));
7626 gst_video_guess_framerate (avg_duration, &stream->fps_n,
7629 GST_DEBUG_OBJECT (qtdemux,
7630 "Calculating framerate, timescale %u gave fps_n %d fps_d %d",
7631 stream->timescale, stream->fps_n, stream->fps_d);
7636 stream->caps = gst_caps_make_writable (stream->caps);
7638 gst_caps_set_simple (stream->caps,
7639 "width", G_TYPE_INT, stream->width,
7640 "height", G_TYPE_INT, stream->height, NULL);
7642 /* set framerate if calculated framerate is reliable */
7643 if (fps_available) {
7644 gst_caps_set_simple (stream->caps,
7645 "framerate", GST_TYPE_FRACTION, stream->fps_n, stream->fps_d, NULL);
7648 /* calculate pixel-aspect-ratio using display width and height */
7649 GST_DEBUG_OBJECT (qtdemux,
7650 "video size %dx%d, target display size %dx%d", stream->width,
7651 stream->height, stream->display_width, stream->display_height);
7652 /* qt file might have pasp atom */
7653 if (stream->par_w > 0 && stream->par_h > 0) {
7654 GST_DEBUG_OBJECT (qtdemux, "par %d:%d", stream->par_w, stream->par_h);
7655 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
7656 GST_TYPE_FRACTION, stream->par_w, stream->par_h, NULL);
7657 } else if (stream->display_width > 0 && stream->display_height > 0 &&
7658 stream->width > 0 && stream->height > 0) {
7661 /* calculate the pixel aspect ratio using the display and pixel w/h */
7662 n = stream->display_width * stream->height;
7663 d = stream->display_height * stream->width;
7666 GST_DEBUG_OBJECT (qtdemux, "setting PAR to %d/%d", n, d);
7669 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
7670 GST_TYPE_FRACTION, stream->par_w, stream->par_h, NULL);
7673 if (stream->interlace_mode > 0) {
7674 if (stream->interlace_mode == 1) {
7675 gst_caps_set_simple (stream->caps, "interlace-mode", G_TYPE_STRING,
7676 "progressive", NULL);
7677 } else if (stream->interlace_mode == 2) {
7678 gst_caps_set_simple (stream->caps, "interlace-mode", G_TYPE_STRING,
7679 "interleaved", NULL);
7680 if (stream->field_order == 9) {
7681 gst_caps_set_simple (stream->caps, "field-order", G_TYPE_STRING,
7682 "top-field-first", NULL);
7683 } else if (stream->field_order == 14) {
7684 gst_caps_set_simple (stream->caps, "field-order", G_TYPE_STRING,
7685 "bottom-field-first", NULL);
7690 /* Create incomplete colorimetry here if needed */
7691 if (stream->colorimetry.range ||
7692 stream->colorimetry.matrix ||
7693 stream->colorimetry.transfer || stream->colorimetry.primaries) {
7694 gchar *colorimetry =
7695 gst_video_colorimetry_to_string (&stream->colorimetry);
7696 gst_caps_set_simple (stream->caps, "colorimetry", G_TYPE_STRING,
7698 g_free (colorimetry);
7701 if (stream->multiview_mode != GST_VIDEO_MULTIVIEW_MODE_NONE) {
7702 guint par_w = 1, par_h = 1;
7704 if (stream->par_w > 0 && stream->par_h > 0) {
7705 par_w = stream->par_w;
7706 par_h = stream->par_h;
7709 if (gst_video_multiview_guess_half_aspect (stream->multiview_mode,
7710 stream->width, stream->height, par_w, par_h)) {
7711 stream->multiview_flags |= GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT;
7714 gst_caps_set_simple (stream->caps,
7715 "multiview-mode", G_TYPE_STRING,
7716 gst_video_multiview_mode_to_caps_string (stream->multiview_mode),
7717 "multiview-flags", GST_TYPE_VIDEO_MULTIVIEW_FLAGSET,
7718 stream->multiview_flags, GST_FLAG_SET_MASK_EXACT, NULL);
7723 else if (stream->subtype == FOURCC_soun) {
7725 stream->caps = gst_caps_make_writable (stream->caps);
7726 if (stream->rate > 0)
7727 gst_caps_set_simple (stream->caps,
7728 "rate", G_TYPE_INT, (int) stream->rate, NULL);
7729 if (stream->n_channels > 0)
7730 gst_caps_set_simple (stream->caps,
7731 "channels", G_TYPE_INT, stream->n_channels, NULL);
7732 if (stream->n_channels > 2) {
7733 /* FIXME: Need to parse the 'chan' atom to get channel layouts
7734 * correctly; this is just the minimum we can do - assume
7735 * we don't actually have any channel positions. */
7736 gst_caps_set_simple (stream->caps,
7737 "channel-mask", GST_TYPE_BITMASK, G_GUINT64_CONSTANT (0), NULL);
7743 GstCaps *prev_caps = NULL;
7745 GST_PAD_ELEMENT_PRIVATE (stream->pad) = stream;
7746 gst_pad_set_event_function (stream->pad, gst_qtdemux_handle_src_event);
7747 gst_pad_set_query_function (stream->pad, gst_qtdemux_handle_src_query);
7748 gst_pad_set_active (stream->pad, TRUE);
7750 gst_pad_use_fixed_caps (stream->pad);
7752 if (stream->protected) {
7753 if (!gst_qtdemux_configure_protected_caps (qtdemux, stream)) {
7754 GST_ERROR_OBJECT (qtdemux,
7755 "Failed to configure protected stream caps.");
7760 if (stream->new_stream) {
7763 GstStreamFlags stream_flags;
7766 gst_pad_get_sticky_event (qtdemux->sinkpad, GST_EVENT_STREAM_START,
7769 if (gst_event_parse_group_id (event, &qtdemux->group_id))
7770 qtdemux->have_group_id = TRUE;
7772 qtdemux->have_group_id = FALSE;
7773 gst_event_unref (event);
7774 } else if (!qtdemux->have_group_id) {
7775 qtdemux->have_group_id = TRUE;
7776 qtdemux->group_id = gst_util_group_id_next ();
7779 stream->new_stream = FALSE;
7781 gst_pad_create_stream_id_printf (stream->pad,
7782 GST_ELEMENT_CAST (qtdemux), "%03u", stream->track_id);
7783 event = gst_event_new_stream_start (stream_id);
7784 if (qtdemux->have_group_id)
7785 gst_event_set_group_id (event, qtdemux->group_id);
7786 stream_flags = GST_STREAM_FLAG_NONE;
7787 if (stream->disabled)
7788 stream_flags |= GST_STREAM_FLAG_UNSELECT;
7790 stream_flags |= GST_STREAM_FLAG_SPARSE;
7791 gst_event_set_stream_flags (event, stream_flags);
7792 gst_pad_push_event (stream->pad, event);
7796 prev_caps = gst_pad_get_current_caps (stream->pad);
7798 if (!prev_caps || !gst_caps_is_equal_fixed (prev_caps, stream->caps)) {
7799 GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT, stream->caps);
7800 gst_pad_set_caps (stream->pad, stream->caps);
7802 GST_DEBUG_OBJECT (qtdemux, "ignore duplicated caps");
7806 gst_caps_unref (prev_caps);
7807 stream->new_caps = FALSE;
7813 gst_qtdemux_add_stream (GstQTDemux * qtdemux,
7814 QtDemuxStream * stream, GstTagList * list)
7816 gboolean ret = TRUE;
7817 /* consistent default for push based mode */
7818 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
7820 if (stream->subtype == FOURCC_vide) {
7821 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
7824 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
7827 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
7828 gst_object_unref (stream->pad);
7834 qtdemux->n_video_streams++;
7835 } else if (stream->subtype == FOURCC_soun) {
7836 gchar *name = g_strdup_printf ("audio_%u", qtdemux->n_audio_streams);
7839 gst_pad_new_from_static_template (&gst_qtdemux_audiosrc_template, name);
7841 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
7842 gst_object_unref (stream->pad);
7847 qtdemux->n_audio_streams++;
7848 } else if (stream->subtype == FOURCC_strm) {
7849 GST_DEBUG_OBJECT (qtdemux, "stream type, not creating pad");
7850 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
7851 || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt) {
7852 gchar *name = g_strdup_printf ("subtitle_%u", qtdemux->n_sub_streams);
7855 gst_pad_new_from_static_template (&gst_qtdemux_subsrc_template, name);
7857 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
7858 gst_object_unref (stream->pad);
7863 qtdemux->n_sub_streams++;
7864 } else if (stream->caps) {
7865 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
7868 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
7870 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
7871 gst_object_unref (stream->pad);
7876 qtdemux->n_video_streams++;
7878 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
7885 GST_DEBUG_OBJECT (qtdemux, "adding pad %s %p to qtdemux %p",
7886 GST_OBJECT_NAME (stream->pad), stream->pad, qtdemux);
7887 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
7888 gst_flow_combiner_add_pad (qtdemux->flowcombiner, stream->pad);
7890 if (stream->pending_tags)
7891 gst_tag_list_unref (stream->pending_tags);
7892 stream->pending_tags = list;
7894 /* global tags go on each pad anyway */
7895 stream->send_global_tags = TRUE;
7896 /* send upstream GST_EVENT_PROTECTION events that were received before
7897 this source pad was created */
7898 for (l = qtdemux->protection_event_queue.head; l != NULL; l = l->next)
7899 gst_pad_push_event (stream->pad, gst_event_ref (l->data));
7903 gst_tag_list_unref (list);
7907 /* find next atom with @fourcc starting at @offset */
7908 static GstFlowReturn
7909 qtdemux_find_atom (GstQTDemux * qtdemux, guint64 * offset,
7910 guint64 * length, guint32 fourcc)
7916 GST_LOG_OBJECT (qtdemux, "finding fourcc %" GST_FOURCC_FORMAT " at offset %"
7917 G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), *offset);
7923 ret = gst_pad_pull_range (qtdemux->sinkpad, *offset, 16, &buf);
7924 if (G_UNLIKELY (ret != GST_FLOW_OK))
7926 if (G_UNLIKELY (gst_buffer_get_size (buf) != 16)) {
7929 gst_buffer_unref (buf);
7932 gst_buffer_map (buf, &map, GST_MAP_READ);
7933 extract_initial_length_and_fourcc (map.data, 16, length, &lfourcc);
7934 gst_buffer_unmap (buf, &map);
7935 gst_buffer_unref (buf);
7937 if (G_UNLIKELY (*length == 0)) {
7938 GST_DEBUG_OBJECT (qtdemux, "invalid length 0");
7939 ret = GST_FLOW_ERROR;
7943 if (lfourcc == fourcc) {
7944 GST_DEBUG_OBJECT (qtdemux, "found fourcc at offset %" G_GUINT64_FORMAT,
7948 GST_LOG_OBJECT (qtdemux,
7949 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
7950 GST_FOURCC_ARGS (fourcc), *offset);
7959 /* might simply have had last one */
7960 GST_DEBUG_OBJECT (qtdemux, "fourcc not found");
7965 /* should only do something in pull mode */
7966 /* call with OBJECT lock */
7967 static GstFlowReturn
7968 qtdemux_add_fragmented_samples (GstQTDemux * qtdemux)
7970 guint64 length, offset;
7971 GstBuffer *buf = NULL;
7972 GstFlowReturn ret = GST_FLOW_OK;
7973 GstFlowReturn res = GST_FLOW_OK;
7976 offset = qtdemux->moof_offset;
7977 GST_DEBUG_OBJECT (qtdemux, "next moof at offset %" G_GUINT64_FORMAT, offset);
7980 GST_DEBUG_OBJECT (qtdemux, "no next moof");
7981 return GST_FLOW_EOS;
7984 /* best not do pull etc with lock held */
7985 GST_OBJECT_UNLOCK (qtdemux);
7987 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
7988 if (ret != GST_FLOW_OK)
7991 ret = gst_qtdemux_pull_atom (qtdemux, offset, length, &buf);
7992 if (G_UNLIKELY (ret != GST_FLOW_OK))
7994 gst_buffer_map (buf, &map, GST_MAP_READ);
7995 if (!qtdemux_parse_moof (qtdemux, map.data, map.size, offset, NULL)) {
7996 gst_buffer_unmap (buf, &map);
7997 gst_buffer_unref (buf);
8002 gst_buffer_unmap (buf, &map);
8003 gst_buffer_unref (buf);
8007 /* look for next moof */
8008 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
8009 if (G_UNLIKELY (ret != GST_FLOW_OK))
8013 GST_OBJECT_LOCK (qtdemux);
8015 qtdemux->moof_offset = offset;
8021 GST_DEBUG_OBJECT (qtdemux, "failed to parse moof");
8023 res = GST_FLOW_ERROR;
8028 /* maybe upstream temporarily flushing */
8029 if (ret != GST_FLOW_FLUSHING) {
8030 GST_DEBUG_OBJECT (qtdemux, "no next moof");
8033 GST_DEBUG_OBJECT (qtdemux, "upstream WRONG_STATE");
8034 /* resume at current position next time */
8041 /* initialise bytereaders for stbl sub-atoms */
8043 qtdemux_stbl_init (GstQTDemux * qtdemux, QtDemuxStream * stream, GNode * stbl)
8045 stream->stbl_index = -1; /* no samples have yet been parsed */
8046 stream->sample_index = -1;
8048 /* time-to-sample atom */
8049 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stts, &stream->stts))
8052 /* copy atom data into a new buffer for later use */
8053 stream->stts.data = g_memdup (stream->stts.data, stream->stts.size);
8055 /* skip version + flags */
8056 if (!gst_byte_reader_skip (&stream->stts, 1 + 3) ||
8057 !gst_byte_reader_get_uint32_be (&stream->stts, &stream->n_sample_times))
8059 GST_LOG_OBJECT (qtdemux, "%u timestamp blocks", stream->n_sample_times);
8061 /* make sure there's enough data */
8062 if (!qt_atom_parser_has_chunks (&stream->stts, stream->n_sample_times, 8)) {
8063 stream->n_sample_times = gst_byte_reader_get_remaining (&stream->stts) / 8;
8064 GST_LOG_OBJECT (qtdemux, "overriding to %u timestamp blocks",
8065 stream->n_sample_times);
8066 if (!stream->n_sample_times)
8070 /* sync sample atom */
8071 stream->stps_present = FALSE;
8072 if ((stream->stss_present =
8073 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stss,
8074 &stream->stss) ? TRUE : FALSE) == TRUE) {
8075 /* copy atom data into a new buffer for later use */
8076 stream->stss.data = g_memdup (stream->stss.data, stream->stss.size);
8078 /* skip version + flags */
8079 if (!gst_byte_reader_skip (&stream->stss, 1 + 3) ||
8080 !gst_byte_reader_get_uint32_be (&stream->stss, &stream->n_sample_syncs))
8083 if (stream->n_sample_syncs) {
8084 /* make sure there's enough data */
8085 if (!qt_atom_parser_has_chunks (&stream->stss, stream->n_sample_syncs, 4))
8089 /* partial sync sample atom */
8090 if ((stream->stps_present =
8091 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stps,
8092 &stream->stps) ? TRUE : FALSE) == TRUE) {
8093 /* copy atom data into a new buffer for later use */
8094 stream->stps.data = g_memdup (stream->stps.data, stream->stps.size);
8096 /* skip version + flags */
8097 if (!gst_byte_reader_skip (&stream->stps, 1 + 3) ||
8098 !gst_byte_reader_get_uint32_be (&stream->stps,
8099 &stream->n_sample_partial_syncs))
8102 /* if there are no entries, the stss table contains the real
8104 if (stream->n_sample_partial_syncs) {
8105 /* make sure there's enough data */
8106 if (!qt_atom_parser_has_chunks (&stream->stps,
8107 stream->n_sample_partial_syncs, 4))
8114 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsz, &stream->stsz))
8117 /* copy atom data into a new buffer for later use */
8118 stream->stsz.data = g_memdup (stream->stsz.data, stream->stsz.size);
8120 /* skip version + flags */
8121 if (!gst_byte_reader_skip (&stream->stsz, 1 + 3) ||
8122 !gst_byte_reader_get_uint32_be (&stream->stsz, &stream->sample_size))
8125 if (!gst_byte_reader_get_uint32_be (&stream->stsz, &stream->n_samples))
8128 if (!stream->n_samples)
8131 /* sample-to-chunk atom */
8132 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsc, &stream->stsc))
8135 /* copy atom data into a new buffer for later use */
8136 stream->stsc.data = g_memdup (stream->stsc.data, stream->stsc.size);
8138 /* skip version + flags */
8139 if (!gst_byte_reader_skip (&stream->stsc, 1 + 3) ||
8140 !gst_byte_reader_get_uint32_be (&stream->stsc,
8141 &stream->n_samples_per_chunk))
8144 GST_DEBUG_OBJECT (qtdemux, "n_samples_per_chunk %u",
8145 stream->n_samples_per_chunk);
8147 /* make sure there's enough data */
8148 if (!qt_atom_parser_has_chunks (&stream->stsc, stream->n_samples_per_chunk,
8154 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stco, &stream->stco))
8155 stream->co_size = sizeof (guint32);
8156 else if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_co64,
8158 stream->co_size = sizeof (guint64);
8162 /* copy atom data into a new buffer for later use */
8163 stream->stco.data = g_memdup (stream->stco.data, stream->stco.size);
8165 /* skip version + flags */
8166 if (!gst_byte_reader_skip (&stream->stco, 1 + 3))
8169 /* chunks_are_samples == TRUE means treat chunks as samples */
8170 stream->chunks_are_samples = stream->sample_size && !stream->sampled;
8171 if (stream->chunks_are_samples) {
8172 /* treat chunks as samples */
8173 if (!gst_byte_reader_get_uint32_be (&stream->stco, &stream->n_samples))
8176 /* skip number of entries */
8177 if (!gst_byte_reader_skip (&stream->stco, 4))
8180 /* make sure there are enough data in the stsz atom */
8181 if (!stream->sample_size) {
8182 /* different sizes for each sample */
8183 if (!qt_atom_parser_has_chunks (&stream->stsz, stream->n_samples, 4))
8188 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
8189 stream->n_samples, (guint) sizeof (QtDemuxSample),
8190 stream->n_samples * sizeof (QtDemuxSample) / (1024.0 * 1024.0));
8192 if (stream->n_samples >=
8193 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample)) {
8194 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
8195 "be larger than %uMB (broken file?)", stream->n_samples,
8196 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
8200 g_assert (stream->samples == NULL);
8201 stream->samples = g_try_new0 (QtDemuxSample, stream->n_samples);
8202 if (!stream->samples) {
8203 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
8208 /* composition time-to-sample */
8209 if ((stream->ctts_present =
8210 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_ctts,
8211 &stream->ctts) ? TRUE : FALSE) == TRUE) {
8212 GstByteReader cslg = GST_BYTE_READER_INIT (NULL, 0);
8214 /* copy atom data into a new buffer for later use */
8215 stream->ctts.data = g_memdup (stream->ctts.data, stream->ctts.size);
8217 /* skip version + flags */
8218 if (!gst_byte_reader_skip (&stream->ctts, 1 + 3)
8219 || !gst_byte_reader_get_uint32_be (&stream->ctts,
8220 &stream->n_composition_times))
8223 /* make sure there's enough data */
8224 if (!qt_atom_parser_has_chunks (&stream->ctts, stream->n_composition_times,
8228 /* This is optional, if missing we iterate the ctts */
8229 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_cslg, &cslg)) {
8230 if (!gst_byte_reader_skip (&cslg, 1 + 3)
8231 || !gst_byte_reader_get_uint32_be (&cslg, &stream->cslg_shift)) {
8232 g_free ((gpointer) cslg.data);
8236 gint32 cslg_least = 0;
8237 guint num_entries, pos;
8240 pos = gst_byte_reader_get_pos (&stream->ctts);
8241 num_entries = stream->n_composition_times;
8243 stream->cslg_shift = 0;
8245 for (i = 0; i < num_entries; i++) {
8248 gst_byte_reader_skip_unchecked (&stream->ctts, 4);
8249 offset = gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
8251 if (offset < cslg_least)
8252 cslg_least = offset;
8256 stream->cslg_shift = ABS (cslg_least);
8258 stream->cslg_shift = 0;
8260 /* reset the reader so we can generate sample table */
8261 gst_byte_reader_set_pos (&stream->ctts, pos);
8264 /* Ensure the cslg_shift value is consistent so we can use it
8265 * unconditionnally to produce TS and Segment */
8266 stream->cslg_shift = 0;
8273 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8274 (_("This file is corrupt and cannot be played.")), (NULL));
8279 gst_qtdemux_stbl_free (stream);
8280 if (!qtdemux->fragmented) {
8281 /* not quite good */
8282 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
8285 /* may pick up samples elsewhere */
8291 /* collect samples from the next sample to be parsed up to sample @n for @stream
8292 * by reading the info from @stbl
8294 * This code can be executed from both the streaming thread and the seeking
8295 * thread so it takes the object lock to protect itself
8298 qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream, guint32 n)
8301 QtDemuxSample *samples, *first, *cur, *last;
8302 guint32 n_samples_per_chunk;
8305 GST_LOG_OBJECT (qtdemux, "parsing samples for stream fourcc %"
8306 GST_FOURCC_FORMAT ", pad %s", GST_FOURCC_ARGS (stream->fourcc),
8307 stream->pad ? GST_PAD_NAME (stream->pad) : "(NULL)");
8309 n_samples = stream->n_samples;
8312 goto out_of_samples;
8314 GST_OBJECT_LOCK (qtdemux);
8315 if (n <= stream->stbl_index)
8316 goto already_parsed;
8318 GST_DEBUG_OBJECT (qtdemux, "parsing up to sample %u", n);
8320 if (!stream->stsz.data) {
8321 /* so we already parsed and passed all the moov samples;
8322 * onto fragmented ones */
8323 g_assert (qtdemux->fragmented);
8327 /* pointer to the sample table */
8328 samples = stream->samples;
8330 /* starts from -1, moves to the next sample index to parse */
8331 stream->stbl_index++;
8333 /* keep track of the first and last sample to fill */
8334 first = &samples[stream->stbl_index];
8337 if (!stream->chunks_are_samples) {
8338 /* set the sample sizes */
8339 if (stream->sample_size == 0) {
8340 /* different sizes for each sample */
8341 for (cur = first; cur <= last; cur++) {
8342 cur->size = gst_byte_reader_get_uint32_be_unchecked (&stream->stsz);
8343 GST_LOG_OBJECT (qtdemux, "sample %d has size %u",
8344 (guint) (cur - samples), cur->size);
8347 /* samples have the same size */
8348 GST_LOG_OBJECT (qtdemux, "all samples have size %u", stream->sample_size);
8349 for (cur = first; cur <= last; cur++)
8350 cur->size = stream->sample_size;
8354 n_samples_per_chunk = stream->n_samples_per_chunk;
8357 for (i = stream->stsc_index; i < n_samples_per_chunk; i++) {
8360 if (stream->stsc_chunk_index >= stream->last_chunk
8361 || stream->stsc_chunk_index < stream->first_chunk) {
8362 stream->first_chunk =
8363 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
8364 stream->samples_per_chunk =
8365 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
8366 gst_byte_reader_skip_unchecked (&stream->stsc, 4);
8368 /* chunk numbers are counted from 1 it seems */
8369 if (G_UNLIKELY (stream->first_chunk == 0))
8372 --stream->first_chunk;
8374 /* the last chunk of each entry is calculated by taking the first chunk
8375 * of the next entry; except if there is no next, where we fake it with
8377 if (G_UNLIKELY (i == (stream->n_samples_per_chunk - 1))) {
8378 stream->last_chunk = G_MAXUINT32;
8380 stream->last_chunk =
8381 gst_byte_reader_peek_uint32_be_unchecked (&stream->stsc);
8382 if (G_UNLIKELY (stream->last_chunk == 0))
8385 --stream->last_chunk;
8388 GST_LOG_OBJECT (qtdemux,
8389 "entry %d has first_chunk %d, last_chunk %d, samples_per_chunk %d", i,
8390 stream->first_chunk, stream->last_chunk, stream->samples_per_chunk);
8392 if (G_UNLIKELY (stream->last_chunk < stream->first_chunk))
8395 if (stream->last_chunk != G_MAXUINT32) {
8396 if (!qt_atom_parser_peek_sub (&stream->stco,
8397 stream->first_chunk * stream->co_size,
8398 (stream->last_chunk - stream->first_chunk) * stream->co_size,
8403 stream->co_chunk = stream->stco;
8404 if (!gst_byte_reader_skip (&stream->co_chunk,
8405 stream->first_chunk * stream->co_size))
8409 stream->stsc_chunk_index = stream->first_chunk;
8412 last_chunk = stream->last_chunk;
8414 if (stream->chunks_are_samples) {
8415 cur = &samples[stream->stsc_chunk_index];
8417 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
8420 stream->stsc_chunk_index = j;
8425 qt_atom_parser_get_offset_unchecked (&stream->co_chunk,
8428 GST_LOG_OBJECT (qtdemux, "Created entry %d with offset "
8429 "%" G_GUINT64_FORMAT, j, cur->offset);
8431 if (stream->samples_per_frame * stream->bytes_per_frame) {
8433 (stream->samples_per_chunk * stream->n_channels) /
8434 stream->samples_per_frame * stream->bytes_per_frame;
8436 cur->size = stream->samples_per_chunk;
8439 GST_DEBUG_OBJECT (qtdemux,
8440 "keyframe sample %d: timestamp %" GST_TIME_FORMAT ", size %u",
8441 j, GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream,
8442 stream->stco_sample_index)), cur->size);
8444 cur->timestamp = stream->stco_sample_index;
8445 cur->duration = stream->samples_per_chunk;
8446 cur->keyframe = TRUE;
8449 stream->stco_sample_index += stream->samples_per_chunk;
8451 stream->stsc_chunk_index = j;
8453 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
8454 guint32 samples_per_chunk;
8455 guint64 chunk_offset;
8457 if (!stream->stsc_sample_index
8458 && !qt_atom_parser_get_offset (&stream->co_chunk, stream->co_size,
8459 &stream->chunk_offset))
8462 samples_per_chunk = stream->samples_per_chunk;
8463 chunk_offset = stream->chunk_offset;
8465 for (k = stream->stsc_sample_index; k < samples_per_chunk; k++) {
8466 GST_LOG_OBJECT (qtdemux, "creating entry %d with offset %"
8467 G_GUINT64_FORMAT " and size %d",
8468 (guint) (cur - samples), chunk_offset, cur->size);
8470 cur->offset = chunk_offset;
8471 chunk_offset += cur->size;
8474 if (G_UNLIKELY (cur > last)) {
8476 stream->stsc_sample_index = k + 1;
8477 stream->chunk_offset = chunk_offset;
8478 stream->stsc_chunk_index = j;
8482 stream->stsc_sample_index = 0;
8484 stream->stsc_chunk_index = j;
8486 stream->stsc_index++;
8489 if (stream->chunks_are_samples)
8493 guint32 n_sample_times;
8495 n_sample_times = stream->n_sample_times;
8498 for (i = stream->stts_index; i < n_sample_times; i++) {
8499 guint32 stts_samples;
8500 gint32 stts_duration;
8503 if (stream->stts_sample_index >= stream->stts_samples
8504 || !stream->stts_sample_index) {
8506 stream->stts_samples =
8507 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
8508 stream->stts_duration =
8509 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
8511 GST_LOG_OBJECT (qtdemux, "block %d, %u timestamps, duration %u",
8512 i, stream->stts_samples, stream->stts_duration);
8514 stream->stts_sample_index = 0;
8517 stts_samples = stream->stts_samples;
8518 stts_duration = stream->stts_duration;
8519 stts_time = stream->stts_time;
8521 for (j = stream->stts_sample_index; j < stts_samples; j++) {
8522 GST_DEBUG_OBJECT (qtdemux,
8523 "sample %d: index %d, timestamp %" GST_TIME_FORMAT,
8524 (guint) (cur - samples), j,
8525 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stts_time)));
8527 cur->timestamp = stts_time;
8528 cur->duration = stts_duration;
8530 /* avoid 32-bit wrap-around,
8531 * but still mind possible 'negative' duration */
8532 stts_time += (gint64) stts_duration;
8535 if (G_UNLIKELY (cur > last)) {
8537 stream->stts_time = stts_time;
8538 stream->stts_sample_index = j + 1;
8542 stream->stts_sample_index = 0;
8543 stream->stts_time = stts_time;
8544 stream->stts_index++;
8546 /* fill up empty timestamps with the last timestamp, this can happen when
8547 * the last samples do not decode and so we don't have timestamps for them.
8548 * We however look at the last timestamp to estimate the track length so we
8549 * need something in here. */
8550 for (; cur < last; cur++) {
8551 GST_DEBUG_OBJECT (qtdemux,
8552 "fill sample %d: timestamp %" GST_TIME_FORMAT,
8553 (guint) (cur - samples),
8554 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stream->stts_time)));
8555 cur->timestamp = stream->stts_time;
8561 /* sample sync, can be NULL */
8562 if (stream->stss_present == TRUE) {
8563 guint32 n_sample_syncs;
8565 n_sample_syncs = stream->n_sample_syncs;
8567 if (!n_sample_syncs) {
8568 GST_DEBUG_OBJECT (qtdemux, "all samples are keyframes");
8569 stream->all_keyframe = TRUE;
8571 for (i = stream->stss_index; i < n_sample_syncs; i++) {
8572 /* note that the first sample is index 1, not 0 */
8575 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stss);
8577 if (G_LIKELY (index > 0 && index <= n_samples)) {
8579 samples[index].keyframe = TRUE;
8580 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
8581 /* and exit if we have enough samples */
8582 if (G_UNLIKELY (index >= n)) {
8589 stream->stss_index = i;
8592 /* stps marks partial sync frames like open GOP I-Frames */
8593 if (stream->stps_present == TRUE) {
8594 guint32 n_sample_partial_syncs;
8596 n_sample_partial_syncs = stream->n_sample_partial_syncs;
8598 /* if there are no entries, the stss table contains the real
8600 if (n_sample_partial_syncs) {
8601 for (i = stream->stps_index; i < n_sample_partial_syncs; i++) {
8602 /* note that the first sample is index 1, not 0 */
8605 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stps);
8607 if (G_LIKELY (index > 0 && index <= n_samples)) {
8609 samples[index].keyframe = TRUE;
8610 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
8611 /* and exit if we have enough samples */
8612 if (G_UNLIKELY (index >= n)) {
8619 stream->stps_index = i;
8623 /* no stss, all samples are keyframes */
8624 stream->all_keyframe = TRUE;
8625 GST_DEBUG_OBJECT (qtdemux, "setting all keyframes");
8630 /* composition time to sample */
8631 if (stream->ctts_present == TRUE) {
8632 guint32 n_composition_times;
8634 gint32 ctts_soffset;
8636 /* Fill in the pts_offsets */
8638 n_composition_times = stream->n_composition_times;
8640 for (i = stream->ctts_index; i < n_composition_times; i++) {
8641 if (stream->ctts_sample_index >= stream->ctts_count
8642 || !stream->ctts_sample_index) {
8643 stream->ctts_count =
8644 gst_byte_reader_get_uint32_be_unchecked (&stream->ctts);
8645 stream->ctts_soffset =
8646 gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
8647 stream->ctts_sample_index = 0;
8650 ctts_count = stream->ctts_count;
8651 ctts_soffset = stream->ctts_soffset;
8653 for (j = stream->ctts_sample_index; j < ctts_count; j++) {
8654 cur->pts_offset = ctts_soffset;
8657 if (G_UNLIKELY (cur > last)) {
8659 stream->ctts_sample_index = j + 1;
8663 stream->ctts_sample_index = 0;
8664 stream->ctts_index++;
8668 stream->stbl_index = n;
8669 /* if index has been completely parsed, free data that is no-longer needed */
8670 if (n + 1 == stream->n_samples) {
8671 gst_qtdemux_stbl_free (stream);
8672 GST_DEBUG_OBJECT (qtdemux, "parsed all available samples;");
8673 if (qtdemux->pullbased) {
8674 GST_DEBUG_OBJECT (qtdemux, "checking for more samples");
8675 while (n + 1 == stream->n_samples)
8676 if (qtdemux_add_fragmented_samples (qtdemux) != GST_FLOW_OK)
8680 GST_OBJECT_UNLOCK (qtdemux);
8687 GST_LOG_OBJECT (qtdemux,
8688 "Tried to parse up to sample %u but this sample has already been parsed",
8690 /* if fragmented, there may be more */
8691 if (qtdemux->fragmented && n == stream->stbl_index)
8693 GST_OBJECT_UNLOCK (qtdemux);
8699 GST_LOG_OBJECT (qtdemux,
8700 "Tried to parse up to sample %u but there are only %u samples", n + 1,
8702 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8703 (_("This file is corrupt and cannot be played.")), (NULL));
8708 GST_OBJECT_UNLOCK (qtdemux);
8709 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8710 (_("This file is corrupt and cannot be played.")), (NULL));
8715 /* collect all segment info for @stream.
8718 qtdemux_parse_segments (GstQTDemux * qtdemux, QtDemuxStream * stream,
8722 /* accept edts if they contain gaps at start and there is only
8723 * one media segment */
8724 gboolean allow_pushbased_edts = TRUE;
8725 gint media_segments_count = 0;
8727 /* parse and prepare segment info from the edit list */
8728 GST_DEBUG_OBJECT (qtdemux, "looking for edit list container");
8729 stream->n_segments = 0;
8730 stream->segments = NULL;
8731 if ((edts = qtdemux_tree_get_child_by_type (trak, FOURCC_edts))) {
8734 gint i, count, entry_size;
8737 const guint8 *buffer;
8741 GST_DEBUG_OBJECT (qtdemux, "looking for edit list");
8742 if (!(elst = qtdemux_tree_get_child_by_type (edts, FOURCC_elst)))
8745 buffer = elst->data;
8747 size = QT_UINT32 (buffer);
8748 /* version, flags, n_segments */
8750 GST_WARNING_OBJECT (qtdemux, "Invalid edit list");
8753 version = QT_UINT8 (buffer + 8);
8754 entry_size = (version == 1) ? 20 : 12;
8756 n_segments = QT_UINT32 (buffer + 12);
8758 if (size < 16 + n_segments * entry_size) {
8759 GST_WARNING_OBJECT (qtdemux, "Invalid edit list");
8763 /* we might allocate a bit too much, at least allocate 1 segment */
8764 stream->segments = g_new (QtDemuxSegment, MAX (n_segments, 1));
8766 /* segments always start from 0 */
8771 for (i = 0; i < n_segments; i++) {
8774 gboolean time_valid = TRUE;
8775 QtDemuxSegment *segment;
8777 GstClockTime media_start = GST_CLOCK_TIME_NONE;
8780 media_time = QT_UINT64 (buffer + 8);
8781 duration = QT_UINT64 (buffer);
8782 if (media_time == G_MAXUINT64)
8785 media_time = QT_UINT32 (buffer + 4);
8786 duration = QT_UINT32 (buffer);
8787 if (media_time == G_MAXUINT32)
8792 media_start = QTSTREAMTIME_TO_GSTTIME (stream, media_time);
8794 segment = &stream->segments[count++];
8796 /* time and duration expressed in global timescale */
8797 segment->time = stime;
8798 /* add non scaled values so we don't cause roundoff errors */
8799 if (duration || media_start == GST_CLOCK_TIME_NONE) {
8801 stime = QTTIME_TO_GSTTIME (qtdemux, time);
8802 segment->duration = stime - segment->time;
8804 /* zero duration does not imply media_start == media_stop
8805 * but, only specify media_start.*/
8806 stime = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
8807 if (GST_CLOCK_TIME_IS_VALID (stime) && time_valid
8808 && stime >= media_start) {
8809 segment->duration = stime - media_start;
8811 segment->duration = GST_CLOCK_TIME_NONE;
8814 segment->stop_time = stime;
8816 segment->trak_media_start = media_time;
8817 /* media_time expressed in stream timescale */
8819 segment->media_start = media_start;
8820 segment->media_stop = segment->media_start + segment->duration;
8821 media_segments_count++;
8823 segment->media_start = GST_CLOCK_TIME_NONE;
8824 segment->media_stop = GST_CLOCK_TIME_NONE;
8826 rate_int = QT_UINT32 (buffer + ((version == 1) ? 16 : 8));
8828 if (rate_int <= 1) {
8829 /* 0 is not allowed, some programs write 1 instead of the floating point
8831 GST_WARNING_OBJECT (qtdemux, "found suspicious rate %" G_GUINT32_FORMAT,
8835 segment->rate = rate_int / 65536.0;
8838 GST_DEBUG_OBJECT (qtdemux, "created segment %d time %" GST_TIME_FORMAT
8839 ", duration %" GST_TIME_FORMAT ", media_start %" GST_TIME_FORMAT
8840 " (%" G_GUINT64_FORMAT ") , media_stop %" GST_TIME_FORMAT
8841 " stop_time %" GST_TIME_FORMAT " rate %g, (%d) timescale %u",
8842 i, GST_TIME_ARGS (segment->time),
8843 GST_TIME_ARGS (segment->duration),
8844 GST_TIME_ARGS (segment->media_start), media_time,
8845 GST_TIME_ARGS (segment->media_stop),
8846 GST_TIME_ARGS (segment->stop_time), segment->rate, rate_int,
8848 if (segment->stop_time > qtdemux->segment.stop) {
8849 GST_WARNING_OBJECT (qtdemux, "Segment %d "
8850 " extends to %" GST_TIME_FORMAT
8851 " past the end of the file duration %" GST_TIME_FORMAT
8852 " it will be truncated", i, GST_TIME_ARGS (segment->stop_time),
8853 GST_TIME_ARGS (qtdemux->segment.stop));
8854 qtdemux->segment.stop = segment->stop_time;
8857 buffer += entry_size;
8859 GST_DEBUG_OBJECT (qtdemux, "found %d segments", count);
8860 stream->n_segments = count;
8861 if (media_segments_count != 1)
8862 allow_pushbased_edts = FALSE;
8866 /* push based does not handle segments, so act accordingly here,
8867 * and warn if applicable */
8868 if (!qtdemux->pullbased && !allow_pushbased_edts) {
8869 GST_WARNING_OBJECT (qtdemux, "streaming; discarding edit list segments");
8870 /* remove and use default one below, we stream like it anyway */
8871 g_free (stream->segments);
8872 stream->segments = NULL;
8873 stream->n_segments = 0;
8876 /* no segments, create one to play the complete trak */
8877 if (stream->n_segments == 0) {
8878 GstClockTime stream_duration =
8879 QTSTREAMTIME_TO_GSTTIME (stream, stream->duration);
8881 if (stream->segments == NULL)
8882 stream->segments = g_new (QtDemuxSegment, 1);
8884 /* represent unknown our way */
8885 if (stream_duration == 0)
8886 stream_duration = GST_CLOCK_TIME_NONE;
8888 stream->segments[0].time = 0;
8889 stream->segments[0].stop_time = stream_duration;
8890 stream->segments[0].duration = stream_duration;
8891 stream->segments[0].media_start = 0;
8892 stream->segments[0].media_stop = stream_duration;
8893 stream->segments[0].rate = 1.0;
8894 stream->segments[0].trak_media_start = 0;
8896 GST_DEBUG_OBJECT (qtdemux, "created dummy segment %" GST_TIME_FORMAT,
8897 GST_TIME_ARGS (stream_duration));
8898 stream->n_segments = 1;
8899 stream->dummy_segment = TRUE;
8901 GST_DEBUG_OBJECT (qtdemux, "using %d segments", stream->n_segments);
8907 * Parses the stsd atom of a svq3 trak looking for
8908 * the SMI and gama atoms.
8911 qtdemux_parse_svq3_stsd_data (GstQTDemux * qtdemux, GNode * stsd,
8912 guint8 ** gamma, GstBuffer ** seqh)
8914 guint8 *_gamma = NULL;
8915 GstBuffer *_seqh = NULL;
8916 guint8 *stsd_data = stsd->data;
8917 guint32 length = QT_UINT32 (stsd_data);
8921 GST_WARNING_OBJECT (qtdemux, "stsd too short");
8927 version = QT_UINT16 (stsd_data);
8932 while (length > 8) {
8933 guint32 fourcc, size;
8935 size = QT_UINT32 (stsd_data);
8936 fourcc = QT_FOURCC (stsd_data + 4);
8937 data = stsd_data + 8;
8940 GST_WARNING_OBJECT (qtdemux, "Atom of size 0 found, aborting "
8941 "svq3 atom parsing");
8950 GST_WARNING_OBJECT (qtdemux, "Unexpected size %" G_GUINT32_FORMAT
8951 " for gama atom, expected 12", size);
8956 if (size > 16 && QT_FOURCC (data) == FOURCC_SEQH) {
8958 if (_seqh != NULL) {
8959 GST_WARNING_OBJECT (qtdemux, "Unexpected second SEQH SMI atom "
8960 " found, ignoring");
8962 seqh_size = QT_UINT32 (data + 4);
8963 if (seqh_size > 0) {
8964 _seqh = gst_buffer_new_and_alloc (seqh_size);
8965 gst_buffer_fill (_seqh, 0, data + 8, seqh_size);
8972 GST_WARNING_OBJECT (qtdemux, "Unhandled atom %" GST_FOURCC_FORMAT
8973 " in SVQ3 entry in stsd atom", GST_FOURCC_ARGS (fourcc));
8977 if (size <= length) {
8983 GST_WARNING_OBJECT (qtdemux, "SVQ3 entry too short in stsd atom");
8986 GST_WARNING_OBJECT (qtdemux, "Unexpected version for SVQ3 entry %"
8987 G_GUINT16_FORMAT, version);
8998 gst_buffer_unref (_seqh);
9003 qtdemux_get_rtsp_uri_from_hndl (GstQTDemux * qtdemux, GNode * minf)
9010 * Get 'dinf', to get its child 'dref', that might contain a 'hndl'
9011 * atom that might contain a 'data' atom with the rtsp uri.
9012 * This case was reported in bug #597497, some info about
9013 * the hndl atom can be found in TN1195
9015 dinf = qtdemux_tree_get_child_by_type (minf, FOURCC_dinf);
9016 GST_DEBUG_OBJECT (qtdemux, "Trying to obtain rtsp URI for stream trak");
9019 guint32 dref_num_entries = 0;
9020 if (qtdemux_tree_get_child_by_type_full (dinf, FOURCC_dref, &dref) &&
9021 gst_byte_reader_skip (&dref, 4) &&
9022 gst_byte_reader_get_uint32_be (&dref, &dref_num_entries)) {
9025 /* search dref entries for hndl atom */
9026 for (i = 0; i < dref_num_entries; i++) {
9027 guint32 size = 0, type;
9028 guint8 string_len = 0;
9029 if (gst_byte_reader_get_uint32_be (&dref, &size) &&
9030 qt_atom_parser_get_fourcc (&dref, &type)) {
9031 if (type == FOURCC_hndl) {
9032 GST_DEBUG_OBJECT (qtdemux, "Found hndl atom");
9034 /* skip data reference handle bytes and the
9035 * following pascal string and some extra 4
9036 * bytes I have no idea what are */
9037 if (!gst_byte_reader_skip (&dref, 4) ||
9038 !gst_byte_reader_get_uint8 (&dref, &string_len) ||
9039 !gst_byte_reader_skip (&dref, string_len + 4)) {
9040 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl atom");
9044 /* iterate over the atoms to find the data atom */
9045 while (gst_byte_reader_get_remaining (&dref) >= 8) {
9049 if (gst_byte_reader_get_uint32_be (&dref, &atom_size) &&
9050 qt_atom_parser_get_fourcc (&dref, &atom_type)) {
9051 if (atom_type == FOURCC_data) {
9052 const guint8 *uri_aux = NULL;
9054 /* found the data atom that might contain the rtsp uri */
9055 GST_DEBUG_OBJECT (qtdemux, "Found data atom inside "
9056 "hndl atom, interpreting it as an URI");
9057 if (gst_byte_reader_peek_data (&dref, atom_size - 8,
9059 if (g_strstr_len ((gchar *) uri_aux, 7, "rtsp://") != NULL)
9060 uri = g_strndup ((gchar *) uri_aux, atom_size - 8);
9062 GST_WARNING_OBJECT (qtdemux, "Data atom in hndl atom "
9063 "didn't contain a rtsp address");
9065 GST_WARNING_OBJECT (qtdemux, "Failed to get the data "
9070 /* skipping to the next entry */
9071 if (!gst_byte_reader_skip (&dref, atom_size - 8))
9074 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl child "
9081 /* skip to the next entry */
9082 if (!gst_byte_reader_skip (&dref, size - 8))
9085 GST_WARNING_OBJECT (qtdemux, "Error parsing dref atom");
9088 GST_DEBUG_OBJECT (qtdemux, "Finished parsing dref atom");
9094 #define AMR_NB_ALL_MODES 0x81ff
9095 #define AMR_WB_ALL_MODES 0x83ff
9097 qtdemux_parse_amr_bitrate (GstBuffer * buf, gboolean wb)
9099 /* The 'damr' atom is of the form:
9101 * | vendor | decoder_ver | mode_set | mode_change_period | frames/sample |
9102 * 32 b 8 b 16 b 8 b 8 b
9104 * The highest set bit of the first 7 (AMR-NB) or 8 (AMR-WB) bits of mode_set
9105 * represents the highest mode used in the stream (and thus the maximum
9106 * bitrate), with a couple of special cases as seen below.
9109 /* Map of frame type ID -> bitrate */
9110 static const guint nb_bitrates[] = {
9111 4750, 5150, 5900, 6700, 7400, 7950, 10200, 12200
9113 static const guint wb_bitrates[] = {
9114 6600, 8850, 12650, 14250, 15850, 18250, 19850, 23050, 23850
9120 gst_buffer_map (buf, &map, GST_MAP_READ);
9122 if (map.size != 0x11) {
9123 GST_DEBUG ("Atom should have size 0x11, not %" G_GSIZE_FORMAT, map.size);
9127 if (QT_FOURCC (map.data + 4) != FOURCC_damr) {
9128 GST_DEBUG ("Unknown atom in %" GST_FOURCC_FORMAT,
9129 GST_FOURCC_ARGS (QT_UINT32 (map.data + 4)));
9133 mode_set = QT_UINT16 (map.data + 13);
9135 if (mode_set == (wb ? AMR_WB_ALL_MODES : AMR_NB_ALL_MODES))
9136 max_mode = 7 + (wb ? 1 : 0);
9138 /* AMR-NB modes fo from 0-7, and AMR-WB modes go from 0-8 */
9139 max_mode = g_bit_nth_msf ((gulong) mode_set & (wb ? 0x1ff : 0xff), -1);
9141 if (max_mode == -1) {
9142 GST_DEBUG ("No mode indication was found (mode set) = %x",
9147 gst_buffer_unmap (buf, &map);
9148 return wb ? wb_bitrates[max_mode] : nb_bitrates[max_mode];
9151 gst_buffer_unmap (buf, &map);
9156 qtdemux_parse_transformation_matrix (GstQTDemux * qtdemux,
9157 GstByteReader * reader, guint32 * matrix, const gchar * atom)
9160 * 9 values of 32 bits (fixed point 16.16, except 2 5 and 8 that are 2.30)
9166 if (gst_byte_reader_get_remaining (reader) < 36)
9169 matrix[0] = gst_byte_reader_get_uint32_be_unchecked (reader);
9170 matrix[1] = gst_byte_reader_get_uint32_be_unchecked (reader);
9171 matrix[2] = gst_byte_reader_get_uint32_be_unchecked (reader);
9172 matrix[3] = gst_byte_reader_get_uint32_be_unchecked (reader);
9173 matrix[4] = gst_byte_reader_get_uint32_be_unchecked (reader);
9174 matrix[5] = gst_byte_reader_get_uint32_be_unchecked (reader);
9175 matrix[6] = gst_byte_reader_get_uint32_be_unchecked (reader);
9176 matrix[7] = gst_byte_reader_get_uint32_be_unchecked (reader);
9177 matrix[8] = gst_byte_reader_get_uint32_be_unchecked (reader);
9179 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix from atom %s", atom);
9180 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[0] >> 16,
9181 matrix[0] & 0xFFFF, matrix[1] >> 16, matrix[1] & 0xFF, matrix[2] >> 16,
9183 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[3] >> 16,
9184 matrix[3] & 0xFFFF, matrix[4] >> 16, matrix[4] & 0xFF, matrix[5] >> 16,
9186 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[6] >> 16,
9187 matrix[6] & 0xFFFF, matrix[7] >> 16, matrix[7] & 0xFF, matrix[8] >> 16,
9194 qtdemux_inspect_transformation_matrix (GstQTDemux * qtdemux,
9195 QtDemuxStream * stream, guint32 * matrix, GstTagList ** taglist)
9202 * This macro will only compare value abdegh, it expects cfi to have already
9205 #define QTCHECK_MATRIX(m,a,b,d,e) ((m)[0] == (a << 16) && (m)[1] == (b << 16) && \
9206 (m)[3] == (d << 16) && (m)[4] == (e << 16))
9208 /* only handle the cases where the last column has standard values */
9209 if (matrix[2] == 0 && matrix[5] == 0 && matrix[8] == 1 << 30) {
9210 const gchar *rotation_tag = NULL;
9212 /* no rotation needed */
9213 if (QTCHECK_MATRIX (matrix, 1, 0, 0, 1)) {
9215 } else if (QTCHECK_MATRIX (matrix, 0, 1, G_MAXUINT16, 0)) {
9216 rotation_tag = "rotate-90";
9217 } else if (QTCHECK_MATRIX (matrix, G_MAXUINT16, 0, 0, G_MAXUINT16)) {
9218 rotation_tag = "rotate-180";
9219 } else if (QTCHECK_MATRIX (matrix, 0, G_MAXUINT16, 1, 0)) {
9220 rotation_tag = "rotate-270";
9222 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
9225 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix rotation %s",
9227 if (rotation_tag != NULL) {
9228 if (*taglist == NULL)
9229 *taglist = gst_tag_list_new_empty ();
9230 gst_tag_list_add (*taglist, GST_TAG_MERGE_REPLACE,
9231 GST_TAG_IMAGE_ORIENTATION, rotation_tag, NULL);
9234 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
9238 /* Parses the boxes defined in ISO/IEC 14496-12 that enable support for
9239 * protected streams (sinf, frma, schm and schi); if the protection scheme is
9240 * Common Encryption (cenc), the function will also parse the tenc box (defined
9241 * in ISO/IEC 23001-7). @container points to the node that contains these boxes
9242 * (typically an enc[v|a|t|s] sample entry); the function will set
9243 * @original_fmt to the fourcc of the original unencrypted stream format.
9244 * Returns TRUE if successful; FALSE otherwise. */
9246 qtdemux_parse_protection_scheme_info (GstQTDemux * qtdemux,
9247 QtDemuxStream * stream, GNode * container, guint32 * original_fmt)
9254 g_return_val_if_fail (qtdemux != NULL, FALSE);
9255 g_return_val_if_fail (stream != NULL, FALSE);
9256 g_return_val_if_fail (container != NULL, FALSE);
9257 g_return_val_if_fail (original_fmt != NULL, FALSE);
9259 sinf = qtdemux_tree_get_child_by_type (container, FOURCC_sinf);
9260 if (G_UNLIKELY (!sinf)) {
9261 if (stream->protection_scheme_type == FOURCC_cenc) {
9262 GST_ERROR_OBJECT (qtdemux, "sinf box does not contain schi box, which is "
9263 "mandatory for Common Encryption");
9269 frma = qtdemux_tree_get_child_by_type (sinf, FOURCC_frma);
9270 if (G_UNLIKELY (!frma)) {
9271 GST_ERROR_OBJECT (qtdemux, "sinf box does not contain mandatory frma box");
9275 *original_fmt = QT_FOURCC ((const guint8 *) frma->data + 8);
9276 GST_DEBUG_OBJECT (qtdemux, "original stream format: '%" GST_FOURCC_FORMAT "'",
9277 GST_FOURCC_ARGS (*original_fmt));
9279 schm = qtdemux_tree_get_child_by_type (sinf, FOURCC_schm);
9281 GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schm box");
9284 stream->protection_scheme_type = QT_FOURCC ((const guint8 *) schm->data + 12);
9285 stream->protection_scheme_version =
9286 QT_UINT32 ((const guint8 *) schm->data + 16);
9288 GST_DEBUG_OBJECT (qtdemux,
9289 "protection_scheme_type: %" GST_FOURCC_FORMAT ", "
9290 "protection_scheme_version: %#010x",
9291 GST_FOURCC_ARGS (stream->protection_scheme_type),
9292 stream->protection_scheme_version);
9294 schi = qtdemux_tree_get_child_by_type (sinf, FOURCC_schi);
9296 GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schi box");
9299 if (stream->protection_scheme_type == FOURCC_cenc) {
9300 QtDemuxCencSampleSetInfo *info;
9302 const guint8 *tenc_data;
9303 guint32 isEncrypted;
9305 const guint8 *default_kid;
9308 if (G_UNLIKELY (!stream->protection_scheme_info))
9309 stream->protection_scheme_info =
9310 g_malloc0 (sizeof (QtDemuxCencSampleSetInfo));
9312 info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
9314 tenc = qtdemux_tree_get_child_by_type (schi, FOURCC_tenc);
9316 GST_ERROR_OBJECT (qtdemux, "schi box does not contain tenc box, "
9317 "which is mandatory for Common Encryption");
9320 tenc_data = (const guint8 *) tenc->data + 12;
9321 isEncrypted = QT_UINT24 (tenc_data);
9322 iv_size = QT_UINT8 (tenc_data + 3);
9323 default_kid = (tenc_data + 4);
9324 kid_buf = gst_buffer_new_allocate (NULL, 16, NULL);
9325 gst_buffer_fill (kid_buf, 0, default_kid, 16);
9326 if (info->default_properties)
9327 gst_structure_free (info->default_properties);
9328 info->default_properties =
9329 gst_structure_new ("application/x-cenc",
9330 "iv_size", G_TYPE_UINT, iv_size,
9331 "encrypted", G_TYPE_BOOLEAN, (isEncrypted == 1),
9332 "kid", GST_TYPE_BUFFER, kid_buf, NULL);
9333 GST_DEBUG_OBJECT (qtdemux, "default sample properties: "
9334 "is_encrypted=%u, iv_size=%u", isEncrypted, iv_size);
9335 gst_buffer_unref (kid_buf);
9341 * With each track we associate a new QtDemuxStream that contains all the info
9343 * traks that do not decode to something (like strm traks) will not have a pad.
9346 qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
9367 QtDemuxStream *stream = NULL;
9368 gboolean new_stream = FALSE;
9369 gchar *codec = NULL;
9370 const guint8 *stsd_data;
9371 guint16 lang_code; /* quicktime lang code or packed iso code */
9373 guint32 tkhd_flags = 0;
9374 guint8 tkhd_version = 0;
9376 guint value_size, stsd_len, len;
9380 GST_DEBUG_OBJECT (qtdemux, "parse_trak");
9382 if (!qtdemux_tree_get_child_by_type_full (trak, FOURCC_tkhd, &tkhd)
9383 || !gst_byte_reader_get_uint8 (&tkhd, &tkhd_version)
9384 || !gst_byte_reader_get_uint24_be (&tkhd, &tkhd_flags))
9387 /* pick between 64 or 32 bits */
9388 value_size = tkhd_version == 1 ? 8 : 4;
9389 if (!gst_byte_reader_skip (&tkhd, value_size * 2) ||
9390 !gst_byte_reader_get_uint32_be (&tkhd, &track_id))
9393 if (!qtdemux->got_moov) {
9394 if (qtdemux_find_stream (qtdemux, track_id))
9395 goto existing_stream;
9396 stream = _create_stream ();
9397 stream->track_id = track_id;
9400 stream = qtdemux_find_stream (qtdemux, track_id);
9402 GST_WARNING_OBJECT (qtdemux, "Stream not found, going to ignore it");
9406 /* flush samples data from this track from previous moov */
9407 gst_qtdemux_stream_flush_segments_data (qtdemux, stream);
9408 gst_qtdemux_stream_flush_samples_data (qtdemux, stream);
9410 /* need defaults for fragments */
9411 qtdemux_parse_trex (qtdemux, stream, &dummy, &dummy, &dummy);
9413 if (stream->pending_tags == NULL)
9414 stream->pending_tags = gst_tag_list_new_empty ();
9416 if ((tkhd_flags & 1) == 0)
9417 stream->disabled = TRUE;
9419 GST_LOG_OBJECT (qtdemux, "track[tkhd] version/flags/id: 0x%02x/%06x/%u",
9420 tkhd_version, tkhd_flags, stream->track_id);
9422 if (!(mdia = qtdemux_tree_get_child_by_type (trak, FOURCC_mdia)))
9425 if (!(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mdhd))) {
9426 /* be nice for some crooked mjp2 files that use mhdr for mdhd */
9427 if (qtdemux->major_brand != FOURCC_mjp2 ||
9428 !(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mhdr)))
9432 len = QT_UINT32 ((guint8 *) mdhd->data);
9433 version = QT_UINT32 ((guint8 *) mdhd->data + 8);
9434 GST_LOG_OBJECT (qtdemux, "track version/flags: %08x", version);
9435 if (version == 0x01000000) {
9438 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 28);
9439 stream->duration = QT_UINT64 ((guint8 *) mdhd->data + 32);
9440 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 36);
9444 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 20);
9445 stream->duration = QT_UINT32 ((guint8 *) mdhd->data + 24);
9446 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 28);
9449 if (lang_code < 0x400) {
9450 qtdemux_lang_map_qt_code_to_iso (stream->lang_id, lang_code);
9451 } else if (lang_code == 0x7fff) {
9452 stream->lang_id[0] = 0; /* unspecified */
9454 stream->lang_id[0] = 0x60 + ((lang_code >> 10) & 0x1F);
9455 stream->lang_id[1] = 0x60 + ((lang_code >> 5) & 0x1F);
9456 stream->lang_id[2] = 0x60 + (lang_code & 0x1F);
9457 stream->lang_id[3] = 0;
9460 GST_LOG_OBJECT (qtdemux, "track timescale: %" G_GUINT32_FORMAT,
9462 GST_LOG_OBJECT (qtdemux, "track duration: %" G_GUINT64_FORMAT,
9464 GST_LOG_OBJECT (qtdemux, "track language code/id: 0x%04x/%s",
9465 lang_code, stream->lang_id);
9467 if (G_UNLIKELY (stream->timescale == 0 || qtdemux->timescale == 0))
9470 if ((tref = qtdemux_tree_get_child_by_type (trak, FOURCC_tref))) {
9471 /* chapters track reference */
9472 GNode *chap = qtdemux_tree_get_child_by_type (tref, FOURCC_chap);
9474 gsize length = GST_READ_UINT32_BE (chap->data);
9475 if (qtdemux->chapters_track_id)
9476 GST_FIXME_OBJECT (qtdemux, "Multiple CHAP tracks");
9479 qtdemux->chapters_track_id =
9480 GST_READ_UINT32_BE ((gint8 *) chap->data + 8);
9485 /* fragmented files may have bogus duration in moov */
9486 if (!qtdemux->fragmented &&
9487 qtdemux->duration != G_MAXINT64 && stream->duration != G_MAXINT32) {
9488 guint64 tdur1, tdur2;
9490 /* don't overflow */
9491 tdur1 = stream->timescale * (guint64) qtdemux->duration;
9492 tdur2 = qtdemux->timescale * (guint64) stream->duration;
9495 * some of those trailers, nowadays, have prologue images that are
9496 * themselves video tracks as well. I haven't really found a way to
9497 * identify those yet, except for just looking at their duration. */
9498 if (tdur1 != 0 && (tdur2 * 10 / tdur1) < 2) {
9499 GST_WARNING_OBJECT (qtdemux,
9500 "Track shorter than 20%% (%" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT
9501 " vs. %" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT ") of the stream "
9502 "found, assuming preview image or something; skipping track",
9503 stream->duration, stream->timescale, qtdemux->duration,
9504 qtdemux->timescale);
9506 gst_qtdemux_stream_free (qtdemux, stream);
9511 if (!(hdlr = qtdemux_tree_get_child_by_type (mdia, FOURCC_hdlr)))
9514 GST_LOG_OBJECT (qtdemux, "track type: %" GST_FOURCC_FORMAT,
9515 GST_FOURCC_ARGS (QT_FOURCC ((guint8 *) hdlr->data + 12)));
9517 len = QT_UINT32 ((guint8 *) hdlr->data);
9519 stream->subtype = QT_FOURCC ((guint8 *) hdlr->data + 16);
9520 GST_LOG_OBJECT (qtdemux, "track subtype: %" GST_FOURCC_FORMAT,
9521 GST_FOURCC_ARGS (stream->subtype));
9523 if (!(minf = qtdemux_tree_get_child_by_type (mdia, FOURCC_minf)))
9526 if (!(stbl = qtdemux_tree_get_child_by_type (minf, FOURCC_stbl)))
9529 /*parse svmi header if existing */
9530 svmi = qtdemux_tree_get_child_by_type (stbl, FOURCC_svmi);
9532 len = QT_UINT32 ((guint8 *) svmi->data);
9533 version = QT_UINT32 ((guint8 *) svmi->data + 8);
9535 GstVideoMultiviewMode mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
9536 GstVideoMultiviewFlags flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
9537 guint8 frame_type, frame_layout;
9539 /* MPEG-A stereo video */
9540 if (qtdemux->major_brand == FOURCC_ss02)
9541 flags |= GST_VIDEO_MULTIVIEW_FLAGS_MIXED_MONO;
9543 frame_type = QT_UINT8 ((guint8 *) svmi->data + 12);
9544 frame_layout = QT_UINT8 ((guint8 *) svmi->data + 13) & 0x01;
9545 switch (frame_type) {
9547 mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
9550 mode = GST_VIDEO_MULTIVIEW_MODE_ROW_INTERLEAVED;
9553 mode = GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME;
9556 /* mode 3 is primary/secondary view sequence, ie
9557 * left/right views in separate tracks. See section 7.2
9558 * of ISO/IEC 23000-11:2009 */
9559 GST_FIXME_OBJECT (qtdemux,
9560 "Implement stereo video in separate streams");
9563 if ((frame_layout & 0x1) == 0)
9564 flags |= GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
9566 GST_LOG_OBJECT (qtdemux,
9567 "StereoVideo: composition type: %u, is_left_first: %u",
9568 frame_type, frame_layout);
9569 stream->multiview_mode = mode;
9570 stream->multiview_flags = flags;
9575 if (!(stsd = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsd)))
9577 stsd_data = (const guint8 *) stsd->data;
9579 /* stsd should at least have one entry */
9580 stsd_len = QT_UINT32 (stsd_data);
9581 if (stsd_len < 24) {
9582 /* .. but skip stream with empty stsd produced by some Vivotek cameras */
9583 if (stream->subtype == FOURCC_vivo) {
9585 gst_qtdemux_stream_free (qtdemux, stream);
9592 GST_LOG_OBJECT (qtdemux, "stsd len: %d", stsd_len);
9594 /* and that entry should fit within stsd */
9595 len = QT_UINT32 (stsd_data + 16);
9596 if (len > stsd_len + 16)
9599 stream->fourcc = fourcc = QT_FOURCC (stsd_data + 16 + 4);
9600 GST_LOG_OBJECT (qtdemux, "stsd type: %" GST_FOURCC_FORMAT,
9601 GST_FOURCC_ARGS (stream->fourcc));
9602 GST_LOG_OBJECT (qtdemux, "stsd type len: %d", len);
9604 if ((fourcc == FOURCC_drms) || (fourcc == FOURCC_drmi))
9605 goto error_encrypted;
9607 if (fourcc == FOURCC_encv || fourcc == FOURCC_enca) {
9608 GNode *enc = qtdemux_tree_get_child_by_type (stsd, fourcc);
9609 stream->protected = TRUE;
9610 if (!qtdemux_parse_protection_scheme_info (qtdemux, stream, enc, &fourcc))
9611 GST_ERROR_OBJECT (qtdemux, "Failed to parse protection scheme info");
9614 if (stream->subtype == FOURCC_vide) {
9615 guint32 w = 0, h = 0;
9617 gint depth, palette_size, palette_count;
9619 guint32 *palette_data = NULL;
9621 stream->sampled = TRUE;
9623 /* version 1 uses some 64-bit ints */
9624 if (!gst_byte_reader_skip (&tkhd, 20 + value_size))
9627 if (!qtdemux_parse_transformation_matrix (qtdemux, &tkhd, matrix, "tkhd"))
9630 if (!gst_byte_reader_get_uint32_be (&tkhd, &w)
9631 || !gst_byte_reader_get_uint32_be (&tkhd, &h))
9634 stream->display_width = w >> 16;
9635 stream->display_height = h >> 16;
9637 qtdemux_inspect_transformation_matrix (qtdemux, stream, matrix,
9638 &stream->pending_tags);
9644 stream->width = QT_UINT16 (stsd_data + offset + 32);
9645 stream->height = QT_UINT16 (stsd_data + offset + 34);
9646 stream->fps_n = 0; /* this is filled in later */
9647 stream->fps_d = 0; /* this is filled in later */
9648 stream->bits_per_sample = QT_UINT16 (stsd_data + offset + 82);
9649 stream->color_table_id = QT_UINT16 (stsd_data + offset + 84);
9651 /* if color_table_id is 0, ctab atom must follow; however some files
9652 * produced by TMPEGEnc have color_table_id = 0 and no ctab atom, so
9653 * if color table is not present we'll correct the value */
9654 if (stream->color_table_id == 0 &&
9655 (len < 90 || QT_FOURCC (stsd_data + offset + 86) != FOURCC_ctab)) {
9656 stream->color_table_id = -1;
9659 GST_LOG_OBJECT (qtdemux, "width %d, height %d, bps %d, color table id %d",
9660 stream->width, stream->height, stream->bits_per_sample,
9661 stream->color_table_id);
9663 depth = stream->bits_per_sample;
9665 /* more than 32 bits means grayscale */
9666 gray = (depth > 32);
9667 /* low 32 bits specify the depth */
9670 /* different number of palette entries is determined by depth. */
9672 if ((depth == 1) || (depth == 2) || (depth == 4) || (depth == 8))
9673 palette_count = (1 << depth);
9674 palette_size = palette_count * 4;
9676 if (stream->color_table_id) {
9677 switch (palette_count) {
9681 palette_data = g_memdup (ff_qt_default_palette_2, palette_size);
9684 palette_data = g_memdup (ff_qt_default_palette_4, palette_size);
9688 palette_data = g_memdup (ff_qt_grayscale_palette_16, palette_size);
9690 palette_data = g_memdup (ff_qt_default_palette_16, palette_size);
9694 palette_data = g_memdup (ff_qt_grayscale_palette_256, palette_size);
9696 palette_data = g_memdup (ff_qt_default_palette_256, palette_size);
9699 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
9700 (_("The video in this file might not play correctly.")),
9701 ("unsupported palette depth %d", depth));
9705 gint i, j, start, end;
9711 start = QT_UINT32 (stsd_data + offset + 86);
9712 palette_count = QT_UINT16 (stsd_data + offset + 90);
9713 end = QT_UINT16 (stsd_data + offset + 92);
9715 GST_LOG_OBJECT (qtdemux, "start %d, end %d, palette_count %d",
9716 start, end, palette_count);
9723 if (len < 94 + (end - start) * 8)
9726 /* palette is always the same size */
9727 palette_data = g_malloc0 (256 * 4);
9728 palette_size = 256 * 4;
9730 for (j = 0, i = start; i <= end; j++, i++) {
9733 a = QT_UINT16 (stsd_data + offset + 94 + (j * 8));
9734 r = QT_UINT16 (stsd_data + offset + 96 + (j * 8));
9735 g = QT_UINT16 (stsd_data + offset + 98 + (j * 8));
9736 b = QT_UINT16 (stsd_data + offset + 100 + (j * 8));
9738 palette_data[i] = ((a & 0xff00) << 16) | ((r & 0xff00) << 8) |
9739 (g & 0xff00) | (b >> 8);
9744 gst_caps_unref (stream->caps);
9747 qtdemux_video_caps (qtdemux, stream, fourcc, stsd_data, &codec);
9748 if (G_UNLIKELY (!stream->caps)) {
9749 g_free (palette_data);
9750 goto unknown_stream;
9754 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
9755 GST_TAG_VIDEO_CODEC, codec, NULL);
9764 if (stream->rgb8_palette)
9765 gst_memory_unref (stream->rgb8_palette);
9766 stream->rgb8_palette = gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY,
9767 palette_data, palette_size, 0, palette_size, palette_data, g_free);
9769 s = gst_caps_get_structure (stream->caps, 0);
9771 /* non-raw video has a palette_data property. raw video has the palette as
9772 * an extra plane that we append to the output buffers before we push
9774 if (!gst_structure_has_name (s, "video/x-raw")) {
9777 palette = gst_buffer_new ();
9778 gst_buffer_append_memory (palette, stream->rgb8_palette);
9779 stream->rgb8_palette = NULL;
9781 gst_caps_set_simple (stream->caps, "palette_data",
9782 GST_TYPE_BUFFER, palette, NULL);
9783 gst_buffer_unref (palette);
9785 } else if (palette_count != 0) {
9786 GST_ELEMENT_WARNING (qtdemux, STREAM, NOT_IMPLEMENTED,
9787 (NULL), ("Unsupported palette depth %d", depth));
9790 GST_LOG_OBJECT (qtdemux, "frame count: %u",
9791 QT_UINT16 (stsd_data + offset + 48));
9797 /* pick 'the' stsd child */
9798 if (!stream->protected)
9799 mp4v = qtdemux_tree_get_child_by_type (stsd, fourcc);
9801 mp4v = qtdemux_tree_get_child_by_type (stsd, FOURCC_encv);
9804 esds = qtdemux_tree_get_child_by_type (mp4v, FOURCC_esds);
9805 pasp = qtdemux_tree_get_child_by_type (mp4v, FOURCC_pasp);
9806 colr = qtdemux_tree_get_child_by_type (mp4v, FOURCC_colr);
9807 fiel = qtdemux_tree_get_child_by_type (mp4v, FOURCC_fiel);
9811 const guint8 *pasp_data = (const guint8 *) pasp->data;
9812 gint len = QT_UINT32 (pasp_data);
9815 stream->par_w = QT_UINT32 (pasp_data + 8);
9816 stream->par_h = QT_UINT32 (pasp_data + 12);
9827 const guint8 *fiel_data = (const guint8 *) fiel->data;
9828 gint len = QT_UINT32 (fiel_data);
9831 stream->interlace_mode = GST_READ_UINT8 (fiel_data + 8);
9832 stream->field_order = GST_READ_UINT8 (fiel_data + 9);
9837 const guint8 *colr_data = (const guint8 *) colr->data;
9838 gint len = QT_UINT32 (colr_data);
9840 if (len == 19 || len == 18) {
9841 guint32 color_type = GST_READ_UINT32_LE (colr_data + 8);
9843 if (color_type == FOURCC_nclx || color_type == FOURCC_nclc) {
9844 guint16 primaries = GST_READ_UINT16_BE (colr_data + 12);
9845 guint16 transfer_function = GST_READ_UINT16_BE (colr_data + 14);
9846 guint16 matrix = GST_READ_UINT16_BE (colr_data + 16);
9847 gboolean full_range = len == 19 ? colr_data[17] >> 7 : FALSE;
9849 switch (primaries) {
9851 stream->colorimetry.primaries = GST_VIDEO_COLOR_PRIMARIES_BT709;
9854 stream->colorimetry.primaries = GST_VIDEO_COLOR_PRIMARIES_BT470BG;
9857 stream->colorimetry.primaries =
9858 GST_VIDEO_COLOR_PRIMARIES_SMPTE170M;
9861 stream->colorimetry.primaries = GST_VIDEO_COLOR_PRIMARIES_BT2020;
9867 switch (transfer_function) {
9869 stream->colorimetry.transfer = GST_VIDEO_TRANSFER_BT709;
9872 stream->colorimetry.transfer = GST_VIDEO_TRANSFER_SMPTE240M;
9880 stream->colorimetry.matrix = GST_VIDEO_COLOR_MATRIX_BT709;
9883 stream->colorimetry.matrix = GST_VIDEO_COLOR_MATRIX_BT601;
9886 stream->colorimetry.matrix = GST_VIDEO_COLOR_MATRIX_SMPTE240M;
9889 stream->colorimetry.matrix = GST_VIDEO_COLOR_MATRIX_BT2020;
9895 stream->colorimetry.range =
9896 full_range ? GST_VIDEO_COLOR_RANGE_0_255 :
9897 GST_VIDEO_COLOR_RANGE_16_235;
9899 GST_DEBUG_OBJECT (qtdemux, "Unsupported color type");
9902 GST_WARNING_OBJECT (qtdemux, "Invalid colr atom size");
9907 gst_qtdemux_handle_esds (qtdemux, stream, esds, stream->pending_tags);
9914 gint len = QT_UINT32 (stsd_data) - 0x66;
9915 const guint8 *avc_data = stsd_data + 0x66;
9918 while (len >= 0x8) {
9921 if (QT_UINT32 (avc_data) <= len)
9922 size = QT_UINT32 (avc_data) - 0x8;
9927 /* No real data, so break out */
9930 switch (QT_FOURCC (avc_data + 0x4)) {
9933 /* parse, if found */
9936 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
9938 /* First 4 bytes are the length of the atom, the next 4 bytes
9939 * are the fourcc, the next 1 byte is the version, and the
9940 * subsequent bytes are profile_tier_level structure like data. */
9941 gst_codec_utils_h264_caps_set_level_and_profile (stream->caps,
9942 avc_data + 8 + 1, size - 1);
9943 buf = gst_buffer_new_and_alloc (size);
9944 gst_buffer_fill (buf, 0, avc_data + 0x8, size);
9945 gst_caps_set_simple (stream->caps,
9946 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9947 gst_buffer_unref (buf);
9955 GST_DEBUG_OBJECT (qtdemux, "found strf codec_data in stsd");
9957 /* First 4 bytes are the length of the atom, the next 4 bytes
9958 * are the fourcc, next 40 bytes are BITMAPINFOHEADER,
9959 * next 1 byte is the version, and the
9960 * subsequent bytes are sequence parameter set like data. */
9962 size -= 40; /* we'll be skipping BITMAPINFOHEADER */
9964 gst_codec_utils_h264_caps_set_level_and_profile (stream->caps,
9965 avc_data + 8 + 40 + 1, size - 1);
9967 buf = gst_buffer_new_and_alloc (size);
9968 gst_buffer_fill (buf, 0, avc_data + 8 + 40, size);
9969 gst_caps_set_simple (stream->caps,
9970 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9971 gst_buffer_unref (buf);
9977 guint avg_bitrate, max_bitrate;
9979 /* bufferSizeDB, maxBitrate and avgBitrate - 4 bytes each */
9983 max_bitrate = QT_UINT32 (avc_data + 0xc);
9984 avg_bitrate = QT_UINT32 (avc_data + 0x10);
9986 if (!max_bitrate && !avg_bitrate)
9989 /* Some muxers seem to swap the average and maximum bitrates
9990 * (I'm looking at you, YouTube), so we swap for sanity. */
9991 if (max_bitrate > 0 && max_bitrate < avg_bitrate) {
9992 guint temp = avg_bitrate;
9994 avg_bitrate = max_bitrate;
9998 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
9999 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
10000 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
10002 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
10003 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
10004 GST_TAG_BITRATE, avg_bitrate, NULL);
10015 avc_data += size + 8;
10024 gint len = QT_UINT32 (stsd_data) - 0x66;
10025 const guint8 *hevc_data = stsd_data + 0x66;
10028 while (len >= 0x8) {
10031 if (QT_UINT32 (hevc_data) <= len)
10032 size = QT_UINT32 (hevc_data) - 0x8;
10037 /* No real data, so break out */
10040 switch (QT_FOURCC (hevc_data + 0x4)) {
10043 /* parse, if found */
10046 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
10048 /* First 4 bytes are the length of the atom, the next 4 bytes
10049 * are the fourcc, the next 1 byte is the version, and the
10050 * subsequent bytes are sequence parameter set like data. */
10051 gst_codec_utils_h265_caps_set_level_tier_and_profile
10052 (stream->caps, hevc_data + 8 + 1, size - 1);
10054 buf = gst_buffer_new_and_alloc (size);
10055 gst_buffer_fill (buf, 0, hevc_data + 0x8, size);
10056 gst_caps_set_simple (stream->caps,
10057 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10058 gst_buffer_unref (buf);
10065 hevc_data += size + 8;
10078 GST_DEBUG_OBJECT (qtdemux, "found %" GST_FOURCC_FORMAT,
10079 GST_FOURCC_ARGS (fourcc));
10081 /* codec data might be in glbl extension atom */
10083 qtdemux_tree_get_child_by_type (mp4v, FOURCC_glbl) : NULL;
10089 GST_DEBUG_OBJECT (qtdemux, "found glbl data in stsd");
10091 len = QT_UINT32 (data);
10094 buf = gst_buffer_new_and_alloc (len);
10095 gst_buffer_fill (buf, 0, data + 8, len);
10096 gst_caps_set_simple (stream->caps,
10097 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10098 gst_buffer_unref (buf);
10105 /* see annex I of the jpeg2000 spec */
10106 GNode *jp2h, *ihdr, *colr, *mjp2, *field, *prefix, *cmap, *cdef;
10107 const guint8 *data;
10108 const gchar *colorspace = NULL;
10110 guint32 ncomp_map = 0;
10111 gint32 *comp_map = NULL;
10112 guint32 nchan_def = 0;
10113 gint32 *chan_def = NULL;
10115 GST_DEBUG_OBJECT (qtdemux, "found mjp2");
10116 /* some required atoms */
10117 mjp2 = qtdemux_tree_get_child_by_type (stsd, FOURCC_mjp2);
10120 jp2h = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2h);
10124 /* number of components; redundant with info in codestream, but useful
10126 ihdr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_ihdr);
10127 if (!ihdr || QT_UINT32 (ihdr->data) != 22)
10129 ncomp = QT_UINT16 (((guint8 *) ihdr->data) + 16);
10131 colr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_colr);
10134 GST_DEBUG_OBJECT (qtdemux, "found colr");
10135 /* extract colour space info */
10136 if (QT_UINT8 ((guint8 *) colr->data + 8) == 1) {
10137 switch (QT_UINT32 ((guint8 *) colr->data + 11)) {
10139 colorspace = "sRGB";
10142 colorspace = "GRAY";
10145 colorspace = "sYUV";
10153 /* colr is required, and only values 16, 17, and 18 are specified,
10154 so error if we have no colorspace */
10157 /* extract component mapping */
10158 cmap = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cmap);
10160 guint32 cmap_len = 0;
10162 cmap_len = QT_UINT32 (cmap->data);
10163 if (cmap_len >= 8) {
10164 /* normal box, subtract off header */
10166 /* cmap: { u16 cmp; u8 mtyp; u8 pcol; }* */
10167 if (cmap_len % 4 == 0) {
10168 ncomp_map = (cmap_len / 4);
10169 comp_map = g_new0 (gint32, ncomp_map);
10170 for (i = 0; i < ncomp_map; i++) {
10173 cmp = QT_UINT16 (((guint8 *) cmap->data) + 8 + i * 4);
10174 mtyp = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 2);
10175 pcol = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 3);
10176 comp_map[i] = (mtyp << 24) | (pcol << 16) | cmp;
10181 /* extract channel definitions */
10182 cdef = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cdef);
10184 guint32 cdef_len = 0;
10186 cdef_len = QT_UINT32 (cdef->data);
10187 if (cdef_len >= 10) {
10188 /* normal box, subtract off header and len */
10190 /* cdef: u16 n; { u16 cn; u16 typ; u16 asoc; }* */
10191 if (cdef_len % 6 == 0) {
10192 nchan_def = (cdef_len / 6);
10193 chan_def = g_new0 (gint32, nchan_def);
10194 for (i = 0; i < nchan_def; i++)
10196 for (i = 0; i < nchan_def; i++) {
10197 guint16 cn, typ, asoc;
10198 cn = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6);
10199 typ = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 2);
10200 asoc = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 4);
10201 if (cn < nchan_def) {
10204 chan_def[cn] = asoc;
10207 chan_def[cn] = 0; /* alpha */
10210 chan_def[cn] = -typ;
10218 gst_caps_set_simple (stream->caps,
10219 "num-components", G_TYPE_INT, ncomp, NULL);
10220 gst_caps_set_simple (stream->caps,
10221 "colorspace", G_TYPE_STRING, colorspace, NULL);
10224 GValue arr = { 0, };
10225 GValue elt = { 0, };
10227 g_value_init (&arr, GST_TYPE_ARRAY);
10228 g_value_init (&elt, G_TYPE_INT);
10229 for (i = 0; i < ncomp_map; i++) {
10230 g_value_set_int (&elt, comp_map[i]);
10231 gst_value_array_append_value (&arr, &elt);
10233 gst_structure_set_value (gst_caps_get_structure (stream->caps, 0),
10234 "component-map", &arr);
10235 g_value_unset (&elt);
10236 g_value_unset (&arr);
10241 GValue arr = { 0, };
10242 GValue elt = { 0, };
10244 g_value_init (&arr, GST_TYPE_ARRAY);
10245 g_value_init (&elt, G_TYPE_INT);
10246 for (i = 0; i < nchan_def; i++) {
10247 g_value_set_int (&elt, chan_def[i]);
10248 gst_value_array_append_value (&arr, &elt);
10250 gst_structure_set_value (gst_caps_get_structure (stream->caps, 0),
10251 "channel-definitions", &arr);
10252 g_value_unset (&elt);
10253 g_value_unset (&arr);
10257 /* some optional atoms */
10258 field = qtdemux_tree_get_child_by_type (mjp2, FOURCC_fiel);
10259 prefix = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2x);
10261 /* indicate possible fields in caps */
10263 data = (guint8 *) field->data + 8;
10265 gst_caps_set_simple (stream->caps, "fields", G_TYPE_INT,
10266 (gint) * data, NULL);
10268 /* add codec_data if provided */
10273 GST_DEBUG_OBJECT (qtdemux, "found prefix data in stsd");
10274 data = prefix->data;
10275 len = QT_UINT32 (data);
10278 buf = gst_buffer_new_and_alloc (len);
10279 gst_buffer_fill (buf, 0, data + 8, len);
10280 gst_caps_set_simple (stream->caps,
10281 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10282 gst_buffer_unref (buf);
10289 /* https://developer.apple.com/standards/qtff-2001.pdf,
10290 * page 92, "Video Sample Description", under table 3.1 */
10293 const gint compressor_offset = 16 + 4 + 4 * 3 + 2 * 2 + 2 * 4 + 4 + 2;
10294 const gint min_size = compressor_offset + 32 + 2 + 2;
10297 guint16 color_table_id = 0;
10300 GST_DEBUG_OBJECT (qtdemux, "found jpeg");
10302 /* recover information on interlaced/progressive */
10303 jpeg = qtdemux_tree_get_child_by_type (stsd, FOURCC_jpeg);
10307 len = QT_UINT32 (jpeg->data);
10308 GST_DEBUG_OBJECT (qtdemux, "Found jpeg: len %u, need %d", len,
10310 if (len >= min_size) {
10311 gst_byte_reader_init (&br, jpeg->data, len);
10313 gst_byte_reader_skip (&br, compressor_offset + 32 + 2);
10314 gst_byte_reader_get_uint16_le (&br, &color_table_id);
10315 if (color_table_id != 0) {
10316 /* the spec says there can be concatenated chunks in the data, and we want
10317 * to find one called field. Walk through them. */
10318 gint offset = min_size;
10319 while (offset + 8 < len) {
10320 guint32 size = 0, tag;
10321 ok = gst_byte_reader_get_uint32_le (&br, &size);
10322 ok &= gst_byte_reader_get_uint32_le (&br, &tag);
10323 if (!ok || size < 8) {
10324 GST_WARNING_OBJECT (qtdemux,
10325 "Failed to walk optional chunk list");
10328 GST_DEBUG_OBJECT (qtdemux,
10329 "Found optional %4.4s chunk, size %u", (const char *) &tag,
10331 if (tag == FOURCC_fiel) {
10332 guint8 n_fields, ordering;
10333 gst_byte_reader_get_uint8 (&br, &n_fields);
10334 gst_byte_reader_get_uint8 (&br, &ordering);
10335 if (n_fields == 1 || n_fields == 2) {
10336 GST_DEBUG_OBJECT (qtdemux,
10337 "Found fiel tag with %u fields, ordering %u", n_fields,
10340 gst_caps_set_simple (stream->caps, "interlace-mode",
10341 G_TYPE_STRING, "interleaved", NULL);
10343 GST_WARNING_OBJECT (qtdemux,
10344 "Found fiel tag with invalid fields (%u)", n_fields);
10350 GST_DEBUG_OBJECT (qtdemux,
10351 "Color table ID is 0, not trying to get interlacedness");
10354 GST_WARNING_OBJECT (qtdemux,
10355 "Length of jpeg chunk is too small, not trying to get interlacedness");
10364 GstBuffer *seqh = NULL;
10365 guint8 *gamma_data = NULL;
10366 gint len = QT_UINT32 (stsd_data);
10368 qtdemux_parse_svq3_stsd_data (qtdemux, stsd, &gamma_data, &seqh);
10370 gst_caps_set_simple (stream->caps, "applied-gamma", G_TYPE_DOUBLE,
10371 QT_FP32 (gamma_data), NULL);
10374 /* sorry for the bad name, but we don't know what this is, other
10375 * than its own fourcc */
10376 gst_caps_set_simple (stream->caps, "seqh", GST_TYPE_BUFFER, seqh,
10378 gst_buffer_unref (seqh);
10381 GST_DEBUG_OBJECT (qtdemux, "found codec_data in stsd");
10382 buf = gst_buffer_new_and_alloc (len);
10383 gst_buffer_fill (buf, 0, stsd_data, len);
10384 gst_caps_set_simple (stream->caps,
10385 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10386 gst_buffer_unref (buf);
10392 gst_caps_set_simple (stream->caps,
10393 "depth", G_TYPE_INT, QT_UINT16 (stsd_data + offset + 82), NULL);
10398 GNode *xith, *xdxt;
10400 GST_DEBUG_OBJECT (qtdemux, "found XiTh");
10401 xith = qtdemux_tree_get_child_by_type (stsd, FOURCC_XiTh);
10405 xdxt = qtdemux_tree_get_child_by_type (xith, FOURCC_XdxT);
10409 GST_DEBUG_OBJECT (qtdemux, "found XdxT node");
10410 /* collect the headers and store them in a stream list so that we can
10411 * send them out first */
10412 qtdemux_parse_theora_extension (qtdemux, stream, xdxt);
10422 GST_DEBUG_OBJECT (qtdemux, "parse ovc1 header");
10423 ovc1 = qtdemux_tree_get_child_by_type (stsd, FOURCC_ovc1);
10426 ovc1_data = ovc1->data;
10427 ovc1_len = QT_UINT32 (ovc1_data);
10428 if (ovc1_len <= 198) {
10429 GST_WARNING_OBJECT (qtdemux, "Too small ovc1 header, skipping");
10432 buf = gst_buffer_new_and_alloc (ovc1_len - 198);
10433 gst_buffer_fill (buf, 0, ovc1_data + 198, ovc1_len - 198);
10434 gst_caps_set_simple (stream->caps,
10435 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10436 gst_buffer_unref (buf);
10441 gint len = QT_UINT32 (stsd_data) - 0x66;
10442 const guint8 *vc1_data = stsd_data + 0x66;
10448 if (QT_UINT32 (vc1_data) <= len)
10449 size = QT_UINT32 (vc1_data) - 8;
10454 /* No real data, so break out */
10457 switch (QT_FOURCC (vc1_data + 0x4)) {
10458 case GST_MAKE_FOURCC ('d', 'v', 'c', '1'):
10462 GST_DEBUG_OBJECT (qtdemux, "found dvc1 codec_data in stsd");
10463 buf = gst_buffer_new_and_alloc (size);
10464 gst_buffer_fill (buf, 0, vc1_data + 8, size);
10465 gst_caps_set_simple (stream->caps,
10466 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10467 gst_buffer_unref (buf);
10474 vc1_data += size + 8;
10483 GST_INFO_OBJECT (qtdemux,
10484 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
10485 GST_FOURCC_ARGS (fourcc), stream->caps);
10487 } else if (stream->subtype == FOURCC_soun) {
10488 int version, samplesize;
10489 guint16 compression_id;
10490 gboolean amrwb = FALSE;
10493 /* sample description entry (16) + sound sample description v0 (20) */
10497 version = QT_UINT32 (stsd_data + offset);
10498 stream->n_channels = QT_UINT16 (stsd_data + offset + 8);
10499 samplesize = QT_UINT16 (stsd_data + offset + 10);
10500 compression_id = QT_UINT16 (stsd_data + offset + 12);
10501 stream->rate = QT_FP32 (stsd_data + offset + 16);
10503 GST_LOG_OBJECT (qtdemux, "version/rev: %08x", version);
10504 GST_LOG_OBJECT (qtdemux, "vendor: %08x",
10505 QT_UINT32 (stsd_data + offset + 4));
10506 GST_LOG_OBJECT (qtdemux, "n_channels: %d", stream->n_channels);
10507 GST_LOG_OBJECT (qtdemux, "sample_size: %d", samplesize);
10508 GST_LOG_OBJECT (qtdemux, "compression_id: %d", compression_id);
10509 GST_LOG_OBJECT (qtdemux, "packet size: %d",
10510 QT_UINT16 (stsd_data + offset + 14));
10511 GST_LOG_OBJECT (qtdemux, "sample rate: %g", stream->rate);
10513 if (compression_id == 0xfffe)
10514 stream->sampled = TRUE;
10516 /* first assume uncompressed audio */
10517 stream->bytes_per_sample = samplesize / 8;
10518 stream->samples_per_frame = stream->n_channels;
10519 stream->bytes_per_frame = stream->n_channels * stream->bytes_per_sample;
10520 stream->samples_per_packet = stream->samples_per_frame;
10521 stream->bytes_per_packet = stream->bytes_per_sample;
10525 /* Yes, these have to be hard-coded */
10528 stream->samples_per_packet = 6;
10529 stream->bytes_per_packet = 1;
10530 stream->bytes_per_frame = 1 * stream->n_channels;
10531 stream->bytes_per_sample = 1;
10532 stream->samples_per_frame = 6 * stream->n_channels;
10537 stream->samples_per_packet = 3;
10538 stream->bytes_per_packet = 1;
10539 stream->bytes_per_frame = 1 * stream->n_channels;
10540 stream->bytes_per_sample = 1;
10541 stream->samples_per_frame = 3 * stream->n_channels;
10546 stream->samples_per_packet = 64;
10547 stream->bytes_per_packet = 34;
10548 stream->bytes_per_frame = 34 * stream->n_channels;
10549 stream->bytes_per_sample = 2;
10550 stream->samples_per_frame = 64 * stream->n_channels;
10556 stream->samples_per_packet = 1;
10557 stream->bytes_per_packet = 1;
10558 stream->bytes_per_frame = 1 * stream->n_channels;
10559 stream->bytes_per_sample = 1;
10560 stream->samples_per_frame = 1 * stream->n_channels;
10565 stream->samples_per_packet = 160;
10566 stream->bytes_per_packet = 33;
10567 stream->bytes_per_frame = 33 * stream->n_channels;
10568 stream->bytes_per_sample = 2;
10569 stream->samples_per_frame = 160 * stream->n_channels;
10576 if (version == 0x00010000) {
10577 /* sample description entry (16) + sound sample description v1 (20+16) */
10588 /* only parse extra decoding config for non-pcm audio */
10589 stream->samples_per_packet = QT_UINT32 (stsd_data + offset);
10590 stream->bytes_per_packet = QT_UINT32 (stsd_data + offset + 4);
10591 stream->bytes_per_frame = QT_UINT32 (stsd_data + offset + 8);
10592 stream->bytes_per_sample = QT_UINT32 (stsd_data + offset + 12);
10594 GST_LOG_OBJECT (qtdemux, "samples/packet: %d",
10595 stream->samples_per_packet);
10596 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
10597 stream->bytes_per_packet);
10598 GST_LOG_OBJECT (qtdemux, "bytes/frame: %d",
10599 stream->bytes_per_frame);
10600 GST_LOG_OBJECT (qtdemux, "bytes/sample: %d",
10601 stream->bytes_per_sample);
10603 if (!stream->sampled && stream->bytes_per_packet) {
10604 stream->samples_per_frame = (stream->bytes_per_frame /
10605 stream->bytes_per_packet) * stream->samples_per_packet;
10606 GST_LOG_OBJECT (qtdemux, "samples/frame: %d",
10607 stream->samples_per_frame);
10612 } else if (version == 0x00020000) {
10619 /* sample description entry (16) + sound sample description v2 (56) */
10623 qtfp.val = QT_UINT64 (stsd_data + offset + 4);
10624 stream->rate = qtfp.fp;
10625 stream->n_channels = QT_UINT32 (stsd_data + offset + 12);
10627 GST_LOG_OBJECT (qtdemux, "Sound sample description Version 2");
10628 GST_LOG_OBJECT (qtdemux, "sample rate: %g", stream->rate);
10629 GST_LOG_OBJECT (qtdemux, "n_channels: %d", stream->n_channels);
10630 GST_LOG_OBJECT (qtdemux, "bits/channel: %d",
10631 QT_UINT32 (stsd_data + offset + 20));
10632 GST_LOG_OBJECT (qtdemux, "format flags: %X",
10633 QT_UINT32 (stsd_data + offset + 24));
10634 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
10635 QT_UINT32 (stsd_data + offset + 28));
10636 GST_LOG_OBJECT (qtdemux, "LPCM frames/packet: %d",
10637 QT_UINT32 (stsd_data + offset + 32));
10638 } else if (version != 0x00000) {
10639 GST_WARNING_OBJECT (qtdemux, "unknown audio STSD version %08x", version);
10643 gst_caps_unref (stream->caps);
10645 stream->caps = qtdemux_audio_caps (qtdemux, stream, fourcc,
10646 stsd_data + 32, len - 16, &codec);
10654 in24 = qtdemux_tree_get_child_by_type (stsd, FOURCC_in24);
10656 enda = qtdemux_tree_get_child_by_type (in24, FOURCC_enda);
10658 wave = qtdemux_tree_get_child_by_type (in24, FOURCC_wave);
10660 enda = qtdemux_tree_get_child_by_type (wave, FOURCC_enda);
10663 int enda_value = QT_UINT16 ((guint8 *) enda->data + 8);
10664 gst_caps_set_simple (stream->caps,
10665 "format", G_TYPE_STRING, (enda_value) ? "S24LE" : "S24BE", NULL);
10672 const guint8 *owma_data;
10673 const gchar *codec_name = NULL;
10677 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
10678 /* FIXME this should also be gst_riff_strf_auds,
10679 * but the latter one is actually missing bits-per-sample :( */
10684 gint32 nSamplesPerSec;
10685 gint32 nAvgBytesPerSec;
10686 gint16 nBlockAlign;
10687 gint16 wBitsPerSample;
10690 WAVEFORMATEX *wfex;
10692 GST_DEBUG_OBJECT (qtdemux, "parse owma");
10693 owma = qtdemux_tree_get_child_by_type (stsd, FOURCC_owma);
10696 owma_data = owma->data;
10697 owma_len = QT_UINT32 (owma_data);
10698 if (owma_len <= 54) {
10699 GST_WARNING_OBJECT (qtdemux, "Too small owma header, skipping");
10702 wfex = (WAVEFORMATEX *) (owma_data + 36);
10703 buf = gst_buffer_new_and_alloc (owma_len - 54);
10704 gst_buffer_fill (buf, 0, owma_data + 54, owma_len - 54);
10705 if (wfex->wFormatTag == 0x0161) {
10706 codec_name = "Windows Media Audio";
10708 } else if (wfex->wFormatTag == 0x0162) {
10709 codec_name = "Windows Media Audio 9 Pro";
10711 } else if (wfex->wFormatTag == 0x0163) {
10712 codec_name = "Windows Media Audio 9 Lossless";
10713 /* is that correct? gstffmpegcodecmap.c is missing it, but
10714 * fluendo codec seems to support it */
10718 gst_caps_set_simple (stream->caps,
10719 "codec_data", GST_TYPE_BUFFER, buf,
10720 "wmaversion", G_TYPE_INT, version,
10721 "block_align", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->nBlockAlign),
10722 "bitrate", G_TYPE_INT, GST_READ_UINT32_LE (&wfex->nAvgBytesPerSec),
10723 "width", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->wBitsPerSample),
10724 "depth", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->wBitsPerSample),
10726 gst_buffer_unref (buf);
10730 codec = g_strdup (codec_name);
10736 gint len = QT_UINT32 (stsd_data) - offset;
10737 const guint8 *wfex_data = stsd_data + offset;
10738 const gchar *codec_name = NULL;
10740 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
10741 /* FIXME this should also be gst_riff_strf_auds,
10742 * but the latter one is actually missing bits-per-sample :( */
10747 gint32 nSamplesPerSec;
10748 gint32 nAvgBytesPerSec;
10749 gint16 nBlockAlign;
10750 gint16 wBitsPerSample;
10755 /* FIXME: unify with similar wavformatex parsing code above */
10756 GST_DEBUG_OBJECT (qtdemux, "parse wma, looking for wfex");
10762 if (QT_UINT32 (wfex_data) <= len)
10763 size = QT_UINT32 (wfex_data) - 8;
10768 /* No real data, so break out */
10771 switch (QT_FOURCC (wfex_data + 4)) {
10772 case GST_MAKE_FOURCC ('w', 'f', 'e', 'x'):
10774 GST_DEBUG_OBJECT (qtdemux, "found wfex in stsd");
10779 wfex.wFormatTag = GST_READ_UINT16_LE (wfex_data + 8 + 0);
10780 wfex.nChannels = GST_READ_UINT16_LE (wfex_data + 8 + 2);
10781 wfex.nSamplesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 4);
10782 wfex.nAvgBytesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 8);
10783 wfex.nBlockAlign = GST_READ_UINT16_LE (wfex_data + 8 + 12);
10784 wfex.wBitsPerSample = GST_READ_UINT16_LE (wfex_data + 8 + 14);
10785 wfex.cbSize = GST_READ_UINT16_LE (wfex_data + 8 + 16);
10787 GST_LOG_OBJECT (qtdemux, "Found wfex box in stsd:");
10788 GST_LOG_OBJECT (qtdemux, "FormatTag = 0x%04x, Channels = %u, "
10789 "SamplesPerSec = %u, AvgBytesPerSec = %u, BlockAlign = %u, "
10790 "BitsPerSample = %u, Size = %u", wfex.wFormatTag,
10791 wfex.nChannels, wfex.nSamplesPerSec, wfex.nAvgBytesPerSec,
10792 wfex.nBlockAlign, wfex.wBitsPerSample, wfex.cbSize);
10794 if (wfex.wFormatTag == 0x0161) {
10795 codec_name = "Windows Media Audio";
10797 } else if (wfex.wFormatTag == 0x0162) {
10798 codec_name = "Windows Media Audio 9 Pro";
10800 } else if (wfex.wFormatTag == 0x0163) {
10801 codec_name = "Windows Media Audio 9 Lossless";
10802 /* is that correct? gstffmpegcodecmap.c is missing it, but
10803 * fluendo codec seems to support it */
10807 gst_caps_set_simple (stream->caps,
10808 "wmaversion", G_TYPE_INT, version,
10809 "block_align", G_TYPE_INT, wfex.nBlockAlign,
10810 "bitrate", G_TYPE_INT, wfex.nAvgBytesPerSec,
10811 "width", G_TYPE_INT, wfex.wBitsPerSample,
10812 "depth", G_TYPE_INT, wfex.wBitsPerSample, NULL);
10814 if (size > wfex.cbSize) {
10817 buf = gst_buffer_new_and_alloc (size - wfex.cbSize);
10818 gst_buffer_fill (buf, 0, wfex_data + 8 + wfex.cbSize,
10819 size - wfex.cbSize);
10820 gst_caps_set_simple (stream->caps,
10821 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10822 gst_buffer_unref (buf);
10824 GST_WARNING_OBJECT (qtdemux, "no codec data");
10829 codec = g_strdup (codec_name);
10837 wfex_data += size + 8;
10844 const guint8 *opus_data;
10845 guint8 *channel_mapping = NULL;
10848 guint8 channel_mapping_family;
10849 guint8 stream_count;
10850 guint8 coupled_count;
10853 opus = qtdemux_tree_get_child_by_type (stsd, FOURCC_opus);
10854 opus_data = opus->data;
10856 channels = GST_READ_UINT8 (opus_data + 45);
10857 rate = GST_READ_UINT32_LE (opus_data + 48);
10858 channel_mapping_family = GST_READ_UINT8 (opus_data + 54);
10859 stream_count = GST_READ_UINT8 (opus_data + 55);
10860 coupled_count = GST_READ_UINT8 (opus_data + 56);
10862 if (channels > 0) {
10863 channel_mapping = g_malloc (channels * sizeof (guint8));
10864 for (i = 0; i < channels; i++)
10865 channel_mapping[i] = GST_READ_UINT8 (opus_data + i + 57);
10868 stream->caps = gst_codec_utils_opus_create_caps (rate, channels,
10869 channel_mapping_family, stream_count, coupled_count,
10881 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
10882 GST_TAG_AUDIO_CODEC, codec, NULL);
10886 /* some bitrate info may have ended up in caps */
10887 s = gst_caps_get_structure (stream->caps, 0);
10888 gst_structure_get_int (s, "bitrate", &bitrate);
10890 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
10891 GST_TAG_BITRATE, bitrate, NULL);
10894 if (stream->protected && fourcc == FOURCC_mp4a)
10895 mp4a = qtdemux_tree_get_child_by_type (stsd, FOURCC_enca);
10897 mp4a = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4a);
10902 wave = qtdemux_tree_get_child_by_type (mp4a, FOURCC_wave);
10904 esds = qtdemux_tree_get_child_by_type (wave, FOURCC_esds);
10906 esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
10910 /* If the fourcc's bottom 16 bits gives 'sm', then the top
10911 16 bits is a byte-swapped wave-style codec identifier,
10912 and we can find a WAVE header internally to a 'wave' atom here.
10913 This can more clearly be thought of as 'ms' as the top 16 bits, and a
10914 codec id as the bottom 16 bits - but byte-swapped to store in QT (which
10917 if ((fourcc & 0xffff) == (('s' << 8) | 'm')) {
10918 if (len < offset + 20) {
10919 GST_WARNING_OBJECT (qtdemux, "No wave atom in MS-style audio");
10921 guint32 datalen = QT_UINT32 (stsd_data + offset + 16);
10922 const guint8 *data = stsd_data + offset + 16;
10924 GNode *waveheadernode;
10926 wavenode = g_node_new ((guint8 *) data);
10927 if (qtdemux_parse_node (qtdemux, wavenode, data, datalen)) {
10928 const guint8 *waveheader;
10931 waveheadernode = qtdemux_tree_get_child_by_type (wavenode, fourcc);
10932 if (waveheadernode) {
10933 waveheader = (const guint8 *) waveheadernode->data;
10934 headerlen = QT_UINT32 (waveheader);
10936 if (headerlen > 8) {
10937 gst_riff_strf_auds *header = NULL;
10938 GstBuffer *headerbuf;
10944 headerbuf = gst_buffer_new_and_alloc (headerlen);
10945 gst_buffer_fill (headerbuf, 0, waveheader, headerlen);
10947 if (gst_riff_parse_strf_auds (GST_ELEMENT_CAST (qtdemux),
10948 headerbuf, &header, &extra)) {
10949 gst_caps_unref (stream->caps);
10950 /* FIXME: Need to do something with the channel reorder map */
10951 stream->caps = gst_riff_create_audio_caps (header->format, NULL,
10952 header, extra, NULL, NULL, NULL);
10955 gst_buffer_unref (extra);
10960 GST_DEBUG ("Didn't find waveheadernode for this codec");
10962 g_node_destroy (wavenode);
10965 gst_qtdemux_handle_esds (qtdemux, stream, esds, stream->pending_tags);
10969 /* FIXME: what is in the chunk? */
10972 gint len = QT_UINT32 (stsd_data);
10974 /* seems to be always = 116 = 0x74 */
10980 gint len = QT_UINT32 (stsd_data);
10983 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x4C);
10985 gst_buffer_fill (buf, 0, stsd_data + 0x4C, len - 0x4C);
10986 gst_caps_set_simple (stream->caps,
10987 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10988 gst_buffer_unref (buf);
10990 gst_caps_set_simple (stream->caps,
10991 "samplesize", G_TYPE_INT, samplesize, NULL);
10996 GNode *alac, *wave = NULL;
10998 /* apparently, m4a has this atom appended directly in the stsd entry,
10999 * while mov has it in a wave atom */
11000 alac = qtdemux_tree_get_child_by_type (stsd, FOURCC_alac);
11002 /* alac now refers to stsd entry atom */
11003 wave = qtdemux_tree_get_child_by_type (alac, FOURCC_wave);
11005 alac = qtdemux_tree_get_child_by_type (wave, FOURCC_alac);
11007 alac = qtdemux_tree_get_child_by_type (alac, FOURCC_alac);
11010 const guint8 *alac_data = alac->data;
11011 gint len = QT_UINT32 (alac->data);
11015 GST_DEBUG_OBJECT (qtdemux,
11016 "discarding alac atom with unexpected len %d", len);
11018 /* codec-data contains alac atom size and prefix,
11019 * ffmpeg likes it that way, not quite gst-ish though ...*/
11020 buf = gst_buffer_new_and_alloc (len);
11021 gst_buffer_fill (buf, 0, alac->data, len);
11022 gst_caps_set_simple (stream->caps,
11023 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11024 gst_buffer_unref (buf);
11026 stream->bytes_per_frame = QT_UINT32 (alac_data + 12);
11027 stream->n_channels = QT_UINT8 (alac_data + 21);
11028 stream->rate = QT_UINT32 (alac_data + 32);
11031 gst_caps_set_simple (stream->caps,
11032 "samplesize", G_TYPE_INT, samplesize, NULL);
11037 /* The codingname of the sample entry is 'fLaC' */
11038 GNode *flac = qtdemux_tree_get_child_by_type (stsd, FOURCC_fLaC);
11041 /* The 'dfLa' box is added to the sample entry to convey
11042 initializing information for the decoder. */
11043 const GNode *dfla =
11044 qtdemux_tree_get_child_by_type (flac, FOURCC_dfLa);
11047 const guint32 len = QT_UINT32 (dfla->data);
11049 /* Must contain at least dfLa box header (12),
11050 * METADATA_BLOCK_HEADER (4), METADATA_BLOCK_STREAMINFO (34) */
11052 GST_DEBUG_OBJECT (qtdemux,
11053 "discarding dfla atom with unexpected len %d", len);
11055 /* skip dfLa header to get the METADATA_BLOCKs */
11056 const guint8 *metadata_blocks = (guint8 *) dfla->data + 12;
11057 const guint32 metadata_blocks_len = len - 12;
11059 gchar *stream_marker = g_strdup ("fLaC");
11060 GstBuffer *block = gst_buffer_new_wrapped (stream_marker,
11061 strlen (stream_marker));
11064 guint32 remainder = 0;
11065 guint32 block_size = 0;
11066 gboolean is_last = FALSE;
11068 GValue array = G_VALUE_INIT;
11069 GValue value = G_VALUE_INIT;
11071 g_value_init (&array, GST_TYPE_ARRAY);
11072 g_value_init (&value, GST_TYPE_BUFFER);
11074 gst_value_set_buffer (&value, block);
11075 gst_value_array_append_value (&array, &value);
11076 g_value_reset (&value);
11078 gst_buffer_unref (block);
11080 /* check there's at least one METADATA_BLOCK_HEADER's worth
11081 * of data, and we haven't already finished parsing */
11082 while (!is_last && ((index + 3) < metadata_blocks_len)) {
11083 remainder = metadata_blocks_len - index;
11085 /* add the METADATA_BLOCK_HEADER size to the signalled size */
11087 (metadata_blocks[index + 1] << 16) +
11088 (metadata_blocks[index + 2] << 8) +
11089 metadata_blocks[index + 3];
11091 /* be careful not to read off end of box */
11092 if (block_size > remainder) {
11096 is_last = metadata_blocks[index] >> 7;
11098 block = gst_buffer_new_and_alloc (block_size);
11100 gst_buffer_fill (block, 0, &metadata_blocks[index],
11103 gst_value_set_buffer (&value, block);
11104 gst_value_array_append_value (&array, &value);
11105 g_value_reset (&value);
11107 gst_buffer_unref (block);
11109 index += block_size;
11112 /* only append the metadata if we successfully read all of it */
11114 gst_structure_set_value (gst_caps_get_structure (stream->caps,
11115 0), "streamheader", &array);
11117 GST_WARNING_OBJECT (qtdemux,
11118 "discarding all METADATA_BLOCKs due to invalid "
11119 "block_size %d at idx %d, rem %d", block_size, index,
11123 g_value_unset (&value);
11124 g_value_unset (&array);
11126 /* The sample rate obtained from the stsd may not be accurate
11127 * since it cannot represent rates greater than 65535Hz, so
11128 * override that value with the sample rate from the
11129 * METADATA_BLOCK_STREAMINFO block */
11131 (QT_UINT32 (metadata_blocks + 14) >> 12) & 0xFFFFF;
11142 gint len = QT_UINT32 (stsd_data);
11145 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x34);
11148 gst_buffer_fill (buf, 0, stsd_data + 0x34, len - 0x34);
11150 /* If we have enough data, let's try to get the 'damr' atom. See
11151 * the 3GPP container spec (26.244) for more details. */
11152 if ((len - 0x34) > 8 &&
11153 (bitrate = qtdemux_parse_amr_bitrate (buf, amrwb))) {
11154 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
11155 GST_TAG_MAXIMUM_BITRATE, bitrate, NULL);
11158 gst_caps_set_simple (stream->caps,
11159 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11160 gst_buffer_unref (buf);
11166 /* mp4a atom withtout ESDS; Attempt to build codec data from atom */
11167 gint len = QT_UINT32 (stsd_data);
11170 guint16 sound_version = QT_UINT16 (stsd_data + 32);
11172 if (sound_version == 1) {
11173 guint16 channels = QT_UINT16 (stsd_data + 40);
11174 guint32 time_scale = QT_UINT32 (stsd_data + 46);
11175 guint8 codec_data[2];
11177 gint profile = 2; /* FIXME: Can this be determined somehow? There doesn't seem to be anything in mp4a atom that specifis compression */
11179 gint sample_rate_index =
11180 gst_codec_utils_aac_get_index_from_sample_rate (time_scale);
11182 /* build AAC codec data */
11183 codec_data[0] = profile << 3;
11184 codec_data[0] |= ((sample_rate_index >> 1) & 0x7);
11185 codec_data[1] = (sample_rate_index & 0x01) << 7;
11186 codec_data[1] |= (channels & 0xF) << 3;
11188 buf = gst_buffer_new_and_alloc (2);
11189 gst_buffer_fill (buf, 0, codec_data, 2);
11190 gst_caps_set_simple (stream->caps,
11191 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11192 gst_buffer_unref (buf);
11198 GST_INFO_OBJECT (qtdemux,
11199 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
11203 GST_INFO_OBJECT (qtdemux,
11204 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
11205 GST_FOURCC_ARGS (fourcc), stream->caps);
11207 } else if (stream->subtype == FOURCC_strm) {
11208 if (fourcc == FOURCC_rtsp) {
11209 stream->redirect_uri = qtdemux_get_rtsp_uri_from_hndl (qtdemux, minf);
11211 GST_INFO_OBJECT (qtdemux, "unhandled stream type %" GST_FOURCC_FORMAT,
11212 GST_FOURCC_ARGS (fourcc));
11213 goto unknown_stream;
11215 stream->sampled = TRUE;
11216 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
11217 || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt) {
11219 stream->sampled = TRUE;
11220 stream->sparse = TRUE;
11223 qtdemux_sub_caps (qtdemux, stream, fourcc, stsd_data, &codec);
11225 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
11226 GST_TAG_SUBTITLE_CODEC, codec, NULL);
11231 /* hunt for sort-of codec data */
11235 GNode *mp4s = NULL;
11236 GNode *esds = NULL;
11238 /* look for palette in a stsd->mp4s->esds sub-atom */
11239 mp4s = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4s);
11241 esds = qtdemux_tree_get_child_by_type (mp4s, FOURCC_esds);
11242 if (esds == NULL) {
11244 GST_LOG_OBJECT (qtdemux, "Skipping invalid stsd: no esds child");
11248 gst_qtdemux_handle_esds (qtdemux, stream, esds, stream->pending_tags);
11252 GST_INFO_OBJECT (qtdemux,
11253 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
11256 GST_INFO_OBJECT (qtdemux,
11257 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
11258 GST_FOURCC_ARGS (fourcc), stream->caps);
11260 /* everything in 1 sample */
11261 stream->sampled = TRUE;
11264 qtdemux_generic_caps (qtdemux, stream, fourcc, stsd_data, &codec);
11266 if (stream->caps == NULL)
11267 goto unknown_stream;
11270 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
11271 GST_TAG_SUBTITLE_CODEC, codec, NULL);
11277 /* promote to sampled format */
11278 if (stream->fourcc == FOURCC_samr) {
11279 /* force mono 8000 Hz for AMR */
11280 stream->sampled = TRUE;
11281 stream->n_channels = 1;
11282 stream->rate = 8000;
11283 } else if (stream->fourcc == FOURCC_sawb) {
11284 /* force mono 16000 Hz for AMR-WB */
11285 stream->sampled = TRUE;
11286 stream->n_channels = 1;
11287 stream->rate = 16000;
11288 } else if (stream->fourcc == FOURCC_mp4a) {
11289 stream->sampled = TRUE;
11292 /* collect sample information */
11293 if (!qtdemux_stbl_init (qtdemux, stream, stbl))
11294 goto samples_failed;
11296 if (qtdemux->fragmented) {
11299 /* need all moov samples as basis; probably not many if any at all */
11300 /* prevent moof parsing taking of at this time */
11301 offset = qtdemux->moof_offset;
11302 qtdemux->moof_offset = 0;
11303 if (stream->n_samples &&
11304 !qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
11305 qtdemux->moof_offset = offset;
11306 goto samples_failed;
11308 qtdemux->moof_offset = 0;
11309 /* movie duration more reliable in this case (e.g. mehd) */
11310 if (qtdemux->segment.duration &&
11311 GST_CLOCK_TIME_IS_VALID (qtdemux->segment.duration))
11313 GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->segment.duration);
11316 /* configure segments */
11317 if (!qtdemux_parse_segments (qtdemux, stream, trak))
11318 goto segments_failed;
11320 /* add some language tag, if useful */
11321 if (stream->lang_id[0] != '\0' && strcmp (stream->lang_id, "unk") &&
11322 strcmp (stream->lang_id, "und")) {
11323 const gchar *lang_code;
11325 /* convert ISO 639-2 code to ISO 639-1 */
11326 lang_code = gst_tag_get_language_code (stream->lang_id);
11327 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
11328 GST_TAG_LANGUAGE_CODE, (lang_code) ? lang_code : stream->lang_id, NULL);
11331 /* Check for UDTA tags */
11332 if ((udta = qtdemux_tree_get_child_by_type (trak, FOURCC_udta))) {
11333 qtdemux_parse_udta (qtdemux, stream->pending_tags, udta);
11336 /* now we are ready to add the stream */
11337 if (qtdemux->n_streams >= GST_QTDEMUX_MAX_STREAMS)
11338 goto too_many_streams;
11340 if (!qtdemux->got_moov) {
11341 qtdemux->streams[qtdemux->n_streams] = stream;
11342 qtdemux->n_streams++;
11343 GST_DEBUG_OBJECT (qtdemux, "n_streams is now %d", qtdemux->n_streams);
11351 GST_INFO_OBJECT (qtdemux, "skip disabled track");
11353 gst_qtdemux_stream_free (qtdemux, stream);
11358 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
11359 (_("This file is corrupt and cannot be played.")), (NULL));
11361 gst_qtdemux_stream_free (qtdemux, stream);
11366 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT, (NULL), (NULL));
11368 gst_qtdemux_stream_free (qtdemux, stream);
11374 /* we posted an error already */
11375 /* free stbl sub-atoms */
11376 gst_qtdemux_stbl_free (stream);
11378 gst_qtdemux_stream_free (qtdemux, stream);
11383 GST_INFO_OBJECT (qtdemux, "stream with track id %i already exists",
11386 gst_qtdemux_stream_free (qtdemux, stream);
11391 GST_INFO_OBJECT (qtdemux, "unknown subtype %" GST_FOURCC_FORMAT,
11392 GST_FOURCC_ARGS (stream->subtype));
11394 gst_qtdemux_stream_free (qtdemux, stream);
11399 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
11400 (_("This file contains too many streams. Only playing first %d"),
11401 GST_QTDEMUX_MAX_STREAMS), (NULL));
11406 /* If we can estimate the overall bitrate, and don't have information about the
11407 * stream bitrate for exactly one stream, this guesses the stream bitrate as
11408 * the overall bitrate minus the sum of the bitrates of all other streams. This
11409 * should be useful for the common case where we have one audio and one video
11410 * stream and can estimate the bitrate of one, but not the other. */
11412 gst_qtdemux_guess_bitrate (GstQTDemux * qtdemux)
11414 QtDemuxStream *stream = NULL;
11415 gint64 size, sys_bitrate, sum_bitrate = 0;
11416 GstClockTime duration;
11420 if (qtdemux->fragmented)
11423 GST_DEBUG_OBJECT (qtdemux, "Looking for streams with unknown bitrate");
11425 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &size)
11427 GST_DEBUG_OBJECT (qtdemux,
11428 "Size in bytes of the stream not known - bailing");
11432 /* Subtract the header size */
11433 GST_DEBUG_OBJECT (qtdemux, "Total size %" G_GINT64_FORMAT ", header size %u",
11434 size, qtdemux->header_size);
11436 if (size < qtdemux->header_size)
11439 size = size - qtdemux->header_size;
11441 if (!gst_qtdemux_get_duration (qtdemux, &duration)) {
11442 GST_DEBUG_OBJECT (qtdemux, "Stream duration not known - bailing");
11446 for (i = 0; i < qtdemux->n_streams; i++) {
11447 switch (qtdemux->streams[i]->subtype) {
11450 GST_DEBUG_OBJECT (qtdemux, "checking bitrate for %" GST_PTR_FORMAT,
11451 qtdemux->streams[i]->caps);
11452 /* retrieve bitrate, prefer avg then max */
11454 if (qtdemux->streams[i]->pending_tags) {
11455 gst_tag_list_get_uint (qtdemux->streams[i]->pending_tags,
11456 GST_TAG_MAXIMUM_BITRATE, &bitrate);
11457 GST_DEBUG_OBJECT (qtdemux, "max-bitrate: %u", bitrate);
11458 gst_tag_list_get_uint (qtdemux->streams[i]->pending_tags,
11459 GST_TAG_NOMINAL_BITRATE, &bitrate);
11460 GST_DEBUG_OBJECT (qtdemux, "nominal-bitrate: %u", bitrate);
11461 gst_tag_list_get_uint (qtdemux->streams[i]->pending_tags,
11462 GST_TAG_BITRATE, &bitrate);
11463 GST_DEBUG_OBJECT (qtdemux, "bitrate: %u", bitrate);
11466 sum_bitrate += bitrate;
11469 GST_DEBUG_OBJECT (qtdemux,
11470 ">1 stream with unknown bitrate - bailing");
11473 stream = qtdemux->streams[i];
11477 /* For other subtypes, we assume no significant impact on bitrate */
11483 GST_DEBUG_OBJECT (qtdemux, "All stream bitrates are known");
11487 sys_bitrate = gst_util_uint64_scale (size, GST_SECOND * 8, duration);
11489 if (sys_bitrate < sum_bitrate) {
11490 /* This can happen, since sum_bitrate might be derived from maximum
11491 * bitrates and not average bitrates */
11492 GST_DEBUG_OBJECT (qtdemux,
11493 "System bitrate less than sum bitrate - bailing");
11497 bitrate = sys_bitrate - sum_bitrate;
11498 GST_DEBUG_OBJECT (qtdemux, "System bitrate = %" G_GINT64_FORMAT
11499 ", Stream bitrate = %u", sys_bitrate, bitrate);
11501 if (!stream->pending_tags)
11502 stream->pending_tags = gst_tag_list_new_empty ();
11504 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
11505 GST_TAG_BITRATE, bitrate, NULL);
11508 static GstFlowReturn
11509 qtdemux_prepare_streams (GstQTDemux * qtdemux)
11512 GstFlowReturn ret = GST_FLOW_OK;
11514 GST_DEBUG_OBJECT (qtdemux, "prepare streams");
11516 for (i = 0; ret == GST_FLOW_OK && i < qtdemux->n_streams; i++) {
11517 QtDemuxStream *stream = qtdemux->streams[i];
11518 guint32 sample_num = 0;
11520 GST_DEBUG_OBJECT (qtdemux, "stream %d, id %d, fourcc %" GST_FOURCC_FORMAT,
11521 i, stream->track_id, GST_FOURCC_ARGS (stream->fourcc));
11523 if (qtdemux->fragmented) {
11524 /* need all moov samples first */
11525 GST_OBJECT_LOCK (qtdemux);
11526 while (stream->n_samples == 0)
11527 if ((ret = qtdemux_add_fragmented_samples (qtdemux)) != GST_FLOW_OK)
11529 GST_OBJECT_UNLOCK (qtdemux);
11531 /* discard any stray moof */
11532 qtdemux->moof_offset = 0;
11535 /* prepare braking */
11536 if (ret != GST_FLOW_ERROR)
11539 /* in pull mode, we should have parsed some sample info by now;
11540 * and quite some code will not handle no samples.
11541 * in push mode, we'll just have to deal with it */
11542 if (G_UNLIKELY (qtdemux->pullbased && !stream->n_samples)) {
11543 GST_DEBUG_OBJECT (qtdemux, "no samples for stream; discarding");
11544 gst_qtdemux_remove_stream (qtdemux, i);
11549 /* parse the initial sample for use in setting the frame rate cap */
11550 while (sample_num == 0 && sample_num < stream->n_samples) {
11551 if (!qtdemux_parse_samples (qtdemux, stream, sample_num))
11555 if (stream->n_samples > 0 && stream->stbl_index >= 0) {
11556 stream->first_duration = stream->samples[0].duration;
11557 GST_LOG_OBJECT (qtdemux, "stream %d first duration %u",
11558 stream->track_id, stream->first_duration);
11565 static GstFlowReturn
11566 qtdemux_expose_streams (GstQTDemux * qtdemux)
11569 GSList *oldpads = NULL;
11572 GST_DEBUG_OBJECT (qtdemux, "exposing streams");
11574 for (i = 0; i < qtdemux->n_streams; i++) {
11575 QtDemuxStream *stream = qtdemux->streams[i];
11576 GstPad *oldpad = stream->pad;
11579 GST_DEBUG_OBJECT (qtdemux, "stream %d, id %d, fourcc %" GST_FOURCC_FORMAT,
11580 i, stream->track_id, GST_FOURCC_ARGS (stream->fourcc));
11582 if ((stream->subtype == FOURCC_text || stream->subtype == FOURCC_sbtl) &&
11583 stream->track_id == qtdemux->chapters_track_id) {
11584 /* TODO - parse chapters track and expose it as GstToc; For now just ignore it
11585 so that it doesn't look like a subtitle track */
11586 gst_qtdemux_remove_stream (qtdemux, i);
11591 /* now we have all info and can expose */
11592 list = stream->pending_tags;
11593 stream->pending_tags = NULL;
11595 oldpads = g_slist_prepend (oldpads, oldpad);
11596 if (!gst_qtdemux_add_stream (qtdemux, stream, list))
11597 return GST_FLOW_ERROR;
11600 gst_qtdemux_guess_bitrate (qtdemux);
11602 gst_element_no_more_pads (GST_ELEMENT_CAST (qtdemux));
11604 for (iter = oldpads; iter; iter = g_slist_next (iter)) {
11605 GstPad *oldpad = iter->data;
11608 event = gst_event_new_eos ();
11609 if (qtdemux->segment_seqnum)
11610 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
11612 gst_pad_push_event (oldpad, event);
11613 gst_pad_set_active (oldpad, FALSE);
11614 gst_element_remove_pad (GST_ELEMENT (qtdemux), oldpad);
11615 gst_flow_combiner_remove_pad (qtdemux->flowcombiner, oldpad);
11616 gst_object_unref (oldpad);
11619 /* check if we should post a redirect in case there is a single trak
11620 * and it is a redirecting trak */
11621 if (qtdemux->n_streams == 1 && qtdemux->streams[0]->redirect_uri != NULL) {
11624 GST_INFO_OBJECT (qtdemux, "Issuing a redirect due to a single track with "
11625 "an external content");
11626 m = gst_message_new_element (GST_OBJECT_CAST (qtdemux),
11627 gst_structure_new ("redirect",
11628 "new-location", G_TYPE_STRING, qtdemux->streams[0]->redirect_uri,
11630 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), m);
11631 qtdemux->posted_redirect = TRUE;
11634 for (i = 0; i < qtdemux->n_streams; i++) {
11635 QtDemuxStream *stream = qtdemux->streams[i];
11637 qtdemux_do_allocation (qtdemux, stream);
11640 qtdemux->exposed = TRUE;
11641 return GST_FLOW_OK;
11644 /* check if major or compatible brand is 3GP */
11645 static inline gboolean
11646 qtdemux_is_brand_3gp (GstQTDemux * qtdemux, gboolean major)
11649 return ((qtdemux->major_brand & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
11651 } else if (qtdemux->comp_brands != NULL) {
11655 gboolean res = FALSE;
11657 gst_buffer_map (qtdemux->comp_brands, &map, GST_MAP_READ);
11660 while (size >= 4) {
11661 res = res || ((QT_FOURCC (data) & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
11666 gst_buffer_unmap (qtdemux->comp_brands, &map);
11673 /* check if tag is a spec'ed 3GP tag keyword storing a string */
11674 static inline gboolean
11675 qtdemux_is_string_tag_3gp (GstQTDemux * qtdemux, guint32 fourcc)
11677 return fourcc == FOURCC_cprt || fourcc == FOURCC_gnre || fourcc == FOURCC_titl
11678 || fourcc == FOURCC_dscp || fourcc == FOURCC_perf || fourcc == FOURCC_auth
11679 || fourcc == FOURCC_albm;
11683 qtdemux_tag_add_location (GstQTDemux * qtdemux, GstTagList * taglist,
11684 const char *tag, const char *dummy, GNode * node)
11686 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
11690 gdouble longitude, latitude, altitude;
11693 len = QT_UINT32 (node->data);
11700 /* TODO: language code skipped */
11702 name = gst_tag_freeform_string_to_utf8 (data + offset, -1, env_vars);
11705 /* do not alarm in trivial case, but bail out otherwise */
11706 if (*(data + offset) != 0) {
11707 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8, "
11711 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
11712 GST_TAG_GEO_LOCATION_NAME, name, NULL);
11713 offset += strlen (name);
11717 if (len < offset + 2 + 4 + 4 + 4)
11720 /* +1 +1 = skip null-terminator and location role byte */
11722 /* table in spec says unsigned, semantics say negative has meaning ... */
11723 longitude = QT_SFP32 (data + offset);
11726 latitude = QT_SFP32 (data + offset);
11729 altitude = QT_SFP32 (data + offset);
11731 /* one invalid means all are invalid */
11732 if (longitude >= -180.0 && longitude <= 180.0 &&
11733 latitude >= -90.0 && latitude <= 90.0) {
11734 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
11735 GST_TAG_GEO_LOCATION_LATITUDE, latitude,
11736 GST_TAG_GEO_LOCATION_LONGITUDE, longitude,
11737 GST_TAG_GEO_LOCATION_ELEVATION, altitude, NULL);
11740 /* TODO: no GST_TAG_, so astronomical body and additional notes skipped */
11747 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP location");
11754 qtdemux_tag_add_year (GstQTDemux * qtdemux, GstTagList * taglist,
11755 const char *tag, const char *dummy, GNode * node)
11761 len = QT_UINT32 (node->data);
11765 y = QT_UINT16 ((guint8 *) node->data + 12);
11767 GST_DEBUG_OBJECT (qtdemux, "year: %u is not a valid year", y);
11770 GST_DEBUG_OBJECT (qtdemux, "year: %u", y);
11772 date = g_date_new_dmy (1, 1, y);
11773 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, date, NULL);
11774 g_date_free (date);
11778 qtdemux_tag_add_classification (GstQTDemux * qtdemux, GstTagList * taglist,
11779 const char *tag, const char *dummy, GNode * node)
11782 char *tag_str = NULL;
11787 len = QT_UINT32 (node->data);
11792 entity = (guint8 *) node->data + offset;
11793 if (entity[0] == 0 || entity[1] == 0 || entity[2] == 0 || entity[3] == 0) {
11794 GST_DEBUG_OBJECT (qtdemux,
11795 "classification info: %c%c%c%c invalid classification entity",
11796 entity[0], entity[1], entity[2], entity[3]);
11801 table = QT_UINT16 ((guint8 *) node->data + offset);
11803 /* Language code skipped */
11807 /* Tag format: "XXXX://Y[YYYY]/classification info string"
11808 * XXXX: classification entity, fixed length 4 chars.
11809 * Y[YYYY]: classification table, max 5 chars.
11811 tag_str = g_strdup_printf ("----://%u/%s",
11812 table, (char *) node->data + offset);
11814 /* memcpy To be sure we're preserving byte order */
11815 memcpy (tag_str, entity, 4);
11816 GST_DEBUG_OBJECT (qtdemux, "classification info: %s", tag_str);
11818 gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND, tag, tag_str, NULL);
11827 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP classification");
11833 qtdemux_tag_add_str_full (GstQTDemux * qtdemux, GstTagList * taglist,
11834 const char *tag, const char *dummy, GNode * node)
11836 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
11842 gboolean ret = TRUE;
11843 const gchar *charset = NULL;
11845 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
11847 len = QT_UINT32 (data->data);
11848 type = QT_UINT32 ((guint8 *) data->data + 8);
11849 if (type == 0x00000001 && len > 16) {
11850 s = gst_tag_freeform_string_to_utf8 ((char *) data->data + 16, len - 16,
11853 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
11854 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, s, NULL);
11857 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
11861 len = QT_UINT32 (node->data);
11862 type = QT_UINT32 ((guint8 *) node->data + 4);
11863 if ((type >> 24) == 0xa9 && len > 8 + 4) {
11867 /* Type starts with the (C) symbol, so the next data is a list
11868 * of (string size(16), language code(16), string) */
11870 str_len = QT_UINT16 ((guint8 *) node->data + 8);
11871 lang_code = QT_UINT16 ((guint8 *) node->data + 10);
11873 /* the string + fourcc + size + 2 16bit fields,
11874 * means that there are more tags in this atom */
11875 if (len > str_len + 8 + 4) {
11876 /* TODO how to represent the same tag in different languages? */
11877 GST_WARNING_OBJECT (qtdemux, "Ignoring metadata entry with multiple "
11878 "text alternatives, reading only first one");
11882 len = MIN (len, str_len + 8 + 4); /* remove trailing strings that we don't use */
11883 GST_DEBUG_OBJECT (qtdemux, "found international text tag");
11885 if (lang_code < 0x800) { /* MAC encoded string */
11888 } else if (len > 14 && qtdemux_is_string_tag_3gp (qtdemux,
11889 QT_FOURCC ((guint8 *) node->data + 4))) {
11890 guint32 type = QT_UINT32 ((guint8 *) node->data + 8);
11892 /* we go for 3GP style encoding if major brands claims so,
11893 * or if no hope for data be ok UTF-8, and compatible 3GP brand present */
11894 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
11895 (qtdemux_is_brand_3gp (qtdemux, FALSE) &&
11896 ((type & 0x00FFFFFF) == 0x0) && (type >> 24 <= 0xF))) {
11898 /* 16-bit Language code is ignored here as well */
11899 GST_DEBUG_OBJECT (qtdemux, "found 3gpp text tag");
11906 GST_DEBUG_OBJECT (qtdemux, "found normal text tag");
11907 ret = FALSE; /* may have to fallback */
11910 GError *err = NULL;
11912 s = g_convert ((gchar *) node->data + offset, len - offset, "utf8",
11913 charset, NULL, NULL, &err);
11915 GST_DEBUG_OBJECT (qtdemux, "Failed to convert string from charset %s:"
11916 " %s(%d): %s", charset, g_quark_to_string (err->domain), err->code,
11918 g_error_free (err);
11921 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
11922 len - offset, env_vars);
11925 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
11926 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, s, NULL);
11930 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
11937 qtdemux_tag_add_str (GstQTDemux * qtdemux, GstTagList * taglist,
11938 const char *tag, const char *dummy, GNode * node)
11940 qtdemux_tag_add_str_full (qtdemux, taglist, tag, dummy, node);
11944 qtdemux_tag_add_keywords (GstQTDemux * qtdemux, GstTagList * taglist,
11945 const char *tag, const char *dummy, GNode * node)
11947 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
11949 char *s, *t, *k = NULL;
11954 /* first try normal string tag if major brand not 3GP */
11955 if (!qtdemux_is_brand_3gp (qtdemux, TRUE)) {
11956 if (!qtdemux_tag_add_str_full (qtdemux, taglist, tag, dummy, node)) {
11957 /* hm, that did not work, maybe 3gpp storage in non-3gpp major brand;
11958 * let's try it 3gpp way after minor safety check */
11960 if (QT_UINT32 (data) < 15 || !qtdemux_is_brand_3gp (qtdemux, FALSE))
11966 GST_DEBUG_OBJECT (qtdemux, "found 3gpp keyword tag");
11970 len = QT_UINT32 (data);
11974 count = QT_UINT8 (data + 14);
11976 for (; count; count--) {
11979 if (offset + 1 > len)
11981 slen = QT_UINT8 (data + offset);
11983 if (offset + slen > len)
11985 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
11988 GST_DEBUG_OBJECT (qtdemux, "adding keyword %s", GST_STR_NULL (s));
11990 t = g_strjoin (",", k, s, NULL);
11998 GST_DEBUG_OBJECT (qtdemux, "failed to convert keyword to UTF-8");
12005 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (k));
12006 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, k, NULL);
12015 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP keywords");
12021 qtdemux_tag_add_num (GstQTDemux * qtdemux, GstTagList * taglist,
12022 const char *tag1, const char *tag2, GNode * node)
12029 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12031 len = QT_UINT32 (data->data);
12032 type = QT_UINT32 ((guint8 *) data->data + 8);
12033 if (type == 0x00000000 && len >= 22) {
12034 n1 = QT_UINT16 ((guint8 *) data->data + 18);
12035 n2 = QT_UINT16 ((guint8 *) data->data + 20);
12037 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag1, n1);
12038 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, n1, NULL);
12041 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag2, n2);
12042 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag2, n2, NULL);
12049 qtdemux_tag_add_tmpo (GstQTDemux * qtdemux, GstTagList * taglist,
12050 const char *tag1, const char *dummy, GNode * node)
12057 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12059 len = QT_UINT32 (data->data);
12060 type = QT_UINT32 ((guint8 *) data->data + 8);
12061 GST_DEBUG_OBJECT (qtdemux, "have tempo tag, type=%d,len=%d", type, len);
12062 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
12063 if ((type == 0x00000015 || type == 0x0000000f) && len >= 18) {
12064 n1 = QT_UINT16 ((guint8 *) data->data + 16);
12066 /* do not add bpm=0 */
12067 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", n1);
12068 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, (gdouble) n1,
12076 qtdemux_tag_add_uint32 (GstQTDemux * qtdemux, GstTagList * taglist,
12077 const char *tag1, const char *dummy, GNode * node)
12084 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12086 len = QT_UINT32 (data->data);
12087 type = QT_UINT32 ((guint8 *) data->data + 8);
12088 GST_DEBUG_OBJECT (qtdemux, "have %s tag, type=%d,len=%d", tag1, type, len);
12089 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
12090 if ((type == 0x00000015 || type == 0x0000000f) && len >= 20) {
12091 num = QT_UINT32 ((guint8 *) data->data + 16);
12093 /* do not add num=0 */
12094 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", num);
12095 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, num, NULL);
12102 qtdemux_tag_add_covr (GstQTDemux * qtdemux, GstTagList * taglist,
12103 const char *tag1, const char *dummy, GNode * node)
12110 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12112 len = QT_UINT32 (data->data);
12113 type = QT_UINT32 ((guint8 *) data->data + 8);
12114 GST_DEBUG_OBJECT (qtdemux, "have covr tag, type=%d,len=%d", type, len);
12115 if ((type == 0x0000000d || type == 0x0000000e) && len > 16) {
12116 GstTagImageType image_type;
12118 if (gst_tag_list_get_tag_size (taglist, GST_TAG_IMAGE) == 0)
12119 image_type = GST_TAG_IMAGE_TYPE_FRONT_COVER;
12121 image_type = GST_TAG_IMAGE_TYPE_NONE;
12124 gst_tag_image_data_to_image_sample ((guint8 *) data->data + 16,
12125 len - 16, image_type))) {
12126 GST_DEBUG_OBJECT (qtdemux, "adding tag size %d", len - 16);
12127 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, sample, NULL);
12128 gst_sample_unref (sample);
12135 qtdemux_tag_add_date (GstQTDemux * qtdemux, GstTagList * taglist,
12136 const char *tag, const char *dummy, GNode * node)
12143 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12145 len = QT_UINT32 (data->data);
12146 type = QT_UINT32 ((guint8 *) data->data + 8);
12147 if (type == 0x00000001 && len > 16) {
12148 guint y, m = 1, d = 1;
12151 s = g_strndup ((char *) data->data + 16, len - 16);
12152 GST_DEBUG_OBJECT (qtdemux, "adding date '%s'", s);
12153 ret = sscanf (s, "%u-%u-%u", &y, &m, &d);
12154 if (ret >= 1 && y > 1500 && y < 3000) {
12157 date = g_date_new_dmy (d, m, y);
12158 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, date, NULL);
12159 g_date_free (date);
12161 GST_DEBUG_OBJECT (qtdemux, "could not parse date string '%s'", s);
12169 qtdemux_tag_add_gnre (GstQTDemux * qtdemux, GstTagList * taglist,
12170 const char *tag, const char *dummy, GNode * node)
12174 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12176 /* re-route to normal string tag if major brand says so
12177 * or no data atom and compatible brand suggests so */
12178 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
12179 (qtdemux_is_brand_3gp (qtdemux, FALSE) && !data)) {
12180 qtdemux_tag_add_str (qtdemux, taglist, tag, dummy, node);
12185 guint len, type, n;
12187 len = QT_UINT32 (data->data);
12188 type = QT_UINT32 ((guint8 *) data->data + 8);
12189 if (type == 0x00000000 && len >= 18) {
12190 n = QT_UINT16 ((guint8 *) data->data + 16);
12192 const gchar *genre;
12194 genre = gst_tag_id3_genre_get (n - 1);
12195 if (genre != NULL) {
12196 GST_DEBUG_OBJECT (qtdemux, "adding %d [%s]", n, genre);
12197 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, genre, NULL);
12205 qtdemux_add_double_tag_from_str (GstQTDemux * demux, GstTagList * taglist,
12206 const gchar * tag, guint8 * data, guint32 datasize)
12211 /* make a copy to have \0 at the end */
12212 datacopy = g_strndup ((gchar *) data, datasize);
12214 /* convert the str to double */
12215 if (sscanf (datacopy, "%lf", &value) == 1) {
12216 GST_DEBUG_OBJECT (demux, "adding tag: %s [%s]", tag, datacopy);
12217 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, value, NULL);
12219 GST_WARNING_OBJECT (demux, "Failed to parse double from string: %s",
12227 qtdemux_tag_add_revdns (GstQTDemux * demux, GstTagList * taglist,
12228 const char *tag, const char *tag_bis, GNode * node)
12237 const gchar *meanstr;
12238 const gchar *namestr;
12240 /* checking the whole ---- atom size for consistency */
12241 if (QT_UINT32 (node->data) <= 4 + 12 + 12 + 16) {
12242 GST_WARNING_OBJECT (demux, "Tag ---- atom is too small, ignoring");
12246 mean = qtdemux_tree_get_child_by_type (node, FOURCC_mean);
12248 GST_WARNING_OBJECT (demux, "No 'mean' atom found");
12252 meansize = QT_UINT32 (mean->data);
12253 if (meansize <= 12) {
12254 GST_WARNING_OBJECT (demux, "Small mean atom, ignoring the whole tag");
12257 meanstr = ((gchar *) mean->data) + 12;
12260 name = qtdemux_tree_get_child_by_type (node, FOURCC_name);
12262 GST_WARNING_OBJECT (demux, "'name' atom not found, ignoring tag");
12266 namesize = QT_UINT32 (name->data);
12267 if (namesize <= 12) {
12268 GST_WARNING_OBJECT (demux, "'name' atom is too small, ignoring tag");
12271 namestr = ((gchar *) name->data) + 12;
12279 * uint24 - data type
12283 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12285 GST_WARNING_OBJECT (demux, "No data atom in this tag");
12288 datasize = QT_UINT32 (data->data);
12289 if (datasize <= 16) {
12290 GST_WARNING_OBJECT (demux, "Data atom too small");
12293 datatype = QT_UINT32 (((gchar *) data->data) + 8) & 0xFFFFFF;
12295 if ((strncmp (meanstr, "com.apple.iTunes", meansize) == 0) ||
12296 (strncmp (meanstr, "org.hydrogenaudio.replaygain", meansize) == 0)) {
12297 static const struct
12299 const gchar name[28];
12300 const gchar tag[28];
12303 "replaygain_track_gain", GST_TAG_TRACK_GAIN}, {
12304 "replaygain_track_peak", GST_TAG_TRACK_PEAK}, {
12305 "replaygain_album_gain", GST_TAG_ALBUM_GAIN}, {
12306 "replaygain_album_peak", GST_TAG_ALBUM_PEAK}, {
12307 "MusicBrainz Track Id", GST_TAG_MUSICBRAINZ_TRACKID}, {
12308 "MusicBrainz Artist Id", GST_TAG_MUSICBRAINZ_ARTISTID}, {
12309 "MusicBrainz Album Id", GST_TAG_MUSICBRAINZ_ALBUMID}, {
12310 "MusicBrainz Album Artist Id", GST_TAG_MUSICBRAINZ_ALBUMARTISTID}
12314 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
12315 if (!g_ascii_strncasecmp (tags[i].name, namestr, namesize)) {
12316 switch (gst_tag_get_type (tags[i].tag)) {
12317 case G_TYPE_DOUBLE:
12318 qtdemux_add_double_tag_from_str (demux, taglist, tags[i].tag,
12319 ((guint8 *) data->data) + 16, datasize - 16);
12321 case G_TYPE_STRING:
12322 qtdemux_tag_add_str (demux, taglist, tags[i].tag, NULL, node);
12331 if (i == G_N_ELEMENTS (tags))
12341 #ifndef GST_DISABLE_GST_DEBUG
12343 gchar *namestr_dbg;
12344 gchar *meanstr_dbg;
12346 meanstr_dbg = g_strndup (meanstr, meansize);
12347 namestr_dbg = g_strndup (namestr, namesize);
12349 GST_WARNING_OBJECT (demux, "This tag %s:%s type:%u is not mapped, "
12350 "file a bug at bugzilla.gnome.org", meanstr_dbg, namestr_dbg, datatype);
12352 g_free (namestr_dbg);
12353 g_free (meanstr_dbg);
12360 qtdemux_tag_add_id32 (GstQTDemux * demux, GstTagList * taglist, const char *tag,
12361 const char *tag_bis, GNode * node)
12366 GstTagList *id32_taglist = NULL;
12368 GST_LOG_OBJECT (demux, "parsing ID32");
12371 len = GST_READ_UINT32_BE (data);
12373 /* need at least full box and language tag */
12377 buf = gst_buffer_new_allocate (NULL, len - 14, NULL);
12378 gst_buffer_fill (buf, 0, data + 14, len - 14);
12380 id32_taglist = gst_tag_list_from_id3v2_tag (buf);
12381 if (id32_taglist) {
12382 GST_LOG_OBJECT (demux, "parsing ok");
12383 gst_tag_list_insert (taglist, id32_taglist, GST_TAG_MERGE_KEEP);
12384 gst_tag_list_unref (id32_taglist);
12386 GST_LOG_OBJECT (demux, "parsing failed");
12389 gst_buffer_unref (buf);
12392 typedef void (*GstQTDemuxAddTagFunc) (GstQTDemux * demux, GstTagList * taglist,
12393 const char *tag, const char *tag_bis, GNode * node);
12396 FOURCC_pcst -> if media is a podcast -> bool
12397 FOURCC_cpil -> if media is part of a compilation -> bool
12398 FOURCC_pgap -> if media is part of a gapless context -> bool
12399 FOURCC_tven -> the tv episode id e.g. S01E23 -> str
12402 static const struct
12405 const gchar *gst_tag;
12406 const gchar *gst_tag_bis;
12407 const GstQTDemuxAddTagFunc func;
12410 FOURCC__nam, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
12411 FOURCC_titl, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
12412 FOURCC__grp, GST_TAG_GROUPING, NULL, qtdemux_tag_add_str}, {
12413 FOURCC__wrt, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
12414 FOURCC__ART, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
12415 FOURCC_aART, GST_TAG_ALBUM_ARTIST, NULL, qtdemux_tag_add_str}, {
12416 FOURCC_perf, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
12417 FOURCC_auth, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
12418 FOURCC__alb, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
12419 FOURCC_albm, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
12420 FOURCC_cprt, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
12421 FOURCC__cpy, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
12422 FOURCC__cmt, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
12423 FOURCC__des, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
12424 FOURCC_desc, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
12425 FOURCC_dscp, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
12426 FOURCC__lyr, GST_TAG_LYRICS, NULL, qtdemux_tag_add_str}, {
12427 FOURCC__day, GST_TAG_DATE, NULL, qtdemux_tag_add_date}, {
12428 FOURCC_yrrc, GST_TAG_DATE, NULL, qtdemux_tag_add_year}, {
12429 FOURCC__too, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
12430 FOURCC__inf, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
12431 FOURCC_trkn, GST_TAG_TRACK_NUMBER, GST_TAG_TRACK_COUNT, qtdemux_tag_add_num}, {
12432 FOURCC_disk, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
12433 qtdemux_tag_add_num}, {
12434 FOURCC_disc, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
12435 qtdemux_tag_add_num}, {
12436 FOURCC__gen, GST_TAG_GENRE, NULL, qtdemux_tag_add_str}, {
12437 FOURCC_gnre, GST_TAG_GENRE, NULL, qtdemux_tag_add_gnre}, {
12438 FOURCC_tmpo, GST_TAG_BEATS_PER_MINUTE, NULL, qtdemux_tag_add_tmpo}, {
12439 FOURCC_covr, GST_TAG_IMAGE, NULL, qtdemux_tag_add_covr}, {
12440 FOURCC_sonm, GST_TAG_TITLE_SORTNAME, NULL, qtdemux_tag_add_str}, {
12441 FOURCC_soal, GST_TAG_ALBUM_SORTNAME, NULL, qtdemux_tag_add_str}, {
12442 FOURCC_soar, GST_TAG_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
12443 FOURCC_soaa, GST_TAG_ALBUM_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
12444 FOURCC_soco, GST_TAG_COMPOSER_SORTNAME, NULL, qtdemux_tag_add_str}, {
12445 FOURCC_sosn, GST_TAG_SHOW_SORTNAME, NULL, qtdemux_tag_add_str}, {
12446 FOURCC_tvsh, GST_TAG_SHOW_NAME, NULL, qtdemux_tag_add_str}, {
12447 FOURCC_tvsn, GST_TAG_SHOW_SEASON_NUMBER, NULL, qtdemux_tag_add_uint32}, {
12448 FOURCC_tves, GST_TAG_SHOW_EPISODE_NUMBER, NULL, qtdemux_tag_add_uint32}, {
12449 FOURCC_kywd, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_keywords}, {
12450 FOURCC_keyw, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_str}, {
12451 FOURCC__enc, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
12452 FOURCC_loci, GST_TAG_GEO_LOCATION_NAME, NULL, qtdemux_tag_add_location}, {
12453 FOURCC_clsf, GST_QT_DEMUX_CLASSIFICATION_TAG, NULL,
12454 qtdemux_tag_add_classification}, {
12455 FOURCC__mak, GST_TAG_DEVICE_MANUFACTURER, NULL, qtdemux_tag_add_str}, {
12456 FOURCC__mod, GST_TAG_DEVICE_MODEL, NULL, qtdemux_tag_add_str}, {
12457 FOURCC__swr, GST_TAG_APPLICATION_NAME, NULL, qtdemux_tag_add_str}, {
12459 /* This is a special case, some tags are stored in this
12460 * 'reverse dns naming', according to:
12461 * http://atomicparsley.sourceforge.net/mpeg-4files.html and
12464 FOURCC_____, "", NULL, qtdemux_tag_add_revdns}, {
12465 /* see http://www.mp4ra.org/specs.html for ID32 in meta box */
12466 FOURCC_ID32, "", NULL, qtdemux_tag_add_id32}
12469 struct _GstQtDemuxTagList
12472 GstTagList *taglist;
12474 typedef struct _GstQtDemuxTagList GstQtDemuxTagList;
12477 qtdemux_tag_add_blob (GNode * node, GstQtDemuxTagList * qtdemuxtaglist)
12483 const gchar *style;
12488 GstQTDemux *demux = qtdemuxtaglist->demux;
12489 GstTagList *taglist = qtdemuxtaglist->taglist;
12492 len = QT_UINT32 (data);
12493 buf = gst_buffer_new_and_alloc (len);
12494 gst_buffer_fill (buf, 0, data, len);
12496 /* heuristic to determine style of tag */
12497 if (QT_FOURCC (data + 4) == FOURCC_____ ||
12498 (len > 8 + 12 && QT_FOURCC (data + 12) == FOURCC_data))
12500 else if (demux->major_brand == FOURCC_qt__)
12501 style = "quicktime";
12502 /* fall back to assuming iso/3gp tag style */
12506 /* santize the name for the caps. */
12507 for (i = 0; i < 4; i++) {
12508 guint8 d = data[4 + i];
12509 if (g_ascii_isalnum (d))
12510 ndata[i] = g_ascii_tolower (d);
12515 media_type = g_strdup_printf ("application/x-gst-qt-%c%c%c%c-tag",
12516 ndata[0], ndata[1], ndata[2], ndata[3]);
12517 GST_DEBUG_OBJECT (demux, "media type %s", media_type);
12519 s = gst_structure_new (media_type, "style", G_TYPE_STRING, style, NULL);
12520 sample = gst_sample_new (buf, NULL, NULL, s);
12521 gst_buffer_unref (buf);
12522 g_free (media_type);
12524 GST_DEBUG_OBJECT (demux, "adding private tag; size %d, info %" GST_PTR_FORMAT,
12527 gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND,
12528 GST_QT_DEMUX_PRIVATE_TAG, sample, NULL);
12530 gst_sample_unref (sample);
12534 qtdemux_parse_udta (GstQTDemux * qtdemux, GstTagList * taglist, GNode * udta)
12541 GstQtDemuxTagList demuxtaglist;
12543 demuxtaglist.demux = qtdemux;
12544 demuxtaglist.taglist = taglist;
12546 meta = qtdemux_tree_get_child_by_type (udta, FOURCC_meta);
12547 if (meta != NULL) {
12548 ilst = qtdemux_tree_get_child_by_type (meta, FOURCC_ilst);
12549 if (ilst == NULL) {
12550 GST_LOG_OBJECT (qtdemux, "no ilst");
12555 GST_LOG_OBJECT (qtdemux, "no meta so using udta itself");
12559 while (i < G_N_ELEMENTS (add_funcs)) {
12560 node = qtdemux_tree_get_child_by_type (ilst, add_funcs[i].fourcc);
12564 len = QT_UINT32 (node->data);
12566 GST_DEBUG_OBJECT (qtdemux, "too small tag atom %" GST_FOURCC_FORMAT,
12567 GST_FOURCC_ARGS (add_funcs[i].fourcc));
12569 add_funcs[i].func (qtdemux, taglist, add_funcs[i].gst_tag,
12570 add_funcs[i].gst_tag_bis, node);
12572 g_node_destroy (node);
12578 /* parsed nodes have been removed, pass along remainder as blob */
12579 g_node_children_foreach (ilst, G_TRAVERSE_ALL,
12580 (GNodeForeachFunc) qtdemux_tag_add_blob, &demuxtaglist);
12582 /* parse up XMP_ node if existing */
12583 xmp_ = qtdemux_tree_get_child_by_type (udta, FOURCC_XMP_);
12584 if (xmp_ != NULL) {
12586 GstTagList *xmptaglist;
12588 buf = _gst_buffer_new_wrapped (((guint8 *) xmp_->data) + 8,
12589 QT_UINT32 ((guint8 *) xmp_->data) - 8, NULL);
12590 xmptaglist = gst_tag_list_from_xmp_buffer (buf);
12591 gst_buffer_unref (buf);
12593 qtdemux_handle_xmp_taglist (qtdemux, taglist, xmptaglist);
12595 GST_DEBUG_OBJECT (qtdemux, "No XMP_ node found");
12601 GstStructure *structure; /* helper for sort function */
12603 guint min_req_bitrate;
12604 guint min_req_qt_version;
12608 qtdemux_redirects_sort_func (gconstpointer a, gconstpointer b)
12610 GstQtReference *ref_a = (GstQtReference *) a;
12611 GstQtReference *ref_b = (GstQtReference *) b;
12613 if (ref_b->min_req_qt_version != ref_a->min_req_qt_version)
12614 return ref_b->min_req_qt_version - ref_a->min_req_qt_version;
12616 /* known bitrates go before unknown; higher bitrates go first */
12617 return ref_b->min_req_bitrate - ref_a->min_req_bitrate;
12620 /* sort the redirects and post a message for the application.
12623 qtdemux_process_redirects (GstQTDemux * qtdemux, GList * references)
12625 GstQtReference *best;
12628 GValue list_val = { 0, };
12631 g_assert (references != NULL);
12633 references = g_list_sort (references, qtdemux_redirects_sort_func);
12635 best = (GstQtReference *) references->data;
12637 g_value_init (&list_val, GST_TYPE_LIST);
12639 for (l = references; l != NULL; l = l->next) {
12640 GstQtReference *ref = (GstQtReference *) l->data;
12641 GValue struct_val = { 0, };
12643 ref->structure = gst_structure_new ("redirect",
12644 "new-location", G_TYPE_STRING, ref->location, NULL);
12646 if (ref->min_req_bitrate > 0) {
12647 gst_structure_set (ref->structure, "minimum-bitrate", G_TYPE_INT,
12648 ref->min_req_bitrate, NULL);
12651 g_value_init (&struct_val, GST_TYPE_STRUCTURE);
12652 g_value_set_boxed (&struct_val, ref->structure);
12653 gst_value_list_append_value (&list_val, &struct_val);
12654 g_value_unset (&struct_val);
12655 /* don't free anything here yet, since we need best->structure below */
12658 g_assert (best != NULL);
12659 s = gst_structure_copy (best->structure);
12661 if (g_list_length (references) > 1) {
12662 gst_structure_set_value (s, "locations", &list_val);
12665 g_value_unset (&list_val);
12667 for (l = references; l != NULL; l = l->next) {
12668 GstQtReference *ref = (GstQtReference *) l->data;
12670 gst_structure_free (ref->structure);
12671 g_free (ref->location);
12674 g_list_free (references);
12676 GST_INFO_OBJECT (qtdemux, "posting redirect message: %" GST_PTR_FORMAT, s);
12677 msg = gst_message_new_element (GST_OBJECT_CAST (qtdemux), s);
12678 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
12679 qtdemux->posted_redirect = TRUE;
12682 /* look for redirect nodes, collect all redirect information and
12686 qtdemux_parse_redirects (GstQTDemux * qtdemux)
12688 GNode *rmra, *rmda, *rdrf;
12690 rmra = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_rmra);
12692 GList *redirects = NULL;
12694 rmda = qtdemux_tree_get_child_by_type (rmra, FOURCC_rmda);
12696 GstQtReference ref = { NULL, NULL, 0, 0 };
12697 GNode *rmdr, *rmvc;
12699 if ((rmdr = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmdr))) {
12700 ref.min_req_bitrate = QT_UINT32 ((guint8 *) rmdr->data + 12);
12701 GST_LOG_OBJECT (qtdemux, "data rate atom, required bitrate = %u",
12702 ref.min_req_bitrate);
12705 if ((rmvc = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmvc))) {
12706 guint32 package = QT_FOURCC ((guint8 *) rmvc->data + 12);
12707 guint version = QT_UINT32 ((guint8 *) rmvc->data + 16);
12709 #ifndef GST_DISABLE_GST_DEBUG
12710 guint bitmask = QT_UINT32 ((guint8 *) rmvc->data + 20);
12712 guint check_type = QT_UINT16 ((guint8 *) rmvc->data + 24);
12714 GST_LOG_OBJECT (qtdemux,
12715 "version check atom [%" GST_FOURCC_FORMAT "], version=0x%08x"
12716 ", mask=%08x, check_type=%u", GST_FOURCC_ARGS (package), version,
12717 bitmask, check_type);
12718 if (package == FOURCC_qtim && check_type == 0) {
12719 ref.min_req_qt_version = version;
12723 rdrf = qtdemux_tree_get_child_by_type (rmda, FOURCC_rdrf);
12729 ref_len = QT_UINT32 ((guint8 *) rdrf->data);
12730 if (ref_len > 20) {
12731 ref_type = QT_FOURCC ((guint8 *) rdrf->data + 12);
12732 ref_data = (guint8 *) rdrf->data + 20;
12733 if (ref_type == FOURCC_alis) {
12734 guint record_len, record_version, fn_len;
12736 if (ref_len > 70) {
12737 /* MacOSX alias record, google for alias-layout.txt */
12738 record_len = QT_UINT16 (ref_data + 4);
12739 record_version = QT_UINT16 (ref_data + 4 + 2);
12740 fn_len = QT_UINT8 (ref_data + 50);
12741 if (record_len > 50 && record_version == 2 && fn_len > 0) {
12742 ref.location = g_strndup ((gchar *) ref_data + 51, fn_len);
12745 GST_WARNING_OBJECT (qtdemux, "Invalid rdrf/alis size (%u < 70)",
12748 } else if (ref_type == FOURCC_url_) {
12749 ref.location = g_strndup ((gchar *) ref_data, ref_len - 8);
12751 GST_DEBUG_OBJECT (qtdemux,
12752 "unknown rdrf reference type %" GST_FOURCC_FORMAT,
12753 GST_FOURCC_ARGS (ref_type));
12755 if (ref.location != NULL) {
12756 GST_INFO_OBJECT (qtdemux, "New location: %s", ref.location);
12758 g_list_prepend (redirects, g_memdup (&ref, sizeof (ref)));
12760 GST_WARNING_OBJECT (qtdemux,
12761 "Failed to extract redirect location from rdrf atom");
12764 GST_WARNING_OBJECT (qtdemux, "Invalid rdrf size (%u < 20)", ref_len);
12768 /* look for others */
12769 rmda = qtdemux_tree_get_sibling_by_type (rmda, FOURCC_rmda);
12772 if (redirects != NULL) {
12773 qtdemux_process_redirects (qtdemux, redirects);
12779 static GstTagList *
12780 qtdemux_add_container_format (GstQTDemux * qtdemux, GstTagList * tags)
12784 if (tags == NULL) {
12785 tags = gst_tag_list_new_empty ();
12786 gst_tag_list_set_scope (tags, GST_TAG_SCOPE_GLOBAL);
12789 if (qtdemux->major_brand == FOURCC_mjp2)
12790 fmt = "Motion JPEG 2000";
12791 else if ((qtdemux->major_brand & 0xffff) == FOURCC_3g__)
12793 else if (qtdemux->major_brand == FOURCC_qt__)
12795 else if (qtdemux->fragmented)
12798 fmt = "ISO MP4/M4A";
12800 GST_LOG_OBJECT (qtdemux, "mapped %" GST_FOURCC_FORMAT " to '%s'",
12801 GST_FOURCC_ARGS (qtdemux->major_brand), fmt);
12803 gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_CONTAINER_FORMAT,
12809 /* we have read the complete moov node now.
12810 * This function parses all of the relevant info, creates the traks and
12811 * prepares all data structures for playback
12814 qtdemux_parse_tree (GstQTDemux * qtdemux)
12820 GstClockTime duration;
12822 guint64 creation_time;
12823 GstDateTime *datetime = NULL;
12826 /* make sure we have a usable taglist */
12827 if (!qtdemux->tag_list) {
12828 qtdemux->tag_list = gst_tag_list_new_empty ();
12829 gst_tag_list_set_scope (qtdemux->tag_list, GST_TAG_SCOPE_GLOBAL);
12831 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
12834 mvhd = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvhd);
12835 if (mvhd == NULL) {
12836 GST_LOG_OBJECT (qtdemux, "No mvhd node found, looking for redirects.");
12837 return qtdemux_parse_redirects (qtdemux);
12840 version = QT_UINT8 ((guint8 *) mvhd->data + 8);
12841 if (version == 1) {
12842 creation_time = QT_UINT64 ((guint8 *) mvhd->data + 12);
12843 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 28);
12844 qtdemux->duration = QT_UINT64 ((guint8 *) mvhd->data + 32);
12845 } else if (version == 0) {
12846 creation_time = QT_UINT32 ((guint8 *) mvhd->data + 12);
12847 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 20);
12848 qtdemux->duration = QT_UINT32 ((guint8 *) mvhd->data + 24);
12850 GST_WARNING_OBJECT (qtdemux, "Unhandled mvhd version %d", version);
12854 /* Moving qt creation time (secs since 1904) to unix time */
12855 if (creation_time != 0) {
12856 /* Try to use epoch first as it should be faster and more commonly found */
12857 if (creation_time >= QTDEMUX_SECONDS_FROM_1904_TO_1970) {
12860 creation_time -= QTDEMUX_SECONDS_FROM_1904_TO_1970;
12861 /* some data cleansing sanity */
12862 g_get_current_time (&now);
12863 if (now.tv_sec + 24 * 3600 < creation_time) {
12864 GST_DEBUG_OBJECT (qtdemux, "discarding bogus future creation time");
12866 datetime = gst_date_time_new_from_unix_epoch_utc (creation_time);
12869 GDateTime *base_dt = g_date_time_new_utc (1904, 1, 1, 0, 0, 0);
12870 GDateTime *dt, *dt_local;
12872 dt = g_date_time_add_seconds (base_dt, creation_time);
12873 dt_local = g_date_time_to_local (dt);
12874 datetime = gst_date_time_new_from_g_date_time (dt_local);
12876 g_date_time_unref (base_dt);
12877 g_date_time_unref (dt);
12881 /* Use KEEP as explicit tags should have a higher priority than mvhd tag */
12882 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_KEEP, GST_TAG_DATE_TIME,
12884 gst_date_time_unref (datetime);
12887 GST_INFO_OBJECT (qtdemux, "timescale: %u", qtdemux->timescale);
12888 GST_INFO_OBJECT (qtdemux, "duration: %" G_GUINT64_FORMAT, qtdemux->duration);
12890 /* check for fragmented file and get some (default) data */
12891 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
12894 GstByteReader mehd_data;
12896 /* let track parsing or anyone know weird stuff might happen ... */
12897 qtdemux->fragmented = TRUE;
12899 /* compensate for total duration */
12900 mehd = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_mehd, &mehd_data);
12902 qtdemux_parse_mehd (qtdemux, &mehd_data);
12905 /* set duration in the segment info */
12906 gst_qtdemux_get_duration (qtdemux, &duration);
12908 qtdemux->segment.duration = duration;
12909 /* also do not exceed duration; stop is set that way post seek anyway,
12910 * and segment activation falls back to duration,
12911 * whereas loop only checks stop, so let's align this here as well */
12912 qtdemux->segment.stop = duration;
12915 /* parse all traks */
12916 trak = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_trak);
12918 qtdemux_parse_trak (qtdemux, trak);
12919 /* iterate all siblings */
12920 trak = qtdemux_tree_get_sibling_by_type (trak, FOURCC_trak);
12923 if (!qtdemux->tag_list) {
12924 GST_DEBUG_OBJECT (qtdemux, "new tag list");
12925 qtdemux->tag_list = gst_tag_list_new_empty ();
12926 gst_tag_list_set_scope (qtdemux->tag_list, GST_TAG_SCOPE_GLOBAL);
12928 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
12932 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_udta);
12934 qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
12936 GST_LOG_OBJECT (qtdemux, "No udta node found.");
12939 /* maybe also some tags in meta box */
12940 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_meta);
12942 GST_DEBUG_OBJECT (qtdemux, "Parsing meta box for tags.");
12943 qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
12945 GST_LOG_OBJECT (qtdemux, "No meta node found.");
12948 /* parse any protection system info */
12949 pssh = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_pssh);
12951 GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
12952 qtdemux_parse_pssh (qtdemux, pssh);
12953 pssh = qtdemux_tree_get_sibling_by_type (pssh, FOURCC_pssh);
12956 qtdemux->tag_list = qtdemux_add_container_format (qtdemux, qtdemux->tag_list);
12961 /* taken from ffmpeg */
12963 read_descr_size (guint8 * ptr, guint8 * end, guint8 ** end_out)
12975 len = (len << 7) | (c & 0x7f);
12983 /* this can change the codec originally present in @list */
12985 gst_qtdemux_handle_esds (GstQTDemux * qtdemux, QtDemuxStream * stream,
12986 GNode * esds, GstTagList * list)
12988 int len = QT_UINT32 (esds->data);
12989 guint8 *ptr = esds->data;
12990 guint8 *end = ptr + len;
12992 guint8 *data_ptr = NULL;
12994 guint8 object_type_id = 0;
12995 const char *codec_name = NULL;
12996 GstCaps *caps = NULL;
12998 GST_MEMDUMP_OBJECT (qtdemux, "esds", ptr, len);
13000 GST_DEBUG_OBJECT (qtdemux, "version/flags = %08x", QT_UINT32 (ptr));
13002 while (ptr + 1 < end) {
13003 tag = QT_UINT8 (ptr);
13004 GST_DEBUG_OBJECT (qtdemux, "tag = %02x", tag);
13006 len = read_descr_size (ptr, end, &ptr);
13007 GST_DEBUG_OBJECT (qtdemux, "len = %d", len);
13009 /* Check the stated amount of data is available for reading */
13010 if (len < 0 || ptr + len > end)
13014 case ES_DESCRIPTOR_TAG:
13015 GST_DEBUG_OBJECT (qtdemux, "ID %04x", QT_UINT16 (ptr));
13016 GST_DEBUG_OBJECT (qtdemux, "priority %04x", QT_UINT8 (ptr + 2));
13019 case DECODER_CONFIG_DESC_TAG:{
13020 guint max_bitrate, avg_bitrate;
13022 object_type_id = QT_UINT8 (ptr);
13023 max_bitrate = QT_UINT32 (ptr + 5);
13024 avg_bitrate = QT_UINT32 (ptr + 9);
13025 GST_DEBUG_OBJECT (qtdemux, "object_type_id %02x", object_type_id);
13026 GST_DEBUG_OBJECT (qtdemux, "stream_type %02x", QT_UINT8 (ptr + 1));
13027 GST_DEBUG_OBJECT (qtdemux, "buffer_size_db %02x", QT_UINT24 (ptr + 2));
13028 GST_DEBUG_OBJECT (qtdemux, "max bitrate %u", max_bitrate);
13029 GST_DEBUG_OBJECT (qtdemux, "avg bitrate %u", avg_bitrate);
13030 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
13031 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
13032 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
13034 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
13035 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
13036 avg_bitrate, NULL);
13041 case DECODER_SPECIFIC_INFO_TAG:
13042 GST_MEMDUMP_OBJECT (qtdemux, "data", ptr, len);
13043 if (object_type_id == 0xe0 && len == 0x40) {
13049 GST_DEBUG_OBJECT (qtdemux,
13050 "Have VOBSUB palette. Creating palette event");
13051 /* move to decConfigDescr data and read palette */
13053 for (i = 0; i < 16; i++) {
13054 clut[i] = QT_UINT32 (data);
13058 s = gst_structure_new ("application/x-gst-dvd", "event",
13059 G_TYPE_STRING, "dvd-spu-clut-change",
13060 "clut00", G_TYPE_INT, clut[0], "clut01", G_TYPE_INT, clut[1],
13061 "clut02", G_TYPE_INT, clut[2], "clut03", G_TYPE_INT, clut[3],
13062 "clut04", G_TYPE_INT, clut[4], "clut05", G_TYPE_INT, clut[5],
13063 "clut06", G_TYPE_INT, clut[6], "clut07", G_TYPE_INT, clut[7],
13064 "clut08", G_TYPE_INT, clut[8], "clut09", G_TYPE_INT, clut[9],
13065 "clut10", G_TYPE_INT, clut[10], "clut11", G_TYPE_INT, clut[11],
13066 "clut12", G_TYPE_INT, clut[12], "clut13", G_TYPE_INT, clut[13],
13067 "clut14", G_TYPE_INT, clut[14], "clut15", G_TYPE_INT, clut[15],
13070 /* store event and trigger custom processing */
13071 stream->pending_event =
13072 gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s);
13074 /* Generic codec_data handler puts it on the caps */
13081 case SL_CONFIG_DESC_TAG:
13082 GST_DEBUG_OBJECT (qtdemux, "data %02x", QT_UINT8 (ptr));
13086 GST_DEBUG_OBJECT (qtdemux, "Unknown/unhandled descriptor tag %02x",
13088 GST_MEMDUMP_OBJECT (qtdemux, "descriptor data", ptr, len);
13094 /* object_type_id in the esds atom in mp4a and mp4v tells us which codec is
13095 * in use, and should also be used to override some other parameters for some
13097 switch (object_type_id) {
13098 case 0x20: /* MPEG-4 */
13099 /* 4 bytes for the visual_object_sequence_start_code and 1 byte for the
13100 * profile_and_level_indication */
13101 if (data_ptr != NULL && data_len >= 5 &&
13102 GST_READ_UINT32_BE (data_ptr) == 0x000001b0) {
13103 gst_codec_utils_mpeg4video_caps_set_level_and_profile (stream->caps,
13104 data_ptr + 4, data_len - 4);
13106 break; /* Nothing special needed here */
13107 case 0x21: /* H.264 */
13108 codec_name = "H.264 / AVC";
13109 caps = gst_caps_new_simple ("video/x-h264",
13110 "stream-format", G_TYPE_STRING, "avc",
13111 "alignment", G_TYPE_STRING, "au", NULL);
13113 case 0x40: /* AAC (any) */
13114 case 0x66: /* AAC Main */
13115 case 0x67: /* AAC LC */
13116 case 0x68: /* AAC SSR */
13117 /* Override channels and rate based on the codec_data, as it's often
13119 /* Only do so for basic setup without HE-AAC extension */
13120 if (data_ptr && data_len == 2) {
13121 guint channels, rate;
13123 channels = gst_codec_utils_aac_get_channels (data_ptr, data_len);
13125 stream->n_channels = channels;
13127 rate = gst_codec_utils_aac_get_sample_rate (data_ptr, data_len);
13129 stream->rate = rate;
13132 /* Set level and profile if possible */
13133 if (data_ptr != NULL && data_len >= 2) {
13134 gst_codec_utils_aac_caps_set_level_and_profile (stream->caps,
13135 data_ptr, data_len);
13137 const gchar *profile_str = NULL;
13140 guint8 *codec_data;
13141 gint rate_idx, profile;
13143 /* No codec_data, let's invent something.
13144 * FIXME: This is wrong for SBR! */
13146 GST_WARNING_OBJECT (qtdemux, "No codec_data for AAC available");
13148 buffer = gst_buffer_new_and_alloc (2);
13149 gst_buffer_map (buffer, &map, GST_MAP_WRITE);
13150 codec_data = map.data;
13153 gst_codec_utils_aac_get_index_from_sample_rate (stream->rate);
13155 switch (object_type_id) {
13157 profile_str = "main";
13161 profile_str = "lc";
13165 profile_str = "ssr";
13173 codec_data[0] = ((profile + 1) << 3) | ((rate_idx & 0xE) >> 1);
13174 codec_data[1] = ((rate_idx & 0x1) << 7) | (stream->n_channels << 3);
13176 gst_buffer_unmap (buffer, &map);
13177 gst_caps_set_simple (stream->caps, "codec_data", GST_TYPE_BUFFER,
13179 gst_buffer_unref (buffer);
13182 gst_caps_set_simple (stream->caps, "profile", G_TYPE_STRING,
13183 profile_str, NULL);
13187 case 0x60: /* MPEG-2, various profiles */
13193 codec_name = "MPEG-2 video";
13194 caps = gst_caps_new_simple ("video/mpeg",
13195 "mpegversion", G_TYPE_INT, 2,
13196 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13198 case 0x69: /* MPEG-2 BC audio */
13199 case 0x6B: /* MPEG-1 audio */
13200 caps = gst_caps_new_simple ("audio/mpeg",
13201 "mpegversion", G_TYPE_INT, 1, "parsed", G_TYPE_BOOLEAN, TRUE, NULL);
13202 codec_name = "MPEG-1 audio";
13204 case 0x6A: /* MPEG-1 */
13205 codec_name = "MPEG-1 video";
13206 caps = gst_caps_new_simple ("video/mpeg",
13207 "mpegversion", G_TYPE_INT, 1,
13208 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13210 case 0x6C: /* MJPEG */
13212 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
13214 codec_name = "Motion-JPEG";
13216 case 0x6D: /* PNG */
13218 gst_caps_new_simple ("image/png", "parsed", G_TYPE_BOOLEAN, TRUE,
13220 codec_name = "PNG still images";
13222 case 0x6E: /* JPEG2000 */
13223 codec_name = "JPEG-2000";
13224 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
13226 case 0xA4: /* Dirac */
13227 codec_name = "Dirac";
13228 caps = gst_caps_new_empty_simple ("video/x-dirac");
13230 case 0xA5: /* AC3 */
13231 codec_name = "AC-3 audio";
13232 caps = gst_caps_new_simple ("audio/x-ac3",
13233 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
13235 case 0xA9: /* AC3 */
13236 codec_name = "DTS audio";
13237 caps = gst_caps_new_simple ("audio/x-dts",
13238 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
13240 case 0xE1: /* QCELP */
13241 /* QCELP, the codec_data is a riff tag (little endian) with
13242 * 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). */
13243 caps = gst_caps_new_empty_simple ("audio/qcelp");
13244 codec_name = "QCELP";
13250 /* If we have a replacement caps, then change our caps for this stream */
13252 gst_caps_unref (stream->caps);
13253 stream->caps = caps;
13256 if (codec_name && list)
13257 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
13258 GST_TAG_AUDIO_CODEC, codec_name, NULL);
13260 /* Add the codec_data attribute to caps, if we have it */
13264 buffer = gst_buffer_new_and_alloc (data_len);
13265 gst_buffer_fill (buffer, 0, data_ptr, data_len);
13267 GST_DEBUG_OBJECT (qtdemux, "setting codec_data from esds");
13268 GST_MEMDUMP_OBJECT (qtdemux, "codec_data from esds", data_ptr, data_len);
13270 gst_caps_set_simple (stream->caps, "codec_data", GST_TYPE_BUFFER,
13272 gst_buffer_unref (buffer);
13277 static inline GstCaps *
13278 _get_unknown_codec_name (const gchar * type, guint32 fourcc)
13282 char *s, fourstr[5];
13284 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
13285 for (i = 0; i < 4; i++) {
13286 if (!g_ascii_isalnum (fourstr[i]))
13289 s = g_strdup_printf ("%s/x-gst-fourcc-%s", type, g_strstrip (fourstr));
13290 caps = gst_caps_new_empty_simple (s);
13295 #define _codec(name) \
13297 if (codec_name) { \
13298 *codec_name = g_strdup (name); \
13303 qtdemux_video_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
13304 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
13306 GstCaps *caps = NULL;
13307 GstVideoFormat format = GST_VIDEO_FORMAT_UNKNOWN;
13310 case GST_MAKE_FOURCC ('p', 'n', 'g', ' '):
13311 _codec ("PNG still images");
13312 caps = gst_caps_new_empty_simple ("image/png");
13315 _codec ("JPEG still images");
13317 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
13320 case GST_MAKE_FOURCC ('m', 'j', 'p', 'a'):
13321 case GST_MAKE_FOURCC ('A', 'V', 'D', 'J'):
13322 case GST_MAKE_FOURCC ('M', 'J', 'P', 'G'):
13323 case GST_MAKE_FOURCC ('d', 'm', 'b', '1'):
13324 _codec ("Motion-JPEG");
13326 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
13329 case GST_MAKE_FOURCC ('m', 'j', 'p', 'b'):
13330 _codec ("Motion-JPEG format B");
13331 caps = gst_caps_new_empty_simple ("video/x-mjpeg-b");
13334 _codec ("JPEG-2000");
13335 /* override to what it should be according to spec, avoid palette_data */
13336 stream->bits_per_sample = 24;
13337 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
13340 _codec ("Sorensen video v.3");
13341 caps = gst_caps_new_simple ("video/x-svq",
13342 "svqversion", G_TYPE_INT, 3, NULL);
13344 case GST_MAKE_FOURCC ('s', 'v', 'q', 'i'):
13345 case GST_MAKE_FOURCC ('S', 'V', 'Q', '1'):
13346 _codec ("Sorensen video v.1");
13347 caps = gst_caps_new_simple ("video/x-svq",
13348 "svqversion", G_TYPE_INT, 1, NULL);
13350 case GST_MAKE_FOURCC ('W', 'R', 'A', 'W'):
13351 caps = gst_caps_new_empty_simple ("video/x-raw");
13352 gst_caps_set_simple (caps, "format", G_TYPE_STRING, "RGB8P", NULL);
13353 _codec ("Windows Raw RGB");
13354 stream->alignment = 32;
13360 bps = QT_UINT16 (stsd_data + 98);
13363 format = GST_VIDEO_FORMAT_RGB15;
13366 format = GST_VIDEO_FORMAT_RGB16;
13369 format = GST_VIDEO_FORMAT_RGB;
13372 format = GST_VIDEO_FORMAT_ARGB;
13380 case GST_MAKE_FOURCC ('y', 'v', '1', '2'):
13381 format = GST_VIDEO_FORMAT_I420;
13383 case GST_MAKE_FOURCC ('y', 'u', 'v', '2'):
13384 case GST_MAKE_FOURCC ('Y', 'u', 'v', '2'):
13385 format = GST_VIDEO_FORMAT_I420;
13388 case GST_MAKE_FOURCC ('2', 'V', 'u', 'y'):
13389 format = GST_VIDEO_FORMAT_UYVY;
13391 case GST_MAKE_FOURCC ('v', '3', '0', '8'):
13392 format = GST_VIDEO_FORMAT_v308;
13394 case GST_MAKE_FOURCC ('v', '2', '1', '6'):
13395 format = GST_VIDEO_FORMAT_v216;
13398 format = GST_VIDEO_FORMAT_v210;
13400 case GST_MAKE_FOURCC ('r', '2', '1', '0'):
13401 format = GST_VIDEO_FORMAT_r210;
13403 /* Packed YUV 4:4:4 10 bit in 32 bits, complex
13404 case GST_MAKE_FOURCC ('v', '4', '1', '0'):
13405 format = GST_VIDEO_FORMAT_v410;
13408 /* Packed YUV 4:4:4:4 8 bit in 32 bits
13409 * but different order than AYUV
13410 case GST_MAKE_FOURCC ('v', '4', '0', '8'):
13411 format = GST_VIDEO_FORMAT_v408;
13414 case GST_MAKE_FOURCC ('m', 'p', 'e', 'g'):
13415 case GST_MAKE_FOURCC ('m', 'p', 'g', '1'):
13416 _codec ("MPEG-1 video");
13417 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
13418 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13420 case GST_MAKE_FOURCC ('h', 'd', 'v', '1'): /* HDV 720p30 */
13421 case GST_MAKE_FOURCC ('h', 'd', 'v', '2'): /* HDV 1080i60 */
13422 case GST_MAKE_FOURCC ('h', 'd', 'v', '3'): /* HDV 1080i50 */
13423 case GST_MAKE_FOURCC ('h', 'd', 'v', '4'): /* HDV 720p24 */
13424 case GST_MAKE_FOURCC ('h', 'd', 'v', '5'): /* HDV 720p25 */
13425 case GST_MAKE_FOURCC ('h', 'd', 'v', '6'): /* HDV 1080p24 */
13426 case GST_MAKE_FOURCC ('h', 'd', 'v', '7'): /* HDV 1080p25 */
13427 case GST_MAKE_FOURCC ('h', 'd', 'v', '8'): /* HDV 1080p30 */
13428 case GST_MAKE_FOURCC ('h', 'd', 'v', '9'): /* HDV 720p60 */
13429 case GST_MAKE_FOURCC ('h', 'd', 'v', 'a'): /* HDV 720p50 */
13430 case GST_MAKE_FOURCC ('m', 'x', '5', 'n'): /* MPEG2 IMX NTSC 525/60 50mb/s produced by FCP */
13431 case GST_MAKE_FOURCC ('m', 'x', '5', 'p'): /* MPEG2 IMX PAL 625/60 50mb/s produced by FCP */
13432 case GST_MAKE_FOURCC ('m', 'x', '4', 'n'): /* MPEG2 IMX NTSC 525/60 40mb/s produced by FCP */
13433 case GST_MAKE_FOURCC ('m', 'x', '4', 'p'): /* MPEG2 IMX PAL 625/60 40mb/s produced by FCP */
13434 case GST_MAKE_FOURCC ('m', 'x', '3', 'n'): /* MPEG2 IMX NTSC 525/60 30mb/s produced by FCP */
13435 case GST_MAKE_FOURCC ('m', 'x', '3', 'p'): /* MPEG2 IMX PAL 625/50 30mb/s produced by FCP */
13436 case GST_MAKE_FOURCC ('x', 'd', 'v', '1'): /* XDCAM HD 720p30 35Mb/s */
13437 case GST_MAKE_FOURCC ('x', 'd', 'v', '2'): /* XDCAM HD 1080i60 35Mb/s */
13438 case GST_MAKE_FOURCC ('x', 'd', 'v', '3'): /* XDCAM HD 1080i50 35Mb/s */
13439 case GST_MAKE_FOURCC ('x', 'd', 'v', '4'): /* XDCAM HD 720p24 35Mb/s */
13440 case GST_MAKE_FOURCC ('x', 'd', 'v', '5'): /* XDCAM HD 720p25 35Mb/s */
13441 case GST_MAKE_FOURCC ('x', 'd', 'v', '6'): /* XDCAM HD 1080p24 35Mb/s */
13442 case GST_MAKE_FOURCC ('x', 'd', 'v', '7'): /* XDCAM HD 1080p25 35Mb/s */
13443 case GST_MAKE_FOURCC ('x', 'd', 'v', '8'): /* XDCAM HD 1080p30 35Mb/s */
13444 case GST_MAKE_FOURCC ('x', 'd', 'v', '9'): /* XDCAM HD 720p60 35Mb/s */
13445 case GST_MAKE_FOURCC ('x', 'd', 'v', 'a'): /* XDCAM HD 720p50 35Mb/s */
13446 case GST_MAKE_FOURCC ('x', 'd', 'v', 'b'): /* XDCAM EX 1080i60 50Mb/s CBR */
13447 case GST_MAKE_FOURCC ('x', 'd', 'v', 'c'): /* XDCAM EX 1080i50 50Mb/s CBR */
13448 case GST_MAKE_FOURCC ('x', 'd', 'v', 'd'): /* XDCAM HD 1080p24 50Mb/s CBR */
13449 case GST_MAKE_FOURCC ('x', 'd', 'v', 'e'): /* XDCAM HD 1080p25 50Mb/s CBR */
13450 case GST_MAKE_FOURCC ('x', 'd', 'v', 'f'): /* XDCAM HD 1080p30 50Mb/s CBR */
13451 case GST_MAKE_FOURCC ('x', 'd', '5', '1'): /* XDCAM HD422 720p30 50Mb/s CBR */
13452 case GST_MAKE_FOURCC ('x', 'd', '5', '4'): /* XDCAM HD422 720p24 50Mb/s CBR */
13453 case GST_MAKE_FOURCC ('x', 'd', '5', '5'): /* XDCAM HD422 720p25 50Mb/s CBR */
13454 case GST_MAKE_FOURCC ('x', 'd', '5', '9'): /* XDCAM HD422 720p60 50Mb/s CBR */
13455 case GST_MAKE_FOURCC ('x', 'd', '5', 'a'): /* XDCAM HD422 720p50 50Mb/s CBR */
13456 case GST_MAKE_FOURCC ('x', 'd', '5', 'b'): /* XDCAM HD422 1080i50 50Mb/s CBR */
13457 case GST_MAKE_FOURCC ('x', 'd', '5', 'c'): /* XDCAM HD422 1080i50 50Mb/s CBR */
13458 case GST_MAKE_FOURCC ('x', 'd', '5', 'd'): /* XDCAM HD422 1080p24 50Mb/s CBR */
13459 case GST_MAKE_FOURCC ('x', 'd', '5', 'e'): /* XDCAM HD422 1080p25 50Mb/s CBR */
13460 case GST_MAKE_FOURCC ('x', 'd', '5', 'f'): /* XDCAM HD422 1080p30 50Mb/s CBR */
13461 case GST_MAKE_FOURCC ('x', 'd', 'h', 'd'): /* XDCAM HD 540p */
13462 case GST_MAKE_FOURCC ('x', 'd', 'h', '2'): /* XDCAM HD422 540p */
13463 case GST_MAKE_FOURCC ('A', 'V', 'm', 'p'): /* AVID IMX PAL */
13464 case GST_MAKE_FOURCC ('m', 'p', 'g', '2'): /* AVID IMX PAL */
13465 case GST_MAKE_FOURCC ('m', 'p', '2', 'v'): /* AVID IMX PAL */
13466 case GST_MAKE_FOURCC ('m', '2', 'v', '1'):
13467 _codec ("MPEG-2 video");
13468 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 2,
13469 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13471 case GST_MAKE_FOURCC ('g', 'i', 'f', ' '):
13472 _codec ("GIF still images");
13473 caps = gst_caps_new_empty_simple ("image/gif");
13476 case GST_MAKE_FOURCC ('H', '2', '6', '3'):
13478 case GST_MAKE_FOURCC ('U', '2', '6', '3'):
13480 /* ffmpeg uses the height/width props, don't know why */
13481 caps = gst_caps_new_simple ("video/x-h263",
13482 "variant", G_TYPE_STRING, "itu", NULL);
13486 _codec ("MPEG-4 video");
13487 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
13488 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13490 case GST_MAKE_FOURCC ('3', 'i', 'v', 'd'):
13491 case GST_MAKE_FOURCC ('3', 'I', 'V', 'D'):
13492 _codec ("Microsoft MPEG-4 4.3"); /* FIXME? */
13493 caps = gst_caps_new_simple ("video/x-msmpeg",
13494 "msmpegversion", G_TYPE_INT, 43, NULL);
13496 case GST_MAKE_FOURCC ('D', 'I', 'V', '3'):
13498 caps = gst_caps_new_simple ("video/x-divx",
13499 "divxversion", G_TYPE_INT, 3, NULL);
13501 case GST_MAKE_FOURCC ('D', 'I', 'V', 'X'):
13502 case GST_MAKE_FOURCC ('d', 'i', 'v', 'x'):
13504 caps = gst_caps_new_simple ("video/x-divx",
13505 "divxversion", G_TYPE_INT, 4, NULL);
13507 case GST_MAKE_FOURCC ('D', 'X', '5', '0'):
13509 caps = gst_caps_new_simple ("video/x-divx",
13510 "divxversion", G_TYPE_INT, 5, NULL);
13513 case GST_MAKE_FOURCC ('F', 'F', 'V', '1'):
13515 caps = gst_caps_new_simple ("video/x-ffv",
13516 "ffvversion", G_TYPE_INT, 1, NULL);
13519 case GST_MAKE_FOURCC ('3', 'I', 'V', '1'):
13520 case GST_MAKE_FOURCC ('3', 'I', 'V', '2'):
13525 case GST_MAKE_FOURCC ('U', 'M', 'P', '4'):
13526 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
13527 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13531 case GST_MAKE_FOURCC ('c', 'v', 'i', 'd'):
13532 _codec ("Cinepak");
13533 caps = gst_caps_new_empty_simple ("video/x-cinepak");
13535 case GST_MAKE_FOURCC ('q', 'd', 'r', 'w'):
13536 _codec ("Apple QuickDraw");
13537 caps = gst_caps_new_empty_simple ("video/x-qdrw");
13539 case GST_MAKE_FOURCC ('r', 'p', 'z', 'a'):
13540 _codec ("Apple video");
13541 caps = gst_caps_new_empty_simple ("video/x-apple-video");
13545 _codec ("H.264 / AVC");
13546 caps = gst_caps_new_simple ("video/x-h264",
13547 "stream-format", G_TYPE_STRING, "avc",
13548 "alignment", G_TYPE_STRING, "au", NULL);
13551 _codec ("H.264 / AVC");
13552 caps = gst_caps_new_simple ("video/x-h264",
13553 "stream-format", G_TYPE_STRING, "avc3",
13554 "alignment", G_TYPE_STRING, "au", NULL);
13558 _codec ("H.265 / HEVC");
13559 caps = gst_caps_new_simple ("video/x-h265",
13560 "stream-format", G_TYPE_STRING, "hvc1",
13561 "alignment", G_TYPE_STRING, "au", NULL);
13564 _codec ("H.265 / HEVC");
13565 caps = gst_caps_new_simple ("video/x-h265",
13566 "stream-format", G_TYPE_STRING, "hev1",
13567 "alignment", G_TYPE_STRING, "au", NULL);
13570 _codec ("Run-length encoding");
13571 caps = gst_caps_new_simple ("video/x-rle",
13572 "layout", G_TYPE_STRING, "quicktime", NULL);
13575 _codec ("Run-length encoding");
13576 caps = gst_caps_new_simple ("video/x-rle",
13577 "layout", G_TYPE_STRING, "microsoft", NULL);
13579 case GST_MAKE_FOURCC ('I', 'V', '3', '2'):
13580 case GST_MAKE_FOURCC ('i', 'v', '3', '2'):
13581 _codec ("Indeo Video 3");
13582 caps = gst_caps_new_simple ("video/x-indeo",
13583 "indeoversion", G_TYPE_INT, 3, NULL);
13585 case GST_MAKE_FOURCC ('I', 'V', '4', '1'):
13586 case GST_MAKE_FOURCC ('i', 'v', '4', '1'):
13587 _codec ("Intel Video 4");
13588 caps = gst_caps_new_simple ("video/x-indeo",
13589 "indeoversion", G_TYPE_INT, 4, NULL);
13593 case GST_MAKE_FOURCC ('d', 'v', 's', 'd'):
13594 case GST_MAKE_FOURCC ('D', 'V', 'S', 'D'):
13595 case GST_MAKE_FOURCC ('d', 'v', 'c', 's'):
13596 case GST_MAKE_FOURCC ('D', 'V', 'C', 'S'):
13597 case GST_MAKE_FOURCC ('d', 'v', '2', '5'):
13598 case GST_MAKE_FOURCC ('d', 'v', 'p', 'p'):
13599 _codec ("DV Video");
13600 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 25,
13601 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13603 case FOURCC_dv5n: /* DVCPRO50 NTSC */
13604 case FOURCC_dv5p: /* DVCPRO50 PAL */
13605 _codec ("DVCPro50 Video");
13606 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 50,
13607 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13609 case GST_MAKE_FOURCC ('d', 'v', 'h', '5'): /* DVCPRO HD 50i produced by FCP */
13610 case GST_MAKE_FOURCC ('d', 'v', 'h', '6'): /* DVCPRO HD 60i produced by FCP */
13611 _codec ("DVCProHD Video");
13612 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 100,
13613 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13615 case GST_MAKE_FOURCC ('s', 'm', 'c', ' '):
13616 _codec ("Apple Graphics (SMC)");
13617 caps = gst_caps_new_empty_simple ("video/x-smc");
13619 case GST_MAKE_FOURCC ('V', 'P', '3', '1'):
13621 caps = gst_caps_new_empty_simple ("video/x-vp3");
13623 case GST_MAKE_FOURCC ('V', 'P', '6', 'F'):
13624 _codec ("VP6 Flash");
13625 caps = gst_caps_new_empty_simple ("video/x-vp6-flash");
13629 caps = gst_caps_new_empty_simple ("video/x-theora");
13630 /* theora uses one byte of padding in the data stream because it does not
13631 * allow 0 sized packets while theora does */
13632 stream->padding = 1;
13636 caps = gst_caps_new_empty_simple ("video/x-dirac");
13638 case GST_MAKE_FOURCC ('t', 'i', 'f', 'f'):
13639 _codec ("TIFF still images");
13640 caps = gst_caps_new_empty_simple ("image/tiff");
13642 case GST_MAKE_FOURCC ('i', 'c', 'o', 'd'):
13643 _codec ("Apple Intermediate Codec");
13644 caps = gst_caps_from_string ("video/x-apple-intermediate-codec");
13646 case GST_MAKE_FOURCC ('A', 'V', 'd', 'n'):
13647 _codec ("AVID DNxHD");
13648 caps = gst_caps_from_string ("video/x-dnxhd");
13651 _codec ("On2 VP8");
13652 caps = gst_caps_from_string ("video/x-vp8");
13655 _codec ("Apple ProRes LT");
13657 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "lt",
13661 _codec ("Apple ProRes HQ");
13663 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "hq",
13667 _codec ("Apple ProRes");
13669 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
13673 _codec ("Apple ProRes Proxy");
13675 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
13679 _codec ("Apple ProRes 4444");
13681 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
13685 _codec ("Apple ProRes 4444 XQ");
13687 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
13693 caps = gst_caps_new_simple ("video/x-wmv",
13694 "wmvversion", G_TYPE_INT, 3, "format", G_TYPE_STRING, "WVC1", NULL);
13696 case GST_MAKE_FOURCC ('k', 'p', 'c', 'd'):
13699 caps = _get_unknown_codec_name ("video", fourcc);
13704 if (format != GST_VIDEO_FORMAT_UNKNOWN) {
13707 gst_video_info_init (&info);
13708 gst_video_info_set_format (&info, format, stream->width, stream->height);
13710 caps = gst_video_info_to_caps (&info);
13711 *codec_name = gst_pb_utils_get_codec_description (caps);
13713 /* enable clipping for raw video streams */
13714 stream->need_clip = TRUE;
13715 stream->alignment = 32;
13722 round_up_pow2 (guint n)
13734 qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
13735 guint32 fourcc, const guint8 * data, int len, gchar ** codec_name)
13738 const GstStructure *s;
13741 GstAudioFormat format = 0;
13744 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
13746 depth = stream->bytes_per_packet * 8;
13749 case GST_MAKE_FOURCC ('N', 'O', 'N', 'E'):
13751 /* 8-bit audio is unsigned */
13753 format = GST_AUDIO_FORMAT_U8;
13754 /* otherwise it's signed and big-endian just like 'twos' */
13756 endian = G_BIG_ENDIAN;
13763 endian = G_LITTLE_ENDIAN;
13766 format = gst_audio_format_build_integer (TRUE, endian, depth, depth);
13768 str = g_strdup_printf ("Raw %d-bit PCM audio", depth);
13772 caps = gst_caps_new_simple ("audio/x-raw",
13773 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
13774 "layout", G_TYPE_STRING, "interleaved", NULL);
13775 stream->alignment = GST_ROUND_UP_8 (depth);
13776 stream->alignment = round_up_pow2 (stream->alignment);
13779 case GST_MAKE_FOURCC ('f', 'l', '6', '4'):
13780 _codec ("Raw 64-bit floating-point audio");
13781 caps = gst_caps_new_simple ("audio/x-raw",
13782 "format", G_TYPE_STRING, "F64BE",
13783 "layout", G_TYPE_STRING, "interleaved", NULL);
13784 stream->alignment = 8;
13786 case GST_MAKE_FOURCC ('f', 'l', '3', '2'):
13787 _codec ("Raw 32-bit floating-point audio");
13788 caps = gst_caps_new_simple ("audio/x-raw",
13789 "format", G_TYPE_STRING, "F32BE",
13790 "layout", G_TYPE_STRING, "interleaved", NULL);
13791 stream->alignment = 4;
13794 _codec ("Raw 24-bit PCM audio");
13795 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
13797 caps = gst_caps_new_simple ("audio/x-raw",
13798 "format", G_TYPE_STRING, "S24BE",
13799 "layout", G_TYPE_STRING, "interleaved", NULL);
13800 stream->alignment = 4;
13802 case GST_MAKE_FOURCC ('i', 'n', '3', '2'):
13803 _codec ("Raw 32-bit PCM audio");
13804 caps = gst_caps_new_simple ("audio/x-raw",
13805 "format", G_TYPE_STRING, "S32BE",
13806 "layout", G_TYPE_STRING, "interleaved", NULL);
13807 stream->alignment = 4;
13810 _codec ("Mu-law audio");
13811 caps = gst_caps_new_empty_simple ("audio/x-mulaw");
13814 _codec ("A-law audio");
13815 caps = gst_caps_new_empty_simple ("audio/x-alaw");
13819 _codec ("Microsoft ADPCM");
13820 /* Microsoft ADPCM-ACM code 2 */
13821 caps = gst_caps_new_simple ("audio/x-adpcm",
13822 "layout", G_TYPE_STRING, "microsoft", NULL);
13826 _codec ("DVI/IMA ADPCM");
13827 caps = gst_caps_new_simple ("audio/x-adpcm",
13828 "layout", G_TYPE_STRING, "dvi", NULL);
13832 _codec ("DVI/Intel IMA ADPCM");
13833 /* FIXME DVI/Intel IMA ADPCM/ACM code 17 */
13834 caps = gst_caps_new_simple ("audio/x-adpcm",
13835 "layout", G_TYPE_STRING, "quicktime", NULL);
13839 /* MPEG layer 3, CBR only (pre QT4.1) */
13841 _codec ("MPEG-1 layer 3");
13842 /* MPEG layer 3, CBR & VBR (QT4.1 and later) */
13843 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 3,
13844 "mpegversion", G_TYPE_INT, 1, NULL);
13846 case GST_MAKE_FOURCC ('.', 'm', 'p', '2'):
13847 _codec ("MPEG-1 layer 2");
13849 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 2,
13850 "mpegversion", G_TYPE_INT, 1, NULL);
13853 case GST_MAKE_FOURCC ('e', 'c', '-', '3'):
13854 _codec ("EAC-3 audio");
13855 caps = gst_caps_new_simple ("audio/x-eac3",
13856 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
13857 stream->sampled = TRUE;
13859 case GST_MAKE_FOURCC ('s', 'a', 'c', '3'): // Nero Recode
13861 _codec ("AC-3 audio");
13862 caps = gst_caps_new_simple ("audio/x-ac3",
13863 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
13864 stream->sampled = TRUE;
13866 case GST_MAKE_FOURCC ('d', 't', 's', 'c'):
13867 case GST_MAKE_FOURCC ('D', 'T', 'S', ' '):
13868 _codec ("DTS audio");
13869 caps = gst_caps_new_simple ("audio/x-dts",
13870 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
13871 stream->sampled = TRUE;
13873 case GST_MAKE_FOURCC ('d', 't', 's', 'h'): // DTS-HD
13874 case GST_MAKE_FOURCC ('d', 't', 's', 'l'): // DTS-HD Lossless
13875 _codec ("DTS-HD audio");
13876 caps = gst_caps_new_simple ("audio/x-dts",
13877 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
13878 stream->sampled = TRUE;
13882 caps = gst_caps_new_simple ("audio/x-mace",
13883 "maceversion", G_TYPE_INT, 3, NULL);
13887 caps = gst_caps_new_simple ("audio/x-mace",
13888 "maceversion", G_TYPE_INT, 6, NULL);
13890 case GST_MAKE_FOURCC ('O', 'g', 'g', 'V'):
13892 caps = gst_caps_new_empty_simple ("application/ogg");
13894 case GST_MAKE_FOURCC ('d', 'v', 'c', 'a'):
13895 _codec ("DV audio");
13896 caps = gst_caps_new_empty_simple ("audio/x-dv");
13899 _codec ("MPEG-4 AAC audio");
13900 caps = gst_caps_new_simple ("audio/mpeg",
13901 "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE,
13902 "stream-format", G_TYPE_STRING, "raw", NULL);
13904 case GST_MAKE_FOURCC ('Q', 'D', 'M', 'C'):
13905 _codec ("QDesign Music");
13906 caps = gst_caps_new_empty_simple ("audio/x-qdm");
13909 _codec ("QDesign Music v.2");
13910 /* FIXME: QDesign music version 2 (no constant) */
13911 if (FALSE && data) {
13912 caps = gst_caps_new_simple ("audio/x-qdm2",
13913 "framesize", G_TYPE_INT, QT_UINT32 (data + 52),
13914 "bitrate", G_TYPE_INT, QT_UINT32 (data + 40),
13915 "blocksize", G_TYPE_INT, QT_UINT32 (data + 44), NULL);
13917 caps = gst_caps_new_empty_simple ("audio/x-qdm2");
13921 _codec ("GSM audio");
13922 caps = gst_caps_new_empty_simple ("audio/x-gsm");
13925 _codec ("AMR audio");
13926 caps = gst_caps_new_empty_simple ("audio/AMR");
13929 _codec ("AMR-WB audio");
13930 caps = gst_caps_new_empty_simple ("audio/AMR-WB");
13933 _codec ("Quicktime IMA ADPCM");
13934 caps = gst_caps_new_simple ("audio/x-adpcm",
13935 "layout", G_TYPE_STRING, "quicktime", NULL);
13938 _codec ("Apple lossless audio");
13939 caps = gst_caps_new_empty_simple ("audio/x-alac");
13942 _codec ("Free Lossless Audio Codec");
13943 caps = gst_caps_new_simple ("audio/x-flac",
13944 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
13946 case GST_MAKE_FOURCC ('Q', 'c', 'l', 'p'):
13947 _codec ("QualComm PureVoice");
13948 caps = gst_caps_from_string ("audio/qcelp");
13953 caps = gst_caps_new_empty_simple ("audio/x-wma");
13957 caps = gst_caps_new_empty_simple ("audio/x-opus");
13959 case GST_MAKE_FOURCC ('l', 'p', 'c', 'm'):
13964 GstAudioFormat format;
13967 FLAG_IS_FLOAT = 0x1,
13968 FLAG_IS_BIG_ENDIAN = 0x2,
13969 FLAG_IS_SIGNED = 0x4,
13970 FLAG_IS_PACKED = 0x8,
13971 FLAG_IS_ALIGNED_HIGH = 0x10,
13972 FLAG_IS_NON_INTERLEAVED = 0x20
13974 _codec ("Raw LPCM audio");
13976 if (data && len >= 56) {
13977 depth = QT_UINT32 (data + 40);
13978 flags = QT_UINT32 (data + 44);
13979 width = QT_UINT32 (data + 48) * 8 / stream->n_channels;
13981 if ((flags & FLAG_IS_FLOAT) == 0) {
13986 format = gst_audio_format_build_integer ((flags & FLAG_IS_SIGNED) ?
13987 TRUE : FALSE, (flags & FLAG_IS_BIG_ENDIAN) ?
13988 G_BIG_ENDIAN : G_LITTLE_ENDIAN, width, depth);
13989 caps = gst_caps_new_simple ("audio/x-raw",
13990 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
13991 "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
13992 "non-interleaved" : "interleaved", NULL);
13993 stream->alignment = GST_ROUND_UP_8 (depth);
13994 stream->alignment = round_up_pow2 (stream->alignment);
13999 if (flags & FLAG_IS_BIG_ENDIAN)
14000 format = GST_AUDIO_FORMAT_F64BE;
14002 format = GST_AUDIO_FORMAT_F64LE;
14004 if (flags & FLAG_IS_BIG_ENDIAN)
14005 format = GST_AUDIO_FORMAT_F32BE;
14007 format = GST_AUDIO_FORMAT_F32LE;
14009 caps = gst_caps_new_simple ("audio/x-raw",
14010 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
14011 "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
14012 "non-interleaved" : "interleaved", NULL);
14013 stream->alignment = width / 8;
14017 case GST_MAKE_FOURCC ('q', 't', 'v', 'r'):
14021 caps = _get_unknown_codec_name ("audio", fourcc);
14027 GstCaps *templ_caps =
14028 gst_static_pad_template_get_caps (&gst_qtdemux_audiosrc_template);
14029 GstCaps *intersection = gst_caps_intersect (caps, templ_caps);
14030 gst_caps_unref (caps);
14031 gst_caps_unref (templ_caps);
14032 caps = intersection;
14035 /* enable clipping for raw audio streams */
14036 s = gst_caps_get_structure (caps, 0);
14037 name = gst_structure_get_name (s);
14038 if (g_str_has_prefix (name, "audio/x-raw")) {
14039 stream->need_clip = TRUE;
14040 stream->max_buffer_size = 4096 * stream->bytes_per_frame;
14041 GST_DEBUG ("setting max buffer size to %d", stream->max_buffer_size);
14047 qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
14048 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
14052 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
14056 _codec ("DVD subtitle");
14057 caps = gst_caps_new_empty_simple ("subpicture/x-dvd");
14058 stream->need_process = TRUE;
14061 _codec ("Quicktime timed text");
14064 _codec ("3GPP timed text");
14066 caps = gst_caps_new_simple ("text/x-raw", "format", G_TYPE_STRING,
14068 /* actual text piece needs to be extracted */
14069 stream->need_process = TRUE;
14072 _codec ("XML subtitles");
14073 caps = gst_caps_new_empty_simple ("application/ttml+xml");
14077 caps = _get_unknown_codec_name ("text", fourcc);
14085 qtdemux_generic_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
14086 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
14092 _codec ("MPEG 1 video");
14093 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
14094 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14104 gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux,
14105 const gchar * system_id)
14109 if (!qtdemux->protection_system_ids)
14110 qtdemux->protection_system_ids =
14111 g_ptr_array_new_with_free_func ((GDestroyNotify) g_free);
14112 /* Check whether we already have an entry for this system ID. */
14113 for (i = 0; i < qtdemux->protection_system_ids->len; ++i) {
14114 const gchar *id = g_ptr_array_index (qtdemux->protection_system_ids, i);
14115 if (g_ascii_strcasecmp (system_id, id) == 0) {
14119 GST_DEBUG_OBJECT (qtdemux, "Adding cenc protection system ID %s", system_id);
14120 g_ptr_array_add (qtdemux->protection_system_ids, g_ascii_strdown (system_id,