2 * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
3 * Copyright (C) <2003> David A. Schleef <ds@schleef.org>
4 * Copyright (C) <2006> Wim Taymans <wim@fluendo.com>
5 * Copyright (C) <2007> Julien Moutte <julien@fluendo.com>
6 * Copyright (C) <2009> Tim-Philipp Müller <tim centricular net>
7 * Copyright (C) <2009> STEricsson <benjamin.gaignard@stericsson.com>
8 * Copyright (C) <2013> Sreerenj Balachandran <sreerenj.balachandran@intel.com>
9 * Copyright (C) <2013> Intel Corporation
10 * Copyright (C) <2014> Centricular Ltd
11 * Copyright (C) <2015> YouView TV Ltd.
13 * This library is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU Library General Public
15 * License as published by the Free Software Foundation; either
16 * version 2 of the License, or (at your option) any later version.
18 * This library is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * Library General Public License for more details.
23 * You should have received a copy of the GNU Library General Public
24 * License along with this library; if not, write to the
25 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
26 * Boston, MA 02110-1301, USA.
30 * SECTION:element-qtdemux
32 * Demuxes a .mov file into raw or compressed audio and/or video streams.
34 * This element supports both push and pull-based scheduling, depending on the
35 * capabilities of the upstream elements.
38 * <title>Example launch line</title>
40 * gst-launch-1.0 filesrc location=test.mov ! qtdemux name=demux demux.audio_0 ! queue ! decodebin ! audioconvert ! audioresample ! autoaudiosink demux.video_0 ! queue ! decodebin ! videoconvert ! videoscale ! autovideosink
41 * ]| Play (parse and decode) a .mov file and try to output it to
42 * an automatically detected soundcard and videosink. If the MOV file contains
43 * compressed audio or video data, this will only work if you have the
44 * right decoder elements/plugins installed.
52 #include "gst/gst-i18n-plugin.h"
54 #include <glib/gprintf.h>
55 #include <gst/tag/tag.h>
56 #include <gst/audio/audio.h>
57 #include <gst/video/video.h>
59 #include "qtatomparser.h"
60 #include "qtdemux_types.h"
61 #include "qtdemux_dump.h"
63 #include "descriptors.h"
64 #include "qtdemux_lang.h"
66 #include "qtpalette.h"
68 #include "gst/riff/riff-media.h"
69 #include "gst/riff/riff-read.h"
71 #include <gst/pbutils/pbutils.h>
78 #include <gst/math-compat.h>
84 /* max. size considered 'sane' for non-mdat atoms */
85 #define QTDEMUX_MAX_ATOM_SIZE (25*1024*1024)
87 /* if the sample index is larger than this, something is likely wrong */
88 #define QTDEMUX_MAX_SAMPLE_INDEX_SIZE (50*1024*1024)
90 /* For converting qt creation times to unix epoch times */
91 #define QTDEMUX_SECONDS_PER_DAY (60 * 60 * 24)
92 #define QTDEMUX_LEAP_YEARS_FROM_1904_TO_1970 17
93 #define QTDEMUX_SECONDS_FROM_1904_TO_1970 (((1970 - 1904) * (guint64) 365 + \
94 QTDEMUX_LEAP_YEARS_FROM_1904_TO_1970) * QTDEMUX_SECONDS_PER_DAY)
96 #define STREAM_IS_EOS(s) (s->time_position == GST_CLOCK_TIME_NONE)
98 GST_DEBUG_CATEGORY (qtdemux_debug);
100 /*typedef struct _QtNode QtNode; */
101 typedef struct _QtDemuxSegment QtDemuxSegment;
102 typedef struct _QtDemuxSample QtDemuxSample;
104 typedef struct _QtDemuxCencSampleSetInfo QtDemuxCencSampleSetInfo;
113 struct _QtDemuxSample
116 gint32 pts_offset; /* Add this value to timestamp to get the pts */
118 guint64 timestamp; /* DTS In mov time */
119 guint32 duration; /* In mov time */
120 gboolean keyframe; /* TRUE when this packet is a keyframe */
123 /* Macros for converting to/from timescale */
124 #define QTSTREAMTIME_TO_GSTTIME(stream, value) (gst_util_uint64_scale((value), GST_SECOND, (stream)->timescale))
125 #define GSTTIME_TO_QTSTREAMTIME(stream, value) (gst_util_uint64_scale((value), (stream)->timescale, GST_SECOND))
127 #define QTTIME_TO_GSTTIME(qtdemux, value) (gst_util_uint64_scale((value), GST_SECOND, (qtdemux)->timescale))
128 #define GSTTIME_TO_QTTIME(qtdemux, value) (gst_util_uint64_scale((value), (qtdemux)->timescale, GST_SECOND))
130 /* timestamp is the DTS */
131 #define QTSAMPLE_DTS(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp))
132 /* timestamp + offset is the PTS */
133 #define QTSAMPLE_PTS(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp + (stream)->cslg_shift + (sample)->pts_offset))
134 /* timestamp + duration - dts is the duration */
135 #define QTSAMPLE_DUR_DTS(stream, sample, dts) (QTSTREAMTIME_TO_GSTTIME ((stream), (sample)->timestamp + (sample)->duration) - (dts))
137 #define QTSAMPLE_KEYFRAME(stream,sample) ((stream)->all_keyframe || (sample)->keyframe)
140 * Quicktime has tracks and segments. A track is a continuous piece of
141 * multimedia content. The track is not always played from start to finish but
142 * instead, pieces of the track are 'cut out' and played in sequence. This is
143 * what the segments do.
145 * Inside the track we have keyframes (K) and delta frames. The track has its
146 * own timing, which starts from 0 and extends to end. The position in the track
147 * is called the media_time.
149 * The segments now describe the pieces that should be played from this track
150 * and are basically tuples of media_time/duration/rate entries. We can have
151 * multiple segments and they are all played after one another. An example:
153 * segment 1: media_time: 1 second, duration: 1 second, rate 1
154 * segment 2: media_time: 3 second, duration: 2 second, rate 2
156 * To correctly play back this track, one must play: 1 second of media starting
157 * from media_time 1 followed by 2 seconds of media starting from media_time 3
160 * Each of the segments will be played at a specific time, the first segment at
161 * time 0, the second one after the duration of the first one, etc.. Note that
162 * the time in resulting playback is not identical to the media_time of the
165 * Visually, assuming the track has 4 second of media_time:
168 * .-----------------------------------------------------------.
169 * track: | K.....K.........K........K.......K.......K...........K... |
170 * '-----------------------------------------------------------'
172 * .------------^ ^ .----------^ ^
173 * / .-------------' / .------------------'
175 * .--------------. .--------------.
176 * | segment 1 | | segment 2 |
177 * '--------------' '--------------'
179 * The challenge here is to cut out the right pieces of the track for each of
180 * the playback segments. This fortunately can easily be done with the SEGMENT
181 * events of GStreamer.
183 * For playback of segment 1, we need to provide the decoder with the keyframe
184 * (a), in the above figure, but we must instruct it only to output the decoded
185 * data between second 1 and 2. We do this with a SEGMENT event for 1 to 2, time
186 * position set to the time of the segment: 0.
188 * We then proceed to push data from keyframe (a) to frame (b). The decoder
189 * decodes but clips all before media_time 1.
191 * After finishing a segment, we push out a new SEGMENT event with the clipping
192 * boundaries of the new data.
194 * This is a good usecase for the GStreamer accumulated SEGMENT events.
197 struct _QtDemuxSegment
199 /* global time and duration, all gst time */
201 GstClockTime stop_time;
202 GstClockTime duration;
203 /* media time of trak, all gst time */
204 GstClockTime media_start;
205 GstClockTime media_stop;
207 /* Media start time in trak timescale units */
208 guint32 trak_media_start;
211 #define QTSEGMENT_IS_EMPTY(s) ((s)->media_start == GST_CLOCK_TIME_NONE)
213 /* Used with fragmented MP4 files (mfra atom) */
218 } QtDemuxRandomAccessEntry;
220 struct _QtDemuxStream
231 gboolean new_stream; /* signals that a stream_start is required */
232 gboolean on_keyframe; /* if this stream last pushed buffer was a
233 * keyframe. This is important to identify
234 * where to stop pushing buffers after a
235 * segment stop time */
237 /* if the stream has a redirect URI in its headers, we store it here */
244 guint64 duration; /* in timescale */
248 gchar lang_id[4]; /* ISO 639-2T language code */
252 QtDemuxSample *samples;
253 gboolean all_keyframe; /* TRUE when all samples are keyframes (no stss) */
254 guint32 first_duration; /* duration in timescale of first sample, used for figuring out
255 the framerate, in timescale units */
256 guint32 offset_in_sample;
257 guint32 max_buffer_size;
259 /* if we use chunks or samples */
271 /* Numerator/denominator framerate */
274 guint16 bits_per_sample;
275 guint16 color_table_id;
276 GstMemory *rgb8_palette;
281 guint samples_per_packet;
282 guint samples_per_frame;
283 guint bytes_per_packet;
284 guint bytes_per_sample;
285 guint bytes_per_frame;
289 gboolean use_allocator;
290 GstAllocator *allocator;
291 GstAllocationParams params;
293 /* when a discontinuity is pending */
296 /* list of buffers to push first */
299 /* if we need to clip this buffer. This is only needed for uncompressed
303 /* buffer needs some custom processing, e.g. subtitles */
304 gboolean need_process;
306 /* current position */
307 guint32 segment_index;
308 guint32 sample_index;
309 GstClockTime time_position; /* in gst time */
310 guint64 accumulated_base;
312 /* the Gst segment we are processing out, used for clipping */
314 guint32 segment_seqnum; /* segment event seqnum obtained from seek */
316 /* quicktime segments */
318 QtDemuxSegment *segments;
319 gboolean dummy_segment;
324 GstTagList *pending_tags;
325 gboolean send_global_tags;
327 GstEvent *pending_event;
337 gboolean chunks_are_samples; /* TRUE means treat chunks as samples */
341 GstByteReader co_chunk;
343 guint32 current_chunk;
345 guint32 samples_per_chunk;
346 guint32 stco_sample_index;
348 guint32 sample_size; /* 0 means variable sizes are stored in stsz */
351 guint32 n_samples_per_chunk;
352 guint32 stsc_chunk_index;
353 guint32 stsc_sample_index;
354 guint64 chunk_offset;
357 guint32 stts_samples;
358 guint32 n_sample_times;
359 guint32 stts_sample_index;
361 guint32 stts_duration;
363 gboolean stss_present;
364 guint32 n_sample_syncs;
367 gboolean stps_present;
368 guint32 n_sample_partial_syncs;
370 QtDemuxRandomAccessEntry *ra_entries;
373 const QtDemuxRandomAccessEntry *pending_seek;
376 gboolean ctts_present;
377 guint32 n_composition_times;
379 guint32 ctts_sample_index;
387 gboolean parsed_trex;
388 guint32 def_sample_duration;
389 guint32 def_sample_size;
390 guint32 def_sample_flags;
394 /* stereoscopic video streams */
395 GstVideoMultiviewMode multiview_mode;
396 GstVideoMultiviewFlags multiview_flags;
398 /* protected streams */
400 guint32 protection_scheme_type;
401 guint32 protection_scheme_version;
402 gpointer protection_scheme_info; /* specific to the protection scheme */
403 GQueue protection_scheme_event_queue;
406 /* Contains properties and cryptographic info for a set of samples from a
407 * track protected using Common Encryption (cenc) */
408 struct _QtDemuxCencSampleSetInfo
410 GstStructure *default_properties;
412 /* @crypto_info holds one GstStructure per sample */
413 GPtrArray *crypto_info;
418 QTDEMUX_STATE_INITIAL, /* Initial state (haven't got the header yet) */
419 QTDEMUX_STATE_HEADER, /* Parsing the header */
420 QTDEMUX_STATE_MOVIE, /* Parsing/Playing the media data */
421 QTDEMUX_STATE_BUFFER_MDAT /* Buffering the mdat atom */
424 static GNode *qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc);
425 static GNode *qtdemux_tree_get_child_by_type_full (GNode * node,
426 guint32 fourcc, GstByteReader * parser);
427 static GNode *qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc);
428 static GNode *qtdemux_tree_get_sibling_by_type_full (GNode * node,
429 guint32 fourcc, GstByteReader * parser);
431 static GstFlowReturn qtdemux_add_fragmented_samples (GstQTDemux * qtdemux);
433 static GstStaticPadTemplate gst_qtdemux_sink_template =
434 GST_STATIC_PAD_TEMPLATE ("sink",
437 GST_STATIC_CAPS ("video/quicktime; video/mj2; audio/x-m4a; "
441 static GstStaticPadTemplate gst_qtdemux_videosrc_template =
442 GST_STATIC_PAD_TEMPLATE ("video_%u",
445 GST_STATIC_CAPS_ANY);
447 static GstStaticPadTemplate gst_qtdemux_audiosrc_template =
448 GST_STATIC_PAD_TEMPLATE ("audio_%u",
451 GST_STATIC_CAPS_ANY);
453 static GstStaticPadTemplate gst_qtdemux_subsrc_template =
454 GST_STATIC_PAD_TEMPLATE ("subtitle_%u",
457 GST_STATIC_CAPS_ANY);
459 #define gst_qtdemux_parent_class parent_class
460 G_DEFINE_TYPE (GstQTDemux, gst_qtdemux, GST_TYPE_ELEMENT);
462 static void gst_qtdemux_dispose (GObject * object);
465 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
466 GstClockTime media_time);
468 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
469 QtDemuxStream * str, gint64 media_offset);
472 static void gst_qtdemux_set_index (GstElement * element, GstIndex * index);
473 static GstIndex *gst_qtdemux_get_index (GstElement * element);
475 static GstStateChangeReturn gst_qtdemux_change_state (GstElement * element,
476 GstStateChange transition);
477 static gboolean qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent);
478 static gboolean qtdemux_sink_activate_mode (GstPad * sinkpad,
479 GstObject * parent, GstPadMode mode, gboolean active);
481 static void gst_qtdemux_loop (GstPad * pad);
482 static GstFlowReturn gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent,
484 static gboolean gst_qtdemux_handle_sink_event (GstPad * pad, GstObject * parent,
486 static gboolean gst_qtdemux_setcaps (GstQTDemux * qtdemux, GstCaps * caps);
487 static gboolean gst_qtdemux_configure_stream (GstQTDemux * qtdemux,
488 QtDemuxStream * stream);
489 static GstFlowReturn gst_qtdemux_process_adapter (GstQTDemux * demux,
492 static gboolean qtdemux_parse_moov (GstQTDemux * qtdemux,
493 const guint8 * buffer, guint length);
494 static gboolean qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node,
495 const guint8 * buffer, guint length);
496 static gboolean qtdemux_parse_tree (GstQTDemux * qtdemux);
497 static void qtdemux_parse_udta (GstQTDemux * qtdemux, GstTagList * taglist,
500 static void gst_qtdemux_handle_esds (GstQTDemux * qtdemux,
501 QtDemuxStream * stream, GNode * esds, GstTagList * list);
502 static GstCaps *qtdemux_video_caps (GstQTDemux * qtdemux,
503 QtDemuxStream * stream, guint32 fourcc, const guint8 * stsd_data,
504 gchar ** codec_name);
505 static GstCaps *qtdemux_audio_caps (GstQTDemux * qtdemux,
506 QtDemuxStream * stream, guint32 fourcc, const guint8 * data, int len,
507 gchar ** codec_name);
508 static GstCaps *qtdemux_sub_caps (GstQTDemux * qtdemux,
509 QtDemuxStream * stream, guint32 fourcc, const guint8 * data,
510 gchar ** codec_name);
511 static GstCaps *qtdemux_generic_caps (GstQTDemux * qtdemux,
512 QtDemuxStream * stream, guint32 fourcc, const guint8 * stsd_data,
513 gchar ** codec_name);
515 static gboolean qtdemux_parse_samples (GstQTDemux * qtdemux,
516 QtDemuxStream * stream, guint32 n);
517 static GstFlowReturn qtdemux_expose_streams (GstQTDemux * qtdemux);
518 static void gst_qtdemux_stream_free (GstQTDemux * qtdemux,
519 QtDemuxStream * stream);
520 static void gst_qtdemux_stream_clear (GstQTDemux * qtdemux,
521 QtDemuxStream * stream);
522 static void gst_qtdemux_remove_stream (GstQTDemux * qtdemux, int index);
523 static GstFlowReturn qtdemux_prepare_streams (GstQTDemux * qtdemux);
524 static void qtdemux_do_allocation (GstQTDemux * qtdemux,
525 QtDemuxStream * stream);
527 static gboolean qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux);
528 static void check_update_duration (GstQTDemux * qtdemux, GstClockTime duration);
530 static void gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux,
534 gst_qtdemux_class_init (GstQTDemuxClass * klass)
536 GObjectClass *gobject_class;
537 GstElementClass *gstelement_class;
539 gobject_class = (GObjectClass *) klass;
540 gstelement_class = (GstElementClass *) klass;
542 parent_class = g_type_class_peek_parent (klass);
544 gobject_class->dispose = gst_qtdemux_dispose;
546 gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_qtdemux_change_state);
548 gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_qtdemux_set_index);
549 gstelement_class->get_index = GST_DEBUG_FUNCPTR (gst_qtdemux_get_index);
552 gst_tag_register_musicbrainz_tags ();
554 gst_element_class_add_pad_template (gstelement_class,
555 gst_static_pad_template_get (&gst_qtdemux_sink_template));
556 gst_element_class_add_pad_template (gstelement_class,
557 gst_static_pad_template_get (&gst_qtdemux_videosrc_template));
558 gst_element_class_add_pad_template (gstelement_class,
559 gst_static_pad_template_get (&gst_qtdemux_audiosrc_template));
560 gst_element_class_add_pad_template (gstelement_class,
561 gst_static_pad_template_get (&gst_qtdemux_subsrc_template));
562 gst_element_class_set_static_metadata (gstelement_class, "QuickTime demuxer",
564 "Demultiplex a QuickTime file into audio and video streams",
565 "David Schleef <ds@schleef.org>, Wim Taymans <wim@fluendo.com>");
567 GST_DEBUG_CATEGORY_INIT (qtdemux_debug, "qtdemux", 0, "qtdemux plugin");
572 gst_qtdemux_init (GstQTDemux * qtdemux)
575 gst_pad_new_from_static_template (&gst_qtdemux_sink_template, "sink");
576 gst_pad_set_activate_function (qtdemux->sinkpad, qtdemux_sink_activate);
577 gst_pad_set_activatemode_function (qtdemux->sinkpad,
578 qtdemux_sink_activate_mode);
579 gst_pad_set_chain_function (qtdemux->sinkpad, gst_qtdemux_chain);
580 gst_pad_set_event_function (qtdemux->sinkpad, gst_qtdemux_handle_sink_event);
581 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), qtdemux->sinkpad);
583 qtdemux->state = QTDEMUX_STATE_INITIAL;
584 qtdemux->pullbased = FALSE;
585 qtdemux->posted_redirect = FALSE;
586 qtdemux->neededbytes = 16;
588 qtdemux->adapter = gst_adapter_new ();
590 qtdemux->first_mdat = -1;
591 qtdemux->got_moov = FALSE;
592 qtdemux->mdatoffset = -1;
593 qtdemux->mdatbuffer = NULL;
594 qtdemux->restoredata_buffer = NULL;
595 qtdemux->restoredata_offset = -1;
596 qtdemux->fragment_start = -1;
597 qtdemux->fragment_start_offset = -1;
598 qtdemux->media_caps = NULL;
599 qtdemux->exposed = FALSE;
600 qtdemux->mss_mode = FALSE;
601 qtdemux->pending_newsegment = NULL;
602 qtdemux->upstream_format_is_time = FALSE;
603 qtdemux->have_group_id = FALSE;
604 qtdemux->group_id = G_MAXUINT;
605 qtdemux->protection_system_ids = NULL;
606 g_queue_init (&qtdemux->protection_event_queue);
607 gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
608 qtdemux->flowcombiner = gst_flow_combiner_new ();
610 GST_OBJECT_FLAG_SET (qtdemux, GST_ELEMENT_FLAG_INDEXABLE);
614 gst_qtdemux_dispose (GObject * object)
616 GstQTDemux *qtdemux = GST_QTDEMUX (object);
618 if (qtdemux->adapter) {
619 g_object_unref (G_OBJECT (qtdemux->adapter));
620 qtdemux->adapter = NULL;
622 gst_flow_combiner_free (qtdemux->flowcombiner);
623 g_queue_foreach (&qtdemux->protection_event_queue, (GFunc) gst_event_unref,
625 g_queue_clear (&qtdemux->protection_event_queue);
627 G_OBJECT_CLASS (parent_class)->dispose (object);
631 gst_qtdemux_post_no_playable_stream_error (GstQTDemux * qtdemux)
633 if (qtdemux->posted_redirect) {
634 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
635 (_("This file contains no playable streams.")),
636 ("no known streams found, a redirect message has been posted"));
638 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
639 (_("This file contains no playable streams.")),
640 ("no known streams found"));
645 _gst_buffer_new_wrapped (gpointer mem, gsize size, GFreeFunc free_func)
647 return gst_buffer_new_wrapped_full (free_func ? 0 : GST_MEMORY_FLAG_READONLY,
648 mem, size, 0, size, mem, free_func);
652 gst_qtdemux_pull_atom (GstQTDemux * qtdemux, guint64 offset, guint64 size,
659 if (G_UNLIKELY (size == 0)) {
661 GstBuffer *tmp = NULL;
663 ret = gst_qtdemux_pull_atom (qtdemux, offset, sizeof (guint32), &tmp);
664 if (ret != GST_FLOW_OK)
667 gst_buffer_map (tmp, &map, GST_MAP_READ);
668 size = QT_UINT32 (map.data);
669 GST_DEBUG_OBJECT (qtdemux, "size 0x%08" G_GINT64_MODIFIER "x", size);
671 gst_buffer_unmap (tmp, &map);
672 gst_buffer_unref (tmp);
675 /* Sanity check: catch bogus sizes (fuzzed/broken files) */
676 if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
677 if (qtdemux->state != QTDEMUX_STATE_MOVIE && qtdemux->got_moov) {
678 /* we're pulling header but already got most interesting bits,
679 * so never mind the rest (e.g. tags) (that much) */
680 GST_WARNING_OBJECT (qtdemux, "atom has bogus size %" G_GUINT64_FORMAT,
684 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
685 (_("This file is invalid and cannot be played.")),
686 ("atom has bogus size %" G_GUINT64_FORMAT, size));
687 return GST_FLOW_ERROR;
691 flow = gst_pad_pull_range (qtdemux->sinkpad, offset, size, buf);
693 if (G_UNLIKELY (flow != GST_FLOW_OK))
696 bsize = gst_buffer_get_size (*buf);
697 /* Catch short reads - we don't want any partial atoms */
698 if (G_UNLIKELY (bsize < size)) {
699 GST_WARNING_OBJECT (qtdemux,
700 "short read: %" G_GSIZE_FORMAT " < %" G_GUINT64_FORMAT, bsize, size);
701 gst_buffer_unref (*buf);
711 gst_qtdemux_src_convert (GstPad * pad, GstFormat src_format, gint64 src_value,
712 GstFormat dest_format, gint64 * dest_value)
715 QtDemuxStream *stream = gst_pad_get_element_private (pad);
716 GstQTDemux *qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
719 if (stream->subtype != FOURCC_vide) {
724 switch (src_format) {
725 case GST_FORMAT_TIME:
726 switch (dest_format) {
727 case GST_FORMAT_BYTES:{
728 index = gst_qtdemux_find_index_linear (qtdemux, stream, src_value);
732 *dest_value = stream->samples[index].offset;
734 GST_DEBUG_OBJECT (qtdemux, "Format Conversion Time->Offset :%"
735 GST_TIME_FORMAT "->%" G_GUINT64_FORMAT,
736 GST_TIME_ARGS (src_value), *dest_value);
744 case GST_FORMAT_BYTES:
745 switch (dest_format) {
746 case GST_FORMAT_TIME:{
748 gst_qtdemux_find_index_for_given_media_offset_linear (qtdemux,
755 QTSTREAMTIME_TO_GSTTIME (stream,
756 stream->samples[index].timestamp);
757 GST_DEBUG_OBJECT (qtdemux,
758 "Format Conversion Offset->Time :%" G_GUINT64_FORMAT "->%"
759 GST_TIME_FORMAT, src_value, GST_TIME_ARGS (*dest_value));
772 gst_object_unref (qtdemux);
779 gst_qtdemux_get_duration (GstQTDemux * qtdemux, GstClockTime * duration)
783 *duration = GST_CLOCK_TIME_NONE;
785 if (qtdemux->duration != 0) {
786 if (qtdemux->duration != G_MAXINT64 && qtdemux->timescale != 0) {
787 *duration = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
794 gst_qtdemux_handle_src_query (GstPad * pad, GstObject * parent,
797 gboolean res = FALSE;
798 GstQTDemux *qtdemux = GST_QTDEMUX (parent);
800 GST_LOG_OBJECT (pad, "%s query", GST_QUERY_TYPE_NAME (query));
802 switch (GST_QUERY_TYPE (query)) {
803 case GST_QUERY_POSITION:{
806 gst_query_parse_position (query, &fmt, NULL);
807 if (fmt == GST_FORMAT_TIME
808 && GST_CLOCK_TIME_IS_VALID (qtdemux->segment.position)) {
809 gst_query_set_position (query, GST_FORMAT_TIME,
810 qtdemux->segment.position);
815 case GST_QUERY_DURATION:{
818 gst_query_parse_duration (query, &fmt, NULL);
819 if (fmt == GST_FORMAT_TIME) {
820 /* First try to query upstream */
821 res = gst_pad_query_default (pad, parent, query);
824 if (gst_qtdemux_get_duration (qtdemux, &duration) && duration > 0) {
825 gst_query_set_duration (query, GST_FORMAT_TIME, duration);
832 case GST_QUERY_CONVERT:{
833 GstFormat src_fmt, dest_fmt;
834 gint64 src_value, dest_value = 0;
836 gst_query_parse_convert (query, &src_fmt, &src_value, &dest_fmt, NULL);
838 res = gst_qtdemux_src_convert (pad,
839 src_fmt, src_value, dest_fmt, &dest_value);
841 gst_query_set_convert (query, src_fmt, src_value, dest_fmt, dest_value);
846 case GST_QUERY_FORMATS:
847 gst_query_set_formats (query, 2, GST_FORMAT_TIME, GST_FORMAT_BYTES);
850 case GST_QUERY_SEEKING:{
854 /* try upstream first */
855 res = gst_pad_query_default (pad, parent, query);
858 gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
859 if (fmt == GST_FORMAT_TIME) {
860 GstClockTime duration = GST_CLOCK_TIME_NONE;
862 gst_qtdemux_get_duration (qtdemux, &duration);
864 if (!qtdemux->pullbased) {
867 /* we might be able with help from upstream */
869 q = gst_query_new_seeking (GST_FORMAT_BYTES);
870 if (gst_pad_peer_query (qtdemux->sinkpad, q)) {
871 gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL);
872 GST_LOG_OBJECT (qtdemux, "upstream BYTE seekable %d", seekable);
876 gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0, duration);
882 case GST_QUERY_SEGMENT:
887 format = qtdemux->segment.format;
890 gst_segment_to_stream_time (&qtdemux->segment, format,
891 qtdemux->segment.start);
892 if ((stop = qtdemux->segment.stop) == -1)
893 stop = qtdemux->segment.duration;
895 stop = gst_segment_to_stream_time (&qtdemux->segment, format, stop);
897 gst_query_set_segment (query, qtdemux->segment.rate, format, start, stop);
902 res = gst_pad_query_default (pad, parent, query);
910 gst_qtdemux_push_tags (GstQTDemux * qtdemux, QtDemuxStream * stream)
912 if (G_LIKELY (stream->pad)) {
913 GST_DEBUG_OBJECT (qtdemux, "Checking pad %s:%s for tags",
914 GST_DEBUG_PAD_NAME (stream->pad));
916 if (G_UNLIKELY (stream->pending_tags)) {
917 GST_DEBUG_OBJECT (qtdemux, "Sending tags %" GST_PTR_FORMAT,
918 stream->pending_tags);
919 gst_pad_push_event (stream->pad,
920 gst_event_new_tag (stream->pending_tags));
921 #ifdef GST_EXT_QTDEMUX_MODIFICATION
922 /* post message qtdemux tag (for early recive application) */
923 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
924 gst_message_new_tag (GST_OBJECT_CAST (qtdemux),
925 gst_tag_list_copy (stream->pending_tags)));
927 stream->pending_tags = NULL;
930 if (G_UNLIKELY (stream->send_global_tags && qtdemux->tag_list)) {
931 GST_DEBUG_OBJECT (qtdemux, "Sending global tags %" GST_PTR_FORMAT,
933 gst_pad_push_event (stream->pad,
934 gst_event_new_tag (gst_tag_list_ref (qtdemux->tag_list)));
935 stream->send_global_tags = FALSE;
940 /* push event on all source pads; takes ownership of the event */
942 gst_qtdemux_push_event (GstQTDemux * qtdemux, GstEvent * event)
945 gboolean has_valid_stream = FALSE;
946 GstEventType etype = GST_EVENT_TYPE (event);
948 GST_DEBUG_OBJECT (qtdemux, "pushing %s event on all source pads",
949 GST_EVENT_TYPE_NAME (event));
951 for (n = 0; n < qtdemux->n_streams; n++) {
953 QtDemuxStream *stream = qtdemux->streams[n];
954 GST_DEBUG_OBJECT (qtdemux, "pushing on pad %i", n);
956 if ((pad = stream->pad)) {
957 has_valid_stream = TRUE;
959 if (etype == GST_EVENT_EOS) {
960 /* let's not send twice */
961 if (stream->sent_eos)
963 stream->sent_eos = TRUE;
966 gst_pad_push_event (pad, gst_event_ref (event));
970 gst_event_unref (event);
972 /* if it is EOS and there are no pads, post an error */
973 if (!has_valid_stream && etype == GST_EVENT_EOS) {
974 gst_qtdemux_post_no_playable_stream_error (qtdemux);
978 /* push a pending newsegment event, if any from the streaming thread */
980 gst_qtdemux_push_pending_newsegment (GstQTDemux * qtdemux)
982 if (qtdemux->pending_newsegment) {
983 gst_qtdemux_push_event (qtdemux, qtdemux->pending_newsegment);
984 qtdemux->pending_newsegment = NULL;
994 find_func (QtDemuxSample * s1, guint64 * media_time, gpointer user_data)
996 if (s1->timestamp + s1->pts_offset > *media_time)
1002 /* find the index of the sample that includes the data for @media_time using a
1003 * binary search. Only to be called in optimized cases of linear search below.
1005 * Returns the index of the sample.
1008 gst_qtdemux_find_index (GstQTDemux * qtdemux, QtDemuxStream * str,
1011 QtDemuxSample *result;
1014 /* convert media_time to mov format */
1016 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
1018 result = gst_util_array_binary_search (str->samples, str->stbl_index + 1,
1019 sizeof (QtDemuxSample), (GCompareDataFunc) find_func,
1020 GST_SEARCH_MODE_BEFORE, &media_time, NULL);
1022 if (G_LIKELY (result))
1023 index = result - str->samples;
1032 /* find the index of the sample that includes the data for @media_offset using a
1035 * Returns the index of the sample.
1038 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
1039 QtDemuxStream * str, gint64 media_offset)
1041 QtDemuxSample *result = str->samples;
1044 if (result == NULL || str->n_samples == 0)
1047 if (media_offset == result->offset)
1051 while (index < str->n_samples - 1) {
1052 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
1055 if (media_offset < result->offset)
1066 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
1071 /* find the index of the sample that includes the data for @media_time using a
1072 * linear search, and keeping in mind that not all samples may have been parsed
1073 * yet. If possible, it will delegate to binary search.
1075 * Returns the index of the sample.
1078 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
1079 GstClockTime media_time)
1083 QtDemuxSample *sample;
1085 /* convert media_time to mov format */
1087 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
1089 sample = str->samples;
1090 if (mov_time == sample->timestamp + sample->pts_offset)
1093 /* use faster search if requested time in already parsed range */
1094 sample = str->samples + str->stbl_index;
1095 if (str->stbl_index >= 0 &&
1096 mov_time <= (sample->timestamp + sample->pts_offset))
1097 return gst_qtdemux_find_index (qtdemux, str, media_time);
1099 while (index < str->n_samples - 1) {
1100 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
1103 sample = str->samples + index + 1;
1104 if (mov_time < (sample->timestamp + sample->pts_offset))
1114 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
1119 /* find the index of the keyframe needed to decode the sample at @index
1122 * Returns the index of the keyframe.
1125 gst_qtdemux_find_keyframe (GstQTDemux * qtdemux, QtDemuxStream * str,
1128 guint32 new_index = index;
1130 if (index >= str->n_samples) {
1131 new_index = str->n_samples;
1135 /* all keyframes, return index */
1136 if (str->all_keyframe) {
1141 /* else go back until we have a keyframe */
1143 if (str->samples[new_index].keyframe)
1153 GST_DEBUG_OBJECT (qtdemux, "searching for keyframe index before index %u "
1154 "gave %u", index, new_index);
1159 /* find the segment for @time_position for @stream
1161 * Returns the index of the segment containing @time_position.
1162 * Returns the last segment and sets the @eos variable to TRUE
1163 * if the time is beyond the end. @eos may be NULL
1166 gst_qtdemux_find_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
1167 GstClockTime time_position)
1172 GST_LOG_OBJECT (stream->pad, "finding segment for %" GST_TIME_FORMAT,
1173 GST_TIME_ARGS (time_position));
1176 for (i = 0; i < stream->n_segments; i++) {
1177 QtDemuxSegment *segment = &stream->segments[i];
1179 GST_LOG_OBJECT (stream->pad,
1180 "looking at segment %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT,
1181 GST_TIME_ARGS (segment->time), GST_TIME_ARGS (segment->stop_time));
1183 /* For the last segment we include stop_time in the last segment */
1184 if (i < stream->n_segments - 1) {
1185 if (segment->time <= time_position && time_position < segment->stop_time) {
1186 GST_LOG_OBJECT (stream->pad, "segment %d matches", i);
1191 /* Last segment always matches */
1199 /* move the stream @str to the sample position @index.
1201 * Updates @str->sample_index and marks discontinuity if needed.
1204 gst_qtdemux_move_stream (GstQTDemux * qtdemux, QtDemuxStream * str,
1207 /* no change needed */
1208 if (index == str->sample_index)
1211 GST_DEBUG_OBJECT (qtdemux, "moving to sample %u of %u", index,
1214 /* position changed, we have a discont */
1215 str->sample_index = index;
1216 str->offset_in_sample = 0;
1217 /* Each time we move in the stream we store the position where we are
1219 str->from_sample = index;
1220 str->discont = TRUE;
1224 gst_qtdemux_adjust_seek (GstQTDemux * qtdemux, gint64 desired_time,
1225 gboolean use_sparse, gint64 * key_time, gint64 * key_offset)
1228 gint64 min_byte_offset = -1;
1231 min_offset = desired_time;
1233 /* for each stream, find the index of the sample in the segment
1234 * and move back to the previous keyframe. */
1235 for (n = 0; n < qtdemux->n_streams; n++) {
1237 guint32 index, kindex;
1239 GstClockTime media_start;
1240 GstClockTime media_time;
1241 GstClockTime seg_time;
1242 QtDemuxSegment *seg;
1244 str = qtdemux->streams[n];
1246 if (str->sparse && !use_sparse)
1249 seg_idx = gst_qtdemux_find_segment (qtdemux, str, desired_time);
1250 GST_DEBUG_OBJECT (qtdemux, "align segment %d", seg_idx);
1252 /* get segment and time in the segment */
1253 seg = &str->segments[seg_idx];
1254 seg_time = desired_time - seg->time;
1256 /* get the media time in the segment */
1257 media_start = seg->media_start + seg_time;
1259 /* get the index of the sample with media time */
1260 index = gst_qtdemux_find_index_linear (qtdemux, str, media_start);
1261 GST_DEBUG_OBJECT (qtdemux, "sample for %" GST_TIME_FORMAT " at %u"
1262 " at offset %" G_GUINT64_FORMAT,
1263 GST_TIME_ARGS (media_start), index, str->samples[index].offset);
1265 /* find previous keyframe */
1266 kindex = gst_qtdemux_find_keyframe (qtdemux, str, index);
1268 /* if the keyframe is at a different position, we need to update the
1269 * requested seek time */
1270 if (index != kindex) {
1273 /* get timestamp of keyframe */
1274 media_time = QTSAMPLE_DTS (str, &str->samples[kindex]);
1275 GST_DEBUG_OBJECT (qtdemux,
1276 "keyframe at %u with time %" GST_TIME_FORMAT " at offset %"
1277 G_GUINT64_FORMAT, kindex, GST_TIME_ARGS (media_time),
1278 str->samples[kindex].offset);
1280 /* keyframes in the segment get a chance to change the
1281 * desired_offset. keyframes out of the segment are
1283 if (media_time >= seg->media_start) {
1284 GstClockTime seg_time;
1286 /* this keyframe is inside the segment, convert back to
1288 seg_time = (media_time - seg->media_start) + seg->time;
1289 if (seg_time < min_offset)
1290 min_offset = seg_time;
1294 if (min_byte_offset < 0 || str->samples[index].offset < min_byte_offset)
1295 min_byte_offset = str->samples[index].offset;
1299 *key_time = min_offset;
1301 *key_offset = min_byte_offset;
1305 gst_qtdemux_convert_seek (GstPad * pad, GstFormat * format,
1306 GstSeekType cur_type, gint64 * cur, GstSeekType stop_type, gint64 * stop)
1310 g_return_val_if_fail (format != NULL, FALSE);
1311 g_return_val_if_fail (cur != NULL, FALSE);
1312 g_return_val_if_fail (stop != NULL, FALSE);
1314 if (*format == GST_FORMAT_TIME)
1318 if (cur_type != GST_SEEK_TYPE_NONE)
1319 res = gst_pad_query_convert (pad, *format, *cur, GST_FORMAT_TIME, cur);
1320 if (res && stop_type != GST_SEEK_TYPE_NONE)
1321 res = gst_pad_query_convert (pad, *format, *stop, GST_FORMAT_TIME, stop);
1324 *format = GST_FORMAT_TIME;
1329 /* perform seek in push based mode:
1330 find BYTE position to move to based on time and delegate to upstream
1333 gst_qtdemux_do_push_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1338 GstSeekType cur_type, stop_type;
1339 gint64 cur, stop, key_cur;
1342 gint64 original_stop;
1345 GST_DEBUG_OBJECT (qtdemux, "doing push-based seek");
1347 gst_event_parse_seek (event, &rate, &format, &flags,
1348 &cur_type, &cur, &stop_type, &stop);
1349 seqnum = gst_event_get_seqnum (event);
1351 /* only forward streaming and seeking is possible */
1353 goto unsupported_seek;
1355 /* convert to TIME if needed and possible */
1356 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1360 /* Upstream seek in bytes will have undefined stop, but qtdemux stores
1361 * the original stop position to use when upstream pushes the new segment
1363 original_stop = stop;
1366 /* find reasonable corresponding BYTE position,
1367 * also try to mind about keyframes, since we can not go back a bit for them
1369 gst_qtdemux_adjust_seek (qtdemux, cur, FALSE, &key_cur, &byte_cur);
1374 GST_DEBUG_OBJECT (qtdemux, "Pushing BYTE seek rate %g, "
1375 "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, byte_cur,
1378 GST_OBJECT_LOCK (qtdemux);
1379 qtdemux->seek_offset = byte_cur;
1380 if (!(flags & GST_SEEK_FLAG_KEY_UNIT)) {
1381 qtdemux->push_seek_start = cur;
1383 qtdemux->push_seek_start = key_cur;
1386 if (stop_type == GST_SEEK_TYPE_NONE) {
1387 qtdemux->push_seek_stop = qtdemux->segment.stop;
1389 qtdemux->push_seek_stop = original_stop;
1391 GST_OBJECT_UNLOCK (qtdemux);
1393 /* BYTE seek event */
1394 event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type, byte_cur,
1396 gst_event_set_seqnum (event, seqnum);
1397 res = gst_pad_push_event (qtdemux->sinkpad, event);
1404 GST_DEBUG_OBJECT (qtdemux, "could not determine byte position to seek to, "
1410 GST_DEBUG_OBJECT (qtdemux, "unsupported seek, seek aborted.");
1415 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1420 /* perform the seek.
1422 * We set all segment_indexes in the streams to unknown and
1423 * adjust the time_position to the desired position. this is enough
1424 * to trigger a segment switch in the streaming thread to start
1425 * streaming from the desired position.
1427 * Keyframe seeking is a little more complicated when dealing with
1428 * segments. Ideally we want to move to the previous keyframe in
1429 * the segment but there might not be a keyframe in the segment. In
1430 * fact, none of the segments could contain a keyframe. We take a
1431 * practical approach: seek to the previous keyframe in the segment,
1432 * if there is none, seek to the beginning of the segment.
1434 * Called with STREAM_LOCK
1437 gst_qtdemux_perform_seek (GstQTDemux * qtdemux, GstSegment * segment,
1438 guint32 seqnum, GstSeekFlags flags)
1440 gint64 desired_offset;
1443 desired_offset = segment->position;
1445 GST_DEBUG_OBJECT (qtdemux, "seeking to %" GST_TIME_FORMAT,
1446 GST_TIME_ARGS (desired_offset));
1448 /* may not have enough fragmented info to do this adjustment,
1449 * and we can't scan (and probably should not) at this time with
1450 * possibly flushing upstream */
1451 if ((flags & GST_SEEK_FLAG_KEY_UNIT) && !qtdemux->fragmented) {
1454 gst_qtdemux_adjust_seek (qtdemux, desired_offset, TRUE, &min_offset, NULL);
1455 GST_DEBUG_OBJECT (qtdemux, "keyframe seek, align to %"
1456 GST_TIME_FORMAT, GST_TIME_ARGS (min_offset));
1457 desired_offset = min_offset;
1460 /* and set all streams to the final position */
1461 gst_flow_combiner_reset (qtdemux->flowcombiner);
1462 for (n = 0; n < qtdemux->n_streams; n++) {
1463 QtDemuxStream *stream = qtdemux->streams[n];
1465 stream->time_position = desired_offset;
1466 stream->accumulated_base = 0;
1467 stream->sample_index = -1;
1468 stream->offset_in_sample = 0;
1469 stream->segment_index = -1;
1470 stream->sent_eos = FALSE;
1471 stream->segment_seqnum = seqnum;
1473 if (segment->flags & GST_SEEK_FLAG_FLUSH)
1474 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
1476 segment->position = desired_offset;
1477 segment->time = desired_offset;
1478 if (segment->rate >= 0) {
1479 segment->start = desired_offset;
1481 /* we stop at the end */
1482 if (segment->stop == -1)
1483 segment->stop = segment->duration;
1485 segment->stop = desired_offset;
1488 if (qtdemux->fragmented)
1489 qtdemux->fragmented_seek_pending = TRUE;
1494 /* do a seek in pull based mode */
1496 gst_qtdemux_do_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1501 GstSeekType cur_type, stop_type;
1505 GstSegment seeksegment;
1507 GstEvent *flush_event;
1510 GST_DEBUG_OBJECT (qtdemux, "doing seek with event");
1512 gst_event_parse_seek (event, &rate, &format, &flags,
1513 &cur_type, &cur, &stop_type, &stop);
1514 seqnum = gst_event_get_seqnum (event);
1516 /* we have to have a format as the segment format. Try to convert
1518 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1522 GST_DEBUG_OBJECT (qtdemux, "seek format %s", gst_format_get_name (format));
1524 GST_DEBUG_OBJECT (qtdemux, "doing seek without event");
1528 flush = flags & GST_SEEK_FLAG_FLUSH;
1530 /* stop streaming, either by flushing or by pausing the task */
1532 flush_event = gst_event_new_flush_start ();
1534 gst_event_set_seqnum (flush_event, seqnum);
1535 /* unlock upstream pull_range */
1536 gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event));
1537 /* make sure out loop function exits */
1538 gst_qtdemux_push_event (qtdemux, flush_event);
1540 /* non flushing seek, pause the task */
1541 gst_pad_pause_task (qtdemux->sinkpad);
1544 /* wait for streaming to finish */
1545 GST_PAD_STREAM_LOCK (qtdemux->sinkpad);
1547 /* copy segment, we need this because we still need the old
1548 * segment when we close the current segment. */
1549 memcpy (&seeksegment, &qtdemux->segment, sizeof (GstSegment));
1552 /* configure the segment with the seek variables */
1553 GST_DEBUG_OBJECT (qtdemux, "configuring seek");
1554 gst_segment_do_seek (&seeksegment, rate, format, flags,
1555 cur_type, cur, stop_type, stop, &update);
1558 /* now do the seek, this actually never returns FALSE */
1559 gst_qtdemux_perform_seek (qtdemux, &seeksegment, seqnum, flags);
1561 /* prepare for streaming again */
1563 flush_event = gst_event_new_flush_stop (TRUE);
1565 gst_event_set_seqnum (flush_event, seqnum);
1567 gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event));
1568 gst_qtdemux_push_event (qtdemux, flush_event);
1571 /* commit the new segment */
1572 memcpy (&qtdemux->segment, &seeksegment, sizeof (GstSegment));
1574 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
1575 GstMessage *msg = gst_message_new_segment_start (GST_OBJECT_CAST (qtdemux),
1576 qtdemux->segment.format, qtdemux->segment.position);
1578 gst_message_set_seqnum (msg, seqnum);
1579 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
1582 /* restart streaming, NEWSEGMENT will be sent from the streaming thread. */
1583 gst_pad_start_task (qtdemux->sinkpad, (GstTaskFunction) gst_qtdemux_loop,
1584 qtdemux->sinkpad, NULL);
1586 GST_PAD_STREAM_UNLOCK (qtdemux->sinkpad);
1593 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1599 qtdemux_ensure_index (GstQTDemux * qtdemux)
1603 GST_DEBUG_OBJECT (qtdemux, "collecting all metadata for all streams");
1605 /* Build complete index */
1606 for (i = 0; i < qtdemux->n_streams; i++) {
1607 QtDemuxStream *stream = qtdemux->streams[i];
1609 if (!qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1))
1617 GST_LOG_OBJECT (qtdemux,
1618 "Building complete index of stream %u for seeking failed!", i);
1624 gst_qtdemux_handle_src_event (GstPad * pad, GstObject * parent,
1627 gboolean res = TRUE;
1628 GstQTDemux *qtdemux = GST_QTDEMUX (parent);
1630 switch (GST_EVENT_TYPE (event)) {
1631 case GST_EVENT_SEEK:
1633 #ifndef GST_DISABLE_GST_DEBUG
1634 GstClockTime ts = gst_util_get_timestamp ();
1637 if (qtdemux->upstream_format_is_time && qtdemux->fragmented) {
1638 /* seek should be handled by upstream, we might need to re-download fragments */
1639 GST_DEBUG_OBJECT (qtdemux,
1640 "let upstream handle seek for fragmented playback");
1644 /* Build complete index for seeking;
1645 * if not a fragmented file at least */
1646 if (!qtdemux->fragmented)
1647 if (!qtdemux_ensure_index (qtdemux))
1649 #ifndef GST_DISABLE_GST_DEBUG
1650 ts = gst_util_get_timestamp () - ts;
1651 GST_INFO_OBJECT (qtdemux,
1652 "Time taken to parse index %" GST_TIME_FORMAT, GST_TIME_ARGS (ts));
1655 if (qtdemux->pullbased) {
1656 res = gst_qtdemux_do_seek (qtdemux, pad, event);
1657 } else if (gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (event))) {
1658 GST_DEBUG_OBJECT (qtdemux, "Upstream successfully seeked");
1660 } else if (qtdemux->state == QTDEMUX_STATE_MOVIE && qtdemux->n_streams
1661 && !qtdemux->fragmented) {
1662 res = gst_qtdemux_do_push_seek (qtdemux, pad, event);
1664 GST_DEBUG_OBJECT (qtdemux,
1665 "ignoring seek in push mode in current state");
1668 gst_event_unref (event);
1671 case GST_EVENT_NAVIGATION:
1673 gst_event_unref (event);
1677 res = gst_pad_event_default (pad, parent, event);
1687 GST_ERROR_OBJECT (qtdemux, "Index failed");
1688 gst_event_unref (event);
1694 /* stream/index return sample that is min/max w.r.t. byte position,
1695 * time is min/max w.r.t. time of samples,
1696 * the latter need not be time of the former sample */
1698 gst_qtdemux_find_sample (GstQTDemux * qtdemux, gint64 byte_pos, gboolean fw,
1699 gboolean set, QtDemuxStream ** _stream, gint * _index, gint64 * _time)
1702 gint64 time, min_time;
1703 QtDemuxStream *stream;
1709 for (n = 0; n < qtdemux->n_streams; ++n) {
1712 gboolean set_sample;
1714 str = qtdemux->streams[n];
1721 i = str->n_samples - 1;
1725 for (; (i >= 0) && (i < str->n_samples); i += inc) {
1726 if (str->samples[i].size == 0)
1729 if (fw && (str->samples[i].offset < byte_pos))
1732 if (!fw && (str->samples[i].offset + str->samples[i].size > byte_pos))
1735 /* move stream to first available sample */
1737 gst_qtdemux_move_stream (qtdemux, str, i);
1741 /* avoid index from sparse streams since they might be far away */
1743 /* determine min/max time */
1744 time = QTSAMPLE_PTS (str, &str->samples[i]);
1745 if (min_time == -1 || (!fw && time > min_time) ||
1746 (fw && time < min_time)) {
1750 /* determine stream with leading sample, to get its position */
1752 (fw && (str->samples[i].offset < stream->samples[index].offset)) ||
1753 (!fw && (str->samples[i].offset > stream->samples[index].offset))) {
1761 /* no sample for this stream, mark eos */
1763 gst_qtdemux_move_stream (qtdemux, str, str->n_samples);
1774 static QtDemuxStream *
1775 _create_stream (void)
1777 QtDemuxStream *stream;
1779 stream = g_new0 (QtDemuxStream, 1);
1780 /* new streams always need a discont */
1781 stream->discont = TRUE;
1782 /* we enable clipping for raw audio/video streams */
1783 stream->need_clip = FALSE;
1784 stream->need_process = FALSE;
1785 stream->segment_index = -1;
1786 stream->time_position = 0;
1787 stream->sample_index = -1;
1788 stream->offset_in_sample = 0;
1789 stream->new_stream = TRUE;
1790 stream->multiview_mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
1791 stream->multiview_flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
1792 stream->protected = FALSE;
1793 stream->protection_scheme_type = 0;
1794 stream->protection_scheme_version = 0;
1795 stream->protection_scheme_info = NULL;
1796 g_queue_init (&stream->protection_scheme_event_queue);
1801 gst_qtdemux_setcaps (GstQTDemux * demux, GstCaps * caps)
1803 GstStructure *structure;
1804 const gchar *variant;
1805 const GstCaps *mediacaps = NULL;
1807 GST_DEBUG_OBJECT (demux, "Sink set caps: %" GST_PTR_FORMAT, caps);
1809 structure = gst_caps_get_structure (caps, 0);
1810 variant = gst_structure_get_string (structure, "variant");
1812 if (variant && strcmp (variant, "mss-fragmented") == 0) {
1813 QtDemuxStream *stream;
1814 const GValue *value;
1816 demux->fragmented = TRUE;
1817 demux->mss_mode = TRUE;
1819 if (demux->n_streams > 1) {
1820 /* can't do this, we can only renegotiate for another mss format */
1824 value = gst_structure_get_value (structure, "media-caps");
1827 const GValue *timescale_v;
1829 /* TODO update when stream changes during playback */
1831 if (demux->n_streams == 0) {
1832 stream = _create_stream ();
1833 demux->streams[demux->n_streams] = stream;
1834 demux->n_streams = 1;
1836 stream = demux->streams[0];
1839 timescale_v = gst_structure_get_value (structure, "timescale");
1841 stream->timescale = g_value_get_uint64 (timescale_v);
1843 /* default mss timescale */
1844 stream->timescale = 10000000;
1846 demux->timescale = stream->timescale;
1848 mediacaps = gst_value_get_caps (value);
1849 if (!stream->caps || !gst_caps_is_equal_fixed (mediacaps, stream->caps)) {
1850 GST_DEBUG_OBJECT (demux, "We have a new caps %" GST_PTR_FORMAT,
1852 stream->new_caps = TRUE;
1854 gst_caps_replace (&stream->caps, (GstCaps *) mediacaps);
1855 structure = gst_caps_get_structure (mediacaps, 0);
1856 if (g_str_has_prefix (gst_structure_get_name (structure), "video")) {
1857 stream->subtype = FOURCC_vide;
1859 gst_structure_get_int (structure, "width", &stream->width);
1860 gst_structure_get_int (structure, "height", &stream->height);
1861 gst_structure_get_fraction (structure, "framerate", &stream->fps_n,
1863 } else if (g_str_has_prefix (gst_structure_get_name (structure), "audio")) {
1865 stream->subtype = FOURCC_soun;
1866 gst_structure_get_int (structure, "channels", &stream->n_channels);
1867 gst_structure_get_int (structure, "rate", &rate);
1868 stream->rate = rate;
1871 gst_caps_replace (&demux->media_caps, (GstCaps *) mediacaps);
1873 demux->mss_mode = FALSE;
1880 gst_qtdemux_reset (GstQTDemux * qtdemux, gboolean hard)
1884 GST_DEBUG_OBJECT (qtdemux, "Resetting demux");
1885 gst_pad_stop_task (qtdemux->sinkpad);
1887 if (hard || qtdemux->upstream_format_is_time) {
1888 qtdemux->state = QTDEMUX_STATE_INITIAL;
1889 qtdemux->neededbytes = 16;
1890 qtdemux->todrop = 0;
1891 qtdemux->pullbased = FALSE;
1892 qtdemux->posted_redirect = FALSE;
1893 qtdemux->first_mdat = -1;
1894 qtdemux->header_size = 0;
1895 qtdemux->mdatoffset = -1;
1896 qtdemux->restoredata_offset = -1;
1897 if (qtdemux->mdatbuffer)
1898 gst_buffer_unref (qtdemux->mdatbuffer);
1899 if (qtdemux->restoredata_buffer)
1900 gst_buffer_unref (qtdemux->restoredata_buffer);
1901 qtdemux->mdatbuffer = NULL;
1902 qtdemux->restoredata_buffer = NULL;
1903 qtdemux->mdatleft = 0;
1904 if (qtdemux->comp_brands)
1905 gst_buffer_unref (qtdemux->comp_brands);
1906 qtdemux->comp_brands = NULL;
1907 qtdemux->last_moov_offset = -1;
1908 if (qtdemux->moov_node)
1909 g_node_destroy (qtdemux->moov_node);
1910 qtdemux->moov_node = NULL;
1911 qtdemux->moov_node_compressed = NULL;
1912 if (qtdemux->tag_list)
1913 gst_mini_object_unref (GST_MINI_OBJECT_CAST (qtdemux->tag_list));
1914 qtdemux->tag_list = NULL;
1916 if (qtdemux->element_index)
1917 gst_object_unref (qtdemux->element_index);
1918 qtdemux->element_index = NULL;
1920 qtdemux->major_brand = 0;
1921 if (qtdemux->pending_newsegment)
1922 gst_event_unref (qtdemux->pending_newsegment);
1923 qtdemux->pending_newsegment = NULL;
1924 qtdemux->upstream_format_is_time = FALSE;
1925 qtdemux->upstream_seekable = FALSE;
1926 qtdemux->upstream_size = 0;
1928 qtdemux->fragment_start = -1;
1929 qtdemux->fragment_start_offset = -1;
1930 qtdemux->duration = 0;
1931 qtdemux->moof_offset = 0;
1932 qtdemux->chapters_track_id = 0;
1933 qtdemux->have_group_id = FALSE;
1934 qtdemux->group_id = G_MAXUINT;
1936 if (qtdemux->protection_system_ids) {
1937 g_ptr_array_free (qtdemux->protection_system_ids, TRUE);
1938 qtdemux->protection_system_ids = NULL;
1940 g_queue_foreach (&qtdemux->protection_event_queue, (GFunc) gst_event_unref,
1942 g_queue_clear (&qtdemux->protection_event_queue);
1944 qtdemux->offset = 0;
1945 gst_adapter_clear (qtdemux->adapter);
1946 gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
1949 for (n = 0; n < qtdemux->n_streams; n++) {
1950 gst_qtdemux_stream_free (qtdemux, qtdemux->streams[n]);
1951 qtdemux->streams[n] = NULL;
1953 qtdemux->n_streams = 0;
1954 qtdemux->n_video_streams = 0;
1955 qtdemux->n_audio_streams = 0;
1956 qtdemux->n_sub_streams = 0;
1957 qtdemux->exposed = FALSE;
1958 qtdemux->fragmented = FALSE;
1959 qtdemux->mss_mode = FALSE;
1960 gst_caps_replace (&qtdemux->media_caps, NULL);
1961 qtdemux->timescale = 0;
1962 qtdemux->got_moov = FALSE;
1963 } else if (qtdemux->mss_mode) {
1964 gst_flow_combiner_reset (qtdemux->flowcombiner);
1965 for (n = 0; n < qtdemux->n_streams; n++)
1966 gst_qtdemux_stream_clear (qtdemux, qtdemux->streams[n]);
1968 gst_flow_combiner_reset (qtdemux->flowcombiner);
1969 for (n = 0; n < qtdemux->n_streams; n++) {
1970 qtdemux->streams[n]->sent_eos = FALSE;
1971 qtdemux->streams[n]->segment_seqnum = 0;
1972 qtdemux->streams[n]->time_position = 0;
1973 qtdemux->streams[n]->accumulated_base = 0;
1979 gst_qtdemux_handle_sink_event (GstPad * sinkpad, GstObject * parent,
1982 GstQTDemux *demux = GST_QTDEMUX (parent);
1983 gboolean res = TRUE;
1985 GST_LOG_OBJECT (demux, "handling %s event", GST_EVENT_TYPE_NAME (event));
1987 switch (GST_EVENT_TYPE (event)) {
1988 case GST_EVENT_SEGMENT:
1991 QtDemuxStream *stream;
1994 GstEvent *segment_event;
1996 /* some debug output */
1997 gst_event_copy_segment (event, &segment);
1998 GST_DEBUG_OBJECT (demux, "received newsegment %" GST_SEGMENT_FORMAT,
2001 if (segment.format == GST_FORMAT_TIME) {
2002 GST_DEBUG_OBJECT (demux, "new pending_newsegment");
2003 gst_event_replace (&demux->pending_newsegment, event);
2004 demux->upstream_format_is_time = TRUE;
2006 GST_DEBUG_OBJECT (demux, "Not storing upstream newsegment, "
2007 "not in time format");
2009 /* chain will send initial newsegment after pads have been added */
2010 if (demux->state != QTDEMUX_STATE_MOVIE || !demux->n_streams) {
2011 GST_DEBUG_OBJECT (demux, "still starting, eating event");
2016 /* check if this matches a time seek we received previously
2017 * FIXME for backwards compatibility reasons we use the
2018 * seek_offset here to compare. In the future we might want to
2019 * change this to use the seqnum as it uniquely should identify
2020 * the segment that corresponds to the seek. */
2021 GST_DEBUG_OBJECT (demux, "Stored seek offset: %" G_GINT64_FORMAT
2022 ", received segment offset %" G_GINT64_FORMAT,
2023 demux->seek_offset, segment.start);
2024 if (segment.format == GST_FORMAT_BYTES
2025 && demux->seek_offset == segment.start) {
2026 GST_OBJECT_LOCK (demux);
2027 offset = segment.start;
2029 segment.format = GST_FORMAT_TIME;
2030 segment.start = demux->push_seek_start;
2031 segment.stop = demux->push_seek_stop;
2032 GST_DEBUG_OBJECT (demux, "Replaced segment with stored seek "
2033 "segment %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT,
2034 GST_TIME_ARGS (segment.start), GST_TIME_ARGS (segment.stop));
2035 GST_OBJECT_UNLOCK (demux);
2038 /* we only expect a BYTE segment, e.g. following a seek */
2039 if (segment.format == GST_FORMAT_BYTES) {
2040 if (GST_CLOCK_TIME_IS_VALID (segment.start)) {
2041 offset = segment.start;
2043 gst_qtdemux_find_sample (demux, segment.start, TRUE, FALSE, NULL,
2044 NULL, (gint64 *) & segment.start);
2045 if ((gint64) segment.start < 0)
2048 if (GST_CLOCK_TIME_IS_VALID (segment.stop)) {
2049 gst_qtdemux_find_sample (demux, segment.stop, FALSE, FALSE, NULL,
2050 NULL, (gint64 *) & segment.stop);
2051 /* keyframe seeking should already arrange for start >= stop,
2052 * but make sure in other rare cases */
2053 segment.stop = MAX (segment.stop, segment.start);
2055 } else if (segment.format == GST_FORMAT_TIME) {
2056 /* push all data on the adapter before starting this
2058 gst_qtdemux_process_adapter (demux, TRUE);
2060 GST_DEBUG_OBJECT (demux, "unsupported segment format, ignoring");
2064 /* accept upstream's notion of segment and distribute along */
2065 segment.format = GST_FORMAT_TIME;
2066 segment.position = segment.time = segment.start;
2067 segment.duration = demux->segment.duration;
2068 segment.base = gst_segment_to_running_time (&demux->segment,
2069 GST_FORMAT_TIME, demux->segment.position);
2071 gst_segment_copy_into (&segment, &demux->segment);
2072 GST_DEBUG_OBJECT (demux, "Pushing newseg %" GST_SEGMENT_FORMAT, &segment);
2073 segment_event = gst_event_new_segment (&segment);
2074 gst_event_set_seqnum (segment_event, gst_event_get_seqnum (event));
2075 gst_qtdemux_push_event (demux, segment_event);
2077 /* clear leftover in current segment, if any */
2078 gst_adapter_clear (demux->adapter);
2080 /* set up streaming thread */
2081 demux->offset = offset;
2082 if (demux->upstream_format_is_time) {
2083 GST_DEBUG_OBJECT (demux, "Upstream is driving in time format, "
2084 "set values to restart reading from a new atom");
2085 demux->neededbytes = 16;
2088 gst_qtdemux_find_sample (demux, offset, TRUE, TRUE, &stream, &idx,
2091 demux->todrop = stream->samples[idx].offset - offset;
2092 demux->neededbytes = demux->todrop + stream->samples[idx].size;
2094 /* set up for EOS */
2095 demux->neededbytes = -1;
2100 gst_event_unref (event);
2104 case GST_EVENT_FLUSH_STOP:
2108 dur = demux->segment.duration;
2109 gst_qtdemux_reset (demux, FALSE);
2110 demux->segment.duration = dur;
2114 /* If we are in push mode, and get an EOS before we've seen any streams,
2115 * then error out - we have nowhere to send the EOS */
2116 if (!demux->pullbased) {
2118 gboolean has_valid_stream = FALSE;
2119 for (i = 0; i < demux->n_streams; i++) {
2120 if (demux->streams[i]->pad != NULL) {
2121 has_valid_stream = TRUE;
2125 if (!has_valid_stream)
2126 gst_qtdemux_post_no_playable_stream_error (demux);
2128 GST_DEBUG_OBJECT (demux, "Data still available after EOS: %u",
2129 (guint) gst_adapter_available (demux->adapter));
2130 if (gst_qtdemux_process_adapter (demux, TRUE) != GST_FLOW_OK) {
2136 case GST_EVENT_CAPS:{
2137 GstCaps *caps = NULL;
2139 gst_event_parse_caps (event, &caps);
2140 gst_qtdemux_setcaps (demux, caps);
2142 gst_event_unref (event);
2145 case GST_EVENT_PROTECTION:
2147 const gchar *system_id = NULL;
2149 gst_event_parse_protection (event, &system_id, NULL, NULL);
2150 GST_DEBUG_OBJECT (demux, "Received protection event for system ID %s",
2152 gst_qtdemux_append_protection_system_id (demux, system_id);
2153 /* save the event for later, for source pads that have not been created */
2154 g_queue_push_tail (&demux->protection_event_queue, gst_event_ref (event));
2155 /* send it to all pads that already exist */
2156 gst_qtdemux_push_event (demux, event);
2164 res = gst_pad_event_default (demux->sinkpad, parent, event) & res;
2172 gst_qtdemux_set_index (GstElement * element, GstIndex * index)
2174 GstQTDemux *demux = GST_QTDEMUX (element);
2176 GST_OBJECT_LOCK (demux);
2177 if (demux->element_index)
2178 gst_object_unref (demux->element_index);
2180 demux->element_index = gst_object_ref (index);
2182 demux->element_index = NULL;
2184 GST_OBJECT_UNLOCK (demux);
2185 /* object lock might be taken again */
2187 gst_index_get_writer_id (index, GST_OBJECT (element), &demux->index_id);
2188 GST_DEBUG_OBJECT (demux, "Set index %" GST_PTR_FORMAT "for writer id %d",
2189 demux->element_index, demux->index_id);
2193 gst_qtdemux_get_index (GstElement * element)
2195 GstIndex *result = NULL;
2196 GstQTDemux *demux = GST_QTDEMUX (element);
2198 GST_OBJECT_LOCK (demux);
2199 if (demux->element_index)
2200 result = gst_object_ref (demux->element_index);
2201 GST_OBJECT_UNLOCK (demux);
2203 GST_DEBUG_OBJECT (demux, "Returning index %" GST_PTR_FORMAT, result);
2210 gst_qtdemux_stbl_free (QtDemuxStream * stream)
2212 g_free ((gpointer) stream->stco.data);
2213 stream->stco.data = NULL;
2214 g_free ((gpointer) stream->stsz.data);
2215 stream->stsz.data = NULL;
2216 g_free ((gpointer) stream->stsc.data);
2217 stream->stsc.data = NULL;
2218 g_free ((gpointer) stream->stts.data);
2219 stream->stts.data = NULL;
2220 g_free ((gpointer) stream->stss.data);
2221 stream->stss.data = NULL;
2222 g_free ((gpointer) stream->stps.data);
2223 stream->stps.data = NULL;
2224 g_free ((gpointer) stream->ctts.data);
2225 stream->ctts.data = NULL;
2229 gst_qtdemux_stream_flush_segments_data (GstQTDemux * qtdemux,
2230 QtDemuxStream * stream)
2232 g_free (stream->segments);
2233 stream->segments = NULL;
2234 stream->segment_index = -1;
2235 stream->accumulated_base = 0;
2239 gst_qtdemux_stream_flush_samples_data (GstQTDemux * qtdemux,
2240 QtDemuxStream * stream)
2242 g_free (stream->samples);
2243 stream->samples = NULL;
2244 gst_qtdemux_stbl_free (stream);
2247 g_free (stream->ra_entries);
2248 stream->ra_entries = NULL;
2249 stream->n_ra_entries = 0;
2251 stream->sample_index = -1;
2252 stream->stbl_index = -1;
2253 stream->n_samples = 0;
2254 stream->time_position = 0;
2258 gst_qtdemux_stream_clear (GstQTDemux * qtdemux, QtDemuxStream * stream)
2260 if (stream->allocator)
2261 gst_object_unref (stream->allocator);
2262 while (stream->buffers) {
2263 gst_buffer_unref (GST_BUFFER_CAST (stream->buffers->data));
2264 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
2266 if (stream->rgb8_palette) {
2267 gst_memory_unref (stream->rgb8_palette);
2268 stream->rgb8_palette = NULL;
2271 if (stream->pending_tags)
2272 gst_tag_list_unref (stream->pending_tags);
2273 stream->pending_tags = NULL;
2274 g_free (stream->redirect_uri);
2275 stream->redirect_uri = NULL;
2276 stream->sent_eos = FALSE;
2277 stream->sparse = FALSE;
2278 stream->protected = FALSE;
2279 if (stream->protection_scheme_info) {
2280 if (stream->protection_scheme_type == FOURCC_cenc) {
2281 QtDemuxCencSampleSetInfo *info =
2282 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
2283 if (info->default_properties)
2284 gst_structure_free (info->default_properties);
2285 if (info->crypto_info)
2286 g_ptr_array_free (info->crypto_info, TRUE);
2288 g_free (stream->protection_scheme_info);
2289 stream->protection_scheme_info = NULL;
2291 stream->protection_scheme_type = 0;
2292 stream->protection_scheme_version = 0;
2293 g_queue_foreach (&stream->protection_scheme_event_queue,
2294 (GFunc) gst_event_unref, NULL);
2295 g_queue_clear (&stream->protection_scheme_event_queue);
2296 gst_qtdemux_stream_flush_segments_data (qtdemux, stream);
2297 gst_qtdemux_stream_flush_samples_data (qtdemux, stream);
2301 gst_qtdemux_stream_free (GstQTDemux * qtdemux, QtDemuxStream * stream)
2303 gst_qtdemux_stream_clear (qtdemux, stream);
2305 gst_caps_unref (stream->caps);
2306 stream->caps = NULL;
2308 gst_element_remove_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
2309 gst_flow_combiner_remove_pad (qtdemux->flowcombiner, stream->pad);
2315 gst_qtdemux_remove_stream (GstQTDemux * qtdemux, int i)
2317 g_assert (i >= 0 && i < qtdemux->n_streams && qtdemux->streams[i] != NULL);
2319 gst_qtdemux_stream_free (qtdemux, qtdemux->streams[i]);
2320 qtdemux->streams[i] = qtdemux->streams[qtdemux->n_streams - 1];
2321 qtdemux->streams[qtdemux->n_streams - 1] = NULL;
2322 qtdemux->n_streams--;
2325 static GstStateChangeReturn
2326 gst_qtdemux_change_state (GstElement * element, GstStateChange transition)
2328 GstQTDemux *qtdemux = GST_QTDEMUX (element);
2329 GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
2331 switch (transition) {
2332 case GST_STATE_CHANGE_PAUSED_TO_READY:
2338 result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
2340 switch (transition) {
2341 case GST_STATE_CHANGE_PAUSED_TO_READY:{
2342 gst_qtdemux_reset (qtdemux, TRUE);
2353 qtdemux_parse_ftyp (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2355 /* counts as header data */
2356 qtdemux->header_size += length;
2358 /* only consider at least a sufficiently complete ftyp atom */
2362 qtdemux->major_brand = QT_FOURCC (buffer + 8);
2363 GST_DEBUG_OBJECT (qtdemux, "major brand: %" GST_FOURCC_FORMAT,
2364 GST_FOURCC_ARGS (qtdemux->major_brand));
2365 buf = qtdemux->comp_brands = gst_buffer_new_and_alloc (length - 16);
2366 gst_buffer_fill (buf, 0, buffer + 16, length - 16);
2371 qtdemux_handle_xmp_taglist (GstQTDemux * qtdemux, GstTagList * taglist,
2372 GstTagList * xmptaglist)
2374 /* Strip out bogus fields */
2376 if (gst_tag_list_get_scope (taglist) == GST_TAG_SCOPE_GLOBAL) {
2377 gst_tag_list_remove_tag (xmptaglist, GST_TAG_VIDEO_CODEC);
2378 gst_tag_list_remove_tag (xmptaglist, GST_TAG_AUDIO_CODEC);
2380 gst_tag_list_remove_tag (xmptaglist, GST_TAG_CONTAINER_FORMAT);
2383 GST_DEBUG_OBJECT (qtdemux, "Found XMP tags %" GST_PTR_FORMAT, xmptaglist);
2385 /* prioritize native tags using _KEEP mode */
2386 gst_tag_list_insert (taglist, xmptaglist, GST_TAG_MERGE_KEEP);
2387 gst_tag_list_unref (xmptaglist);
2392 qtdemux_parse_uuid (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2394 static const guint8 xmp_uuid[] = { 0xBE, 0x7A, 0xCF, 0xCB,
2395 0x97, 0xA9, 0x42, 0xE8,
2396 0x9C, 0x71, 0x99, 0x94,
2397 0x91, 0xE3, 0xAF, 0xAC
2399 static const guint8 playready_uuid[] = {
2400 0xd0, 0x8a, 0x4f, 0x18, 0x10, 0xf3, 0x4a, 0x82,
2401 0xb6, 0xc8, 0x32, 0xd8, 0xab, 0xa1, 0x83, 0xd3
2405 /* counts as header data */
2406 qtdemux->header_size += length;
2408 offset = (QT_UINT32 (buffer) == 0) ? 16 : 8;
2410 if (length <= offset + 16) {
2411 GST_DEBUG_OBJECT (qtdemux, "uuid atom is too short, skipping");
2415 if (memcmp (buffer + offset, xmp_uuid, 16) == 0) {
2417 GstTagList *taglist;
2419 buf = _gst_buffer_new_wrapped ((guint8 *) buffer + offset + 16,
2420 length - offset - 16, NULL);
2421 taglist = gst_tag_list_from_xmp_buffer (buf);
2422 gst_buffer_unref (buf);
2424 qtdemux_handle_xmp_taglist (qtdemux, qtdemux->tag_list, taglist);
2426 } else if (memcmp (buffer + offset, playready_uuid, 16) == 0) {
2428 const gunichar2 *s_utf16;
2431 len = GST_READ_UINT16_LE (buffer + offset + 0x30);
2432 s_utf16 = (const gunichar2 *) (buffer + offset + 0x32);
2433 contents = g_utf16_to_utf8 (s_utf16, len / 2, NULL, NULL, NULL);
2434 GST_ERROR_OBJECT (qtdemux, "contents: %s", contents);
2438 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT,
2439 (_("Cannot play stream because it is encrypted with PlayReady DRM.")),
2442 GST_DEBUG_OBJECT (qtdemux, "Ignoring unknown uuid: %08x-%08x-%08x-%08x",
2443 GST_READ_UINT32_LE (buffer + offset),
2444 GST_READ_UINT32_LE (buffer + offset + 4),
2445 GST_READ_UINT32_LE (buffer + offset + 8),
2446 GST_READ_UINT32_LE (buffer + offset + 12));
2451 qtdemux_parse_sidx (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2453 GstSidxParser sidx_parser;
2454 GstIsoffParserResult res;
2457 gst_isoff_qt_sidx_parser_init (&sidx_parser);
2460 gst_isoff_qt_sidx_parser_add_data (&sidx_parser, buffer, length,
2462 GST_DEBUG_OBJECT (qtdemux, "sidx parse result: %d", res);
2463 if (res == GST_ISOFF_QT_PARSER_DONE) {
2464 check_update_duration (qtdemux, sidx_parser.cumulative_pts);
2466 gst_isoff_qt_sidx_parser_clear (&sidx_parser);
2469 /* caller verifies at least 8 bytes in buf */
2471 extract_initial_length_and_fourcc (const guint8 * data, guint size,
2472 guint64 * plength, guint32 * pfourcc)
2477 length = QT_UINT32 (data);
2478 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
2479 fourcc = QT_FOURCC (data + 4);
2480 GST_DEBUG ("atom type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
2483 length = G_MAXUINT64;
2484 } else if (length == 1 && size >= 16) {
2485 /* this means we have an extended size, which is the 64 bit value of
2486 * the next 8 bytes */
2487 length = QT_UINT64 (data + 8);
2488 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
2498 qtdemux_parse_mehd (GstQTDemux * qtdemux, GstByteReader * br)
2500 guint32 version = 0;
2501 GstClockTime duration = 0;
2503 if (!gst_byte_reader_get_uint32_be (br, &version))
2508 if (!gst_byte_reader_get_uint64_be (br, &duration))
2513 if (!gst_byte_reader_get_uint32_be (br, &dur))
2518 GST_INFO_OBJECT (qtdemux, "mehd duration: %" G_GUINT64_FORMAT, duration);
2519 qtdemux->duration = duration;
2525 GST_DEBUG_OBJECT (qtdemux, "parsing mehd failed");
2531 qtdemux_parse_trex (GstQTDemux * qtdemux, QtDemuxStream * stream,
2532 guint32 * ds_duration, guint32 * ds_size, guint32 * ds_flags)
2534 if (!stream->parsed_trex && qtdemux->moov_node) {
2536 GstByteReader trex_data;
2538 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
2540 trex = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_trex,
2543 guint32 id = 0, dur = 0, size = 0, flags = 0, dummy = 0;
2545 /* skip version/flags */
2546 if (!gst_byte_reader_skip (&trex_data, 4))
2548 if (!gst_byte_reader_get_uint32_be (&trex_data, &id))
2550 if (id != stream->track_id)
2552 /* sample description index; ignore */
2553 if (!gst_byte_reader_get_uint32_be (&trex_data, &dummy))
2555 if (!gst_byte_reader_get_uint32_be (&trex_data, &dur))
2557 if (!gst_byte_reader_get_uint32_be (&trex_data, &size))
2559 if (!gst_byte_reader_get_uint32_be (&trex_data, &flags))
2562 GST_DEBUG_OBJECT (qtdemux, "fragment defaults for stream %d; "
2563 "duration %d, size %d, flags 0x%x", stream->track_id,
2566 stream->parsed_trex = TRUE;
2567 stream->def_sample_duration = dur;
2568 stream->def_sample_size = size;
2569 stream->def_sample_flags = flags;
2572 /* iterate all siblings */
2573 trex = qtdemux_tree_get_sibling_by_type_full (trex, FOURCC_trex,
2579 *ds_duration = stream->def_sample_duration;
2580 *ds_size = stream->def_sample_size;
2581 *ds_flags = stream->def_sample_flags;
2583 /* even then, above values are better than random ... */
2584 if (G_UNLIKELY (!stream->parsed_trex)) {
2585 GST_WARNING_OBJECT (qtdemux,
2586 "failed to find fragment defaults for stream %d", stream->track_id);
2593 /* This method should be called whenever a more accurate duration might
2594 * have been found. It will update all relevant variables if/where needed
2597 check_update_duration (GstQTDemux * qtdemux, GstClockTime duration)
2601 GstClockTime prevdur;
2603 movdur = GSTTIME_TO_QTTIME (qtdemux, duration);
2605 if (movdur > qtdemux->duration) {
2606 prevdur = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
2607 GST_DEBUG_OBJECT (qtdemux,
2608 "Updating total duration to %" GST_TIME_FORMAT " was %" GST_TIME_FORMAT,
2609 GST_TIME_ARGS (duration), GST_TIME_ARGS (prevdur));
2610 qtdemux->duration = movdur;
2611 GST_DEBUG_OBJECT (qtdemux,
2612 "qtdemux->segment.duration: %" GST_TIME_FORMAT " .stop: %"
2613 GST_TIME_FORMAT, GST_TIME_ARGS (qtdemux->segment.duration),
2614 GST_TIME_ARGS (qtdemux->segment.stop));
2615 if (qtdemux->segment.duration == prevdur) {
2616 /* If the current segment has duration/stop identical to previous duration
2617 * update them also (because they were set at that point in time with
2618 * the wrong duration */
2619 /* We convert the value *from* the timescale version to avoid rounding errors */
2620 GstClockTime fixeddur = QTTIME_TO_GSTTIME (qtdemux, movdur);
2621 GST_DEBUG_OBJECT (qtdemux, "Updated segment.duration and segment.stop");
2622 qtdemux->segment.duration = fixeddur;
2623 qtdemux->segment.stop = fixeddur;
2626 for (i = 0; i < qtdemux->n_streams; i++) {
2627 QtDemuxStream *stream = qtdemux->streams[i];
2629 movdur = GSTTIME_TO_QTSTREAMTIME (stream, duration);
2630 if (movdur > stream->duration) {
2631 GST_DEBUG_OBJECT (qtdemux,
2632 "Updating stream #%d duration to %" GST_TIME_FORMAT, i,
2633 GST_TIME_ARGS (duration));
2634 stream->duration = movdur;
2635 if (stream->dummy_segment) {
2636 /* Update all dummy values to new duration */
2637 stream->segments[0].stop_time = duration;
2638 stream->segments[0].duration = duration;
2639 stream->segments[0].media_stop = duration;
2647 qtdemux_parse_trun (GstQTDemux * qtdemux, GstByteReader * trun,
2648 QtDemuxStream * stream, guint32 d_sample_duration, guint32 d_sample_size,
2649 guint32 d_sample_flags, gint64 moof_offset, gint64 moof_length,
2650 gint64 * base_offset, gint64 * running_offset, gint64 decode_ts)
2652 GstClockTime gst_ts = GST_CLOCK_TIME_NONE;
2654 gint32 data_offset = 0;
2655 guint32 flags = 0, first_flags = 0, samples_count = 0;
2658 guint entry_size, dur_offset, size_offset, flags_offset = 0, ct_offset = 0;
2659 QtDemuxSample *sample;
2660 gboolean ismv = FALSE;
2662 GST_LOG_OBJECT (qtdemux, "parsing trun stream %d; "
2663 "default dur %d, size %d, flags 0x%x, base offset %" G_GINT64_FORMAT ", "
2664 "decode ts %" G_GINT64_FORMAT, stream->track_id, d_sample_duration,
2665 d_sample_size, d_sample_flags, *base_offset, decode_ts);
2667 if (stream->pending_seek && moof_offset < stream->pending_seek->moof_offset) {
2668 GST_INFO_OBJECT (stream->pad, "skipping trun before seek target fragment");
2672 /* presence of stss or not can't really tell us much,
2673 * and flags and so on tend to be marginally reliable in these files */
2674 if (stream->subtype == FOURCC_soun) {
2675 GST_DEBUG_OBJECT (qtdemux,
2676 "sound track in fragmented file; marking all keyframes");
2677 stream->all_keyframe = TRUE;
2680 if (!gst_byte_reader_skip (trun, 1) ||
2681 !gst_byte_reader_get_uint24_be (trun, &flags))
2684 if (!gst_byte_reader_get_uint32_be (trun, &samples_count))
2687 if (flags & TR_DATA_OFFSET) {
2688 /* note this is really signed */
2689 if (!gst_byte_reader_get_int32_be (trun, &data_offset))
2691 GST_LOG_OBJECT (qtdemux, "trun data offset %d", data_offset);
2692 /* default base offset = first byte of moof */
2693 if (*base_offset == -1) {
2694 GST_LOG_OBJECT (qtdemux, "base_offset at moof");
2695 *base_offset = moof_offset;
2697 *running_offset = *base_offset + data_offset;
2699 /* if no offset at all, that would mean data starts at moof start,
2700 * which is a bit wrong and is ismv crappy way, so compensate
2701 * assuming data is in mdat following moof */
2702 if (*base_offset == -1) {
2703 *base_offset = moof_offset + moof_length + 8;
2704 GST_LOG_OBJECT (qtdemux, "base_offset assumed in mdat after moof");
2707 if (*running_offset == -1)
2708 *running_offset = *base_offset;
2711 GST_LOG_OBJECT (qtdemux, "running offset now %" G_GINT64_FORMAT,
2713 GST_LOG_OBJECT (qtdemux, "trun offset %d, flags 0x%x, entries %d",
2714 data_offset, flags, samples_count);
2716 if (flags & TR_FIRST_SAMPLE_FLAGS) {
2717 if (G_UNLIKELY (flags & TR_SAMPLE_FLAGS)) {
2718 GST_DEBUG_OBJECT (qtdemux,
2719 "invalid flags; SAMPLE and FIRST_SAMPLE present, discarding latter");
2720 flags ^= TR_FIRST_SAMPLE_FLAGS;
2722 if (!gst_byte_reader_get_uint32_be (trun, &first_flags))
2724 GST_LOG_OBJECT (qtdemux, "first flags: 0x%x", first_flags);
2728 /* FIXME ? spec says other bits should also be checked to determine
2729 * entry size (and prefix size for that matter) */
2731 dur_offset = size_offset = 0;
2732 if (flags & TR_SAMPLE_DURATION) {
2733 GST_LOG_OBJECT (qtdemux, "entry duration present");
2734 dur_offset = entry_size;
2737 if (flags & TR_SAMPLE_SIZE) {
2738 GST_LOG_OBJECT (qtdemux, "entry size present");
2739 size_offset = entry_size;
2742 if (flags & TR_SAMPLE_FLAGS) {
2743 GST_LOG_OBJECT (qtdemux, "entry flags present");
2744 flags_offset = entry_size;
2747 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
2748 GST_LOG_OBJECT (qtdemux, "entry ct offset present");
2749 ct_offset = entry_size;
2753 if (!qt_atom_parser_has_chunks (trun, samples_count, entry_size))
2755 data = (guint8 *) gst_byte_reader_peek_data_unchecked (trun);
2757 if (stream->n_samples + samples_count >=
2758 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample))
2761 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
2762 stream->n_samples + samples_count, (guint) sizeof (QtDemuxSample),
2763 (stream->n_samples + samples_count) *
2764 sizeof (QtDemuxSample) / (1024.0 * 1024.0));
2766 /* create a new array of samples if it's the first sample parsed */
2767 if (stream->n_samples == 0) {
2768 g_assert (stream->samples == NULL);
2769 stream->samples = g_try_new0 (QtDemuxSample, samples_count);
2770 /* or try to reallocate it with space enough to insert the new samples */
2772 stream->samples = g_try_renew (QtDemuxSample, stream->samples,
2773 stream->n_samples + samples_count);
2774 if (stream->samples == NULL)
2777 if (qtdemux->fragment_start != -1) {
2778 timestamp = GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->fragment_start);
2779 qtdemux->fragment_start = -1;
2781 if (stream->n_samples == 0) {
2782 if (decode_ts > 0) {
2783 timestamp = decode_ts;
2784 } else if (stream->pending_seek != NULL) {
2785 /* if we don't have a timestamp from a tfdt box, we'll use the one
2786 * from the mfra seek table */
2787 GST_INFO_OBJECT (stream->pad, "pending seek ts = %" GST_TIME_FORMAT,
2788 GST_TIME_ARGS (stream->pending_seek->ts));
2790 /* FIXME: this is not fully correct, the timestamp refers to the random
2791 * access sample refered to in the tfra entry, which may not necessarily
2792 * be the first sample in the tfrag/trun (but hopefully/usually is) */
2793 timestamp = GSTTIME_TO_QTSTREAMTIME (stream, stream->pending_seek->ts);
2798 gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
2799 GST_INFO_OBJECT (stream->pad, "first sample ts %" GST_TIME_FORMAT,
2800 GST_TIME_ARGS (gst_ts));
2802 /* subsequent fragments extend stream */
2804 stream->samples[stream->n_samples - 1].timestamp +
2805 stream->samples[stream->n_samples - 1].duration;
2807 gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
2808 GST_INFO_OBJECT (qtdemux, "first sample ts %" GST_TIME_FORMAT
2809 " (extends previous samples)", GST_TIME_ARGS (gst_ts));
2813 sample = stream->samples + stream->n_samples;
2814 for (i = 0; i < samples_count; i++) {
2815 guint32 dur, size, sflags, ct;
2817 /* first read sample data */
2818 if (flags & TR_SAMPLE_DURATION) {
2819 dur = QT_UINT32 (data + dur_offset);
2821 dur = d_sample_duration;
2823 if (flags & TR_SAMPLE_SIZE) {
2824 size = QT_UINT32 (data + size_offset);
2826 size = d_sample_size;
2828 if (flags & TR_FIRST_SAMPLE_FLAGS) {
2830 sflags = first_flags;
2832 sflags = d_sample_flags;
2834 } else if (flags & TR_SAMPLE_FLAGS) {
2835 sflags = QT_UINT32 (data + flags_offset);
2837 sflags = d_sample_flags;
2839 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
2840 ct = QT_UINT32 (data + ct_offset);
2846 /* fill the sample information */
2847 sample->offset = *running_offset;
2848 sample->pts_offset = ct;
2849 sample->size = size;
2850 sample->timestamp = timestamp;
2851 sample->duration = dur;
2852 /* sample-is-difference-sample */
2853 /* ismv seems to use 0x40 for keyframe, 0xc0 for non-keyframe,
2854 * now idea how it relates to bitfield other than massive LE/BE confusion */
2855 sample->keyframe = ismv ? ((sflags & 0xff) == 0x40) : !(sflags & 0x10000);
2856 *running_offset += size;
2861 /* Update total duration if needed */
2862 check_update_duration (qtdemux, QTSTREAMTIME_TO_GSTTIME (stream, timestamp));
2864 stream->n_samples += samples_count;
2866 if (stream->pending_seek != NULL)
2867 stream->pending_seek = NULL;
2873 GST_WARNING_OBJECT (qtdemux, "failed to parse trun");
2878 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
2884 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
2885 "be larger than %uMB (broken file?)", stream->n_samples,
2886 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
2891 /* find stream with @id */
2892 static inline QtDemuxStream *
2893 qtdemux_find_stream (GstQTDemux * qtdemux, guint32 id)
2895 QtDemuxStream *stream;
2899 if (G_UNLIKELY (!id)) {
2900 GST_DEBUG_OBJECT (qtdemux, "invalid track id 0");
2904 /* try to get it fast and simple */
2905 if (G_LIKELY (id <= qtdemux->n_streams)) {
2906 stream = qtdemux->streams[id - 1];
2907 if (G_LIKELY (stream->track_id == id))
2911 /* linear search otherwise */
2912 for (i = 0; i < qtdemux->n_streams; i++) {
2913 stream = qtdemux->streams[i];
2914 if (stream->track_id == id)
2917 if (qtdemux->mss_mode) {
2918 /* mss should have only 1 stream anyway */
2919 return qtdemux->streams[0];
2926 qtdemux_parse_mfhd (GstQTDemux * qtdemux, GstByteReader * mfhd,
2927 guint32 * fragment_number)
2929 if (!gst_byte_reader_skip (mfhd, 4))
2931 if (!gst_byte_reader_get_uint32_be (mfhd, fragment_number))
2936 GST_WARNING_OBJECT (qtdemux, "Failed to parse mfhd atom");
2942 qtdemux_parse_tfhd (GstQTDemux * qtdemux, GstByteReader * tfhd,
2943 QtDemuxStream ** stream, guint32 * default_sample_duration,
2944 guint32 * default_sample_size, guint32 * default_sample_flags,
2945 gint64 * base_offset)
2948 guint32 track_id = 0;
2950 if (!gst_byte_reader_skip (tfhd, 1) ||
2951 !gst_byte_reader_get_uint24_be (tfhd, &flags))
2954 if (!gst_byte_reader_get_uint32_be (tfhd, &track_id))
2957 *stream = qtdemux_find_stream (qtdemux, track_id);
2958 if (G_UNLIKELY (!*stream))
2959 goto unknown_stream;
2961 if (flags & TF_DEFAULT_BASE_IS_MOOF)
2962 *base_offset = qtdemux->moof_offset;
2964 if (flags & TF_BASE_DATA_OFFSET)
2965 if (!gst_byte_reader_get_uint64_be (tfhd, (guint64 *) base_offset))
2968 /* obtain stream defaults */
2969 qtdemux_parse_trex (qtdemux, *stream,
2970 default_sample_duration, default_sample_size, default_sample_flags);
2972 /* FIXME: Handle TF_SAMPLE_DESCRIPTION_INDEX properly */
2973 if (flags & TF_SAMPLE_DESCRIPTION_INDEX)
2974 if (!gst_byte_reader_skip (tfhd, 4))
2977 if (flags & TF_DEFAULT_SAMPLE_DURATION)
2978 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_duration))
2981 if (flags & TF_DEFAULT_SAMPLE_SIZE)
2982 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_size))
2985 if (flags & TF_DEFAULT_SAMPLE_FLAGS)
2986 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_flags))
2993 GST_WARNING_OBJECT (qtdemux, "invalid track fragment header");
2998 GST_DEBUG_OBJECT (qtdemux, "unknown stream in tfhd");
3004 qtdemux_parse_tfdt (GstQTDemux * qtdemux, GstByteReader * br,
3005 guint64 * decode_time)
3007 guint32 version = 0;
3009 if (!gst_byte_reader_get_uint32_be (br, &version))
3014 if (!gst_byte_reader_get_uint64_be (br, decode_time))
3017 guint32 dec_time = 0;
3018 if (!gst_byte_reader_get_uint32_be (br, &dec_time))
3020 *decode_time = dec_time;
3023 GST_INFO_OBJECT (qtdemux, "Track fragment decode time: %" G_GUINT64_FORMAT,
3030 GST_DEBUG_OBJECT (qtdemux, "parsing tfdt failed");
3035 /* Returns a pointer to a GstStructure containing the properties of
3036 * the stream sample identified by @sample_index. The caller must unref
3037 * the returned object after use. Returns NULL if unsuccessful. */
3038 static GstStructure *
3039 qtdemux_get_cenc_sample_properties (GstQTDemux * qtdemux,
3040 QtDemuxStream * stream, guint sample_index)
3042 QtDemuxCencSampleSetInfo *info = NULL;
3044 g_return_val_if_fail (stream != NULL, NULL);
3045 g_return_val_if_fail (stream->protected, NULL);
3046 g_return_val_if_fail (stream->protection_scheme_info != NULL, NULL);
3048 info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
3050 /* Currently, cenc properties for groups of samples are not supported, so
3051 * simply return a copy of the default sample properties */
3052 return gst_structure_copy (info->default_properties);
3055 /* Parses the sizes of sample auxiliary information contained within a stream,
3056 * as given in a saiz box. Returns array of sample_count guint8 size values,
3057 * or NULL on failure */
3059 qtdemux_parse_saiz (GstQTDemux * qtdemux, QtDemuxStream * stream,
3060 GstByteReader * br, guint32 * sample_count)
3064 guint8 default_info_size;
3066 g_return_val_if_fail (qtdemux != NULL, NULL);
3067 g_return_val_if_fail (stream != NULL, NULL);
3068 g_return_val_if_fail (br != NULL, NULL);
3069 g_return_val_if_fail (sample_count != NULL, NULL);
3071 if (!gst_byte_reader_get_uint32_be (br, &flags))
3075 /* aux_info_type and aux_info_type_parameter are ignored */
3076 if (!gst_byte_reader_skip (br, 8))
3080 if (!gst_byte_reader_get_uint8 (br, &default_info_size))
3082 GST_DEBUG_OBJECT (qtdemux, "default_info_size: %u", default_info_size);
3084 if (!gst_byte_reader_get_uint32_be (br, sample_count))
3086 GST_DEBUG_OBJECT (qtdemux, "sample_count: %u", *sample_count);
3089 if (default_info_size == 0) {
3090 if (!gst_byte_reader_dup_data (br, *sample_count, &info_sizes)) {
3094 info_sizes = g_new (guint8, *sample_count);
3095 memset (info_sizes, default_info_size, *sample_count);
3101 /* Parses the offset of sample auxiliary information contained within a stream,
3102 * as given in a saio box. Returns TRUE if successful; FALSE otherwise. */
3104 qtdemux_parse_saio (GstQTDemux * qtdemux, QtDemuxStream * stream,
3105 GstByteReader * br, guint32 * info_type, guint32 * info_type_parameter,
3110 guint32 aux_info_type = 0;
3111 guint32 aux_info_type_parameter = 0;
3112 guint32 entry_count;
3116 g_return_val_if_fail (qtdemux != NULL, FALSE);
3117 g_return_val_if_fail (stream != NULL, FALSE);
3118 g_return_val_if_fail (br != NULL, FALSE);
3119 g_return_val_if_fail (offset != NULL, FALSE);
3121 if (!gst_byte_reader_get_uint8 (br, &version))
3124 if (!gst_byte_reader_get_uint24_be (br, &flags))
3128 if (!gst_byte_reader_get_uint32_be (br, &aux_info_type))
3130 if (!gst_byte_reader_get_uint32_be (br, &aux_info_type_parameter))
3132 } else if (stream->protected) {
3133 aux_info_type = stream->protection_scheme_type;
3135 aux_info_type = stream->fourcc;
3139 *info_type = aux_info_type;
3140 if (info_type_parameter)
3141 *info_type_parameter = aux_info_type_parameter;
3143 GST_DEBUG_OBJECT (qtdemux, "aux_info_type: '%" GST_FOURCC_FORMAT "', "
3144 "aux_info_type_parameter: %#06x",
3145 GST_FOURCC_ARGS (aux_info_type), aux_info_type_parameter);
3147 if (!gst_byte_reader_get_uint32_be (br, &entry_count))
3150 if (entry_count != 1) {
3151 GST_ERROR_OBJECT (qtdemux, "multiple offsets are not supported");
3156 if (!gst_byte_reader_get_uint32_be (br, &off_32))
3158 *offset = (guint64) off_32;
3160 if (!gst_byte_reader_get_uint64_be (br, &off_64))
3165 GST_DEBUG_OBJECT (qtdemux, "offset: %" G_GUINT64_FORMAT, *offset);
3170 qtdemux_gst_structure_free (GstStructure * gststructure)
3173 gst_structure_free (gststructure);
3177 /* Parses auxiliary information relating to samples protected using Common
3178 * Encryption (cenc); the format of this information is defined in
3179 * ISO/IEC 23001-7. Returns TRUE if successful; FALSE otherwise. */
3181 qtdemux_parse_cenc_aux_info (GstQTDemux * qtdemux, QtDemuxStream * stream,
3182 GstByteReader * br, guint8 * info_sizes, guint32 sample_count)
3184 QtDemuxCencSampleSetInfo *ss_info = NULL;
3188 g_return_val_if_fail (qtdemux != NULL, FALSE);
3189 g_return_val_if_fail (stream != NULL, FALSE);
3190 g_return_val_if_fail (br != NULL, FALSE);
3191 g_return_val_if_fail (stream->protected, FALSE);
3192 g_return_val_if_fail (stream->protection_scheme_info != NULL, FALSE);
3194 ss_info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
3196 if (ss_info->crypto_info) {
3197 GST_LOG_OBJECT (qtdemux, "unreffing existing crypto_info");
3198 g_ptr_array_free (ss_info->crypto_info, TRUE);
3201 ss_info->crypto_info =
3202 g_ptr_array_new_full (sample_count,
3203 (GDestroyNotify) qtdemux_gst_structure_free);
3205 for (i = 0; i < sample_count; ++i) {
3206 GstStructure *properties;
3207 guint16 n_subsamples;
3212 properties = qtdemux_get_cenc_sample_properties (qtdemux, stream, i);
3213 if (properties == NULL) {
3214 GST_ERROR_OBJECT (qtdemux, "failed to get properties for sample %u", i);
3217 if (!gst_structure_get_uint (properties, "iv_size", &iv_size)) {
3218 GST_ERROR_OBJECT (qtdemux, "failed to get iv_size for sample %u", i);
3219 gst_structure_free (properties);
3222 if (!gst_byte_reader_dup_data (br, iv_size, &data)) {
3223 GST_ERROR_OBJECT (qtdemux, "failed to get IV for sample %u", i);
3224 gst_structure_free (properties);
3227 buf = gst_buffer_new_wrapped (data, iv_size);
3228 gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL);
3229 size = info_sizes[i];
3230 if (size > iv_size) {
3231 if (!gst_byte_reader_get_uint16_be (br, &n_subsamples)
3232 || !(n_subsamples > 0)) {
3233 gst_structure_free (properties);
3234 GST_ERROR_OBJECT (qtdemux,
3235 "failed to get subsample count for sample %u", i);
3238 GST_LOG_OBJECT (qtdemux, "subsample count: %u", n_subsamples);
3239 if (!gst_byte_reader_dup_data (br, n_subsamples * 6, &data)) {
3240 GST_ERROR_OBJECT (qtdemux, "failed to get subsample data for sample %u",
3242 gst_structure_free (properties);
3245 buf = gst_buffer_new_wrapped (data, n_subsamples * 6);
3247 gst_structure_free (properties);
3250 gst_structure_set (properties,
3251 "subsample_count", G_TYPE_UINT, n_subsamples,
3252 "subsamples", GST_TYPE_BUFFER, buf, NULL);
3254 gst_structure_set (properties, "subsample_count", G_TYPE_UINT, 0, NULL);
3256 g_ptr_array_add (ss_info->crypto_info, properties);
3261 /* Converts a UUID in raw byte form to a string representation, as defined in
3262 * RFC 4122. The caller takes ownership of the returned string and is
3263 * responsible for freeing it after use. */
3265 qtdemux_uuid_bytes_to_string (gconstpointer uuid_bytes)
3267 const guint8 *uuid = (const guint8 *) uuid_bytes;
3269 return g_strdup_printf ("%02x%02x%02x%02x-%02x%02x-%02x%02x-"
3270 "%02x%02x-%02x%02x%02x%02x%02x%02x",
3271 uuid[0], uuid[1], uuid[2], uuid[3],
3272 uuid[4], uuid[5], uuid[6], uuid[7],
3273 uuid[8], uuid[9], uuid[10], uuid[11],
3274 uuid[12], uuid[13], uuid[14], uuid[15]);
3277 /* Parses a Protection System Specific Header box (pssh), as defined in the
3278 * Common Encryption (cenc) standard (ISO/IEC 23001-7), which contains
3279 * information needed by a specific content protection system in order to
3280 * decrypt cenc-protected tracks. Returns TRUE if successful; FALSE
3283 qtdemux_parse_pssh (GstQTDemux * qtdemux, GNode * node)
3285 gchar *sysid_string;
3286 guint32 pssh_size = QT_UINT32 (node->data);
3287 GstBuffer *pssh = NULL;
3288 GstEvent *event = NULL;
3289 guint32 parent_box_type;
3292 if (G_UNLIKELY (pssh_size < 32U)) {
3293 GST_ERROR_OBJECT (qtdemux, "invalid box size");
3298 qtdemux_uuid_bytes_to_string ((const guint8 *) node->data + 12);
3300 gst_qtdemux_append_protection_system_id (qtdemux, sysid_string);
3302 pssh = gst_buffer_new_wrapped (g_memdup (node->data, pssh_size), pssh_size);
3303 GST_LOG_OBJECT (qtdemux, "cenc pssh size: %" G_GSIZE_FORMAT,
3304 gst_buffer_get_size (pssh));
3306 parent_box_type = QT_FOURCC ((const guint8 *) node->parent->data + 4);
3308 /* Push an event containing the pssh box onto the queues of all streams. */
3309 event = gst_event_new_protection (sysid_string, pssh,
3310 (parent_box_type == FOURCC_moov) ? "isobmff/moov" : "isobmff/moof");
3311 for (i = 0; i < qtdemux->n_streams; ++i) {
3312 g_queue_push_tail (&qtdemux->streams[i]->protection_scheme_event_queue,
3313 gst_event_ref (event));
3315 g_free (sysid_string);
3316 gst_event_unref (event);
3317 gst_buffer_unref (pssh);
3322 qtdemux_parse_moof (GstQTDemux * qtdemux, const guint8 * buffer, guint length,
3323 guint64 moof_offset, QtDemuxStream * stream)
3325 GNode *moof_node, *traf_node, *tfhd_node, *trun_node, *tfdt_node, *mfhd_node;
3326 GstByteReader mfhd_data, trun_data, tfhd_data, tfdt_data;
3327 GNode *saiz_node, *saio_node, *pssh_node;
3328 GstByteReader saiz_data, saio_data;
3329 guint32 ds_size = 0, ds_duration = 0, ds_flags = 0;
3330 gint64 base_offset, running_offset;
3333 /* NOTE @stream ignored */
3335 moof_node = g_node_new ((guint8 *) buffer);
3336 qtdemux_parse_node (qtdemux, moof_node, buffer, length);
3337 qtdemux_node_dump (qtdemux, moof_node);
3339 /* Get fragment number from mfhd and check it's valid */
3341 qtdemux_tree_get_child_by_type_full (moof_node, FOURCC_mfhd, &mfhd_data);
3342 if (mfhd_node == NULL)
3344 if (!qtdemux_parse_mfhd (qtdemux, &mfhd_data, &frag_num))
3346 GST_DEBUG_OBJECT (qtdemux, "Fragment #%d", frag_num);
3348 /* unknown base_offset to start with */
3349 base_offset = running_offset = -1;
3350 traf_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_traf);
3352 guint64 decode_time = 0;
3354 /* Fragment Header node */
3356 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfhd,
3360 if (!qtdemux_parse_tfhd (qtdemux, &tfhd_data, &stream, &ds_duration,
3361 &ds_size, &ds_flags, &base_offset))
3364 /* The following code assumes at most a single set of sample auxiliary
3365 * data in the fragment (consisting of a saiz box and a corresponding saio
3366 * box); in theory, however, there could be multiple sets of sample
3367 * auxiliary data in a fragment. */
3369 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saiz,
3373 guint32 sample_count;
3374 guint32 info_type = 0;
3376 guint32 info_type_parameter = 0;
3378 info_sizes = qtdemux_parse_saiz (qtdemux, stream, &saiz_data,
3380 if (G_UNLIKELY (info_sizes == NULL)) {
3381 GST_ERROR_OBJECT (qtdemux, "failed to parse saiz box");
3385 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saio,
3388 GST_ERROR_OBJECT (qtdemux, "saiz box without a corresponding saio box");
3392 if (G_UNLIKELY (!qtdemux_parse_saio (qtdemux, stream, &saio_data,
3393 &info_type, &info_type_parameter, &offset))) {
3394 GST_ERROR_OBJECT (qtdemux, "failed to parse saio box");
3395 g_free (info_sizes);
3398 if (base_offset > qtdemux->moof_offset)
3399 offset += (guint64) (base_offset - qtdemux->moof_offset);
3400 if (info_type == FOURCC_cenc && info_type_parameter == 0U) {
3402 if (offset > length) {
3403 GST_ERROR_OBJECT (qtdemux, "cenc auxiliary info outside moof "
3404 "boxes is not supported");
3405 g_free (info_sizes);
3408 gst_byte_reader_init (&br, buffer + offset, length - offset);
3409 if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
3410 info_sizes, sample_count)) {
3411 GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
3415 g_free (info_sizes);
3419 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfdt,
3422 GstClockTime decode_time_ts;
3424 /* We'll use decode_time to interpolate timestamps
3425 * in case the input timestamps are missing */
3426 qtdemux_parse_tfdt (qtdemux, &tfdt_data, &decode_time);
3428 decode_time_ts = QTSTREAMTIME_TO_GSTTIME (stream, decode_time);
3430 GST_DEBUG_OBJECT (qtdemux, "decode time %" G_GINT64_FORMAT
3431 " (%" GST_TIME_FORMAT ")", decode_time,
3432 GST_TIME_ARGS (decode_time_ts));
3434 /* Discard the fragment buffer timestamp info to avoid using it.
3435 * Rely on tfdt instead as it is more accurate than the timestamp
3436 * that is fetched from a manifest/playlist and is usually
3438 qtdemux->fragment_start = -1;
3441 if (G_UNLIKELY (!stream)) {
3442 /* we lost track of offset, we'll need to regain it,
3443 * but can delay complaining until later or avoid doing so altogether */
3447 if (G_UNLIKELY (base_offset < -1))
3450 if (qtdemux->upstream_format_is_time)
3451 gst_qtdemux_stream_flush_samples_data (qtdemux, stream);
3453 /* Track Run node */
3455 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_trun,
3458 qtdemux_parse_trun (qtdemux, &trun_data, stream,
3459 ds_duration, ds_size, ds_flags, moof_offset, length, &base_offset,
3460 &running_offset, decode_time);
3461 /* iterate all siblings */
3462 trun_node = qtdemux_tree_get_sibling_by_type_full (trun_node, FOURCC_trun,
3465 /* if no new base_offset provided for next traf,
3466 * base is end of current traf */
3467 base_offset = running_offset;
3468 running_offset = -1;
3470 /* iterate all siblings */
3471 traf_node = qtdemux_tree_get_sibling_by_type (traf_node, FOURCC_traf);
3474 /* parse any protection system info */
3475 pssh_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_pssh);
3477 GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
3478 qtdemux_parse_pssh (qtdemux, pssh_node);
3479 pssh_node = qtdemux_tree_get_sibling_by_type (pssh_node, FOURCC_pssh);
3482 g_node_destroy (moof_node);
3487 GST_DEBUG_OBJECT (qtdemux, "missing tfhd box");
3492 GST_DEBUG_OBJECT (qtdemux, "Missing mfhd box");
3497 GST_DEBUG_OBJECT (qtdemux, "lost offset");
3502 g_node_destroy (moof_node);
3503 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
3504 (_("This file is corrupt and cannot be played.")), (NULL));
3510 /* might be used if some day we actually use mfra & co
3511 * for random access to fragments,
3512 * but that will require quite some modifications and much less relying
3513 * on a sample array */
3517 qtdemux_parse_tfra (GstQTDemux * qtdemux, GNode * tfra_node)
3519 QtDemuxStream *stream;
3520 guint32 ver_flags, track_id, len, num_entries, i;
3521 guint value_size, traf_size, trun_size, sample_size;
3522 guint64 time = 0, moof_offset = 0;
3524 GstBuffer *buf = NULL;
3529 gst_byte_reader_init (&tfra, tfra_node->data, QT_UINT32 (tfra_node->data));
3531 if (!gst_byte_reader_skip (&tfra, 8))
3534 if (!gst_byte_reader_get_uint32_be (&tfra, &ver_flags))
3537 if (!gst_byte_reader_get_uint32_be (&tfra, &track_id)
3538 || !gst_byte_reader_get_uint32_be (&tfra, &len)
3539 || !gst_byte_reader_get_uint32_be (&tfra, &num_entries))
3542 GST_DEBUG_OBJECT (qtdemux, "parsing tfra box for track id %u", track_id);
3544 stream = qtdemux_find_stream (qtdemux, track_id);
3546 goto unknown_trackid;
3548 value_size = ((ver_flags >> 24) == 1) ? sizeof (guint64) : sizeof (guint32);
3549 sample_size = (len & 3) + 1;
3550 trun_size = ((len & 12) >> 2) + 1;
3551 traf_size = ((len & 48) >> 4) + 1;
3553 GST_DEBUG_OBJECT (qtdemux, "%u entries, sizes: value %u, traf %u, trun %u, "
3554 "sample %u", num_entries, value_size, traf_size, trun_size, sample_size);
3556 if (num_entries == 0)
3559 if (!qt_atom_parser_has_chunks (&tfra, num_entries,
3560 value_size + value_size + traf_size + trun_size + sample_size))
3563 g_free (stream->ra_entries);
3564 stream->ra_entries = g_new (QtDemuxRandomAccessEntry, num_entries);
3565 stream->n_ra_entries = num_entries;
3567 for (i = 0; i < num_entries; i++) {
3568 qt_atom_parser_get_offset (&tfra, value_size, &time);
3569 qt_atom_parser_get_offset (&tfra, value_size, &moof_offset);
3570 qt_atom_parser_get_uint_with_size_unchecked (&tfra, traf_size);
3571 qt_atom_parser_get_uint_with_size_unchecked (&tfra, trun_size);
3572 qt_atom_parser_get_uint_with_size_unchecked (&tfra, sample_size);
3574 time = QTSTREAMTIME_TO_GSTTIME (stream, time);
3576 GST_LOG_OBJECT (qtdemux, "fragment time: %" GST_TIME_FORMAT ", "
3577 " moof_offset: %" G_GUINT64_FORMAT, GST_TIME_ARGS (time), moof_offset);
3579 stream->ra_entries[i].ts = time;
3580 stream->ra_entries[i].moof_offset = moof_offset;
3582 /* don't want to go through the entire file and read all moofs at startup */
3584 ret = gst_qtdemux_pull_atom (qtdemux, moof_offset, 0, &buf);
3585 if (ret != GST_FLOW_OK)
3587 qtdemux_parse_moof (qtdemux, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf),
3588 moof_offset, stream);
3589 gst_buffer_unref (buf);
3593 check_update_duration (qtdemux, time);
3600 GST_WARNING_OBJECT (qtdemux, "Couldn't find stream for track %u", track_id);
3605 GST_WARNING_OBJECT (qtdemux, "broken traf box, ignoring");
3610 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
3616 qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux)
3618 GstMapInfo mfro_map = GST_MAP_INFO_INIT;
3619 GstMapInfo mfra_map = GST_MAP_INFO_INIT;
3620 GstBuffer *mfro = NULL, *mfra = NULL;
3622 gboolean ret = FALSE;
3623 GNode *mfra_node, *tfra_node;
3624 guint64 mfra_offset = 0;
3625 guint32 fourcc, mfra_size;
3628 /* query upstream size in bytes */
3629 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &len))
3630 goto size_query_failed;
3632 /* mfro box should be at the very end of the file */
3633 flow = gst_qtdemux_pull_atom (qtdemux, len - 16, 16, &mfro);
3634 if (flow != GST_FLOW_OK)
3637 gst_buffer_map (mfro, &mfro_map, GST_MAP_READ);
3639 fourcc = QT_FOURCC (mfro_map.data + 4);
3640 if (fourcc != FOURCC_mfro)
3643 GST_INFO_OBJECT (qtdemux, "Found mfro box");
3644 if (mfro_map.size < 16)
3645 goto invalid_mfro_size;
3647 mfra_size = QT_UINT32 (mfro_map.data + 12);
3648 if (mfra_size >= len)
3649 goto invalid_mfra_size;
3651 mfra_offset = len - mfra_size;
3653 GST_INFO_OBJECT (qtdemux, "mfra offset: %" G_GUINT64_FORMAT ", size %u",
3654 mfra_offset, mfra_size);
3656 /* now get and parse mfra box */
3657 flow = gst_qtdemux_pull_atom (qtdemux, mfra_offset, mfra_size, &mfra);
3658 if (flow != GST_FLOW_OK)
3661 gst_buffer_map (mfra, &mfra_map, GST_MAP_READ);
3663 mfra_node = g_node_new ((guint8 *) mfra_map.data);
3664 qtdemux_parse_node (qtdemux, mfra_node, mfra_map.data, mfra_map.size);
3666 tfra_node = qtdemux_tree_get_child_by_type (mfra_node, FOURCC_tfra);
3669 qtdemux_parse_tfra (qtdemux, tfra_node);
3670 /* iterate all siblings */
3671 tfra_node = qtdemux_tree_get_sibling_by_type (tfra_node, FOURCC_tfra);
3673 g_node_destroy (mfra_node);
3675 GST_INFO_OBJECT (qtdemux, "parsed movie fragment random access box (mfra)");
3681 if (mfro_map.memory != NULL)
3682 gst_buffer_unmap (mfro, &mfro_map);
3683 gst_buffer_unref (mfro);
3686 if (mfra_map.memory != NULL)
3687 gst_buffer_unmap (mfra, &mfra_map);
3688 gst_buffer_unref (mfra);
3695 GST_WARNING_OBJECT (qtdemux, "could not query upstream size");
3700 GST_WARNING_OBJECT (qtdemux, "mfro size is too small");
3705 GST_WARNING_OBJECT (qtdemux, "mfra_size in mfro box is invalid");
3710 GST_WARNING_OBJECT (qtdemux, "bogus mfra offset or size, broken file");
3716 add_offset (guint64 offset, guint64 advance)
3718 /* Avoid 64-bit overflow by clamping */
3719 if (offset > G_MAXUINT64 - advance)
3721 return offset + advance;
3724 static GstFlowReturn
3725 gst_qtdemux_loop_state_header (GstQTDemux * qtdemux)
3729 GstBuffer *buf = NULL;
3730 GstFlowReturn ret = GST_FLOW_OK;
3731 guint64 cur_offset = qtdemux->offset;
3734 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, 16, &buf);
3735 if (G_UNLIKELY (ret != GST_FLOW_OK))
3737 gst_buffer_map (buf, &map, GST_MAP_READ);
3738 if (G_LIKELY (map.size >= 8))
3739 extract_initial_length_and_fourcc (map.data, map.size, &length, &fourcc);
3740 gst_buffer_unmap (buf, &map);
3741 gst_buffer_unref (buf);
3743 /* maybe we already got most we needed, so only consider this eof */
3744 if (G_UNLIKELY (length == 0)) {
3745 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
3746 (_("Invalid atom size.")),
3747 ("Header atom '%" GST_FOURCC_FORMAT "' has empty length",
3748 GST_FOURCC_ARGS (fourcc)));
3755 /* record for later parsing when needed */
3756 if (!qtdemux->moof_offset) {
3757 qtdemux->moof_offset = qtdemux->offset;
3759 if (qtdemux_pull_mfro_mfra (qtdemux)) {
3762 qtdemux->offset += length; /* skip moof and keep going */
3764 if (qtdemux->got_moov) {
3765 GST_INFO_OBJECT (qtdemux, "moof header, got moov, done with headers");
3776 GST_LOG_OBJECT (qtdemux,
3777 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
3778 GST_FOURCC_ARGS (fourcc), cur_offset);
3779 qtdemux->offset = add_offset (qtdemux->offset, length);
3784 GstBuffer *moov = NULL;
3786 if (qtdemux->got_moov) {
3787 GST_DEBUG_OBJECT (qtdemux, "Skipping moov atom as we have one already");
3788 qtdemux->offset = add_offset (qtdemux->offset, length);
3792 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, length, &moov);
3793 if (ret != GST_FLOW_OK)
3795 gst_buffer_map (moov, &map, GST_MAP_READ);
3797 if (length != map.size) {
3798 /* Some files have a 'moov' atom at the end of the file which contains
3799 * a terminal 'free' atom where the body of the atom is missing.
3800 * Check for, and permit, this special case.
3802 if (map.size >= 8) {
3803 guint8 *final_data = map.data + (map.size - 8);
3804 guint32 final_length = QT_UINT32 (final_data);
3805 guint32 final_fourcc = QT_FOURCC (final_data + 4);
3807 if (final_fourcc == FOURCC_free
3808 && map.size + final_length - 8 == length) {
3809 /* Ok, we've found that special case. Allocate a new buffer with
3810 * that free atom actually present. */
3811 GstBuffer *newmoov = gst_buffer_new_and_alloc (length);
3812 gst_buffer_fill (newmoov, 0, map.data, map.size);
3813 gst_buffer_memset (newmoov, map.size, 0, final_length - 8);
3814 gst_buffer_unmap (moov, &map);
3815 gst_buffer_unref (moov);
3817 gst_buffer_map (moov, &map, GST_MAP_READ);
3822 if (length != map.size) {
3823 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
3824 (_("This file is incomplete and cannot be played.")),
3825 ("We got less than expected (received %" G_GSIZE_FORMAT
3826 ", wanted %u, offset %" G_GUINT64_FORMAT ")", map.size,
3827 (guint) length, cur_offset));
3828 gst_buffer_unmap (moov, &map);
3829 gst_buffer_unref (moov);
3830 ret = GST_FLOW_ERROR;
3833 qtdemux->offset += length;
3835 qtdemux_parse_moov (qtdemux, map.data, length);
3836 qtdemux_node_dump (qtdemux, qtdemux->moov_node);
3838 qtdemux_parse_tree (qtdemux);
3839 g_node_destroy (qtdemux->moov_node);
3840 gst_buffer_unmap (moov, &map);
3841 gst_buffer_unref (moov);
3842 qtdemux->moov_node = NULL;
3843 qtdemux->got_moov = TRUE;
3849 GstBuffer *ftyp = NULL;
3851 /* extract major brand; might come in handy for ISO vs QT issues */
3852 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &ftyp);
3853 if (ret != GST_FLOW_OK)
3855 qtdemux->offset += length;
3856 gst_buffer_map (ftyp, &map, GST_MAP_READ);
3857 qtdemux_parse_ftyp (qtdemux, map.data, map.size);
3858 gst_buffer_unmap (ftyp, &map);
3859 gst_buffer_unref (ftyp);
3864 GstBuffer *uuid = NULL;
3866 /* uuid are extension atoms */
3867 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &uuid);
3868 if (ret != GST_FLOW_OK)
3870 qtdemux->offset += length;
3871 gst_buffer_map (uuid, &map, GST_MAP_READ);
3872 qtdemux_parse_uuid (qtdemux, map.data, map.size);
3873 gst_buffer_unmap (uuid, &map);
3874 gst_buffer_unref (uuid);
3879 GstBuffer *sidx = NULL;
3880 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &sidx);
3881 if (ret != GST_FLOW_OK)
3883 qtdemux->offset += length;
3884 gst_buffer_map (sidx, &map, GST_MAP_READ);
3885 qtdemux_parse_sidx (qtdemux, map.data, map.size);
3886 gst_buffer_unmap (sidx, &map);
3887 gst_buffer_unref (sidx);
3892 GstBuffer *unknown = NULL;
3894 GST_LOG_OBJECT (qtdemux,
3895 "unknown %08x '%" GST_FOURCC_FORMAT "' of size %" G_GUINT64_FORMAT
3896 " at %" G_GUINT64_FORMAT, fourcc, GST_FOURCC_ARGS (fourcc), length,
3898 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &unknown);
3899 if (ret != GST_FLOW_OK)
3901 gst_buffer_map (unknown, &map, GST_MAP_READ);
3902 GST_MEMDUMP ("Unknown tag", map.data, map.size);
3903 gst_buffer_unmap (unknown, &map);
3904 gst_buffer_unref (unknown);
3905 qtdemux->offset += length;
3911 if (ret == GST_FLOW_EOS && (qtdemux->got_moov || qtdemux->media_caps)) {
3912 /* digested all data, show what we have */
3913 qtdemux_prepare_streams (qtdemux);
3914 ret = qtdemux_expose_streams (qtdemux);
3916 qtdemux->state = QTDEMUX_STATE_MOVIE;
3917 GST_DEBUG_OBJECT (qtdemux, "switching state to STATE_MOVIE (%d)",
3924 /* Seeks to the previous keyframe of the indexed stream and
3925 * aligns other streams with respect to the keyframe timestamp
3926 * of indexed stream. Only called in case of Reverse Playback
3928 static GstFlowReturn
3929 gst_qtdemux_seek_to_previous_keyframe (GstQTDemux * qtdemux)
3932 guint32 seg_idx = 0, k_index = 0;
3933 guint32 ref_seg_idx, ref_k_index;
3934 GstClockTime k_pos = 0, last_stop = 0;
3935 QtDemuxSegment *seg = NULL;
3936 QtDemuxStream *ref_str = NULL;
3937 guint64 seg_media_start_mov; /* segment media start time in mov format */
3940 /* Now we choose an arbitrary stream, get the previous keyframe timestamp
3941 * and finally align all the other streams on that timestamp with their
3942 * respective keyframes */
3943 for (n = 0; n < qtdemux->n_streams; n++) {
3944 QtDemuxStream *str = qtdemux->streams[n];
3946 /* No candidate yet, take the first stream */
3952 /* So that stream has a segment, we prefer video streams */
3953 if (str->subtype == FOURCC_vide) {
3959 if (G_UNLIKELY (!ref_str)) {
3960 GST_DEBUG_OBJECT (qtdemux, "couldn't find any stream");
3964 if (G_UNLIKELY (!ref_str->from_sample)) {
3965 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of the file");
3969 /* So that stream has been playing from from_sample to to_sample. We will
3970 * get the timestamp of the previous sample and search for a keyframe before
3971 * that. For audio streams we do an arbitrary jump in the past (10 samples) */
3972 if (ref_str->subtype == FOURCC_vide) {
3973 k_index = gst_qtdemux_find_keyframe (qtdemux, ref_str,
3974 ref_str->from_sample - 1);
3976 if (ref_str->from_sample >= 10)
3977 k_index = ref_str->from_sample - 10;
3983 ref_str->samples[k_index].timestamp +
3984 ref_str->samples[k_index].pts_offset;
3986 /* get current segment for that stream */
3987 seg = &ref_str->segments[ref_str->segment_index];
3988 /* Use segment start in original timescale for comparisons */
3989 seg_media_start_mov = seg->trak_media_start;
3991 GST_LOG_OBJECT (qtdemux, "keyframe index %u ts %" G_GUINT64_FORMAT
3992 " seg start %" G_GUINT64_FORMAT " %" GST_TIME_FORMAT "\n",
3993 k_index, target_ts, seg_media_start_mov,
3994 GST_TIME_ARGS (seg->media_start));
3996 /* Crawl back through segments to find the one containing this I frame */
3997 while (target_ts < seg_media_start_mov) {
3998 GST_DEBUG_OBJECT (qtdemux,
3999 "keyframe position (sample %u) is out of segment %u " " target %"
4000 G_GUINT64_FORMAT " seg start %" G_GUINT64_FORMAT, k_index,
4001 ref_str->segment_index, target_ts, seg_media_start_mov);
4003 if (G_UNLIKELY (!ref_str->segment_index)) {
4004 /* Reached first segment, let's consider it's EOS */
4007 ref_str->segment_index--;
4008 seg = &ref_str->segments[ref_str->segment_index];
4009 /* Use segment start in original timescale for comparisons */
4010 seg_media_start_mov = seg->trak_media_start;
4012 /* Calculate time position of the keyframe and where we should stop */
4014 QTSTREAMTIME_TO_GSTTIME (ref_str,
4015 target_ts - seg->trak_media_start) + seg->time;
4017 QTSTREAMTIME_TO_GSTTIME (ref_str,
4018 ref_str->samples[ref_str->from_sample].timestamp -
4019 seg->trak_media_start) + seg->time;
4021 GST_DEBUG_OBJECT (qtdemux, "preferred stream played from sample %u, "
4022 "now going to sample %u (pts %" GST_TIME_FORMAT ")", ref_str->from_sample,
4023 k_index, GST_TIME_ARGS (k_pos));
4025 /* Set last_stop with the keyframe timestamp we pushed of that stream */
4026 qtdemux->segment.position = last_stop;
4027 GST_DEBUG_OBJECT (qtdemux, "last_stop now is %" GST_TIME_FORMAT,
4028 GST_TIME_ARGS (last_stop));
4030 if (G_UNLIKELY (last_stop < qtdemux->segment.start)) {
4031 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of segment");
4035 ref_seg_idx = ref_str->segment_index;
4036 ref_k_index = k_index;
4038 /* Align them all on this */
4039 for (n = 0; n < qtdemux->n_streams; n++) {
4041 GstClockTime seg_time = 0;
4042 QtDemuxStream *str = qtdemux->streams[n];
4044 /* aligning reference stream again might lead to backing up to yet another
4045 * keyframe (due to timestamp rounding issues),
4046 * potentially putting more load on downstream; so let's try to avoid */
4047 if (str == ref_str) {
4048 seg_idx = ref_seg_idx;
4049 seg = &str->segments[seg_idx];
4050 k_index = ref_k_index;
4051 GST_DEBUG_OBJECT (qtdemux, "reference stream %d segment %d, "
4052 "sample at index %d", n, ref_str->segment_index, k_index);
4054 seg_idx = gst_qtdemux_find_segment (qtdemux, str, k_pos);
4055 GST_DEBUG_OBJECT (qtdemux,
4056 "stream %d align segment %d for keyframe pos %" GST_TIME_FORMAT, n,
4057 seg_idx, GST_TIME_ARGS (k_pos));
4059 /* get segment and time in the segment */
4060 seg = &str->segments[seg_idx];
4061 seg_time = k_pos - seg->time;
4063 /* get the media time in the segment.
4064 * No adjustment for empty "filler" segments */
4065 if (seg->media_start != GST_CLOCK_TIME_NONE)
4066 seg_time += seg->media_start;
4068 /* get the index of the sample with media time */
4069 index = gst_qtdemux_find_index_linear (qtdemux, str, seg_time);
4070 GST_DEBUG_OBJECT (qtdemux,
4071 "stream %d sample for %" GST_TIME_FORMAT " at %u", n,
4072 GST_TIME_ARGS (seg_time), index);
4074 /* find previous keyframe */
4075 k_index = gst_qtdemux_find_keyframe (qtdemux, str, index);
4078 /* Remember until where we want to go */
4079 str->to_sample = str->from_sample - 1;
4080 /* Define our time position */
4082 str->samples[k_index].timestamp + str->samples[k_index].pts_offset;
4083 str->time_position = QTSTREAMTIME_TO_GSTTIME (str, target_ts) + seg->time;
4084 if (seg->media_start != GST_CLOCK_TIME_NONE)
4085 str->time_position -= seg->media_start;
4087 /* Now seek back in time */
4088 gst_qtdemux_move_stream (qtdemux, str, k_index);
4089 GST_DEBUG_OBJECT (qtdemux, "stream %d keyframe at %u, time position %"
4090 GST_TIME_FORMAT " playing from sample %u to %u", n, k_index,
4091 GST_TIME_ARGS (str->time_position), str->from_sample, str->to_sample);
4097 return GST_FLOW_EOS;
4100 /* activate the given segment number @seg_idx of @stream at time @offset.
4101 * @offset is an absolute global position over all the segments.
4103 * This will push out a NEWSEGMENT event with the right values and
4104 * position the stream index to the first decodable sample before
4110 gst_qtdemux_activate_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
4111 guint32 seg_idx, GstClockTime offset)
4114 QtDemuxSegment *segment;
4115 guint32 index, kf_index;
4116 GstClockTime seg_time;
4117 GstClockTime start, stop, time;
4120 GST_LOG_OBJECT (stream->pad, "activate segment %d, offset %" GST_TIME_FORMAT,
4121 seg_idx, GST_TIME_ARGS (offset));
4123 /* update the current segment */
4124 stream->segment_index = seg_idx;
4126 /* get the segment */
4127 segment = &stream->segments[seg_idx];
4129 if (G_UNLIKELY (offset < segment->time)) {
4130 GST_WARNING_OBJECT (stream->pad, "offset < segment->time %" GST_TIME_FORMAT,
4131 GST_TIME_ARGS (segment->time));
4135 /* segment lies beyond total indicated duration */
4136 if (G_UNLIKELY (qtdemux->segment.duration != GST_CLOCK_TIME_NONE &&
4137 segment->time > qtdemux->segment.duration)) {
4138 GST_WARNING_OBJECT (stream->pad, "file duration %" GST_TIME_FORMAT
4139 " < segment->time %" GST_TIME_FORMAT,
4140 GST_TIME_ARGS (qtdemux->segment.duration),
4141 GST_TIME_ARGS (segment->time));
4145 /* get time in this segment */
4146 seg_time = offset - segment->time;
4148 GST_LOG_OBJECT (stream->pad, "seg_time %" GST_TIME_FORMAT,
4149 GST_TIME_ARGS (seg_time));
4151 if (G_UNLIKELY (seg_time > segment->duration)) {
4152 GST_LOG_OBJECT (stream->pad,
4153 "seg_time > segment->duration %" GST_TIME_FORMAT,
4154 GST_TIME_ARGS (segment->duration));
4155 seg_time = segment->duration;
4158 /* qtdemux->segment.stop is in outside-time-realm, whereas
4159 * segment->media_stop is in track-time-realm.
4161 * In order to compare the two, we need to bring segment.stop
4162 * into the track-time-realm */
4164 stop = qtdemux->segment.stop;
4165 if (stop == GST_CLOCK_TIME_NONE)
4166 stop = qtdemux->segment.duration;
4167 if (stop == GST_CLOCK_TIME_NONE)
4168 stop = segment->media_stop;
4171 MIN (segment->media_stop, stop - segment->time + segment->media_start);
4173 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
4174 start = segment->time + seg_time;
4176 stop = start - seg_time + segment->duration;
4177 } else if (qtdemux->segment.rate >= 0) {
4178 start = MIN (segment->media_start + seg_time, stop);
4181 if (segment->media_start >= qtdemux->segment.start) {
4182 time = segment->time;
4184 time = segment->time + (qtdemux->segment.start - segment->media_start);
4187 start = MAX (segment->media_start, qtdemux->segment.start);
4188 stop = MIN (segment->media_start + seg_time, stop);
4191 GST_DEBUG_OBJECT (stream->pad, "new segment %d from %" GST_TIME_FORMAT
4192 " to %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT, seg_idx,
4193 GST_TIME_ARGS (start), GST_TIME_ARGS (stop), GST_TIME_ARGS (time));
4195 /* combine global rate with that of the segment */
4196 rate = segment->rate * qtdemux->segment.rate;
4198 /* Copy flags from main segment */
4199 stream->segment.flags = qtdemux->segment.flags;
4201 /* update the segment values used for clipping */
4202 stream->segment.offset = qtdemux->segment.offset;
4203 stream->segment.base = qtdemux->segment.base + stream->accumulated_base;
4204 stream->segment.applied_rate = qtdemux->segment.applied_rate;
4205 stream->segment.rate = rate;
4206 stream->segment.start = start + QTSTREAMTIME_TO_GSTTIME (stream,
4207 stream->cslg_shift);
4208 stream->segment.stop = stop + QTSTREAMTIME_TO_GSTTIME (stream,
4209 stream->cslg_shift);
4210 stream->segment.time = time;
4211 stream->segment.position = stream->segment.start;
4213 GST_DEBUG_OBJECT (stream->pad, "New segment: %" GST_SEGMENT_FORMAT,
4216 /* now prepare and send the segment */
4218 event = gst_event_new_segment (&stream->segment);
4219 if (stream->segment_seqnum) {
4220 gst_event_set_seqnum (event, stream->segment_seqnum);
4222 gst_pad_push_event (stream->pad, event);
4223 /* assume we can send more data now */
4224 GST_PAD_LAST_FLOW_RETURN (stream->pad) = GST_FLOW_OK;
4225 /* clear to send tags on this pad now */
4226 gst_qtdemux_push_tags (qtdemux, stream);
4229 /* in the fragmented case, we pick a fragment that starts before our
4230 * desired position and rely on downstream to wait for a keyframe
4231 * (FIXME: doesn't seem to work so well with ismv and wmv, as no parser; the
4232 * tfra entries tells us which trun/sample the key unit is in, but we don't
4233 * make use of this additional information at the moment) */
4234 if (qtdemux->fragmented) {
4235 stream->to_sample = G_MAXUINT32;
4239 /* and move to the keyframe before the indicated media time of the
4241 if (G_LIKELY (!QTSEGMENT_IS_EMPTY (segment))) {
4242 if (qtdemux->segment.rate >= 0) {
4243 index = gst_qtdemux_find_index_linear (qtdemux, stream, start);
4244 stream->to_sample = G_MAXUINT32;
4245 GST_DEBUG_OBJECT (stream->pad,
4246 "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
4247 GST_TIME_FORMAT, GST_TIME_ARGS (start), index,
4248 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
4250 index = gst_qtdemux_find_index_linear (qtdemux, stream, stop);
4251 stream->to_sample = index;
4252 GST_DEBUG_OBJECT (stream->pad,
4253 "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
4254 GST_TIME_FORMAT, GST_TIME_ARGS (stop), index,
4255 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
4258 GST_DEBUG_OBJECT (stream->pad, "No need to look for keyframe, "
4259 "this is an empty segment");
4263 /* gst_qtdemux_parse_sample () called from gst_qtdemux_find_index_linear ()
4264 * encountered an error and printed a message so we return appropriately */
4268 /* we're at the right spot */
4269 if (index == stream->sample_index) {
4270 GST_DEBUG_OBJECT (stream->pad, "we are at the right index");
4274 /* find keyframe of the target index */
4275 kf_index = gst_qtdemux_find_keyframe (qtdemux, stream, index);
4278 /* indent does stupid stuff with stream->samples[].timestamp */
4280 /* if we move forwards, we don't have to go back to the previous
4281 * keyframe since we already sent that. We can also just jump to
4282 * the keyframe right before the target index if there is one. */
4283 if (index > stream->sample_index) {
4284 /* moving forwards check if we move past a keyframe */
4285 if (kf_index > stream->sample_index) {
4286 GST_DEBUG_OBJECT (stream->pad,
4287 "moving forwards to keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" )", kf_index,
4288 GST_TIME_ARGS (QTSAMPLE_PTS(stream, &stream->samples[kf_index])),
4289 GST_TIME_ARGS (QTSAMPLE_DTS(stream, &stream->samples[kf_index])));
4290 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
4292 GST_DEBUG_OBJECT (stream->pad,
4293 "moving forwards, keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" ) already sent", kf_index,
4294 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[kf_index])),
4295 GST_TIME_ARGS (QTSAMPLE_DTS (stream, &stream->samples[kf_index])));
4298 GST_DEBUG_OBJECT (stream->pad,
4299 "moving backwards to keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" )", kf_index,
4300 GST_TIME_ARGS (QTSAMPLE_PTS(stream, &stream->samples[kf_index])),
4301 GST_TIME_ARGS (QTSAMPLE_DTS(stream, &stream->samples[kf_index])));
4302 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
4310 /* prepare to get the current sample of @stream, getting essential values.
4312 * This function will also prepare and send the segment when needed.
4314 * Return FALSE if the stream is EOS.
4319 gst_qtdemux_prepare_current_sample (GstQTDemux * qtdemux,
4320 QtDemuxStream * stream, gboolean * empty, guint64 * offset, guint * size,
4321 GstClockTime * dts, GstClockTime * pts, GstClockTime * duration,
4322 gboolean * keyframe)
4324 QtDemuxSample *sample;
4325 GstClockTime time_position;
4328 g_return_val_if_fail (stream != NULL, FALSE);
4330 time_position = stream->time_position;
4331 if (G_UNLIKELY (time_position == GST_CLOCK_TIME_NONE))
4334 seg_idx = stream->segment_index;
4335 if (G_UNLIKELY (seg_idx == -1)) {
4336 /* find segment corresponding to time_position if we are looking
4338 seg_idx = gst_qtdemux_find_segment (qtdemux, stream, time_position);
4341 /* different segment, activate it, sample_index will be set. */
4342 if (G_UNLIKELY (stream->segment_index != seg_idx))
4343 gst_qtdemux_activate_segment (qtdemux, stream, seg_idx, time_position);
4345 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (&stream->segments[stream->
4347 QtDemuxSegment *seg = &stream->segments[stream->segment_index];
4349 GST_LOG_OBJECT (qtdemux, "Empty segment activated,"
4350 " prepare empty sample");
4353 *pts = *dts = time_position;
4354 *duration = seg->duration - (time_position - seg->time);
4361 if (stream->sample_index == -1)
4362 stream->sample_index = 0;
4364 GST_LOG_OBJECT (qtdemux, "segment active, index = %u of %u",
4365 stream->sample_index, stream->n_samples);
4367 if (G_UNLIKELY (stream->sample_index >= stream->n_samples)) {
4368 if (!qtdemux->fragmented)
4371 GST_INFO_OBJECT (qtdemux, "out of samples, trying to add more");
4375 GST_OBJECT_LOCK (qtdemux);
4376 flow = qtdemux_add_fragmented_samples (qtdemux);
4377 GST_OBJECT_UNLOCK (qtdemux);
4379 if (flow != GST_FLOW_OK)
4382 while (stream->sample_index >= stream->n_samples);
4385 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
4386 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
4387 stream->sample_index);
4391 /* now get the info for the sample we're at */
4392 sample = &stream->samples[stream->sample_index];
4394 *dts = QTSAMPLE_DTS (stream, sample);
4395 *pts = QTSAMPLE_PTS (stream, sample);
4396 *offset = sample->offset;
4397 *size = sample->size;
4398 *duration = QTSAMPLE_DUR_DTS (stream, sample, *dts);
4399 *keyframe = QTSAMPLE_KEYFRAME (stream, sample);
4406 stream->time_position = GST_CLOCK_TIME_NONE;
4411 /* move to the next sample in @stream.
4413 * Moves to the next segment when needed.
4416 gst_qtdemux_advance_sample (GstQTDemux * qtdemux, QtDemuxStream * stream)
4418 QtDemuxSample *sample;
4419 QtDemuxSegment *segment;
4421 /* get current segment */
4422 segment = &stream->segments[stream->segment_index];
4424 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
4425 GST_DEBUG_OBJECT (qtdemux, "Empty segment, no samples to advance");
4429 if (G_UNLIKELY (stream->sample_index >= stream->to_sample)) {
4430 /* Mark the stream as EOS */
4431 GST_DEBUG_OBJECT (qtdemux,
4432 "reached max allowed sample %u, mark EOS", stream->to_sample);
4433 stream->time_position = GST_CLOCK_TIME_NONE;
4437 /* move to next sample */
4438 stream->sample_index++;
4439 stream->offset_in_sample = 0;
4441 /* reached the last sample, we need the next segment */
4442 if (G_UNLIKELY (stream->sample_index >= stream->n_samples))
4445 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
4446 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
4447 stream->sample_index);
4451 /* get next sample */
4452 sample = &stream->samples[stream->sample_index];
4454 /* see if we are past the segment */
4455 if (G_UNLIKELY (QTSAMPLE_DTS (stream, sample) >= segment->media_stop))
4458 if (QTSAMPLE_DTS (stream, sample) >= segment->media_start) {
4459 /* inside the segment, update time_position, looks very familiar to
4460 * GStreamer segments, doesn't it? */
4461 stream->time_position =
4462 QTSAMPLE_DTS (stream, sample) - segment->media_start + segment->time;
4464 /* not yet in segment, time does not yet increment. This means
4465 * that we are still prerolling keyframes to the decoder so it can
4466 * decode the first sample of the segment. */
4467 stream->time_position = segment->time;
4471 /* move to the next segment */
4474 GST_DEBUG_OBJECT (qtdemux, "segment %d ended ", stream->segment_index);
4476 if (stream->segment_index == stream->n_segments - 1) {
4477 /* are we at the end of the last segment, we're EOS */
4478 stream->time_position = GST_CLOCK_TIME_NONE;
4480 /* else we're only at the end of the current segment */
4481 stream->time_position = segment->stop_time;
4483 /* make sure we select a new segment */
4485 /* accumulate previous segments */
4486 if (GST_CLOCK_TIME_IS_VALID (stream->segment.stop))
4487 stream->accumulated_base +=
4488 (stream->segment.stop -
4489 stream->segment.start) / ABS (stream->segment.rate);
4491 stream->segment_index = -1;
4496 gst_qtdemux_sync_streams (GstQTDemux * demux)
4500 if (demux->n_streams <= 1)
4503 for (i = 0; i < demux->n_streams; i++) {
4504 QtDemuxStream *stream;
4505 GstClockTime end_time;
4507 stream = demux->streams[i];
4512 /* TODO advance time on subtitle streams here, if any some day */
4514 /* some clips/trailers may have unbalanced streams at the end,
4515 * so send EOS on shorter stream to prevent stalling others */
4517 /* do not mess with EOS if SEGMENT seeking */
4518 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT)
4521 if (demux->pullbased) {
4522 /* loop mode is sample time based */
4523 if (!STREAM_IS_EOS (stream))
4526 /* push mode is byte position based */
4527 if (stream->n_samples &&
4528 stream->samples[stream->n_samples - 1].offset >= demux->offset)
4532 if (stream->sent_eos)
4535 /* only act if some gap */
4536 end_time = stream->segments[stream->n_segments - 1].stop_time;
4537 GST_LOG_OBJECT (demux, "current position: %" GST_TIME_FORMAT
4538 ", stream end: %" GST_TIME_FORMAT,
4539 GST_TIME_ARGS (demux->segment.position), GST_TIME_ARGS (end_time));
4540 if (GST_CLOCK_TIME_IS_VALID (end_time)
4541 && (end_time + 2 * GST_SECOND < demux->segment.position)) {
4542 GST_DEBUG_OBJECT (demux, "sending EOS for stream %s",
4543 GST_PAD_NAME (stream->pad));
4544 stream->sent_eos = TRUE;
4545 gst_pad_push_event (stream->pad, gst_event_new_eos ());
4550 /* EOS and NOT_LINKED need to be combined. This means that we return:
4552 * GST_FLOW_NOT_LINKED: when all pads NOT_LINKED.
4553 * GST_FLOW_EOS: when all pads EOS or NOT_LINKED.
4555 static GstFlowReturn
4556 gst_qtdemux_combine_flows (GstQTDemux * demux, QtDemuxStream * stream,
4559 GST_LOG_OBJECT (demux, "flow return: %s", gst_flow_get_name (ret));
4562 ret = gst_flow_combiner_update_pad_flow (demux->flowcombiner, stream->pad,
4565 ret = gst_flow_combiner_update_flow (demux->flowcombiner, ret);
4567 GST_LOG_OBJECT (demux, "combined flow return: %s", gst_flow_get_name (ret));
4571 /* the input buffer metadata must be writable. Returns NULL when the buffer is
4572 * completely clipped
4574 * Should be used only with raw buffers */
4576 gst_qtdemux_clip_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
4579 guint64 start, stop, cstart, cstop, diff;
4580 GstClockTime pts, duration;
4582 gint num_rate, denom_rate;
4587 osize = size = gst_buffer_get_size (buf);
4590 /* depending on the type, setup the clip parameters */
4591 if (stream->subtype == FOURCC_soun) {
4592 frame_size = stream->bytes_per_frame;
4593 num_rate = GST_SECOND;
4594 denom_rate = (gint) stream->rate;
4596 } else if (stream->subtype == FOURCC_vide) {
4598 num_rate = stream->fps_n;
4599 denom_rate = stream->fps_d;
4604 if (frame_size <= 0)
4605 goto bad_frame_size;
4607 /* we can only clip if we have a valid pts */
4608 pts = GST_BUFFER_PTS (buf);
4609 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (pts)))
4612 duration = GST_BUFFER_DURATION (buf);
4614 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (duration))) {
4616 gst_util_uint64_scale_int (size / frame_size, num_rate, denom_rate);
4620 stop = start + duration;
4622 if (G_UNLIKELY (!gst_segment_clip (&stream->segment,
4623 GST_FORMAT_TIME, start, stop, &cstart, &cstop)))
4626 /* see if some clipping happened */
4627 diff = cstart - start;
4633 /* bring clipped time to samples and to bytes */
4634 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
4637 GST_DEBUG_OBJECT (qtdemux,
4638 "clipping start to %" GST_TIME_FORMAT " %"
4639 G_GUINT64_FORMAT " bytes", GST_TIME_ARGS (cstart), diff);
4645 diff = stop - cstop;
4650 /* bring clipped time to samples and then to bytes */
4651 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
4653 GST_DEBUG_OBJECT (qtdemux,
4654 "clipping stop to %" GST_TIME_FORMAT " %" G_GUINT64_FORMAT
4655 " bytes", GST_TIME_ARGS (cstop), diff);
4660 if (offset != 0 || size != osize)
4661 gst_buffer_resize (buf, offset, size);
4663 GST_BUFFER_DTS (buf) = GST_CLOCK_TIME_NONE;
4664 GST_BUFFER_PTS (buf) = pts;
4665 GST_BUFFER_DURATION (buf) = duration;
4669 /* dropped buffer */
4672 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
4677 GST_DEBUG_OBJECT (qtdemux, "bad frame size");
4682 GST_DEBUG_OBJECT (qtdemux, "no pts on buffer");
4687 GST_DEBUG_OBJECT (qtdemux, "clipped buffer");
4688 gst_buffer_unref (buf);
4693 /* the input buffer metadata must be writable,
4694 * but time/duration etc not yet set and need not be preserved */
4696 gst_qtdemux_process_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
4703 /* not many cases for now */
4704 if (G_UNLIKELY (stream->fourcc == FOURCC_mp4s)) {
4705 /* send a one time dvd clut event */
4706 if (stream->pending_event && stream->pad)
4707 gst_pad_push_event (stream->pad, stream->pending_event);
4708 stream->pending_event = NULL;
4711 if (G_UNLIKELY (stream->subtype != FOURCC_text
4712 && stream->subtype != FOURCC_sbtl &&
4713 stream->subtype != FOURCC_subp)) {
4717 gst_buffer_map (buf, &map, GST_MAP_READ);
4719 /* empty buffer is sent to terminate previous subtitle */
4720 if (map.size <= 2) {
4721 gst_buffer_unmap (buf, &map);
4722 gst_buffer_unref (buf);
4725 if (stream->subtype == FOURCC_subp) {
4726 /* That's all the processing needed for subpictures */
4727 gst_buffer_unmap (buf, &map);
4731 nsize = GST_READ_UINT16_BE (map.data);
4732 nsize = MIN (nsize, map.size - 2);
4734 GST_LOG_OBJECT (qtdemux, "3GPP timed text subtitle: %d/%" G_GSIZE_FORMAT "",
4737 /* takes care of UTF-8 validation or UTF-16 recognition,
4738 * no other encoding expected */
4739 str = gst_tag_freeform_string_to_utf8 ((gchar *) map.data + 2, nsize, NULL);
4740 gst_buffer_unmap (buf, &map);
4742 gst_buffer_unref (buf);
4743 buf = _gst_buffer_new_wrapped (str, strlen (str), g_free);
4745 /* this should not really happen unless the subtitle is corrupted */
4746 gst_buffer_unref (buf);
4750 /* FIXME ? convert optional subsequent style info to markup */
4755 /* Sets a buffer's attributes properly and pushes it downstream.
4756 * Also checks for additional actions and custom processing that may
4757 * need to be done first.
4759 static GstFlowReturn
4760 gst_qtdemux_decorate_and_push_buffer (GstQTDemux * qtdemux,
4761 QtDemuxStream * stream, GstBuffer * buf,
4762 GstClockTime dts, GstClockTime pts, GstClockTime duration,
4763 gboolean keyframe, GstClockTime position, guint64 byte_position)
4765 GstFlowReturn ret = GST_FLOW_OK;
4767 /* offset the timestamps according to the edit list */
4769 if (G_UNLIKELY (stream->fourcc == FOURCC_rtsp)) {
4773 gst_buffer_map (buf, &map, GST_MAP_READ);
4774 url = g_strndup ((gchar *) map.data, map.size);
4775 gst_buffer_unmap (buf, &map);
4776 if (url != NULL && strlen (url) != 0) {
4777 /* we have RTSP redirect now */
4778 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
4779 gst_message_new_element (GST_OBJECT_CAST (qtdemux),
4780 gst_structure_new ("redirect",
4781 "new-location", G_TYPE_STRING, url, NULL)));
4782 qtdemux->posted_redirect = TRUE;
4784 GST_WARNING_OBJECT (qtdemux, "Redirect URI of stream is empty, not "
4790 /* position reporting */
4791 if (qtdemux->segment.rate >= 0) {
4792 qtdemux->segment.position = position;
4793 gst_qtdemux_sync_streams (qtdemux);
4796 if (G_UNLIKELY (!stream->pad)) {
4797 GST_DEBUG_OBJECT (qtdemux, "No output pad for stream, ignoring");
4798 gst_buffer_unref (buf);
4802 /* send out pending buffers */
4803 while (stream->buffers) {
4804 GstBuffer *buffer = (GstBuffer *) stream->buffers->data;
4806 if (G_UNLIKELY (stream->discont)) {
4807 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
4808 GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
4809 stream->discont = FALSE;
4811 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
4814 gst_pad_push (stream->pad, buffer);
4816 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
4819 /* we're going to modify the metadata */
4820 buf = gst_buffer_make_writable (buf);
4822 if (G_UNLIKELY (stream->need_process))
4823 buf = gst_qtdemux_process_buffer (qtdemux, stream, buf);
4829 GST_BUFFER_DTS (buf) = dts;
4830 GST_BUFFER_PTS (buf) = pts;
4831 GST_BUFFER_DURATION (buf) = duration;
4832 GST_BUFFER_OFFSET (buf) = -1;
4833 GST_BUFFER_OFFSET_END (buf) = -1;
4835 if (G_UNLIKELY (stream->rgb8_palette))
4836 gst_buffer_append_memory (buf, gst_memory_ref (stream->rgb8_palette));
4838 if (G_UNLIKELY (stream->padding)) {
4839 gst_buffer_resize (buf, stream->padding, -1);
4842 if (G_UNLIKELY (qtdemux->element_index)) {
4843 GstClockTime stream_time;
4846 gst_segment_to_stream_time (&stream->segment, GST_FORMAT_TIME,
4848 if (GST_CLOCK_TIME_IS_VALID (stream_time)) {
4849 GST_LOG_OBJECT (qtdemux,
4850 "adding association %" GST_TIME_FORMAT "-> %"
4851 G_GUINT64_FORMAT, GST_TIME_ARGS (stream_time), byte_position);
4852 gst_index_add_association (qtdemux->element_index,
4854 keyframe ? GST_ASSOCIATION_FLAG_KEY_UNIT :
4855 GST_ASSOCIATION_FLAG_DELTA_UNIT, GST_FORMAT_TIME, stream_time,
4856 GST_FORMAT_BYTES, byte_position, NULL);
4861 if (stream->need_clip)
4862 buf = gst_qtdemux_clip_buffer (qtdemux, stream, buf);
4864 if (G_UNLIKELY (buf == NULL))
4867 if (G_UNLIKELY (stream->discont)) {
4868 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
4869 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
4870 stream->discont = FALSE;
4872 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
4876 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
4877 stream->on_keyframe = FALSE;
4879 stream->on_keyframe = TRUE;
4883 GST_LOG_OBJECT (qtdemux,
4884 "Pushing buffer with dts %" GST_TIME_FORMAT ", pts %" GST_TIME_FORMAT
4885 ", duration %" GST_TIME_FORMAT " on pad %s", GST_TIME_ARGS (dts),
4886 GST_TIME_ARGS (pts), GST_TIME_ARGS (duration),
4887 GST_PAD_NAME (stream->pad));
4889 if (stream->protected && stream->protection_scheme_type == FOURCC_cenc) {
4890 GstStructure *crypto_info;
4891 QtDemuxCencSampleSetInfo *info =
4892 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
4896 while ((event = g_queue_pop_head (&stream->protection_scheme_event_queue))) {
4897 gst_pad_push_event (stream->pad, event);
4900 index = stream->sample_index - (stream->n_samples - info->crypto_info->len);
4901 if (G_LIKELY (index >= 0 && index < info->crypto_info->len)) {
4902 /* steal structure from array */
4903 crypto_info = g_ptr_array_index (info->crypto_info, index);
4904 g_ptr_array_index (info->crypto_info, index) = NULL;
4905 GST_LOG_OBJECT (qtdemux, "attaching cenc metadata [%u]", index);
4906 if (!crypto_info || !gst_buffer_add_protection_meta (buf, crypto_info))
4907 GST_ERROR_OBJECT (qtdemux, "failed to attach cenc metadata to buffer");
4911 ret = gst_pad_push (stream->pad, buf);
4913 if (GST_CLOCK_TIME_IS_VALID (pts) && GST_CLOCK_TIME_IS_VALID (duration)) {
4914 /* mark position in stream, we'll need this to know when to send GAP event */
4915 stream->segment.position = pts + duration;
4922 static const QtDemuxRandomAccessEntry *
4923 gst_qtdemux_stream_seek_fragment (GstQTDemux * qtdemux, QtDemuxStream * stream,
4924 GstClockTime pos, gboolean after)
4926 QtDemuxRandomAccessEntry *entries = stream->ra_entries;
4927 guint n_entries = stream->n_ra_entries;
4930 /* we assume the table is sorted */
4931 for (i = 0; i < n_entries; ++i) {
4932 if (entries[i].ts > pos)
4936 /* FIXME: maybe save first moof_offset somewhere instead, but for now it's
4937 * probably okay to assume that the index lists the very first fragment */
4944 return &entries[i - 1];
4948 gst_qtdemux_do_fragmented_seek (GstQTDemux * qtdemux)
4950 const QtDemuxRandomAccessEntry *best_entry = NULL;
4953 GST_OBJECT_LOCK (qtdemux);
4955 g_assert (qtdemux->n_streams > 0);
4957 for (i = 0; i < qtdemux->n_streams; i++) {
4958 const QtDemuxRandomAccessEntry *entry;
4959 QtDemuxStream *stream;
4960 gboolean is_audio_or_video;
4962 stream = qtdemux->streams[i];
4964 g_free (stream->samples);
4965 stream->samples = NULL;
4966 stream->n_samples = 0;
4967 stream->stbl_index = -1; /* no samples have yet been parsed */
4968 stream->sample_index = -1;
4970 if (stream->ra_entries == NULL)
4973 if (stream->subtype == FOURCC_vide || stream->subtype == FOURCC_soun)
4974 is_audio_or_video = TRUE;
4976 is_audio_or_video = FALSE;
4979 gst_qtdemux_stream_seek_fragment (qtdemux, stream,
4980 stream->time_position, !is_audio_or_video);
4982 GST_INFO_OBJECT (stream->pad, "%" GST_TIME_FORMAT " at offset "
4983 "%" G_GUINT64_FORMAT, GST_TIME_ARGS (entry->ts), entry->moof_offset);
4985 stream->pending_seek = entry;
4987 /* decide position to jump to just based on audio/video tracks, not subs */
4988 if (!is_audio_or_video)
4991 if (best_entry == NULL || entry->moof_offset < best_entry->moof_offset)
4995 if (best_entry == NULL) {
4996 GST_OBJECT_UNLOCK (qtdemux);
5000 GST_INFO_OBJECT (qtdemux, "seek to %" GST_TIME_FORMAT ", best fragment "
5001 "moof offset: %" G_GUINT64_FORMAT ", ts %" GST_TIME_FORMAT,
5002 GST_TIME_ARGS (qtdemux->streams[0]->time_position),
5003 best_entry->moof_offset, GST_TIME_ARGS (best_entry->ts));
5005 qtdemux->moof_offset = best_entry->moof_offset;
5007 qtdemux_add_fragmented_samples (qtdemux);
5009 GST_OBJECT_UNLOCK (qtdemux);
5013 static GstFlowReturn
5014 gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux)
5016 GstFlowReturn ret = GST_FLOW_OK;
5017 GstBuffer *buf = NULL;
5018 QtDemuxStream *stream;
5019 GstClockTime min_time;
5021 GstClockTime dts = GST_CLOCK_TIME_NONE;
5022 GstClockTime pts = GST_CLOCK_TIME_NONE;
5023 GstClockTime duration = 0;
5024 gboolean keyframe = FALSE;
5025 guint sample_size = 0;
5031 gst_qtdemux_push_pending_newsegment (qtdemux);
5033 if (qtdemux->fragmented_seek_pending) {
5034 GST_INFO_OBJECT (qtdemux, "pending fragmented seek");
5035 gst_qtdemux_do_fragmented_seek (qtdemux);
5036 GST_INFO_OBJECT (qtdemux, "fragmented seek done!");
5037 qtdemux->fragmented_seek_pending = FALSE;
5040 /* Figure out the next stream sample to output, min_time is expressed in
5041 * global time and runs over the edit list segments. */
5042 min_time = G_MAXUINT64;
5044 for (i = 0; i < qtdemux->n_streams; i++) {
5045 GstClockTime position;
5047 stream = qtdemux->streams[i];
5048 position = stream->time_position;
5050 /* position of -1 is EOS */
5051 if (position != GST_CLOCK_TIME_NONE && position < min_time) {
5052 min_time = position;
5057 if (G_UNLIKELY (index == -1)) {
5058 GST_DEBUG_OBJECT (qtdemux, "all streams are EOS");
5062 /* check for segment end */
5063 if (G_UNLIKELY (qtdemux->segment.stop != -1
5064 && ((qtdemux->segment.rate >= 0 && qtdemux->segment.stop <= min_time)
5065 || (qtdemux->segment.rate < 0
5066 && qtdemux->segment.start > min_time))
5067 && qtdemux->streams[index]->on_keyframe)) {
5068 GST_DEBUG_OBJECT (qtdemux, "we reached the end of our segment.");
5069 qtdemux->streams[index]->time_position = GST_CLOCK_TIME_NONE;
5073 /* gap events for subtitle streams */
5074 for (i = 0; i < qtdemux->n_streams; i++) {
5075 stream = qtdemux->streams[i];
5076 if (stream->pad && (stream->subtype == FOURCC_subp
5077 || stream->subtype == FOURCC_text
5078 || stream->subtype == FOURCC_sbtl)) {
5079 /* send one second gap events until the stream catches up */
5080 /* gaps can only be sent after segment is activated (segment.stop is no longer -1) */
5081 while (GST_CLOCK_TIME_IS_VALID (stream->segment.stop) &&
5082 GST_CLOCK_TIME_IS_VALID (stream->segment.position) &&
5083 stream->segment.position + GST_SECOND < min_time) {
5085 gst_event_new_gap (stream->segment.position, GST_SECOND);
5086 gst_pad_push_event (stream->pad, gap);
5087 stream->segment.position += GST_SECOND;
5092 stream = qtdemux->streams[index];
5093 if (stream->new_caps) {
5094 gst_qtdemux_configure_stream (qtdemux, stream);
5095 qtdemux_do_allocation (qtdemux, stream);
5098 /* fetch info for the current sample of this stream */
5099 if (G_UNLIKELY (!gst_qtdemux_prepare_current_sample (qtdemux, stream, &empty,
5100 &offset, &sample_size, &dts, &pts, &duration, &keyframe)))
5103 /* If we're doing a keyframe-only trickmode, only push keyframes on video streams */
5104 if (G_UNLIKELY (qtdemux->
5105 segment.flags & GST_SEGMENT_FLAG_TRICKMODE_KEY_UNITS)) {
5106 if (stream->subtype == FOURCC_vide && !keyframe) {
5107 GST_LOG_OBJECT (qtdemux, "Skipping non-keyframe on stream %d", index);
5112 GST_DEBUG_OBJECT (qtdemux,
5113 "pushing from stream %d, empty %d offset %" G_GUINT64_FORMAT
5114 ", size %d, dts=%" GST_TIME_FORMAT ", pts=%" GST_TIME_FORMAT
5115 ", duration %" GST_TIME_FORMAT, index, empty, offset, sample_size,
5116 GST_TIME_ARGS (dts), GST_TIME_ARGS (pts), GST_TIME_ARGS (duration));
5118 if (G_UNLIKELY (empty)) {
5119 /* empty segment, push a gap and move to the next one */
5120 gst_pad_push_event (stream->pad, gst_event_new_gap (pts, duration));
5121 stream->segment.position = pts + duration;
5125 /* hmm, empty sample, skip and move to next sample */
5126 if (G_UNLIKELY (sample_size <= 0))
5129 /* last pushed sample was out of boundary, goto next sample */
5130 if (G_UNLIKELY (GST_PAD_LAST_FLOW_RETURN (stream->pad) == GST_FLOW_EOS))
5133 if (stream->max_buffer_size == 0 || sample_size <= stream->max_buffer_size) {
5136 GST_DEBUG_OBJECT (qtdemux,
5137 "size %d larger than stream max_buffer_size %d, trimming",
5138 sample_size, stream->max_buffer_size);
5140 MIN (sample_size - stream->offset_in_sample, stream->max_buffer_size);
5143 GST_LOG_OBJECT (qtdemux, "reading %d bytes @ %" G_GUINT64_FORMAT, size,
5146 if (stream->use_allocator) {
5147 /* if we have a per-stream allocator, use it */
5148 buf = gst_buffer_new_allocate (stream->allocator, size, &stream->params);
5151 ret = gst_qtdemux_pull_atom (qtdemux, offset + stream->offset_in_sample,
5153 if (G_UNLIKELY (ret != GST_FLOW_OK))
5156 if (size != sample_size) {
5157 pts += gst_util_uint64_scale_int (GST_SECOND,
5158 stream->offset_in_sample / stream->bytes_per_frame, stream->timescale);
5159 dts += gst_util_uint64_scale_int (GST_SECOND,
5160 stream->offset_in_sample / stream->bytes_per_frame, stream->timescale);
5161 duration = gst_util_uint64_scale_int (GST_SECOND,
5162 size / stream->bytes_per_frame, stream->timescale);
5165 ret = gst_qtdemux_decorate_and_push_buffer (qtdemux, stream, buf,
5166 dts, pts, duration, keyframe, min_time, offset);
5168 if (size != sample_size) {
5169 QtDemuxSample *sample = &stream->samples[stream->sample_index];
5170 QtDemuxSegment *segment = &stream->segments[stream->segment_index];
5172 GstClockTime time_position = QTSTREAMTIME_TO_GSTTIME (stream,
5173 sample->timestamp + stream->offset_in_sample / stream->bytes_per_frame);
5174 if (time_position >= segment->media_start) {
5175 /* inside the segment, update time_position, looks very familiar to
5176 * GStreamer segments, doesn't it? */
5177 stream->time_position = (time_position - segment->media_start) +
5180 /* not yet in segment, time does not yet increment. This means
5181 * that we are still prerolling keyframes to the decoder so it can
5182 * decode the first sample of the segment. */
5183 stream->time_position = segment->time;
5188 ret = gst_qtdemux_combine_flows (qtdemux, stream, ret);
5189 /* ignore unlinked, we will not push on the pad anymore and we will EOS when
5190 * we have no more data for the pad to push */
5191 if (ret == GST_FLOW_EOS)
5194 stream->offset_in_sample += size;
5195 if (stream->offset_in_sample >= sample_size) {
5196 gst_qtdemux_advance_sample (qtdemux, stream);
5201 gst_qtdemux_advance_sample (qtdemux, stream);
5209 GST_DEBUG_OBJECT (qtdemux, "No samples left for any streams - EOS");
5215 GST_DEBUG_OBJECT (qtdemux, "No samples left for stream");
5216 /* EOS will be raised if all are EOS */
5223 gst_qtdemux_loop (GstPad * pad)
5225 GstQTDemux *qtdemux;
5229 qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
5231 cur_offset = qtdemux->offset;
5232 GST_LOG_OBJECT (qtdemux, "loop at position %" G_GUINT64_FORMAT ", state %d",
5233 cur_offset, qtdemux->state);
5235 switch (qtdemux->state) {
5236 case QTDEMUX_STATE_INITIAL:
5237 case QTDEMUX_STATE_HEADER:
5238 ret = gst_qtdemux_loop_state_header (qtdemux);
5240 case QTDEMUX_STATE_MOVIE:
5241 ret = gst_qtdemux_loop_state_movie (qtdemux);
5242 if (qtdemux->segment.rate < 0 && ret == GST_FLOW_EOS) {
5243 ret = gst_qtdemux_seek_to_previous_keyframe (qtdemux);
5251 /* if something went wrong, pause */
5252 if (ret != GST_FLOW_OK)
5256 gst_object_unref (qtdemux);
5262 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
5263 (NULL), ("streaming stopped, invalid state"));
5264 gst_pad_pause_task (pad);
5265 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
5270 const gchar *reason = gst_flow_get_name (ret);
5272 GST_LOG_OBJECT (qtdemux, "pausing task, reason %s", reason);
5274 gst_pad_pause_task (pad);
5276 /* fatal errors need special actions */
5278 if (ret == GST_FLOW_EOS) {
5279 if (qtdemux->n_streams == 0) {
5280 /* we have no streams, post an error */
5281 gst_qtdemux_post_no_playable_stream_error (qtdemux);
5283 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
5286 if ((stop = qtdemux->segment.stop) == -1)
5287 stop = qtdemux->segment.duration;
5289 if (qtdemux->segment.rate >= 0) {
5290 GST_LOG_OBJECT (qtdemux, "Sending segment done, at end of segment");
5291 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
5292 gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
5293 GST_FORMAT_TIME, stop));
5294 gst_qtdemux_push_event (qtdemux,
5295 gst_event_new_segment_done (GST_FORMAT_TIME, stop));
5297 /* For Reverse Playback */
5298 GST_LOG_OBJECT (qtdemux, "Sending segment done, at start of segment");
5299 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
5300 gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
5301 GST_FORMAT_TIME, qtdemux->segment.start));
5302 gst_qtdemux_push_event (qtdemux,
5303 gst_event_new_segment_done (GST_FORMAT_TIME,
5304 qtdemux->segment.start));
5307 GST_LOG_OBJECT (qtdemux, "Sending EOS at end of segment");
5308 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
5310 } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
5311 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
5312 (NULL), ("streaming stopped, reason %s", reason));
5313 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
5322 * Returns if there are samples to be played.
5325 has_next_entry (GstQTDemux * demux)
5327 QtDemuxStream *stream;
5330 GST_DEBUG_OBJECT (demux, "Checking if there are samples not played yet");
5332 for (i = 0; i < demux->n_streams; i++) {
5333 stream = demux->streams[i];
5335 if (stream->sample_index == -1) {
5336 stream->sample_index = 0;
5337 stream->offset_in_sample = 0;
5340 if (stream->sample_index >= stream->n_samples) {
5341 GST_LOG_OBJECT (demux, "stream %d samples exhausted", i);
5344 GST_DEBUG_OBJECT (demux, "Found a sample");
5348 GST_DEBUG_OBJECT (demux, "There wasn't any next sample");
5355 * Returns the size of the first entry at the current offset.
5356 * If -1, there are none (which means EOS or empty file).
5359 next_entry_size (GstQTDemux * demux)
5361 QtDemuxStream *stream;
5364 guint64 smalloffs = (guint64) - 1;
5365 QtDemuxSample *sample;
5367 GST_LOG_OBJECT (demux, "Finding entry at offset %" G_GUINT64_FORMAT,
5370 for (i = 0; i < demux->n_streams; i++) {
5371 stream = demux->streams[i];
5373 if (stream->sample_index == -1) {
5374 stream->sample_index = 0;
5375 stream->offset_in_sample = 0;
5378 if (stream->sample_index >= stream->n_samples) {
5379 GST_LOG_OBJECT (demux, "stream %d samples exhausted", i);
5383 if (!qtdemux_parse_samples (demux, stream, stream->sample_index)) {
5384 GST_LOG_OBJECT (demux, "Parsing of index %u from stbl atom failed!",
5385 stream->sample_index);
5389 sample = &stream->samples[stream->sample_index];
5391 GST_LOG_OBJECT (demux,
5392 "Checking Stream %d (sample_index:%d / offset:%" G_GUINT64_FORMAT
5393 " / size:%" G_GUINT32_FORMAT ")", i, stream->sample_index,
5394 sample->offset, sample->size);
5396 if (((smalloffs == -1)
5397 || (sample->offset < smalloffs)) && (sample->size)) {
5399 smalloffs = sample->offset;
5403 GST_LOG_OBJECT (demux,
5404 "stream %d offset %" G_GUINT64_FORMAT " demux->offset :%"
5405 G_GUINT64_FORMAT, smallidx, smalloffs, demux->offset);
5410 stream = demux->streams[smallidx];
5411 sample = &stream->samples[stream->sample_index];
5413 if (sample->offset >= demux->offset) {
5414 demux->todrop = sample->offset - demux->offset;
5415 return sample->size + demux->todrop;
5418 GST_DEBUG_OBJECT (demux,
5419 "There wasn't any entry at offset %" G_GUINT64_FORMAT, demux->offset);
5424 gst_qtdemux_post_progress (GstQTDemux * demux, gint num, gint denom)
5426 gint perc = (gint) ((gdouble) num * 100.0 / (gdouble) denom);
5428 gst_element_post_message (GST_ELEMENT_CAST (demux),
5429 gst_message_new_element (GST_OBJECT_CAST (demux),
5430 gst_structure_new ("progress", "percent", G_TYPE_INT, perc, NULL)));
5434 qtdemux_seek_offset (GstQTDemux * demux, guint64 offset)
5439 GST_DEBUG_OBJECT (demux, "Seeking to %" G_GUINT64_FORMAT, offset);
5442 gst_event_new_seek (1.0, GST_FORMAT_BYTES,
5443 GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset,
5444 GST_SEEK_TYPE_NONE, -1);
5446 res = gst_pad_push_event (demux->sinkpad, event);
5451 /* check for seekable upstream, above and beyond a mere query */
5453 gst_qtdemux_check_seekability (GstQTDemux * demux)
5456 gboolean seekable = FALSE;
5457 gint64 start = -1, stop = -1;
5459 if (demux->upstream_size)
5462 query = gst_query_new_seeking (GST_FORMAT_BYTES);
5463 if (!gst_pad_peer_query (demux->sinkpad, query)) {
5464 GST_DEBUG_OBJECT (demux, "seeking query failed");
5468 gst_query_parse_seeking (query, NULL, &seekable, &start, &stop);
5470 /* try harder to query upstream size if we didn't get it the first time */
5471 if (seekable && stop == -1) {
5472 GST_DEBUG_OBJECT (demux, "doing duration query to fix up unset stop");
5473 gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &stop);
5476 /* if upstream doesn't know the size, it's likely that it's not seekable in
5477 * practice even if it technically may be seekable */
5478 if (seekable && (start != 0 || stop <= start)) {
5479 GST_DEBUG_OBJECT (demux, "seekable but unknown start/stop -> disable");
5484 gst_query_unref (query);
5486 GST_DEBUG_OBJECT (demux, "seekable: %d (%" G_GUINT64_FORMAT " - %"
5487 G_GUINT64_FORMAT ")", seekable, start, stop);
5488 demux->upstream_seekable = seekable;
5489 demux->upstream_size = seekable ? stop : -1;
5493 gst_qtdemux_drop_data (GstQTDemux * demux, gint bytes)
5495 g_return_if_fail (bytes <= demux->todrop);
5497 GST_LOG_OBJECT (demux, "Dropping %d bytes", bytes);
5498 gst_adapter_flush (demux->adapter, bytes);
5499 demux->neededbytes -= bytes;
5500 demux->offset += bytes;
5501 demux->todrop -= bytes;
5504 static GstFlowReturn
5505 gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent, GstBuffer * inbuf)
5509 demux = GST_QTDEMUX (parent);
5511 if (GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_DISCONT)) {
5514 GST_DEBUG_OBJECT (demux, "Got DISCONT, marking all streams as DISCONT");
5516 for (i = 0; i < demux->n_streams; i++) {
5517 demux->streams[i]->discont = TRUE;
5520 /* Reverse fragmented playback, need to flush all we have before
5521 * consuming a new fragment.
5522 * The samples array have the timestamps calculated by accumulating the
5523 * durations but this won't work for reverse playback of fragments as
5524 * the timestamps of a subsequent fragment should be smaller than the
5525 * previously received one. */
5526 if (demux->fragmented && demux->segment.rate < 0) {
5527 gst_qtdemux_process_adapter (demux, TRUE);
5528 for (i = 0; i < demux->n_streams; i++)
5529 gst_qtdemux_stream_flush_samples_data (demux, demux->streams[i]);
5533 gst_adapter_push (demux->adapter, inbuf);
5535 GST_DEBUG_OBJECT (demux,
5536 "pushing in inbuf %p, neededbytes:%u, available:%" G_GSIZE_FORMAT, inbuf,
5537 demux->neededbytes, gst_adapter_available (demux->adapter));
5539 return gst_qtdemux_process_adapter (demux, FALSE);
5542 static GstFlowReturn
5543 gst_qtdemux_process_adapter (GstQTDemux * demux, gboolean force)
5545 GstFlowReturn ret = GST_FLOW_OK;
5547 /* we never really mean to buffer that much */
5548 if (demux->neededbytes == -1) {
5552 while (((gst_adapter_available (demux->adapter)) >= demux->neededbytes) &&
5553 (ret == GST_FLOW_OK || (ret == GST_FLOW_NOT_LINKED && force))) {
5555 GST_DEBUG_OBJECT (demux,
5556 "state:%d , demux->neededbytes:%d, demux->offset:%" G_GUINT64_FORMAT,
5557 demux->state, demux->neededbytes, demux->offset);
5559 switch (demux->state) {
5560 case QTDEMUX_STATE_INITIAL:{
5565 gst_qtdemux_check_seekability (demux);
5567 data = gst_adapter_map (demux->adapter, demux->neededbytes);
5569 /* get fourcc/length, set neededbytes */
5570 extract_initial_length_and_fourcc ((guint8 *) data, demux->neededbytes,
5572 gst_adapter_unmap (demux->adapter);
5574 GST_DEBUG_OBJECT (demux, "Peeking found [%" GST_FOURCC_FORMAT "] "
5575 "size: %" G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), size);
5577 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
5578 (_("This file is invalid and cannot be played.")),
5579 ("initial atom '%" GST_FOURCC_FORMAT "' has empty length",
5580 GST_FOURCC_ARGS (fourcc)));
5581 ret = GST_FLOW_ERROR;
5584 if (fourcc == FOURCC_mdat) {
5585 gint next_entry = next_entry_size (demux);
5586 if (demux->n_streams > 0 && (next_entry != -1 || !demux->fragmented)) {
5587 /* we have the headers, start playback */
5588 demux->state = QTDEMUX_STATE_MOVIE;
5589 demux->neededbytes = next_entry;
5590 demux->mdatleft = size;
5592 /* no headers yet, try to get them */
5595 guint64 old, target;
5598 old = demux->offset;
5599 target = old + size;
5601 /* try to jump over the atom with a seek */
5602 /* only bother if it seems worth doing so,
5603 * and avoids possible upstream/server problems */
5604 if (demux->upstream_seekable &&
5605 demux->upstream_size > 4 * (1 << 20)) {
5606 res = qtdemux_seek_offset (demux, target);
5608 GST_DEBUG_OBJECT (demux, "skipping seek");
5613 GST_DEBUG_OBJECT (demux, "seek success");
5614 /* remember the offset fo the first mdat so we can seek back to it
5615 * after we have the headers */
5616 if (fourcc == FOURCC_mdat && demux->first_mdat == -1) {
5617 demux->first_mdat = old;
5618 GST_DEBUG_OBJECT (demux, "first mdat at %" G_GUINT64_FORMAT,
5621 /* seek worked, continue reading */
5622 demux->offset = target;
5623 demux->neededbytes = 16;
5624 demux->state = QTDEMUX_STATE_INITIAL;
5626 /* seek failed, need to buffer */
5627 demux->offset = old;
5628 GST_DEBUG_OBJECT (demux, "seek failed/skipped");
5629 /* there may be multiple mdat (or alike) buffers */
5631 if (demux->mdatbuffer)
5632 bs = gst_buffer_get_size (demux->mdatbuffer);
5635 if (size + bs > 10 * (1 << 20))
5637 demux->state = QTDEMUX_STATE_BUFFER_MDAT;
5638 demux->neededbytes = size;
5639 if (!demux->mdatbuffer)
5640 demux->mdatoffset = demux->offset;
5643 } else if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
5644 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
5645 (_("This file is invalid and cannot be played.")),
5646 ("atom %" GST_FOURCC_FORMAT " has bogus size %" G_GUINT64_FORMAT,
5647 GST_FOURCC_ARGS (fourcc), size));
5648 ret = GST_FLOW_ERROR;
5651 /* this means we already started buffering and still no moov header,
5652 * let's continue buffering everything till we get moov */
5653 if (demux->mdatbuffer && !(fourcc == FOURCC_moov
5654 || fourcc == FOURCC_moof))
5656 demux->neededbytes = size;
5657 demux->state = QTDEMUX_STATE_HEADER;
5661 case QTDEMUX_STATE_HEADER:{
5665 GST_DEBUG_OBJECT (demux, "In header");
5667 data = gst_adapter_map (demux->adapter, demux->neededbytes);
5669 /* parse the header */
5670 extract_initial_length_and_fourcc (data, demux->neededbytes, NULL,
5672 if (fourcc == FOURCC_moov) {
5673 /* in usual fragmented setup we could try to scan for more
5674 * and end up at the the moov (after mdat) again */
5675 if (demux->got_moov && demux->n_streams > 0 &&
5677 || demux->last_moov_offset == demux->offset)) {
5678 GST_DEBUG_OBJECT (demux,
5679 "Skipping moov atom as we have (this) one already");
5681 GST_DEBUG_OBJECT (demux, "Parsing [moov]");
5683 if (demux->got_moov && demux->fragmented) {
5684 GST_DEBUG_OBJECT (demux,
5685 "Got a second moov, clean up data from old one");
5686 if (demux->moov_node)
5687 g_node_destroy (demux->moov_node);
5688 demux->moov_node = NULL;
5689 demux->moov_node_compressed = NULL;
5691 /* prepare newsegment to send when streaming actually starts */
5692 if (!demux->pending_newsegment)
5693 demux->pending_newsegment =
5694 gst_event_new_segment (&demux->segment);
5697 demux->last_moov_offset = demux->offset;
5699 qtdemux_parse_moov (demux, data, demux->neededbytes);
5700 qtdemux_node_dump (demux, demux->moov_node);
5701 qtdemux_parse_tree (demux);
5702 qtdemux_prepare_streams (demux);
5703 if (!demux->got_moov)
5704 qtdemux_expose_streams (demux);
5708 for (n = 0; n < demux->n_streams; n++) {
5709 QtDemuxStream *stream = demux->streams[n];
5711 gst_qtdemux_configure_stream (demux, stream);
5715 demux->got_moov = TRUE;
5717 g_node_destroy (demux->moov_node);
5718 demux->moov_node = NULL;
5719 GST_DEBUG_OBJECT (demux, "Finished parsing the header");
5721 } else if (fourcc == FOURCC_moof) {
5722 if ((demux->got_moov || demux->media_caps) && demux->fragmented) {
5724 GstClockTime prev_pts;
5725 guint64 prev_offset;
5727 GST_DEBUG_OBJECT (demux, "Parsing [moof]");
5730 * The timestamp of the moof buffer is relevant as some scenarios
5731 * won't have the initial timestamp in the atoms. Whenever a new
5732 * buffer has started, we get that buffer's PTS and use it as a base
5733 * timestamp for the trun entries.
5735 * To keep track of the current buffer timestamp and starting point
5736 * we use gst_adapter_prev_pts that gives us the PTS and the distance
5737 * from the beggining of the buffer, with the distance and demux->offset
5738 * we know if it is still the same buffer or not.
5740 prev_pts = gst_adapter_prev_pts (demux->adapter, &dist);
5741 prev_offset = demux->offset - dist;
5742 if (demux->fragment_start_offset == -1
5743 || prev_offset > demux->fragment_start_offset) {
5744 demux->fragment_start_offset = prev_offset;
5745 demux->fragment_start = prev_pts;
5746 GST_DEBUG_OBJECT (demux,
5747 "New fragment start found at: %" G_GUINT64_FORMAT " : %"
5748 GST_TIME_FORMAT, demux->fragment_start_offset,
5749 GST_TIME_ARGS (demux->fragment_start));
5752 demux->moof_offset = demux->offset;
5753 if (!qtdemux_parse_moof (demux, data, demux->neededbytes,
5754 demux->offset, NULL)) {
5755 gst_adapter_unmap (demux->adapter);
5756 ret = GST_FLOW_ERROR;
5759 /* in MSS we need to expose the pads after the first moof as we won't get a moov */
5760 if (demux->mss_mode && !demux->exposed) {
5761 if (!demux->pending_newsegment) {
5763 gst_segment_init (&segment, GST_FORMAT_TIME);
5764 GST_DEBUG_OBJECT (demux, "new pending_newsegment");
5765 demux->pending_newsegment = gst_event_new_segment (&segment);
5767 qtdemux_expose_streams (demux);
5770 GST_DEBUG_OBJECT (demux, "Discarding [moof]");
5772 } else if (fourcc == FOURCC_ftyp) {
5773 GST_DEBUG_OBJECT (demux, "Parsing [ftyp]");
5774 qtdemux_parse_ftyp (demux, data, demux->neededbytes);
5775 } else if (fourcc == FOURCC_uuid) {
5776 GST_DEBUG_OBJECT (demux, "Parsing [uuid]");
5777 qtdemux_parse_uuid (demux, data, demux->neededbytes);
5778 } else if (fourcc == FOURCC_sidx) {
5779 GST_DEBUG_OBJECT (demux, "Parsing [sidx]");
5780 qtdemux_parse_sidx (demux, data, demux->neededbytes);
5782 GST_WARNING_OBJECT (demux,
5783 "Unknown fourcc while parsing header : %" GST_FOURCC_FORMAT,
5784 GST_FOURCC_ARGS (fourcc));
5785 /* Let's jump that one and go back to initial state */
5787 gst_adapter_unmap (demux->adapter);
5790 if (demux->mdatbuffer && demux->n_streams) {
5791 gsize remaining_data_size = 0;
5793 /* the mdat was before the header */
5794 GST_DEBUG_OBJECT (demux, "We have n_streams:%d and mdatbuffer:%p",
5795 demux->n_streams, demux->mdatbuffer);
5796 /* restore our adapter/offset view of things with upstream;
5797 * put preceding buffered data ahead of current moov data.
5798 * This should also handle evil mdat, moov, mdat cases and alike */
5799 gst_adapter_flush (demux->adapter, demux->neededbytes);
5801 /* Store any remaining data after the mdat for later usage */
5802 remaining_data_size = gst_adapter_available (demux->adapter);
5803 if (remaining_data_size > 0) {
5804 g_assert (demux->restoredata_buffer == NULL);
5805 demux->restoredata_buffer =
5806 gst_adapter_take_buffer (demux->adapter, remaining_data_size);
5807 demux->restoredata_offset = demux->offset + demux->neededbytes;
5808 GST_DEBUG_OBJECT (demux,
5809 "Stored %" G_GSIZE_FORMAT " post mdat bytes at offset %"
5810 G_GUINT64_FORMAT, remaining_data_size,
5811 demux->restoredata_offset);
5814 gst_adapter_push (demux->adapter, demux->mdatbuffer);
5815 demux->mdatbuffer = NULL;
5816 demux->offset = demux->mdatoffset;
5817 demux->neededbytes = next_entry_size (demux);
5818 demux->state = QTDEMUX_STATE_MOVIE;
5819 demux->mdatleft = gst_adapter_available (demux->adapter);
5821 GST_DEBUG_OBJECT (demux, "Carrying on normally");
5822 gst_adapter_flush (demux->adapter, demux->neededbytes);
5824 /* only go back to the mdat if there are samples to play */
5825 if (demux->got_moov && demux->first_mdat != -1
5826 && has_next_entry (demux)) {
5829 /* we need to seek back */
5830 res = qtdemux_seek_offset (demux, demux->first_mdat);
5832 demux->offset = demux->first_mdat;
5834 GST_DEBUG_OBJECT (demux, "Seek back failed");
5837 demux->offset += demux->neededbytes;
5839 demux->neededbytes = 16;
5840 demux->state = QTDEMUX_STATE_INITIAL;
5845 case QTDEMUX_STATE_BUFFER_MDAT:{
5849 GST_DEBUG_OBJECT (demux, "Got our buffer at offset %" G_GUINT64_FORMAT,
5851 buf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
5852 gst_buffer_extract (buf, 0, fourcc, 4);
5853 GST_DEBUG_OBJECT (demux, "mdatbuffer starts with %" GST_FOURCC_FORMAT,
5854 GST_FOURCC_ARGS (QT_FOURCC (fourcc)));
5855 if (demux->mdatbuffer)
5856 demux->mdatbuffer = gst_buffer_append (demux->mdatbuffer, buf);
5858 demux->mdatbuffer = buf;
5859 demux->offset += demux->neededbytes;
5860 demux->neededbytes = 16;
5861 demux->state = QTDEMUX_STATE_INITIAL;
5862 gst_qtdemux_post_progress (demux, 1, 1);
5866 case QTDEMUX_STATE_MOVIE:{
5867 QtDemuxStream *stream = NULL;
5868 QtDemuxSample *sample;
5870 GstClockTime dts, pts, duration;
5873 GST_DEBUG_OBJECT (demux,
5874 "BEGIN // in MOVIE for offset %" G_GUINT64_FORMAT, demux->offset);
5876 if (demux->fragmented) {
5877 GST_DEBUG_OBJECT (demux, "mdat remaining %" G_GUINT64_FORMAT,
5879 if (G_LIKELY (demux->todrop < demux->mdatleft)) {
5880 /* if needed data starts within this atom,
5881 * then it should not exceed this atom */
5882 if (G_UNLIKELY (demux->neededbytes > demux->mdatleft)) {
5883 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
5884 (_("This file is invalid and cannot be played.")),
5885 ("sample data crosses atom boundary"));
5886 ret = GST_FLOW_ERROR;
5889 demux->mdatleft -= demux->neededbytes;
5891 GST_DEBUG_OBJECT (demux, "data atom emptied; resuming atom scan");
5892 /* so we are dropping more than left in this atom */
5893 gst_qtdemux_drop_data (demux, demux->mdatleft);
5894 demux->mdatleft = 0;
5896 /* need to resume atom parsing so we do not miss any other pieces */
5897 demux->state = QTDEMUX_STATE_INITIAL;
5898 demux->neededbytes = 16;
5900 /* check if there was any stored post mdat data from previous buffers */
5901 if (demux->restoredata_buffer) {
5902 g_assert (gst_adapter_available (demux->adapter) == 0);
5904 gst_adapter_push (demux->adapter, demux->restoredata_buffer);
5905 demux->restoredata_buffer = NULL;
5906 demux->offset = demux->restoredata_offset;
5913 if (demux->todrop) {
5914 gst_qtdemux_drop_data (demux, demux->todrop);
5918 /* initial newsegment sent here after having added pads,
5919 * possible others in sink_event */
5920 if (G_UNLIKELY (demux->pending_newsegment)) {
5921 gst_qtdemux_push_pending_newsegment (demux);
5922 /* clear to send tags on all streams */
5923 for (i = 0; i < demux->n_streams; i++) {
5924 stream = demux->streams[i];
5925 gst_qtdemux_push_tags (demux, stream);
5926 if (stream->sparse) {
5927 GST_INFO_OBJECT (demux, "Sending gap event on stream %d", i);
5928 gst_pad_push_event (stream->pad,
5929 gst_event_new_gap (stream->segment.position,
5930 GST_CLOCK_TIME_NONE));
5935 /* Figure out which stream this packet belongs to */
5936 for (i = 0; i < demux->n_streams; i++) {
5937 stream = demux->streams[i];
5938 if (stream->sample_index >= stream->n_samples)
5940 GST_LOG_OBJECT (demux,
5941 "Checking stream %d (sample_index:%d / offset:%" G_GUINT64_FORMAT
5942 " / size:%d)", i, stream->sample_index,
5943 stream->samples[stream->sample_index].offset,
5944 stream->samples[stream->sample_index].size);
5946 if (stream->samples[stream->sample_index].offset == demux->offset)
5950 if (G_UNLIKELY (stream == NULL || i == demux->n_streams))
5951 goto unknown_stream;
5953 if (stream->new_caps) {
5954 gst_qtdemux_configure_stream (demux, stream);
5957 /* Put data in a buffer, set timestamps, caps, ... */
5958 sample = &stream->samples[stream->sample_index];
5960 if (G_LIKELY (!(STREAM_IS_EOS (stream)))) {
5961 GST_DEBUG_OBJECT (demux, "stream : %" GST_FOURCC_FORMAT,
5962 GST_FOURCC_ARGS (stream->fourcc));
5964 dts = QTSAMPLE_DTS (stream, sample);
5965 pts = QTSAMPLE_PTS (stream, sample);
5966 duration = QTSAMPLE_DUR_DTS (stream, sample, dts);
5967 keyframe = QTSAMPLE_KEYFRAME (stream, sample);
5969 /* check for segment end */
5970 if (G_UNLIKELY (demux->segment.stop != -1
5971 && demux->segment.stop <= pts && stream->on_keyframe)) {
5972 GST_DEBUG_OBJECT (demux, "we reached the end of our segment.");
5973 stream->time_position = GST_CLOCK_TIME_NONE; /* this means EOS */
5975 /* skip this data, stream is EOS */
5976 gst_adapter_flush (demux->adapter, demux->neededbytes);
5978 /* check if all streams are eos */
5980 for (i = 0; i < demux->n_streams; i++) {
5981 if (!STREAM_IS_EOS (demux->streams[i])) {
5987 if (ret == GST_FLOW_EOS) {
5988 GST_DEBUG_OBJECT (demux, "All streams are EOS, signal upstream");
5995 gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
5997 /* FIXME: should either be an assert or a plain check */
5998 g_return_val_if_fail (outbuf != NULL, GST_FLOW_ERROR);
6000 ret = gst_qtdemux_decorate_and_push_buffer (demux, stream, outbuf,
6001 dts, pts, duration, keyframe, dts, demux->offset);
6005 ret = gst_qtdemux_combine_flows (demux, stream, ret);
6007 /* skip this data, stream is EOS */
6008 gst_adapter_flush (demux->adapter, demux->neededbytes);
6011 stream->sample_index++;
6012 stream->offset_in_sample = 0;
6014 /* update current offset and figure out size of next buffer */
6015 GST_LOG_OBJECT (demux, "increasing offset %" G_GUINT64_FORMAT " by %u",
6016 demux->offset, demux->neededbytes);
6017 demux->offset += demux->neededbytes;
6018 GST_LOG_OBJECT (demux, "offset is now %" G_GUINT64_FORMAT,
6021 if ((demux->neededbytes = next_entry_size (demux)) == -1) {
6022 if (demux->fragmented) {
6023 GST_DEBUG_OBJECT (demux, "(temporarily) out of fragmented samples");
6024 /* there may be more to follow, only finish this atom */
6025 demux->todrop = demux->mdatleft;
6026 demux->neededbytes = demux->todrop;
6038 /* when buffering movie data, at least show user something is happening */
6039 if (ret == GST_FLOW_OK && demux->state == QTDEMUX_STATE_BUFFER_MDAT &&
6040 gst_adapter_available (demux->adapter) <= demux->neededbytes) {
6041 gst_qtdemux_post_progress (demux, gst_adapter_available (demux->adapter),
6042 demux->neededbytes);
6051 GST_ELEMENT_ERROR (demux, STREAM, FAILED, (NULL), ("unknown stream found"));
6052 ret = GST_FLOW_ERROR;
6057 GST_DEBUG_OBJECT (demux, "no next entry, EOS");
6063 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
6064 (NULL), ("qtdemuxer invalid state %d", demux->state));
6065 ret = GST_FLOW_ERROR;
6070 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
6071 (NULL), ("no 'moov' atom within the first 10 MB"));
6072 ret = GST_FLOW_ERROR;
6078 qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent)
6083 query = gst_query_new_scheduling ();
6085 if (!gst_pad_peer_query (sinkpad, query)) {
6086 gst_query_unref (query);
6090 pull_mode = gst_query_has_scheduling_mode_with_flags (query,
6091 GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
6092 gst_query_unref (query);
6097 GST_DEBUG_OBJECT (sinkpad, "activating pull");
6098 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
6102 GST_DEBUG_OBJECT (sinkpad, "activating push");
6103 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
6108 qtdemux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
6109 GstPadMode mode, gboolean active)
6112 GstQTDemux *demux = GST_QTDEMUX (parent);
6115 case GST_PAD_MODE_PUSH:
6116 demux->pullbased = FALSE;
6119 case GST_PAD_MODE_PULL:
6121 demux->pullbased = TRUE;
6122 res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_qtdemux_loop,
6125 res = gst_pad_stop_task (sinkpad);
6137 qtdemux_zalloc (void *opaque, unsigned int items, unsigned int size)
6139 return g_malloc (items * size);
6143 qtdemux_zfree (void *opaque, void *addr)
6149 qtdemux_inflate (void *z_buffer, guint z_length, guint length)
6155 z = g_new0 (z_stream, 1);
6156 z->zalloc = qtdemux_zalloc;
6157 z->zfree = qtdemux_zfree;
6160 z->next_in = z_buffer;
6161 z->avail_in = z_length;
6163 buffer = (guint8 *) g_malloc (length);
6164 ret = inflateInit (z);
6165 while (z->avail_in > 0) {
6166 if (z->avail_out == 0) {
6168 buffer = (guint8 *) g_realloc (buffer, length);
6169 z->next_out = buffer + z->total_out;
6170 z->avail_out = 1024;
6172 ret = inflate (z, Z_SYNC_FLUSH);
6176 if (ret != Z_STREAM_END) {
6177 g_warning ("inflate() returned %d", ret);
6183 #endif /* HAVE_ZLIB */
6186 qtdemux_parse_moov (GstQTDemux * qtdemux, const guint8 * buffer, guint length)
6190 qtdemux->moov_node = g_node_new ((guint8 *) buffer);
6192 /* counts as header data */
6193 qtdemux->header_size += length;
6195 GST_DEBUG_OBJECT (qtdemux, "parsing 'moov' atom");
6196 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buffer, length);
6198 cmov = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_cmov);
6204 dcom = qtdemux_tree_get_child_by_type (cmov, FOURCC_dcom);
6205 cmvd = qtdemux_tree_get_child_by_type (cmov, FOURCC_cmvd);
6206 if (dcom == NULL || cmvd == NULL)
6207 goto invalid_compression;
6209 method = QT_FOURCC ((guint8 *) dcom->data + 8);
6212 case GST_MAKE_FOURCC ('z', 'l', 'i', 'b'):{
6213 guint uncompressed_length;
6214 guint compressed_length;
6217 uncompressed_length = QT_UINT32 ((guint8 *) cmvd->data + 8);
6218 compressed_length = QT_UINT32 ((guint8 *) cmvd->data + 4) - 12;
6219 GST_LOG ("length = %u", uncompressed_length);
6222 (guint8 *) qtdemux_inflate ((guint8 *) cmvd->data + 12,
6223 compressed_length, uncompressed_length);
6225 qtdemux->moov_node_compressed = qtdemux->moov_node;
6226 qtdemux->moov_node = g_node_new (buf);
6228 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buf,
6229 uncompressed_length);
6232 #endif /* HAVE_ZLIB */
6234 GST_WARNING_OBJECT (qtdemux, "unknown or unhandled header compression "
6235 "type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (method));
6242 invalid_compression:
6244 GST_ERROR_OBJECT (qtdemux, "invalid compressed header");
6250 qtdemux_parse_container (GstQTDemux * qtdemux, GNode * node, const guint8 * buf,
6253 while (G_UNLIKELY (buf < end)) {
6257 if (G_UNLIKELY (buf + 4 > end)) {
6258 GST_LOG_OBJECT (qtdemux, "buffer overrun");
6261 len = QT_UINT32 (buf);
6262 if (G_UNLIKELY (len == 0)) {
6263 GST_LOG_OBJECT (qtdemux, "empty container");
6266 if (G_UNLIKELY (len < 8)) {
6267 GST_WARNING_OBJECT (qtdemux, "length too short (%d < 8)", len);
6270 if (G_UNLIKELY (len > (end - buf))) {
6271 GST_WARNING_OBJECT (qtdemux, "length too long (%d > %d)", len,
6272 (gint) (end - buf));
6276 child = g_node_new ((guint8 *) buf);
6277 g_node_append (node, child);
6278 GST_LOG_OBJECT (qtdemux, "adding new node of len %d", len);
6279 qtdemux_parse_node (qtdemux, child, buf, len);
6287 qtdemux_parse_theora_extension (GstQTDemux * qtdemux, QtDemuxStream * stream,
6290 int len = QT_UINT32 (xdxt->data);
6291 guint8 *buf = xdxt->data;
6292 guint8 *end = buf + len;
6295 /* skip size and type */
6303 size = QT_UINT32 (buf);
6304 type = QT_FOURCC (buf + 4);
6306 GST_LOG_OBJECT (qtdemux, "%p %p", buf, end);
6308 if (buf + size > end || size <= 0)
6314 GST_WARNING_OBJECT (qtdemux, "have cookie %" GST_FOURCC_FORMAT,
6315 GST_FOURCC_ARGS (type));
6319 buffer = gst_buffer_new_and_alloc (size);
6320 gst_buffer_fill (buffer, 0, buf, size);
6321 stream->buffers = g_slist_append (stream->buffers, buffer);
6322 GST_LOG_OBJECT (qtdemux, "parsing theora header");
6325 buffer = gst_buffer_new_and_alloc (size);
6326 gst_buffer_fill (buffer, 0, buf, size);
6327 stream->buffers = g_slist_append (stream->buffers, buffer);
6328 GST_LOG_OBJECT (qtdemux, "parsing theora comment");
6331 buffer = gst_buffer_new_and_alloc (size);
6332 gst_buffer_fill (buffer, 0, buf, size);
6333 stream->buffers = g_slist_append (stream->buffers, buffer);
6334 GST_LOG_OBJECT (qtdemux, "parsing theora codebook");
6337 GST_WARNING_OBJECT (qtdemux,
6338 "unknown theora cookie %" GST_FOURCC_FORMAT,
6339 GST_FOURCC_ARGS (type));
6348 qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node, const guint8 * buffer,
6352 guint32 node_length = 0;
6353 const QtNodeType *type;
6356 GST_LOG_OBJECT (qtdemux, "qtdemux_parse buffer %p length %u", buffer, length);
6358 if (G_UNLIKELY (length < 8))
6359 goto not_enough_data;
6361 node_length = QT_UINT32 (buffer);
6362 fourcc = QT_FOURCC (buffer + 4);
6364 /* ignore empty nodes */
6365 if (G_UNLIKELY (fourcc == 0 || node_length == 8))
6368 type = qtdemux_type_get (fourcc);
6370 end = buffer + length;
6372 GST_LOG_OBJECT (qtdemux,
6373 "parsing '%" GST_FOURCC_FORMAT "', length=%u, name '%s'",
6374 GST_FOURCC_ARGS (fourcc), node_length, type->name);
6376 if (node_length > length)
6377 goto broken_atom_size;
6379 if (type->flags & QT_FLAG_CONTAINER) {
6380 qtdemux_parse_container (qtdemux, node, buffer + 8, end);
6385 if (node_length < 20) {
6386 GST_LOG_OBJECT (qtdemux, "skipping small stsd box");
6389 GST_DEBUG_OBJECT (qtdemux,
6390 "parsing stsd (sample table, sample description) atom");
6391 /* Skip over 8 byte atom hdr + 1 byte version, 3 bytes flags, 4 byte num_entries */
6392 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
6402 /* also read alac (or whatever) in stead of mp4a in the following,
6403 * since a similar layout is used in other cases as well */
6404 if (fourcc == FOURCC_mp4a)
6409 /* There are two things we might encounter here: a true mp4a atom, and
6410 an mp4a entry in an stsd atom. The latter is what we're interested
6411 in, and it looks like an atom, but isn't really one. The true mp4a
6412 atom is short, so we detect it based on length here. */
6413 if (length < min_size) {
6414 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
6415 GST_FOURCC_ARGS (fourcc));
6419 /* 'version' here is the sound sample description version. Types 0 and
6420 1 are documented in the QTFF reference, but type 2 is not: it's
6421 described in Apple header files instead (struct SoundDescriptionV2
6423 version = QT_UINT16 (buffer + 16);
6425 GST_DEBUG_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT " version 0x%08x",
6426 GST_FOURCC_ARGS (fourcc), version);
6428 /* parse any esds descriptors */
6440 GST_WARNING_OBJECT (qtdemux,
6441 "unhandled %" GST_FOURCC_FORMAT " version 0x%08x",
6442 GST_FOURCC_ARGS (fourcc), version);
6447 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
6464 /* codec_data is contained inside these atoms, which all have
6465 * the same format. */
6467 GST_DEBUG_OBJECT (qtdemux, "parsing in %" GST_FOURCC_FORMAT,
6468 GST_FOURCC_ARGS (fourcc));
6469 version = QT_UINT32 (buffer + 16);
6470 GST_DEBUG_OBJECT (qtdemux, "version %08x", version);
6471 if (1 || version == 0x00000000) {
6472 buf = buffer + 0x32;
6474 /* FIXME Quicktime uses PASCAL string while
6475 * the iso format uses C strings. Check the file
6476 * type before attempting to parse the string here. */
6477 tlen = QT_UINT8 (buf);
6478 GST_DEBUG_OBJECT (qtdemux, "tlen = %d", tlen);
6480 GST_DEBUG_OBJECT (qtdemux, "string = %.*s", tlen, (char *) buf);
6481 /* the string has a reserved space of 32 bytes so skip
6482 * the remaining 31 */
6484 buf += 4; /* and 4 bytes reserved */
6486 GST_MEMDUMP_OBJECT (qtdemux, "mp4v", buf, end - buf);
6488 qtdemux_parse_container (qtdemux, node, buf, end);
6494 GST_MEMDUMP_OBJECT (qtdemux, "H264", buffer, end - buffer);
6495 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
6500 GST_MEMDUMP_OBJECT (qtdemux, "avc1", buffer, end - buffer);
6501 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
6506 GST_MEMDUMP_OBJECT (qtdemux, "avc3", buffer, end - buffer);
6507 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
6512 GST_MEMDUMP_OBJECT (qtdemux, "H265", buffer, end - buffer);
6513 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
6518 GST_MEMDUMP_OBJECT (qtdemux, "hvc1", buffer, end - buffer);
6519 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
6524 GST_MEMDUMP_OBJECT (qtdemux, "hev1", buffer, end - buffer);
6525 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
6530 qtdemux_parse_container (qtdemux, node, buffer + 86, end);
6535 GST_DEBUG_OBJECT (qtdemux, "parsing meta atom");
6536 qtdemux_parse_container (qtdemux, node, buffer + 12, end);
6541 GST_MEMDUMP_OBJECT (qtdemux, "mp4s", buffer, end - buffer);
6542 /* Skip 8 byte header, plus 8 byte version + flags + entry_count */
6543 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
6551 version = QT_UINT32 (buffer + 12);
6552 GST_DEBUG_OBJECT (qtdemux, "parsing XiTh atom version 0x%08x", version);
6559 GST_DEBUG_OBJECT (qtdemux, "unknown version 0x%08x", version);
6564 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
6569 qtdemux_parse_container (qtdemux, node, buffer + 0x34, end);
6574 qtdemux_parse_uuid (qtdemux, buffer, end - buffer);
6579 qtdemux_parse_container (qtdemux, node, buffer + 86, end);
6584 qtdemux_parse_container (qtdemux, node, buffer + 36, end);
6588 if (!strcmp (type->name, "unknown"))
6589 GST_MEMDUMP ("Unknown tag", buffer + 4, end - buffer - 4);
6593 GST_LOG_OBJECT (qtdemux, "parsed '%" GST_FOURCC_FORMAT "'",
6594 GST_FOURCC_ARGS (fourcc));
6600 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
6601 (_("This file is corrupt and cannot be played.")),
6602 ("Not enough data for an atom header, got only %u bytes", length));
6607 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
6608 (_("This file is corrupt and cannot be played.")),
6609 ("Atom '%" GST_FOURCC_FORMAT "' has size of %u bytes, but we have only "
6610 "%u bytes available.", GST_FOURCC_ARGS (fourcc), node_length,
6617 qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc)
6621 guint32 child_fourcc;
6623 for (child = g_node_first_child (node); child;
6624 child = g_node_next_sibling (child)) {
6625 buffer = (guint8 *) child->data;
6627 child_fourcc = QT_FOURCC (buffer + 4);
6629 if (G_UNLIKELY (child_fourcc == fourcc)) {
6637 qtdemux_tree_get_child_by_type_full (GNode * node, guint32 fourcc,
6638 GstByteReader * parser)
6642 guint32 child_fourcc, child_len;
6644 for (child = g_node_first_child (node); child;
6645 child = g_node_next_sibling (child)) {
6646 buffer = (guint8 *) child->data;
6648 child_len = QT_UINT32 (buffer);
6649 child_fourcc = QT_FOURCC (buffer + 4);
6651 if (G_UNLIKELY (child_fourcc == fourcc)) {
6652 if (G_UNLIKELY (child_len < (4 + 4)))
6654 /* FIXME: must verify if atom length < parent atom length */
6655 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
6663 qtdemux_tree_get_sibling_by_type_full (GNode * node, guint32 fourcc,
6664 GstByteReader * parser)
6668 guint32 child_fourcc, child_len;
6670 for (child = g_node_next_sibling (node); child;
6671 child = g_node_next_sibling (child)) {
6672 buffer = (guint8 *) child->data;
6674 child_fourcc = QT_FOURCC (buffer + 4);
6676 if (child_fourcc == fourcc) {
6678 child_len = QT_UINT32 (buffer);
6679 if (G_UNLIKELY (child_len < (4 + 4)))
6681 /* FIXME: must verify if atom length < parent atom length */
6682 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
6691 qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc)
6693 return qtdemux_tree_get_sibling_by_type_full (node, fourcc, NULL);
6697 qtdemux_do_allocation (GstQTDemux * qtdemux, QtDemuxStream * stream)
6699 /* FIXME: This can only reliably work if demuxers have a
6700 * separate streaming thread per srcpad. This should be
6701 * done in a demuxer base class, which integrates parts
6704 * https://bugzilla.gnome.org/show_bug.cgi?id=701856
6709 query = gst_query_new_allocation (stream->caps, FALSE);
6711 if (!gst_pad_peer_query (stream->pad, query)) {
6712 /* not a problem, just debug a little */
6713 GST_DEBUG_OBJECT (qtdemux, "peer ALLOCATION query failed");
6716 if (stream->allocator)
6717 gst_object_unref (stream->allocator);
6719 if (gst_query_get_n_allocation_params (query) > 0) {
6720 /* try the allocator */
6721 gst_query_parse_nth_allocation_param (query, 0, &stream->allocator,
6723 stream->use_allocator = TRUE;
6725 stream->allocator = NULL;
6726 gst_allocation_params_init (&stream->params);
6727 stream->use_allocator = FALSE;
6729 gst_query_unref (query);
6734 gst_qtdemux_configure_protected_caps (GstQTDemux * qtdemux,
6735 QtDemuxStream * stream)
6738 const gchar *selected_system;
6740 g_return_val_if_fail (qtdemux != NULL, FALSE);
6741 g_return_val_if_fail (stream != NULL, FALSE);
6742 g_return_val_if_fail (gst_caps_get_size (stream->caps) == 1, FALSE);
6744 if (stream->protection_scheme_type != FOURCC_cenc) {
6745 GST_ERROR_OBJECT (qtdemux, "unsupported protection scheme");
6748 if (qtdemux->protection_system_ids == NULL) {
6749 GST_ERROR_OBJECT (qtdemux, "stream is protected using cenc, but no "
6750 "cenc protection system information has been found");
6753 g_ptr_array_add (qtdemux->protection_system_ids, NULL);
6754 selected_system = gst_protection_select_system ((const gchar **)
6755 qtdemux->protection_system_ids->pdata);
6756 g_ptr_array_remove_index (qtdemux->protection_system_ids,
6757 qtdemux->protection_system_ids->len - 1);
6758 if (!selected_system) {
6759 GST_ERROR_OBJECT (qtdemux, "stream is protected, but no "
6760 "suitable decryptor element has been found");
6764 s = gst_caps_get_structure (stream->caps, 0);
6765 gst_structure_set (s,
6766 "original-media-type", G_TYPE_STRING, gst_structure_get_name (s),
6767 GST_PROTECTION_SYSTEM_ID_CAPS_FIELD, G_TYPE_STRING, selected_system,
6769 gst_structure_set_name (s, "application/x-cenc");
6774 gst_qtdemux_configure_stream (GstQTDemux * qtdemux, QtDemuxStream * stream)
6776 if (stream->subtype == FOURCC_vide) {
6777 /* fps is calculated base on the duration of the average framerate since
6778 * qt does not have a fixed framerate. */
6779 if ((stream->n_samples == 1) && (stream->first_duration == 0)) {
6784 if (stream->duration == 0 || stream->n_samples < 2) {
6785 stream->fps_n = stream->timescale;
6788 /* Calculate a framerate, ignoring the first sample which is sometimes truncated */
6789 /* stream->duration is guint64, timescale, n_samples are guint32 */
6790 GstClockTime avg_duration =
6791 gst_util_uint64_scale_round (stream->duration -
6792 stream->first_duration, GST_SECOND,
6793 (guint64) (stream->timescale) * (stream->n_samples - 1));
6795 GST_LOG_OBJECT (qtdemux,
6796 "Calculating avg sample duration based on stream duration %"
6798 " minus first sample %u, leaving %d samples gives %"
6799 GST_TIME_FORMAT, stream->duration, stream->first_duration,
6800 stream->n_samples - 1, GST_TIME_ARGS (avg_duration));
6802 gst_video_guess_framerate (avg_duration, &stream->fps_n,
6805 GST_DEBUG_OBJECT (qtdemux,
6806 "Calculating framerate, timescale %u gave fps_n %d fps_d %d",
6807 stream->timescale, stream->fps_n, stream->fps_d);
6811 stream->caps = gst_caps_make_writable (stream->caps);
6813 gst_caps_set_simple (stream->caps,
6814 "width", G_TYPE_INT, stream->width,
6815 "height", G_TYPE_INT, stream->height,
6816 "framerate", GST_TYPE_FRACTION, stream->fps_n, stream->fps_d, NULL);
6818 /* calculate pixel-aspect-ratio using display width and height */
6819 GST_DEBUG_OBJECT (qtdemux,
6820 "video size %dx%d, target display size %dx%d", stream->width,
6821 stream->height, stream->display_width, stream->display_height);
6822 /* qt file might have pasp atom */
6823 if (stream->par_w > 0 && stream->par_h > 0) {
6824 GST_DEBUG_OBJECT (qtdemux, "par %d:%d", stream->par_w, stream->par_h);
6825 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
6826 GST_TYPE_FRACTION, stream->par_w, stream->par_h, NULL);
6827 } else if (stream->display_width > 0 && stream->display_height > 0 &&
6828 stream->width > 0 && stream->height > 0) {
6831 /* calculate the pixel aspect ratio using the display and pixel w/h */
6832 n = stream->display_width * stream->height;
6833 d = stream->display_height * stream->width;
6836 GST_DEBUG_OBJECT (qtdemux, "setting PAR to %d/%d", n, d);
6839 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
6840 GST_TYPE_FRACTION, stream->par_w, stream->par_h, NULL);
6843 if (stream->multiview_mode != GST_VIDEO_MULTIVIEW_MODE_NONE) {
6844 guint par_w = 1, par_h = 1;
6846 if (stream->par_w > 0 && stream->par_h > 0) {
6847 par_w = stream->par_w;
6848 par_h = stream->par_h;
6851 if (gst_video_multiview_guess_half_aspect (stream->multiview_mode,
6852 stream->width, stream->height, par_w, par_h)) {
6853 stream->multiview_flags |= GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT;
6856 gst_caps_set_simple (stream->caps,
6857 "multiview-mode", G_TYPE_STRING,
6858 gst_video_multiview_mode_to_caps_string (stream->multiview_mode),
6859 "multiview-flags", GST_TYPE_VIDEO_MULTIVIEW_FLAGSET,
6860 stream->multiview_flags, GST_FLAG_SET_MASK_EXACT, NULL);
6865 else if (stream->subtype == FOURCC_soun) {
6867 stream->caps = gst_caps_make_writable (stream->caps);
6868 if (stream->rate > 0)
6869 gst_caps_set_simple (stream->caps,
6870 "rate", G_TYPE_INT, (int) stream->rate, NULL);
6871 if (stream->n_channels > 0)
6872 gst_caps_set_simple (stream->caps,
6873 "channels", G_TYPE_INT, stream->n_channels, NULL);
6874 if (stream->n_channels > 2) {
6875 /* FIXME: Need to parse the 'chan' atom to get channel layouts
6876 * correctly; this is just the minimum we can do - assume
6877 * we don't actually have any channel positions. */
6878 gst_caps_set_simple (stream->caps,
6879 "channel-mask", GST_TYPE_BITMASK, G_GUINT64_CONSTANT (0), NULL);
6885 GST_PAD_ELEMENT_PRIVATE (stream->pad) = stream;
6886 gst_pad_set_event_function (stream->pad, gst_qtdemux_handle_src_event);
6887 gst_pad_set_query_function (stream->pad, gst_qtdemux_handle_src_query);
6888 gst_pad_set_active (stream->pad, TRUE);
6890 gst_pad_use_fixed_caps (stream->pad);
6892 if (stream->protected) {
6893 if (!gst_qtdemux_configure_protected_caps (qtdemux, stream)) {
6894 GST_ERROR_OBJECT (qtdemux,
6895 "Failed to configure protected stream caps.");
6900 GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT, stream->caps);
6901 if (stream->new_stream) {
6904 GstStreamFlags stream_flags;
6907 gst_pad_get_sticky_event (qtdemux->sinkpad, GST_EVENT_STREAM_START,
6910 if (gst_event_parse_group_id (event, &qtdemux->group_id))
6911 qtdemux->have_group_id = TRUE;
6913 qtdemux->have_group_id = FALSE;
6914 gst_event_unref (event);
6915 } else if (!qtdemux->have_group_id) {
6916 qtdemux->have_group_id = TRUE;
6917 qtdemux->group_id = gst_util_group_id_next ();
6920 stream->new_stream = FALSE;
6922 gst_pad_create_stream_id_printf (stream->pad,
6923 GST_ELEMENT_CAST (qtdemux), "%03u", stream->track_id);
6924 event = gst_event_new_stream_start (stream_id);
6925 if (qtdemux->have_group_id)
6926 gst_event_set_group_id (event, qtdemux->group_id);
6927 stream_flags = GST_STREAM_FLAG_NONE;
6928 if (stream->disabled)
6929 stream_flags |= GST_STREAM_FLAG_UNSELECT;
6931 stream_flags |= GST_STREAM_FLAG_SPARSE;
6932 gst_event_set_stream_flags (event, stream_flags);
6933 gst_pad_push_event (stream->pad, event);
6936 gst_pad_set_caps (stream->pad, stream->caps);
6937 stream->new_caps = FALSE;
6943 gst_qtdemux_add_stream (GstQTDemux * qtdemux,
6944 QtDemuxStream * stream, GstTagList * list)
6946 /* consistent default for push based mode */
6947 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
6949 if (stream->subtype == FOURCC_vide) {
6950 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
6953 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
6956 gst_qtdemux_configure_stream (qtdemux, stream);
6957 qtdemux->n_video_streams++;
6958 } else if (stream->subtype == FOURCC_soun) {
6959 gchar *name = g_strdup_printf ("audio_%u", qtdemux->n_audio_streams);
6962 gst_pad_new_from_static_template (&gst_qtdemux_audiosrc_template, name);
6964 gst_qtdemux_configure_stream (qtdemux, stream);
6965 qtdemux->n_audio_streams++;
6966 } else if (stream->subtype == FOURCC_strm) {
6967 GST_DEBUG_OBJECT (qtdemux, "stream type, not creating pad");
6968 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
6969 || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt) {
6970 gchar *name = g_strdup_printf ("subtitle_%u", qtdemux->n_sub_streams);
6973 gst_pad_new_from_static_template (&gst_qtdemux_subsrc_template, name);
6975 gst_qtdemux_configure_stream (qtdemux, stream);
6976 qtdemux->n_sub_streams++;
6977 } else if (stream->caps) {
6978 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
6981 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
6983 gst_qtdemux_configure_stream (qtdemux, stream);
6984 qtdemux->n_video_streams++;
6986 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
6993 GST_DEBUG_OBJECT (qtdemux, "adding pad %s %p to qtdemux %p",
6994 GST_OBJECT_NAME (stream->pad), stream->pad, qtdemux);
6995 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
6996 gst_flow_combiner_add_pad (qtdemux->flowcombiner, stream->pad);
6998 if (stream->pending_tags)
6999 gst_tag_list_unref (stream->pending_tags);
7000 stream->pending_tags = list;
7002 /* global tags go on each pad anyway */
7003 stream->send_global_tags = TRUE;
7004 /* send upstream GST_EVENT_PROTECTION events that were received before
7005 this source pad was created */
7006 for (l = qtdemux->protection_event_queue.head; l != NULL; l = l->next)
7007 gst_pad_push_event (stream->pad, gst_event_ref (l->data));
7011 gst_tag_list_unref (list);
7015 /* find next atom with @fourcc starting at @offset */
7016 static GstFlowReturn
7017 qtdemux_find_atom (GstQTDemux * qtdemux, guint64 * offset,
7018 guint64 * length, guint32 fourcc)
7024 GST_LOG_OBJECT (qtdemux, "finding fourcc %" GST_FOURCC_FORMAT " at offset %"
7025 G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), *offset);
7031 ret = gst_pad_pull_range (qtdemux->sinkpad, *offset, 16, &buf);
7032 if (G_UNLIKELY (ret != GST_FLOW_OK))
7034 if (G_UNLIKELY (gst_buffer_get_size (buf) != 16)) {
7037 gst_buffer_unref (buf);
7040 gst_buffer_map (buf, &map, GST_MAP_READ);
7041 extract_initial_length_and_fourcc (map.data, 16, length, &lfourcc);
7042 gst_buffer_unmap (buf, &map);
7043 gst_buffer_unref (buf);
7045 if (G_UNLIKELY (*length == 0)) {
7046 GST_DEBUG_OBJECT (qtdemux, "invalid length 0");
7047 ret = GST_FLOW_ERROR;
7051 if (lfourcc == fourcc) {
7052 GST_DEBUG_OBJECT (qtdemux, "found fourcc at offset %" G_GUINT64_FORMAT,
7056 GST_LOG_OBJECT (qtdemux,
7057 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
7058 GST_FOURCC_ARGS (fourcc), *offset);
7067 /* might simply have had last one */
7068 GST_DEBUG_OBJECT (qtdemux, "fourcc not found");
7073 /* should only do something in pull mode */
7074 /* call with OBJECT lock */
7075 static GstFlowReturn
7076 qtdemux_add_fragmented_samples (GstQTDemux * qtdemux)
7078 guint64 length, offset;
7079 GstBuffer *buf = NULL;
7080 GstFlowReturn ret = GST_FLOW_OK;
7081 GstFlowReturn res = GST_FLOW_OK;
7084 offset = qtdemux->moof_offset;
7085 GST_DEBUG_OBJECT (qtdemux, "next moof at offset %" G_GUINT64_FORMAT, offset);
7088 GST_DEBUG_OBJECT (qtdemux, "no next moof");
7089 return GST_FLOW_EOS;
7092 /* best not do pull etc with lock held */
7093 GST_OBJECT_UNLOCK (qtdemux);
7095 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
7096 if (ret != GST_FLOW_OK)
7099 ret = gst_qtdemux_pull_atom (qtdemux, offset, length, &buf);
7100 if (G_UNLIKELY (ret != GST_FLOW_OK))
7102 gst_buffer_map (buf, &map, GST_MAP_READ);
7103 if (!qtdemux_parse_moof (qtdemux, map.data, map.size, offset, NULL)) {
7104 gst_buffer_unmap (buf, &map);
7105 gst_buffer_unref (buf);
7110 gst_buffer_unmap (buf, &map);
7111 gst_buffer_unref (buf);
7115 /* look for next moof */
7116 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
7117 if (G_UNLIKELY (ret != GST_FLOW_OK))
7121 GST_OBJECT_LOCK (qtdemux);
7123 qtdemux->moof_offset = offset;
7129 GST_DEBUG_OBJECT (qtdemux, "failed to parse moof");
7131 res = GST_FLOW_ERROR;
7136 /* maybe upstream temporarily flushing */
7137 if (ret != GST_FLOW_FLUSHING) {
7138 GST_DEBUG_OBJECT (qtdemux, "no next moof");
7141 GST_DEBUG_OBJECT (qtdemux, "upstream WRONG_STATE");
7142 /* resume at current position next time */
7149 /* initialise bytereaders for stbl sub-atoms */
7151 qtdemux_stbl_init (GstQTDemux * qtdemux, QtDemuxStream * stream, GNode * stbl)
7153 stream->stbl_index = -1; /* no samples have yet been parsed */
7154 stream->sample_index = -1;
7156 /* time-to-sample atom */
7157 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stts, &stream->stts))
7160 /* copy atom data into a new buffer for later use */
7161 stream->stts.data = g_memdup (stream->stts.data, stream->stts.size);
7163 /* skip version + flags */
7164 if (!gst_byte_reader_skip (&stream->stts, 1 + 3) ||
7165 !gst_byte_reader_get_uint32_be (&stream->stts, &stream->n_sample_times))
7167 GST_LOG_OBJECT (qtdemux, "%u timestamp blocks", stream->n_sample_times);
7169 /* make sure there's enough data */
7170 if (!qt_atom_parser_has_chunks (&stream->stts, stream->n_sample_times, 8)) {
7171 stream->n_sample_times = gst_byte_reader_get_remaining (&stream->stts) / 8;
7172 GST_LOG_OBJECT (qtdemux, "overriding to %u timestamp blocks",
7173 stream->n_sample_times);
7174 if (!stream->n_sample_times)
7178 /* sync sample atom */
7179 stream->stps_present = FALSE;
7180 if ((stream->stss_present =
7181 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stss,
7182 &stream->stss) ? TRUE : FALSE) == TRUE) {
7183 /* copy atom data into a new buffer for later use */
7184 stream->stss.data = g_memdup (stream->stss.data, stream->stss.size);
7186 /* skip version + flags */
7187 if (!gst_byte_reader_skip (&stream->stss, 1 + 3) ||
7188 !gst_byte_reader_get_uint32_be (&stream->stss, &stream->n_sample_syncs))
7191 if (stream->n_sample_syncs) {
7192 /* make sure there's enough data */
7193 if (!qt_atom_parser_has_chunks (&stream->stss, stream->n_sample_syncs, 4))
7197 /* partial sync sample atom */
7198 if ((stream->stps_present =
7199 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stps,
7200 &stream->stps) ? TRUE : FALSE) == TRUE) {
7201 /* copy atom data into a new buffer for later use */
7202 stream->stps.data = g_memdup (stream->stps.data, stream->stps.size);
7204 /* skip version + flags */
7205 if (!gst_byte_reader_skip (&stream->stps, 1 + 3) ||
7206 !gst_byte_reader_get_uint32_be (&stream->stps,
7207 &stream->n_sample_partial_syncs))
7210 /* if there are no entries, the stss table contains the real
7212 if (stream->n_sample_partial_syncs) {
7213 /* make sure there's enough data */
7214 if (!qt_atom_parser_has_chunks (&stream->stps,
7215 stream->n_sample_partial_syncs, 4))
7222 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsz, &stream->stsz))
7225 /* copy atom data into a new buffer for later use */
7226 stream->stsz.data = g_memdup (stream->stsz.data, stream->stsz.size);
7228 /* skip version + flags */
7229 if (!gst_byte_reader_skip (&stream->stsz, 1 + 3) ||
7230 !gst_byte_reader_get_uint32_be (&stream->stsz, &stream->sample_size))
7233 if (!gst_byte_reader_get_uint32_be (&stream->stsz, &stream->n_samples))
7236 if (!stream->n_samples)
7239 /* sample-to-chunk atom */
7240 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsc, &stream->stsc))
7243 /* copy atom data into a new buffer for later use */
7244 stream->stsc.data = g_memdup (stream->stsc.data, stream->stsc.size);
7246 /* skip version + flags */
7247 if (!gst_byte_reader_skip (&stream->stsc, 1 + 3) ||
7248 !gst_byte_reader_get_uint32_be (&stream->stsc,
7249 &stream->n_samples_per_chunk))
7252 GST_DEBUG_OBJECT (qtdemux, "n_samples_per_chunk %u",
7253 stream->n_samples_per_chunk);
7255 /* make sure there's enough data */
7256 if (!qt_atom_parser_has_chunks (&stream->stsc, stream->n_samples_per_chunk,
7262 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stco, &stream->stco))
7263 stream->co_size = sizeof (guint32);
7264 else if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_co64,
7266 stream->co_size = sizeof (guint64);
7270 /* copy atom data into a new buffer for later use */
7271 stream->stco.data = g_memdup (stream->stco.data, stream->stco.size);
7273 /* skip version + flags */
7274 if (!gst_byte_reader_skip (&stream->stco, 1 + 3))
7277 /* chunks_are_samples == TRUE means treat chunks as samples */
7278 stream->chunks_are_samples = stream->sample_size && !stream->sampled;
7279 if (stream->chunks_are_samples) {
7280 /* treat chunks as samples */
7281 if (!gst_byte_reader_get_uint32_be (&stream->stco, &stream->n_samples))
7284 /* skip number of entries */
7285 if (!gst_byte_reader_skip (&stream->stco, 4))
7288 /* make sure there are enough data in the stsz atom */
7289 if (!stream->sample_size) {
7290 /* different sizes for each sample */
7291 if (!qt_atom_parser_has_chunks (&stream->stsz, stream->n_samples, 4))
7296 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
7297 stream->n_samples, (guint) sizeof (QtDemuxSample),
7298 stream->n_samples * sizeof (QtDemuxSample) / (1024.0 * 1024.0));
7300 if (stream->n_samples >=
7301 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample)) {
7302 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
7303 "be larger than %uMB (broken file?)", stream->n_samples,
7304 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
7308 g_assert (stream->samples == NULL);
7309 stream->samples = g_try_new0 (QtDemuxSample, stream->n_samples);
7310 if (!stream->samples) {
7311 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
7316 /* composition time-to-sample */
7317 if ((stream->ctts_present =
7318 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_ctts,
7319 &stream->ctts) ? TRUE : FALSE) == TRUE) {
7320 GstByteReader cslg = GST_BYTE_READER_INIT (NULL, 0);
7322 /* copy atom data into a new buffer for later use */
7323 stream->ctts.data = g_memdup (stream->ctts.data, stream->ctts.size);
7325 /* skip version + flags */
7326 if (!gst_byte_reader_skip (&stream->ctts, 1 + 3)
7327 || !gst_byte_reader_get_uint32_be (&stream->ctts,
7328 &stream->n_composition_times))
7331 /* make sure there's enough data */
7332 if (!qt_atom_parser_has_chunks (&stream->ctts, stream->n_composition_times,
7336 /* This is optional, if missing we iterate the ctts */
7337 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_cslg, &cslg)) {
7338 if (!gst_byte_reader_skip (&cslg, 1 + 3)
7339 || !gst_byte_reader_get_uint32_be (&cslg, &stream->cslg_shift)) {
7340 g_free ((gpointer) cslg.data);
7344 gint32 cslg_least = 0;
7345 guint num_entries, pos;
7348 pos = gst_byte_reader_get_pos (&stream->ctts);
7349 num_entries = stream->n_composition_times;
7351 stream->cslg_shift = 0;
7353 for (i = 0; i < num_entries; i++) {
7356 gst_byte_reader_skip_unchecked (&stream->ctts, 4);
7357 offset = gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
7359 if (offset < cslg_least)
7360 cslg_least = offset;
7364 stream->cslg_shift = ABS (cslg_least);
7366 stream->cslg_shift = 0;
7368 /* reset the reader so we can generate sample table */
7369 gst_byte_reader_set_pos (&stream->ctts, pos);
7372 /* Ensure the cslg_shift value is consistent so we can use it
7373 * unconditionnally to produce TS and Segment */
7374 stream->cslg_shift = 0;
7381 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
7382 (_("This file is corrupt and cannot be played.")), (NULL));
7387 gst_qtdemux_stbl_free (stream);
7388 if (!qtdemux->fragmented) {
7389 /* not quite good */
7390 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
7393 /* may pick up samples elsewhere */
7399 /* collect samples from the next sample to be parsed up to sample @n for @stream
7400 * by reading the info from @stbl
7402 * This code can be executed from both the streaming thread and the seeking
7403 * thread so it takes the object lock to protect itself
7406 qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream, guint32 n)
7409 QtDemuxSample *samples, *first, *cur, *last;
7410 guint32 n_samples_per_chunk;
7413 GST_LOG_OBJECT (qtdemux, "parsing samples for stream fourcc %"
7414 GST_FOURCC_FORMAT ", pad %s", GST_FOURCC_ARGS (stream->fourcc),
7415 stream->pad ? GST_PAD_NAME (stream->pad) : "(NULL)");
7417 n_samples = stream->n_samples;
7420 goto out_of_samples;
7422 GST_OBJECT_LOCK (qtdemux);
7423 if (n <= stream->stbl_index)
7424 goto already_parsed;
7426 GST_DEBUG_OBJECT (qtdemux, "parsing up to sample %u", n);
7428 if (!stream->stsz.data) {
7429 /* so we already parsed and passed all the moov samples;
7430 * onto fragmented ones */
7431 g_assert (qtdemux->fragmented);
7435 /* pointer to the sample table */
7436 samples = stream->samples;
7438 /* starts from -1, moves to the next sample index to parse */
7439 stream->stbl_index++;
7441 /* keep track of the first and last sample to fill */
7442 first = &samples[stream->stbl_index];
7445 if (!stream->chunks_are_samples) {
7446 /* set the sample sizes */
7447 if (stream->sample_size == 0) {
7448 /* different sizes for each sample */
7449 for (cur = first; cur <= last; cur++) {
7450 cur->size = gst_byte_reader_get_uint32_be_unchecked (&stream->stsz);
7451 GST_LOG_OBJECT (qtdemux, "sample %d has size %u",
7452 (guint) (cur - samples), cur->size);
7455 /* samples have the same size */
7456 GST_LOG_OBJECT (qtdemux, "all samples have size %u", stream->sample_size);
7457 for (cur = first; cur <= last; cur++)
7458 cur->size = stream->sample_size;
7462 n_samples_per_chunk = stream->n_samples_per_chunk;
7465 for (i = stream->stsc_index; i < n_samples_per_chunk; i++) {
7468 if (stream->stsc_chunk_index >= stream->last_chunk
7469 || stream->stsc_chunk_index < stream->first_chunk) {
7470 stream->first_chunk =
7471 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
7472 stream->samples_per_chunk =
7473 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
7474 gst_byte_reader_skip_unchecked (&stream->stsc, 4);
7476 /* chunk numbers are counted from 1 it seems */
7477 if (G_UNLIKELY (stream->first_chunk == 0))
7480 --stream->first_chunk;
7482 /* the last chunk of each entry is calculated by taking the first chunk
7483 * of the next entry; except if there is no next, where we fake it with
7485 if (G_UNLIKELY (i == (stream->n_samples_per_chunk - 1))) {
7486 stream->last_chunk = G_MAXUINT32;
7488 stream->last_chunk =
7489 gst_byte_reader_peek_uint32_be_unchecked (&stream->stsc);
7490 if (G_UNLIKELY (stream->last_chunk == 0))
7493 --stream->last_chunk;
7496 GST_LOG_OBJECT (qtdemux,
7497 "entry %d has first_chunk %d, last_chunk %d, samples_per_chunk %d", i,
7498 stream->first_chunk, stream->last_chunk, stream->samples_per_chunk);
7500 if (G_UNLIKELY (stream->last_chunk < stream->first_chunk))
7503 if (stream->last_chunk != G_MAXUINT32) {
7504 if (!qt_atom_parser_peek_sub (&stream->stco,
7505 stream->first_chunk * stream->co_size,
7506 (stream->last_chunk - stream->first_chunk) * stream->co_size,
7511 stream->co_chunk = stream->stco;
7512 if (!gst_byte_reader_skip (&stream->co_chunk,
7513 stream->first_chunk * stream->co_size))
7517 stream->stsc_chunk_index = stream->first_chunk;
7520 last_chunk = stream->last_chunk;
7522 if (stream->chunks_are_samples) {
7523 cur = &samples[stream->stsc_chunk_index];
7525 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
7528 stream->stsc_chunk_index = j;
7533 qt_atom_parser_get_offset_unchecked (&stream->co_chunk,
7536 GST_LOG_OBJECT (qtdemux, "Created entry %d with offset "
7537 "%" G_GUINT64_FORMAT, j, cur->offset);
7539 if (stream->samples_per_frame * stream->bytes_per_frame) {
7541 (stream->samples_per_chunk * stream->n_channels) /
7542 stream->samples_per_frame * stream->bytes_per_frame;
7544 cur->size = stream->samples_per_chunk;
7547 GST_DEBUG_OBJECT (qtdemux,
7548 "keyframe sample %d: timestamp %" GST_TIME_FORMAT ", size %u",
7549 j, GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream,
7550 stream->stco_sample_index)), cur->size);
7552 cur->timestamp = stream->stco_sample_index;
7553 cur->duration = stream->samples_per_chunk;
7554 cur->keyframe = TRUE;
7557 stream->stco_sample_index += stream->samples_per_chunk;
7559 stream->stsc_chunk_index = j;
7561 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
7562 guint32 samples_per_chunk;
7563 guint64 chunk_offset;
7565 if (!stream->stsc_sample_index
7566 && !qt_atom_parser_get_offset (&stream->co_chunk, stream->co_size,
7567 &stream->chunk_offset))
7570 samples_per_chunk = stream->samples_per_chunk;
7571 chunk_offset = stream->chunk_offset;
7573 for (k = stream->stsc_sample_index; k < samples_per_chunk; k++) {
7574 GST_LOG_OBJECT (qtdemux, "creating entry %d with offset %"
7575 G_GUINT64_FORMAT " and size %d",
7576 (guint) (cur - samples), chunk_offset, cur->size);
7578 cur->offset = chunk_offset;
7579 chunk_offset += cur->size;
7582 if (G_UNLIKELY (cur > last)) {
7584 stream->stsc_sample_index = k + 1;
7585 stream->chunk_offset = chunk_offset;
7586 stream->stsc_chunk_index = j;
7590 stream->stsc_sample_index = 0;
7592 stream->stsc_chunk_index = j;
7594 stream->stsc_index++;
7597 if (stream->chunks_are_samples)
7601 guint32 n_sample_times;
7603 n_sample_times = stream->n_sample_times;
7606 for (i = stream->stts_index; i < n_sample_times; i++) {
7607 guint32 stts_samples;
7608 gint32 stts_duration;
7611 if (stream->stts_sample_index >= stream->stts_samples
7612 || !stream->stts_sample_index) {
7614 stream->stts_samples =
7615 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
7616 stream->stts_duration =
7617 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
7619 GST_LOG_OBJECT (qtdemux, "block %d, %u timestamps, duration %u",
7620 i, stream->stts_samples, stream->stts_duration);
7622 stream->stts_sample_index = 0;
7625 stts_samples = stream->stts_samples;
7626 stts_duration = stream->stts_duration;
7627 stts_time = stream->stts_time;
7629 for (j = stream->stts_sample_index; j < stts_samples; j++) {
7630 GST_DEBUG_OBJECT (qtdemux,
7631 "sample %d: index %d, timestamp %" GST_TIME_FORMAT,
7632 (guint) (cur - samples), j,
7633 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stts_time)));
7635 cur->timestamp = stts_time;
7636 cur->duration = stts_duration;
7638 /* avoid 32-bit wrap-around,
7639 * but still mind possible 'negative' duration */
7640 stts_time += (gint64) stts_duration;
7643 if (G_UNLIKELY (cur > last)) {
7645 stream->stts_time = stts_time;
7646 stream->stts_sample_index = j + 1;
7650 stream->stts_sample_index = 0;
7651 stream->stts_time = stts_time;
7652 stream->stts_index++;
7654 /* fill up empty timestamps with the last timestamp, this can happen when
7655 * the last samples do not decode and so we don't have timestamps for them.
7656 * We however look at the last timestamp to estimate the track length so we
7657 * need something in here. */
7658 for (; cur < last; cur++) {
7659 GST_DEBUG_OBJECT (qtdemux,
7660 "fill sample %d: timestamp %" GST_TIME_FORMAT,
7661 (guint) (cur - samples),
7662 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stream->stts_time)));
7663 cur->timestamp = stream->stts_time;
7669 /* sample sync, can be NULL */
7670 if (stream->stss_present == TRUE) {
7671 guint32 n_sample_syncs;
7673 n_sample_syncs = stream->n_sample_syncs;
7675 if (!n_sample_syncs) {
7676 GST_DEBUG_OBJECT (qtdemux, "all samples are keyframes");
7677 stream->all_keyframe = TRUE;
7679 for (i = stream->stss_index; i < n_sample_syncs; i++) {
7680 /* note that the first sample is index 1, not 0 */
7683 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stss);
7685 if (G_LIKELY (index > 0 && index <= n_samples)) {
7687 samples[index].keyframe = TRUE;
7688 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
7689 /* and exit if we have enough samples */
7690 if (G_UNLIKELY (index >= n)) {
7697 stream->stss_index = i;
7700 /* stps marks partial sync frames like open GOP I-Frames */
7701 if (stream->stps_present == TRUE) {
7702 guint32 n_sample_partial_syncs;
7704 n_sample_partial_syncs = stream->n_sample_partial_syncs;
7706 /* if there are no entries, the stss table contains the real
7708 if (n_sample_partial_syncs) {
7709 for (i = stream->stps_index; i < n_sample_partial_syncs; i++) {
7710 /* note that the first sample is index 1, not 0 */
7713 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stps);
7715 if (G_LIKELY (index > 0 && index <= n_samples)) {
7717 samples[index].keyframe = TRUE;
7718 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
7719 /* and exit if we have enough samples */
7720 if (G_UNLIKELY (index >= n)) {
7727 stream->stps_index = i;
7731 /* no stss, all samples are keyframes */
7732 stream->all_keyframe = TRUE;
7733 GST_DEBUG_OBJECT (qtdemux, "setting all keyframes");
7738 /* composition time to sample */
7739 if (stream->ctts_present == TRUE) {
7740 guint32 n_composition_times;
7742 gint32 ctts_soffset;
7744 /* Fill in the pts_offsets */
7746 n_composition_times = stream->n_composition_times;
7748 for (i = stream->ctts_index; i < n_composition_times; i++) {
7749 if (stream->ctts_sample_index >= stream->ctts_count
7750 || !stream->ctts_sample_index) {
7751 stream->ctts_count =
7752 gst_byte_reader_get_uint32_be_unchecked (&stream->ctts);
7753 stream->ctts_soffset =
7754 gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
7755 stream->ctts_sample_index = 0;
7758 ctts_count = stream->ctts_count;
7759 ctts_soffset = stream->ctts_soffset;
7761 for (j = stream->ctts_sample_index; j < ctts_count; j++) {
7762 cur->pts_offset = ctts_soffset;
7765 if (G_UNLIKELY (cur > last)) {
7767 stream->ctts_sample_index = j + 1;
7771 stream->ctts_sample_index = 0;
7772 stream->ctts_index++;
7776 stream->stbl_index = n;
7777 /* if index has been completely parsed, free data that is no-longer needed */
7778 if (n + 1 == stream->n_samples) {
7779 gst_qtdemux_stbl_free (stream);
7780 GST_DEBUG_OBJECT (qtdemux, "parsed all available samples;");
7781 if (qtdemux->pullbased) {
7782 GST_DEBUG_OBJECT (qtdemux, "checking for more samples");
7783 while (n + 1 == stream->n_samples)
7784 if (qtdemux_add_fragmented_samples (qtdemux) != GST_FLOW_OK)
7788 GST_OBJECT_UNLOCK (qtdemux);
7795 GST_LOG_OBJECT (qtdemux,
7796 "Tried to parse up to sample %u but this sample has already been parsed",
7798 /* if fragmented, there may be more */
7799 if (qtdemux->fragmented && n == stream->stbl_index)
7801 GST_OBJECT_UNLOCK (qtdemux);
7807 GST_LOG_OBJECT (qtdemux,
7808 "Tried to parse up to sample %u but there are only %u samples", n + 1,
7810 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
7811 (_("This file is corrupt and cannot be played.")), (NULL));
7816 GST_OBJECT_UNLOCK (qtdemux);
7817 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
7818 (_("This file is corrupt and cannot be played.")), (NULL));
7823 /* collect all segment info for @stream.
7826 qtdemux_parse_segments (GstQTDemux * qtdemux, QtDemuxStream * stream,
7831 /* parse and prepare segment info from the edit list */
7832 GST_DEBUG_OBJECT (qtdemux, "looking for edit list container");
7833 stream->n_segments = 0;
7834 stream->segments = NULL;
7835 if ((edts = qtdemux_tree_get_child_by_type (trak, FOURCC_edts))) {
7843 GST_DEBUG_OBJECT (qtdemux, "looking for edit list");
7844 if (!(elst = qtdemux_tree_get_child_by_type (edts, FOURCC_elst)))
7847 buffer = elst->data;
7849 n_segments = QT_UINT32 (buffer + 12);
7851 /* we might allocate a bit too much, at least allocate 1 segment */
7852 stream->segments = g_new (QtDemuxSegment, MAX (n_segments, 1));
7854 /* segments always start from 0 */
7858 for (i = 0; i < n_segments; i++) {
7861 QtDemuxSegment *segment;
7864 GstClockTime media_start = GST_CLOCK_TIME_NONE;
7867 media_time = QT_UINT32 (buffer + 20 + i * 12);
7868 duration = QT_UINT32 (buffer + 16 + i * 12);
7871 if (media_time != G_MAXUINT32)
7872 media_start = QTSTREAMTIME_TO_GSTTIME (stream, media_time);
7875 segment = &stream->segments[count++];
7877 /* time and duration expressed in global timescale */
7878 segment->time = stime;
7879 /* add non scaled values so we don't cause roundoff errors */
7881 if (duration || media_start == GST_CLOCK_TIME_NONE) {
7883 stime = QTTIME_TO_GSTTIME (qtdemux, time);
7884 segment->duration = stime - segment->time;
7886 /* zero duration does not imply media_start == media_stop
7887 * but, only specify media_start.*/
7888 stime = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
7889 if (GST_CLOCK_TIME_IS_VALID (stime) && media_time != G_MAXUINT32
7890 && stime >= media_start) {
7891 segment->duration = stime - media_start;
7893 segment->duration = GST_CLOCK_TIME_NONE;
7898 stime = QTTIME_TO_GSTTIME (qtdemux, time);
7900 segment->stop_time = stime;
7902 #ifndef GST_UPSTREAM
7903 segment->duration = stime - segment->time;
7906 segment->trak_media_start = media_time;
7907 /* media_time expressed in stream timescale */
7908 if (media_time != G_MAXUINT32) {
7910 segment->media_start = media_start;
7912 segment->media_start = QTSTREAMTIME_TO_GSTTIME (stream, media_time);
7914 segment->media_stop = segment->media_start + segment->duration;
7916 segment->media_start = GST_CLOCK_TIME_NONE;
7917 segment->media_stop = GST_CLOCK_TIME_NONE;
7919 rate_int = GST_READ_UINT32_BE (buffer + 24 + i * 12);
7921 if (rate_int <= 1) {
7922 /* 0 is not allowed, some programs write 1 instead of the floating point
7924 GST_WARNING_OBJECT (qtdemux, "found suspicious rate %" G_GUINT32_FORMAT,
7928 segment->rate = rate_int / 65536.0;
7931 GST_DEBUG_OBJECT (qtdemux, "created segment %d time %" GST_TIME_FORMAT
7932 ", duration %" GST_TIME_FORMAT ", media_start %" GST_TIME_FORMAT
7933 " (%" G_GUINT64_FORMAT ") , media_stop %" GST_TIME_FORMAT
7934 " stop_time %" GST_TIME_FORMAT " rate %g, (%d) timescale %u",
7935 i, GST_TIME_ARGS (segment->time),
7936 GST_TIME_ARGS (segment->duration),
7937 GST_TIME_ARGS (segment->media_start), media_time,
7938 GST_TIME_ARGS (segment->media_stop),
7939 GST_TIME_ARGS (segment->stop_time), segment->rate, rate_int,
7941 if (segment->stop_time > qtdemux->segment.stop) {
7942 GST_WARNING_OBJECT (qtdemux, "Segment %d "
7943 " extends to %" GST_TIME_FORMAT
7944 " past the end of the file duration %" GST_TIME_FORMAT
7945 " it will be truncated", i, GST_TIME_ARGS (segment->stop_time),
7946 GST_TIME_ARGS (qtdemux->segment.stop));
7947 qtdemux->segment.stop = segment->stop_time;
7950 GST_DEBUG_OBJECT (qtdemux, "found %d segments", count);
7951 stream->n_segments = count;
7955 /* push based does not handle segments, so act accordingly here,
7956 * and warn if applicable */
7957 if (!qtdemux->pullbased) {
7958 GST_WARNING_OBJECT (qtdemux, "streaming; discarding edit list segments");
7959 /* remove and use default one below, we stream like it anyway */
7960 g_free (stream->segments);
7961 stream->segments = NULL;
7962 stream->n_segments = 0;
7965 /* no segments, create one to play the complete trak */
7966 if (stream->n_segments == 0) {
7967 GstClockTime stream_duration =
7968 QTSTREAMTIME_TO_GSTTIME (stream, stream->duration);
7970 if (stream->segments == NULL)
7971 stream->segments = g_new (QtDemuxSegment, 1);
7973 /* represent unknown our way */
7974 if (stream_duration == 0)
7975 stream_duration = GST_CLOCK_TIME_NONE;
7977 stream->segments[0].time = 0;
7978 stream->segments[0].stop_time = stream_duration;
7979 stream->segments[0].duration = stream_duration;
7980 stream->segments[0].media_start = 0;
7981 stream->segments[0].media_stop = stream_duration;
7982 stream->segments[0].rate = 1.0;
7983 stream->segments[0].trak_media_start = 0;
7985 GST_DEBUG_OBJECT (qtdemux, "created dummy segment %" GST_TIME_FORMAT,
7986 GST_TIME_ARGS (stream_duration));
7987 stream->n_segments = 1;
7988 stream->dummy_segment = TRUE;
7990 GST_DEBUG_OBJECT (qtdemux, "using %d segments", stream->n_segments);
7996 * Parses the stsd atom of a svq3 trak looking for
7997 * the SMI and gama atoms.
8000 qtdemux_parse_svq3_stsd_data (GstQTDemux * qtdemux, GNode * stsd,
8001 guint8 ** gamma, GstBuffer ** seqh)
8003 guint8 *_gamma = NULL;
8004 GstBuffer *_seqh = NULL;
8005 guint8 *stsd_data = stsd->data;
8006 guint32 length = QT_UINT32 (stsd_data);
8010 GST_WARNING_OBJECT (qtdemux, "stsd too short");
8016 version = QT_UINT16 (stsd_data);
8021 while (length > 8) {
8022 guint32 fourcc, size;
8024 size = QT_UINT32 (stsd_data);
8025 fourcc = QT_FOURCC (stsd_data + 4);
8026 data = stsd_data + 8;
8029 GST_WARNING_OBJECT (qtdemux, "Atom of size 0 found, aborting "
8030 "svq3 atom parsing");
8039 GST_WARNING_OBJECT (qtdemux, "Unexpected size %" G_GUINT32_FORMAT
8040 " for gama atom, expected 12", size);
8045 if (size > 16 && QT_FOURCC (data) == FOURCC_SEQH) {
8047 if (_seqh != NULL) {
8048 GST_WARNING_OBJECT (qtdemux, "Unexpected second SEQH SMI atom "
8049 " found, ignoring");
8051 seqh_size = QT_UINT32 (data + 4);
8052 if (seqh_size > 0) {
8053 _seqh = gst_buffer_new_and_alloc (seqh_size);
8054 gst_buffer_fill (_seqh, 0, data + 8, seqh_size);
8061 GST_WARNING_OBJECT (qtdemux, "Unhandled atom %" GST_FOURCC_FORMAT
8062 " in SVQ3 entry in stsd atom", GST_FOURCC_ARGS (fourcc));
8066 if (size <= length) {
8072 GST_WARNING_OBJECT (qtdemux, "SVQ3 entry too short in stsd atom");
8075 GST_WARNING_OBJECT (qtdemux, "Unexpected version for SVQ3 entry %"
8076 G_GUINT16_FORMAT, version);
8087 gst_buffer_unref (_seqh);
8092 qtdemux_get_rtsp_uri_from_hndl (GstQTDemux * qtdemux, GNode * minf)
8099 * Get 'dinf', to get its child 'dref', that might contain a 'hndl'
8100 * atom that might contain a 'data' atom with the rtsp uri.
8101 * This case was reported in bug #597497, some info about
8102 * the hndl atom can be found in TN1195
8104 dinf = qtdemux_tree_get_child_by_type (minf, FOURCC_dinf);
8105 GST_DEBUG_OBJECT (qtdemux, "Trying to obtain rtsp URI for stream trak");
8108 guint32 dref_num_entries = 0;
8109 if (qtdemux_tree_get_child_by_type_full (dinf, FOURCC_dref, &dref) &&
8110 gst_byte_reader_skip (&dref, 4) &&
8111 gst_byte_reader_get_uint32_be (&dref, &dref_num_entries)) {
8114 /* search dref entries for hndl atom */
8115 for (i = 0; i < dref_num_entries; i++) {
8116 guint32 size = 0, type;
8117 guint8 string_len = 0;
8118 if (gst_byte_reader_get_uint32_be (&dref, &size) &&
8119 qt_atom_parser_get_fourcc (&dref, &type)) {
8120 if (type == FOURCC_hndl) {
8121 GST_DEBUG_OBJECT (qtdemux, "Found hndl atom");
8123 /* skip data reference handle bytes and the
8124 * following pascal string and some extra 4
8125 * bytes I have no idea what are */
8126 if (!gst_byte_reader_skip (&dref, 4) ||
8127 !gst_byte_reader_get_uint8 (&dref, &string_len) ||
8128 !gst_byte_reader_skip (&dref, string_len + 4)) {
8129 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl atom");
8133 /* iterate over the atoms to find the data atom */
8134 while (gst_byte_reader_get_remaining (&dref) >= 8) {
8138 if (gst_byte_reader_get_uint32_be (&dref, &atom_size) &&
8139 qt_atom_parser_get_fourcc (&dref, &atom_type)) {
8140 if (atom_type == FOURCC_data) {
8141 const guint8 *uri_aux = NULL;
8143 /* found the data atom that might contain the rtsp uri */
8144 GST_DEBUG_OBJECT (qtdemux, "Found data atom inside "
8145 "hndl atom, interpreting it as an URI");
8146 if (gst_byte_reader_peek_data (&dref, atom_size - 8,
8148 if (g_strstr_len ((gchar *) uri_aux, 7, "rtsp://") != NULL)
8149 uri = g_strndup ((gchar *) uri_aux, atom_size - 8);
8151 GST_WARNING_OBJECT (qtdemux, "Data atom in hndl atom "
8152 "didn't contain a rtsp address");
8154 GST_WARNING_OBJECT (qtdemux, "Failed to get the data "
8159 /* skipping to the next entry */
8160 if (!gst_byte_reader_skip (&dref, atom_size - 8))
8163 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl child "
8170 /* skip to the next entry */
8171 if (!gst_byte_reader_skip (&dref, size - 8))
8174 GST_WARNING_OBJECT (qtdemux, "Error parsing dref atom");
8177 GST_DEBUG_OBJECT (qtdemux, "Finished parsing dref atom");
8183 #define AMR_NB_ALL_MODES 0x81ff
8184 #define AMR_WB_ALL_MODES 0x83ff
8186 qtdemux_parse_amr_bitrate (GstBuffer * buf, gboolean wb)
8188 /* The 'damr' atom is of the form:
8190 * | vendor | decoder_ver | mode_set | mode_change_period | frames/sample |
8191 * 32 b 8 b 16 b 8 b 8 b
8193 * The highest set bit of the first 7 (AMR-NB) or 8 (AMR-WB) bits of mode_set
8194 * represents the highest mode used in the stream (and thus the maximum
8195 * bitrate), with a couple of special cases as seen below.
8198 /* Map of frame type ID -> bitrate */
8199 static const guint nb_bitrates[] = {
8200 4750, 5150, 5900, 6700, 7400, 7950, 10200, 12200
8202 static const guint wb_bitrates[] = {
8203 6600, 8850, 12650, 14250, 15850, 18250, 19850, 23050, 23850
8209 gst_buffer_map (buf, &map, GST_MAP_READ);
8211 if (map.size != 0x11) {
8212 GST_DEBUG ("Atom should have size 0x11, not %" G_GSIZE_FORMAT, map.size);
8216 if (QT_FOURCC (map.data + 4) != GST_MAKE_FOURCC ('d', 'a', 'm', 'r')) {
8217 GST_DEBUG ("Unknown atom in %" GST_FOURCC_FORMAT,
8218 GST_FOURCC_ARGS (QT_UINT32 (map.data + 4)));
8222 mode_set = QT_UINT16 (map.data + 13);
8224 if (mode_set == (wb ? AMR_WB_ALL_MODES : AMR_NB_ALL_MODES))
8225 max_mode = 7 + (wb ? 1 : 0);
8227 /* AMR-NB modes fo from 0-7, and AMR-WB modes go from 0-8 */
8228 max_mode = g_bit_nth_msf ((gulong) mode_set & (wb ? 0x1ff : 0xff), -1);
8230 if (max_mode == -1) {
8231 GST_DEBUG ("No mode indication was found (mode set) = %x",
8236 gst_buffer_unmap (buf, &map);
8237 return wb ? wb_bitrates[max_mode] : nb_bitrates[max_mode];
8240 gst_buffer_unmap (buf, &map);
8245 qtdemux_parse_transformation_matrix (GstQTDemux * qtdemux,
8246 GstByteReader * reader, guint32 * matrix, const gchar * atom)
8249 * 9 values of 32 bits (fixed point 16.16, except 2 5 and 8 that are 2.30)
8255 if (gst_byte_reader_get_remaining (reader) < 36)
8258 matrix[0] = gst_byte_reader_get_uint32_be_unchecked (reader);
8259 matrix[1] = gst_byte_reader_get_uint32_be_unchecked (reader);
8260 matrix[2] = gst_byte_reader_get_uint32_be_unchecked (reader);
8261 matrix[3] = gst_byte_reader_get_uint32_be_unchecked (reader);
8262 matrix[4] = gst_byte_reader_get_uint32_be_unchecked (reader);
8263 matrix[5] = gst_byte_reader_get_uint32_be_unchecked (reader);
8264 matrix[6] = gst_byte_reader_get_uint32_be_unchecked (reader);
8265 matrix[7] = gst_byte_reader_get_uint32_be_unchecked (reader);
8266 matrix[8] = gst_byte_reader_get_uint32_be_unchecked (reader);
8268 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix from atom %s", atom);
8269 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[0] >> 16,
8270 matrix[0] & 0xFFFF, matrix[1] >> 16, matrix[1] & 0xFF, matrix[2] >> 16,
8272 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[3] >> 16,
8273 matrix[3] & 0xFFFF, matrix[4] >> 16, matrix[4] & 0xFF, matrix[5] >> 16,
8275 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[6] >> 16,
8276 matrix[6] & 0xFFFF, matrix[7] >> 16, matrix[7] & 0xFF, matrix[8] >> 16,
8283 qtdemux_inspect_transformation_matrix (GstQTDemux * qtdemux,
8284 QtDemuxStream * stream, guint32 * matrix, GstTagList ** taglist)
8291 * This macro will only compare value abdegh, it expects cfi to have already
8294 #define QTCHECK_MATRIX(m,a,b,d,e) ((m)[0] == (a << 16) && (m)[1] == (b << 16) && \
8295 (m)[3] == (d << 16) && (m)[4] == (e << 16))
8297 /* only handle the cases where the last column has standard values */
8298 if (matrix[2] == 0 && matrix[5] == 0 && matrix[8] == 1 << 30) {
8299 const gchar *rotation_tag = NULL;
8301 /* no rotation needed */
8302 if (QTCHECK_MATRIX (matrix, 1, 0, 0, 1)) {
8304 } else if (QTCHECK_MATRIX (matrix, 0, 1, G_MAXUINT16, 0)) {
8305 rotation_tag = "rotate-90";
8306 } else if (QTCHECK_MATRIX (matrix, G_MAXUINT16, 0, 0, G_MAXUINT16)) {
8307 rotation_tag = "rotate-180";
8308 } else if (QTCHECK_MATRIX (matrix, 0, G_MAXUINT16, 1, 0)) {
8309 rotation_tag = "rotate-270";
8311 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
8314 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix rotation %s",
8316 if (rotation_tag != NULL) {
8317 if (*taglist == NULL)
8318 *taglist = gst_tag_list_new_empty ();
8319 gst_tag_list_add (*taglist, GST_TAG_MERGE_REPLACE,
8320 GST_TAG_IMAGE_ORIENTATION, rotation_tag, NULL);
8323 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
8327 /* Parses the boxes defined in ISO/IEC 14496-12 that enable support for
8328 * protected streams (sinf, frma, schm and schi); if the protection scheme is
8329 * Common Encryption (cenc), the function will also parse the tenc box (defined
8330 * in ISO/IEC 23001-7). @container points to the node that contains these boxes
8331 * (typically an enc[v|a|t|s] sample entry); the function will set
8332 * @original_fmt to the fourcc of the original unencrypted stream format.
8333 * Returns TRUE if successful; FALSE otherwise. */
8335 qtdemux_parse_protection_scheme_info (GstQTDemux * qtdemux,
8336 QtDemuxStream * stream, GNode * container, guint32 * original_fmt)
8343 g_return_val_if_fail (qtdemux != NULL, FALSE);
8344 g_return_val_if_fail (stream != NULL, FALSE);
8345 g_return_val_if_fail (container != NULL, FALSE);
8346 g_return_val_if_fail (original_fmt != NULL, FALSE);
8348 sinf = qtdemux_tree_get_child_by_type (container, FOURCC_sinf);
8349 if (G_UNLIKELY (!sinf)) {
8350 if (stream->protection_scheme_type == FOURCC_cenc) {
8351 GST_ERROR_OBJECT (qtdemux, "sinf box does not contain schi box, which is "
8352 "mandatory for Common Encryption");
8358 frma = qtdemux_tree_get_child_by_type (sinf, FOURCC_frma);
8359 if (G_UNLIKELY (!frma)) {
8360 GST_ERROR_OBJECT (qtdemux, "sinf box does not contain mandatory frma box");
8364 *original_fmt = QT_FOURCC ((const guint8 *) frma->data + 8);
8365 GST_DEBUG_OBJECT (qtdemux, "original stream format: '%" GST_FOURCC_FORMAT "'",
8366 GST_FOURCC_ARGS (*original_fmt));
8368 schm = qtdemux_tree_get_child_by_type (sinf, FOURCC_schm);
8370 GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schm box");
8373 stream->protection_scheme_type = QT_FOURCC ((const guint8 *) schm->data + 12);
8374 stream->protection_scheme_version =
8375 QT_UINT32 ((const guint8 *) schm->data + 16);
8377 GST_DEBUG_OBJECT (qtdemux,
8378 "protection_scheme_type: %" GST_FOURCC_FORMAT ", "
8379 "protection_scheme_version: %#010x",
8380 GST_FOURCC_ARGS (stream->protection_scheme_type),
8381 stream->protection_scheme_version);
8383 schi = qtdemux_tree_get_child_by_type (sinf, FOURCC_schi);
8385 GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schi box");
8388 if (stream->protection_scheme_type == FOURCC_cenc) {
8389 QtDemuxCencSampleSetInfo *info;
8391 const guint8 *tenc_data;
8392 guint32 isEncrypted;
8394 const guint8 *default_kid;
8397 if (G_UNLIKELY (!stream->protection_scheme_info))
8398 stream->protection_scheme_info =
8399 g_malloc0 (sizeof (QtDemuxCencSampleSetInfo));
8401 info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
8403 tenc = qtdemux_tree_get_child_by_type (schi, FOURCC_tenc);
8405 GST_ERROR_OBJECT (qtdemux, "schi box does not contain tenc box, "
8406 "which is mandatory for Common Encryption");
8409 tenc_data = (const guint8 *) tenc->data + 12;
8410 isEncrypted = QT_UINT24 (tenc_data);
8411 iv_size = QT_UINT8 (tenc_data + 3);
8412 default_kid = (tenc_data + 4);
8413 kid_buf = gst_buffer_new_allocate (NULL, 16, NULL);
8414 gst_buffer_fill (kid_buf, 0, default_kid, 16);
8415 if (info->default_properties)
8416 gst_structure_free (info->default_properties);
8417 info->default_properties =
8418 gst_structure_new ("application/x-cenc",
8419 "iv_size", G_TYPE_UINT, iv_size,
8420 "encrypted", G_TYPE_BOOLEAN, (isEncrypted == 1),
8421 "kid", GST_TYPE_BUFFER, kid_buf, NULL);
8422 GST_DEBUG_OBJECT (qtdemux, "default sample properties: "
8423 "is_encrypted=%u, iv_size=%u", isEncrypted, iv_size);
8424 gst_buffer_unref (kid_buf);
8430 * With each track we associate a new QtDemuxStream that contains all the info
8432 * traks that do not decode to something (like strm traks) will not have a pad.
8435 qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
8454 QtDemuxStream *stream = NULL;
8455 gboolean new_stream = FALSE;
8456 gchar *codec = NULL;
8457 const guint8 *stsd_data;
8458 guint16 lang_code; /* quicktime lang code or packed iso code */
8460 guint32 tkhd_flags = 0;
8461 guint8 tkhd_version = 0;
8463 guint value_size, stsd_len, len;
8466 GST_DEBUG_OBJECT (qtdemux, "parse_trak");
8468 if (!qtdemux_tree_get_child_by_type_full (trak, FOURCC_tkhd, &tkhd)
8469 || !gst_byte_reader_get_uint8 (&tkhd, &tkhd_version)
8470 || !gst_byte_reader_get_uint24_be (&tkhd, &tkhd_flags))
8473 /* pick between 64 or 32 bits */
8474 value_size = tkhd_version == 1 ? 8 : 4;
8475 if (!gst_byte_reader_skip (&tkhd, value_size * 2) ||
8476 !gst_byte_reader_get_uint32_be (&tkhd, &track_id))
8479 if (!qtdemux->got_moov) {
8480 if (qtdemux_find_stream (qtdemux, track_id))
8481 goto existing_stream;
8482 stream = _create_stream ();
8483 stream->track_id = track_id;
8486 stream = qtdemux_find_stream (qtdemux, track_id);
8488 GST_WARNING_OBJECT (qtdemux, "Stream not found, going to ignore it");
8492 /* flush samples data from this track from previous moov */
8493 gst_qtdemux_stream_flush_segments_data (qtdemux, stream);
8494 gst_qtdemux_stream_flush_samples_data (qtdemux, stream);
8497 if (stream->pending_tags == NULL)
8498 stream->pending_tags = gst_tag_list_new_empty ();
8500 if ((tkhd_flags & 1) == 0)
8501 stream->disabled = TRUE;
8503 GST_LOG_OBJECT (qtdemux, "track[tkhd] version/flags/id: 0x%02x/%06x/%u",
8504 tkhd_version, tkhd_flags, stream->track_id);
8506 if (!(mdia = qtdemux_tree_get_child_by_type (trak, FOURCC_mdia)))
8509 if (!(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mdhd))) {
8510 /* be nice for some crooked mjp2 files that use mhdr for mdhd */
8511 if (qtdemux->major_brand != FOURCC_mjp2 ||
8512 !(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mhdr)))
8516 len = QT_UINT32 ((guint8 *) mdhd->data);
8517 version = QT_UINT32 ((guint8 *) mdhd->data + 8);
8518 GST_LOG_OBJECT (qtdemux, "track version/flags: %08x", version);
8519 if (version == 0x01000000) {
8522 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 28);
8523 stream->duration = QT_UINT64 ((guint8 *) mdhd->data + 32);
8524 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 36);
8528 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 20);
8529 stream->duration = QT_UINT32 ((guint8 *) mdhd->data + 24);
8530 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 28);
8533 if (lang_code < 0x400) {
8534 qtdemux_lang_map_qt_code_to_iso (stream->lang_id, lang_code);
8535 } else if (lang_code == 0x7fff) {
8536 stream->lang_id[0] = 0; /* unspecified */
8538 stream->lang_id[0] = 0x60 + ((lang_code >> 10) & 0x1F);
8539 stream->lang_id[1] = 0x60 + ((lang_code >> 5) & 0x1F);
8540 stream->lang_id[2] = 0x60 + (lang_code & 0x1F);
8541 stream->lang_id[3] = 0;
8544 GST_LOG_OBJECT (qtdemux, "track timescale: %" G_GUINT32_FORMAT,
8546 GST_LOG_OBJECT (qtdemux, "track duration: %" G_GUINT64_FORMAT,
8548 GST_LOG_OBJECT (qtdemux, "track language code/id: 0x%04x/%s",
8549 lang_code, stream->lang_id);
8551 if (G_UNLIKELY (stream->timescale == 0 || qtdemux->timescale == 0))
8554 if ((tref = qtdemux_tree_get_child_by_type (trak, FOURCC_tref))) {
8555 /* chapters track reference */
8556 GNode *chap = qtdemux_tree_get_child_by_type (tref, FOURCC_chap);
8558 gsize length = GST_READ_UINT32_BE (chap->data);
8559 if (qtdemux->chapters_track_id)
8560 GST_FIXME_OBJECT (qtdemux, "Multiple CHAP tracks");
8563 qtdemux->chapters_track_id =
8564 GST_READ_UINT32_BE ((gint8 *) chap->data + 8);
8569 /* fragmented files may have bogus duration in moov */
8570 if (!qtdemux->fragmented &&
8571 qtdemux->duration != G_MAXINT64 && stream->duration != G_MAXINT32) {
8572 guint64 tdur1, tdur2;
8574 /* don't overflow */
8575 tdur1 = stream->timescale * (guint64) qtdemux->duration;
8576 tdur2 = qtdemux->timescale * (guint64) stream->duration;
8579 * some of those trailers, nowadays, have prologue images that are
8580 * themselves vide tracks as well. I haven't really found a way to
8581 * identify those yet, except for just looking at their duration. */
8582 if (tdur1 != 0 && (tdur2 * 10 / tdur1) < 2) {
8583 GST_WARNING_OBJECT (qtdemux,
8584 "Track shorter than 20%% (%" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT
8585 " vs. %" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT ") of the stream "
8586 "found, assuming preview image or something; skipping track",
8587 stream->duration, stream->timescale, qtdemux->duration,
8588 qtdemux->timescale);
8590 gst_qtdemux_stream_free (qtdemux, stream);
8595 if (!(hdlr = qtdemux_tree_get_child_by_type (mdia, FOURCC_hdlr)))
8598 GST_LOG_OBJECT (qtdemux, "track type: %" GST_FOURCC_FORMAT,
8599 GST_FOURCC_ARGS (QT_FOURCC ((guint8 *) hdlr->data + 12)));
8601 len = QT_UINT32 ((guint8 *) hdlr->data);
8603 stream->subtype = QT_FOURCC ((guint8 *) hdlr->data + 16);
8604 GST_LOG_OBJECT (qtdemux, "track subtype: %" GST_FOURCC_FORMAT,
8605 GST_FOURCC_ARGS (stream->subtype));
8607 if (!(minf = qtdemux_tree_get_child_by_type (mdia, FOURCC_minf)))
8610 if (!(stbl = qtdemux_tree_get_child_by_type (minf, FOURCC_stbl)))
8613 /*parse svmi header if existing */
8614 svmi = qtdemux_tree_get_child_by_type (stbl, FOURCC_svmi);
8616 len = QT_UINT32 ((guint8 *) svmi->data);
8617 version = QT_UINT32 ((guint8 *) svmi->data + 8);
8619 GstVideoMultiviewMode mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
8620 GstVideoMultiviewFlags flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
8621 guint8 frame_type, frame_layout;
8623 /* MPEG-A stereo video */
8624 if (qtdemux->major_brand == FOURCC_ss02)
8625 flags |= GST_VIDEO_MULTIVIEW_FLAGS_MIXED_MONO;
8627 frame_type = QT_UINT8 ((guint8 *) svmi->data + 12);
8628 frame_layout = QT_UINT8 ((guint8 *) svmi->data + 13) & 0x01;
8629 switch (frame_type) {
8631 mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
8634 mode = GST_VIDEO_MULTIVIEW_MODE_ROW_INTERLEAVED;
8637 mode = GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME;
8640 /* mode 3 is primary/secondary view sequence, ie
8641 * left/right views in separate tracks. See section 7.2
8642 * of ISO/IEC 23000-11:2009 */
8643 GST_FIXME_OBJECT (qtdemux,
8644 "Implement stereo video in separate streams");
8647 if ((frame_layout & 0x1) == 0)
8648 flags |= GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
8650 GST_LOG_OBJECT (qtdemux,
8651 "StereoVideo: composition type: %u, is_left_first: %u",
8652 frame_type, frame_layout);
8653 stream->multiview_mode = mode;
8654 stream->multiview_flags = flags;
8659 if (!(stsd = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsd)))
8661 stsd_data = (const guint8 *) stsd->data;
8663 /* stsd should at least have one entry */
8664 stsd_len = QT_UINT32 (stsd_data);
8665 if (stsd_len < 24) {
8666 /* .. but skip stream with empty stsd produced by some Vivotek cameras */
8667 if (stream->subtype == FOURCC_vivo) {
8669 gst_qtdemux_stream_free (qtdemux, stream);
8676 GST_LOG_OBJECT (qtdemux, "stsd len: %d", stsd_len);
8678 /* and that entry should fit within stsd */
8679 len = QT_UINT32 (stsd_data + 16);
8680 if (len > stsd_len + 16)
8683 stream->fourcc = fourcc = QT_FOURCC (stsd_data + 16 + 4);
8684 GST_LOG_OBJECT (qtdemux, "stsd type: %" GST_FOURCC_FORMAT,
8685 GST_FOURCC_ARGS (stream->fourcc));
8686 GST_LOG_OBJECT (qtdemux, "stsd type len: %d", len);
8688 if ((fourcc == FOURCC_drms) || (fourcc == FOURCC_drmi))
8689 goto error_encrypted;
8691 if (fourcc == FOURCC_encv || fourcc == FOURCC_enca) {
8692 GNode *enc = qtdemux_tree_get_child_by_type (stsd, fourcc);
8693 stream->protected = TRUE;
8694 if (!qtdemux_parse_protection_scheme_info (qtdemux, stream, enc, &fourcc))
8695 GST_ERROR_OBJECT (qtdemux, "Failed to parse protection scheme info");
8698 if (stream->subtype == FOURCC_vide) {
8699 guint32 w = 0, h = 0;
8701 gint depth, palette_size, palette_count;
8703 guint32 *palette_data = NULL;
8705 stream->sampled = TRUE;
8707 /* version 1 uses some 64-bit ints */
8708 if (!gst_byte_reader_skip (&tkhd, 20 + value_size))
8711 if (!qtdemux_parse_transformation_matrix (qtdemux, &tkhd, matrix, "tkhd"))
8714 if (!gst_byte_reader_get_uint32_be (&tkhd, &w)
8715 || !gst_byte_reader_get_uint32_be (&tkhd, &h))
8718 stream->display_width = w >> 16;
8719 stream->display_height = h >> 16;
8721 qtdemux_inspect_transformation_matrix (qtdemux, stream, matrix,
8722 &stream->pending_tags);
8728 stream->width = QT_UINT16 (stsd_data + offset + 32);
8729 stream->height = QT_UINT16 (stsd_data + offset + 34);
8730 stream->fps_n = 0; /* this is filled in later */
8731 stream->fps_d = 0; /* this is filled in later */
8732 stream->bits_per_sample = QT_UINT16 (stsd_data + offset + 82);
8733 stream->color_table_id = QT_UINT16 (stsd_data + offset + 84);
8735 GST_LOG_OBJECT (qtdemux, "width %d, height %d, bps %d, color table id %d",
8736 stream->width, stream->height, stream->bits_per_sample,
8737 stream->color_table_id);
8739 depth = stream->bits_per_sample;
8741 /* more than 32 bits means grayscale */
8742 gray = (depth > 32);
8743 /* low 32 bits specify the depth */
8746 /* different number of palette entries is determined by depth. */
8748 if ((depth == 1) || (depth == 2) || (depth == 4) || (depth == 8))
8749 palette_count = (1 << depth);
8750 palette_size = palette_count * 4;
8752 if (stream->color_table_id) {
8753 switch (palette_count) {
8757 palette_data = g_memdup (ff_qt_default_palette_2, palette_size);
8760 palette_data = g_memdup (ff_qt_default_palette_4, palette_size);
8764 palette_data = g_memdup (ff_qt_grayscale_palette_16, palette_size);
8766 palette_data = g_memdup (ff_qt_default_palette_16, palette_size);
8770 palette_data = g_memdup (ff_qt_grayscale_palette_256, palette_size);
8772 palette_data = g_memdup (ff_qt_default_palette_256, palette_size);
8775 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
8776 (_("The video in this file might not play correctly.")),
8777 ("unsupported palette depth %d", depth));
8781 gint i, j, start, end;
8787 start = QT_UINT32 (stsd_data + offset + 86);
8788 palette_count = QT_UINT16 (stsd_data + offset + 90);
8789 end = QT_UINT16 (stsd_data + offset + 92);
8791 GST_LOG_OBJECT (qtdemux, "start %d, end %d, palette_count %d",
8792 start, end, palette_count);
8799 if (len < 94 + (end - start) * 8)
8802 /* palette is always the same size */
8803 palette_data = g_malloc0 (256 * 4);
8804 palette_size = 256 * 4;
8806 for (j = 0, i = start; i <= end; j++, i++) {
8809 a = QT_UINT16 (stsd_data + offset + 94 + (j * 8));
8810 r = QT_UINT16 (stsd_data + offset + 96 + (j * 8));
8811 g = QT_UINT16 (stsd_data + offset + 98 + (j * 8));
8812 b = QT_UINT16 (stsd_data + offset + 100 + (j * 8));
8814 palette_data[i] = ((a & 0xff00) << 16) | ((r & 0xff00) << 8) |
8815 (g & 0xff00) | (b >> 8);
8820 gst_caps_unref (stream->caps);
8823 qtdemux_video_caps (qtdemux, stream, fourcc, stsd_data, &codec);
8824 if (G_UNLIKELY (!stream->caps)) {
8825 g_free (palette_data);
8826 goto unknown_stream;
8830 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
8831 GST_TAG_VIDEO_CODEC, codec, NULL);
8840 if (stream->rgb8_palette)
8841 gst_memory_unref (stream->rgb8_palette);
8842 stream->rgb8_palette = gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY,
8843 palette_data, palette_size, 0, palette_size, palette_data, g_free);
8845 s = gst_caps_get_structure (stream->caps, 0);
8847 /* non-raw video has a palette_data property. raw video has the palette as
8848 * an extra plane that we append to the output buffers before we push
8850 if (!gst_structure_has_name (s, "video/x-raw")) {
8853 palette = gst_buffer_new ();
8854 gst_buffer_append_memory (palette, stream->rgb8_palette);
8855 stream->rgb8_palette = NULL;
8857 gst_caps_set_simple (stream->caps, "palette_data",
8858 GST_TYPE_BUFFER, palette, NULL);
8859 gst_buffer_unref (palette);
8861 } else if (palette_count != 0) {
8862 GST_ELEMENT_WARNING (qtdemux, STREAM, NOT_IMPLEMENTED,
8863 (NULL), ("Unsupported palette depth %d", depth));
8866 GST_LOG_OBJECT (qtdemux, "frame count: %u",
8867 QT_UINT16 (stsd_data + offset + 48));
8871 /* pick 'the' stsd child */
8872 if (!stream->protected)
8873 mp4v = qtdemux_tree_get_child_by_type (stsd, fourcc);
8875 mp4v = qtdemux_tree_get_child_by_type (stsd, FOURCC_encv);
8878 esds = qtdemux_tree_get_child_by_type (mp4v, FOURCC_esds);
8879 pasp = qtdemux_tree_get_child_by_type (mp4v, FOURCC_pasp);
8883 const guint8 *pasp_data = (const guint8 *) pasp->data;
8885 stream->par_w = QT_UINT32 (pasp_data + 8);
8886 stream->par_h = QT_UINT32 (pasp_data + 12);
8893 gst_qtdemux_handle_esds (qtdemux, stream, esds, stream->pending_tags);
8900 gint len = QT_UINT32 (stsd_data) - 0x66;
8901 const guint8 *avc_data = stsd_data + 0x66;
8904 while (len >= 0x8) {
8907 if (QT_UINT32 (avc_data) <= len)
8908 size = QT_UINT32 (avc_data) - 0x8;
8913 /* No real data, so break out */
8916 switch (QT_FOURCC (avc_data + 0x4)) {
8919 /* parse, if found */
8922 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
8924 /* First 4 bytes are the length of the atom, the next 4 bytes
8925 * are the fourcc, the next 1 byte is the version, and the
8926 * subsequent bytes are profile_tier_level structure like data. */
8927 gst_codec_utils_h264_caps_set_level_and_profile (stream->caps,
8928 avc_data + 8 + 1, size - 1);
8929 buf = gst_buffer_new_and_alloc (size);
8930 gst_buffer_fill (buf, 0, avc_data + 0x8, size);
8931 gst_caps_set_simple (stream->caps,
8932 "codec_data", GST_TYPE_BUFFER, buf, NULL);
8933 gst_buffer_unref (buf);
8941 GST_DEBUG_OBJECT (qtdemux, "found strf codec_data in stsd");
8943 /* First 4 bytes are the length of the atom, the next 4 bytes
8944 * are the fourcc, next 40 bytes are BITMAPINFOHEADER,
8945 * next 1 byte is the version, and the
8946 * subsequent bytes are sequence parameter set like data. */
8948 size -= 40; /* we'll be skipping BITMAPINFOHEADER */
8950 gst_codec_utils_h264_caps_set_level_and_profile (stream->caps,
8951 avc_data + 8 + 40 + 1, size - 1);
8953 buf = gst_buffer_new_and_alloc (size);
8954 gst_buffer_fill (buf, 0, avc_data + 8 + 40, size);
8955 gst_caps_set_simple (stream->caps,
8956 "codec_data", GST_TYPE_BUFFER, buf, NULL);
8957 gst_buffer_unref (buf);
8963 guint avg_bitrate, max_bitrate;
8965 /* bufferSizeDB, maxBitrate and avgBitrate - 4 bytes each */
8969 max_bitrate = QT_UINT32 (avc_data + 0xc);
8970 avg_bitrate = QT_UINT32 (avc_data + 0x10);
8972 if (!max_bitrate && !avg_bitrate)
8975 /* Some muxers seem to swap the average and maximum bitrates
8976 * (I'm looking at you, YouTube), so we swap for sanity. */
8977 if (max_bitrate > 0 && max_bitrate < avg_bitrate) {
8978 guint temp = avg_bitrate;
8980 avg_bitrate = max_bitrate;
8984 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
8985 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
8986 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
8988 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
8989 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
8990 GST_TAG_BITRATE, avg_bitrate, NULL);
9001 avc_data += size + 8;
9010 gint len = QT_UINT32 (stsd_data) - 0x66;
9011 const guint8 *hevc_data = stsd_data + 0x66;
9014 while (len >= 0x8) {
9017 if (QT_UINT32 (hevc_data) <= len)
9018 size = QT_UINT32 (hevc_data) - 0x8;
9023 /* No real data, so break out */
9026 switch (QT_FOURCC (hevc_data + 0x4)) {
9029 /* parse, if found */
9032 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
9034 /* First 4 bytes are the length of the atom, the next 4 bytes
9035 * are the fourcc, the next 1 byte is the version, and the
9036 * subsequent bytes are sequence parameter set like data. */
9037 gst_codec_utils_h265_caps_set_level_tier_and_profile
9038 (stream->caps, hevc_data + 8 + 1, size - 1);
9040 buf = gst_buffer_new_and_alloc (size);
9041 gst_buffer_fill (buf, 0, hevc_data + 0x8, size);
9042 gst_caps_set_simple (stream->caps,
9043 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9044 gst_buffer_unref (buf);
9051 hevc_data += size + 8;
9062 GST_DEBUG_OBJECT (qtdemux, "found %" GST_FOURCC_FORMAT,
9063 GST_FOURCC_ARGS (fourcc));
9065 /* codec data might be in glbl extension atom */
9067 qtdemux_tree_get_child_by_type (mp4v, FOURCC_glbl) : NULL;
9073 GST_DEBUG_OBJECT (qtdemux, "found glbl data in stsd");
9075 len = QT_UINT32 (data);
9078 buf = gst_buffer_new_and_alloc (len);
9079 gst_buffer_fill (buf, 0, data + 8, len);
9080 gst_caps_set_simple (stream->caps,
9081 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9082 gst_buffer_unref (buf);
9089 /* see annex I of the jpeg2000 spec */
9090 GNode *jp2h, *ihdr, *colr, *mjp2, *field, *prefix, *cmap, *cdef;
9092 const gchar *colorspace = NULL;
9094 guint32 ncomp_map = 0;
9095 gint32 *comp_map = NULL;
9096 guint32 nchan_def = 0;
9097 gint32 *chan_def = NULL;
9099 GST_DEBUG_OBJECT (qtdemux, "found mjp2");
9100 /* some required atoms */
9101 mjp2 = qtdemux_tree_get_child_by_type (stsd, FOURCC_mjp2);
9104 jp2h = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2h);
9108 /* number of components; redundant with info in codestream, but useful
9110 ihdr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_ihdr);
9111 if (!ihdr || QT_UINT32 (ihdr->data) != 22)
9113 ncomp = QT_UINT16 (((guint8 *) ihdr->data) + 16);
9115 colr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_colr);
9118 GST_DEBUG_OBJECT (qtdemux, "found colr");
9119 /* extract colour space info */
9120 if (QT_UINT8 ((guint8 *) colr->data + 8) == 1) {
9121 switch (QT_UINT32 ((guint8 *) colr->data + 11)) {
9123 colorspace = "sRGB";
9126 colorspace = "GRAY";
9129 colorspace = "sYUV";
9137 /* colr is required, and only values 16, 17, and 18 are specified,
9138 so error if we have no colorspace */
9141 /* extract component mapping */
9142 cmap = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cmap);
9144 guint32 cmap_len = 0;
9146 cmap_len = QT_UINT32 (cmap->data);
9147 if (cmap_len >= 8) {
9148 /* normal box, subtract off header */
9150 /* cmap: { u16 cmp; u8 mtyp; u8 pcol; }* */
9151 if (cmap_len % 4 == 0) {
9152 ncomp_map = (cmap_len / 4);
9153 comp_map = g_new0 (gint32, ncomp_map);
9154 for (i = 0; i < ncomp_map; i++) {
9157 cmp = QT_UINT16 (((guint8 *) cmap->data) + 8 + i * 4);
9158 mtyp = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 2);
9159 pcol = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 3);
9160 comp_map[i] = (mtyp << 24) | (pcol << 16) | cmp;
9165 /* extract channel definitions */
9166 cdef = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cdef);
9168 guint32 cdef_len = 0;
9170 cdef_len = QT_UINT32 (cdef->data);
9171 if (cdef_len >= 10) {
9172 /* normal box, subtract off header and len */
9174 /* cdef: u16 n; { u16 cn; u16 typ; u16 asoc; }* */
9175 if (cdef_len % 6 == 0) {
9176 nchan_def = (cdef_len / 6);
9177 chan_def = g_new0 (gint32, nchan_def);
9178 for (i = 0; i < nchan_def; i++)
9180 for (i = 0; i < nchan_def; i++) {
9181 guint16 cn, typ, asoc;
9182 cn = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6);
9183 typ = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 2);
9184 asoc = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 4);
9185 if (cn < nchan_def) {
9188 chan_def[cn] = asoc;
9191 chan_def[cn] = 0; /* alpha */
9194 chan_def[cn] = -typ;
9202 gst_caps_set_simple (stream->caps,
9203 "num-components", G_TYPE_INT, ncomp, NULL);
9204 gst_caps_set_simple (stream->caps,
9205 "colorspace", G_TYPE_STRING, colorspace, NULL);
9208 GValue arr = { 0, };
9209 GValue elt = { 0, };
9211 g_value_init (&arr, GST_TYPE_ARRAY);
9212 g_value_init (&elt, G_TYPE_INT);
9213 for (i = 0; i < ncomp_map; i++) {
9214 g_value_set_int (&elt, comp_map[i]);
9215 gst_value_array_append_value (&arr, &elt);
9217 gst_structure_set_value (gst_caps_get_structure (stream->caps, 0),
9218 "component-map", &arr);
9219 g_value_unset (&elt);
9220 g_value_unset (&arr);
9225 GValue arr = { 0, };
9226 GValue elt = { 0, };
9228 g_value_init (&arr, GST_TYPE_ARRAY);
9229 g_value_init (&elt, G_TYPE_INT);
9230 for (i = 0; i < nchan_def; i++) {
9231 g_value_set_int (&elt, chan_def[i]);
9232 gst_value_array_append_value (&arr, &elt);
9234 gst_structure_set_value (gst_caps_get_structure (stream->caps, 0),
9235 "channel-definitions", &arr);
9236 g_value_unset (&elt);
9237 g_value_unset (&arr);
9241 /* some optional atoms */
9242 field = qtdemux_tree_get_child_by_type (mjp2, FOURCC_fiel);
9243 prefix = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2x);
9245 /* indicate possible fields in caps */
9247 data = (guint8 *) field->data + 8;
9249 gst_caps_set_simple (stream->caps, "fields", G_TYPE_INT,
9250 (gint) * data, NULL);
9252 /* add codec_data if provided */
9257 GST_DEBUG_OBJECT (qtdemux, "found prefix data in stsd");
9258 data = prefix->data;
9259 len = QT_UINT32 (data);
9262 buf = gst_buffer_new_and_alloc (len);
9263 gst_buffer_fill (buf, 0, data + 8, len);
9264 gst_caps_set_simple (stream->caps,
9265 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9266 gst_buffer_unref (buf);
9275 GstBuffer *seqh = NULL;
9276 guint8 *gamma_data = NULL;
9277 gint len = QT_UINT32 (stsd_data);
9279 qtdemux_parse_svq3_stsd_data (qtdemux, stsd, &gamma_data, &seqh);
9281 gst_caps_set_simple (stream->caps, "applied-gamma", G_TYPE_DOUBLE,
9282 QT_FP32 (gamma_data), NULL);
9285 /* sorry for the bad name, but we don't know what this is, other
9286 * than its own fourcc */
9287 gst_caps_set_simple (stream->caps, "seqh", GST_TYPE_BUFFER, seqh,
9291 GST_DEBUG_OBJECT (qtdemux, "found codec_data in stsd");
9292 buf = gst_buffer_new_and_alloc (len);
9293 gst_buffer_fill (buf, 0, stsd_data, len);
9294 gst_caps_set_simple (stream->caps,
9295 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9296 gst_buffer_unref (buf);
9302 gst_caps_set_simple (stream->caps,
9303 "depth", G_TYPE_INT, QT_UINT16 (stsd_data + offset + 82), NULL);
9310 GST_DEBUG_OBJECT (qtdemux, "found XiTh");
9311 xith = qtdemux_tree_get_child_by_type (stsd, FOURCC_XiTh);
9315 xdxt = qtdemux_tree_get_child_by_type (xith, FOURCC_XdxT);
9319 GST_DEBUG_OBJECT (qtdemux, "found XdxT node");
9320 /* collect the headers and store them in a stream list so that we can
9321 * send them out first */
9322 qtdemux_parse_theora_extension (qtdemux, stream, xdxt);
9332 GST_DEBUG_OBJECT (qtdemux, "parse ovc1 header");
9333 ovc1 = qtdemux_tree_get_child_by_type (stsd, FOURCC_ovc1);
9336 ovc1_data = ovc1->data;
9337 ovc1_len = QT_UINT32 (ovc1_data);
9338 if (ovc1_len <= 198) {
9339 GST_WARNING_OBJECT (qtdemux, "Too small ovc1 header, skipping");
9342 buf = gst_buffer_new_and_alloc (ovc1_len - 198);
9343 gst_buffer_fill (buf, 0, ovc1_data + 198, ovc1_len - 198);
9344 gst_caps_set_simple (stream->caps,
9345 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9346 gst_buffer_unref (buf);
9349 case GST_MAKE_FOURCC ('v', 'c', '-', '1'):
9351 gint len = QT_UINT32 (stsd_data) - 0x66;
9352 const guint8 *vc1_data = stsd_data + 0x66;
9358 if (QT_UINT32 (vc1_data) <= len)
9359 size = QT_UINT32 (vc1_data) - 8;
9364 /* No real data, so break out */
9367 switch (QT_FOURCC (vc1_data + 0x4)) {
9368 case GST_MAKE_FOURCC ('d', 'v', 'c', '1'):
9372 GST_DEBUG_OBJECT (qtdemux, "found dvc1 codec_data in stsd");
9373 buf = gst_buffer_new_and_alloc (size);
9374 gst_buffer_fill (buf, 0, vc1_data + 8, size);
9375 gst_caps_set_simple (stream->caps,
9376 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9377 gst_buffer_unref (buf);
9384 vc1_data += size + 8;
9393 GST_INFO_OBJECT (qtdemux,
9394 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
9395 GST_FOURCC_ARGS (fourcc), stream->caps);
9397 } else if (stream->subtype == FOURCC_soun) {
9398 int version, samplesize;
9399 guint16 compression_id;
9400 gboolean amrwb = FALSE;
9403 /* sample description entry (16) + sound sample description v0 (20) */
9407 version = QT_UINT32 (stsd_data + offset);
9408 stream->n_channels = QT_UINT16 (stsd_data + offset + 8);
9409 samplesize = QT_UINT16 (stsd_data + offset + 10);
9410 compression_id = QT_UINT16 (stsd_data + offset + 12);
9411 stream->rate = QT_FP32 (stsd_data + offset + 16);
9413 GST_LOG_OBJECT (qtdemux, "version/rev: %08x", version);
9414 GST_LOG_OBJECT (qtdemux, "vendor: %08x",
9415 QT_UINT32 (stsd_data + offset + 4));
9416 GST_LOG_OBJECT (qtdemux, "n_channels: %d", stream->n_channels);
9417 GST_LOG_OBJECT (qtdemux, "sample_size: %d", samplesize);
9418 GST_LOG_OBJECT (qtdemux, "compression_id: %d", compression_id);
9419 GST_LOG_OBJECT (qtdemux, "packet size: %d",
9420 QT_UINT16 (stsd_data + offset + 14));
9421 GST_LOG_OBJECT (qtdemux, "sample rate: %g", stream->rate);
9423 if (compression_id == 0xfffe)
9424 stream->sampled = TRUE;
9426 /* first assume uncompressed audio */
9427 stream->bytes_per_sample = samplesize / 8;
9428 stream->samples_per_frame = stream->n_channels;
9429 stream->bytes_per_frame = stream->n_channels * stream->bytes_per_sample;
9430 stream->samples_per_packet = stream->samples_per_frame;
9431 stream->bytes_per_packet = stream->bytes_per_sample;
9435 /* Yes, these have to be hard-coded */
9438 stream->samples_per_packet = 6;
9439 stream->bytes_per_packet = 1;
9440 stream->bytes_per_frame = 1 * stream->n_channels;
9441 stream->bytes_per_sample = 1;
9442 stream->samples_per_frame = 6 * stream->n_channels;
9447 stream->samples_per_packet = 3;
9448 stream->bytes_per_packet = 1;
9449 stream->bytes_per_frame = 1 * stream->n_channels;
9450 stream->bytes_per_sample = 1;
9451 stream->samples_per_frame = 3 * stream->n_channels;
9456 stream->samples_per_packet = 64;
9457 stream->bytes_per_packet = 34;
9458 stream->bytes_per_frame = 34 * stream->n_channels;
9459 stream->bytes_per_sample = 2;
9460 stream->samples_per_frame = 64 * stream->n_channels;
9466 stream->samples_per_packet = 1;
9467 stream->bytes_per_packet = 1;
9468 stream->bytes_per_frame = 1 * stream->n_channels;
9469 stream->bytes_per_sample = 1;
9470 stream->samples_per_frame = 1 * stream->n_channels;
9475 stream->samples_per_packet = 160;
9476 stream->bytes_per_packet = 33;
9477 stream->bytes_per_frame = 33 * stream->n_channels;
9478 stream->bytes_per_sample = 2;
9479 stream->samples_per_frame = 160 * stream->n_channels;
9486 if (version == 0x00010000) {
9487 /* sample description entry (16) + sound sample description v1 (20+16) */
9498 /* only parse extra decoding config for non-pcm audio */
9499 stream->samples_per_packet = QT_UINT32 (stsd_data + offset);
9500 stream->bytes_per_packet = QT_UINT32 (stsd_data + offset + 4);
9501 stream->bytes_per_frame = QT_UINT32 (stsd_data + offset + 8);
9502 stream->bytes_per_sample = QT_UINT32 (stsd_data + offset + 12);
9504 GST_LOG_OBJECT (qtdemux, "samples/packet: %d",
9505 stream->samples_per_packet);
9506 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
9507 stream->bytes_per_packet);
9508 GST_LOG_OBJECT (qtdemux, "bytes/frame: %d",
9509 stream->bytes_per_frame);
9510 GST_LOG_OBJECT (qtdemux, "bytes/sample: %d",
9511 stream->bytes_per_sample);
9513 if (!stream->sampled && stream->bytes_per_packet) {
9514 stream->samples_per_frame = (stream->bytes_per_frame /
9515 stream->bytes_per_packet) * stream->samples_per_packet;
9516 GST_LOG_OBJECT (qtdemux, "samples/frame: %d",
9517 stream->samples_per_frame);
9522 } else if (version == 0x00020000) {
9529 /* sample description entry (16) + sound sample description v2 (56) */
9533 qtfp.val = QT_UINT64 (stsd_data + offset + 4);
9534 stream->rate = qtfp.fp;
9535 stream->n_channels = QT_UINT32 (stsd_data + offset + 12);
9537 GST_LOG_OBJECT (qtdemux, "Sound sample description Version 2");
9538 GST_LOG_OBJECT (qtdemux, "sample rate: %g", stream->rate);
9539 GST_LOG_OBJECT (qtdemux, "n_channels: %d", stream->n_channels);
9540 GST_LOG_OBJECT (qtdemux, "bits/channel: %d",
9541 QT_UINT32 (stsd_data + offset + 20));
9542 GST_LOG_OBJECT (qtdemux, "format flags: %X",
9543 QT_UINT32 (stsd_data + offset + 24));
9544 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
9545 QT_UINT32 (stsd_data + offset + 28));
9546 GST_LOG_OBJECT (qtdemux, "LPCM frames/packet: %d",
9547 QT_UINT32 (stsd_data + offset + 32));
9548 } else if (version != 0x00000) {
9549 GST_WARNING_OBJECT (qtdemux, "unknown audio STSD version %08x", version);
9553 gst_caps_unref (stream->caps);
9555 stream->caps = qtdemux_audio_caps (qtdemux, stream, fourcc,
9556 stsd_data + 32, len - 16, &codec);
9564 in24 = qtdemux_tree_get_child_by_type (stsd, FOURCC_in24);
9566 enda = qtdemux_tree_get_child_by_type (in24, FOURCC_enda);
9568 wave = qtdemux_tree_get_child_by_type (in24, FOURCC_wave);
9570 enda = qtdemux_tree_get_child_by_type (wave, FOURCC_enda);
9573 int enda_value = QT_UINT16 ((guint8 *) enda->data + 8);
9574 gst_caps_set_simple (stream->caps,
9575 "format", G_TYPE_STRING, (enda_value) ? "S24LE" : "S24BE", NULL);
9582 const guint8 *owma_data;
9583 const gchar *codec_name = NULL;
9587 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
9588 /* FIXME this should also be gst_riff_strf_auds,
9589 * but the latter one is actually missing bits-per-sample :( */
9594 gint32 nSamplesPerSec;
9595 gint32 nAvgBytesPerSec;
9597 gint16 wBitsPerSample;
9602 GST_DEBUG_OBJECT (qtdemux, "parse owma");
9603 owma = qtdemux_tree_get_child_by_type (stsd, FOURCC_owma);
9606 owma_data = owma->data;
9607 owma_len = QT_UINT32 (owma_data);
9608 if (owma_len <= 54) {
9609 GST_WARNING_OBJECT (qtdemux, "Too small owma header, skipping");
9612 wfex = (WAVEFORMATEX *) (owma_data + 36);
9613 buf = gst_buffer_new_and_alloc (owma_len - 54);
9614 gst_buffer_fill (buf, 0, owma_data + 54, owma_len - 54);
9615 if (wfex->wFormatTag == 0x0161) {
9616 codec_name = "Windows Media Audio";
9618 } else if (wfex->wFormatTag == 0x0162) {
9619 codec_name = "Windows Media Audio 9 Pro";
9621 } else if (wfex->wFormatTag == 0x0163) {
9622 codec_name = "Windows Media Audio 9 Lossless";
9623 /* is that correct? gstffmpegcodecmap.c is missing it, but
9624 * fluendo codec seems to support it */
9628 gst_caps_set_simple (stream->caps,
9629 "codec_data", GST_TYPE_BUFFER, buf,
9630 "wmaversion", G_TYPE_INT, version,
9631 "block_align", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->nBlockAlign),
9632 "bitrate", G_TYPE_INT, GST_READ_UINT32_LE (&wfex->nAvgBytesPerSec),
9633 "width", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->wBitsPerSample),
9634 "depth", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->wBitsPerSample),
9636 gst_buffer_unref (buf);
9640 codec = g_strdup (codec_name);
9644 case GST_MAKE_FOURCC ('w', 'm', 'a', ' '):
9646 gint len = QT_UINT32 (stsd_data) - offset;
9647 const guint8 *wfex_data = stsd_data + offset;
9648 const gchar *codec_name = NULL;
9650 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
9651 /* FIXME this should also be gst_riff_strf_auds,
9652 * but the latter one is actually missing bits-per-sample :( */
9657 gint32 nSamplesPerSec;
9658 gint32 nAvgBytesPerSec;
9660 gint16 wBitsPerSample;
9665 /* FIXME: unify with similar wavformatex parsing code above */
9666 GST_DEBUG_OBJECT (qtdemux, "parse wma, looking for wfex");
9672 if (QT_UINT32 (wfex_data) <= len)
9673 size = QT_UINT32 (wfex_data) - 8;
9678 /* No real data, so break out */
9681 switch (QT_FOURCC (wfex_data + 4)) {
9682 case GST_MAKE_FOURCC ('w', 'f', 'e', 'x'):
9684 GST_DEBUG_OBJECT (qtdemux, "found wfex in stsd");
9689 wfex.wFormatTag = GST_READ_UINT16_LE (wfex_data + 8 + 0);
9690 wfex.nChannels = GST_READ_UINT16_LE (wfex_data + 8 + 2);
9691 wfex.nSamplesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 4);
9692 wfex.nAvgBytesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 8);
9693 wfex.nBlockAlign = GST_READ_UINT16_LE (wfex_data + 8 + 12);
9694 wfex.wBitsPerSample = GST_READ_UINT16_LE (wfex_data + 8 + 14);
9695 wfex.cbSize = GST_READ_UINT16_LE (wfex_data + 8 + 16);
9697 GST_LOG_OBJECT (qtdemux, "Found wfex box in stsd:");
9698 GST_LOG_OBJECT (qtdemux, "FormatTag = 0x%04x, Channels = %u, "
9699 "SamplesPerSec = %u, AvgBytesPerSec = %u, BlockAlign = %u, "
9700 "BitsPerSample = %u, Size = %u", wfex.wFormatTag,
9701 wfex.nChannels, wfex.nSamplesPerSec, wfex.nAvgBytesPerSec,
9702 wfex.nBlockAlign, wfex.wBitsPerSample, wfex.cbSize);
9704 if (wfex.wFormatTag == 0x0161) {
9705 codec_name = "Windows Media Audio";
9707 } else if (wfex.wFormatTag == 0x0162) {
9708 codec_name = "Windows Media Audio 9 Pro";
9710 } else if (wfex.wFormatTag == 0x0163) {
9711 codec_name = "Windows Media Audio 9 Lossless";
9712 /* is that correct? gstffmpegcodecmap.c is missing it, but
9713 * fluendo codec seems to support it */
9717 gst_caps_set_simple (stream->caps,
9718 "wmaversion", G_TYPE_INT, version,
9719 "block_align", G_TYPE_INT, wfex.nBlockAlign,
9720 "bitrate", G_TYPE_INT, wfex.nAvgBytesPerSec,
9721 "width", G_TYPE_INT, wfex.wBitsPerSample,
9722 "depth", G_TYPE_INT, wfex.wBitsPerSample, NULL);
9724 if (size > wfex.cbSize) {
9727 buf = gst_buffer_new_and_alloc (size - wfex.cbSize);
9728 gst_buffer_fill (buf, 0, wfex_data + 8 + wfex.cbSize,
9729 size - wfex.cbSize);
9730 gst_caps_set_simple (stream->caps,
9731 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9732 gst_buffer_unref (buf);
9734 GST_WARNING_OBJECT (qtdemux, "no codec data");
9739 codec = g_strdup (codec_name);
9747 wfex_data += size + 8;
9759 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
9760 GST_TAG_AUDIO_CODEC, codec, NULL);
9764 /* some bitrate info may have ended up in caps */
9765 s = gst_caps_get_structure (stream->caps, 0);
9766 gst_structure_get_int (s, "bitrate", &bitrate);
9768 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
9769 GST_TAG_BITRATE, bitrate, NULL);
9772 if (stream->protected && fourcc == FOURCC_mp4a)
9773 mp4a = qtdemux_tree_get_child_by_type (stsd, FOURCC_enca);
9775 mp4a = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4a);
9780 wave = qtdemux_tree_get_child_by_type (mp4a, FOURCC_wave);
9782 esds = qtdemux_tree_get_child_by_type (wave, FOURCC_esds);
9784 esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
9788 /* If the fourcc's bottom 16 bits gives 'sm', then the top
9789 16 bits is a byte-swapped wave-style codec identifier,
9790 and we can find a WAVE header internally to a 'wave' atom here.
9791 This can more clearly be thought of as 'ms' as the top 16 bits, and a
9792 codec id as the bottom 16 bits - but byte-swapped to store in QT (which
9795 if ((fourcc & 0xffff) == (('s' << 8) | 'm')) {
9796 if (len < offset + 20) {
9797 GST_WARNING_OBJECT (qtdemux, "No wave atom in MS-style audio");
9799 guint32 datalen = QT_UINT32 (stsd_data + offset + 16);
9800 const guint8 *data = stsd_data + offset + 16;
9802 GNode *waveheadernode;
9804 wavenode = g_node_new ((guint8 *) data);
9805 if (qtdemux_parse_node (qtdemux, wavenode, data, datalen)) {
9806 const guint8 *waveheader;
9809 waveheadernode = qtdemux_tree_get_child_by_type (wavenode, fourcc);
9810 if (waveheadernode) {
9811 waveheader = (const guint8 *) waveheadernode->data;
9812 headerlen = QT_UINT32 (waveheader);
9814 if (headerlen > 8) {
9815 gst_riff_strf_auds *header = NULL;
9816 GstBuffer *headerbuf;
9822 headerbuf = gst_buffer_new_and_alloc (headerlen);
9823 gst_buffer_fill (headerbuf, 0, waveheader, headerlen);
9825 if (gst_riff_parse_strf_auds (GST_ELEMENT_CAST (qtdemux),
9826 headerbuf, &header, &extra)) {
9827 gst_caps_unref (stream->caps);
9828 /* FIXME: Need to do something with the channel reorder map */
9829 stream->caps = gst_riff_create_audio_caps (header->format, NULL,
9830 header, extra, NULL, NULL, NULL);
9833 gst_buffer_unref (extra);
9838 GST_DEBUG ("Didn't find waveheadernode for this codec");
9840 g_node_destroy (wavenode);
9843 gst_qtdemux_handle_esds (qtdemux, stream, esds, stream->pending_tags);
9847 /* FIXME: what is in the chunk? */
9850 gint len = QT_UINT32 (stsd_data);
9852 /* seems to be always = 116 = 0x74 */
9858 gint len = QT_UINT32 (stsd_data);
9861 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x4C);
9863 gst_buffer_fill (buf, 0, stsd_data + 0x4C, len - 0x4C);
9864 gst_caps_set_simple (stream->caps,
9865 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9866 gst_buffer_unref (buf);
9868 gst_caps_set_simple (stream->caps,
9869 "samplesize", G_TYPE_INT, samplesize, NULL);
9874 GNode *alac, *wave = NULL;
9876 /* apparently, m4a has this atom appended directly in the stsd entry,
9877 * while mov has it in a wave atom */
9878 alac = qtdemux_tree_get_child_by_type (stsd, FOURCC_alac);
9880 /* alac now refers to stsd entry atom */
9881 wave = qtdemux_tree_get_child_by_type (alac, FOURCC_wave);
9883 alac = qtdemux_tree_get_child_by_type (wave, FOURCC_alac);
9885 alac = qtdemux_tree_get_child_by_type (alac, FOURCC_alac);
9888 const guint8 *alac_data = alac->data;
9889 gint len = QT_UINT32 (alac->data);
9893 GST_DEBUG_OBJECT (qtdemux,
9894 "discarding alac atom with unexpected len %d", len);
9896 /* codec-data contains alac atom size and prefix,
9897 * ffmpeg likes it that way, not quite gst-ish though ...*/
9898 buf = gst_buffer_new_and_alloc (len);
9899 gst_buffer_fill (buf, 0, alac->data, len);
9900 gst_caps_set_simple (stream->caps,
9901 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9902 gst_buffer_unref (buf);
9904 stream->bytes_per_frame = QT_UINT32 (alac_data + 12);
9905 stream->n_channels = QT_UINT8 (alac_data + 21);
9906 stream->rate = QT_UINT32 (alac_data + 32);
9909 gst_caps_set_simple (stream->caps,
9910 "samplesize", G_TYPE_INT, samplesize, NULL);
9918 gint len = QT_UINT32 (stsd_data);
9921 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x34);
9924 gst_buffer_fill (buf, 0, stsd_data + 0x34, len - 0x34);
9926 /* If we have enough data, let's try to get the 'damr' atom. See
9927 * the 3GPP container spec (26.244) for more details. */
9928 if ((len - 0x34) > 8 &&
9929 (bitrate = qtdemux_parse_amr_bitrate (buf, amrwb))) {
9930 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
9931 GST_TAG_MAXIMUM_BITRATE, bitrate, NULL);
9934 gst_caps_set_simple (stream->caps,
9935 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9936 gst_buffer_unref (buf);
9942 /* mp4a atom withtout ESDS; Attempt to build codec data from atom */
9943 gint len = QT_UINT32 (stsd_data);
9946 guint16 sound_version = QT_UINT16 (stsd_data + 32);
9948 if (sound_version == 1) {
9949 guint16 channels = QT_UINT16 (stsd_data + 40);
9950 guint32 time_scale = QT_UINT32 (stsd_data + 46);
9951 guint8 codec_data[2];
9953 gint profile = 2; /* FIXME: Can this be determined somehow? There doesn't seem to be anything in mp4a atom that specifis compression */
9955 gint sample_rate_index =
9956 gst_codec_utils_aac_get_index_from_sample_rate (time_scale);
9958 /* build AAC codec data */
9959 codec_data[0] = profile << 3;
9960 codec_data[0] |= ((sample_rate_index >> 1) & 0x7);
9961 codec_data[1] = (sample_rate_index & 0x01) << 7;
9962 codec_data[1] |= (channels & 0xF) << 3;
9964 buf = gst_buffer_new_and_alloc (2);
9965 gst_buffer_fill (buf, 0, codec_data, 2);
9966 gst_caps_set_simple (stream->caps,
9967 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9968 gst_buffer_unref (buf);
9974 GST_INFO_OBJECT (qtdemux,
9975 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
9979 GST_INFO_OBJECT (qtdemux,
9980 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
9981 GST_FOURCC_ARGS (fourcc), stream->caps);
9983 } else if (stream->subtype == FOURCC_strm) {
9984 if (fourcc == FOURCC_rtsp) {
9985 stream->redirect_uri = qtdemux_get_rtsp_uri_from_hndl (qtdemux, minf);
9987 GST_INFO_OBJECT (qtdemux, "unhandled stream type %" GST_FOURCC_FORMAT,
9988 GST_FOURCC_ARGS (fourcc));
9989 goto unknown_stream;
9991 stream->sampled = TRUE;
9992 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
9993 || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt) {
9995 stream->sampled = TRUE;
9996 stream->sparse = TRUE;
9999 qtdemux_sub_caps (qtdemux, stream, fourcc, stsd_data, &codec);
10001 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
10002 GST_TAG_SUBTITLE_CODEC, codec, NULL);
10007 /* hunt for sort-of codec data */
10011 GNode *mp4s = NULL;
10012 GNode *esds = NULL;
10014 /* look for palette in a stsd->mp4s->esds sub-atom */
10015 mp4s = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4s);
10017 esds = qtdemux_tree_get_child_by_type (mp4s, FOURCC_esds);
10018 if (esds == NULL) {
10020 GST_LOG_OBJECT (qtdemux, "Skipping invalid stsd: no esds child");
10024 gst_qtdemux_handle_esds (qtdemux, stream, esds, stream->pending_tags);
10028 GST_INFO_OBJECT (qtdemux,
10029 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
10032 GST_INFO_OBJECT (qtdemux,
10033 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
10034 GST_FOURCC_ARGS (fourcc), stream->caps);
10036 /* everything in 1 sample */
10037 stream->sampled = TRUE;
10040 qtdemux_generic_caps (qtdemux, stream, fourcc, stsd_data, &codec);
10042 if (stream->caps == NULL)
10043 goto unknown_stream;
10046 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
10047 GST_TAG_SUBTITLE_CODEC, codec, NULL);
10053 /* promote to sampled format */
10054 if (stream->fourcc == FOURCC_samr) {
10055 /* force mono 8000 Hz for AMR */
10056 stream->sampled = TRUE;
10057 stream->n_channels = 1;
10058 stream->rate = 8000;
10059 } else if (stream->fourcc == FOURCC_sawb) {
10060 /* force mono 16000 Hz for AMR-WB */
10061 stream->sampled = TRUE;
10062 stream->n_channels = 1;
10063 stream->rate = 16000;
10064 } else if (stream->fourcc == FOURCC_mp4a) {
10065 stream->sampled = TRUE;
10068 /* collect sample information */
10069 if (!qtdemux_stbl_init (qtdemux, stream, stbl))
10070 goto samples_failed;
10072 if (qtdemux->fragmented) {
10076 /* need all moov samples as basis; probably not many if any at all */
10077 /* prevent moof parsing taking of at this time */
10078 offset = qtdemux->moof_offset;
10079 qtdemux->moof_offset = 0;
10080 if (stream->n_samples &&
10081 !qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
10082 qtdemux->moof_offset = offset;
10083 goto samples_failed;
10085 qtdemux->moof_offset = 0;
10086 /* movie duration more reliable in this case (e.g. mehd) */
10087 if (qtdemux->segment.duration &&
10088 GST_CLOCK_TIME_IS_VALID (qtdemux->segment.duration))
10090 GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->segment.duration);
10091 /* need defaults for fragments */
10092 qtdemux_parse_trex (qtdemux, stream, &dummy, &dummy, &dummy);
10095 /* configure segments */
10096 if (!qtdemux_parse_segments (qtdemux, stream, trak))
10097 goto segments_failed;
10099 /* add some language tag, if useful */
10100 if (stream->lang_id[0] != '\0' && strcmp (stream->lang_id, "unk") &&
10101 strcmp (stream->lang_id, "und")) {
10102 const gchar *lang_code;
10104 /* convert ISO 639-2 code to ISO 639-1 */
10105 lang_code = gst_tag_get_language_code (stream->lang_id);
10106 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
10107 GST_TAG_LANGUAGE_CODE, (lang_code) ? lang_code : stream->lang_id, NULL);
10110 /* Check for UDTA tags */
10111 if ((udta = qtdemux_tree_get_child_by_type (trak, FOURCC_udta))) {
10112 qtdemux_parse_udta (qtdemux, stream->pending_tags, udta);
10115 /* now we are ready to add the stream */
10116 if (qtdemux->n_streams >= GST_QTDEMUX_MAX_STREAMS)
10117 goto too_many_streams;
10119 if (!qtdemux->got_moov) {
10120 qtdemux->streams[qtdemux->n_streams] = stream;
10121 qtdemux->n_streams++;
10122 GST_DEBUG_OBJECT (qtdemux, "n_streams is now %d", qtdemux->n_streams);
10130 GST_INFO_OBJECT (qtdemux, "skip disabled track");
10132 gst_qtdemux_stream_free (qtdemux, stream);
10137 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
10138 (_("This file is corrupt and cannot be played.")), (NULL));
10140 gst_qtdemux_stream_free (qtdemux, stream);
10145 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT, (NULL), (NULL));
10147 gst_qtdemux_stream_free (qtdemux, stream);
10153 /* we posted an error already */
10154 /* free stbl sub-atoms */
10155 gst_qtdemux_stbl_free (stream);
10157 gst_qtdemux_stream_free (qtdemux, stream);
10162 GST_INFO_OBJECT (qtdemux, "stream with track id %i already exists",
10165 gst_qtdemux_stream_free (qtdemux, stream);
10170 GST_INFO_OBJECT (qtdemux, "unknown subtype %" GST_FOURCC_FORMAT,
10171 GST_FOURCC_ARGS (stream->subtype));
10173 gst_qtdemux_stream_free (qtdemux, stream);
10178 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
10179 (_("This file contains too many streams. Only playing first %d"),
10180 GST_QTDEMUX_MAX_STREAMS), (NULL));
10185 /* If we can estimate the overall bitrate, and don't have information about the
10186 * stream bitrate for exactly one stream, this guesses the stream bitrate as
10187 * the overall bitrate minus the sum of the bitrates of all other streams. This
10188 * should be useful for the common case where we have one audio and one video
10189 * stream and can estimate the bitrate of one, but not the other. */
10191 gst_qtdemux_guess_bitrate (GstQTDemux * qtdemux)
10193 QtDemuxStream *stream = NULL;
10194 gint64 size, sys_bitrate, sum_bitrate = 0;
10195 GstClockTime duration;
10199 if (qtdemux->fragmented)
10202 GST_DEBUG_OBJECT (qtdemux, "Looking for streams with unknown bitrate");
10204 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &size)
10206 GST_DEBUG_OBJECT (qtdemux,
10207 "Size in bytes of the stream not known - bailing");
10211 /* Subtract the header size */
10212 GST_DEBUG_OBJECT (qtdemux, "Total size %" G_GINT64_FORMAT ", header size %u",
10213 size, qtdemux->header_size);
10215 if (size < qtdemux->header_size)
10218 size = size - qtdemux->header_size;
10220 if (!gst_qtdemux_get_duration (qtdemux, &duration) ||
10221 duration == GST_CLOCK_TIME_NONE) {
10222 GST_DEBUG_OBJECT (qtdemux, "Stream duration not known - bailing");
10226 for (i = 0; i < qtdemux->n_streams; i++) {
10227 switch (qtdemux->streams[i]->subtype) {
10230 GST_DEBUG_OBJECT (qtdemux, "checking bitrate for %" GST_PTR_FORMAT,
10231 qtdemux->streams[i]->caps);
10232 /* retrieve bitrate, prefer avg then max */
10234 if (qtdemux->streams[i]->pending_tags) {
10235 gst_tag_list_get_uint (qtdemux->streams[i]->pending_tags,
10236 GST_TAG_MAXIMUM_BITRATE, &bitrate);
10237 GST_DEBUG_OBJECT (qtdemux, "max-bitrate: %u", bitrate);
10238 gst_tag_list_get_uint (qtdemux->streams[i]->pending_tags,
10239 GST_TAG_NOMINAL_BITRATE, &bitrate);
10240 GST_DEBUG_OBJECT (qtdemux, "nominal-bitrate: %u", bitrate);
10241 gst_tag_list_get_uint (qtdemux->streams[i]->pending_tags,
10242 GST_TAG_BITRATE, &bitrate);
10243 GST_DEBUG_OBJECT (qtdemux, "bitrate: %u", bitrate);
10246 sum_bitrate += bitrate;
10249 GST_DEBUG_OBJECT (qtdemux,
10250 ">1 stream with unknown bitrate - bailing");
10253 stream = qtdemux->streams[i];
10257 /* For other subtypes, we assume no significant impact on bitrate */
10263 GST_DEBUG_OBJECT (qtdemux, "All stream bitrates are known");
10267 sys_bitrate = gst_util_uint64_scale (size, GST_SECOND * 8, duration);
10269 if (sys_bitrate < sum_bitrate) {
10270 /* This can happen, since sum_bitrate might be derived from maximum
10271 * bitrates and not average bitrates */
10272 GST_DEBUG_OBJECT (qtdemux,
10273 "System bitrate less than sum bitrate - bailing");
10277 bitrate = sys_bitrate - sum_bitrate;
10278 GST_DEBUG_OBJECT (qtdemux, "System bitrate = %" G_GINT64_FORMAT
10279 ", Stream bitrate = %u", sys_bitrate, bitrate);
10281 if (!stream->pending_tags)
10282 stream->pending_tags = gst_tag_list_new_empty ();
10284 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
10285 GST_TAG_BITRATE, bitrate, NULL);
10288 static GstFlowReturn
10289 qtdemux_prepare_streams (GstQTDemux * qtdemux)
10292 GstFlowReturn ret = GST_FLOW_OK;
10294 GST_DEBUG_OBJECT (qtdemux, "prepare streams");
10296 for (i = 0; ret == GST_FLOW_OK && i < qtdemux->n_streams; i++) {
10297 QtDemuxStream *stream = qtdemux->streams[i];
10298 guint32 sample_num = 0;
10300 GST_DEBUG_OBJECT (qtdemux, "stream %d, id %d, fourcc %" GST_FOURCC_FORMAT,
10301 i, stream->track_id, GST_FOURCC_ARGS (stream->fourcc));
10303 if (qtdemux->fragmented) {
10304 /* need all moov samples first */
10305 GST_OBJECT_LOCK (qtdemux);
10306 while (stream->n_samples == 0)
10307 if ((ret = qtdemux_add_fragmented_samples (qtdemux)) != GST_FLOW_OK)
10309 GST_OBJECT_UNLOCK (qtdemux);
10311 /* discard any stray moof */
10312 qtdemux->moof_offset = 0;
10315 /* prepare braking */
10316 if (ret != GST_FLOW_ERROR)
10319 /* in pull mode, we should have parsed some sample info by now;
10320 * and quite some code will not handle no samples.
10321 * in push mode, we'll just have to deal with it */
10322 if (G_UNLIKELY (qtdemux->pullbased && !stream->n_samples)) {
10323 GST_DEBUG_OBJECT (qtdemux, "no samples for stream; discarding");
10324 gst_qtdemux_remove_stream (qtdemux, i);
10329 /* parse the initial sample for use in setting the frame rate cap */
10330 while (sample_num == 0 && sample_num < stream->n_samples) {
10331 if (!qtdemux_parse_samples (qtdemux, stream, sample_num))
10335 if (stream->n_samples > 0 && stream->stbl_index >= 0) {
10336 stream->first_duration = stream->samples[0].duration;
10337 GST_LOG_OBJECT (qtdemux, "stream %d first duration %u",
10338 stream->track_id, stream->first_duration);
10345 static GstFlowReturn
10346 qtdemux_expose_streams (GstQTDemux * qtdemux)
10349 GstFlowReturn ret = GST_FLOW_OK;
10350 GSList *oldpads = NULL;
10353 GST_DEBUG_OBJECT (qtdemux, "exposing streams");
10355 for (i = 0; ret == GST_FLOW_OK && i < qtdemux->n_streams; i++) {
10356 QtDemuxStream *stream = qtdemux->streams[i];
10357 GstPad *oldpad = stream->pad;
10360 GST_DEBUG_OBJECT (qtdemux, "stream %d, id %d, fourcc %" GST_FOURCC_FORMAT,
10361 i, stream->track_id, GST_FOURCC_ARGS (stream->fourcc));
10363 if ((stream->subtype == FOURCC_text || stream->subtype == FOURCC_sbtl) &&
10364 stream->track_id == qtdemux->chapters_track_id) {
10365 /* TODO - parse chapters track and expose it as GstToc; For now just ignore it
10366 so that it doesn't look like a subtitle track */
10367 gst_qtdemux_remove_stream (qtdemux, i);
10372 /* now we have all info and can expose */
10373 list = stream->pending_tags;
10374 stream->pending_tags = NULL;
10376 oldpads = g_slist_prepend (oldpads, oldpad);
10377 gst_qtdemux_add_stream (qtdemux, stream, list);
10380 gst_qtdemux_guess_bitrate (qtdemux);
10382 gst_element_no_more_pads (GST_ELEMENT_CAST (qtdemux));
10384 for (iter = oldpads; iter; iter = g_slist_next (iter)) {
10385 GstPad *oldpad = iter->data;
10387 gst_pad_push_event (oldpad, gst_event_new_eos ());
10388 gst_pad_set_active (oldpad, FALSE);
10389 gst_element_remove_pad (GST_ELEMENT (qtdemux), oldpad);
10390 gst_flow_combiner_remove_pad (qtdemux->flowcombiner, oldpad);
10391 gst_object_unref (oldpad);
10394 /* check if we should post a redirect in case there is a single trak
10395 * and it is a redirecting trak */
10396 if (qtdemux->n_streams == 1 && qtdemux->streams[0]->redirect_uri != NULL) {
10399 GST_INFO_OBJECT (qtdemux, "Issuing a redirect due to a single track with "
10400 "an external content");
10401 m = gst_message_new_element (GST_OBJECT_CAST (qtdemux),
10402 gst_structure_new ("redirect",
10403 "new-location", G_TYPE_STRING, qtdemux->streams[0]->redirect_uri,
10405 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), m);
10406 qtdemux->posted_redirect = TRUE;
10409 for (i = 0; i < qtdemux->n_streams; i++) {
10410 QtDemuxStream *stream = qtdemux->streams[i];
10412 qtdemux_do_allocation (qtdemux, stream);
10415 qtdemux->exposed = TRUE;
10419 /* check if major or compatible brand is 3GP */
10420 static inline gboolean
10421 qtdemux_is_brand_3gp (GstQTDemux * qtdemux, gboolean major)
10424 return ((qtdemux->major_brand & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
10425 GST_MAKE_FOURCC ('3', 'g', 0, 0));
10426 } else if (qtdemux->comp_brands != NULL) {
10430 gboolean res = FALSE;
10432 gst_buffer_map (qtdemux->comp_brands, &map, GST_MAP_READ);
10435 while (size >= 4) {
10436 res = res || ((QT_FOURCC (data) & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
10437 GST_MAKE_FOURCC ('3', 'g', 0, 0));
10441 gst_buffer_unmap (qtdemux->comp_brands, &map);
10448 /* check if tag is a spec'ed 3GP tag keyword storing a string */
10449 static inline gboolean
10450 qtdemux_is_string_tag_3gp (GstQTDemux * qtdemux, guint32 fourcc)
10452 return fourcc == FOURCC_cprt || fourcc == FOURCC_gnre || fourcc == FOURCC_titl
10453 || fourcc == FOURCC_dscp || fourcc == FOURCC_perf || fourcc == FOURCC_auth
10454 || fourcc == FOURCC_albm;
10458 qtdemux_tag_add_location (GstQTDemux * qtdemux, GstTagList * taglist,
10459 const char *tag, const char *dummy, GNode * node)
10461 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
10465 gdouble longitude, latitude, altitude;
10468 len = QT_UINT32 (node->data);
10475 /* TODO: language code skipped */
10477 name = gst_tag_freeform_string_to_utf8 (data + offset, -1, env_vars);
10480 /* do not alarm in trivial case, but bail out otherwise */
10481 if (*(data + offset) != 0) {
10482 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8, "
10486 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
10487 GST_TAG_GEO_LOCATION_NAME, name, NULL);
10488 offset += strlen (name);
10492 if (len < offset + 2 + 4 + 4 + 4)
10495 /* +1 +1 = skip null-terminator and location role byte */
10497 /* table in spec says unsigned, semantics say negative has meaning ... */
10498 longitude = QT_SFP32 (data + offset);
10501 latitude = QT_SFP32 (data + offset);
10504 altitude = QT_SFP32 (data + offset);
10506 /* one invalid means all are invalid */
10507 if (longitude >= -180.0 && longitude <= 180.0 &&
10508 latitude >= -90.0 && latitude <= 90.0) {
10509 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
10510 GST_TAG_GEO_LOCATION_LATITUDE, latitude,
10511 GST_TAG_GEO_LOCATION_LONGITUDE, longitude,
10512 GST_TAG_GEO_LOCATION_ELEVATION, altitude, NULL);
10515 /* TODO: no GST_TAG_, so astronomical body and additional notes skipped */
10522 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP location");
10529 qtdemux_tag_add_year (GstQTDemux * qtdemux, GstTagList * taglist,
10530 const char *tag, const char *dummy, GNode * node)
10536 len = QT_UINT32 (node->data);
10540 y = QT_UINT16 ((guint8 *) node->data + 12);
10542 GST_DEBUG_OBJECT (qtdemux, "year: %u is not a valid year", y);
10545 GST_DEBUG_OBJECT (qtdemux, "year: %u", y);
10547 date = g_date_new_dmy (1, 1, y);
10548 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, date, NULL);
10549 g_date_free (date);
10553 qtdemux_tag_add_classification (GstQTDemux * qtdemux, GstTagList * taglist,
10554 const char *tag, const char *dummy, GNode * node)
10557 char *tag_str = NULL;
10562 len = QT_UINT32 (node->data);
10567 entity = (guint8 *) node->data + offset;
10568 if (entity[0] == 0 || entity[1] == 0 || entity[2] == 0 || entity[3] == 0) {
10569 GST_DEBUG_OBJECT (qtdemux,
10570 "classification info: %c%c%c%c invalid classification entity",
10571 entity[0], entity[1], entity[2], entity[3]);
10576 table = QT_UINT16 ((guint8 *) node->data + offset);
10578 /* Language code skipped */
10582 /* Tag format: "XXXX://Y[YYYY]/classification info string"
10583 * XXXX: classification entity, fixed length 4 chars.
10584 * Y[YYYY]: classification table, max 5 chars.
10586 tag_str = g_strdup_printf ("----://%u/%s",
10587 table, (char *) node->data + offset);
10589 /* memcpy To be sure we're preserving byte order */
10590 memcpy (tag_str, entity, 4);
10591 GST_DEBUG_OBJECT (qtdemux, "classification info: %s", tag_str);
10593 gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND, tag, tag_str, NULL);
10602 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP classification");
10608 qtdemux_tag_add_str_full (GstQTDemux * qtdemux, GstTagList * taglist,
10609 const char *tag, const char *dummy, GNode * node)
10611 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
10617 gboolean ret = TRUE;
10618 const gchar *charset = NULL;
10620 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
10622 len = QT_UINT32 (data->data);
10623 type = QT_UINT32 ((guint8 *) data->data + 8);
10624 if (type == 0x00000001 && len > 16) {
10625 s = gst_tag_freeform_string_to_utf8 ((char *) data->data + 16, len - 16,
10628 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
10629 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, s, NULL);
10632 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
10636 len = QT_UINT32 (node->data);
10637 type = QT_UINT32 ((guint8 *) node->data + 4);
10638 if ((type >> 24) == 0xa9) {
10642 /* Type starts with the (C) symbol, so the next data is a list
10643 * of (string size(16), language code(16), string) */
10645 str_len = QT_UINT16 ((guint8 *) node->data + 8);
10646 lang_code = QT_UINT16 ((guint8 *) node->data + 10);
10648 /* the string + fourcc + size + 2 16bit fields,
10649 * means that there are more tags in this atom */
10650 if (len > str_len + 8 + 4) {
10651 /* TODO how to represent the same tag in different languages? */
10652 GST_WARNING_OBJECT (qtdemux, "Ignoring metadata entry with multiple "
10653 "text alternatives, reading only first one");
10657 len = str_len + 8 + 4; /* remove trailing strings that we don't use */
10658 GST_DEBUG_OBJECT (qtdemux, "found international text tag");
10660 if (lang_code < 0x800) { /* MAC encoded string */
10663 } else if (len > 14 && qtdemux_is_string_tag_3gp (qtdemux,
10664 QT_FOURCC ((guint8 *) node->data + 4))) {
10665 guint32 type = QT_UINT32 ((guint8 *) node->data + 8);
10667 /* we go for 3GP style encoding if major brands claims so,
10668 * or if no hope for data be ok UTF-8, and compatible 3GP brand present */
10669 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
10670 (qtdemux_is_brand_3gp (qtdemux, FALSE) &&
10671 ((type & 0x00FFFFFF) == 0x0) && (type >> 24 <= 0xF))) {
10673 /* 16-bit Language code is ignored here as well */
10674 GST_DEBUG_OBJECT (qtdemux, "found 3gpp text tag");
10681 GST_DEBUG_OBJECT (qtdemux, "found normal text tag");
10682 ret = FALSE; /* may have to fallback */
10685 GError *err = NULL;
10687 s = g_convert ((gchar *) node->data + offset, len - offset, "utf8",
10688 charset, NULL, NULL, &err);
10690 GST_DEBUG_OBJECT (qtdemux, "Failed to convert string from charset %s:"
10691 " %s(%d): %s", charset, g_quark_to_string (err->domain), err->code,
10693 g_error_free (err);
10696 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
10697 len - offset, env_vars);
10700 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
10701 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, s, NULL);
10705 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
10712 qtdemux_tag_add_str (GstQTDemux * qtdemux, GstTagList * taglist,
10713 const char *tag, const char *dummy, GNode * node)
10715 qtdemux_tag_add_str_full (qtdemux, taglist, tag, dummy, node);
10719 qtdemux_tag_add_keywords (GstQTDemux * qtdemux, GstTagList * taglist,
10720 const char *tag, const char *dummy, GNode * node)
10722 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
10724 char *s, *t, *k = NULL;
10729 /* first try normal string tag if major brand not 3GP */
10730 if (!qtdemux_is_brand_3gp (qtdemux, TRUE)) {
10731 if (!qtdemux_tag_add_str_full (qtdemux, taglist, tag, dummy, node)) {
10732 /* hm, that did not work, maybe 3gpp storage in non-3gpp major brand;
10733 * let's try it 3gpp way after minor safety check */
10735 if (QT_UINT32 (data) < 15 || !qtdemux_is_brand_3gp (qtdemux, FALSE))
10741 GST_DEBUG_OBJECT (qtdemux, "found 3gpp keyword tag");
10745 len = QT_UINT32 (data);
10749 count = QT_UINT8 (data + 14);
10751 for (; count; count--) {
10754 if (offset + 1 > len)
10756 slen = QT_UINT8 (data + offset);
10758 if (offset + slen > len)
10760 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
10763 GST_DEBUG_OBJECT (qtdemux, "adding keyword %s", GST_STR_NULL (s));
10765 t = g_strjoin (",", k, s, NULL);
10773 GST_DEBUG_OBJECT (qtdemux, "failed to convert keyword to UTF-8");
10780 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (k));
10781 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, k, NULL);
10790 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP keywords");
10796 qtdemux_tag_add_num (GstQTDemux * qtdemux, GstTagList * taglist,
10797 const char *tag1, const char *tag2, GNode * node)
10804 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
10806 len = QT_UINT32 (data->data);
10807 type = QT_UINT32 ((guint8 *) data->data + 8);
10808 if (type == 0x00000000 && len >= 22) {
10809 n1 = QT_UINT16 ((guint8 *) data->data + 18);
10810 n2 = QT_UINT16 ((guint8 *) data->data + 20);
10812 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag1, n1);
10813 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, n1, NULL);
10816 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag2, n2);
10817 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag2, n2, NULL);
10824 qtdemux_tag_add_tmpo (GstQTDemux * qtdemux, GstTagList * taglist,
10825 const char *tag1, const char *dummy, GNode * node)
10832 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
10834 len = QT_UINT32 (data->data);
10835 type = QT_UINT32 ((guint8 *) data->data + 8);
10836 GST_DEBUG_OBJECT (qtdemux, "have tempo tag, type=%d,len=%d", type, len);
10837 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
10838 if ((type == 0x00000015 || type == 0x0000000f) && len >= 18) {
10839 n1 = QT_UINT16 ((guint8 *) data->data + 16);
10841 /* do not add bpm=0 */
10842 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", n1);
10843 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, (gdouble) n1,
10851 qtdemux_tag_add_uint32 (GstQTDemux * qtdemux, GstTagList * taglist,
10852 const char *tag1, const char *dummy, GNode * node)
10859 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
10861 len = QT_UINT32 (data->data);
10862 type = QT_UINT32 ((guint8 *) data->data + 8);
10863 GST_DEBUG_OBJECT (qtdemux, "have %s tag, type=%d,len=%d", tag1, type, len);
10864 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
10865 if ((type == 0x00000015 || type == 0x0000000f) && len >= 20) {
10866 num = QT_UINT32 ((guint8 *) data->data + 16);
10868 /* do not add num=0 */
10869 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", num);
10870 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, num, NULL);
10877 qtdemux_tag_add_covr (GstQTDemux * qtdemux, GstTagList * taglist,
10878 const char *tag1, const char *dummy, GNode * node)
10885 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
10887 len = QT_UINT32 (data->data);
10888 type = QT_UINT32 ((guint8 *) data->data + 8);
10889 GST_DEBUG_OBJECT (qtdemux, "have covr tag, type=%d,len=%d", type, len);
10890 if ((type == 0x0000000d || type == 0x0000000e) && len > 16) {
10892 gst_tag_image_data_to_image_sample ((guint8 *) data->data + 16,
10893 len - 16, GST_TAG_IMAGE_TYPE_NONE))) {
10894 GST_DEBUG_OBJECT (qtdemux, "adding tag size %d", len - 16);
10895 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, sample, NULL);
10896 gst_sample_unref (sample);
10903 qtdemux_tag_add_date (GstQTDemux * qtdemux, GstTagList * taglist,
10904 const char *tag, const char *dummy, GNode * node)
10911 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
10913 len = QT_UINT32 (data->data);
10914 type = QT_UINT32 ((guint8 *) data->data + 8);
10915 if (type == 0x00000001 && len > 16) {
10916 guint y, m = 1, d = 1;
10919 s = g_strndup ((char *) data->data + 16, len - 16);
10920 GST_DEBUG_OBJECT (qtdemux, "adding date '%s'", s);
10921 ret = sscanf (s, "%u-%u-%u", &y, &m, &d);
10922 if (ret >= 1 && y > 1500 && y < 3000) {
10925 date = g_date_new_dmy (d, m, y);
10926 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, date, NULL);
10927 g_date_free (date);
10929 GST_DEBUG_OBJECT (qtdemux, "could not parse date string '%s'", s);
10937 qtdemux_tag_add_gnre (GstQTDemux * qtdemux, GstTagList * taglist,
10938 const char *tag, const char *dummy, GNode * node)
10942 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
10944 /* re-route to normal string tag if major brand says so
10945 * or no data atom and compatible brand suggests so */
10946 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
10947 (qtdemux_is_brand_3gp (qtdemux, FALSE) && !data)) {
10948 qtdemux_tag_add_str (qtdemux, taglist, tag, dummy, node);
10953 guint len, type, n;
10955 len = QT_UINT32 (data->data);
10956 type = QT_UINT32 ((guint8 *) data->data + 8);
10957 if (type == 0x00000000 && len >= 18) {
10958 n = QT_UINT16 ((guint8 *) data->data + 16);
10960 const gchar *genre;
10962 genre = gst_tag_id3_genre_get (n - 1);
10963 if (genre != NULL) {
10964 GST_DEBUG_OBJECT (qtdemux, "adding %d [%s]", n, genre);
10965 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, genre, NULL);
10973 qtdemux_add_double_tag_from_str (GstQTDemux * demux, GstTagList * taglist,
10974 const gchar * tag, guint8 * data, guint32 datasize)
10979 /* make a copy to have \0 at the end */
10980 datacopy = g_strndup ((gchar *) data, datasize);
10982 /* convert the str to double */
10983 if (sscanf (datacopy, "%lf", &value) == 1) {
10984 GST_DEBUG_OBJECT (demux, "adding tag: %s [%s]", tag, datacopy);
10985 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, value, NULL);
10987 GST_WARNING_OBJECT (demux, "Failed to parse double from string: %s",
10995 qtdemux_tag_add_revdns (GstQTDemux * demux, GstTagList * taglist,
10996 const char *tag, const char *tag_bis, GNode * node)
11005 const gchar *meanstr;
11006 const gchar *namestr;
11008 /* checking the whole ---- atom size for consistency */
11009 if (QT_UINT32 (node->data) <= 4 + 12 + 12 + 16) {
11010 GST_WARNING_OBJECT (demux, "Tag ---- atom is too small, ignoring");
11014 mean = qtdemux_tree_get_child_by_type (node, FOURCC_mean);
11016 GST_WARNING_OBJECT (demux, "No 'mean' atom found");
11020 meansize = QT_UINT32 (mean->data);
11021 if (meansize <= 12) {
11022 GST_WARNING_OBJECT (demux, "Small mean atom, ignoring the whole tag");
11025 meanstr = ((gchar *) mean->data) + 12;
11028 name = qtdemux_tree_get_child_by_type (node, FOURCC_name);
11030 GST_WARNING_OBJECT (demux, "'name' atom not found, ignoring tag");
11034 namesize = QT_UINT32 (name->data);
11035 if (namesize <= 12) {
11036 GST_WARNING_OBJECT (demux, "'name' atom is too small, ignoring tag");
11039 namestr = ((gchar *) name->data) + 12;
11047 * uint24 - data type
11051 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
11053 GST_WARNING_OBJECT (demux, "No data atom in this tag");
11056 datasize = QT_UINT32 (data->data);
11057 if (datasize <= 16) {
11058 GST_WARNING_OBJECT (demux, "Data atom too small");
11061 datatype = QT_UINT32 (((gchar *) data->data) + 8) & 0xFFFFFF;
11063 if ((strncmp (meanstr, "com.apple.iTunes", meansize) == 0) ||
11064 (strncmp (meanstr, "org.hydrogenaudio.replaygain", meansize) == 0)) {
11065 static const struct
11067 const gchar name[28];
11068 const gchar tag[28];
11071 "replaygain_track_gain", GST_TAG_TRACK_GAIN}, {
11072 "replaygain_track_peak", GST_TAG_TRACK_PEAK}, {
11073 "replaygain_album_gain", GST_TAG_ALBUM_GAIN}, {
11074 "replaygain_album_peak", GST_TAG_ALBUM_PEAK}, {
11075 "MusicBrainz Track Id", GST_TAG_MUSICBRAINZ_TRACKID}, {
11076 "MusicBrainz Artist Id", GST_TAG_MUSICBRAINZ_ARTISTID}, {
11077 "MusicBrainz Album Id", GST_TAG_MUSICBRAINZ_ALBUMID}, {
11078 "MusicBrainz Album Artist Id", GST_TAG_MUSICBRAINZ_ALBUMARTISTID}
11082 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
11083 if (!g_ascii_strncasecmp (tags[i].name, namestr, namesize)) {
11084 switch (gst_tag_get_type (tags[i].tag)) {
11085 case G_TYPE_DOUBLE:
11086 qtdemux_add_double_tag_from_str (demux, taglist, tags[i].tag,
11087 ((guint8 *) data->data) + 16, datasize - 16);
11089 case G_TYPE_STRING:
11090 qtdemux_tag_add_str (demux, taglist, tags[i].tag, NULL, node);
11099 if (i == G_N_ELEMENTS (tags))
11109 #ifndef GST_DISABLE_GST_DEBUG
11111 gchar *namestr_dbg;
11112 gchar *meanstr_dbg;
11114 meanstr_dbg = g_strndup (meanstr, meansize);
11115 namestr_dbg = g_strndup (namestr, namesize);
11117 GST_WARNING_OBJECT (demux, "This tag %s:%s type:%u is not mapped, "
11118 "file a bug at bugzilla.gnome.org", meanstr_dbg, namestr_dbg, datatype);
11120 g_free (namestr_dbg);
11121 g_free (meanstr_dbg);
11128 qtdemux_tag_add_id32 (GstQTDemux * demux, GstTagList * taglist, const char *tag,
11129 const char *tag_bis, GNode * node)
11134 GstTagList *id32_taglist = NULL;
11136 GST_LOG_OBJECT (demux, "parsing ID32");
11139 len = GST_READ_UINT32_BE (data);
11141 /* need at least full box and language tag */
11145 buf = gst_buffer_new_allocate (NULL, len - 14, NULL);
11146 gst_buffer_fill (buf, 0, data + 14, len - 14);
11148 id32_taglist = gst_tag_list_from_id3v2_tag (buf);
11149 if (id32_taglist) {
11150 GST_LOG_OBJECT (demux, "parsing ok");
11151 gst_tag_list_insert (taglist, id32_taglist, GST_TAG_MERGE_KEEP);
11152 gst_tag_list_unref (id32_taglist);
11154 GST_LOG_OBJECT (demux, "parsing failed");
11157 gst_buffer_unref (buf);
11160 typedef void (*GstQTDemuxAddTagFunc) (GstQTDemux * demux, GstTagList * taglist,
11161 const char *tag, const char *tag_bis, GNode * node);
11164 FOURCC_pcst -> if media is a podcast -> bool
11165 FOURCC_cpil -> if media is part of a compilation -> bool
11166 FOURCC_pgap -> if media is part of a gapless context -> bool
11167 FOURCC_tven -> the tv episode id e.g. S01E23 -> str
11170 static const struct
11173 const gchar *gst_tag;
11174 const gchar *gst_tag_bis;
11175 const GstQTDemuxAddTagFunc func;
11178 FOURCC__nam, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
11179 FOURCC_titl, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
11180 FOURCC__grp, GST_TAG_GROUPING, NULL, qtdemux_tag_add_str}, {
11181 FOURCC__wrt, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
11182 FOURCC__ART, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
11183 FOURCC_aART, GST_TAG_ALBUM_ARTIST, NULL, qtdemux_tag_add_str}, {
11184 FOURCC_perf, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
11185 FOURCC_auth, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
11186 FOURCC__alb, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
11187 FOURCC_albm, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
11188 FOURCC_cprt, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
11189 FOURCC__cpy, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
11190 FOURCC__cmt, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
11191 FOURCC__des, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
11192 FOURCC_desc, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
11193 FOURCC_dscp, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
11194 FOURCC__lyr, GST_TAG_LYRICS, NULL, qtdemux_tag_add_str}, {
11195 FOURCC__day, GST_TAG_DATE, NULL, qtdemux_tag_add_date}, {
11196 FOURCC_yrrc, GST_TAG_DATE, NULL, qtdemux_tag_add_year}, {
11197 FOURCC__too, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
11198 FOURCC__inf, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
11199 FOURCC_trkn, GST_TAG_TRACK_NUMBER, GST_TAG_TRACK_COUNT, qtdemux_tag_add_num}, {
11200 FOURCC_disk, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
11201 qtdemux_tag_add_num}, {
11202 FOURCC_disc, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
11203 qtdemux_tag_add_num}, {
11204 FOURCC__gen, GST_TAG_GENRE, NULL, qtdemux_tag_add_str}, {
11205 FOURCC_gnre, GST_TAG_GENRE, NULL, qtdemux_tag_add_gnre}, {
11206 FOURCC_tmpo, GST_TAG_BEATS_PER_MINUTE, NULL, qtdemux_tag_add_tmpo}, {
11207 FOURCC_covr, GST_TAG_PREVIEW_IMAGE, NULL, qtdemux_tag_add_covr}, {
11208 FOURCC_sonm, GST_TAG_TITLE_SORTNAME, NULL, qtdemux_tag_add_str}, {
11209 FOURCC_soal, GST_TAG_ALBUM_SORTNAME, NULL, qtdemux_tag_add_str}, {
11210 FOURCC_soar, GST_TAG_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
11211 FOURCC_soaa, GST_TAG_ALBUM_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
11212 FOURCC_soco, GST_TAG_COMPOSER_SORTNAME, NULL, qtdemux_tag_add_str}, {
11213 FOURCC_sosn, GST_TAG_SHOW_SORTNAME, NULL, qtdemux_tag_add_str}, {
11214 FOURCC_tvsh, GST_TAG_SHOW_NAME, NULL, qtdemux_tag_add_str}, {
11215 FOURCC_tvsn, GST_TAG_SHOW_SEASON_NUMBER, NULL, qtdemux_tag_add_uint32}, {
11216 FOURCC_tves, GST_TAG_SHOW_EPISODE_NUMBER, NULL, qtdemux_tag_add_uint32}, {
11217 FOURCC_kywd, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_keywords}, {
11218 FOURCC_keyw, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_str}, {
11219 FOURCC__enc, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
11220 FOURCC_loci, GST_TAG_GEO_LOCATION_NAME, NULL, qtdemux_tag_add_location}, {
11221 FOURCC_clsf, GST_QT_DEMUX_CLASSIFICATION_TAG, NULL,
11222 qtdemux_tag_add_classification}, {
11223 FOURCC__mak, GST_TAG_DEVICE_MANUFACTURER, NULL, qtdemux_tag_add_str}, {
11224 FOURCC__mod, GST_TAG_DEVICE_MODEL, NULL, qtdemux_tag_add_str}, {
11225 FOURCC__swr, GST_TAG_APPLICATION_NAME, NULL, qtdemux_tag_add_str}, {
11227 /* This is a special case, some tags are stored in this
11228 * 'reverse dns naming', according to:
11229 * http://atomicparsley.sourceforge.net/mpeg-4files.html and
11232 FOURCC_____, "", NULL, qtdemux_tag_add_revdns}, {
11233 /* see http://www.mp4ra.org/specs.html for ID32 in meta box */
11234 FOURCC_ID32, "", NULL, qtdemux_tag_add_id32}
11237 struct _GstQtDemuxTagList
11240 GstTagList *taglist;
11242 typedef struct _GstQtDemuxTagList GstQtDemuxTagList;
11245 qtdemux_tag_add_blob (GNode * node, GstQtDemuxTagList * qtdemuxtaglist)
11251 const gchar *style;
11256 GstQTDemux *demux = qtdemuxtaglist->demux;
11257 GstTagList *taglist = qtdemuxtaglist->taglist;
11260 len = QT_UINT32 (data);
11261 buf = gst_buffer_new_and_alloc (len);
11262 gst_buffer_fill (buf, 0, data, len);
11264 /* heuristic to determine style of tag */
11265 if (QT_FOURCC (data + 4) == FOURCC_____ ||
11266 (len > 8 + 12 && QT_FOURCC (data + 12) == FOURCC_data))
11268 else if (demux->major_brand == FOURCC_qt__)
11269 style = "quicktime";
11270 /* fall back to assuming iso/3gp tag style */
11274 /* santize the name for the caps. */
11275 for (i = 0; i < 4; i++) {
11276 guint8 d = data[4 + i];
11277 if (g_ascii_isalnum (d))
11278 ndata[i] = g_ascii_tolower (d);
11283 media_type = g_strdup_printf ("application/x-gst-qt-%c%c%c%c-tag",
11284 ndata[0], ndata[1], ndata[2], ndata[3]);
11285 GST_DEBUG_OBJECT (demux, "media type %s", media_type);
11287 s = gst_structure_new (media_type, "style", G_TYPE_STRING, style, NULL);
11288 sample = gst_sample_new (buf, NULL, NULL, s);
11289 gst_buffer_unref (buf);
11290 g_free (media_type);
11292 GST_DEBUG_OBJECT (demux, "adding private tag; size %d, info %" GST_PTR_FORMAT,
11295 gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND,
11296 GST_QT_DEMUX_PRIVATE_TAG, sample, NULL);
11298 gst_sample_unref (sample);
11302 qtdemux_parse_udta (GstQTDemux * qtdemux, GstTagList * taglist, GNode * udta)
11309 GstQtDemuxTagList demuxtaglist;
11311 demuxtaglist.demux = qtdemux;
11312 demuxtaglist.taglist = taglist;
11314 meta = qtdemux_tree_get_child_by_type (udta, FOURCC_meta);
11315 if (meta != NULL) {
11316 ilst = qtdemux_tree_get_child_by_type (meta, FOURCC_ilst);
11317 if (ilst == NULL) {
11318 GST_LOG_OBJECT (qtdemux, "no ilst");
11323 GST_LOG_OBJECT (qtdemux, "no meta so using udta itself");
11327 while (i < G_N_ELEMENTS (add_funcs)) {
11328 node = qtdemux_tree_get_child_by_type (ilst, add_funcs[i].fourcc);
11332 len = QT_UINT32 (node->data);
11334 GST_DEBUG_OBJECT (qtdemux, "too small tag atom %" GST_FOURCC_FORMAT,
11335 GST_FOURCC_ARGS (add_funcs[i].fourcc));
11337 add_funcs[i].func (qtdemux, taglist, add_funcs[i].gst_tag,
11338 add_funcs[i].gst_tag_bis, node);
11340 g_node_destroy (node);
11346 /* parsed nodes have been removed, pass along remainder as blob */
11347 g_node_children_foreach (ilst, G_TRAVERSE_ALL,
11348 (GNodeForeachFunc) qtdemux_tag_add_blob, &demuxtaglist);
11350 /* parse up XMP_ node if existing */
11351 xmp_ = qtdemux_tree_get_child_by_type (udta, FOURCC_XMP_);
11352 if (xmp_ != NULL) {
11354 GstTagList *xmptaglist;
11356 buf = _gst_buffer_new_wrapped (((guint8 *) xmp_->data) + 8,
11357 QT_UINT32 ((guint8 *) xmp_->data) - 8, NULL);
11358 xmptaglist = gst_tag_list_from_xmp_buffer (buf);
11359 gst_buffer_unref (buf);
11361 qtdemux_handle_xmp_taglist (qtdemux, taglist, xmptaglist);
11363 GST_DEBUG_OBJECT (qtdemux, "No XMP_ node found");
11369 GstStructure *structure; /* helper for sort function */
11371 guint min_req_bitrate;
11372 guint min_req_qt_version;
11376 qtdemux_redirects_sort_func (gconstpointer a, gconstpointer b)
11378 GstQtReference *ref_a = (GstQtReference *) a;
11379 GstQtReference *ref_b = (GstQtReference *) b;
11381 if (ref_b->min_req_qt_version != ref_a->min_req_qt_version)
11382 return ref_b->min_req_qt_version - ref_a->min_req_qt_version;
11384 /* known bitrates go before unknown; higher bitrates go first */
11385 return ref_b->min_req_bitrate - ref_a->min_req_bitrate;
11388 /* sort the redirects and post a message for the application.
11391 qtdemux_process_redirects (GstQTDemux * qtdemux, GList * references)
11393 GstQtReference *best;
11396 GValue list_val = { 0, };
11399 g_assert (references != NULL);
11401 references = g_list_sort (references, qtdemux_redirects_sort_func);
11403 best = (GstQtReference *) references->data;
11405 g_value_init (&list_val, GST_TYPE_LIST);
11407 for (l = references; l != NULL; l = l->next) {
11408 GstQtReference *ref = (GstQtReference *) l->data;
11409 GValue struct_val = { 0, };
11411 ref->structure = gst_structure_new ("redirect",
11412 "new-location", G_TYPE_STRING, ref->location, NULL);
11414 if (ref->min_req_bitrate > 0) {
11415 gst_structure_set (ref->structure, "minimum-bitrate", G_TYPE_INT,
11416 ref->min_req_bitrate, NULL);
11419 g_value_init (&struct_val, GST_TYPE_STRUCTURE);
11420 g_value_set_boxed (&struct_val, ref->structure);
11421 gst_value_list_append_value (&list_val, &struct_val);
11422 g_value_unset (&struct_val);
11423 /* don't free anything here yet, since we need best->structure below */
11426 g_assert (best != NULL);
11427 s = gst_structure_copy (best->structure);
11429 if (g_list_length (references) > 1) {
11430 gst_structure_set_value (s, "locations", &list_val);
11433 g_value_unset (&list_val);
11435 for (l = references; l != NULL; l = l->next) {
11436 GstQtReference *ref = (GstQtReference *) l->data;
11438 gst_structure_free (ref->structure);
11439 g_free (ref->location);
11442 g_list_free (references);
11444 GST_INFO_OBJECT (qtdemux, "posting redirect message: %" GST_PTR_FORMAT, s);
11445 msg = gst_message_new_element (GST_OBJECT_CAST (qtdemux), s);
11446 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
11447 qtdemux->posted_redirect = TRUE;
11450 /* look for redirect nodes, collect all redirect information and
11454 qtdemux_parse_redirects (GstQTDemux * qtdemux)
11456 GNode *rmra, *rmda, *rdrf;
11458 rmra = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_rmra);
11460 GList *redirects = NULL;
11462 rmda = qtdemux_tree_get_child_by_type (rmra, FOURCC_rmda);
11464 GstQtReference ref = { NULL, NULL, 0, 0 };
11465 GNode *rmdr, *rmvc;
11467 if ((rmdr = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmdr))) {
11468 ref.min_req_bitrate = QT_UINT32 ((guint8 *) rmdr->data + 12);
11469 GST_LOG_OBJECT (qtdemux, "data rate atom, required bitrate = %u",
11470 ref.min_req_bitrate);
11473 if ((rmvc = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmvc))) {
11474 guint32 package = QT_FOURCC ((guint8 *) rmvc->data + 12);
11475 guint version = QT_UINT32 ((guint8 *) rmvc->data + 16);
11477 #ifndef GST_DISABLE_GST_DEBUG
11478 guint bitmask = QT_UINT32 ((guint8 *) rmvc->data + 20);
11480 guint check_type = QT_UINT16 ((guint8 *) rmvc->data + 24);
11482 GST_LOG_OBJECT (qtdemux,
11483 "version check atom [%" GST_FOURCC_FORMAT "], version=0x%08x"
11484 ", mask=%08x, check_type=%u", GST_FOURCC_ARGS (package), version,
11485 bitmask, check_type);
11486 if (package == FOURCC_qtim && check_type == 0) {
11487 ref.min_req_qt_version = version;
11491 rdrf = qtdemux_tree_get_child_by_type (rmda, FOURCC_rdrf);
11497 ref_len = QT_UINT32 ((guint8 *) rdrf->data);
11498 if (ref_len > 20) {
11499 ref_type = QT_FOURCC ((guint8 *) rdrf->data + 12);
11500 ref_data = (guint8 *) rdrf->data + 20;
11501 if (ref_type == FOURCC_alis) {
11502 guint record_len, record_version, fn_len;
11504 if (ref_len > 70) {
11505 /* MacOSX alias record, google for alias-layout.txt */
11506 record_len = QT_UINT16 (ref_data + 4);
11507 record_version = QT_UINT16 (ref_data + 4 + 2);
11508 fn_len = QT_UINT8 (ref_data + 50);
11509 if (record_len > 50 && record_version == 2 && fn_len > 0) {
11510 ref.location = g_strndup ((gchar *) ref_data + 51, fn_len);
11513 GST_WARNING_OBJECT (qtdemux, "Invalid rdrf/alis size (%u < 70)",
11516 } else if (ref_type == FOURCC_url_) {
11517 ref.location = g_strndup ((gchar *) ref_data, ref_len - 8);
11519 GST_DEBUG_OBJECT (qtdemux,
11520 "unknown rdrf reference type %" GST_FOURCC_FORMAT,
11521 GST_FOURCC_ARGS (ref_type));
11523 if (ref.location != NULL) {
11524 GST_INFO_OBJECT (qtdemux, "New location: %s", ref.location);
11526 g_list_prepend (redirects, g_memdup (&ref, sizeof (ref)));
11528 GST_WARNING_OBJECT (qtdemux,
11529 "Failed to extract redirect location from rdrf atom");
11532 GST_WARNING_OBJECT (qtdemux, "Invalid rdrf size (%u < 20)", ref_len);
11536 /* look for others */
11537 rmda = qtdemux_tree_get_sibling_by_type (rmda, FOURCC_rmda);
11540 if (redirects != NULL) {
11541 qtdemux_process_redirects (qtdemux, redirects);
11547 static GstTagList *
11548 qtdemux_add_container_format (GstQTDemux * qtdemux, GstTagList * tags)
11552 if (tags == NULL) {
11553 tags = gst_tag_list_new_empty ();
11554 gst_tag_list_set_scope (tags, GST_TAG_SCOPE_GLOBAL);
11557 if (qtdemux->major_brand == FOURCC_mjp2)
11558 fmt = "Motion JPEG 2000";
11559 else if ((qtdemux->major_brand & 0xffff) == GST_MAKE_FOURCC ('3', 'g', 0, 0))
11561 else if (qtdemux->major_brand == FOURCC_qt__)
11563 else if (qtdemux->fragmented)
11566 fmt = "ISO MP4/M4A";
11568 GST_LOG_OBJECT (qtdemux, "mapped %" GST_FOURCC_FORMAT " to '%s'",
11569 GST_FOURCC_ARGS (qtdemux->major_brand), fmt);
11571 gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_CONTAINER_FORMAT,
11577 /* we have read th complete moov node now.
11578 * This function parses all of the relevant info, creates the traks and
11579 * prepares all data structures for playback
11582 qtdemux_parse_tree (GstQTDemux * qtdemux)
11588 GstClockTime duration;
11590 guint64 creation_time;
11591 GstDateTime *datetime = NULL;
11594 /* make sure we have a usable taglist */
11595 if (!qtdemux->tag_list) {
11596 qtdemux->tag_list = gst_tag_list_new_empty ();
11597 gst_tag_list_set_scope (qtdemux->tag_list, GST_TAG_SCOPE_GLOBAL);
11599 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
11602 mvhd = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvhd);
11603 if (mvhd == NULL) {
11604 GST_LOG_OBJECT (qtdemux, "No mvhd node found, looking for redirects.");
11605 return qtdemux_parse_redirects (qtdemux);
11608 version = QT_UINT8 ((guint8 *) mvhd->data + 8);
11609 if (version == 1) {
11610 creation_time = QT_UINT64 ((guint8 *) mvhd->data + 12);
11611 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 28);
11612 qtdemux->duration = QT_UINT64 ((guint8 *) mvhd->data + 32);
11613 } else if (version == 0) {
11614 creation_time = QT_UINT32 ((guint8 *) mvhd->data + 12);
11615 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 20);
11616 qtdemux->duration = QT_UINT32 ((guint8 *) mvhd->data + 24);
11618 GST_WARNING_OBJECT (qtdemux, "Unhandled mvhd version %d", version);
11622 /* Moving qt creation time (secs since 1904) to unix time */
11623 if (creation_time != 0) {
11624 /* Try to use epoch first as it should be faster and more commonly found */
11625 if (creation_time >= QTDEMUX_SECONDS_FROM_1904_TO_1970) {
11628 creation_time -= QTDEMUX_SECONDS_FROM_1904_TO_1970;
11629 /* some data cleansing sanity */
11630 g_get_current_time (&now);
11631 if (now.tv_sec + 24 * 3600 < creation_time) {
11632 GST_DEBUG_OBJECT (qtdemux, "discarding bogus future creation time");
11634 datetime = gst_date_time_new_from_unix_epoch_utc (creation_time);
11637 GDateTime *base_dt = g_date_time_new_utc (1904, 1, 1, 0, 0, 0);
11638 GDateTime *dt, *dt_local;
11640 dt = g_date_time_add_seconds (base_dt, creation_time);
11641 dt_local = g_date_time_to_local (dt);
11642 datetime = gst_date_time_new_from_g_date_time (dt_local);
11644 g_date_time_unref (base_dt);
11645 g_date_time_unref (dt);
11649 /* Use KEEP as explicit tags should have a higher priority than mvhd tag */
11650 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_KEEP, GST_TAG_DATE_TIME,
11652 gst_date_time_unref (datetime);
11655 GST_INFO_OBJECT (qtdemux, "timescale: %u", qtdemux->timescale);
11656 GST_INFO_OBJECT (qtdemux, "duration: %" G_GUINT64_FORMAT, qtdemux->duration);
11658 /* check for fragmented file and get some (default) data */
11659 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
11662 GstByteReader mehd_data;
11664 /* let track parsing or anyone know weird stuff might happen ... */
11665 qtdemux->fragmented = TRUE;
11667 /* compensate for total duration */
11668 mehd = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_mehd, &mehd_data);
11670 qtdemux_parse_mehd (qtdemux, &mehd_data);
11673 /* set duration in the segment info */
11674 gst_qtdemux_get_duration (qtdemux, &duration);
11676 qtdemux->segment.duration = duration;
11677 /* also do not exceed duration; stop is set that way post seek anyway,
11678 * and segment activation falls back to duration,
11679 * whereas loop only checks stop, so let's align this here as well */
11680 qtdemux->segment.stop = duration;
11683 /* parse all traks */
11684 trak = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_trak);
11686 qtdemux_parse_trak (qtdemux, trak);
11687 /* iterate all siblings */
11688 trak = qtdemux_tree_get_sibling_by_type (trak, FOURCC_trak);
11691 if (!qtdemux->tag_list) {
11692 GST_DEBUG_OBJECT (qtdemux, "new tag list");
11693 qtdemux->tag_list = gst_tag_list_new_empty ();
11694 gst_tag_list_set_scope (qtdemux->tag_list, GST_TAG_SCOPE_GLOBAL);
11696 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
11700 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_udta);
11702 qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
11704 GST_LOG_OBJECT (qtdemux, "No udta node found.");
11707 /* maybe also some tags in meta box */
11708 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_meta);
11710 GST_DEBUG_OBJECT (qtdemux, "Parsing meta box for tags.");
11711 qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
11713 GST_LOG_OBJECT (qtdemux, "No meta node found.");
11716 /* parse any protection system info */
11717 pssh = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_pssh);
11719 GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
11720 qtdemux_parse_pssh (qtdemux, pssh);
11721 pssh = qtdemux_tree_get_sibling_by_type (pssh, FOURCC_pssh);
11724 qtdemux->tag_list = qtdemux_add_container_format (qtdemux, qtdemux->tag_list);
11729 /* taken from ffmpeg */
11731 read_descr_size (guint8 * ptr, guint8 * end, guint8 ** end_out)
11743 len = (len << 7) | (c & 0x7f);
11751 /* this can change the codec originally present in @list */
11753 gst_qtdemux_handle_esds (GstQTDemux * qtdemux, QtDemuxStream * stream,
11754 GNode * esds, GstTagList * list)
11756 int len = QT_UINT32 (esds->data);
11757 guint8 *ptr = esds->data;
11758 guint8 *end = ptr + len;
11760 guint8 *data_ptr = NULL;
11762 guint8 object_type_id = 0;
11763 const char *codec_name = NULL;
11764 GstCaps *caps = NULL;
11766 GST_MEMDUMP_OBJECT (qtdemux, "esds", ptr, len);
11768 GST_DEBUG_OBJECT (qtdemux, "version/flags = %08x", QT_UINT32 (ptr));
11770 while (ptr + 1 < end) {
11771 tag = QT_UINT8 (ptr);
11772 GST_DEBUG_OBJECT (qtdemux, "tag = %02x", tag);
11774 len = read_descr_size (ptr, end, &ptr);
11775 GST_DEBUG_OBJECT (qtdemux, "len = %d", len);
11777 /* Check the stated amount of data is available for reading */
11778 if (len < 0 || ptr + len > end)
11782 case ES_DESCRIPTOR_TAG:
11783 GST_DEBUG_OBJECT (qtdemux, "ID %04x", QT_UINT16 (ptr));
11784 GST_DEBUG_OBJECT (qtdemux, "priority %04x", QT_UINT8 (ptr + 2));
11787 case DECODER_CONFIG_DESC_TAG:{
11788 guint max_bitrate, avg_bitrate;
11790 object_type_id = QT_UINT8 (ptr);
11791 max_bitrate = QT_UINT32 (ptr + 5);
11792 avg_bitrate = QT_UINT32 (ptr + 9);
11793 GST_DEBUG_OBJECT (qtdemux, "object_type_id %02x", object_type_id);
11794 GST_DEBUG_OBJECT (qtdemux, "stream_type %02x", QT_UINT8 (ptr + 1));
11795 GST_DEBUG_OBJECT (qtdemux, "buffer_size_db %02x", QT_UINT24 (ptr + 2));
11796 GST_DEBUG_OBJECT (qtdemux, "max bitrate %u", max_bitrate);
11797 GST_DEBUG_OBJECT (qtdemux, "avg bitrate %u", avg_bitrate);
11798 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
11799 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
11800 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
11802 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
11803 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
11804 avg_bitrate, NULL);
11809 case DECODER_SPECIFIC_INFO_TAG:
11810 GST_MEMDUMP_OBJECT (qtdemux, "data", ptr, len);
11811 if (object_type_id == 0xe0 && len == 0x40) {
11817 GST_DEBUG_OBJECT (qtdemux,
11818 "Have VOBSUB palette. Creating palette event");
11819 /* move to decConfigDescr data and read palette */
11821 for (i = 0; i < 16; i++) {
11822 clut[i] = QT_UINT32 (data);
11826 s = gst_structure_new ("application/x-gst-dvd", "event",
11827 G_TYPE_STRING, "dvd-spu-clut-change",
11828 "clut00", G_TYPE_INT, clut[0], "clut01", G_TYPE_INT, clut[1],
11829 "clut02", G_TYPE_INT, clut[2], "clut03", G_TYPE_INT, clut[3],
11830 "clut04", G_TYPE_INT, clut[4], "clut05", G_TYPE_INT, clut[5],
11831 "clut06", G_TYPE_INT, clut[6], "clut07", G_TYPE_INT, clut[7],
11832 "clut08", G_TYPE_INT, clut[8], "clut09", G_TYPE_INT, clut[9],
11833 "clut10", G_TYPE_INT, clut[10], "clut11", G_TYPE_INT, clut[11],
11834 "clut12", G_TYPE_INT, clut[12], "clut13", G_TYPE_INT, clut[13],
11835 "clut14", G_TYPE_INT, clut[14], "clut15", G_TYPE_INT, clut[15],
11838 /* store event and trigger custom processing */
11839 stream->pending_event =
11840 gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s);
11842 /* Generic codec_data handler puts it on the caps */
11849 case SL_CONFIG_DESC_TAG:
11850 GST_DEBUG_OBJECT (qtdemux, "data %02x", QT_UINT8 (ptr));
11854 GST_DEBUG_OBJECT (qtdemux, "Unknown/unhandled descriptor tag %02x",
11856 GST_MEMDUMP_OBJECT (qtdemux, "descriptor data", ptr, len);
11862 /* object_type_id in the esds atom in mp4a and mp4v tells us which codec is
11863 * in use, and should also be used to override some other parameters for some
11865 switch (object_type_id) {
11866 case 0x20: /* MPEG-4 */
11867 /* 4 bytes for the visual_object_sequence_start_code and 1 byte for the
11868 * profile_and_level_indication */
11869 if (data_ptr != NULL && data_len >= 5 &&
11870 GST_READ_UINT32_BE (data_ptr) == 0x000001b0) {
11871 gst_codec_utils_mpeg4video_caps_set_level_and_profile (stream->caps,
11872 data_ptr + 4, data_len - 4);
11874 break; /* Nothing special needed here */
11875 case 0x21: /* H.264 */
11876 codec_name = "H.264 / AVC";
11877 caps = gst_caps_new_simple ("video/x-h264",
11878 "stream-format", G_TYPE_STRING, "avc",
11879 "alignment", G_TYPE_STRING, "au", NULL);
11881 case 0x40: /* AAC (any) */
11882 case 0x66: /* AAC Main */
11883 case 0x67: /* AAC LC */
11884 case 0x68: /* AAC SSR */
11885 /* Override channels and rate based on the codec_data, as it's often
11887 /* Only do so for basic setup without HE-AAC extension */
11888 if (data_ptr && data_len == 2) {
11889 guint channels, rateindex, rate;
11891 /* FIXME: add gst_codec_utils_aac_get_{channels|sample_rate}()? */
11892 channels = (data_ptr[1] & 0x7f) >> 3;
11893 if (channels > 0 && channels < 7) {
11894 stream->n_channels = channels;
11895 } else if (channels == 7) {
11896 stream->n_channels = 8;
11899 rateindex = ((data_ptr[0] & 0x7) << 1) | ((data_ptr[1] & 0x80) >> 7);
11900 rate = gst_codec_utils_aac_get_sample_rate_from_index (rateindex);
11902 stream->rate = rate;
11905 /* Set level and profile if possible */
11906 if (data_ptr != NULL && data_len >= 2) {
11907 gst_codec_utils_aac_caps_set_level_and_profile (stream->caps,
11908 data_ptr, data_len);
11911 case 0x60: /* MPEG-2, various profiles */
11917 codec_name = "MPEG-2 video";
11918 caps = gst_caps_new_simple ("video/mpeg",
11919 "mpegversion", G_TYPE_INT, 2,
11920 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
11922 case 0x69: /* MPEG-2 BC audio */
11923 case 0x6B: /* MPEG-1 audio */
11924 caps = gst_caps_new_simple ("audio/mpeg",
11925 "mpegversion", G_TYPE_INT, 1, "parsed", G_TYPE_BOOLEAN, TRUE, NULL);
11926 codec_name = "MPEG-1 audio";
11928 case 0x6A: /* MPEG-1 */
11929 codec_name = "MPEG-1 video";
11930 caps = gst_caps_new_simple ("video/mpeg",
11931 "mpegversion", G_TYPE_INT, 1,
11932 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
11934 case 0x6C: /* MJPEG */
11936 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
11938 codec_name = "Motion-JPEG";
11940 case 0x6D: /* PNG */
11942 gst_caps_new_simple ("image/png", "parsed", G_TYPE_BOOLEAN, TRUE,
11944 codec_name = "PNG still images";
11946 case 0x6E: /* JPEG2000 */
11947 codec_name = "JPEG-2000";
11948 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
11950 case 0xA4: /* Dirac */
11951 codec_name = "Dirac";
11952 caps = gst_caps_new_empty_simple ("video/x-dirac");
11954 case 0xA5: /* AC3 */
11955 codec_name = "AC-3 audio";
11956 caps = gst_caps_new_simple ("audio/x-ac3",
11957 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
11959 case 0xA9: /* AC3 */
11960 codec_name = "DTS audio";
11961 caps = gst_caps_new_simple ("audio/x-dts",
11962 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
11964 case 0xE1: /* QCELP */
11965 /* QCELP, the codec_data is a riff tag (little endian) with
11966 * 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). */
11967 caps = gst_caps_new_empty_simple ("audio/qcelp");
11968 codec_name = "QCELP";
11974 /* If we have a replacement caps, then change our caps for this stream */
11976 gst_caps_unref (stream->caps);
11977 stream->caps = caps;
11980 if (codec_name && list)
11981 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
11982 GST_TAG_AUDIO_CODEC, codec_name, NULL);
11984 /* Add the codec_data attribute to caps, if we have it */
11988 buffer = gst_buffer_new_and_alloc (data_len);
11989 gst_buffer_fill (buffer, 0, data_ptr, data_len);
11991 GST_DEBUG_OBJECT (qtdemux, "setting codec_data from esds");
11992 GST_MEMDUMP_OBJECT (qtdemux, "codec_data from esds", data_ptr, data_len);
11994 gst_caps_set_simple (stream->caps, "codec_data", GST_TYPE_BUFFER,
11996 gst_buffer_unref (buffer);
12001 #define _codec(name) \
12003 if (codec_name) { \
12004 *codec_name = g_strdup (name); \
12009 qtdemux_video_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
12010 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
12012 GstCaps *caps = NULL;
12013 GstVideoFormat format = GST_VIDEO_FORMAT_UNKNOWN;
12016 case GST_MAKE_FOURCC ('p', 'n', 'g', ' '):
12017 _codec ("PNG still images");
12018 caps = gst_caps_new_empty_simple ("image/png");
12020 case GST_MAKE_FOURCC ('j', 'p', 'e', 'g'):
12021 _codec ("JPEG still images");
12023 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
12026 case GST_MAKE_FOURCC ('m', 'j', 'p', 'a'):
12027 case GST_MAKE_FOURCC ('A', 'V', 'D', 'J'):
12028 case GST_MAKE_FOURCC ('M', 'J', 'P', 'G'):
12029 case GST_MAKE_FOURCC ('d', 'm', 'b', '1'):
12030 _codec ("Motion-JPEG");
12032 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
12035 case GST_MAKE_FOURCC ('m', 'j', 'p', 'b'):
12036 _codec ("Motion-JPEG format B");
12037 caps = gst_caps_new_empty_simple ("video/x-mjpeg-b");
12039 case GST_MAKE_FOURCC ('m', 'j', 'p', '2'):
12040 _codec ("JPEG-2000");
12041 /* override to what it should be according to spec, avoid palette_data */
12042 stream->bits_per_sample = 24;
12043 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
12045 case GST_MAKE_FOURCC ('S', 'V', 'Q', '3'):
12046 _codec ("Sorensen video v.3");
12047 caps = gst_caps_new_simple ("video/x-svq",
12048 "svqversion", G_TYPE_INT, 3, NULL);
12050 case GST_MAKE_FOURCC ('s', 'v', 'q', 'i'):
12051 case GST_MAKE_FOURCC ('S', 'V', 'Q', '1'):
12052 _codec ("Sorensen video v.1");
12053 caps = gst_caps_new_simple ("video/x-svq",
12054 "svqversion", G_TYPE_INT, 1, NULL);
12056 case GST_MAKE_FOURCC ('W', 'R', 'A', 'W'):
12057 caps = gst_caps_new_empty_simple ("video/x-raw");
12058 gst_caps_set_simple (caps, "format", G_TYPE_STRING, "RGB8P", NULL);
12059 _codec ("Windows Raw RGB");
12061 case GST_MAKE_FOURCC ('r', 'a', 'w', ' '):
12065 bps = QT_UINT16 (stsd_data + 98);
12068 format = GST_VIDEO_FORMAT_RGB15;
12071 format = GST_VIDEO_FORMAT_RGB16;
12074 format = GST_VIDEO_FORMAT_RGB;
12077 format = GST_VIDEO_FORMAT_ARGB;
12085 case GST_MAKE_FOURCC ('y', 'v', '1', '2'):
12086 format = GST_VIDEO_FORMAT_I420;
12088 case GST_MAKE_FOURCC ('y', 'u', 'v', '2'):
12089 case GST_MAKE_FOURCC ('Y', 'u', 'v', '2'):
12090 format = GST_VIDEO_FORMAT_I420;
12092 case GST_MAKE_FOURCC ('2', 'v', 'u', 'y'):
12093 case GST_MAKE_FOURCC ('2', 'V', 'u', 'y'):
12094 format = GST_VIDEO_FORMAT_UYVY;
12096 case GST_MAKE_FOURCC ('v', '3', '0', '8'):
12097 format = GST_VIDEO_FORMAT_v308;
12099 case GST_MAKE_FOURCC ('v', '2', '1', '6'):
12100 format = GST_VIDEO_FORMAT_v216;
12102 case GST_MAKE_FOURCC ('v', '2', '1', '0'):
12103 format = GST_VIDEO_FORMAT_v210;
12105 case GST_MAKE_FOURCC ('r', '2', '1', '0'):
12106 format = GST_VIDEO_FORMAT_r210;
12108 /* Packed YUV 4:4:4 10 bit in 32 bits, complex
12109 case GST_MAKE_FOURCC ('v', '4', '1', '0'):
12110 format = GST_VIDEO_FORMAT_v410;
12113 /* Packed YUV 4:4:4:4 8 bit in 32 bits
12114 * but different order than AYUV
12115 case GST_MAKE_FOURCC ('v', '4', '0', '8'):
12116 format = GST_VIDEO_FORMAT_v408;
12119 case GST_MAKE_FOURCC ('m', 'p', 'e', 'g'):
12120 case GST_MAKE_FOURCC ('m', 'p', 'g', '1'):
12121 _codec ("MPEG-1 video");
12122 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
12123 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
12125 case GST_MAKE_FOURCC ('h', 'd', 'v', '1'): /* HDV 720p30 */
12126 case GST_MAKE_FOURCC ('h', 'd', 'v', '2'): /* HDV 1080i60 */
12127 case GST_MAKE_FOURCC ('h', 'd', 'v', '3'): /* HDV 1080i50 */
12128 case GST_MAKE_FOURCC ('h', 'd', 'v', '4'): /* HDV 720p24 */
12129 case GST_MAKE_FOURCC ('h', 'd', 'v', '5'): /* HDV 720p25 */
12130 case GST_MAKE_FOURCC ('h', 'd', 'v', '6'): /* HDV 1080p24 */
12131 case GST_MAKE_FOURCC ('h', 'd', 'v', '7'): /* HDV 1080p25 */
12132 case GST_MAKE_FOURCC ('h', 'd', 'v', '8'): /* HDV 1080p30 */
12133 case GST_MAKE_FOURCC ('h', 'd', 'v', '9'): /* HDV 720p60 */
12134 case GST_MAKE_FOURCC ('h', 'd', 'v', 'a'): /* HDV 720p50 */
12135 case GST_MAKE_FOURCC ('m', 'x', '5', 'n'): /* MPEG2 IMX NTSC 525/60 50mb/s produced by FCP */
12136 case GST_MAKE_FOURCC ('m', 'x', '5', 'p'): /* MPEG2 IMX PAL 625/60 50mb/s produced by FCP */
12137 case GST_MAKE_FOURCC ('m', 'x', '4', 'n'): /* MPEG2 IMX NTSC 525/60 40mb/s produced by FCP */
12138 case GST_MAKE_FOURCC ('m', 'x', '4', 'p'): /* MPEG2 IMX PAL 625/60 40mb/s produced by FCP */
12139 case GST_MAKE_FOURCC ('m', 'x', '3', 'n'): /* MPEG2 IMX NTSC 525/60 30mb/s produced by FCP */
12140 case GST_MAKE_FOURCC ('m', 'x', '3', 'p'): /* MPEG2 IMX PAL 625/50 30mb/s produced by FCP */
12141 case GST_MAKE_FOURCC ('x', 'd', 'v', '1'): /* XDCAM HD 720p30 35Mb/s */
12142 case GST_MAKE_FOURCC ('x', 'd', 'v', '2'): /* XDCAM HD 1080i60 35Mb/s */
12143 case GST_MAKE_FOURCC ('x', 'd', 'v', '3'): /* XDCAM HD 1080i50 35Mb/s */
12144 case GST_MAKE_FOURCC ('x', 'd', 'v', '4'): /* XDCAM HD 720p24 35Mb/s */
12145 case GST_MAKE_FOURCC ('x', 'd', 'v', '5'): /* XDCAM HD 720p25 35Mb/s */
12146 case GST_MAKE_FOURCC ('x', 'd', 'v', '6'): /* XDCAM HD 1080p24 35Mb/s */
12147 case GST_MAKE_FOURCC ('x', 'd', 'v', '7'): /* XDCAM HD 1080p25 35Mb/s */
12148 case GST_MAKE_FOURCC ('x', 'd', 'v', '8'): /* XDCAM HD 1080p30 35Mb/s */
12149 case GST_MAKE_FOURCC ('x', 'd', 'v', '9'): /* XDCAM HD 720p60 35Mb/s */
12150 case GST_MAKE_FOURCC ('x', 'd', 'v', 'a'): /* XDCAM HD 720p50 35Mb/s */
12151 case GST_MAKE_FOURCC ('x', 'd', 'v', 'b'): /* XDCAM EX 1080i60 50Mb/s CBR */
12152 case GST_MAKE_FOURCC ('x', 'd', 'v', 'c'): /* XDCAM EX 1080i50 50Mb/s CBR */
12153 case GST_MAKE_FOURCC ('x', 'd', 'v', 'd'): /* XDCAM HD 1080p24 50Mb/s CBR */
12154 case GST_MAKE_FOURCC ('x', 'd', 'v', 'e'): /* XDCAM HD 1080p25 50Mb/s CBR */
12155 case GST_MAKE_FOURCC ('x', 'd', 'v', 'f'): /* XDCAM HD 1080p30 50Mb/s CBR */
12156 case GST_MAKE_FOURCC ('x', 'd', '5', '1'): /* XDCAM HD422 720p30 50Mb/s CBR */
12157 case GST_MAKE_FOURCC ('x', 'd', '5', '4'): /* XDCAM HD422 720p24 50Mb/s CBR */
12158 case GST_MAKE_FOURCC ('x', 'd', '5', '5'): /* XDCAM HD422 720p25 50Mb/s CBR */
12159 case GST_MAKE_FOURCC ('x', 'd', '5', '9'): /* XDCAM HD422 720p60 50Mb/s CBR */
12160 case GST_MAKE_FOURCC ('x', 'd', '5', 'a'): /* XDCAM HD422 720p50 50Mb/s CBR */
12161 case GST_MAKE_FOURCC ('x', 'd', '5', 'b'): /* XDCAM HD422 1080i50 50Mb/s CBR */
12162 case GST_MAKE_FOURCC ('x', 'd', '5', 'c'): /* XDCAM HD422 1080i50 50Mb/s CBR */
12163 case GST_MAKE_FOURCC ('x', 'd', '5', 'd'): /* XDCAM HD422 1080p24 50Mb/s CBR */
12164 case GST_MAKE_FOURCC ('x', 'd', '5', 'e'): /* XDCAM HD422 1080p25 50Mb/s CBR */
12165 case GST_MAKE_FOURCC ('x', 'd', '5', 'f'): /* XDCAM HD422 1080p30 50Mb/s CBR */
12166 case GST_MAKE_FOURCC ('x', 'd', 'h', 'd'): /* XDCAM HD 540p */
12167 case GST_MAKE_FOURCC ('x', 'd', 'h', '2'): /* XDCAM HD422 540p */
12168 case GST_MAKE_FOURCC ('A', 'V', 'm', 'p'): /* AVID IMX PAL */
12169 case GST_MAKE_FOURCC ('m', 'p', 'g', '2'): /* AVID IMX PAL */
12170 case GST_MAKE_FOURCC ('m', 'p', '2', 'v'): /* AVID IMX PAL */
12171 _codec ("MPEG-2 video");
12172 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 2,
12173 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
12175 case GST_MAKE_FOURCC ('g', 'i', 'f', ' '):
12176 _codec ("GIF still images");
12177 caps = gst_caps_new_empty_simple ("image/gif");
12179 case GST_MAKE_FOURCC ('h', '2', '6', '3'):
12180 case GST_MAKE_FOURCC ('H', '2', '6', '3'):
12181 case GST_MAKE_FOURCC ('s', '2', '6', '3'):
12182 case GST_MAKE_FOURCC ('U', '2', '6', '3'):
12184 /* ffmpeg uses the height/width props, don't know why */
12185 caps = gst_caps_new_simple ("video/x-h263",
12186 "variant", G_TYPE_STRING, "itu", NULL);
12188 case GST_MAKE_FOURCC ('m', 'p', '4', 'v'):
12189 case GST_MAKE_FOURCC ('M', 'P', '4', 'V'):
12190 _codec ("MPEG-4 video");
12191 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
12192 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
12194 case GST_MAKE_FOURCC ('3', 'i', 'v', 'd'):
12195 case GST_MAKE_FOURCC ('3', 'I', 'V', 'D'):
12196 _codec ("Microsoft MPEG-4 4.3"); /* FIXME? */
12197 caps = gst_caps_new_simple ("video/x-msmpeg",
12198 "msmpegversion", G_TYPE_INT, 43, NULL);
12200 case GST_MAKE_FOURCC ('D', 'I', 'V', '3'):
12202 caps = gst_caps_new_simple ("video/x-divx",
12203 "divxversion", G_TYPE_INT, 3, NULL);
12205 case GST_MAKE_FOURCC ('D', 'I', 'V', 'X'):
12206 case GST_MAKE_FOURCC ('d', 'i', 'v', 'x'):
12208 caps = gst_caps_new_simple ("video/x-divx",
12209 "divxversion", G_TYPE_INT, 4, NULL);
12211 case GST_MAKE_FOURCC ('D', 'X', '5', '0'):
12213 caps = gst_caps_new_simple ("video/x-divx",
12214 "divxversion", G_TYPE_INT, 5, NULL);
12217 case GST_MAKE_FOURCC ('3', 'I', 'V', '1'):
12218 case GST_MAKE_FOURCC ('3', 'I', 'V', '2'):
12219 case GST_MAKE_FOURCC ('X', 'V', 'I', 'D'):
12220 case GST_MAKE_FOURCC ('x', 'v', 'i', 'd'):
12221 case GST_MAKE_FOURCC ('F', 'M', 'P', '4'):
12222 case GST_MAKE_FOURCC ('U', 'M', 'P', '4'):
12223 caps = gst_caps_new_simple ("video/mpeg",
12224 "mpegversion", G_TYPE_INT, 4, NULL);
12226 *codec_name = g_strdup ("MPEG-4");
12229 case GST_MAKE_FOURCC ('c', 'v', 'i', 'd'):
12230 _codec ("Cinepak");
12231 caps = gst_caps_new_empty_simple ("video/x-cinepak");
12233 case GST_MAKE_FOURCC ('q', 'd', 'r', 'w'):
12234 _codec ("Apple QuickDraw");
12235 caps = gst_caps_new_empty_simple ("video/x-qdrw");
12237 case GST_MAKE_FOURCC ('r', 'p', 'z', 'a'):
12238 _codec ("Apple video");
12239 caps = gst_caps_new_empty_simple ("video/x-apple-video");
12241 case GST_MAKE_FOURCC ('H', '2', '6', '4'):
12242 case GST_MAKE_FOURCC ('a', 'v', 'c', '1'):
12243 _codec ("H.264 / AVC");
12244 caps = gst_caps_new_simple ("video/x-h264",
12245 "stream-format", G_TYPE_STRING, "avc",
12246 "alignment", G_TYPE_STRING, "au", NULL);
12248 case GST_MAKE_FOURCC ('a', 'v', 'c', '3'):
12249 _codec ("H.264 / AVC");
12250 caps = gst_caps_new_simple ("video/x-h264",
12251 "stream-format", G_TYPE_STRING, "avc3",
12252 "alignment", G_TYPE_STRING, "au", NULL);
12254 case GST_MAKE_FOURCC ('H', '2', '6', '5'):
12255 case GST_MAKE_FOURCC ('h', 'v', 'c', '1'):
12256 _codec ("H.265 / HEVC");
12257 caps = gst_caps_new_simple ("video/x-h265",
12258 "stream-format", G_TYPE_STRING, "hvc1",
12259 "alignment", G_TYPE_STRING, "au", NULL);
12261 case GST_MAKE_FOURCC ('h', 'e', 'v', '1'):
12262 _codec ("H.265 / HEVC");
12263 caps = gst_caps_new_simple ("video/x-h265",
12264 "stream-format", G_TYPE_STRING, "hev1",
12265 "alignment", G_TYPE_STRING, "au", NULL);
12267 case GST_MAKE_FOURCC ('r', 'l', 'e', ' '):
12268 _codec ("Run-length encoding");
12269 caps = gst_caps_new_simple ("video/x-rle",
12270 "layout", G_TYPE_STRING, "quicktime", NULL);
12272 case GST_MAKE_FOURCC ('W', 'R', 'L', 'E'):
12273 _codec ("Run-length encoding");
12274 caps = gst_caps_new_simple ("video/x-rle",
12275 "layout", G_TYPE_STRING, "microsoft", NULL);
12277 case GST_MAKE_FOURCC ('I', 'V', '3', '2'):
12278 case GST_MAKE_FOURCC ('i', 'v', '3', '2'):
12279 _codec ("Indeo Video 3");
12280 caps = gst_caps_new_simple ("video/x-indeo",
12281 "indeoversion", G_TYPE_INT, 3, NULL);
12283 case GST_MAKE_FOURCC ('I', 'V', '4', '1'):
12284 case GST_MAKE_FOURCC ('i', 'v', '4', '1'):
12285 _codec ("Intel Video 4");
12286 caps = gst_caps_new_simple ("video/x-indeo",
12287 "indeoversion", G_TYPE_INT, 4, NULL);
12289 case GST_MAKE_FOURCC ('d', 'v', 'c', 'p'):
12290 case GST_MAKE_FOURCC ('d', 'v', 'c', ' '):
12291 case GST_MAKE_FOURCC ('d', 'v', 's', 'd'):
12292 case GST_MAKE_FOURCC ('D', 'V', 'S', 'D'):
12293 case GST_MAKE_FOURCC ('d', 'v', 'c', 's'):
12294 case GST_MAKE_FOURCC ('D', 'V', 'C', 'S'):
12295 case GST_MAKE_FOURCC ('d', 'v', '2', '5'):
12296 case GST_MAKE_FOURCC ('d', 'v', 'p', 'p'):
12297 _codec ("DV Video");
12298 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 25,
12299 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
12301 case GST_MAKE_FOURCC ('d', 'v', '5', 'n'): /* DVCPRO50 NTSC */
12302 case GST_MAKE_FOURCC ('d', 'v', '5', 'p'): /* DVCPRO50 PAL */
12303 _codec ("DVCPro50 Video");
12304 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 50,
12305 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
12307 case GST_MAKE_FOURCC ('d', 'v', 'h', '5'): /* DVCPRO HD 50i produced by FCP */
12308 case GST_MAKE_FOURCC ('d', 'v', 'h', '6'): /* DVCPRO HD 60i produced by FCP */
12309 _codec ("DVCProHD Video");
12310 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 100,
12311 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
12313 case GST_MAKE_FOURCC ('s', 'm', 'c', ' '):
12314 _codec ("Apple Graphics (SMC)");
12315 caps = gst_caps_new_empty_simple ("video/x-smc");
12317 case GST_MAKE_FOURCC ('V', 'P', '3', '1'):
12319 caps = gst_caps_new_empty_simple ("video/x-vp3");
12321 case GST_MAKE_FOURCC ('V', 'P', '6', 'F'):
12322 _codec ("VP6 Flash");
12323 caps = gst_caps_new_empty_simple ("video/x-vp6-flash");
12325 case GST_MAKE_FOURCC ('X', 'i', 'T', 'h'):
12327 caps = gst_caps_new_empty_simple ("video/x-theora");
12328 /* theora uses one byte of padding in the data stream because it does not
12329 * allow 0 sized packets while theora does */
12330 stream->padding = 1;
12332 case GST_MAKE_FOURCC ('d', 'r', 'a', 'c'):
12334 caps = gst_caps_new_empty_simple ("video/x-dirac");
12336 case GST_MAKE_FOURCC ('t', 'i', 'f', 'f'):
12337 _codec ("TIFF still images");
12338 caps = gst_caps_new_empty_simple ("image/tiff");
12340 case GST_MAKE_FOURCC ('i', 'c', 'o', 'd'):
12341 _codec ("Apple Intermediate Codec");
12342 caps = gst_caps_from_string ("video/x-apple-intermediate-codec");
12344 case GST_MAKE_FOURCC ('A', 'V', 'd', 'n'):
12345 _codec ("AVID DNxHD");
12346 caps = gst_caps_from_string ("video/x-dnxhd");
12348 case GST_MAKE_FOURCC ('V', 'P', '8', '0'):
12349 _codec ("On2 VP8");
12350 caps = gst_caps_from_string ("video/x-vp8");
12352 case GST_MAKE_FOURCC ('a', 'p', 'c', 's'):
12353 _codec ("Apple ProRes LT");
12355 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "lt",
12358 case GST_MAKE_FOURCC ('a', 'p', 'c', 'h'):
12359 _codec ("Apple ProRes HQ");
12361 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "hq",
12364 case GST_MAKE_FOURCC ('a', 'p', 'c', 'n'):
12365 _codec ("Apple ProRes");
12367 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
12370 case GST_MAKE_FOURCC ('a', 'p', 'c', 'o'):
12371 _codec ("Apple ProRes Proxy");
12373 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
12376 case GST_MAKE_FOURCC ('a', 'p', '4', 'h'):
12377 _codec ("Apple ProRes 4444");
12379 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
12382 case GST_MAKE_FOURCC ('v', 'c', '-', '1'):
12385 caps = gst_caps_new_simple ("video/x-wmv",
12386 "wmvversion", G_TYPE_INT, 3, "format", G_TYPE_STRING, "WVC1", NULL);
12388 case GST_MAKE_FOURCC ('k', 'p', 'c', 'd'):
12391 char *s, fourstr[5];
12393 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
12394 s = g_strdup_printf ("video/x-gst-fourcc-%s", g_strstrip (fourstr));
12395 caps = gst_caps_new_empty_simple (s);
12400 if (format != GST_VIDEO_FORMAT_UNKNOWN) {
12403 gst_video_info_init (&info);
12404 gst_video_info_set_format (&info, format, stream->width, stream->height);
12406 caps = gst_video_info_to_caps (&info);
12407 *codec_name = gst_pb_utils_get_codec_description (caps);
12409 /* enable clipping for raw video streams */
12410 stream->need_clip = TRUE;
12417 qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
12418 guint32 fourcc, const guint8 * data, int len, gchar ** codec_name)
12421 const GstStructure *s;
12424 GstAudioFormat format = 0;
12427 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
12429 depth = stream->bytes_per_packet * 8;
12432 case GST_MAKE_FOURCC ('N', 'O', 'N', 'E'):
12433 case GST_MAKE_FOURCC ('r', 'a', 'w', ' '):
12434 /* 8-bit audio is unsigned */
12436 format = GST_AUDIO_FORMAT_U8;
12437 /* otherwise it's signed and big-endian just like 'twos' */
12438 case GST_MAKE_FOURCC ('t', 'w', 'o', 's'):
12439 endian = G_BIG_ENDIAN;
12441 case GST_MAKE_FOURCC ('s', 'o', 'w', 't'):
12446 endian = G_LITTLE_ENDIAN;
12449 format = gst_audio_format_build_integer (TRUE, endian, depth, depth);
12451 str = g_strdup_printf ("Raw %d-bit PCM audio", depth);
12455 caps = gst_caps_new_simple ("audio/x-raw",
12456 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
12457 "layout", G_TYPE_STRING, "interleaved", NULL);
12460 case GST_MAKE_FOURCC ('f', 'l', '6', '4'):
12461 _codec ("Raw 64-bit floating-point audio");
12462 caps = gst_caps_new_simple ("audio/x-raw",
12463 "format", G_TYPE_STRING, "F64BE",
12464 "layout", G_TYPE_STRING, "interleaved", NULL);
12466 case GST_MAKE_FOURCC ('f', 'l', '3', '2'):
12467 _codec ("Raw 32-bit floating-point audio");
12468 caps = gst_caps_new_simple ("audio/x-raw",
12469 "format", G_TYPE_STRING, "F32BE",
12470 "layout", G_TYPE_STRING, "interleaved", NULL);
12473 _codec ("Raw 24-bit PCM audio");
12474 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
12476 caps = gst_caps_new_simple ("audio/x-raw",
12477 "format", G_TYPE_STRING, "S24BE",
12478 "layout", G_TYPE_STRING, "interleaved", NULL);
12480 case GST_MAKE_FOURCC ('i', 'n', '3', '2'):
12481 _codec ("Raw 32-bit PCM audio");
12482 caps = gst_caps_new_simple ("audio/x-raw",
12483 "format", G_TYPE_STRING, "S32BE",
12484 "layout", G_TYPE_STRING, "interleaved", NULL);
12486 case GST_MAKE_FOURCC ('u', 'l', 'a', 'w'):
12487 _codec ("Mu-law audio");
12488 caps = gst_caps_new_empty_simple ("audio/x-mulaw");
12490 case GST_MAKE_FOURCC ('a', 'l', 'a', 'w'):
12491 _codec ("A-law audio");
12492 caps = gst_caps_new_empty_simple ("audio/x-alaw");
12496 _codec ("Microsoft ADPCM");
12497 /* Microsoft ADPCM-ACM code 2 */
12498 caps = gst_caps_new_simple ("audio/x-adpcm",
12499 "layout", G_TYPE_STRING, "microsoft", NULL);
12503 _codec ("DVI/IMA ADPCM");
12504 caps = gst_caps_new_simple ("audio/x-adpcm",
12505 "layout", G_TYPE_STRING, "dvi", NULL);
12509 _codec ("DVI/Intel IMA ADPCM");
12510 /* FIXME DVI/Intel IMA ADPCM/ACM code 17 */
12511 caps = gst_caps_new_simple ("audio/x-adpcm",
12512 "layout", G_TYPE_STRING, "quicktime", NULL);
12516 /* MPEG layer 3, CBR only (pre QT4.1) */
12517 case GST_MAKE_FOURCC ('.', 'm', 'p', '3'):
12518 _codec ("MPEG-1 layer 3");
12519 /* MPEG layer 3, CBR & VBR (QT4.1 and later) */
12520 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 3,
12521 "mpegversion", G_TYPE_INT, 1, NULL);
12524 case GST_MAKE_FOURCC ('e', 'c', '-', '3'):
12525 _codec ("EAC-3 audio");
12526 caps = gst_caps_new_simple ("audio/x-eac3",
12527 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
12528 stream->sampled = TRUE;
12530 case GST_MAKE_FOURCC ('s', 'a', 'c', '3'): // Nero Recode
12531 case GST_MAKE_FOURCC ('a', 'c', '-', '3'):
12532 _codec ("AC-3 audio");
12533 caps = gst_caps_new_simple ("audio/x-ac3",
12534 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
12535 stream->sampled = TRUE;
12537 case GST_MAKE_FOURCC ('d', 't', 's', 'c'):
12538 case GST_MAKE_FOURCC ('D', 'T', 'S', ' '):
12539 _codec ("DTS audio");
12540 caps = gst_caps_new_simple ("audio/x-dts",
12541 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
12542 stream->sampled = TRUE;
12544 case GST_MAKE_FOURCC ('d', 't', 's', 'h'): // DTS-HD
12545 case GST_MAKE_FOURCC ('d', 't', 's', 'l'): // DTS-HD Lossless
12546 _codec ("DTS-HD audio");
12547 caps = gst_caps_new_simple ("audio/x-dts",
12548 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
12549 stream->sampled = TRUE;
12551 case GST_MAKE_FOURCC ('M', 'A', 'C', '3'):
12553 caps = gst_caps_new_simple ("audio/x-mace",
12554 "maceversion", G_TYPE_INT, 3, NULL);
12556 case GST_MAKE_FOURCC ('M', 'A', 'C', '6'):
12558 caps = gst_caps_new_simple ("audio/x-mace",
12559 "maceversion", G_TYPE_INT, 6, NULL);
12561 case GST_MAKE_FOURCC ('O', 'g', 'g', 'V'):
12563 caps = gst_caps_new_empty_simple ("application/ogg");
12565 case GST_MAKE_FOURCC ('d', 'v', 'c', 'a'):
12566 _codec ("DV audio");
12567 caps = gst_caps_new_empty_simple ("audio/x-dv");
12569 case GST_MAKE_FOURCC ('m', 'p', '4', 'a'):
12570 _codec ("MPEG-4 AAC audio");
12571 caps = gst_caps_new_simple ("audio/mpeg",
12572 "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE,
12573 "stream-format", G_TYPE_STRING, "raw", NULL);
12575 case GST_MAKE_FOURCC ('Q', 'D', 'M', 'C'):
12576 _codec ("QDesign Music");
12577 caps = gst_caps_new_empty_simple ("audio/x-qdm");
12579 case GST_MAKE_FOURCC ('Q', 'D', 'M', '2'):
12580 _codec ("QDesign Music v.2");
12581 /* FIXME: QDesign music version 2 (no constant) */
12582 if (FALSE && data) {
12583 caps = gst_caps_new_simple ("audio/x-qdm2",
12584 "framesize", G_TYPE_INT, QT_UINT32 (data + 52),
12585 "bitrate", G_TYPE_INT, QT_UINT32 (data + 40),
12586 "blocksize", G_TYPE_INT, QT_UINT32 (data + 44), NULL);
12588 caps = gst_caps_new_empty_simple ("audio/x-qdm2");
12591 case GST_MAKE_FOURCC ('a', 'g', 's', 'm'):
12592 _codec ("GSM audio");
12593 caps = gst_caps_new_empty_simple ("audio/x-gsm");
12595 case GST_MAKE_FOURCC ('s', 'a', 'm', 'r'):
12596 _codec ("AMR audio");
12597 caps = gst_caps_new_empty_simple ("audio/AMR");
12599 case GST_MAKE_FOURCC ('s', 'a', 'w', 'b'):
12600 _codec ("AMR-WB audio");
12601 caps = gst_caps_new_empty_simple ("audio/AMR-WB");
12603 case GST_MAKE_FOURCC ('i', 'm', 'a', '4'):
12604 _codec ("Quicktime IMA ADPCM");
12605 caps = gst_caps_new_simple ("audio/x-adpcm",
12606 "layout", G_TYPE_STRING, "quicktime", NULL);
12608 case GST_MAKE_FOURCC ('a', 'l', 'a', 'c'):
12609 _codec ("Apple lossless audio");
12610 caps = gst_caps_new_empty_simple ("audio/x-alac");
12612 case GST_MAKE_FOURCC ('Q', 'c', 'l', 'p'):
12613 _codec ("QualComm PureVoice");
12614 caps = gst_caps_from_string ("audio/qcelp");
12616 case GST_MAKE_FOURCC ('w', 'm', 'a', ' '):
12619 caps = gst_caps_new_empty_simple ("audio/x-wma");
12621 case GST_MAKE_FOURCC ('l', 'p', 'c', 'm'):
12626 GstAudioFormat format;
12629 FLAG_IS_FLOAT = 0x1,
12630 FLAG_IS_BIG_ENDIAN = 0x2,
12631 FLAG_IS_SIGNED = 0x4,
12632 FLAG_IS_PACKED = 0x8,
12633 FLAG_IS_ALIGNED_HIGH = 0x10,
12634 FLAG_IS_NON_INTERLEAVED = 0x20
12636 _codec ("Raw LPCM audio");
12638 if (data && len >= 56) {
12639 depth = QT_UINT32 (data + 40);
12640 flags = QT_UINT32 (data + 44);
12641 width = QT_UINT32 (data + 48) * 8 / stream->n_channels;
12643 if ((flags & FLAG_IS_FLOAT) == 0) {
12648 format = gst_audio_format_build_integer ((flags & FLAG_IS_SIGNED) ?
12649 TRUE : FALSE, (flags & FLAG_IS_BIG_ENDIAN) ?
12650 G_BIG_ENDIAN : G_LITTLE_ENDIAN, width, depth);
12651 caps = gst_caps_new_simple ("audio/x-raw",
12652 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
12653 "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
12654 "non-interleaved" : "interleaved", NULL);
12659 if (flags & FLAG_IS_BIG_ENDIAN)
12660 format = GST_AUDIO_FORMAT_F64BE;
12662 format = GST_AUDIO_FORMAT_F64LE;
12664 if (flags & FLAG_IS_BIG_ENDIAN)
12665 format = GST_AUDIO_FORMAT_F32BE;
12667 format = GST_AUDIO_FORMAT_F32LE;
12669 caps = gst_caps_new_simple ("audio/x-raw",
12670 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
12671 "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
12672 "non-interleaved" : "interleaved", NULL);
12676 case GST_MAKE_FOURCC ('q', 't', 'v', 'r'):
12680 char *s, fourstr[5];
12682 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
12683 s = g_strdup_printf ("audio/x-gst-fourcc-%s", g_strstrip (fourstr));
12684 caps = gst_caps_new_empty_simple (s);
12690 GstCaps *templ_caps =
12691 gst_static_pad_template_get_caps (&gst_qtdemux_audiosrc_template);
12692 GstCaps *intersection = gst_caps_intersect (caps, templ_caps);
12693 gst_caps_unref (caps);
12694 gst_caps_unref (templ_caps);
12695 caps = intersection;
12698 /* enable clipping for raw audio streams */
12699 s = gst_caps_get_structure (caps, 0);
12700 name = gst_structure_get_name (s);
12701 if (g_str_has_prefix (name, "audio/x-raw")) {
12702 stream->need_clip = TRUE;
12703 stream->max_buffer_size = 4096 * stream->bytes_per_frame;
12704 GST_DEBUG ("setting max buffer size to %d", stream->max_buffer_size);
12710 qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
12711 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
12715 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
12718 case GST_MAKE_FOURCC ('m', 'p', '4', 's'):
12719 _codec ("DVD subtitle");
12720 caps = gst_caps_new_empty_simple ("subpicture/x-dvd");
12721 stream->need_process = TRUE;
12723 case GST_MAKE_FOURCC ('t', 'e', 'x', 't'):
12724 _codec ("Quicktime timed text");
12726 case GST_MAKE_FOURCC ('t', 'x', '3', 'g'):
12727 _codec ("3GPP timed text");
12729 caps = gst_caps_new_simple ("text/x-raw", "format", G_TYPE_STRING,
12731 /* actual text piece needs to be extracted */
12732 stream->need_process = TRUE;
12736 char *s, fourstr[5];
12738 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
12739 s = g_strdup_printf ("text/x-gst-fourcc-%s", g_strstrip (fourstr));
12740 caps = gst_caps_new_empty_simple (s);
12748 qtdemux_generic_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
12749 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
12754 case GST_MAKE_FOURCC ('m', '1', 'v', ' '):
12755 _codec ("MPEG 1 video");
12756 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
12757 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
12767 gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux,
12768 const gchar * system_id)
12772 if (!qtdemux->protection_system_ids)
12773 qtdemux->protection_system_ids =
12774 g_ptr_array_new_with_free_func ((GDestroyNotify) g_free);
12775 /* Check whether we already have an entry for this system ID. */
12776 for (i = 0; i < qtdemux->protection_system_ids->len; ++i) {
12777 const gchar *id = g_ptr_array_index (qtdemux->protection_system_ids, i);
12778 if (g_ascii_strcasecmp (system_id, id) == 0) {
12782 GST_DEBUG_OBJECT (qtdemux, "Adding cenc protection system ID %s", system_id);
12783 g_ptr_array_add (qtdemux->protection_system_ids, g_ascii_strdown (system_id,