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
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Library General Public
14 * License as published by the Free Software Foundation; either
15 * version 2 of the License, or (at your option) any later version.
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Library General Public License for more details.
22 * You should have received a copy of the GNU Library General Public
23 * License along with this library; if not, write to the
24 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
25 * Boston, MA 02110-1301, USA.
29 * SECTION:element-qtdemux
31 * Demuxes a .mov file into raw or compressed audio and/or video streams.
33 * This element supports both push and pull-based scheduling, depending on the
34 * capabilities of the upstream elements.
37 * <title>Example launch line</title>
39 * gst-launch-1.0 filesrc location=test.mov ! qtdemux name=demux demux.audio_0 ! decodebin ! audioconvert ! audioresample ! autoaudiosink demux.video_0 ! queue ! decodebin ! videoconvert ! videoscale ! autovideosink
40 * ]| Play (parse and decode) a .mov file and try to output it to
41 * an automatically detected soundcard and videosink. If the MOV file contains
42 * compressed audio or video data, this will only work if you have the
43 * right decoder elements/plugins installed.
51 #include "gst/gst-i18n-plugin.h"
53 #include <glib/gprintf.h>
54 #include <gst/tag/tag.h>
55 #include <gst/audio/audio.h>
56 #include <gst/video/video.h>
58 #include "qtatomparser.h"
59 #include "qtdemux_types.h"
60 #include "qtdemux_dump.h"
62 #include "descriptors.h"
63 #include "qtdemux_lang.h"
65 #include "qtpalette.h"
67 #include "gst/riff/riff-media.h"
68 #include "gst/riff/riff-read.h"
70 #include <gst/pbutils/pbutils.h>
77 #include <gst/math-compat.h>
83 /* max. size considered 'sane' for non-mdat atoms */
84 #define QTDEMUX_MAX_ATOM_SIZE (25*1024*1024)
86 /* if the sample index is larger than this, something is likely wrong */
87 #define QTDEMUX_MAX_SAMPLE_INDEX_SIZE (50*1024*1024)
89 /* For converting qt creation times to unix epoch times */
90 #define QTDEMUX_SECONDS_PER_DAY (60 * 60 * 24)
91 #define QTDEMUX_LEAP_YEARS_FROM_1904_TO_1970 17
92 #define QTDEMUX_SECONDS_FROM_1904_TO_1970 (((1970 - 1904) * (guint64) 365 + \
93 QTDEMUX_LEAP_YEARS_FROM_1904_TO_1970) * QTDEMUX_SECONDS_PER_DAY)
95 #define STREAM_IS_EOS(s) (s->time_position == GST_CLOCK_TIME_NONE)
97 GST_DEBUG_CATEGORY (qtdemux_debug);
99 /*typedef struct _QtNode QtNode; */
100 typedef struct _QtDemuxSegment QtDemuxSegment;
101 typedef struct _QtDemuxSample QtDemuxSample;
110 struct _QtDemuxSample
113 gint32 pts_offset; /* Add this value to timestamp to get the pts */
115 guint64 timestamp; /* DTS In mov time */
116 guint32 duration; /* In mov time */
117 gboolean keyframe; /* TRUE when this packet is a keyframe */
120 /* Macros for converting to/from timescale */
121 #define QTSTREAMTIME_TO_GSTTIME(stream, value) (gst_util_uint64_scale((value), GST_SECOND, (stream)->timescale))
122 #define GSTTIME_TO_QTSTREAMTIME(stream, value) (gst_util_uint64_scale((value), (stream)->timescale, GST_SECOND))
124 #define QTTIME_TO_GSTTIME(qtdemux, value) (gst_util_uint64_scale((value), GST_SECOND, (qtdemux)->timescale))
125 #define GSTTIME_TO_QTTIME(qtdemux, value) (gst_util_uint64_scale((value), (qtdemux)->timescale, GST_SECOND))
127 /* timestamp is the DTS */
128 #define QTSAMPLE_DTS(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp))
129 /* timestamp + offset is the PTS */
130 #define QTSAMPLE_PTS(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp + (sample)->pts_offset))
131 /* timestamp + duration - dts is the duration */
132 #define QTSAMPLE_DUR_DTS(stream, sample, dts) (QTSTREAMTIME_TO_GSTTIME ((stream), (sample)->timestamp + (sample)->duration) - (dts))
134 #define QTSAMPLE_KEYFRAME(stream,sample) ((stream)->all_keyframe || (sample)->keyframe)
137 * Quicktime has tracks and segments. A track is a continuous piece of
138 * multimedia content. The track is not always played from start to finish but
139 * instead, pieces of the track are 'cut out' and played in sequence. This is
140 * what the segments do.
142 * Inside the track we have keyframes (K) and delta frames. The track has its
143 * own timing, which starts from 0 and extends to end. The position in the track
144 * is called the media_time.
146 * The segments now describe the pieces that should be played from this track
147 * and are basically tuples of media_time/duration/rate entries. We can have
148 * multiple segments and they are all played after one another. An example:
150 * segment 1: media_time: 1 second, duration: 1 second, rate 1
151 * segment 2: media_time: 3 second, duration: 2 second, rate 2
153 * To correctly play back this track, one must play: 1 second of media starting
154 * from media_time 1 followed by 2 seconds of media starting from media_time 3
157 * Each of the segments will be played at a specific time, the first segment at
158 * time 0, the second one after the duration of the first one, etc.. Note that
159 * the time in resulting playback is not identical to the media_time of the
162 * Visually, assuming the track has 4 second of media_time:
165 * .-----------------------------------------------------------.
166 * track: | K.....K.........K........K.......K.......K...........K... |
167 * '-----------------------------------------------------------'
169 * .------------^ ^ .----------^ ^
170 * / .-------------' / .------------------'
172 * .--------------. .--------------.
173 * | segment 1 | | segment 2 |
174 * '--------------' '--------------'
176 * The challenge here is to cut out the right pieces of the track for each of
177 * the playback segments. This fortunately can easily be done with the SEGMENT
178 * events of GStreamer.
180 * For playback of segment 1, we need to provide the decoder with the keyframe
181 * (a), in the above figure, but we must instruct it only to output the decoded
182 * data between second 1 and 2. We do this with a SEGMENT event for 1 to 2, time
183 * position set to the time of the segment: 0.
185 * We then proceed to push data from keyframe (a) to frame (b). The decoder
186 * decodes but clips all before media_time 1.
188 * After finishing a segment, we push out a new SEGMENT event with the clipping
189 * boundaries of the new data.
191 * This is a good usecase for the GStreamer accumulated SEGMENT events.
194 struct _QtDemuxSegment
196 /* global time and duration, all gst time */
198 GstClockTime stop_time;
199 GstClockTime duration;
200 /* media time of trak, all gst time */
201 GstClockTime media_start;
202 GstClockTime media_stop;
204 /* Media start time in trak timescale units */
205 guint32 trak_media_start;
208 #define QTSEGMENT_IS_EMPTY(s) ((s)->media_start == GST_CLOCK_TIME_NONE)
210 /* Used with fragmented MP4 files (mfra atom) */
215 } QtDemuxRandomAccessEntry;
217 struct _QtDemuxStream
228 gboolean new_stream; /* signals that a stream_start is required */
229 gboolean on_keyframe; /* if this stream last pushed buffer was a
230 * keyframe. This is important to identify
231 * where to stop pushing buffers after a
232 * segment stop time */
234 /* if the stream has a redirect URI in its headers, we store it here */
241 guint64 duration; /* in timescale */
245 gchar lang_id[4]; /* ISO 639-2T language code */
249 QtDemuxSample *samples;
250 gboolean all_keyframe; /* TRUE when all samples are keyframes (no stss) */
251 guint32 first_duration; /* duration in timescale of first sample, used for figuring out
252 the framerate, in timescale units */
253 guint32 offset_in_sample;
254 guint32 max_buffer_size;
256 /* if we use chunks or samples */
268 /* Numerator/denominator framerate */
271 guint16 bits_per_sample;
272 guint16 color_table_id;
273 GstMemory *rgb8_palette;
278 guint samples_per_packet;
279 guint samples_per_frame;
280 guint bytes_per_packet;
281 guint bytes_per_sample;
282 guint bytes_per_frame;
286 gboolean use_allocator;
287 GstAllocator *allocator;
288 GstAllocationParams params;
290 /* when a discontinuity is pending */
293 /* list of buffers to push first */
296 /* if we need to clip this buffer. This is only needed for uncompressed
300 /* buffer needs some custom processing, e.g. subtitles */
301 gboolean need_process;
303 /* current position */
304 guint32 segment_index;
305 guint32 sample_index;
306 GstClockTime time_position; /* in gst time */
308 /* the Gst segment we are processing out, used for clipping */
310 guint32 segment_seqnum; /* segment event seqnum obtained from seek */
312 /* quicktime segments */
314 QtDemuxSegment *segments;
315 gboolean dummy_segment;
320 GstTagList *pending_tags;
321 gboolean send_global_tags;
323 GstEvent *pending_event;
333 gboolean chunks_are_samples; /* TRUE means treat chunks as samples */
337 GstByteReader co_chunk;
339 guint32 current_chunk;
341 guint32 samples_per_chunk;
342 guint32 stco_sample_index;
344 guint32 sample_size; /* 0 means variable sizes are stored in stsz */
347 guint32 n_samples_per_chunk;
348 guint32 stsc_chunk_index;
349 guint32 stsc_sample_index;
350 guint64 chunk_offset;
353 guint32 stts_samples;
354 guint32 n_sample_times;
355 guint32 stts_sample_index;
357 guint32 stts_duration;
359 gboolean stss_present;
360 guint32 n_sample_syncs;
363 gboolean stps_present;
364 guint32 n_sample_partial_syncs;
366 QtDemuxRandomAccessEntry *ra_entries;
369 const QtDemuxRandomAccessEntry *pending_seek;
372 gboolean ctts_present;
373 guint32 n_composition_times;
375 guint32 ctts_sample_index;
380 gboolean parsed_trex;
381 guint32 def_sample_duration;
382 guint32 def_sample_size;
383 guint32 def_sample_flags;
390 QTDEMUX_STATE_INITIAL, /* Initial state (haven't got the header yet) */
391 QTDEMUX_STATE_HEADER, /* Parsing the header */
392 QTDEMUX_STATE_MOVIE, /* Parsing/Playing the media data */
393 QTDEMUX_STATE_BUFFER_MDAT /* Buffering the mdat atom */
396 static GNode *qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc);
397 static GNode *qtdemux_tree_get_child_by_type_full (GNode * node,
398 guint32 fourcc, GstByteReader * parser);
399 static GNode *qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc);
400 static GNode *qtdemux_tree_get_sibling_by_type_full (GNode * node,
401 guint32 fourcc, GstByteReader * parser);
403 static GstFlowReturn qtdemux_add_fragmented_samples (GstQTDemux * qtdemux);
405 static GstStaticPadTemplate gst_qtdemux_sink_template =
406 GST_STATIC_PAD_TEMPLATE ("sink",
409 GST_STATIC_CAPS ("video/quicktime; video/mj2; audio/x-m4a; "
413 static GstStaticPadTemplate gst_qtdemux_videosrc_template =
414 GST_STATIC_PAD_TEMPLATE ("video_%u",
417 GST_STATIC_CAPS_ANY);
419 static GstStaticPadTemplate gst_qtdemux_audiosrc_template =
420 GST_STATIC_PAD_TEMPLATE ("audio_%u",
423 GST_STATIC_CAPS_ANY);
425 static GstStaticPadTemplate gst_qtdemux_subsrc_template =
426 GST_STATIC_PAD_TEMPLATE ("subtitle_%u",
429 GST_STATIC_CAPS_ANY);
431 #define gst_qtdemux_parent_class parent_class
432 G_DEFINE_TYPE (GstQTDemux, gst_qtdemux, GST_TYPE_ELEMENT);
434 static void gst_qtdemux_dispose (GObject * object);
437 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
438 GstClockTime media_time);
440 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
441 QtDemuxStream * str, gint64 media_offset);
444 static void gst_qtdemux_set_index (GstElement * element, GstIndex * index);
445 static GstIndex *gst_qtdemux_get_index (GstElement * element);
447 static GstStateChangeReturn gst_qtdemux_change_state (GstElement * element,
448 GstStateChange transition);
449 static gboolean qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent);
450 static gboolean qtdemux_sink_activate_mode (GstPad * sinkpad,
451 GstObject * parent, GstPadMode mode, gboolean active);
453 static void gst_qtdemux_loop (GstPad * pad);
454 static GstFlowReturn gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent,
456 static gboolean gst_qtdemux_handle_sink_event (GstPad * pad, GstObject * parent,
458 static gboolean gst_qtdemux_setcaps (GstQTDemux * qtdemux, GstCaps * caps);
459 static gboolean gst_qtdemux_configure_stream (GstQTDemux * qtdemux,
460 QtDemuxStream * stream);
461 static GstFlowReturn gst_qtdemux_process_adapter (GstQTDemux * demux,
464 static gboolean qtdemux_parse_moov (GstQTDemux * qtdemux,
465 const guint8 * buffer, guint length);
466 static gboolean qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node,
467 const guint8 * buffer, guint length);
468 static gboolean qtdemux_parse_tree (GstQTDemux * qtdemux);
469 static void qtdemux_parse_udta (GstQTDemux * qtdemux, GstTagList * taglist,
472 static void gst_qtdemux_handle_esds (GstQTDemux * qtdemux,
473 QtDemuxStream * stream, GNode * esds, GstTagList * list);
474 static GstCaps *qtdemux_video_caps (GstQTDemux * qtdemux,
475 QtDemuxStream * stream, guint32 fourcc, const guint8 * stsd_data,
476 gchar ** codec_name);
477 static GstCaps *qtdemux_audio_caps (GstQTDemux * qtdemux,
478 QtDemuxStream * stream, guint32 fourcc, const guint8 * data, int len,
479 gchar ** codec_name);
480 static GstCaps *qtdemux_sub_caps (GstQTDemux * qtdemux,
481 QtDemuxStream * stream, guint32 fourcc, const guint8 * data,
482 gchar ** codec_name);
483 static GstCaps *qtdemux_generic_caps (GstQTDemux * qtdemux,
484 QtDemuxStream * stream, guint32 fourcc, const guint8 * stsd_data,
485 gchar ** codec_name);
487 static gboolean qtdemux_parse_samples (GstQTDemux * qtdemux,
488 QtDemuxStream * stream, guint32 n);
489 static GstFlowReturn qtdemux_expose_streams (GstQTDemux * qtdemux);
490 static void gst_qtdemux_stream_free (GstQTDemux * qtdemux,
491 QtDemuxStream * stream);
492 static void gst_qtdemux_stream_clear (GstQTDemux * qtdemux,
493 QtDemuxStream * stream);
494 static void gst_qtdemux_remove_stream (GstQTDemux * qtdemux, int index);
495 static GstFlowReturn qtdemux_prepare_streams (GstQTDemux * qtdemux);
496 static void qtdemux_do_allocation (GstQTDemux * qtdemux,
497 QtDemuxStream * stream);
499 static gboolean qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux);
500 static void check_update_duration (GstQTDemux * qtdemux, GstClockTime duration);
503 gst_qtdemux_class_init (GstQTDemuxClass * klass)
505 GObjectClass *gobject_class;
506 GstElementClass *gstelement_class;
508 gobject_class = (GObjectClass *) klass;
509 gstelement_class = (GstElementClass *) klass;
511 parent_class = g_type_class_peek_parent (klass);
513 gobject_class->dispose = gst_qtdemux_dispose;
515 gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_qtdemux_change_state);
517 gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_qtdemux_set_index);
518 gstelement_class->get_index = GST_DEBUG_FUNCPTR (gst_qtdemux_get_index);
521 gst_tag_register_musicbrainz_tags ();
523 gst_element_class_add_pad_template (gstelement_class,
524 gst_static_pad_template_get (&gst_qtdemux_sink_template));
525 gst_element_class_add_pad_template (gstelement_class,
526 gst_static_pad_template_get (&gst_qtdemux_videosrc_template));
527 gst_element_class_add_pad_template (gstelement_class,
528 gst_static_pad_template_get (&gst_qtdemux_audiosrc_template));
529 gst_element_class_add_pad_template (gstelement_class,
530 gst_static_pad_template_get (&gst_qtdemux_subsrc_template));
531 gst_element_class_set_static_metadata (gstelement_class, "QuickTime demuxer",
533 "Demultiplex a QuickTime file into audio and video streams",
534 "David Schleef <ds@schleef.org>, Wim Taymans <wim@fluendo.com>");
536 GST_DEBUG_CATEGORY_INIT (qtdemux_debug, "qtdemux", 0, "qtdemux plugin");
541 gst_qtdemux_init (GstQTDemux * qtdemux)
544 gst_pad_new_from_static_template (&gst_qtdemux_sink_template, "sink");
545 gst_pad_set_activate_function (qtdemux->sinkpad, qtdemux_sink_activate);
546 gst_pad_set_activatemode_function (qtdemux->sinkpad,
547 qtdemux_sink_activate_mode);
548 gst_pad_set_chain_function (qtdemux->sinkpad, gst_qtdemux_chain);
549 gst_pad_set_event_function (qtdemux->sinkpad, gst_qtdemux_handle_sink_event);
550 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), qtdemux->sinkpad);
552 qtdemux->state = QTDEMUX_STATE_INITIAL;
553 qtdemux->pullbased = FALSE;
554 qtdemux->posted_redirect = FALSE;
555 qtdemux->neededbytes = 16;
557 qtdemux->adapter = gst_adapter_new ();
559 qtdemux->first_mdat = -1;
560 qtdemux->got_moov = FALSE;
561 qtdemux->mdatoffset = -1;
562 qtdemux->mdatbuffer = NULL;
563 qtdemux->restoredata_buffer = NULL;
564 qtdemux->restoredata_offset = -1;
565 qtdemux->fragment_start = -1;
566 qtdemux->fragment_start_offset = -1;
567 qtdemux->media_caps = NULL;
568 qtdemux->exposed = FALSE;
569 qtdemux->mss_mode = FALSE;
570 qtdemux->pending_newsegment = NULL;
571 qtdemux->upstream_newsegment = FALSE;
572 qtdemux->have_group_id = FALSE;
573 qtdemux->group_id = G_MAXUINT;
574 gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
575 qtdemux->flowcombiner = gst_flow_combiner_new ();
577 GST_OBJECT_FLAG_SET (qtdemux, GST_ELEMENT_FLAG_INDEXABLE);
581 gst_qtdemux_dispose (GObject * object)
583 GstQTDemux *qtdemux = GST_QTDEMUX (object);
585 if (qtdemux->adapter) {
586 g_object_unref (G_OBJECT (qtdemux->adapter));
587 qtdemux->adapter = NULL;
589 gst_flow_combiner_free (qtdemux->flowcombiner);
591 G_OBJECT_CLASS (parent_class)->dispose (object);
595 gst_qtdemux_post_no_playable_stream_error (GstQTDemux * qtdemux)
597 if (qtdemux->posted_redirect) {
598 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
599 (_("This file contains no playable streams.")),
600 ("no known streams found, a redirect message has been posted"));
602 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
603 (_("This file contains no playable streams.")),
604 ("no known streams found"));
609 _gst_buffer_new_wrapped (gpointer mem, gsize size, GFreeFunc free_func)
611 return gst_buffer_new_wrapped_full (free_func ? 0 : GST_MEMORY_FLAG_READONLY,
612 mem, size, 0, size, mem, free_func);
616 gst_qtdemux_pull_atom (GstQTDemux * qtdemux, guint64 offset, guint64 size,
623 if (G_UNLIKELY (size == 0)) {
625 GstBuffer *tmp = NULL;
627 ret = gst_qtdemux_pull_atom (qtdemux, offset, sizeof (guint32), &tmp);
628 if (ret != GST_FLOW_OK)
631 gst_buffer_map (tmp, &map, GST_MAP_READ);
632 size = QT_UINT32 (map.data);
633 GST_DEBUG_OBJECT (qtdemux, "size 0x%08" G_GINT64_MODIFIER "x", size);
635 gst_buffer_unmap (tmp, &map);
636 gst_buffer_unref (tmp);
639 /* Sanity check: catch bogus sizes (fuzzed/broken files) */
640 if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
641 if (qtdemux->state != QTDEMUX_STATE_MOVIE && qtdemux->got_moov) {
642 /* we're pulling header but already got most interesting bits,
643 * so never mind the rest (e.g. tags) (that much) */
644 GST_WARNING_OBJECT (qtdemux, "atom has bogus size %" G_GUINT64_FORMAT,
648 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
649 (_("This file is invalid and cannot be played.")),
650 ("atom has bogus size %" G_GUINT64_FORMAT, size));
651 return GST_FLOW_ERROR;
655 flow = gst_pad_pull_range (qtdemux->sinkpad, offset, size, buf);
657 if (G_UNLIKELY (flow != GST_FLOW_OK))
660 bsize = gst_buffer_get_size (*buf);
661 /* Catch short reads - we don't want any partial atoms */
662 if (G_UNLIKELY (bsize < size)) {
663 GST_WARNING_OBJECT (qtdemux,
664 "short read: %" G_GSIZE_FORMAT " < %" G_GUINT64_FORMAT, bsize, size);
665 gst_buffer_unref (*buf);
675 gst_qtdemux_src_convert (GstPad * pad, GstFormat src_format, gint64 src_value,
676 GstFormat dest_format, gint64 * dest_value)
679 QtDemuxStream *stream = gst_pad_get_element_private (pad);
680 GstQTDemux *qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
683 if (stream->subtype != FOURCC_vide) {
688 switch (src_format) {
689 case GST_FORMAT_TIME:
690 switch (dest_format) {
691 case GST_FORMAT_BYTES:{
692 index = gst_qtdemux_find_index_linear (qtdemux, stream, src_value);
696 *dest_value = stream->samples[index].offset;
698 GST_DEBUG_OBJECT (qtdemux, "Format Conversion Time->Offset :%"
699 GST_TIME_FORMAT "->%" G_GUINT64_FORMAT,
700 GST_TIME_ARGS (src_value), *dest_value);
708 case GST_FORMAT_BYTES:
709 switch (dest_format) {
710 case GST_FORMAT_TIME:{
712 gst_qtdemux_find_index_for_given_media_offset_linear (qtdemux,
719 QTSTREAMTIME_TO_GSTTIME (stream,
720 stream->samples[index].timestamp);
721 GST_DEBUG_OBJECT (qtdemux,
722 "Format Conversion Offset->Time :%" G_GUINT64_FORMAT "->%"
723 GST_TIME_FORMAT, src_value, GST_TIME_ARGS (*dest_value));
736 gst_object_unref (qtdemux);
743 gst_qtdemux_get_duration (GstQTDemux * qtdemux, GstClockTime * duration)
747 *duration = GST_CLOCK_TIME_NONE;
749 if (qtdemux->duration != 0) {
750 if (qtdemux->duration != G_MAXINT64 && qtdemux->timescale != 0) {
751 *duration = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
758 gst_qtdemux_handle_src_query (GstPad * pad, GstObject * parent,
761 gboolean res = FALSE;
762 GstQTDemux *qtdemux = GST_QTDEMUX (parent);
764 GST_LOG_OBJECT (pad, "%s query", GST_QUERY_TYPE_NAME (query));
766 switch (GST_QUERY_TYPE (query)) {
767 case GST_QUERY_POSITION:{
770 gst_query_parse_position (query, &fmt, NULL);
771 if (fmt == GST_FORMAT_TIME
772 && GST_CLOCK_TIME_IS_VALID (qtdemux->segment.position)) {
773 gst_query_set_position (query, GST_FORMAT_TIME,
774 qtdemux->segment.position);
779 case GST_QUERY_DURATION:{
782 gst_query_parse_duration (query, &fmt, NULL);
783 if (fmt == GST_FORMAT_TIME) {
784 /* First try to query upstream */
785 res = gst_pad_query_default (pad, parent, query);
788 if (gst_qtdemux_get_duration (qtdemux, &duration) && duration > 0) {
789 gst_query_set_duration (query, GST_FORMAT_TIME, duration);
796 case GST_QUERY_CONVERT:{
797 GstFormat src_fmt, dest_fmt;
798 gint64 src_value, dest_value = 0;
800 gst_query_parse_convert (query, &src_fmt, &src_value, &dest_fmt, NULL);
802 res = gst_qtdemux_src_convert (pad,
803 src_fmt, src_value, dest_fmt, &dest_value);
805 gst_query_set_convert (query, src_fmt, src_value, dest_fmt, dest_value);
810 case GST_QUERY_FORMATS:
811 gst_query_set_formats (query, 2, GST_FORMAT_TIME, GST_FORMAT_BYTES);
814 case GST_QUERY_SEEKING:{
818 /* try upstream first */
819 res = gst_pad_query_default (pad, parent, query);
822 gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
823 if (fmt == GST_FORMAT_TIME) {
824 GstClockTime duration = GST_CLOCK_TIME_NONE;
826 gst_qtdemux_get_duration (qtdemux, &duration);
828 if (!qtdemux->pullbased) {
831 /* we might be able with help from upstream */
833 q = gst_query_new_seeking (GST_FORMAT_BYTES);
834 if (gst_pad_peer_query (qtdemux->sinkpad, q)) {
835 gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL);
836 GST_LOG_OBJECT (qtdemux, "upstream BYTE seekable %d", seekable);
840 gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0, duration);
846 case GST_QUERY_SEGMENT:
851 format = qtdemux->segment.format;
854 gst_segment_to_stream_time (&qtdemux->segment, format,
855 qtdemux->segment.start);
856 if ((stop = qtdemux->segment.stop) == -1)
857 stop = qtdemux->segment.duration;
859 stop = gst_segment_to_stream_time (&qtdemux->segment, format, stop);
861 gst_query_set_segment (query, qtdemux->segment.rate, format, start, stop);
866 res = gst_pad_query_default (pad, parent, query);
874 gst_qtdemux_push_tags (GstQTDemux * qtdemux, QtDemuxStream * stream)
876 if (G_LIKELY (stream->pad)) {
877 GST_DEBUG_OBJECT (qtdemux, "Checking pad %s:%s for tags",
878 GST_DEBUG_PAD_NAME (stream->pad));
880 if (G_UNLIKELY (stream->pending_tags)) {
881 GST_DEBUG_OBJECT (qtdemux, "Sending tags %" GST_PTR_FORMAT,
882 stream->pending_tags);
883 gst_pad_push_event (stream->pad,
884 gst_event_new_tag (stream->pending_tags));
885 stream->pending_tags = NULL;
888 if (G_UNLIKELY (stream->send_global_tags && qtdemux->tag_list)) {
889 GST_DEBUG_OBJECT (qtdemux, "Sending global tags %" GST_PTR_FORMAT,
891 gst_pad_push_event (stream->pad,
892 gst_event_new_tag (gst_tag_list_ref (qtdemux->tag_list)));
893 stream->send_global_tags = FALSE;
898 /* push event on all source pads; takes ownership of the event */
900 gst_qtdemux_push_event (GstQTDemux * qtdemux, GstEvent * event)
903 gboolean has_valid_stream = FALSE;
904 GstEventType etype = GST_EVENT_TYPE (event);
906 GST_DEBUG_OBJECT (qtdemux, "pushing %s event on all source pads",
907 GST_EVENT_TYPE_NAME (event));
909 for (n = 0; n < qtdemux->n_streams; n++) {
911 QtDemuxStream *stream = qtdemux->streams[n];
912 GST_DEBUG_OBJECT (qtdemux, "pushing on pad %i", n);
914 if ((pad = stream->pad)) {
915 has_valid_stream = TRUE;
917 if (etype == GST_EVENT_EOS) {
918 /* let's not send twice */
919 if (stream->sent_eos)
921 stream->sent_eos = TRUE;
924 gst_pad_push_event (pad, gst_event_ref (event));
928 gst_event_unref (event);
930 /* if it is EOS and there are no pads, post an error */
931 if (!has_valid_stream && etype == GST_EVENT_EOS) {
932 gst_qtdemux_post_no_playable_stream_error (qtdemux);
936 /* push a pending newsegment event, if any from the streaming thread */
938 gst_qtdemux_push_pending_newsegment (GstQTDemux * qtdemux)
940 if (qtdemux->pending_newsegment) {
941 gst_qtdemux_push_event (qtdemux, qtdemux->pending_newsegment);
942 qtdemux->pending_newsegment = NULL;
952 find_func (QtDemuxSample * s1, guint64 * media_time, gpointer user_data)
954 if (s1->timestamp + s1->pts_offset > *media_time)
960 /* find the index of the sample that includes the data for @media_time using a
961 * binary search. Only to be called in optimized cases of linear search below.
963 * Returns the index of the sample.
966 gst_qtdemux_find_index (GstQTDemux * qtdemux, QtDemuxStream * str,
969 QtDemuxSample *result;
972 /* convert media_time to mov format */
974 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
976 result = gst_util_array_binary_search (str->samples, str->stbl_index + 1,
977 sizeof (QtDemuxSample), (GCompareDataFunc) find_func,
978 GST_SEARCH_MODE_BEFORE, &media_time, NULL);
980 if (G_LIKELY (result))
981 index = result - str->samples;
990 /* find the index of the sample that includes the data for @media_offset using a
993 * Returns the index of the sample.
996 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
997 QtDemuxStream * str, gint64 media_offset)
999 QtDemuxSample *result = str->samples;
1002 if (result == NULL || str->n_samples == 0)
1005 if (media_offset == result->offset)
1009 while (index < str->n_samples - 1) {
1010 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
1013 if (media_offset < result->offset)
1024 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
1029 /* find the index of the sample that includes the data for @media_time using a
1030 * linear search, and keeping in mind that not all samples may have been parsed
1031 * yet. If possible, it will delegate to binary search.
1033 * Returns the index of the sample.
1036 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
1037 GstClockTime media_time)
1041 QtDemuxSample *sample;
1043 /* convert media_time to mov format */
1045 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
1047 sample = str->samples;
1048 if (mov_time == sample->timestamp + sample->pts_offset)
1051 /* use faster search if requested time in already parsed range */
1052 sample = str->samples + str->stbl_index;
1053 if (str->stbl_index >= 0 &&
1054 mov_time <= (sample->timestamp + sample->pts_offset))
1055 return gst_qtdemux_find_index (qtdemux, str, media_time);
1057 while (index < str->n_samples - 1) {
1058 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
1061 sample = str->samples + index + 1;
1062 if (mov_time < (sample->timestamp + sample->pts_offset))
1072 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
1077 /* find the index of the keyframe needed to decode the sample at @index
1080 * Returns the index of the keyframe.
1083 gst_qtdemux_find_keyframe (GstQTDemux * qtdemux, QtDemuxStream * str,
1086 guint32 new_index = index;
1088 if (index >= str->n_samples) {
1089 new_index = str->n_samples;
1093 /* all keyframes, return index */
1094 if (str->all_keyframe) {
1099 /* else go back until we have a keyframe */
1101 if (str->samples[new_index].keyframe)
1111 GST_DEBUG_OBJECT (qtdemux, "searching for keyframe index before index %u "
1112 "gave %u", index, new_index);
1117 /* find the segment for @time_position for @stream
1119 * Returns the index of the segment containing @time_position.
1120 * Returns the last segment and sets the @eos variable to TRUE
1121 * if the time is beyond the end. @eos may be NULL
1124 gst_qtdemux_find_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
1125 GstClockTime time_position)
1130 GST_LOG_OBJECT (qtdemux, "finding segment for %" GST_TIME_FORMAT,
1131 GST_TIME_ARGS (time_position));
1134 for (i = 0; i < stream->n_segments; i++) {
1135 QtDemuxSegment *segment = &stream->segments[i];
1137 GST_LOG_OBJECT (qtdemux,
1138 "looking at segment %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT,
1139 GST_TIME_ARGS (segment->time), GST_TIME_ARGS (segment->stop_time));
1141 /* For the last segment we include stop_time in the last segment */
1142 if (i < stream->n_segments - 1) {
1143 if (segment->time <= time_position && time_position < segment->stop_time) {
1144 GST_LOG_OBJECT (qtdemux, "segment %d matches", i);
1149 /* Last segment always matches */
1157 /* move the stream @str to the sample position @index.
1159 * Updates @str->sample_index and marks discontinuity if needed.
1162 gst_qtdemux_move_stream (GstQTDemux * qtdemux, QtDemuxStream * str,
1165 /* no change needed */
1166 if (index == str->sample_index)
1169 GST_DEBUG_OBJECT (qtdemux, "moving to sample %u of %u", index,
1172 /* position changed, we have a discont */
1173 str->sample_index = index;
1174 str->offset_in_sample = 0;
1175 /* Each time we move in the stream we store the position where we are
1177 str->from_sample = index;
1178 str->discont = TRUE;
1182 gst_qtdemux_adjust_seek (GstQTDemux * qtdemux, gint64 desired_time,
1183 gboolean use_sparse, gint64 * key_time, gint64 * key_offset)
1186 gint64 min_byte_offset = -1;
1189 min_offset = desired_time;
1191 /* for each stream, find the index of the sample in the segment
1192 * and move back to the previous keyframe. */
1193 for (n = 0; n < qtdemux->n_streams; n++) {
1195 guint32 index, kindex;
1197 GstClockTime media_start;
1198 GstClockTime media_time;
1199 GstClockTime seg_time;
1200 QtDemuxSegment *seg;
1202 str = qtdemux->streams[n];
1204 if (str->sparse && !use_sparse)
1207 seg_idx = gst_qtdemux_find_segment (qtdemux, str, desired_time);
1208 GST_DEBUG_OBJECT (qtdemux, "align segment %d", seg_idx);
1210 /* get segment and time in the segment */
1211 seg = &str->segments[seg_idx];
1212 seg_time = desired_time - seg->time;
1214 /* get the media time in the segment */
1215 media_start = seg->media_start + seg_time;
1217 /* get the index of the sample with media time */
1218 index = gst_qtdemux_find_index_linear (qtdemux, str, media_start);
1219 GST_DEBUG_OBJECT (qtdemux, "sample for %" GST_TIME_FORMAT " at %u"
1220 " at offset %" G_GUINT64_FORMAT,
1221 GST_TIME_ARGS (media_start), index, str->samples[index].offset);
1223 /* find previous keyframe */
1224 kindex = gst_qtdemux_find_keyframe (qtdemux, str, index);
1226 /* if the keyframe is at a different position, we need to update the
1227 * requested seek time */
1228 if (index != kindex) {
1231 /* get timestamp of keyframe */
1232 media_time = QTSAMPLE_DTS (str, &str->samples[kindex]);
1233 GST_DEBUG_OBJECT (qtdemux,
1234 "keyframe at %u with time %" GST_TIME_FORMAT " at offset %"
1235 G_GUINT64_FORMAT, kindex, GST_TIME_ARGS (media_time),
1236 str->samples[kindex].offset);
1238 /* keyframes in the segment get a chance to change the
1239 * desired_offset. keyframes out of the segment are
1241 if (media_time >= seg->media_start) {
1242 GstClockTime seg_time;
1244 /* this keyframe is inside the segment, convert back to
1246 seg_time = (media_time - seg->media_start) + seg->time;
1247 if (seg_time < min_offset)
1248 min_offset = seg_time;
1252 if (min_byte_offset < 0 || str->samples[index].offset < min_byte_offset)
1253 min_byte_offset = str->samples[index].offset;
1257 *key_time = min_offset;
1259 *key_offset = min_byte_offset;
1263 gst_qtdemux_convert_seek (GstPad * pad, GstFormat * format,
1264 GstSeekType cur_type, gint64 * cur, GstSeekType stop_type, gint64 * stop)
1268 g_return_val_if_fail (format != NULL, FALSE);
1269 g_return_val_if_fail (cur != NULL, FALSE);
1270 g_return_val_if_fail (stop != NULL, FALSE);
1272 if (*format == GST_FORMAT_TIME)
1276 if (cur_type != GST_SEEK_TYPE_NONE)
1277 res = gst_pad_query_convert (pad, *format, *cur, GST_FORMAT_TIME, cur);
1278 if (res && stop_type != GST_SEEK_TYPE_NONE)
1279 res = gst_pad_query_convert (pad, *format, *stop, GST_FORMAT_TIME, stop);
1282 *format = GST_FORMAT_TIME;
1287 /* perform seek in push based mode:
1288 find BYTE position to move to based on time and delegate to upstream
1291 gst_qtdemux_do_push_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1296 GstSeekType cur_type, stop_type;
1297 gint64 cur, stop, key_cur;
1300 gint64 original_stop;
1303 GST_DEBUG_OBJECT (qtdemux, "doing push-based seek");
1305 gst_event_parse_seek (event, &rate, &format, &flags,
1306 &cur_type, &cur, &stop_type, &stop);
1307 seqnum = gst_event_get_seqnum (event);
1309 /* only forward streaming and seeking is possible */
1311 goto unsupported_seek;
1313 /* convert to TIME if needed and possible */
1314 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1318 /* Upstrea seek in bytes will have undefined stop, but qtdemux stores
1319 * the original stop position to use when upstream pushes the new segment
1321 original_stop = stop;
1324 /* find reasonable corresponding BYTE position,
1325 * also try to mind about keyframes, since we can not go back a bit for them
1327 gst_qtdemux_adjust_seek (qtdemux, cur, FALSE, &key_cur, &byte_cur);
1332 GST_DEBUG_OBJECT (qtdemux, "Pushing BYTE seek rate %g, "
1333 "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, byte_cur,
1336 GST_OBJECT_LOCK (qtdemux);
1337 qtdemux->seek_offset = byte_cur;
1338 if (!(flags & GST_SEEK_FLAG_KEY_UNIT)) {
1339 qtdemux->push_seek_start = cur;
1341 qtdemux->push_seek_start = key_cur;
1344 if (stop_type == GST_SEEK_TYPE_NONE) {
1345 qtdemux->push_seek_stop = qtdemux->segment.stop;
1347 qtdemux->push_seek_stop = original_stop;
1349 GST_OBJECT_UNLOCK (qtdemux);
1351 /* BYTE seek event */
1352 event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type, byte_cur,
1354 gst_event_set_seqnum (event, seqnum);
1355 res = gst_pad_push_event (qtdemux->sinkpad, event);
1362 GST_DEBUG_OBJECT (qtdemux, "could not determine byte position to seek to, "
1368 GST_DEBUG_OBJECT (qtdemux, "unsupported seek, seek aborted.");
1373 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1378 /* perform the seek.
1380 * We set all segment_indexes in the streams to unknown and
1381 * adjust the time_position to the desired position. this is enough
1382 * to trigger a segment switch in the streaming thread to start
1383 * streaming from the desired position.
1385 * Keyframe seeking is a little more complicated when dealing with
1386 * segments. Ideally we want to move to the previous keyframe in
1387 * the segment but there might not be a keyframe in the segment. In
1388 * fact, none of the segments could contain a keyframe. We take a
1389 * practical approach: seek to the previous keyframe in the segment,
1390 * if there is none, seek to the beginning of the segment.
1392 * Called with STREAM_LOCK
1395 gst_qtdemux_perform_seek (GstQTDemux * qtdemux, GstSegment * segment,
1398 gint64 desired_offset;
1401 desired_offset = segment->position;
1403 GST_DEBUG_OBJECT (qtdemux, "seeking to %" GST_TIME_FORMAT,
1404 GST_TIME_ARGS (desired_offset));
1406 /* may not have enough fragmented info to do this adjustment,
1407 * and we can't scan (and probably should not) at this time with
1408 * possibly flushing upstream */
1409 if ((segment->flags & GST_SEEK_FLAG_KEY_UNIT) && !qtdemux->fragmented) {
1412 gst_qtdemux_adjust_seek (qtdemux, desired_offset, TRUE, &min_offset, NULL);
1413 GST_DEBUG_OBJECT (qtdemux, "keyframe seek, align to %"
1414 GST_TIME_FORMAT, GST_TIME_ARGS (min_offset));
1415 desired_offset = min_offset;
1418 /* and set all streams to the final position */
1419 for (n = 0; n < qtdemux->n_streams; n++) {
1420 QtDemuxStream *stream = qtdemux->streams[n];
1422 stream->time_position = desired_offset;
1423 stream->sample_index = -1;
1424 stream->offset_in_sample = 0;
1425 stream->segment_index = -1;
1426 stream->sent_eos = FALSE;
1427 stream->segment_seqnum = seqnum;
1429 if (segment->flags & GST_SEEK_FLAG_FLUSH)
1430 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
1432 segment->position = desired_offset;
1433 segment->time = desired_offset;
1435 /* we stop at the end */
1436 if (segment->stop == -1)
1437 segment->stop = segment->duration;
1439 if (qtdemux->fragmented)
1440 qtdemux->fragmented_seek_pending = TRUE;
1445 /* do a seek in pull based mode */
1447 gst_qtdemux_do_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1452 GstSeekType cur_type, stop_type;
1456 GstSegment seeksegment;
1458 GstEvent *flush_event;
1461 GST_DEBUG_OBJECT (qtdemux, "doing seek with event");
1463 gst_event_parse_seek (event, &rate, &format, &flags,
1464 &cur_type, &cur, &stop_type, &stop);
1465 seqnum = gst_event_get_seqnum (event);
1467 /* we have to have a format as the segment format. Try to convert
1469 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1473 GST_DEBUG_OBJECT (qtdemux, "seek format %s", gst_format_get_name (format));
1475 GST_DEBUG_OBJECT (qtdemux, "doing seek without event");
1479 flush = flags & GST_SEEK_FLAG_FLUSH;
1481 /* stop streaming, either by flushing or by pausing the task */
1483 flush_event = gst_event_new_flush_start ();
1485 gst_event_set_seqnum (flush_event, seqnum);
1486 /* unlock upstream pull_range */
1487 gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event));
1488 /* make sure out loop function exits */
1489 gst_qtdemux_push_event (qtdemux, flush_event);
1491 /* non flushing seek, pause the task */
1492 gst_pad_pause_task (qtdemux->sinkpad);
1495 /* wait for streaming to finish */
1496 GST_PAD_STREAM_LOCK (qtdemux->sinkpad);
1498 /* copy segment, we need this because we still need the old
1499 * segment when we close the current segment. */
1500 memcpy (&seeksegment, &qtdemux->segment, sizeof (GstSegment));
1503 /* configure the segment with the seek variables */
1504 GST_DEBUG_OBJECT (qtdemux, "configuring seek");
1505 gst_segment_do_seek (&seeksegment, rate, format, flags,
1506 cur_type, cur, stop_type, stop, &update);
1509 /* now do the seek, this actually never returns FALSE */
1510 gst_qtdemux_perform_seek (qtdemux, &seeksegment, seqnum);
1512 /* prepare for streaming again */
1514 flush_event = gst_event_new_flush_stop (TRUE);
1516 gst_event_set_seqnum (flush_event, seqnum);
1518 gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event));
1519 gst_qtdemux_push_event (qtdemux, flush_event);
1522 /* commit the new segment */
1523 memcpy (&qtdemux->segment, &seeksegment, sizeof (GstSegment));
1525 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
1526 GstMessage *msg = gst_message_new_segment_start (GST_OBJECT_CAST (qtdemux),
1527 qtdemux->segment.format, qtdemux->segment.position);
1529 gst_message_set_seqnum (msg, seqnum);
1530 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
1533 gst_pad_start_task (qtdemux->sinkpad, (GstTaskFunction) gst_qtdemux_loop,
1534 qtdemux->sinkpad, NULL);
1536 GST_PAD_STREAM_UNLOCK (qtdemux->sinkpad);
1543 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1549 qtdemux_ensure_index (GstQTDemux * qtdemux)
1553 GST_DEBUG_OBJECT (qtdemux, "collecting all metadata for all streams");
1555 /* Build complete index */
1556 for (i = 0; i < qtdemux->n_streams; i++) {
1557 QtDemuxStream *stream = qtdemux->streams[i];
1559 if (!qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1))
1567 GST_LOG_OBJECT (qtdemux,
1568 "Building complete index of stream %u for seeking failed!", i);
1574 gst_qtdemux_handle_src_event (GstPad * pad, GstObject * parent,
1577 gboolean res = TRUE;
1578 GstQTDemux *qtdemux = GST_QTDEMUX (parent);
1580 switch (GST_EVENT_TYPE (event)) {
1581 case GST_EVENT_SEEK:
1583 #ifndef GST_DISABLE_GST_DEBUG
1584 GstClockTime ts = gst_util_get_timestamp ();
1587 if (qtdemux->upstream_newsegment && qtdemux->fragmented) {
1588 /* seek should be handled by upstream, we might need to re-download fragments */
1589 GST_DEBUG_OBJECT (qtdemux,
1590 "let upstream handle seek for fragmented playback");
1594 /* Build complete index for seeking;
1595 * if not a fragmented file at least */
1596 if (!qtdemux->fragmented)
1597 if (!qtdemux_ensure_index (qtdemux))
1599 #ifndef GST_DISABLE_GST_DEBUG
1600 ts = gst_util_get_timestamp () - ts;
1601 GST_INFO_OBJECT (qtdemux,
1602 "Time taken to parse index %" GST_TIME_FORMAT, GST_TIME_ARGS (ts));
1605 if (qtdemux->pullbased) {
1606 res = gst_qtdemux_do_seek (qtdemux, pad, event);
1607 } else if (gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (event))) {
1608 GST_DEBUG_OBJECT (qtdemux, "Upstream successfully seeked");
1610 } else if (qtdemux->state == QTDEMUX_STATE_MOVIE && qtdemux->n_streams
1611 && !qtdemux->fragmented) {
1612 res = gst_qtdemux_do_push_seek (qtdemux, pad, event);
1614 GST_DEBUG_OBJECT (qtdemux,
1615 "ignoring seek in push mode in current state");
1618 gst_event_unref (event);
1621 case GST_EVENT_NAVIGATION:
1623 gst_event_unref (event);
1627 res = gst_pad_event_default (pad, parent, event);
1637 GST_ERROR_OBJECT (qtdemux, "Index failed");
1638 gst_event_unref (event);
1644 /* stream/index return sample that is min/max w.r.t. byte position,
1645 * time is min/max w.r.t. time of samples,
1646 * the latter need not be time of the former sample */
1648 gst_qtdemux_find_sample (GstQTDemux * qtdemux, gint64 byte_pos, gboolean fw,
1649 gboolean set, QtDemuxStream ** _stream, gint * _index, gint64 * _time)
1652 gint64 time, min_time;
1653 QtDemuxStream *stream;
1659 for (n = 0; n < qtdemux->n_streams; ++n) {
1662 gboolean set_sample;
1664 str = qtdemux->streams[n];
1671 i = str->n_samples - 1;
1675 for (; (i >= 0) && (i < str->n_samples); i += inc) {
1676 if (str->samples[i].size == 0)
1679 if (fw && (str->samples[i].offset < byte_pos))
1682 if (!fw && (str->samples[i].offset + str->samples[i].size > byte_pos))
1685 /* move stream to first available sample */
1687 gst_qtdemux_move_stream (qtdemux, str, i);
1691 /* avoid index from sparse streams since they might be far away */
1693 /* determine min/max time */
1694 time = QTSAMPLE_PTS (str, &str->samples[i]);
1695 if (min_time == -1 || (!fw && time > min_time) ||
1696 (fw && time < min_time)) {
1700 /* determine stream with leading sample, to get its position */
1702 (fw && (str->samples[i].offset < stream->samples[index].offset)) ||
1703 (!fw && (str->samples[i].offset > stream->samples[index].offset))) {
1711 /* no sample for this stream, mark eos */
1713 gst_qtdemux_move_stream (qtdemux, str, str->n_samples);
1724 static QtDemuxStream *
1725 _create_stream (void)
1727 QtDemuxStream *stream;
1729 stream = g_new0 (QtDemuxStream, 1);
1730 /* new streams always need a discont */
1731 stream->discont = TRUE;
1732 /* we enable clipping for raw audio/video streams */
1733 stream->need_clip = FALSE;
1734 stream->need_process = FALSE;
1735 stream->segment_index = -1;
1736 stream->time_position = 0;
1737 stream->sample_index = -1;
1738 stream->offset_in_sample = 0;
1739 stream->new_stream = TRUE;
1744 gst_qtdemux_setcaps (GstQTDemux * demux, GstCaps * caps)
1746 GstStructure *structure;
1747 const gchar *variant;
1748 const GstCaps *mediacaps = NULL;
1750 GST_DEBUG_OBJECT (demux, "Sink set caps: %" GST_PTR_FORMAT, caps);
1752 structure = gst_caps_get_structure (caps, 0);
1753 variant = gst_structure_get_string (structure, "variant");
1755 if (variant && strcmp (variant, "mss-fragmented") == 0) {
1756 QtDemuxStream *stream;
1757 const GValue *value;
1759 demux->fragmented = TRUE;
1760 demux->mss_mode = TRUE;
1762 if (demux->n_streams > 1) {
1763 /* can't do this, we can only renegotiate for another mss format */
1767 value = gst_structure_get_value (structure, "media-caps");
1770 const GValue *timescale_v;
1772 /* TODO update when stream changes during playback */
1774 if (demux->n_streams == 0) {
1775 stream = _create_stream ();
1776 demux->streams[demux->n_streams] = stream;
1777 demux->n_streams = 1;
1779 stream = demux->streams[0];
1782 timescale_v = gst_structure_get_value (structure, "timescale");
1784 stream->timescale = g_value_get_uint64 (timescale_v);
1786 /* default mss timescale */
1787 stream->timescale = 10000000;
1789 demux->timescale = stream->timescale;
1791 mediacaps = gst_value_get_caps (value);
1792 if (!stream->caps || !gst_caps_is_equal_fixed (mediacaps, stream->caps)) {
1793 GST_DEBUG_OBJECT (demux, "We have a new caps %" GST_PTR_FORMAT,
1795 stream->new_caps = TRUE;
1797 gst_caps_replace (&stream->caps, (GstCaps *) mediacaps);
1798 structure = gst_caps_get_structure (mediacaps, 0);
1799 if (g_str_has_prefix (gst_structure_get_name (structure), "video")) {
1800 stream->subtype = FOURCC_vide;
1802 gst_structure_get_int (structure, "width", &stream->width);
1803 gst_structure_get_int (structure, "height", &stream->height);
1804 gst_structure_get_fraction (structure, "framerate", &stream->fps_n,
1806 } else if (g_str_has_prefix (gst_structure_get_name (structure), "audio")) {
1808 stream->subtype = FOURCC_soun;
1809 gst_structure_get_int (structure, "channels", &stream->n_channels);
1810 gst_structure_get_int (structure, "rate", &rate);
1811 stream->rate = rate;
1814 gst_caps_replace (&demux->media_caps, (GstCaps *) mediacaps);
1816 demux->mss_mode = FALSE;
1823 gst_qtdemux_reset (GstQTDemux * qtdemux, gboolean hard)
1827 GST_DEBUG_OBJECT (qtdemux, "Resetting demux");
1828 gst_pad_stop_task (qtdemux->sinkpad);
1830 if (hard || qtdemux->upstream_newsegment) {
1831 qtdemux->state = QTDEMUX_STATE_INITIAL;
1832 qtdemux->neededbytes = 16;
1833 qtdemux->todrop = 0;
1834 qtdemux->pullbased = FALSE;
1835 qtdemux->posted_redirect = FALSE;
1836 qtdemux->first_mdat = -1;
1837 qtdemux->header_size = 0;
1838 qtdemux->mdatoffset = -1;
1839 qtdemux->restoredata_offset = -1;
1840 if (qtdemux->mdatbuffer)
1841 gst_buffer_unref (qtdemux->mdatbuffer);
1842 if (qtdemux->restoredata_buffer)
1843 gst_buffer_unref (qtdemux->restoredata_buffer);
1844 qtdemux->mdatbuffer = NULL;
1845 qtdemux->restoredata_buffer = NULL;
1846 qtdemux->mdatleft = 0;
1847 if (qtdemux->comp_brands)
1848 gst_buffer_unref (qtdemux->comp_brands);
1849 qtdemux->comp_brands = NULL;
1850 qtdemux->last_moov_offset = -1;
1851 if (qtdemux->moov_node)
1852 g_node_destroy (qtdemux->moov_node);
1853 qtdemux->moov_node = NULL;
1854 qtdemux->moov_node_compressed = NULL;
1855 if (qtdemux->tag_list)
1856 gst_mini_object_unref (GST_MINI_OBJECT_CAST (qtdemux->tag_list));
1857 qtdemux->tag_list = NULL;
1859 if (qtdemux->element_index)
1860 gst_object_unref (qtdemux->element_index);
1861 qtdemux->element_index = NULL;
1863 qtdemux->major_brand = 0;
1864 if (qtdemux->pending_newsegment)
1865 gst_event_unref (qtdemux->pending_newsegment);
1866 qtdemux->pending_newsegment = NULL;
1867 qtdemux->upstream_newsegment = FALSE;
1868 qtdemux->upstream_seekable = FALSE;
1869 qtdemux->upstream_size = 0;
1871 qtdemux->fragment_start = -1;
1872 qtdemux->fragment_start_offset = -1;
1873 qtdemux->duration = 0;
1874 qtdemux->moof_offset = 0;
1875 qtdemux->chapters_track_id = 0;
1876 qtdemux->have_group_id = FALSE;
1877 qtdemux->group_id = G_MAXUINT;
1879 qtdemux->offset = 0;
1880 gst_adapter_clear (qtdemux->adapter);
1881 gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
1884 for (n = 0; n < qtdemux->n_streams; n++) {
1885 gst_qtdemux_stream_free (qtdemux, qtdemux->streams[n]);
1886 qtdemux->streams[n] = NULL;
1888 qtdemux->n_streams = 0;
1889 qtdemux->n_video_streams = 0;
1890 qtdemux->n_audio_streams = 0;
1891 qtdemux->n_sub_streams = 0;
1892 qtdemux->exposed = FALSE;
1893 qtdemux->fragmented = FALSE;
1894 qtdemux->mss_mode = FALSE;
1895 gst_caps_replace (&qtdemux->media_caps, NULL);
1896 qtdemux->timescale = 0;
1897 qtdemux->got_moov = FALSE;
1898 } else if (qtdemux->mss_mode) {
1899 for (n = 0; n < qtdemux->n_streams; n++)
1900 gst_qtdemux_stream_clear (qtdemux, qtdemux->streams[n]);
1902 for (n = 0; n < qtdemux->n_streams; n++) {
1903 qtdemux->streams[n]->sent_eos = FALSE;
1904 qtdemux->streams[n]->segment_seqnum = 0;
1905 qtdemux->streams[n]->time_position = 0;
1911 gst_qtdemux_handle_sink_event (GstPad * sinkpad, GstObject * parent,
1914 GstQTDemux *demux = GST_QTDEMUX (parent);
1915 gboolean res = TRUE;
1917 GST_LOG_OBJECT (demux, "handling %s event", GST_EVENT_TYPE_NAME (event));
1919 switch (GST_EVENT_TYPE (event)) {
1920 case GST_EVENT_SEGMENT:
1923 QtDemuxStream *stream;
1926 GstEvent *segment_event;
1928 /* some debug output */
1929 gst_event_copy_segment (event, &segment);
1930 GST_DEBUG_OBJECT (demux, "received newsegment %" GST_SEGMENT_FORMAT,
1933 if (segment.format == GST_FORMAT_TIME) {
1934 GST_DEBUG_OBJECT (demux, "new pending_newsegment");
1935 gst_event_replace (&demux->pending_newsegment, event);
1936 demux->upstream_newsegment = TRUE;
1938 GST_DEBUG_OBJECT (demux, "Not storing upstream newsegment, "
1939 "not in time format");
1941 /* chain will send initial newsegment after pads have been added */
1942 if (demux->state != QTDEMUX_STATE_MOVIE || !demux->n_streams) {
1943 GST_DEBUG_OBJECT (demux, "still starting, eating event");
1948 /* check if this matches a time seek we received previously
1949 * FIXME for backwards compatibility reasons we use the
1950 * seek_offset here to compare. In the future we might want to
1951 * change this to use the seqnum as it uniquely should identify
1952 * the segment that corresponds to the seek. */
1953 GST_DEBUG_OBJECT (demux, "Stored seek offset: %" G_GINT64_FORMAT
1954 ", received segment offset %" G_GINT64_FORMAT,
1955 demux->seek_offset, segment.start);
1956 if (segment.format == GST_FORMAT_BYTES
1957 && demux->seek_offset == segment.start) {
1958 GST_OBJECT_LOCK (demux);
1959 offset = segment.start;
1961 segment.format = GST_FORMAT_TIME;
1962 segment.start = demux->push_seek_start;
1963 segment.stop = demux->push_seek_stop;
1964 GST_DEBUG_OBJECT (demux, "Replaced segment with stored seek "
1965 "segment %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT,
1966 GST_TIME_ARGS (segment.start), GST_TIME_ARGS (segment.stop));
1967 GST_OBJECT_UNLOCK (demux);
1970 /* we only expect a BYTE segment, e.g. following a seek */
1971 if (segment.format == GST_FORMAT_BYTES) {
1972 if (GST_CLOCK_TIME_IS_VALID (segment.start)) {
1973 offset = segment.start;
1975 gst_qtdemux_find_sample (demux, segment.start, TRUE, FALSE, NULL,
1976 NULL, (gint64 *) & segment.start);
1977 if ((gint64) segment.start < 0)
1980 if (GST_CLOCK_TIME_IS_VALID (segment.stop)) {
1981 gst_qtdemux_find_sample (demux, segment.stop, FALSE, FALSE, NULL,
1982 NULL, (gint64 *) & segment.stop);
1983 /* keyframe seeking should already arrange for start >= stop,
1984 * but make sure in other rare cases */
1985 segment.stop = MAX (segment.stop, segment.start);
1987 } else if (segment.format == GST_FORMAT_TIME) {
1990 gst_qtdemux_push_event (demux, gst_event_ref (event));
1991 gst_event_new_new_segment_full (segment.update, segment.rate,
1992 segment.arate, GST_FORMAT_TIME, segment.start, segment.stop,
1994 gst_adapter_clear (demux->adapter);
1995 demux->neededbytes = 16;
1999 GST_DEBUG_OBJECT (demux, "unsupported segment format, ignoring");
2003 /* accept upstream's notion of segment and distribute along */
2004 segment.format = GST_FORMAT_TIME;
2005 segment.position = segment.time = segment.start;
2006 segment.duration = demux->segment.duration;
2007 segment.base = gst_segment_to_running_time (&demux->segment,
2008 GST_FORMAT_TIME, demux->segment.position);
2010 gst_segment_copy_into (&segment, &demux->segment);
2011 GST_DEBUG_OBJECT (demux, "Pushing newseg %" GST_SEGMENT_FORMAT, &segment);
2012 segment_event = gst_event_new_segment (&segment);
2013 gst_event_set_seqnum (segment_event, gst_event_get_seqnum (event));
2014 gst_qtdemux_push_event (demux, segment_event);
2016 /* clear leftover in current segment, if any */
2017 gst_adapter_clear (demux->adapter);
2018 /* set up streaming thread */
2019 gst_qtdemux_find_sample (demux, offset, TRUE, TRUE, &stream, &idx, NULL);
2020 demux->offset = offset;
2022 demux->todrop = stream->samples[idx].offset - offset;
2023 demux->neededbytes = demux->todrop + stream->samples[idx].size;
2025 /* set up for EOS */
2026 if (demux->upstream_newsegment) {
2027 demux->neededbytes = 16;
2029 demux->neededbytes = -1;
2034 gst_event_unref (event);
2038 case GST_EVENT_FLUSH_STOP:
2042 dur = demux->segment.duration;
2043 gst_qtdemux_reset (demux, FALSE);
2044 demux->segment.duration = dur;
2048 /* If we are in push mode, and get an EOS before we've seen any streams,
2049 * then error out - we have nowhere to send the EOS */
2050 if (!demux->pullbased) {
2052 gboolean has_valid_stream = FALSE;
2053 for (i = 0; i < demux->n_streams; i++) {
2054 if (demux->streams[i]->pad != NULL) {
2055 has_valid_stream = TRUE;
2059 if (!has_valid_stream)
2060 gst_qtdemux_post_no_playable_stream_error (demux);
2062 GST_DEBUG_OBJECT (demux, "Data still available after EOS: %u",
2063 (guint) gst_adapter_available (demux->adapter));
2064 if (gst_qtdemux_process_adapter (demux, TRUE) != GST_FLOW_OK) {
2070 case GST_EVENT_CAPS:{
2071 GstCaps *caps = NULL;
2073 gst_event_parse_caps (event, &caps);
2074 gst_qtdemux_setcaps (demux, caps);
2076 gst_event_unref (event);
2083 res = gst_pad_event_default (demux->sinkpad, parent, event) & res;
2091 gst_qtdemux_set_index (GstElement * element, GstIndex * index)
2093 GstQTDemux *demux = GST_QTDEMUX (element);
2095 GST_OBJECT_LOCK (demux);
2096 if (demux->element_index)
2097 gst_object_unref (demux->element_index);
2099 demux->element_index = gst_object_ref (index);
2101 demux->element_index = NULL;
2103 GST_OBJECT_UNLOCK (demux);
2104 /* object lock might be taken again */
2106 gst_index_get_writer_id (index, GST_OBJECT (element), &demux->index_id);
2107 GST_DEBUG_OBJECT (demux, "Set index %" GST_PTR_FORMAT "for writer id %d",
2108 demux->element_index, demux->index_id);
2112 gst_qtdemux_get_index (GstElement * element)
2114 GstIndex *result = NULL;
2115 GstQTDemux *demux = GST_QTDEMUX (element);
2117 GST_OBJECT_LOCK (demux);
2118 if (demux->element_index)
2119 result = gst_object_ref (demux->element_index);
2120 GST_OBJECT_UNLOCK (demux);
2122 GST_DEBUG_OBJECT (demux, "Returning index %" GST_PTR_FORMAT, result);
2129 gst_qtdemux_stbl_free (QtDemuxStream * stream)
2131 g_free ((gpointer) stream->stco.data);
2132 stream->stco.data = NULL;
2133 g_free ((gpointer) stream->stsz.data);
2134 stream->stsz.data = NULL;
2135 g_free ((gpointer) stream->stsc.data);
2136 stream->stsc.data = NULL;
2137 g_free ((gpointer) stream->stts.data);
2138 stream->stts.data = NULL;
2139 g_free ((gpointer) stream->stss.data);
2140 stream->stss.data = NULL;
2141 g_free ((gpointer) stream->stps.data);
2142 stream->stps.data = NULL;
2143 g_free ((gpointer) stream->ctts.data);
2144 stream->ctts.data = NULL;
2148 gst_qtdemux_stream_clear (GstQTDemux * qtdemux, QtDemuxStream * stream)
2150 if (stream->allocator)
2151 gst_object_unref (stream->allocator);
2152 while (stream->buffers) {
2153 gst_buffer_unref (GST_BUFFER_CAST (stream->buffers->data));
2154 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
2156 if (stream->rgb8_palette) {
2157 gst_memory_unref (stream->rgb8_palette);
2158 stream->rgb8_palette = NULL;
2160 g_free (stream->samples);
2161 stream->samples = NULL;
2162 g_free (stream->segments);
2163 stream->segments = NULL;
2164 if (stream->pending_tags)
2165 gst_tag_list_unref (stream->pending_tags);
2166 stream->pending_tags = NULL;
2167 g_free (stream->redirect_uri);
2168 stream->redirect_uri = NULL;
2169 /* free stbl sub-atoms */
2170 gst_qtdemux_stbl_free (stream);
2172 g_free (stream->ra_entries);
2173 stream->ra_entries = NULL;
2174 stream->n_ra_entries = 0;
2176 stream->sent_eos = FALSE;
2177 stream->segment_index = -1;
2178 stream->time_position = 0;
2179 stream->sample_index = -1;
2180 stream->stbl_index = -1;
2181 stream->n_samples = 0;
2182 stream->sparse = FALSE;
2186 gst_qtdemux_stream_free (GstQTDemux * qtdemux, QtDemuxStream * stream)
2188 gst_qtdemux_stream_clear (qtdemux, stream);
2190 gst_caps_unref (stream->caps);
2191 stream->caps = NULL;
2193 gst_element_remove_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
2194 gst_flow_combiner_remove_pad (qtdemux->flowcombiner, stream->pad);
2200 gst_qtdemux_remove_stream (GstQTDemux * qtdemux, int i)
2202 g_assert (i >= 0 && i < qtdemux->n_streams && qtdemux->streams[i] != NULL);
2204 gst_qtdemux_stream_free (qtdemux, qtdemux->streams[i]);
2205 qtdemux->streams[i] = qtdemux->streams[qtdemux->n_streams - 1];
2206 qtdemux->streams[qtdemux->n_streams - 1] = NULL;
2207 qtdemux->n_streams--;
2210 static GstStateChangeReturn
2211 gst_qtdemux_change_state (GstElement * element, GstStateChange transition)
2213 GstQTDemux *qtdemux = GST_QTDEMUX (element);
2214 GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
2216 switch (transition) {
2217 case GST_STATE_CHANGE_PAUSED_TO_READY:
2223 result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
2225 switch (transition) {
2226 case GST_STATE_CHANGE_PAUSED_TO_READY:{
2227 gst_qtdemux_reset (qtdemux, TRUE);
2238 qtdemux_parse_ftyp (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2240 /* counts as header data */
2241 qtdemux->header_size += length;
2243 /* only consider at least a sufficiently complete ftyp atom */
2247 qtdemux->major_brand = QT_FOURCC (buffer + 8);
2248 GST_DEBUG_OBJECT (qtdemux, "major brand: %" GST_FOURCC_FORMAT,
2249 GST_FOURCC_ARGS (qtdemux->major_brand));
2250 buf = qtdemux->comp_brands = gst_buffer_new_and_alloc (length - 16);
2251 gst_buffer_fill (buf, 0, buffer + 16, length - 16);
2256 qtdemux_handle_xmp_taglist (GstQTDemux * qtdemux, GstTagList * taglist,
2257 GstTagList * xmptaglist)
2259 /* Strip out bogus fields */
2261 if (gst_tag_list_get_scope (taglist) == GST_TAG_SCOPE_GLOBAL) {
2262 gst_tag_list_remove_tag (xmptaglist, GST_TAG_VIDEO_CODEC);
2263 gst_tag_list_remove_tag (xmptaglist, GST_TAG_AUDIO_CODEC);
2265 gst_tag_list_remove_tag (xmptaglist, GST_TAG_CONTAINER_FORMAT);
2268 GST_DEBUG_OBJECT (qtdemux, "Found XMP tags %" GST_PTR_FORMAT, xmptaglist);
2270 /* prioritize native tags using _KEEP mode */
2271 gst_tag_list_insert (taglist, xmptaglist, GST_TAG_MERGE_KEEP);
2272 gst_tag_list_unref (xmptaglist);
2277 qtdemux_parse_uuid (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2279 static const guint8 xmp_uuid[] = { 0xBE, 0x7A, 0xCF, 0xCB,
2280 0x97, 0xA9, 0x42, 0xE8,
2281 0x9C, 0x71, 0x99, 0x94,
2282 0x91, 0xE3, 0xAF, 0xAC
2284 static const guint8 playready_uuid[] = {
2285 0xd0, 0x8a, 0x4f, 0x18, 0x10, 0xf3, 0x4a, 0x82,
2286 0xb6, 0xc8, 0x32, 0xd8, 0xab, 0xa1, 0x83, 0xd3
2290 /* counts as header data */
2291 qtdemux->header_size += length;
2293 offset = (QT_UINT32 (buffer) == 0) ? 16 : 8;
2295 if (length <= offset + 16) {
2296 GST_DEBUG_OBJECT (qtdemux, "uuid atom is too short, skipping");
2300 if (memcmp (buffer + offset, xmp_uuid, 16) == 0) {
2302 GstTagList *taglist;
2304 buf = _gst_buffer_new_wrapped ((guint8 *) buffer + offset + 16,
2305 length - offset - 16, NULL);
2306 taglist = gst_tag_list_from_xmp_buffer (buf);
2307 gst_buffer_unref (buf);
2309 qtdemux_handle_xmp_taglist (qtdemux, qtdemux->tag_list, taglist);
2311 } else if (memcmp (buffer + offset, playready_uuid, 16) == 0) {
2313 const gunichar2 *s_utf16;
2316 len = GST_READ_UINT16_LE (buffer + offset + 0x30);
2317 s_utf16 = (const gunichar2 *) (buffer + offset + 0x32);
2318 contents = g_utf16_to_utf8 (s_utf16, len / 2, NULL, NULL, NULL);
2319 GST_ERROR_OBJECT (qtdemux, "contents: %s", contents);
2323 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT,
2324 (_("Cannot play stream because it is encrypted with PlayReady DRM.")),
2327 GST_DEBUG_OBJECT (qtdemux, "Ignoring unknown uuid: %08x-%08x-%08x-%08x",
2328 GST_READ_UINT32_LE (buffer + offset),
2329 GST_READ_UINT32_LE (buffer + offset + 4),
2330 GST_READ_UINT32_LE (buffer + offset + 8),
2331 GST_READ_UINT32_LE (buffer + offset + 12));
2336 qtdemux_parse_sidx (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2338 GstSidxParser sidx_parser;
2339 GstIsoffParserResult res;
2342 gst_isoff_sidx_parser_init (&sidx_parser);
2345 gst_isoff_sidx_parser_add_data (&sidx_parser, buffer, length, &consumed);
2346 GST_DEBUG_OBJECT (qtdemux, "sidx parse result: %d", res);
2347 if (res == GST_ISOFF_PARSER_DONE) {
2348 check_update_duration (qtdemux, sidx_parser.cumulative_pts);
2350 gst_isoff_sidx_parser_clear (&sidx_parser);
2353 /* caller verifies at least 8 bytes in buf */
2355 extract_initial_length_and_fourcc (const guint8 * data, guint size,
2356 guint64 * plength, guint32 * pfourcc)
2361 length = QT_UINT32 (data);
2362 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
2363 fourcc = QT_FOURCC (data + 4);
2364 GST_DEBUG ("atom type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
2367 length = G_MAXUINT32;
2368 } else if (length == 1 && size >= 16) {
2369 /* this means we have an extended size, which is the 64 bit value of
2370 * the next 8 bytes */
2371 length = QT_UINT64 (data + 8);
2372 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
2382 qtdemux_parse_mehd (GstQTDemux * qtdemux, GstByteReader * br)
2384 guint32 version = 0;
2385 GstClockTime duration = 0;
2387 if (!gst_byte_reader_get_uint32_be (br, &version))
2392 if (!gst_byte_reader_get_uint64_be (br, &duration))
2397 if (!gst_byte_reader_get_uint32_be (br, &dur))
2402 GST_INFO_OBJECT (qtdemux, "mehd duration: %" G_GUINT64_FORMAT, duration);
2403 qtdemux->duration = duration;
2409 GST_DEBUG_OBJECT (qtdemux, "parsing mehd failed");
2415 qtdemux_parse_trex (GstQTDemux * qtdemux, QtDemuxStream * stream,
2416 guint32 * ds_duration, guint32 * ds_size, guint32 * ds_flags)
2418 if (!stream->parsed_trex && qtdemux->moov_node) {
2420 GstByteReader trex_data;
2422 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
2424 trex = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_trex,
2427 guint32 id = 0, dur = 0, size = 0, flags = 0, dummy = 0;
2429 /* skip version/flags */
2430 if (!gst_byte_reader_skip (&trex_data, 4))
2432 if (!gst_byte_reader_get_uint32_be (&trex_data, &id))
2434 if (id != stream->track_id)
2436 /* sample description index; ignore */
2437 if (!gst_byte_reader_get_uint32_be (&trex_data, &dummy))
2439 if (!gst_byte_reader_get_uint32_be (&trex_data, &dur))
2441 if (!gst_byte_reader_get_uint32_be (&trex_data, &size))
2443 if (!gst_byte_reader_get_uint32_be (&trex_data, &flags))
2446 GST_DEBUG_OBJECT (qtdemux, "fragment defaults for stream %d; "
2447 "duration %d, size %d, flags 0x%x", stream->track_id,
2450 stream->parsed_trex = TRUE;
2451 stream->def_sample_duration = dur;
2452 stream->def_sample_size = size;
2453 stream->def_sample_flags = flags;
2456 /* iterate all siblings */
2457 trex = qtdemux_tree_get_sibling_by_type_full (trex, FOURCC_trex,
2463 *ds_duration = stream->def_sample_duration;
2464 *ds_size = stream->def_sample_size;
2465 *ds_flags = stream->def_sample_flags;
2467 /* even then, above values are better than random ... */
2468 if (G_UNLIKELY (!stream->parsed_trex)) {
2469 GST_WARNING_OBJECT (qtdemux,
2470 "failed to find fragment defaults for stream %d", stream->track_id);
2477 /* This method should be called whenever a more accurate duration might
2478 * have been found. It will update all relevant variables if/where needed
2481 check_update_duration (GstQTDemux * qtdemux, GstClockTime duration)
2485 GstClockTime prevdur;
2487 movdur = GSTTIME_TO_QTTIME (qtdemux, duration);
2489 if (movdur > qtdemux->duration) {
2490 prevdur = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
2491 GST_DEBUG_OBJECT (qtdemux,
2492 "Updating total duration to %" GST_TIME_FORMAT " was %" GST_TIME_FORMAT,
2493 GST_TIME_ARGS (duration), GST_TIME_ARGS (prevdur));
2494 qtdemux->duration = movdur;
2495 GST_DEBUG_OBJECT (qtdemux,
2496 "qtdemux->segment.duration: %" GST_TIME_FORMAT " .stop: %"
2497 GST_TIME_FORMAT, GST_TIME_ARGS (qtdemux->segment.duration),
2498 GST_TIME_ARGS (qtdemux->segment.stop));
2499 if (qtdemux->segment.duration == prevdur) {
2500 /* If the current segment has duration/stop identical to previous duration
2501 * update them also (because they were set at that point in time with
2502 * the wrong duration */
2503 /* We convert the value *from* the timescale version to avoid rounding errors */
2504 GstClockTime fixeddur = QTTIME_TO_GSTTIME (qtdemux, movdur);
2505 GST_DEBUG_OBJECT (qtdemux, "Updated segment.duration and segment.stop");
2506 qtdemux->segment.duration = fixeddur;
2507 qtdemux->segment.stop = fixeddur;
2510 for (i = 0; i < qtdemux->n_streams; i++) {
2511 QtDemuxStream *stream = qtdemux->streams[i];
2513 movdur = GSTTIME_TO_QTSTREAMTIME (stream, duration);
2514 if (movdur > stream->duration) {
2515 GST_DEBUG_OBJECT (qtdemux,
2516 "Updating stream #%d duration to %" GST_TIME_FORMAT, i,
2517 GST_TIME_ARGS (duration));
2518 stream->duration = movdur;
2519 if (stream->dummy_segment) {
2520 /* Update all dummy values to new duration */
2521 stream->segments[0].stop_time = duration;
2522 stream->segments[0].duration = duration;
2523 stream->segments[0].media_stop = duration;
2531 qtdemux_parse_trun (GstQTDemux * qtdemux, GstByteReader * trun,
2532 QtDemuxStream * stream, guint32 d_sample_duration, guint32 d_sample_size,
2533 guint32 d_sample_flags, gint64 moof_offset, gint64 moof_length,
2534 gint64 * base_offset, gint64 * running_offset, gint64 decode_ts)
2536 GstClockTime gst_ts = GST_CLOCK_TIME_NONE;
2538 gint32 data_offset = 0;
2539 guint32 flags = 0, first_flags = 0, samples_count = 0;
2542 guint entry_size, dur_offset, size_offset, flags_offset = 0, ct_offset = 0;
2543 QtDemuxSample *sample;
2544 gboolean ismv = FALSE;
2546 GST_LOG_OBJECT (qtdemux, "parsing trun stream %d; "
2547 "default dur %d, size %d, flags 0x%x, base offset %" G_GINT64_FORMAT ", "
2548 "decode ts %" G_GINT64_FORMAT, stream->track_id, d_sample_duration,
2549 d_sample_size, d_sample_flags, *base_offset, decode_ts);
2551 if (stream->pending_seek && moof_offset < stream->pending_seek->moof_offset) {
2552 GST_INFO_OBJECT (stream->pad, "skipping trun before seek target fragment");
2556 /* presence of stss or not can't really tell us much,
2557 * and flags and so on tend to be marginally reliable in these files */
2558 if (stream->subtype == FOURCC_soun) {
2559 GST_DEBUG_OBJECT (qtdemux,
2560 "sound track in fragmented file; marking all keyframes");
2561 stream->all_keyframe = TRUE;
2564 if (!gst_byte_reader_skip (trun, 1) ||
2565 !gst_byte_reader_get_uint24_be (trun, &flags))
2568 if (!gst_byte_reader_get_uint32_be (trun, &samples_count))
2571 if (flags & TR_DATA_OFFSET) {
2572 /* note this is really signed */
2573 if (!gst_byte_reader_get_int32_be (trun, &data_offset))
2575 GST_LOG_OBJECT (qtdemux, "trun data offset %d", data_offset);
2576 /* default base offset = first byte of moof */
2577 if (*base_offset == -1) {
2578 GST_LOG_OBJECT (qtdemux, "base_offset at moof");
2579 *base_offset = moof_offset;
2581 *running_offset = *base_offset + data_offset;
2583 /* if no offset at all, that would mean data starts at moof start,
2584 * which is a bit wrong and is ismv crappy way, so compensate
2585 * assuming data is in mdat following moof */
2586 if (*base_offset == -1) {
2587 *base_offset = moof_offset + moof_length + 8;
2588 GST_LOG_OBJECT (qtdemux, "base_offset assumed in mdat after moof");
2591 if (*running_offset == -1)
2592 *running_offset = *base_offset;
2595 GST_LOG_OBJECT (qtdemux, "running offset now %" G_GINT64_FORMAT,
2597 GST_LOG_OBJECT (qtdemux, "trun offset %d, flags 0x%x, entries %d",
2598 data_offset, flags, samples_count);
2600 if (flags & TR_FIRST_SAMPLE_FLAGS) {
2601 if (G_UNLIKELY (flags & TR_SAMPLE_FLAGS)) {
2602 GST_DEBUG_OBJECT (qtdemux,
2603 "invalid flags; SAMPLE and FIRST_SAMPLE present, discarding latter");
2604 flags ^= TR_FIRST_SAMPLE_FLAGS;
2606 if (!gst_byte_reader_get_uint32_be (trun, &first_flags))
2608 GST_LOG_OBJECT (qtdemux, "first flags: 0x%x", first_flags);
2612 /* FIXME ? spec says other bits should also be checked to determine
2613 * entry size (and prefix size for that matter) */
2615 dur_offset = size_offset = 0;
2616 if (flags & TR_SAMPLE_DURATION) {
2617 GST_LOG_OBJECT (qtdemux, "entry duration present");
2618 dur_offset = entry_size;
2621 if (flags & TR_SAMPLE_SIZE) {
2622 GST_LOG_OBJECT (qtdemux, "entry size present");
2623 size_offset = entry_size;
2626 if (flags & TR_SAMPLE_FLAGS) {
2627 GST_LOG_OBJECT (qtdemux, "entry flags present");
2628 flags_offset = entry_size;
2631 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
2632 GST_LOG_OBJECT (qtdemux, "entry ct offset present");
2633 ct_offset = entry_size;
2637 if (!qt_atom_parser_has_chunks (trun, samples_count, entry_size))
2639 data = (guint8 *) gst_byte_reader_peek_data_unchecked (trun);
2641 if (stream->n_samples >=
2642 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample))
2645 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
2646 stream->n_samples, (guint) sizeof (QtDemuxSample),
2647 stream->n_samples * sizeof (QtDemuxSample) / (1024.0 * 1024.0));
2649 /* create a new array of samples if it's the first sample parsed */
2650 if (stream->n_samples == 0)
2651 stream->samples = g_try_new0 (QtDemuxSample, samples_count);
2652 /* or try to reallocate it with space enough to insert the new samples */
2654 stream->samples = g_try_renew (QtDemuxSample, stream->samples,
2655 stream->n_samples + samples_count);
2656 if (stream->samples == NULL)
2659 if (qtdemux->fragment_start != -1) {
2660 timestamp = GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->fragment_start);
2661 qtdemux->fragment_start = -1;
2663 if (G_UNLIKELY (stream->n_samples == 0)) {
2664 if (decode_ts > 0) {
2665 timestamp = decode_ts;
2666 } else if (stream->pending_seek != NULL) {
2667 /* if we don't have a timestamp from a tfdt box, we'll use the one
2668 * from the mfra seek table */
2669 GST_INFO_OBJECT (stream->pad, "pending seek ts = %" GST_TIME_FORMAT,
2670 GST_TIME_ARGS (stream->pending_seek->ts));
2672 /* FIXME: this is not fully correct, the timestamp refers to the random
2673 * access sample refered to in the tfra entry, which may not necessarily
2674 * be the first sample in the tfrag/trun (but hopefully/usually is) */
2675 timestamp = GSTTIME_TO_QTSTREAMTIME (stream, stream->pending_seek->ts);
2680 gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
2681 GST_INFO_OBJECT (stream->pad, "first sample ts %" GST_TIME_FORMAT,
2682 GST_TIME_ARGS (gst_ts));
2684 /* subsequent fragments extend stream */
2686 stream->samples[stream->n_samples - 1].timestamp +
2687 stream->samples[stream->n_samples - 1].duration;
2689 gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
2690 GST_INFO_OBJECT (qtdemux, "first sample ts %" GST_TIME_FORMAT
2691 " (extends previous samples)", GST_TIME_ARGS (gst_ts));
2695 sample = stream->samples + stream->n_samples;
2696 for (i = 0; i < samples_count; i++) {
2697 guint32 dur, size, sflags, ct;
2699 /* first read sample data */
2700 if (flags & TR_SAMPLE_DURATION) {
2701 dur = QT_UINT32 (data + dur_offset);
2703 dur = d_sample_duration;
2705 if (flags & TR_SAMPLE_SIZE) {
2706 size = QT_UINT32 (data + size_offset);
2708 size = d_sample_size;
2710 if (flags & TR_FIRST_SAMPLE_FLAGS) {
2712 sflags = first_flags;
2714 sflags = d_sample_flags;
2716 } else if (flags & TR_SAMPLE_FLAGS) {
2717 sflags = QT_UINT32 (data + flags_offset);
2719 sflags = d_sample_flags;
2721 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
2722 ct = QT_UINT32 (data + ct_offset);
2728 /* fill the sample information */
2729 sample->offset = *running_offset;
2730 sample->pts_offset = ct;
2731 sample->size = size;
2732 sample->timestamp = timestamp;
2733 sample->duration = dur;
2734 /* sample-is-difference-sample */
2735 /* ismv seems to use 0x40 for keyframe, 0xc0 for non-keyframe,
2736 * now idea how it relates to bitfield other than massive LE/BE confusion */
2737 sample->keyframe = ismv ? ((sflags & 0xff) == 0x40) : !(sflags & 0x10000);
2738 *running_offset += size;
2743 /* Update total duration if needed */
2744 check_update_duration (qtdemux, QTSTREAMTIME_TO_GSTTIME (stream, timestamp));
2746 stream->n_samples += samples_count;
2748 if (stream->pending_seek != NULL)
2749 stream->pending_seek = NULL;
2755 GST_WARNING_OBJECT (qtdemux, "failed to parse trun");
2760 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
2766 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
2767 "be larger than %uMB (broken file?)", stream->n_samples,
2768 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
2773 /* find stream with @id */
2774 static inline QtDemuxStream *
2775 qtdemux_find_stream (GstQTDemux * qtdemux, guint32 id)
2777 QtDemuxStream *stream;
2781 if (G_UNLIKELY (!id)) {
2782 GST_DEBUG_OBJECT (qtdemux, "invalid track id 0");
2786 /* try to get it fast and simple */
2787 if (G_LIKELY (id <= qtdemux->n_streams)) {
2788 stream = qtdemux->streams[id - 1];
2789 if (G_LIKELY (stream->track_id == id))
2793 /* linear search otherwise */
2794 for (i = 0; i < qtdemux->n_streams; i++) {
2795 stream = qtdemux->streams[i];
2796 if (stream->track_id == id)
2799 if (qtdemux->mss_mode) {
2800 /* mss should have only 1 stream anyway */
2801 return qtdemux->streams[0];
2808 qtdemux_parse_mfhd (GstQTDemux * qtdemux, GstByteReader * mfhd,
2809 guint32 * fragment_number)
2811 if (!gst_byte_reader_skip (mfhd, 4))
2813 if (!gst_byte_reader_get_uint32_be (mfhd, fragment_number))
2818 GST_WARNING_OBJECT (qtdemux, "Failed to parse mfhd atom");
2824 qtdemux_parse_tfhd (GstQTDemux * qtdemux, GstByteReader * tfhd,
2825 QtDemuxStream ** stream, guint32 * default_sample_duration,
2826 guint32 * default_sample_size, guint32 * default_sample_flags,
2827 gint64 * base_offset)
2830 guint32 track_id = 0;
2832 if (!gst_byte_reader_skip (tfhd, 1) ||
2833 !gst_byte_reader_get_uint24_be (tfhd, &flags))
2836 if (!gst_byte_reader_get_uint32_be (tfhd, &track_id))
2839 *stream = qtdemux_find_stream (qtdemux, track_id);
2840 if (G_UNLIKELY (!*stream))
2841 goto unknown_stream;
2843 if (flags & TF_BASE_DATA_OFFSET)
2844 if (!gst_byte_reader_get_uint64_be (tfhd, (guint64 *) base_offset))
2847 /* obtain stream defaults */
2848 qtdemux_parse_trex (qtdemux, *stream,
2849 default_sample_duration, default_sample_size, default_sample_flags);
2851 /* FIXME: Handle TF_SAMPLE_DESCRIPTION_INDEX properly */
2852 if (flags & TF_SAMPLE_DESCRIPTION_INDEX)
2853 if (!gst_byte_reader_skip (tfhd, 4))
2856 if (flags & TF_DEFAULT_SAMPLE_DURATION)
2857 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_duration))
2860 if (flags & TF_DEFAULT_SAMPLE_SIZE)
2861 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_size))
2864 if (flags & TF_DEFAULT_SAMPLE_FLAGS)
2865 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_flags))
2872 GST_WARNING_OBJECT (qtdemux, "invalid track fragment header");
2877 GST_DEBUG_OBJECT (qtdemux, "unknown stream in tfhd");
2883 qtdemux_parse_tfdt (GstQTDemux * qtdemux, GstByteReader * br,
2884 guint64 * decode_time)
2886 guint32 version = 0;
2888 if (!gst_byte_reader_get_uint32_be (br, &version))
2893 if (!gst_byte_reader_get_uint64_be (br, decode_time))
2896 guint32 dec_time = 0;
2897 if (!gst_byte_reader_get_uint32_be (br, &dec_time))
2899 *decode_time = dec_time;
2902 GST_INFO_OBJECT (qtdemux, "Track fragment decode time: %" G_GUINT64_FORMAT,
2909 GST_DEBUG_OBJECT (qtdemux, "parsing tfdt failed");
2915 qtdemux_parse_moof (GstQTDemux * qtdemux, const guint8 * buffer, guint length,
2916 guint64 moof_offset, QtDemuxStream * stream)
2918 GNode *moof_node, *traf_node, *tfhd_node, *trun_node, *tfdt_node, *mfhd_node;
2919 GstByteReader mfhd_data, trun_data, tfhd_data, tfdt_data;
2920 guint32 ds_size = 0, ds_duration = 0, ds_flags = 0;
2921 gint64 base_offset, running_offset;
2924 /* NOTE @stream ignored */
2926 moof_node = g_node_new ((guint8 *) buffer);
2927 qtdemux_parse_node (qtdemux, moof_node, buffer, length);
2928 qtdemux_node_dump (qtdemux, moof_node);
2930 /* Get fragment number from mfhd and check it's valid */
2932 qtdemux_tree_get_child_by_type_full (moof_node, FOURCC_mfhd, &mfhd_data);
2933 if (mfhd_node == NULL)
2935 if (!qtdemux_parse_mfhd (qtdemux, &mfhd_data, &frag_num))
2937 GST_DEBUG_OBJECT (qtdemux, "Fragment #%d", frag_num);
2939 /* unknown base_offset to start with */
2940 base_offset = running_offset = -1;
2941 traf_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_traf);
2943 guint64 decode_time = 0;
2945 /* Fragment Header node */
2947 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfhd,
2951 if (!qtdemux_parse_tfhd (qtdemux, &tfhd_data, &stream, &ds_duration,
2952 &ds_size, &ds_flags, &base_offset))
2955 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfdt,
2958 GstClockTime decode_time_ts;
2960 /* We'll use decode_time to interpolate timestamps
2961 * in case the input timestamps are missing */
2962 qtdemux_parse_tfdt (qtdemux, &tfdt_data, &decode_time);
2964 decode_time_ts = QTSTREAMTIME_TO_GSTTIME (stream, decode_time);
2966 GST_DEBUG_OBJECT (qtdemux, "decode time %" G_GINT64_FORMAT
2967 " (%" GST_TIME_FORMAT ")", decode_time,
2968 GST_TIME_ARGS (decode_time_ts));
2971 if (G_UNLIKELY (!stream)) {
2972 /* we lost track of offset, we'll need to regain it,
2973 * but can delay complaining until later or avoid doing so altogether */
2977 if (G_UNLIKELY (base_offset < -1))
2979 /* Track Run node */
2981 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_trun,
2984 qtdemux_parse_trun (qtdemux, &trun_data, stream,
2985 ds_duration, ds_size, ds_flags, moof_offset, length, &base_offset,
2986 &running_offset, decode_time);
2987 /* iterate all siblings */
2988 trun_node = qtdemux_tree_get_sibling_by_type_full (trun_node, FOURCC_trun,
2991 /* if no new base_offset provided for next traf,
2992 * base is end of current traf */
2993 base_offset = running_offset;
2994 running_offset = -1;
2996 /* iterate all siblings */
2997 traf_node = qtdemux_tree_get_sibling_by_type (traf_node, FOURCC_traf);
2999 g_node_destroy (moof_node);
3004 GST_DEBUG_OBJECT (qtdemux, "missing tfhd box");
3009 GST_DEBUG_OBJECT (qtdemux, "Missing mfhd box");
3014 GST_DEBUG_OBJECT (qtdemux, "lost offset");
3019 g_node_destroy (moof_node);
3020 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
3021 (_("This file is corrupt and cannot be played.")), (NULL));
3027 /* might be used if some day we actually use mfra & co
3028 * for random access to fragments,
3029 * but that will require quite some modifications and much less relying
3030 * on a sample array */
3034 qtdemux_parse_tfra (GstQTDemux * qtdemux, GNode * tfra_node)
3036 QtDemuxStream *stream;
3037 guint32 ver_flags, track_id, len, num_entries, i;
3038 guint value_size, traf_size, trun_size, sample_size;
3039 guint64 time = 0, moof_offset = 0;
3041 GstBuffer *buf = NULL;
3046 gst_byte_reader_init (&tfra, tfra_node->data, QT_UINT32 (tfra_node->data));
3048 if (!gst_byte_reader_skip (&tfra, 8))
3051 if (!gst_byte_reader_get_uint32_be (&tfra, &ver_flags))
3054 if (!gst_byte_reader_get_uint32_be (&tfra, &track_id)
3055 || !gst_byte_reader_get_uint32_be (&tfra, &len)
3056 || !gst_byte_reader_get_uint32_be (&tfra, &num_entries))
3059 GST_DEBUG_OBJECT (qtdemux, "parsing tfra box for track id %u", track_id);
3061 stream = qtdemux_find_stream (qtdemux, track_id);
3063 goto unknown_trackid;
3065 value_size = ((ver_flags >> 24) == 1) ? sizeof (guint64) : sizeof (guint32);
3066 sample_size = (len & 3) + 1;
3067 trun_size = ((len & 12) >> 2) + 1;
3068 traf_size = ((len & 48) >> 4) + 1;
3070 GST_DEBUG_OBJECT (qtdemux, "%u entries, sizes: value %u, traf %u, trun %u, "
3071 "sample %u", num_entries, value_size, traf_size, trun_size, sample_size);
3073 if (num_entries == 0)
3076 if (!qt_atom_parser_has_chunks (&tfra, num_entries,
3077 value_size + value_size + traf_size + trun_size + sample_size))
3080 g_free (stream->ra_entries);
3081 stream->ra_entries = g_new (QtDemuxRandomAccessEntry, num_entries);
3082 stream->n_ra_entries = num_entries;
3084 for (i = 0; i < num_entries; i++) {
3085 qt_atom_parser_get_offset (&tfra, value_size, &time);
3086 qt_atom_parser_get_offset (&tfra, value_size, &moof_offset);
3087 qt_atom_parser_get_uint_with_size_unchecked (&tfra, traf_size);
3088 qt_atom_parser_get_uint_with_size_unchecked (&tfra, trun_size);
3089 qt_atom_parser_get_uint_with_size_unchecked (&tfra, sample_size);
3091 time = QTSTREAMTIME_TO_GSTTIME (stream, time);
3093 GST_LOG_OBJECT (qtdemux, "fragment time: %" GST_TIME_FORMAT ", "
3094 " moof_offset: %" G_GUINT64_FORMAT, GST_TIME_ARGS (time), moof_offset);
3096 stream->ra_entries[i].ts = time;
3097 stream->ra_entries[i].moof_offset = moof_offset;
3099 /* don't want to go through the entire file and read all moofs at startup */
3101 ret = gst_qtdemux_pull_atom (qtdemux, moof_offset, 0, &buf);
3102 if (ret != GST_FLOW_OK)
3104 qtdemux_parse_moof (qtdemux, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf),
3105 moof_offset, stream);
3106 gst_buffer_unref (buf);
3110 check_update_duration (qtdemux, time);
3117 GST_WARNING_OBJECT (qtdemux, "Couldn't find stream for track %u", track_id);
3122 GST_WARNING_OBJECT (qtdemux, "broken traf box, ignoring");
3127 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
3133 qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux)
3135 GstMapInfo mfro_map = GST_MAP_INFO_INIT;
3136 GstMapInfo mfra_map = GST_MAP_INFO_INIT;
3137 GstBuffer *mfro = NULL, *mfra = NULL;
3139 gboolean ret = FALSE;
3140 GNode *mfra_node, *tfra_node;
3141 guint64 mfra_offset = 0;
3142 guint32 fourcc, mfra_size;
3145 /* query upstream size in bytes */
3146 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &len))
3147 goto size_query_failed;
3149 /* mfro box should be at the very end of the file */
3150 flow = gst_qtdemux_pull_atom (qtdemux, len - 16, 16, &mfro);
3151 if (flow != GST_FLOW_OK)
3154 gst_buffer_map (mfro, &mfro_map, GST_MAP_READ);
3156 fourcc = QT_FOURCC (mfro_map.data + 4);
3157 if (fourcc != FOURCC_mfro)
3160 GST_INFO_OBJECT (qtdemux, "Found mfro box");
3161 if (mfro_map.size < 16)
3162 goto invalid_mfro_size;
3164 mfra_size = QT_UINT32 (mfro_map.data + 12);
3165 if (mfra_size >= len)
3166 goto invalid_mfra_size;
3168 mfra_offset = len - mfra_size;
3170 GST_INFO_OBJECT (qtdemux, "mfra offset: %" G_GUINT64_FORMAT ", size %u",
3171 mfra_offset, mfra_size);
3173 /* now get and parse mfra box */
3174 flow = gst_qtdemux_pull_atom (qtdemux, mfra_offset, mfra_size, &mfra);
3175 if (flow != GST_FLOW_OK)
3178 gst_buffer_map (mfra, &mfra_map, GST_MAP_READ);
3180 mfra_node = g_node_new ((guint8 *) mfra_map.data);
3181 qtdemux_parse_node (qtdemux, mfra_node, mfra_map.data, mfra_map.size);
3183 tfra_node = qtdemux_tree_get_child_by_type (mfra_node, FOURCC_tfra);
3186 qtdemux_parse_tfra (qtdemux, tfra_node);
3187 /* iterate all siblings */
3188 tfra_node = qtdemux_tree_get_sibling_by_type (tfra_node, FOURCC_tfra);
3190 g_node_destroy (mfra_node);
3192 GST_INFO_OBJECT (qtdemux, "parsed movie fragment random access box (mfra)");
3198 if (mfro_map.memory != NULL)
3199 gst_buffer_unmap (mfro, &mfro_map);
3200 gst_buffer_unref (mfro);
3203 if (mfra_map.memory != NULL)
3204 gst_buffer_unmap (mfra, &mfra_map);
3205 gst_buffer_unref (mfra);
3212 GST_WARNING_OBJECT (qtdemux, "could not query upstream size");
3217 GST_WARNING_OBJECT (qtdemux, "mfro size is too small");
3222 GST_WARNING_OBJECT (qtdemux, "mfra_size in mfro box is invalid");
3227 GST_WARNING_OBJECT (qtdemux, "bogus mfra offset or size, broken file");
3232 static GstFlowReturn
3233 gst_qtdemux_loop_state_header (GstQTDemux * qtdemux)
3237 GstBuffer *buf = NULL;
3238 GstFlowReturn ret = GST_FLOW_OK;
3239 guint64 cur_offset = qtdemux->offset;
3242 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, 16, &buf);
3243 if (G_UNLIKELY (ret != GST_FLOW_OK))
3245 gst_buffer_map (buf, &map, GST_MAP_READ);
3246 if (G_LIKELY (map.size >= 8))
3247 extract_initial_length_and_fourcc (map.data, map.size, &length, &fourcc);
3248 gst_buffer_unmap (buf, &map);
3249 gst_buffer_unref (buf);
3251 /* maybe we already got most we needed, so only consider this eof */
3252 if (G_UNLIKELY (length == 0)) {
3253 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
3254 (_("Invalid atom size.")),
3255 ("Header atom '%" GST_FOURCC_FORMAT "' has empty length",
3256 GST_FOURCC_ARGS (fourcc)));
3263 /* record for later parsing when needed */
3264 if (!qtdemux->moof_offset) {
3265 qtdemux->moof_offset = qtdemux->offset;
3267 if (qtdemux_pull_mfro_mfra (qtdemux)) {
3270 if (qtdemux->got_moov) {
3271 GST_INFO_OBJECT (qtdemux, "moof header, got moov, done with headers");
3282 GST_LOG_OBJECT (qtdemux,
3283 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
3284 GST_FOURCC_ARGS (fourcc), cur_offset);
3285 qtdemux->offset += length;
3290 GstBuffer *moov = NULL;
3292 if (qtdemux->got_moov) {
3293 GST_DEBUG_OBJECT (qtdemux, "Skipping moov atom as we have one already");
3294 qtdemux->offset += length;
3298 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, length, &moov);
3299 if (ret != GST_FLOW_OK)
3301 gst_buffer_map (moov, &map, GST_MAP_READ);
3303 if (length != map.size) {
3304 /* Some files have a 'moov' atom at the end of the file which contains
3305 * a terminal 'free' atom where the body of the atom is missing.
3306 * Check for, and permit, this special case.
3308 if (map.size >= 8) {
3309 guint8 *final_data = map.data + (map.size - 8);
3310 guint32 final_length = QT_UINT32 (final_data);
3311 guint32 final_fourcc = QT_FOURCC (final_data + 4);
3313 if (final_fourcc == FOURCC_free
3314 && map.size + final_length - 8 == length) {
3315 /* Ok, we've found that special case. Allocate a new buffer with
3316 * that free atom actually present. */
3317 GstBuffer *newmoov = gst_buffer_new_and_alloc (length);
3318 gst_buffer_fill (newmoov, 0, map.data, map.size);
3319 gst_buffer_memset (newmoov, map.size, 0, final_length - 8);
3320 gst_buffer_unmap (moov, &map);
3321 gst_buffer_unref (moov);
3323 gst_buffer_map (moov, &map, GST_MAP_READ);
3328 if (length != map.size) {
3329 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
3330 (_("This file is incomplete and cannot be played.")),
3331 ("We got less than expected (received %" G_GSIZE_FORMAT
3332 ", wanted %u, offset %" G_GUINT64_FORMAT ")", map.size,
3333 (guint) length, cur_offset));
3334 gst_buffer_unmap (moov, &map);
3335 gst_buffer_unref (moov);
3336 ret = GST_FLOW_ERROR;
3339 qtdemux->offset += length;
3341 qtdemux_parse_moov (qtdemux, map.data, length);
3342 qtdemux_node_dump (qtdemux, qtdemux->moov_node);
3344 qtdemux_parse_tree (qtdemux);
3345 g_node_destroy (qtdemux->moov_node);
3346 gst_buffer_unmap (moov, &map);
3347 gst_buffer_unref (moov);
3348 qtdemux->moov_node = NULL;
3349 qtdemux->got_moov = TRUE;
3355 GstBuffer *ftyp = NULL;
3357 /* extract major brand; might come in handy for ISO vs QT issues */
3358 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &ftyp);
3359 if (ret != GST_FLOW_OK)
3361 qtdemux->offset += length;
3362 gst_buffer_map (ftyp, &map, GST_MAP_READ);
3363 qtdemux_parse_ftyp (qtdemux, map.data, map.size);
3364 gst_buffer_unmap (ftyp, &map);
3365 gst_buffer_unref (ftyp);
3370 GstBuffer *uuid = NULL;
3372 /* uuid are extension atoms */
3373 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &uuid);
3374 if (ret != GST_FLOW_OK)
3376 qtdemux->offset += length;
3377 gst_buffer_map (uuid, &map, GST_MAP_READ);
3378 qtdemux_parse_uuid (qtdemux, map.data, map.size);
3379 gst_buffer_unmap (uuid, &map);
3380 gst_buffer_unref (uuid);
3385 GstBuffer *sidx = NULL;
3386 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &sidx);
3387 if (ret != GST_FLOW_OK)
3389 qtdemux->offset += length;
3390 gst_buffer_map (sidx, &map, GST_MAP_READ);
3391 qtdemux_parse_sidx (qtdemux, map.data, map.size);
3392 gst_buffer_unmap (sidx, &map);
3393 gst_buffer_unref (sidx);
3398 GstBuffer *unknown = NULL;
3400 GST_LOG_OBJECT (qtdemux,
3401 "unknown %08x '%" GST_FOURCC_FORMAT "' of size %" G_GUINT64_FORMAT
3402 " at %" G_GUINT64_FORMAT, fourcc, GST_FOURCC_ARGS (fourcc), length,
3404 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &unknown);
3405 if (ret != GST_FLOW_OK)
3407 gst_buffer_map (unknown, &map, GST_MAP_READ);
3408 GST_MEMDUMP ("Unknown tag", map.data, map.size);
3409 gst_buffer_unmap (unknown, &map);
3410 gst_buffer_unref (unknown);
3411 qtdemux->offset += length;
3417 if (ret == GST_FLOW_EOS && (qtdemux->got_moov || qtdemux->media_caps)) {
3418 /* digested all data, show what we have */
3419 qtdemux_prepare_streams (qtdemux);
3420 ret = qtdemux_expose_streams (qtdemux);
3422 qtdemux->state = QTDEMUX_STATE_MOVIE;
3423 GST_DEBUG_OBJECT (qtdemux, "switching state to STATE_MOVIE (%d)",
3430 /* Seeks to the previous keyframe of the indexed stream and
3431 * aligns other streams with respect to the keyframe timestamp
3432 * of indexed stream. Only called in case of Reverse Playback
3434 static GstFlowReturn
3435 gst_qtdemux_seek_to_previous_keyframe (GstQTDemux * qtdemux)
3438 guint32 seg_idx = 0, k_index = 0;
3439 guint32 ref_seg_idx, ref_k_index;
3440 GstClockTime k_pos = 0, last_stop = 0;
3441 QtDemuxSegment *seg = NULL;
3442 QtDemuxStream *ref_str = NULL;
3443 guint64 seg_media_start_mov; /* segment media start time in mov format */
3446 /* Now we choose an arbitrary stream, get the previous keyframe timestamp
3447 * and finally align all the other streams on that timestamp with their
3448 * respective keyframes */
3449 for (n = 0; n < qtdemux->n_streams; n++) {
3450 QtDemuxStream *str = qtdemux->streams[n];
3452 /* No candidate yet, take the first stream */
3458 /* So that stream has a segment, we prefer video streams */
3459 if (str->subtype == FOURCC_vide) {
3465 if (G_UNLIKELY (!ref_str)) {
3466 GST_DEBUG_OBJECT (qtdemux, "couldn't find any stream");
3470 if (G_UNLIKELY (!ref_str->from_sample)) {
3471 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of the file");
3475 /* So that stream has been playing from from_sample to to_sample. We will
3476 * get the timestamp of the previous sample and search for a keyframe before
3477 * that. For audio streams we do an arbitrary jump in the past (10 samples) */
3478 if (ref_str->subtype == FOURCC_vide) {
3479 k_index = gst_qtdemux_find_keyframe (qtdemux, ref_str,
3480 ref_str->from_sample - 1);
3482 if (ref_str->from_sample >= 10)
3483 k_index = ref_str->from_sample - 10;
3489 ref_str->samples[k_index].timestamp +
3490 ref_str->samples[k_index].pts_offset;
3492 /* get current segment for that stream */
3493 seg = &ref_str->segments[ref_str->segment_index];
3494 /* Use segment start in original timescale for comparisons */
3495 seg_media_start_mov = seg->trak_media_start;
3497 GST_LOG_OBJECT (qtdemux, "keyframe index %u ts %" G_GUINT64_FORMAT
3498 " seg start %" G_GUINT64_FORMAT " %" GST_TIME_FORMAT "\n",
3499 k_index, target_ts, seg_media_start_mov,
3500 GST_TIME_ARGS (seg->media_start));
3502 /* Crawl back through segments to find the one containing this I frame */
3503 while (target_ts < seg_media_start_mov) {
3504 GST_DEBUG_OBJECT (qtdemux,
3505 "keyframe position (sample %u) is out of segment %u " " target %"
3506 G_GUINT64_FORMAT " seg start %" G_GUINT64_FORMAT, k_index,
3507 ref_str->segment_index, target_ts, seg_media_start_mov);
3509 if (G_UNLIKELY (!ref_str->segment_index)) {
3510 /* Reached first segment, let's consider it's EOS */
3513 ref_str->segment_index--;
3514 seg = &ref_str->segments[ref_str->segment_index];
3515 /* Use segment start in original timescale for comparisons */
3516 seg_media_start_mov = seg->trak_media_start;
3518 /* Calculate time position of the keyframe and where we should stop */
3520 QTSTREAMTIME_TO_GSTTIME (ref_str,
3521 target_ts - seg->trak_media_start) + seg->time;
3523 QTSTREAMTIME_TO_GSTTIME (ref_str,
3524 ref_str->samples[ref_str->from_sample].timestamp -
3525 seg->trak_media_start) + seg->time;
3527 GST_DEBUG_OBJECT (qtdemux, "preferred stream played from sample %u, "
3528 "now going to sample %u (pts %" GST_TIME_FORMAT ")", ref_str->from_sample,
3529 k_index, GST_TIME_ARGS (k_pos));
3531 /* Set last_stop with the keyframe timestamp we pushed of that stream */
3532 qtdemux->segment.position = last_stop;
3533 GST_DEBUG_OBJECT (qtdemux, "last_stop now is %" GST_TIME_FORMAT,
3534 GST_TIME_ARGS (last_stop));
3536 if (G_UNLIKELY (last_stop < qtdemux->segment.start)) {
3537 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of segment");
3541 ref_seg_idx = ref_str->segment_index;
3542 ref_k_index = k_index;
3544 /* Align them all on this */
3545 for (n = 0; n < qtdemux->n_streams; n++) {
3547 GstClockTime seg_time = 0;
3548 QtDemuxStream *str = qtdemux->streams[n];
3550 /* aligning reference stream again might lead to backing up to yet another
3551 * keyframe (due to timestamp rounding issues),
3552 * potentially putting more load on downstream; so let's try to avoid */
3553 if (str == ref_str) {
3554 seg_idx = ref_seg_idx;
3555 seg = &str->segments[seg_idx];
3556 k_index = ref_k_index;
3557 GST_DEBUG_OBJECT (qtdemux, "reference stream %d segment %d, "
3558 "sample at index %d", n, ref_str->segment_index, k_index);
3560 seg_idx = gst_qtdemux_find_segment (qtdemux, str, k_pos);
3561 GST_DEBUG_OBJECT (qtdemux,
3562 "stream %d align segment %d for keyframe pos %" GST_TIME_FORMAT, n,
3563 seg_idx, GST_TIME_ARGS (k_pos));
3565 /* get segment and time in the segment */
3566 seg = &str->segments[seg_idx];
3567 seg_time = k_pos - seg->time;
3569 /* get the media time in the segment.
3570 * No adjustment for empty "filler" segments */
3571 if (seg->media_start != GST_CLOCK_TIME_NONE)
3572 seg_time += seg->media_start;
3574 /* get the index of the sample with media time */
3575 index = gst_qtdemux_find_index_linear (qtdemux, str, seg_time);
3576 GST_DEBUG_OBJECT (qtdemux,
3577 "stream %d sample for %" GST_TIME_FORMAT " at %u", n,
3578 GST_TIME_ARGS (seg_time), index);
3580 /* find previous keyframe */
3581 k_index = gst_qtdemux_find_keyframe (qtdemux, str, index);
3584 /* Remember until where we want to go */
3585 str->to_sample = str->from_sample - 1;
3586 /* Define our time position */
3588 str->samples[k_index].timestamp + str->samples[k_index].pts_offset;
3589 str->time_position = QTSTREAMTIME_TO_GSTTIME (str, target_ts) + seg->time;
3590 if (seg->media_start != GST_CLOCK_TIME_NONE)
3591 str->time_position -= seg->media_start;
3593 /* Now seek back in time */
3594 gst_qtdemux_move_stream (qtdemux, str, k_index);
3595 GST_DEBUG_OBJECT (qtdemux, "stream %d keyframe at %u, time position %"
3596 GST_TIME_FORMAT " playing from sample %u to %u", n, k_index,
3597 GST_TIME_ARGS (str->time_position), str->from_sample, str->to_sample);
3603 return GST_FLOW_EOS;
3606 /* activate the given segment number @seg_idx of @stream at time @offset.
3607 * @offset is an absolute global position over all the segments.
3609 * This will push out a NEWSEGMENT event with the right values and
3610 * position the stream index to the first decodable sample before
3616 gst_qtdemux_activate_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
3617 guint32 seg_idx, GstClockTime offset)
3620 QtDemuxSegment *segment;
3621 guint32 index, kf_index;
3622 GstClockTime seg_time;
3623 GstClockTime start, stop, time;
3626 GST_LOG_OBJECT (qtdemux, "activate segment %d, offset %" GST_TIME_FORMAT,
3627 seg_idx, GST_TIME_ARGS (offset));
3629 /* update the current segment */
3630 stream->segment_index = seg_idx;
3632 /* get the segment */
3633 segment = &stream->segments[seg_idx];
3635 if (G_UNLIKELY (offset < segment->time)) {
3636 GST_WARNING_OBJECT (qtdemux, "offset < segment->time %" GST_TIME_FORMAT,
3637 GST_TIME_ARGS (segment->time));
3641 /* segment lies beyond total indicated duration */
3642 if (G_UNLIKELY (qtdemux->segment.duration != GST_CLOCK_TIME_NONE &&
3643 segment->time > qtdemux->segment.duration)) {
3644 GST_WARNING_OBJECT (qtdemux, "file duration %" GST_TIME_FORMAT
3645 " < segment->time %" GST_TIME_FORMAT,
3646 GST_TIME_ARGS (qtdemux->segment.duration),
3647 GST_TIME_ARGS (segment->time));
3651 /* get time in this segment */
3652 seg_time = offset - segment->time;
3654 GST_LOG_OBJECT (qtdemux, "seg_time %" GST_TIME_FORMAT,
3655 GST_TIME_ARGS (seg_time));
3657 if (G_UNLIKELY (seg_time > segment->duration)) {
3658 GST_LOG_OBJECT (qtdemux, "seg_time > segment->duration %" GST_TIME_FORMAT,
3659 GST_TIME_ARGS (segment->duration));
3660 seg_time = segment->duration;
3663 /* qtdemux->segment.stop is in outside-time-realm, whereas
3664 * segment->media_stop is in track-time-realm.
3666 * In order to compare the two, we need to bring segment.stop
3667 * into the track-time-realm */
3669 stop = qtdemux->segment.stop;
3670 if (stop == GST_CLOCK_TIME_NONE)
3671 stop = qtdemux->segment.duration;
3672 if (stop == GST_CLOCK_TIME_NONE)
3673 stop = segment->media_stop;
3676 MIN (segment->media_stop, stop - segment->time + segment->media_start);
3678 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
3679 start = segment->time + seg_time;
3681 stop = start - seg_time + segment->duration;
3682 } else if (qtdemux->segment.rate >= 0) {
3683 start = MIN (segment->media_start + seg_time, stop);
3686 if (segment->media_start >= qtdemux->segment.start) {
3687 time = segment->time;
3689 time = segment->time + (qtdemux->segment.start - segment->media_start);
3692 start = MAX (segment->media_start, qtdemux->segment.start);
3693 stop = MIN (segment->media_start + seg_time, stop);
3696 GST_DEBUG_OBJECT (qtdemux, "newsegment %d from %" GST_TIME_FORMAT
3697 " to %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT, seg_idx,
3698 GST_TIME_ARGS (start), GST_TIME_ARGS (stop), GST_TIME_ARGS (time));
3700 /* combine global rate with that of the segment */
3701 rate = segment->rate * qtdemux->segment.rate;
3703 /* Copy flags from main segment */
3704 stream->segment.flags = qtdemux->segment.flags;
3706 /* update the segment values used for clipping */
3707 /* accumulate previous segments */
3708 if (GST_CLOCK_TIME_IS_VALID (stream->segment.stop))
3709 stream->segment.base += (stream->segment.stop - stream->segment.start) /
3710 ABS (stream->segment.rate);
3711 stream->segment.rate = rate;
3712 stream->segment.start = start;
3713 stream->segment.stop = stop;
3714 stream->segment.time = time;
3715 stream->segment.position = start;
3717 /* now prepare and send the segment */
3719 event = gst_event_new_segment (&stream->segment);
3720 if (stream->segment_seqnum) {
3721 gst_event_set_seqnum (event, stream->segment_seqnum);
3722 stream->segment_seqnum = 0;
3724 gst_pad_push_event (stream->pad, event);
3725 /* clear to send tags on this pad now */
3726 gst_qtdemux_push_tags (qtdemux, stream);
3729 /* in the fragmented case, we pick a fragment that starts before our
3730 * desired position and rely on downstream to wait for a keyframe
3731 * (FIXME: doesn't seem to work so well with ismv and wmv, as no parser; the
3732 * tfra entries tells us which trun/sample the key unit is in, but we don't
3733 * make use of this additional information at the moment) */
3734 if (qtdemux->fragmented) {
3735 stream->to_sample = G_MAXUINT32;
3739 /* and move to the keyframe before the indicated media time of the
3741 if (G_LIKELY (!QTSEGMENT_IS_EMPTY (segment))) {
3742 if (qtdemux->segment.rate >= 0) {
3743 index = gst_qtdemux_find_index_linear (qtdemux, stream, start);
3744 stream->to_sample = G_MAXUINT32;
3745 GST_DEBUG_OBJECT (qtdemux,
3746 "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
3747 GST_TIME_FORMAT, GST_TIME_ARGS (start), index,
3748 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
3750 index = gst_qtdemux_find_index_linear (qtdemux, stream, stop);
3751 stream->to_sample = index;
3752 GST_DEBUG_OBJECT (qtdemux,
3753 "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
3754 GST_TIME_FORMAT, GST_TIME_ARGS (stop), index,
3755 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
3758 GST_DEBUG_OBJECT (qtdemux, "No need to look for keyframe, "
3759 "this is an empty segment");
3763 /* gst_qtdemux_parse_sample () called from gst_qtdemux_find_index_linear ()
3764 * encountered an error and printed a message so we return appropriately */
3768 /* we're at the right spot */
3769 if (index == stream->sample_index) {
3770 GST_DEBUG_OBJECT (qtdemux, "we are at the right index");
3774 /* find keyframe of the target index */
3775 kf_index = gst_qtdemux_find_keyframe (qtdemux, stream, index);
3778 /* indent does stupid stuff with stream->samples[].timestamp */
3780 /* if we move forwards, we don't have to go back to the previous
3781 * keyframe since we already sent that. We can also just jump to
3782 * the keyframe right before the target index if there is one. */
3783 if (index > stream->sample_index) {
3784 /* moving forwards check if we move past a keyframe */
3785 if (kf_index > stream->sample_index) {
3786 GST_DEBUG_OBJECT (qtdemux,
3787 "moving forwards to keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" )", kf_index,
3788 GST_TIME_ARGS (QTSAMPLE_PTS(stream, &stream->samples[kf_index])),
3789 GST_TIME_ARGS (QTSAMPLE_DTS(stream, &stream->samples[kf_index])));
3790 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
3792 GST_DEBUG_OBJECT (qtdemux,
3793 "moving forwards, keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" ) already sent", kf_index,
3794 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[kf_index])),
3795 GST_TIME_ARGS (QTSAMPLE_DTS (stream, &stream->samples[kf_index])));
3798 GST_DEBUG_OBJECT (qtdemux,
3799 "moving backwards to keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" )", kf_index,
3800 GST_TIME_ARGS (QTSAMPLE_PTS(stream, &stream->samples[kf_index])),
3801 GST_TIME_ARGS (QTSAMPLE_DTS(stream, &stream->samples[kf_index])));
3802 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
3810 /* prepare to get the current sample of @stream, getting essential values.
3812 * This function will also prepare and send the segment when needed.
3814 * Return FALSE if the stream is EOS.
3819 gst_qtdemux_prepare_current_sample (GstQTDemux * qtdemux,
3820 QtDemuxStream * stream, gboolean * empty, guint64 * offset, guint * size,
3821 GstClockTime * dts, GstClockTime * pts, GstClockTime * duration,
3822 gboolean * keyframe)
3824 QtDemuxSample *sample;
3825 GstClockTime time_position;
3828 g_return_val_if_fail (stream != NULL, FALSE);
3830 time_position = stream->time_position;
3831 if (G_UNLIKELY (time_position == GST_CLOCK_TIME_NONE))
3834 seg_idx = stream->segment_index;
3835 if (G_UNLIKELY (seg_idx == -1)) {
3836 /* find segment corresponding to time_position if we are looking
3838 seg_idx = gst_qtdemux_find_segment (qtdemux, stream, time_position);
3841 /* different segment, activate it, sample_index will be set. */
3842 if (G_UNLIKELY (stream->segment_index != seg_idx))
3843 gst_qtdemux_activate_segment (qtdemux, stream, seg_idx, time_position);
3845 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (&stream->segments[stream->
3847 QtDemuxSegment *seg = &stream->segments[stream->segment_index];
3849 GST_LOG_OBJECT (qtdemux, "Empty segment activated,"
3850 " prepare empty sample");
3853 *pts = *dts = time_position;
3854 *duration = seg->duration - (time_position - seg->time);
3861 if (stream->sample_index == -1)
3862 stream->sample_index = 0;
3864 GST_LOG_OBJECT (qtdemux, "segment active, index = %u of %u",
3865 stream->sample_index, stream->n_samples);
3867 if (G_UNLIKELY (stream->sample_index >= stream->n_samples)) {
3868 if (!qtdemux->fragmented)
3871 GST_INFO_OBJECT (qtdemux, "out of samples, trying to add more");
3875 GST_OBJECT_LOCK (qtdemux);
3876 flow = qtdemux_add_fragmented_samples (qtdemux);
3877 GST_OBJECT_UNLOCK (qtdemux);
3879 if (flow != GST_FLOW_OK)
3882 while (stream->sample_index >= stream->n_samples);
3885 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
3886 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
3887 stream->sample_index);
3891 /* now get the info for the sample we're at */
3892 sample = &stream->samples[stream->sample_index];
3894 *dts = QTSAMPLE_DTS (stream, sample);
3895 *pts = QTSAMPLE_PTS (stream, sample);
3896 *offset = sample->offset;
3897 *size = sample->size;
3898 *duration = QTSAMPLE_DUR_DTS (stream, sample, *dts);
3899 *keyframe = QTSAMPLE_KEYFRAME (stream, sample);
3906 stream->time_position = GST_CLOCK_TIME_NONE;
3911 /* move to the next sample in @stream.
3913 * Moves to the next segment when needed.
3916 gst_qtdemux_advance_sample (GstQTDemux * qtdemux, QtDemuxStream * stream)
3918 QtDemuxSample *sample;
3919 QtDemuxSegment *segment;
3921 /* get current segment */
3922 segment = &stream->segments[stream->segment_index];
3924 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
3925 GST_DEBUG_OBJECT (qtdemux, "Empty segment, no samples to advance");
3929 if (G_UNLIKELY (stream->sample_index >= stream->to_sample)) {
3930 /* Mark the stream as EOS */
3931 GST_DEBUG_OBJECT (qtdemux,
3932 "reached max allowed sample %u, mark EOS", stream->to_sample);
3933 stream->time_position = GST_CLOCK_TIME_NONE;
3937 /* move to next sample */
3938 stream->sample_index++;
3939 stream->offset_in_sample = 0;
3941 /* reached the last sample, we need the next segment */
3942 if (G_UNLIKELY (stream->sample_index >= stream->n_samples))
3945 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
3946 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
3947 stream->sample_index);
3951 /* get next sample */
3952 sample = &stream->samples[stream->sample_index];
3954 /* see if we are past the segment */
3955 if (G_UNLIKELY (QTSAMPLE_DTS (stream, sample) >= segment->media_stop))
3958 if (QTSAMPLE_DTS (stream, sample) >= segment->media_start) {
3959 /* inside the segment, update time_position, looks very familiar to
3960 * GStreamer segments, doesn't it? */
3961 stream->time_position =
3962 QTSAMPLE_DTS (stream, sample) - segment->media_start + segment->time;
3964 /* not yet in segment, time does not yet increment. This means
3965 * that we are still prerolling keyframes to the decoder so it can
3966 * decode the first sample of the segment. */
3967 stream->time_position = segment->time;
3971 /* move to the next segment */
3974 GST_DEBUG_OBJECT (qtdemux, "segment %d ended ", stream->segment_index);
3976 if (stream->segment_index == stream->n_segments - 1) {
3977 /* are we at the end of the last segment, we're EOS */
3978 stream->time_position = GST_CLOCK_TIME_NONE;
3980 /* else we're only at the end of the current segment */
3981 stream->time_position = segment->stop_time;
3983 /* make sure we select a new segment */
3984 stream->segment_index = -1;
3989 gst_qtdemux_sync_streams (GstQTDemux * demux)
3993 if (demux->n_streams <= 1)
3996 for (i = 0; i < demux->n_streams; i++) {
3997 QtDemuxStream *stream;
3998 GstClockTime end_time;
4000 stream = demux->streams[i];
4005 /* TODO advance time on subtitle streams here, if any some day */
4007 /* some clips/trailers may have unbalanced streams at the end,
4008 * so send EOS on shorter stream to prevent stalling others */
4010 /* do not mess with EOS if SEGMENT seeking */
4011 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT)
4014 if (demux->pullbased) {
4015 /* loop mode is sample time based */
4016 if (!STREAM_IS_EOS (stream))
4019 /* push mode is byte position based */
4020 if (stream->n_samples &&
4021 stream->samples[stream->n_samples - 1].offset >= demux->offset)
4025 if (stream->sent_eos)
4028 /* only act if some gap */
4029 end_time = stream->segments[stream->n_segments - 1].stop_time;
4030 GST_LOG_OBJECT (demux, "current position: %" GST_TIME_FORMAT
4031 ", stream end: %" GST_TIME_FORMAT,
4032 GST_TIME_ARGS (demux->segment.position), GST_TIME_ARGS (end_time));
4033 if (GST_CLOCK_TIME_IS_VALID (end_time)
4034 && (end_time + 2 * GST_SECOND < demux->segment.position)) {
4035 GST_DEBUG_OBJECT (demux, "sending EOS for stream %s",
4036 GST_PAD_NAME (stream->pad));
4037 stream->sent_eos = TRUE;
4038 gst_pad_push_event (stream->pad, gst_event_new_eos ());
4043 /* EOS and NOT_LINKED need to be combined. This means that we return:
4045 * GST_FLOW_NOT_LINKED: when all pads NOT_LINKED.
4046 * GST_FLOW_EOS: when all pads EOS or NOT_LINKED.
4048 static GstFlowReturn
4049 gst_qtdemux_combine_flows (GstQTDemux * demux, GstFlowReturn ret)
4051 GST_LOG_OBJECT (demux, "flow return: %s", gst_flow_get_name (ret));
4053 ret = gst_flow_combiner_update_flow (demux->flowcombiner, ret);
4055 GST_LOG_OBJECT (demux, "combined flow return: %s", gst_flow_get_name (ret));
4059 /* the input buffer metadata must be writable. Returns NULL when the buffer is
4060 * completely clipped
4062 * Should be used only with raw buffers */
4064 gst_qtdemux_clip_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
4067 guint64 start, stop, cstart, cstop, diff;
4068 GstClockTime pts, duration;
4070 gint num_rate, denom_rate;
4075 osize = size = gst_buffer_get_size (buf);
4078 /* depending on the type, setup the clip parameters */
4079 if (stream->subtype == FOURCC_soun) {
4080 frame_size = stream->bytes_per_frame;
4081 num_rate = GST_SECOND;
4082 denom_rate = (gint) stream->rate;
4084 } else if (stream->subtype == FOURCC_vide) {
4086 num_rate = stream->fps_n;
4087 denom_rate = stream->fps_d;
4092 if (frame_size <= 0)
4093 goto bad_frame_size;
4095 /* we can only clip if we have a valid pts */
4096 pts = GST_BUFFER_PTS (buf);
4097 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (pts)))
4100 duration = GST_BUFFER_DURATION (buf);
4102 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (duration))) {
4104 gst_util_uint64_scale_int (size / frame_size, num_rate, denom_rate);
4108 stop = start + duration;
4110 if (G_UNLIKELY (!gst_segment_clip (&stream->segment,
4111 GST_FORMAT_TIME, start, stop, &cstart, &cstop)))
4114 /* see if some clipping happened */
4115 diff = cstart - start;
4121 /* bring clipped time to samples and to bytes */
4122 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
4125 GST_DEBUG_OBJECT (qtdemux,
4126 "clipping start to %" GST_TIME_FORMAT " %"
4127 G_GUINT64_FORMAT " bytes", GST_TIME_ARGS (cstart), diff);
4133 diff = stop - cstop;
4138 /* bring clipped time to samples and then to bytes */
4139 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
4141 GST_DEBUG_OBJECT (qtdemux,
4142 "clipping stop to %" GST_TIME_FORMAT " %" G_GUINT64_FORMAT
4143 " bytes", GST_TIME_ARGS (cstop), diff);
4148 if (offset != 0 || size != osize)
4149 gst_buffer_resize (buf, offset, size);
4151 GST_BUFFER_DTS (buf) = GST_CLOCK_TIME_NONE;
4152 GST_BUFFER_PTS (buf) = pts;
4153 GST_BUFFER_DURATION (buf) = duration;
4157 /* dropped buffer */
4160 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
4165 GST_DEBUG_OBJECT (qtdemux, "bad frame size");
4170 GST_DEBUG_OBJECT (qtdemux, "no pts on buffer");
4175 GST_DEBUG_OBJECT (qtdemux, "clipped buffer");
4176 gst_buffer_unref (buf);
4181 /* the input buffer metadata must be writable,
4182 * but time/duration etc not yet set and need not be preserved */
4184 gst_qtdemux_process_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
4191 /* not many cases for now */
4192 if (G_UNLIKELY (stream->fourcc == FOURCC_mp4s)) {
4193 /* send a one time dvd clut event */
4194 if (stream->pending_event && stream->pad)
4195 gst_pad_push_event (stream->pad, stream->pending_event);
4196 stream->pending_event = NULL;
4199 if (G_UNLIKELY (stream->subtype != FOURCC_text
4200 && stream->subtype != FOURCC_sbtl &&
4201 stream->subtype != FOURCC_subp)) {
4205 gst_buffer_map (buf, &map, GST_MAP_READ);
4207 /* empty buffer is sent to terminate previous subtitle */
4208 if (map.size <= 2) {
4209 gst_buffer_unmap (buf, &map);
4210 gst_buffer_unref (buf);
4213 if (stream->subtype == FOURCC_subp) {
4214 /* That's all the processing needed for subpictures */
4215 gst_buffer_unmap (buf, &map);
4219 nsize = GST_READ_UINT16_BE (map.data);
4220 nsize = MIN (nsize, map.size - 2);
4222 GST_LOG_OBJECT (qtdemux, "3GPP timed text subtitle: %d/%" G_GSIZE_FORMAT "",
4225 /* takes care of UTF-8 validation or UTF-16 recognition,
4226 * no other encoding expected */
4227 str = gst_tag_freeform_string_to_utf8 ((gchar *) map.data + 2, nsize, NULL);
4228 gst_buffer_unmap (buf, &map);
4230 gst_buffer_unref (buf);
4231 buf = _gst_buffer_new_wrapped (str, strlen (str), g_free);
4233 /* this should not really happen unless the subtitle is corrupted */
4234 gst_buffer_unref (buf);
4238 /* FIXME ? convert optional subsequent style info to markup */
4243 /* Sets a buffer's attributes properly and pushes it downstream.
4244 * Also checks for additional actions and custom processing that may
4245 * need to be done first.
4247 static GstFlowReturn
4248 gst_qtdemux_decorate_and_push_buffer (GstQTDemux * qtdemux,
4249 QtDemuxStream * stream, GstBuffer * buf,
4250 GstClockTime dts, GstClockTime pts, GstClockTime duration,
4251 gboolean keyframe, GstClockTime position, guint64 byte_position)
4253 GstFlowReturn ret = GST_FLOW_OK;
4255 /* offset the timestamps according to the edit list */
4257 if (G_UNLIKELY (stream->fourcc == FOURCC_rtsp)) {
4261 gst_buffer_map (buf, &map, GST_MAP_READ);
4262 url = g_strndup ((gchar *) map.data, map.size);
4263 gst_buffer_unmap (buf, &map);
4264 if (url != NULL && strlen (url) != 0) {
4265 /* we have RTSP redirect now */
4266 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
4267 gst_message_new_element (GST_OBJECT_CAST (qtdemux),
4268 gst_structure_new ("redirect",
4269 "new-location", G_TYPE_STRING, url, NULL)));
4270 qtdemux->posted_redirect = TRUE;
4272 GST_WARNING_OBJECT (qtdemux, "Redirect URI of stream is empty, not "
4278 /* position reporting */
4279 if (qtdemux->segment.rate >= 0) {
4280 qtdemux->segment.position = position;
4281 gst_qtdemux_sync_streams (qtdemux);
4284 if (G_UNLIKELY (!stream->pad)) {
4285 GST_DEBUG_OBJECT (qtdemux, "No output pad for stream, ignoring");
4286 gst_buffer_unref (buf);
4290 /* send out pending buffers */
4291 while (stream->buffers) {
4292 GstBuffer *buffer = (GstBuffer *) stream->buffers->data;
4294 if (G_UNLIKELY (stream->discont)) {
4295 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
4296 GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
4297 stream->discont = FALSE;
4299 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
4302 gst_pad_push (stream->pad, buffer);
4304 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
4307 /* we're going to modify the metadata */
4308 buf = gst_buffer_make_writable (buf);
4310 if (G_UNLIKELY (stream->need_process))
4311 buf = gst_qtdemux_process_buffer (qtdemux, stream, buf);
4317 GST_BUFFER_DTS (buf) = dts;
4318 GST_BUFFER_PTS (buf) = pts;
4319 GST_BUFFER_DURATION (buf) = duration;
4320 GST_BUFFER_OFFSET (buf) = -1;
4321 GST_BUFFER_OFFSET_END (buf) = -1;
4323 if (G_UNLIKELY (stream->rgb8_palette))
4324 gst_buffer_append_memory (buf, gst_memory_ref (stream->rgb8_palette));
4326 if (G_UNLIKELY (stream->padding)) {
4327 gst_buffer_resize (buf, stream->padding, -1);
4330 if (G_UNLIKELY (qtdemux->element_index)) {
4331 GstClockTime stream_time;
4334 gst_segment_to_stream_time (&stream->segment, GST_FORMAT_TIME,
4336 if (GST_CLOCK_TIME_IS_VALID (stream_time)) {
4337 GST_LOG_OBJECT (qtdemux,
4338 "adding association %" GST_TIME_FORMAT "-> %"
4339 G_GUINT64_FORMAT, GST_TIME_ARGS (stream_time), byte_position);
4340 gst_index_add_association (qtdemux->element_index,
4342 keyframe ? GST_ASSOCIATION_FLAG_KEY_UNIT :
4343 GST_ASSOCIATION_FLAG_DELTA_UNIT, GST_FORMAT_TIME, stream_time,
4344 GST_FORMAT_BYTES, byte_position, NULL);
4349 if (stream->need_clip)
4350 buf = gst_qtdemux_clip_buffer (qtdemux, stream, buf);
4352 if (G_UNLIKELY (buf == NULL))
4355 if (G_UNLIKELY (stream->discont)) {
4356 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
4357 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
4358 stream->discont = FALSE;
4360 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
4364 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
4365 stream->on_keyframe = FALSE;
4367 stream->on_keyframe = TRUE;
4371 GST_LOG_OBJECT (qtdemux,
4372 "Pushing buffer with dts %" GST_TIME_FORMAT ", pts %" GST_TIME_FORMAT
4373 ", duration %" GST_TIME_FORMAT " on pad %s", GST_TIME_ARGS (dts),
4374 GST_TIME_ARGS (pts), GST_TIME_ARGS (duration),
4375 GST_PAD_NAME (stream->pad));
4377 ret = gst_pad_push (stream->pad, buf);
4379 if (GST_CLOCK_TIME_IS_VALID (pts) && GST_CLOCK_TIME_IS_VALID (duration)) {
4380 /* mark position in stream, we'll need this to know when to send GAP event */
4381 stream->segment.position = pts + duration;
4388 static const QtDemuxRandomAccessEntry *
4389 gst_qtdemux_stream_seek_fragment (GstQTDemux * qtdemux, QtDemuxStream * stream,
4390 GstClockTime pos, gboolean after)
4392 QtDemuxRandomAccessEntry *entries = stream->ra_entries;
4393 guint n_entries = stream->n_ra_entries;
4396 /* we assume the table is sorted */
4397 for (i = 0; i < n_entries; ++i) {
4398 if (entries[i].ts > pos)
4402 /* FIXME: maybe save first moof_offset somewhere instead, but for now it's
4403 * probably okay to assume that the index lists the very first fragment */
4410 return &entries[i - 1];
4414 gst_qtdemux_do_fragmented_seek (GstQTDemux * qtdemux)
4416 const QtDemuxRandomAccessEntry *best_entry = NULL;
4419 GST_OBJECT_LOCK (qtdemux);
4421 g_assert (qtdemux->n_streams > 0);
4423 for (i = 0; i < qtdemux->n_streams; i++) {
4424 const QtDemuxRandomAccessEntry *entry;
4425 QtDemuxStream *stream;
4426 gboolean is_audio_or_video;
4428 stream = qtdemux->streams[i];
4430 g_free (stream->samples);
4431 stream->samples = NULL;
4432 stream->n_samples = 0;
4433 stream->stbl_index = -1; /* no samples have yet been parsed */
4434 stream->sample_index = -1;
4436 if (stream->ra_entries == NULL)
4439 if (stream->subtype == FOURCC_vide || stream->subtype == FOURCC_soun)
4440 is_audio_or_video = TRUE;
4442 is_audio_or_video = FALSE;
4445 gst_qtdemux_stream_seek_fragment (qtdemux, stream,
4446 stream->time_position, !is_audio_or_video);
4448 GST_INFO_OBJECT (stream->pad, "%" GST_TIME_FORMAT " at offset "
4449 "%" G_GUINT64_FORMAT, GST_TIME_ARGS (entry->ts), entry->moof_offset);
4451 stream->pending_seek = entry;
4453 /* decide position to jump to just based on audio/video tracks, not subs */
4454 if (!is_audio_or_video)
4457 if (best_entry == NULL || entry->moof_offset < best_entry->moof_offset)
4461 if (best_entry == NULL) {
4462 GST_OBJECT_UNLOCK (qtdemux);
4466 GST_INFO_OBJECT (qtdemux, "seek to %" GST_TIME_FORMAT ", best fragment "
4467 "moof offset: %" G_GUINT64_FORMAT ", ts %" GST_TIME_FORMAT,
4468 GST_TIME_ARGS (qtdemux->streams[0]->time_position),
4469 best_entry->moof_offset, GST_TIME_ARGS (best_entry->ts));
4471 qtdemux->moof_offset = best_entry->moof_offset;
4473 qtdemux_add_fragmented_samples (qtdemux);
4475 GST_OBJECT_UNLOCK (qtdemux);
4479 static GstFlowReturn
4480 gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux)
4482 GstFlowReturn ret = GST_FLOW_OK;
4483 GstBuffer *buf = NULL;
4484 QtDemuxStream *stream;
4485 GstClockTime min_time;
4487 GstClockTime dts = GST_CLOCK_TIME_NONE;
4488 GstClockTime pts = GST_CLOCK_TIME_NONE;
4489 GstClockTime duration = 0;
4490 gboolean keyframe = FALSE;
4491 guint sample_size = 0;
4497 gst_qtdemux_push_pending_newsegment (qtdemux);
4499 if (qtdemux->fragmented_seek_pending) {
4500 GST_INFO_OBJECT (qtdemux, "pending fragmented seek");
4501 gst_qtdemux_do_fragmented_seek (qtdemux);
4502 GST_INFO_OBJECT (qtdemux, "fragmented seek done!");
4503 qtdemux->fragmented_seek_pending = FALSE;
4506 /* Figure out the next stream sample to output, min_time is expressed in
4507 * global time and runs over the edit list segments. */
4508 min_time = G_MAXUINT64;
4510 for (i = 0; i < qtdemux->n_streams; i++) {
4511 GstClockTime position;
4513 stream = qtdemux->streams[i];
4514 position = stream->time_position;
4516 /* position of -1 is EOS */
4517 if (position != GST_CLOCK_TIME_NONE && position < min_time) {
4518 min_time = position;
4523 if (G_UNLIKELY (index == -1)) {
4524 GST_DEBUG_OBJECT (qtdemux, "all streams are EOS");
4528 /* check for segment end */
4529 if (G_UNLIKELY (qtdemux->segment.stop != -1
4530 && ((qtdemux->segment.rate >= 0 && qtdemux->segment.stop <= min_time)
4531 || (qtdemux->segment.rate < 0
4532 && qtdemux->segment.start > min_time))
4533 && qtdemux->streams[index]->on_keyframe)) {
4534 GST_DEBUG_OBJECT (qtdemux, "we reached the end of our segment.");
4535 qtdemux->streams[index]->time_position = GST_CLOCK_TIME_NONE;
4539 /* gap events for subtitle streams */
4540 for (i = 0; i < qtdemux->n_streams; i++) {
4541 stream = qtdemux->streams[i];
4542 if (stream->pad && (stream->subtype == FOURCC_subp
4543 || stream->subtype == FOURCC_text
4544 || stream->subtype == FOURCC_sbtl)) {
4545 /* send one second gap events until the stream catches up */
4546 /* gaps can only be sent after segment is activated (segment.stop is no longer -1) */
4547 while (GST_CLOCK_TIME_IS_VALID (stream->segment.stop) &&
4548 GST_CLOCK_TIME_IS_VALID (stream->segment.position) &&
4549 stream->segment.position + GST_SECOND < min_time) {
4551 gst_event_new_gap (stream->segment.position, GST_SECOND);
4552 gst_pad_push_event (stream->pad, gap);
4553 stream->segment.position += GST_SECOND;
4558 stream = qtdemux->streams[index];
4559 if (stream->new_caps) {
4560 gst_qtdemux_configure_stream (qtdemux, stream);
4561 qtdemux_do_allocation (qtdemux, stream);
4564 /* fetch info for the current sample of this stream */
4565 if (G_UNLIKELY (!gst_qtdemux_prepare_current_sample (qtdemux, stream, &empty,
4566 &offset, &sample_size, &dts, &pts, &duration, &keyframe)))
4569 /* If we're doing a keyframe-only trickmode, only push keyframes on video streams */
4570 if (G_UNLIKELY (qtdemux->
4571 segment.flags & GST_SEGMENT_FLAG_TRICKMODE_KEY_UNITS)) {
4572 if (stream->subtype == FOURCC_vide && !keyframe) {
4573 GST_LOG_OBJECT (qtdemux, "Skipping non-keyframe on stream %d", index);
4578 GST_DEBUG_OBJECT (qtdemux,
4579 "pushing from stream %d, empty %d offset %" G_GUINT64_FORMAT
4580 ", size %d, dts=%" GST_TIME_FORMAT ", pts=%" GST_TIME_FORMAT
4581 ", duration %" GST_TIME_FORMAT, index, empty, offset, sample_size,
4582 GST_TIME_ARGS (dts), GST_TIME_ARGS (pts), GST_TIME_ARGS (duration));
4584 if (G_UNLIKELY (empty)) {
4585 /* empty segment, push a gap and move to the next one */
4586 gst_pad_push_event (stream->pad, gst_event_new_gap (pts, duration));
4587 stream->segment.position = pts + duration;
4591 /* hmm, empty sample, skip and move to next sample */
4592 if (G_UNLIKELY (sample_size <= 0))
4595 /* last pushed sample was out of boundary, goto next sample */
4596 if (G_UNLIKELY (GST_PAD_LAST_FLOW_RETURN (stream->pad) == GST_FLOW_EOS))
4599 if (stream->max_buffer_size == 0 || sample_size <= stream->max_buffer_size) {
4602 GST_DEBUG_OBJECT (qtdemux,
4603 "size %d larger than stream max_buffer_size %d, trimming",
4604 sample_size, stream->max_buffer_size);
4606 MIN (sample_size - stream->offset_in_sample, stream->max_buffer_size);
4609 GST_LOG_OBJECT (qtdemux, "reading %d bytes @ %" G_GUINT64_FORMAT, size,
4612 if (stream->use_allocator) {
4613 /* if we have a per-stream allocator, use it */
4614 buf = gst_buffer_new_allocate (stream->allocator, size, &stream->params);
4617 ret = gst_qtdemux_pull_atom (qtdemux, offset + stream->offset_in_sample,
4619 if (G_UNLIKELY (ret != GST_FLOW_OK))
4622 if (size != sample_size) {
4623 pts += gst_util_uint64_scale_int (GST_SECOND,
4624 stream->offset_in_sample / stream->bytes_per_frame, stream->timescale);
4625 dts += gst_util_uint64_scale_int (GST_SECOND,
4626 stream->offset_in_sample / stream->bytes_per_frame, stream->timescale);
4627 duration = gst_util_uint64_scale_int (GST_SECOND,
4628 size / stream->bytes_per_frame, stream->timescale);
4631 ret = gst_qtdemux_decorate_and_push_buffer (qtdemux, stream, buf,
4632 dts, pts, duration, keyframe, min_time, offset);
4634 if (size != sample_size) {
4635 QtDemuxSample *sample = &stream->samples[stream->sample_index];
4636 QtDemuxSegment *segment = &stream->segments[stream->segment_index];
4638 GstClockTime time_position = QTSTREAMTIME_TO_GSTTIME (stream,
4639 sample->timestamp + stream->offset_in_sample / stream->bytes_per_frame);
4640 if (time_position >= segment->media_start) {
4641 /* inside the segment, update time_position, looks very familiar to
4642 * GStreamer segments, doesn't it? */
4643 stream->time_position = (time_position - segment->media_start) +
4646 /* not yet in segment, time does not yet increment. This means
4647 * that we are still prerolling keyframes to the decoder so it can
4648 * decode the first sample of the segment. */
4649 stream->time_position = segment->time;
4654 ret = gst_qtdemux_combine_flows (qtdemux, ret);
4655 /* ignore unlinked, we will not push on the pad anymore and we will EOS when
4656 * we have no more data for the pad to push */
4657 if (ret == GST_FLOW_EOS)
4660 stream->offset_in_sample += size;
4661 if (stream->offset_in_sample >= sample_size) {
4662 gst_qtdemux_advance_sample (qtdemux, stream);
4667 gst_qtdemux_advance_sample (qtdemux, stream);
4675 GST_DEBUG_OBJECT (qtdemux, "No samples left for any streams - EOS");
4681 GST_DEBUG_OBJECT (qtdemux, "No samples left for stream");
4682 /* EOS will be raised if all are EOS */
4689 gst_qtdemux_loop (GstPad * pad)
4691 GstQTDemux *qtdemux;
4695 qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
4697 cur_offset = qtdemux->offset;
4698 GST_LOG_OBJECT (qtdemux, "loop at position %" G_GUINT64_FORMAT ", state %d",
4699 cur_offset, qtdemux->state);
4701 switch (qtdemux->state) {
4702 case QTDEMUX_STATE_INITIAL:
4703 case QTDEMUX_STATE_HEADER:
4704 ret = gst_qtdemux_loop_state_header (qtdemux);
4706 case QTDEMUX_STATE_MOVIE:
4707 ret = gst_qtdemux_loop_state_movie (qtdemux);
4708 if (qtdemux->segment.rate < 0 && ret == GST_FLOW_EOS) {
4709 ret = gst_qtdemux_seek_to_previous_keyframe (qtdemux);
4717 /* if something went wrong, pause */
4718 if (ret != GST_FLOW_OK)
4722 gst_object_unref (qtdemux);
4728 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
4729 (NULL), ("streaming stopped, invalid state"));
4730 gst_pad_pause_task (pad);
4731 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
4736 const gchar *reason = gst_flow_get_name (ret);
4738 GST_LOG_OBJECT (qtdemux, "pausing task, reason %s", reason);
4740 gst_pad_pause_task (pad);
4742 /* fatal errors need special actions */
4744 if (ret == GST_FLOW_EOS) {
4745 if (qtdemux->n_streams == 0) {
4746 /* we have no streams, post an error */
4747 gst_qtdemux_post_no_playable_stream_error (qtdemux);
4749 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
4752 if ((stop = qtdemux->segment.stop) == -1)
4753 stop = qtdemux->segment.duration;
4755 if (qtdemux->segment.rate >= 0) {
4756 GST_LOG_OBJECT (qtdemux, "Sending segment done, at end of segment");
4757 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
4758 gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
4759 GST_FORMAT_TIME, stop));
4760 gst_qtdemux_push_event (qtdemux,
4761 gst_event_new_segment_done (GST_FORMAT_TIME, stop));
4763 /* For Reverse Playback */
4764 GST_LOG_OBJECT (qtdemux, "Sending segment done, at start of segment");
4765 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
4766 gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
4767 GST_FORMAT_TIME, qtdemux->segment.start));
4768 gst_qtdemux_push_event (qtdemux,
4769 gst_event_new_segment_done (GST_FORMAT_TIME,
4770 qtdemux->segment.start));
4773 GST_LOG_OBJECT (qtdemux, "Sending EOS at end of segment");
4774 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
4776 } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
4777 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
4778 (NULL), ("streaming stopped, reason %s", reason));
4779 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
4788 * Returns if there are samples to be played.
4791 has_next_entry (GstQTDemux * demux)
4793 QtDemuxStream *stream;
4796 GST_DEBUG_OBJECT (demux, "Checking if there are samples not played yet");
4798 for (i = 0; i < demux->n_streams; i++) {
4799 stream = demux->streams[i];
4801 if (stream->sample_index == -1) {
4802 stream->sample_index = 0;
4803 stream->offset_in_sample = 0;
4806 if (stream->sample_index >= stream->n_samples) {
4807 GST_LOG_OBJECT (demux, "stream %d samples exhausted", i);
4810 GST_DEBUG_OBJECT (demux, "Found a sample");
4814 GST_DEBUG_OBJECT (demux, "There wasn't any next sample");
4821 * Returns the size of the first entry at the current offset.
4822 * If -1, there are none (which means EOS or empty file).
4825 next_entry_size (GstQTDemux * demux)
4827 QtDemuxStream *stream;
4830 guint64 smalloffs = (guint64) - 1;
4831 QtDemuxSample *sample;
4833 GST_LOG_OBJECT (demux, "Finding entry at offset %" G_GUINT64_FORMAT,
4836 for (i = 0; i < demux->n_streams; i++) {
4837 stream = demux->streams[i];
4839 if (stream->sample_index == -1) {
4840 stream->sample_index = 0;
4841 stream->offset_in_sample = 0;
4844 if (stream->sample_index >= stream->n_samples) {
4845 GST_LOG_OBJECT (demux, "stream %d samples exhausted", i);
4849 if (!qtdemux_parse_samples (demux, stream, stream->sample_index)) {
4850 GST_LOG_OBJECT (demux, "Parsing of index %u from stbl atom failed!",
4851 stream->sample_index);
4855 sample = &stream->samples[stream->sample_index];
4857 GST_LOG_OBJECT (demux,
4858 "Checking Stream %d (sample_index:%d / offset:%" G_GUINT64_FORMAT
4859 " / size:%" G_GUINT32_FORMAT ")", i, stream->sample_index,
4860 sample->offset, sample->size);
4862 if (((smalloffs == -1)
4863 || (sample->offset < smalloffs)) && (sample->size)) {
4865 smalloffs = sample->offset;
4869 GST_LOG_OBJECT (demux,
4870 "stream %d offset %" G_GUINT64_FORMAT " demux->offset :%"
4871 G_GUINT64_FORMAT, smallidx, smalloffs, demux->offset);
4876 stream = demux->streams[smallidx];
4877 sample = &stream->samples[stream->sample_index];
4879 if (sample->offset >= demux->offset) {
4880 demux->todrop = sample->offset - demux->offset;
4881 return sample->size + demux->todrop;
4884 GST_DEBUG_OBJECT (demux,
4885 "There wasn't any entry at offset %" G_GUINT64_FORMAT, demux->offset);
4890 gst_qtdemux_post_progress (GstQTDemux * demux, gint num, gint denom)
4892 gint perc = (gint) ((gdouble) num * 100.0 / (gdouble) denom);
4894 gst_element_post_message (GST_ELEMENT_CAST (demux),
4895 gst_message_new_element (GST_OBJECT_CAST (demux),
4896 gst_structure_new ("progress", "percent", G_TYPE_INT, perc, NULL)));
4900 qtdemux_seek_offset (GstQTDemux * demux, guint64 offset)
4905 GST_DEBUG_OBJECT (demux, "Seeking to %" G_GUINT64_FORMAT, offset);
4908 gst_event_new_seek (1.0, GST_FORMAT_BYTES,
4909 GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset,
4910 GST_SEEK_TYPE_NONE, -1);
4912 res = gst_pad_push_event (demux->sinkpad, event);
4917 /* check for seekable upstream, above and beyond a mere query */
4919 gst_qtdemux_check_seekability (GstQTDemux * demux)
4922 gboolean seekable = FALSE;
4923 gint64 start = -1, stop = -1;
4925 if (demux->upstream_size)
4928 query = gst_query_new_seeking (GST_FORMAT_BYTES);
4929 if (!gst_pad_peer_query (demux->sinkpad, query)) {
4930 GST_DEBUG_OBJECT (demux, "seeking query failed");
4934 gst_query_parse_seeking (query, NULL, &seekable, &start, &stop);
4936 /* try harder to query upstream size if we didn't get it the first time */
4937 if (seekable && stop == -1) {
4938 GST_DEBUG_OBJECT (demux, "doing duration query to fix up unset stop");
4939 gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &stop);
4942 /* if upstream doesn't know the size, it's likely that it's not seekable in
4943 * practice even if it technically may be seekable */
4944 if (seekable && (start != 0 || stop <= start)) {
4945 GST_DEBUG_OBJECT (demux, "seekable but unknown start/stop -> disable");
4950 gst_query_unref (query);
4952 GST_DEBUG_OBJECT (demux, "seekable: %d (%" G_GUINT64_FORMAT " - %"
4953 G_GUINT64_FORMAT ")", seekable, start, stop);
4954 demux->upstream_seekable = seekable;
4955 demux->upstream_size = seekable ? stop : -1;
4959 gst_qtdemux_drop_data (GstQTDemux * demux, gint bytes)
4961 g_return_if_fail (bytes <= demux->todrop);
4963 GST_LOG_OBJECT (demux, "Dropping %d bytes", bytes);
4964 gst_adapter_flush (demux->adapter, bytes);
4965 demux->neededbytes -= bytes;
4966 demux->offset += bytes;
4967 demux->todrop -= bytes;
4970 /* FIXME, unverified after edit list updates */
4971 static GstFlowReturn
4972 gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent, GstBuffer * inbuf)
4976 demux = GST_QTDEMUX (parent);
4978 if (GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_DISCONT)) {
4981 GST_DEBUG_OBJECT (demux, "Got DISCONT, marking all streams as DISCONT");
4983 for (i = 0; i < demux->n_streams; i++) {
4984 demux->streams[i]->discont = TRUE;
4988 gst_adapter_push (demux->adapter, inbuf);
4990 GST_DEBUG_OBJECT (demux,
4991 "pushing in inbuf %p, neededbytes:%u, available:%" G_GSIZE_FORMAT, inbuf,
4992 demux->neededbytes, gst_adapter_available (demux->adapter));
4994 return gst_qtdemux_process_adapter (demux, FALSE);
4997 static GstFlowReturn
4998 gst_qtdemux_process_adapter (GstQTDemux * demux, gboolean force)
5000 GstFlowReturn ret = GST_FLOW_OK;
5002 /* we never really mean to buffer that much */
5003 if (demux->neededbytes == -1) {
5007 while (((gst_adapter_available (demux->adapter)) >= demux->neededbytes) &&
5008 (ret == GST_FLOW_OK || (ret == GST_FLOW_NOT_LINKED && force))) {
5010 GST_DEBUG_OBJECT (demux,
5011 "state:%d , demux->neededbytes:%d, demux->offset:%" G_GUINT64_FORMAT,
5012 demux->state, demux->neededbytes, demux->offset);
5014 switch (demux->state) {
5015 case QTDEMUX_STATE_INITIAL:{
5020 gst_qtdemux_check_seekability (demux);
5022 data = gst_adapter_map (demux->adapter, demux->neededbytes);
5024 /* get fourcc/length, set neededbytes */
5025 extract_initial_length_and_fourcc ((guint8 *) data, demux->neededbytes,
5027 gst_adapter_unmap (demux->adapter);
5029 GST_DEBUG_OBJECT (demux, "Peeking found [%" GST_FOURCC_FORMAT "] "
5030 "size: %" G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), size);
5032 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
5033 (_("This file is invalid and cannot be played.")),
5034 ("initial atom '%" GST_FOURCC_FORMAT "' has empty length",
5035 GST_FOURCC_ARGS (fourcc)));
5036 ret = GST_FLOW_ERROR;
5039 if (fourcc == FOURCC_mdat) {
5040 gint next_entry = next_entry_size (demux);
5041 if (demux->n_streams > 0 && (next_entry != -1 || !demux->fragmented)) {
5042 /* we have the headers, start playback */
5043 demux->state = QTDEMUX_STATE_MOVIE;
5044 demux->neededbytes = next_entry;
5045 demux->mdatleft = size;
5047 /* no headers yet, try to get them */
5050 guint64 old, target;
5053 old = demux->offset;
5054 target = old + size;
5056 /* try to jump over the atom with a seek */
5057 /* only bother if it seems worth doing so,
5058 * and avoids possible upstream/server problems */
5059 if (demux->upstream_seekable &&
5060 demux->upstream_size > 4 * (1 << 20)) {
5061 res = qtdemux_seek_offset (demux, target);
5063 GST_DEBUG_OBJECT (demux, "skipping seek");
5068 GST_DEBUG_OBJECT (demux, "seek success");
5069 /* remember the offset fo the first mdat so we can seek back to it
5070 * after we have the headers */
5071 if (fourcc == FOURCC_mdat && demux->first_mdat == -1) {
5072 demux->first_mdat = old;
5073 GST_DEBUG_OBJECT (demux, "first mdat at %" G_GUINT64_FORMAT,
5076 /* seek worked, continue reading */
5077 demux->offset = target;
5078 demux->neededbytes = 16;
5079 demux->state = QTDEMUX_STATE_INITIAL;
5081 /* seek failed, need to buffer */
5082 demux->offset = old;
5083 GST_DEBUG_OBJECT (demux, "seek failed/skipped");
5084 /* there may be multiple mdat (or alike) buffers */
5086 if (demux->mdatbuffer)
5087 bs = gst_buffer_get_size (demux->mdatbuffer);
5090 if (size + bs > 10 * (1 << 20))
5092 demux->state = QTDEMUX_STATE_BUFFER_MDAT;
5093 demux->neededbytes = size;
5094 if (!demux->mdatbuffer)
5095 demux->mdatoffset = demux->offset;
5098 } else if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
5099 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
5100 (_("This file is invalid and cannot be played.")),
5101 ("atom %" GST_FOURCC_FORMAT " has bogus size %" G_GUINT64_FORMAT,
5102 GST_FOURCC_ARGS (fourcc), size));
5103 ret = GST_FLOW_ERROR;
5106 /* this means we already started buffering and still no moov header,
5107 * let's continue buffering everything till we get moov */
5108 if (demux->mdatbuffer && !(fourcc == FOURCC_moov
5109 || fourcc == FOURCC_moof))
5111 demux->neededbytes = size;
5112 demux->state = QTDEMUX_STATE_HEADER;
5116 case QTDEMUX_STATE_HEADER:{
5120 GST_DEBUG_OBJECT (demux, "In header");
5122 data = gst_adapter_map (demux->adapter, demux->neededbytes);
5124 /* parse the header */
5125 extract_initial_length_and_fourcc (data, demux->neededbytes, NULL,
5127 if (fourcc == FOURCC_moov) {
5128 /* in usual fragmented setup we could try to scan for more
5129 * and end up at the the moov (after mdat) again */
5130 if (demux->got_moov && demux->n_streams > 0 &&
5132 || demux->last_moov_offset == demux->offset)) {
5133 GST_DEBUG_OBJECT (demux,
5134 "Skipping moov atom as we have (this) one already");
5136 GST_DEBUG_OBJECT (demux, "Parsing [moov]");
5138 if (demux->got_moov && demux->fragmented) {
5139 GST_DEBUG_OBJECT (demux,
5140 "Got a second moov, clean up data from old one");
5141 if (demux->moov_node)
5142 g_node_destroy (demux->moov_node);
5143 demux->moov_node = NULL;
5144 demux->moov_node_compressed = NULL;
5146 /* prepare newsegment to send when streaming actually starts */
5147 if (!demux->pending_newsegment)
5148 demux->pending_newsegment =
5149 gst_event_new_segment (&demux->segment);
5152 demux->last_moov_offset = demux->offset;
5154 qtdemux_parse_moov (demux, data, demux->neededbytes);
5155 qtdemux_node_dump (demux, demux->moov_node);
5156 qtdemux_parse_tree (demux);
5157 qtdemux_prepare_streams (demux);
5158 if (!demux->got_moov)
5159 qtdemux_expose_streams (demux);
5163 for (n = 0; n < demux->n_streams; n++) {
5164 QtDemuxStream *stream = demux->streams[n];
5166 gst_qtdemux_configure_stream (demux, stream);
5170 demux->got_moov = TRUE;
5172 g_node_destroy (demux->moov_node);
5173 demux->moov_node = NULL;
5174 GST_DEBUG_OBJECT (demux, "Finished parsing the header");
5176 } else if (fourcc == FOURCC_moof) {
5177 if ((demux->got_moov || demux->media_caps) && demux->fragmented) {
5179 GstClockTime prev_pts;
5180 guint64 prev_offset;
5182 GST_DEBUG_OBJECT (demux, "Parsing [moof]");
5185 * The timestamp of the moof buffer is relevant as some scenarios
5186 * won't have the initial timestamp in the atoms. Whenever a new
5187 * buffer has started, we get that buffer's PTS and use it as a base
5188 * timestamp for the trun entries.
5190 * To keep track of the current buffer timestamp and starting point
5191 * we use gst_adapter_prev_pts that gives us the PTS and the distance
5192 * from the beggining of the buffer, with the distance and demux->offset
5193 * we know if it is still the same buffer or not.
5195 prev_pts = gst_adapter_prev_pts (demux->adapter, &dist);
5196 prev_offset = demux->offset - dist;
5197 if (demux->fragment_start_offset == -1
5198 || prev_offset > demux->fragment_start_offset) {
5199 demux->fragment_start_offset = prev_offset;
5200 demux->fragment_start = prev_pts;
5201 GST_DEBUG_OBJECT (demux,
5202 "New fragment start found at: %" G_GUINT64_FORMAT " : %"
5203 GST_TIME_FORMAT, demux->fragment_start_offset,
5204 GST_TIME_ARGS (demux->fragment_start));
5207 if (!qtdemux_parse_moof (demux, data, demux->neededbytes,
5208 demux->offset, NULL)) {
5209 gst_adapter_unmap (demux->adapter);
5210 ret = GST_FLOW_ERROR;
5213 /* in MSS we need to expose the pads after the first moof as we won't get a moov */
5214 if (demux->mss_mode && !demux->exposed) {
5215 if (!demux->pending_newsegment) {
5217 gst_segment_init (&segment, GST_FORMAT_TIME);
5218 GST_DEBUG_OBJECT (demux, "new pending_newsegment");
5219 demux->pending_newsegment = gst_event_new_segment (&segment);
5221 qtdemux_expose_streams (demux);
5224 GST_DEBUG_OBJECT (demux, "Discarding [moof]");
5226 } else if (fourcc == FOURCC_ftyp) {
5227 GST_DEBUG_OBJECT (demux, "Parsing [ftyp]");
5228 qtdemux_parse_ftyp (demux, data, demux->neededbytes);
5229 } else if (fourcc == FOURCC_uuid) {
5230 GST_DEBUG_OBJECT (demux, "Parsing [uuid]");
5231 qtdemux_parse_uuid (demux, data, demux->neededbytes);
5232 } else if (fourcc == FOURCC_sidx) {
5233 GST_DEBUG_OBJECT (demux, "Parsing [sidx]");
5234 qtdemux_parse_sidx (demux, data, demux->neededbytes);
5236 GST_WARNING_OBJECT (demux,
5237 "Unknown fourcc while parsing header : %" GST_FOURCC_FORMAT,
5238 GST_FOURCC_ARGS (fourcc));
5239 /* Let's jump that one and go back to initial state */
5241 gst_adapter_unmap (demux->adapter);
5244 if (demux->mdatbuffer && demux->n_streams) {
5245 gsize remaining_data_size = 0;
5247 /* the mdat was before the header */
5248 GST_DEBUG_OBJECT (demux, "We have n_streams:%d and mdatbuffer:%p",
5249 demux->n_streams, demux->mdatbuffer);
5250 /* restore our adapter/offset view of things with upstream;
5251 * put preceding buffered data ahead of current moov data.
5252 * This should also handle evil mdat, moov, mdat cases and alike */
5253 gst_adapter_flush (demux->adapter, demux->neededbytes);
5255 /* Store any remaining data after the mdat for later usage */
5256 remaining_data_size = gst_adapter_available (demux->adapter);
5257 if (remaining_data_size > 0) {
5258 g_assert (demux->restoredata_buffer == NULL);
5259 demux->restoredata_buffer =
5260 gst_adapter_take_buffer (demux->adapter, remaining_data_size);
5261 demux->restoredata_offset = demux->offset + demux->neededbytes;
5262 GST_DEBUG_OBJECT (demux,
5263 "Stored %" G_GSIZE_FORMAT " post mdat bytes at offset %"
5264 G_GUINT64_FORMAT, remaining_data_size,
5265 demux->restoredata_offset);
5268 gst_adapter_push (demux->adapter, demux->mdatbuffer);
5269 demux->mdatbuffer = NULL;
5270 demux->offset = demux->mdatoffset;
5271 demux->neededbytes = next_entry_size (demux);
5272 demux->state = QTDEMUX_STATE_MOVIE;
5273 demux->mdatleft = gst_adapter_available (demux->adapter);
5275 GST_DEBUG_OBJECT (demux, "Carrying on normally");
5276 gst_adapter_flush (demux->adapter, demux->neededbytes);
5278 /* only go back to the mdat if there are samples to play */
5279 if (demux->got_moov && demux->first_mdat != -1
5280 && has_next_entry (demux)) {
5283 /* we need to seek back */
5284 res = qtdemux_seek_offset (demux, demux->first_mdat);
5286 demux->offset = demux->first_mdat;
5288 GST_DEBUG_OBJECT (demux, "Seek back failed");
5291 demux->offset += demux->neededbytes;
5293 demux->neededbytes = 16;
5294 demux->state = QTDEMUX_STATE_INITIAL;
5299 case QTDEMUX_STATE_BUFFER_MDAT:{
5303 GST_DEBUG_OBJECT (demux, "Got our buffer at offset %" G_GUINT64_FORMAT,
5305 buf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
5306 gst_buffer_extract (buf, 0, fourcc, 4);
5307 GST_DEBUG_OBJECT (demux, "mdatbuffer starts with %" GST_FOURCC_FORMAT,
5308 GST_FOURCC_ARGS (QT_FOURCC (fourcc)));
5309 if (demux->mdatbuffer)
5310 demux->mdatbuffer = gst_buffer_append (demux->mdatbuffer, buf);
5312 demux->mdatbuffer = buf;
5313 demux->offset += demux->neededbytes;
5314 demux->neededbytes = 16;
5315 demux->state = QTDEMUX_STATE_INITIAL;
5316 gst_qtdemux_post_progress (demux, 1, 1);
5320 case QTDEMUX_STATE_MOVIE:{
5322 QtDemuxStream *stream = NULL;
5323 QtDemuxSample *sample;
5325 GstClockTime dts, pts, duration;
5328 GST_DEBUG_OBJECT (demux,
5329 "BEGIN // in MOVIE for offset %" G_GUINT64_FORMAT, demux->offset);
5331 if (demux->fragmented) {
5332 GST_DEBUG_OBJECT (demux, "mdat remaining %" G_GUINT64_FORMAT,
5334 if (G_LIKELY (demux->todrop < demux->mdatleft)) {
5335 /* if needed data starts within this atom,
5336 * then it should not exceed this atom */
5337 if (G_UNLIKELY (demux->neededbytes > demux->mdatleft)) {
5338 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
5339 (_("This file is invalid and cannot be played.")),
5340 ("sample data crosses atom boundary"));
5341 ret = GST_FLOW_ERROR;
5344 demux->mdatleft -= demux->neededbytes;
5346 GST_DEBUG_OBJECT (demux, "data atom emptied; resuming atom scan");
5347 /* so we are dropping more than left in this atom */
5348 gst_qtdemux_drop_data (demux, demux->mdatleft);
5349 demux->mdatleft = 0;
5351 /* need to resume atom parsing so we do not miss any other pieces */
5352 demux->state = QTDEMUX_STATE_INITIAL;
5353 demux->neededbytes = 16;
5355 /* check if there was any stored post mdat data from previous buffers */
5356 if (demux->restoredata_buffer) {
5357 g_assert (gst_adapter_available (demux->adapter) == 0);
5359 gst_adapter_push (demux->adapter, demux->restoredata_buffer);
5360 demux->restoredata_buffer = NULL;
5361 demux->offset = demux->restoredata_offset;
5368 if (demux->todrop) {
5369 gst_qtdemux_drop_data (demux, demux->todrop);
5373 /* initial newsegment sent here after having added pads,
5374 * possible others in sink_event */
5375 if (G_UNLIKELY (demux->pending_newsegment)) {
5376 gst_qtdemux_push_pending_newsegment (demux);
5377 /* clear to send tags on all streams */
5378 for (i = 0; i < demux->n_streams; i++) {
5379 stream = demux->streams[i];
5380 gst_qtdemux_push_tags (demux, stream);
5381 if (stream->sparse) {
5382 GST_INFO_OBJECT (demux, "Sending gap event on stream %d", i);
5383 gst_pad_push_event (stream->pad,
5384 gst_event_new_gap (stream->segment.position,
5385 GST_CLOCK_TIME_NONE));
5390 /* Figure out which stream this packet belongs to */
5391 for (i = 0; i < demux->n_streams; i++) {
5392 stream = demux->streams[i];
5393 if (stream->sample_index >= stream->n_samples)
5395 GST_LOG_OBJECT (demux,
5396 "Checking stream %d (sample_index:%d / offset:%" G_GUINT64_FORMAT
5397 " / size:%d)", i, stream->sample_index,
5398 stream->samples[stream->sample_index].offset,
5399 stream->samples[stream->sample_index].size);
5401 if (stream->samples[stream->sample_index].offset == demux->offset)
5405 if (G_UNLIKELY (stream == NULL || i == demux->n_streams))
5406 goto unknown_stream;
5408 if (stream->new_caps) {
5409 gst_qtdemux_configure_stream (demux, stream);
5412 /* Put data in a buffer, set timestamps, caps, ... */
5413 sample = &stream->samples[stream->sample_index];
5415 if (G_LIKELY (!(STREAM_IS_EOS (stream)))) {
5416 outbuf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
5417 GST_DEBUG_OBJECT (demux, "stream : %" GST_FOURCC_FORMAT,
5418 GST_FOURCC_ARGS (stream->fourcc));
5420 g_return_val_if_fail (outbuf != NULL, GST_FLOW_ERROR);
5422 dts = QTSAMPLE_DTS (stream, sample);
5423 pts = QTSAMPLE_PTS (stream, sample);
5424 duration = QTSAMPLE_DUR_DTS (stream, sample, dts);
5425 keyframe = QTSAMPLE_KEYFRAME (stream, sample);
5427 /* check for segment end */
5428 if (G_UNLIKELY (demux->segment.stop != -1
5429 && demux->segment.stop <= pts && stream->on_keyframe)) {
5430 GST_DEBUG_OBJECT (demux, "we reached the end of our segment.");
5431 stream->time_position = GST_CLOCK_TIME_NONE; /* this means EOS */
5433 /* check if all streams are eos */
5435 for (i = 0; i < demux->n_streams; i++) {
5436 if (!STREAM_IS_EOS (demux->streams[i])) {
5442 if (ret == GST_FLOW_EOS) {
5443 GST_DEBUG_OBJECT (demux, "All streams are EOS, signal upstream");
5447 ret = gst_qtdemux_decorate_and_push_buffer (demux, stream, outbuf,
5448 dts, pts, duration, keyframe, dts, demux->offset);
5452 ret = gst_qtdemux_combine_flows (demux, ret);
5454 /* skip this data, stream is EOS */
5455 gst_adapter_flush (demux->adapter, demux->neededbytes);
5458 stream->sample_index++;
5459 stream->offset_in_sample = 0;
5461 /* update current offset and figure out size of next buffer */
5462 GST_LOG_OBJECT (demux, "increasing offset %" G_GUINT64_FORMAT " by %u",
5463 demux->offset, demux->neededbytes);
5464 demux->offset += demux->neededbytes;
5465 GST_LOG_OBJECT (demux, "offset is now %" G_GUINT64_FORMAT,
5468 if ((demux->neededbytes = next_entry_size (demux)) == -1) {
5469 if (demux->fragmented) {
5470 GST_DEBUG_OBJECT (demux, "(temporarily) out of fragmented samples");
5471 /* there may be more to follow, only finish this atom */
5472 demux->todrop = demux->mdatleft;
5473 demux->neededbytes = demux->todrop;
5485 /* when buffering movie data, at least show user something is happening */
5486 if (ret == GST_FLOW_OK && demux->state == QTDEMUX_STATE_BUFFER_MDAT &&
5487 gst_adapter_available (demux->adapter) <= demux->neededbytes) {
5488 gst_qtdemux_post_progress (demux, gst_adapter_available (demux->adapter),
5489 demux->neededbytes);
5498 GST_ELEMENT_ERROR (demux, STREAM, FAILED, (NULL), ("unknown stream found"));
5499 ret = GST_FLOW_ERROR;
5504 GST_DEBUG_OBJECT (demux, "no next entry, EOS");
5510 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
5511 (NULL), ("qtdemuxer invalid state %d", demux->state));
5512 ret = GST_FLOW_ERROR;
5517 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
5518 (NULL), ("no 'moov' atom within the first 10 MB"));
5519 ret = GST_FLOW_ERROR;
5525 qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent)
5530 query = gst_query_new_scheduling ();
5532 if (!gst_pad_peer_query (sinkpad, query)) {
5533 gst_query_unref (query);
5537 pull_mode = gst_query_has_scheduling_mode_with_flags (query,
5538 GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
5539 gst_query_unref (query);
5544 GST_DEBUG_OBJECT (sinkpad, "activating pull");
5545 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
5549 GST_DEBUG_OBJECT (sinkpad, "activating push");
5550 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
5555 qtdemux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
5556 GstPadMode mode, gboolean active)
5559 GstQTDemux *demux = GST_QTDEMUX (parent);
5562 case GST_PAD_MODE_PUSH:
5563 demux->pullbased = FALSE;
5566 case GST_PAD_MODE_PULL:
5568 demux->pullbased = TRUE;
5569 res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_qtdemux_loop,
5572 res = gst_pad_stop_task (sinkpad);
5584 qtdemux_zalloc (void *opaque, unsigned int items, unsigned int size)
5586 return g_malloc (items * size);
5590 qtdemux_zfree (void *opaque, void *addr)
5596 qtdemux_inflate (void *z_buffer, guint z_length, guint length)
5602 z = g_new0 (z_stream, 1);
5603 z->zalloc = qtdemux_zalloc;
5604 z->zfree = qtdemux_zfree;
5607 z->next_in = z_buffer;
5608 z->avail_in = z_length;
5610 buffer = (guint8 *) g_malloc (length);
5611 ret = inflateInit (z);
5612 while (z->avail_in > 0) {
5613 if (z->avail_out == 0) {
5615 buffer = (guint8 *) g_realloc (buffer, length);
5616 z->next_out = buffer + z->total_out;
5617 z->avail_out = 1024;
5619 ret = inflate (z, Z_SYNC_FLUSH);
5623 if (ret != Z_STREAM_END) {
5624 g_warning ("inflate() returned %d", ret);
5630 #endif /* HAVE_ZLIB */
5633 qtdemux_parse_moov (GstQTDemux * qtdemux, const guint8 * buffer, guint length)
5637 qtdemux->moov_node = g_node_new ((guint8 *) buffer);
5639 /* counts as header data */
5640 qtdemux->header_size += length;
5642 GST_DEBUG_OBJECT (qtdemux, "parsing 'moov' atom");
5643 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buffer, length);
5645 cmov = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_cmov);
5651 dcom = qtdemux_tree_get_child_by_type (cmov, FOURCC_dcom);
5652 cmvd = qtdemux_tree_get_child_by_type (cmov, FOURCC_cmvd);
5653 if (dcom == NULL || cmvd == NULL)
5654 goto invalid_compression;
5656 method = QT_FOURCC ((guint8 *) dcom->data + 8);
5659 case GST_MAKE_FOURCC ('z', 'l', 'i', 'b'):{
5660 guint uncompressed_length;
5661 guint compressed_length;
5664 uncompressed_length = QT_UINT32 ((guint8 *) cmvd->data + 8);
5665 compressed_length = QT_UINT32 ((guint8 *) cmvd->data + 4) - 12;
5666 GST_LOG ("length = %u", uncompressed_length);
5669 (guint8 *) qtdemux_inflate ((guint8 *) cmvd->data + 12,
5670 compressed_length, uncompressed_length);
5672 qtdemux->moov_node_compressed = qtdemux->moov_node;
5673 qtdemux->moov_node = g_node_new (buf);
5675 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buf,
5676 uncompressed_length);
5679 #endif /* HAVE_ZLIB */
5681 GST_WARNING_OBJECT (qtdemux, "unknown or unhandled header compression "
5682 "type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (method));
5689 invalid_compression:
5691 GST_ERROR_OBJECT (qtdemux, "invalid compressed header");
5697 qtdemux_parse_container (GstQTDemux * qtdemux, GNode * node, const guint8 * buf,
5700 while (G_UNLIKELY (buf < end)) {
5704 if (G_UNLIKELY (buf + 4 > end)) {
5705 GST_LOG_OBJECT (qtdemux, "buffer overrun");
5708 len = QT_UINT32 (buf);
5709 if (G_UNLIKELY (len == 0)) {
5710 GST_LOG_OBJECT (qtdemux, "empty container");
5713 if (G_UNLIKELY (len < 8)) {
5714 GST_WARNING_OBJECT (qtdemux, "length too short (%d < 8)", len);
5717 if (G_UNLIKELY (len > (end - buf))) {
5718 GST_WARNING_OBJECT (qtdemux, "length too long (%d > %d)", len,
5719 (gint) (end - buf));
5723 child = g_node_new ((guint8 *) buf);
5724 g_node_append (node, child);
5725 GST_LOG_OBJECT (qtdemux, "adding new node of len %d", len);
5726 qtdemux_parse_node (qtdemux, child, buf, len);
5734 qtdemux_parse_theora_extension (GstQTDemux * qtdemux, QtDemuxStream * stream,
5737 int len = QT_UINT32 (xdxt->data);
5738 guint8 *buf = xdxt->data;
5739 guint8 *end = buf + len;
5742 /* skip size and type */
5750 size = QT_UINT32 (buf);
5751 type = QT_FOURCC (buf + 4);
5753 GST_LOG_OBJECT (qtdemux, "%p %p", buf, end);
5755 if (buf + size > end || size <= 0)
5761 GST_WARNING_OBJECT (qtdemux, "have cookie %" GST_FOURCC_FORMAT,
5762 GST_FOURCC_ARGS (type));
5766 buffer = gst_buffer_new_and_alloc (size);
5767 gst_buffer_fill (buffer, 0, buf, size);
5768 stream->buffers = g_slist_append (stream->buffers, buffer);
5769 GST_LOG_OBJECT (qtdemux, "parsing theora header");
5772 buffer = gst_buffer_new_and_alloc (size);
5773 gst_buffer_fill (buffer, 0, buf, size);
5774 stream->buffers = g_slist_append (stream->buffers, buffer);
5775 GST_LOG_OBJECT (qtdemux, "parsing theora comment");
5778 buffer = gst_buffer_new_and_alloc (size);
5779 gst_buffer_fill (buffer, 0, buf, size);
5780 stream->buffers = g_slist_append (stream->buffers, buffer);
5781 GST_LOG_OBJECT (qtdemux, "parsing theora codebook");
5784 GST_WARNING_OBJECT (qtdemux,
5785 "unknown theora cookie %" GST_FOURCC_FORMAT,
5786 GST_FOURCC_ARGS (type));
5795 qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node, const guint8 * buffer,
5799 guint32 node_length = 0;
5800 const QtNodeType *type;
5803 GST_LOG_OBJECT (qtdemux, "qtdemux_parse buffer %p length %u", buffer, length);
5805 if (G_UNLIKELY (length < 8))
5806 goto not_enough_data;
5808 node_length = QT_UINT32 (buffer);
5809 fourcc = QT_FOURCC (buffer + 4);
5811 /* ignore empty nodes */
5812 if (G_UNLIKELY (fourcc == 0 || node_length == 8))
5815 type = qtdemux_type_get (fourcc);
5817 end = buffer + length;
5819 GST_LOG_OBJECT (qtdemux,
5820 "parsing '%" GST_FOURCC_FORMAT "', length=%u, name '%s'",
5821 GST_FOURCC_ARGS (fourcc), node_length, type->name);
5823 if (node_length > length)
5824 goto broken_atom_size;
5826 if (type->flags & QT_FLAG_CONTAINER) {
5827 qtdemux_parse_container (qtdemux, node, buffer + 8, end);
5832 if (node_length < 20) {
5833 GST_LOG_OBJECT (qtdemux, "skipping small stsd box");
5836 GST_DEBUG_OBJECT (qtdemux,
5837 "parsing stsd (sample table, sample description) atom");
5838 /* Skip over 8 byte atom hdr + 1 byte version, 3 bytes flags, 4 byte num_entries */
5839 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
5849 /* also read alac (or whatever) in stead of mp4a in the following,
5850 * since a similar layout is used in other cases as well */
5851 if (fourcc == FOURCC_mp4a)
5856 /* There are two things we might encounter here: a true mp4a atom, and
5857 an mp4a entry in an stsd atom. The latter is what we're interested
5858 in, and it looks like an atom, but isn't really one. The true mp4a
5859 atom is short, so we detect it based on length here. */
5860 if (length < min_size) {
5861 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
5862 GST_FOURCC_ARGS (fourcc));
5866 /* 'version' here is the sound sample description version. Types 0 and
5867 1 are documented in the QTFF reference, but type 2 is not: it's
5868 described in Apple header files instead (struct SoundDescriptionV2
5870 version = QT_UINT16 (buffer + 16);
5872 GST_DEBUG_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT " version 0x%08x",
5873 GST_FOURCC_ARGS (fourcc), version);
5875 /* parse any esds descriptors */
5887 GST_WARNING_OBJECT (qtdemux,
5888 "unhandled %" GST_FOURCC_FORMAT " version 0x%08x",
5889 GST_FOURCC_ARGS (fourcc), version);
5894 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
5911 /* codec_data is contained inside these atoms, which all have
5912 * the same format. */
5914 GST_DEBUG_OBJECT (qtdemux, "parsing in %" GST_FOURCC_FORMAT,
5915 GST_FOURCC_ARGS (fourcc));
5916 version = QT_UINT32 (buffer + 16);
5917 GST_DEBUG_OBJECT (qtdemux, "version %08x", version);
5918 if (1 || version == 0x00000000) {
5919 buf = buffer + 0x32;
5921 /* FIXME Quicktime uses PASCAL string while
5922 * the iso format uses C strings. Check the file
5923 * type before attempting to parse the string here. */
5924 tlen = QT_UINT8 (buf);
5925 GST_DEBUG_OBJECT (qtdemux, "tlen = %d", tlen);
5927 GST_DEBUG_OBJECT (qtdemux, "string = %.*s", tlen, (char *) buf);
5928 /* the string has a reserved space of 32 bytes so skip
5929 * the remaining 31 */
5931 buf += 4; /* and 4 bytes reserved */
5933 GST_MEMDUMP_OBJECT (qtdemux, "mp4v", buf, end - buf);
5935 qtdemux_parse_container (qtdemux, node, buf, end);
5941 GST_MEMDUMP_OBJECT (qtdemux, "H264", buffer, end - buffer);
5942 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
5947 GST_MEMDUMP_OBJECT (qtdemux, "avc1", buffer, end - buffer);
5948 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
5953 GST_MEMDUMP_OBJECT (qtdemux, "avc3", buffer, end - buffer);
5954 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
5959 GST_MEMDUMP_OBJECT (qtdemux, "H265", buffer, end - buffer);
5960 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
5965 GST_MEMDUMP_OBJECT (qtdemux, "hvc1", buffer, end - buffer);
5966 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
5971 GST_MEMDUMP_OBJECT (qtdemux, "hev1", buffer, end - buffer);
5972 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
5977 qtdemux_parse_container (qtdemux, node, buffer + 86, end);
5982 GST_DEBUG_OBJECT (qtdemux, "parsing meta atom");
5983 qtdemux_parse_container (qtdemux, node, buffer + 12, end);
5988 GST_MEMDUMP_OBJECT (qtdemux, "mp4s", buffer, end - buffer);
5989 /* Skip 8 byte header, plus 8 byte version + flags + entry_count */
5990 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
5998 version = QT_UINT32 (buffer + 12);
5999 GST_DEBUG_OBJECT (qtdemux, "parsing XiTh atom version 0x%08x", version);
6006 GST_DEBUG_OBJECT (qtdemux, "unknown version 0x%08x", version);
6011 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
6016 qtdemux_parse_container (qtdemux, node, buffer + 0x34, end);
6021 qtdemux_parse_uuid (qtdemux, buffer, end - buffer);
6025 if (!strcmp (type->name, "unknown"))
6026 GST_MEMDUMP ("Unknown tag", buffer + 4, end - buffer - 4);
6030 GST_LOG_OBJECT (qtdemux, "parsed '%" GST_FOURCC_FORMAT "'",
6031 GST_FOURCC_ARGS (fourcc));
6037 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
6038 (_("This file is corrupt and cannot be played.")),
6039 ("Not enough data for an atom header, got only %u bytes", length));
6044 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
6045 (_("This file is corrupt and cannot be played.")),
6046 ("Atom '%" GST_FOURCC_FORMAT "' has size of %u bytes, but we have only "
6047 "%u bytes available.", GST_FOURCC_ARGS (fourcc), node_length,
6054 qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc)
6058 guint32 child_fourcc;
6060 for (child = g_node_first_child (node); child;
6061 child = g_node_next_sibling (child)) {
6062 buffer = (guint8 *) child->data;
6064 child_fourcc = QT_FOURCC (buffer + 4);
6066 if (G_UNLIKELY (child_fourcc == fourcc)) {
6074 qtdemux_tree_get_child_by_type_full (GNode * node, guint32 fourcc,
6075 GstByteReader * parser)
6079 guint32 child_fourcc, child_len;
6081 for (child = g_node_first_child (node); child;
6082 child = g_node_next_sibling (child)) {
6083 buffer = (guint8 *) child->data;
6085 child_len = QT_UINT32 (buffer);
6086 child_fourcc = QT_FOURCC (buffer + 4);
6088 if (G_UNLIKELY (child_fourcc == fourcc)) {
6089 if (G_UNLIKELY (child_len < (4 + 4)))
6091 /* FIXME: must verify if atom length < parent atom length */
6092 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
6100 qtdemux_tree_get_sibling_by_type_full (GNode * node, guint32 fourcc,
6101 GstByteReader * parser)
6105 guint32 child_fourcc, child_len;
6107 for (child = g_node_next_sibling (node); child;
6108 child = g_node_next_sibling (child)) {
6109 buffer = (guint8 *) child->data;
6111 child_fourcc = QT_FOURCC (buffer + 4);
6113 if (child_fourcc == fourcc) {
6115 child_len = QT_UINT32 (buffer);
6116 if (G_UNLIKELY (child_len < (4 + 4)))
6118 /* FIXME: must verify if atom length < parent atom length */
6119 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
6128 qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc)
6130 return qtdemux_tree_get_sibling_by_type_full (node, fourcc, NULL);
6134 qtdemux_do_allocation (GstQTDemux * qtdemux, QtDemuxStream * stream)
6136 /* FIXME: This can only reliably work if demuxers have a
6137 * separate streaming thread per srcpad. This should be
6138 * done in a demuxer base class, which integrates parts
6141 * https://bugzilla.gnome.org/show_bug.cgi?id=701856
6146 query = gst_query_new_allocation (stream->caps, FALSE);
6148 if (!gst_pad_peer_query (stream->pad, query)) {
6149 /* not a problem, just debug a little */
6150 GST_DEBUG_OBJECT (qtdemux, "peer ALLOCATION query failed");
6153 if (stream->allocator)
6154 gst_object_unref (stream->allocator);
6156 if (gst_query_get_n_allocation_params (query) > 0) {
6157 /* try the allocator */
6158 gst_query_parse_nth_allocation_param (query, 0, &stream->allocator,
6160 stream->use_allocator = TRUE;
6162 stream->allocator = NULL;
6163 gst_allocation_params_init (&stream->params);
6164 stream->use_allocator = FALSE;
6166 gst_query_unref (query);
6171 gst_qtdemux_configure_stream (GstQTDemux * qtdemux, QtDemuxStream * stream)
6173 if (stream->subtype == FOURCC_vide) {
6174 /* fps is calculated base on the duration of the average framerate since
6175 * qt does not have a fixed framerate. */
6176 if ((stream->n_samples == 1) && (stream->first_duration == 0)) {
6181 if (stream->duration == 0 || stream->n_samples < 2) {
6182 stream->fps_n = stream->timescale;
6185 /* Calculate a framerate, ignoring the first sample which is sometimes truncated */
6186 /* stream->duration is guint64, timescale, n_samples are guint32 */
6187 GstClockTime avg_duration =
6188 gst_util_uint64_scale_round (stream->duration -
6189 stream->first_duration, GST_SECOND,
6190 (guint64) (stream->timescale) * (stream->n_samples - 1));
6192 GST_LOG_OBJECT (qtdemux,
6193 "Calculating avg sample duration based on stream duration %"
6195 " minus first sample %u, leaving %d samples gives %"
6196 GST_TIME_FORMAT, stream->duration, stream->first_duration,
6197 stream->n_samples - 1, GST_TIME_ARGS (avg_duration));
6199 gst_video_guess_framerate (avg_duration, &stream->fps_n,
6202 GST_DEBUG_OBJECT (qtdemux,
6203 "Calculating framerate, timescale %u gave fps_n %d fps_d %d",
6204 stream->timescale, stream->fps_n, stream->fps_d);
6208 stream->caps = gst_caps_make_writable (stream->caps);
6210 gst_caps_set_simple (stream->caps,
6211 "width", G_TYPE_INT, stream->width,
6212 "height", G_TYPE_INT, stream->height,
6213 "framerate", GST_TYPE_FRACTION, stream->fps_n, stream->fps_d, NULL);
6215 /* calculate pixel-aspect-ratio using display width and height */
6216 GST_DEBUG_OBJECT (qtdemux,
6217 "video size %dx%d, target display size %dx%d", stream->width,
6218 stream->height, stream->display_width, stream->display_height);
6220 if (stream->display_width > 0 && stream->display_height > 0 &&
6221 stream->width > 0 && stream->height > 0) {
6224 /* calculate the pixel aspect ratio using the display and pixel w/h */
6225 n = stream->display_width * stream->height;
6226 d = stream->display_height * stream->width;
6229 GST_DEBUG_OBJECT (qtdemux, "setting PAR to %d/%d", n, d);
6230 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
6231 GST_TYPE_FRACTION, n, d, NULL);
6234 /* qt file might have pasp atom */
6235 if (stream->par_w > 0 && stream->par_h > 0) {
6236 GST_DEBUG_OBJECT (qtdemux, "par %d:%d", stream->par_w, stream->par_h);
6237 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
6238 GST_TYPE_FRACTION, stream->par_w, stream->par_h, NULL);
6241 } else if (stream->subtype == FOURCC_soun) {
6243 stream->caps = gst_caps_make_writable (stream->caps);
6244 if (stream->rate > 0)
6245 gst_caps_set_simple (stream->caps,
6246 "rate", G_TYPE_INT, (int) stream->rate, NULL);
6247 if (stream->n_channels > 0)
6248 gst_caps_set_simple (stream->caps,
6249 "channels", G_TYPE_INT, stream->n_channels, NULL);
6250 if (stream->n_channels > 2) {
6251 /* FIXME: Need to parse the 'chan' atom to get channel layouts
6252 * correctly; this is just the minimum we can do - assume
6253 * we don't actually have any channel positions. */
6254 gst_caps_set_simple (stream->caps,
6255 "channel-mask", GST_TYPE_BITMASK, G_GUINT64_CONSTANT (0), NULL);
6261 GST_PAD_ELEMENT_PRIVATE (stream->pad) = stream;
6262 gst_pad_set_event_function (stream->pad, gst_qtdemux_handle_src_event);
6263 gst_pad_set_query_function (stream->pad, gst_qtdemux_handle_src_query);
6264 gst_pad_set_active (stream->pad, TRUE);
6266 gst_pad_use_fixed_caps (stream->pad);
6268 GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT, stream->caps);
6269 if (stream->new_stream) {
6272 GstStreamFlags stream_flags;
6275 gst_pad_get_sticky_event (qtdemux->sinkpad, GST_EVENT_STREAM_START,
6278 if (gst_event_parse_group_id (event, &qtdemux->group_id))
6279 qtdemux->have_group_id = TRUE;
6281 qtdemux->have_group_id = FALSE;
6282 gst_event_unref (event);
6283 } else if (!qtdemux->have_group_id) {
6284 qtdemux->have_group_id = TRUE;
6285 qtdemux->group_id = gst_util_group_id_next ();
6288 stream->new_stream = FALSE;
6290 gst_pad_create_stream_id_printf (stream->pad,
6291 GST_ELEMENT_CAST (qtdemux), "%03u", stream->track_id);
6292 event = gst_event_new_stream_start (stream_id);
6293 if (qtdemux->have_group_id)
6294 gst_event_set_group_id (event, qtdemux->group_id);
6295 stream_flags = GST_STREAM_FLAG_NONE;
6296 if (stream->disabled)
6297 stream_flags |= GST_STREAM_FLAG_UNSELECT;
6299 stream_flags |= GST_STREAM_FLAG_SPARSE;
6300 gst_event_set_stream_flags (event, stream_flags);
6301 gst_pad_push_event (stream->pad, event);
6304 gst_pad_set_caps (stream->pad, stream->caps);
6305 stream->new_caps = FALSE;
6311 gst_qtdemux_add_stream (GstQTDemux * qtdemux,
6312 QtDemuxStream * stream, GstTagList * list)
6314 /* consistent default for push based mode */
6315 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
6317 if (stream->subtype == FOURCC_vide) {
6318 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
6321 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
6324 gst_qtdemux_configure_stream (qtdemux, stream);
6325 qtdemux->n_video_streams++;
6326 } else if (stream->subtype == FOURCC_soun) {
6327 gchar *name = g_strdup_printf ("audio_%u", qtdemux->n_audio_streams);
6330 gst_pad_new_from_static_template (&gst_qtdemux_audiosrc_template, name);
6332 gst_qtdemux_configure_stream (qtdemux, stream);
6333 qtdemux->n_audio_streams++;
6334 } else if (stream->subtype == FOURCC_strm) {
6335 GST_DEBUG_OBJECT (qtdemux, "stream type, not creating pad");
6336 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
6337 || stream->subtype == FOURCC_sbtl) {
6338 gchar *name = g_strdup_printf ("subtitle_%u", qtdemux->n_sub_streams);
6341 gst_pad_new_from_static_template (&gst_qtdemux_subsrc_template, name);
6343 gst_qtdemux_configure_stream (qtdemux, stream);
6344 qtdemux->n_sub_streams++;
6345 } else if (stream->caps) {
6346 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
6349 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
6351 gst_qtdemux_configure_stream (qtdemux, stream);
6352 qtdemux->n_video_streams++;
6354 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
6359 GST_DEBUG_OBJECT (qtdemux, "adding pad %s %p to qtdemux %p",
6360 GST_OBJECT_NAME (stream->pad), stream->pad, qtdemux);
6361 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
6362 gst_flow_combiner_add_pad (qtdemux->flowcombiner, stream->pad);
6364 if (stream->pending_tags)
6365 gst_tag_list_unref (stream->pending_tags);
6366 stream->pending_tags = list;
6367 /* global tags go on each pad anyway */
6368 stream->send_global_tags = TRUE;
6374 /* find next atom with @fourcc starting at @offset */
6375 static GstFlowReturn
6376 qtdemux_find_atom (GstQTDemux * qtdemux, guint64 * offset,
6377 guint64 * length, guint32 fourcc)
6383 GST_LOG_OBJECT (qtdemux, "finding fourcc %" GST_FOURCC_FORMAT " at offset %"
6384 G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), *offset);
6390 ret = gst_pad_pull_range (qtdemux->sinkpad, *offset, 16, &buf);
6391 if (G_UNLIKELY (ret != GST_FLOW_OK))
6393 if (G_UNLIKELY (gst_buffer_get_size (buf) != 16)) {
6396 gst_buffer_unref (buf);
6399 gst_buffer_map (buf, &map, GST_MAP_READ);
6400 extract_initial_length_and_fourcc (map.data, 16, length, &lfourcc);
6401 gst_buffer_unmap (buf, &map);
6402 gst_buffer_unref (buf);
6404 if (G_UNLIKELY (*length == 0)) {
6405 GST_DEBUG_OBJECT (qtdemux, "invalid length 0");
6406 ret = GST_FLOW_ERROR;
6410 if (lfourcc == fourcc) {
6411 GST_DEBUG_OBJECT (qtdemux, "found fourcc at offset %" G_GUINT64_FORMAT,
6415 GST_LOG_OBJECT (qtdemux,
6416 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
6417 GST_FOURCC_ARGS (fourcc), *offset);
6426 /* might simply have had last one */
6427 GST_DEBUG_OBJECT (qtdemux, "fourcc not found");
6432 /* should only do something in pull mode */
6433 /* call with OBJECT lock */
6434 static GstFlowReturn
6435 qtdemux_add_fragmented_samples (GstQTDemux * qtdemux)
6437 guint64 length, offset;
6438 GstBuffer *buf = NULL;
6439 GstFlowReturn ret = GST_FLOW_OK;
6440 GstFlowReturn res = GST_FLOW_OK;
6443 offset = qtdemux->moof_offset;
6444 GST_DEBUG_OBJECT (qtdemux, "next moof at offset %" G_GUINT64_FORMAT, offset);
6447 GST_DEBUG_OBJECT (qtdemux, "no next moof");
6448 return GST_FLOW_EOS;
6451 /* best not do pull etc with lock held */
6452 GST_OBJECT_UNLOCK (qtdemux);
6454 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
6455 if (ret != GST_FLOW_OK)
6458 ret = gst_qtdemux_pull_atom (qtdemux, offset, length, &buf);
6459 if (G_UNLIKELY (ret != GST_FLOW_OK))
6461 gst_buffer_map (buf, &map, GST_MAP_READ);
6462 if (!qtdemux_parse_moof (qtdemux, map.data, map.size, offset, NULL)) {
6463 gst_buffer_unmap (buf, &map);
6464 gst_buffer_unref (buf);
6469 gst_buffer_unmap (buf, &map);
6470 gst_buffer_unref (buf);
6474 /* look for next moof */
6475 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
6476 if (G_UNLIKELY (ret != GST_FLOW_OK))
6480 GST_OBJECT_LOCK (qtdemux);
6482 qtdemux->moof_offset = offset;
6488 GST_DEBUG_OBJECT (qtdemux, "failed to parse moof");
6490 res = GST_FLOW_ERROR;
6495 /* maybe upstream temporarily flushing */
6496 if (ret != GST_FLOW_FLUSHING) {
6497 GST_DEBUG_OBJECT (qtdemux, "no next moof");
6500 GST_DEBUG_OBJECT (qtdemux, "upstream WRONG_STATE");
6501 /* resume at current position next time */
6508 /* initialise bytereaders for stbl sub-atoms */
6510 qtdemux_stbl_init (GstQTDemux * qtdemux, QtDemuxStream * stream, GNode * stbl)
6512 stream->stbl_index = -1; /* no samples have yet been parsed */
6513 stream->sample_index = -1;
6515 /* time-to-sample atom */
6516 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stts, &stream->stts))
6519 /* copy atom data into a new buffer for later use */
6520 stream->stts.data = g_memdup (stream->stts.data, stream->stts.size);
6522 /* skip version + flags */
6523 if (!gst_byte_reader_skip (&stream->stts, 1 + 3) ||
6524 !gst_byte_reader_get_uint32_be (&stream->stts, &stream->n_sample_times))
6526 GST_LOG_OBJECT (qtdemux, "%u timestamp blocks", stream->n_sample_times);
6528 /* make sure there's enough data */
6529 if (!qt_atom_parser_has_chunks (&stream->stts, stream->n_sample_times, 8)) {
6530 stream->n_sample_times = gst_byte_reader_get_remaining (&stream->stts) / 8;
6531 GST_LOG_OBJECT (qtdemux, "overriding to %u timestamp blocks",
6532 stream->n_sample_times);
6533 if (!stream->n_sample_times)
6537 /* sync sample atom */
6538 stream->stps_present = FALSE;
6539 if ((stream->stss_present =
6540 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stss,
6541 &stream->stss) ? TRUE : FALSE) == TRUE) {
6542 /* copy atom data into a new buffer for later use */
6543 stream->stss.data = g_memdup (stream->stss.data, stream->stss.size);
6545 /* skip version + flags */
6546 if (!gst_byte_reader_skip (&stream->stss, 1 + 3) ||
6547 !gst_byte_reader_get_uint32_be (&stream->stss, &stream->n_sample_syncs))
6550 if (stream->n_sample_syncs) {
6551 /* make sure there's enough data */
6552 if (!qt_atom_parser_has_chunks (&stream->stss, stream->n_sample_syncs, 4))
6556 /* partial sync sample atom */
6557 if ((stream->stps_present =
6558 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stps,
6559 &stream->stps) ? TRUE : FALSE) == TRUE) {
6560 /* copy atom data into a new buffer for later use */
6561 stream->stps.data = g_memdup (stream->stps.data, stream->stps.size);
6563 /* skip version + flags */
6564 if (!gst_byte_reader_skip (&stream->stps, 1 + 3) ||
6565 !gst_byte_reader_get_uint32_be (&stream->stps,
6566 &stream->n_sample_partial_syncs))
6569 /* if there are no entries, the stss table contains the real
6571 if (stream->n_sample_partial_syncs) {
6572 /* make sure there's enough data */
6573 if (!qt_atom_parser_has_chunks (&stream->stps,
6574 stream->n_sample_partial_syncs, 4))
6581 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsz, &stream->stsz))
6584 /* copy atom data into a new buffer for later use */
6585 stream->stsz.data = g_memdup (stream->stsz.data, stream->stsz.size);
6587 /* skip version + flags */
6588 if (!gst_byte_reader_skip (&stream->stsz, 1 + 3) ||
6589 !gst_byte_reader_get_uint32_be (&stream->stsz, &stream->sample_size))
6592 if (!gst_byte_reader_get_uint32_be (&stream->stsz, &stream->n_samples))
6595 if (!stream->n_samples)
6598 /* sample-to-chunk atom */
6599 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsc, &stream->stsc))
6602 /* copy atom data into a new buffer for later use */
6603 stream->stsc.data = g_memdup (stream->stsc.data, stream->stsc.size);
6605 /* skip version + flags */
6606 if (!gst_byte_reader_skip (&stream->stsc, 1 + 3) ||
6607 !gst_byte_reader_get_uint32_be (&stream->stsc,
6608 &stream->n_samples_per_chunk))
6611 GST_DEBUG_OBJECT (qtdemux, "n_samples_per_chunk %u",
6612 stream->n_samples_per_chunk);
6614 /* make sure there's enough data */
6615 if (!qt_atom_parser_has_chunks (&stream->stsc, stream->n_samples_per_chunk,
6621 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stco, &stream->stco))
6622 stream->co_size = sizeof (guint32);
6623 else if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_co64,
6625 stream->co_size = sizeof (guint64);
6629 /* copy atom data into a new buffer for later use */
6630 stream->stco.data = g_memdup (stream->stco.data, stream->stco.size);
6632 /* skip version + flags */
6633 if (!gst_byte_reader_skip (&stream->stco, 1 + 3))
6636 /* chunks_are_samples == TRUE means treat chunks as samples */
6637 stream->chunks_are_samples = stream->sample_size && !stream->sampled;
6638 if (stream->chunks_are_samples) {
6639 /* treat chunks as samples */
6640 if (!gst_byte_reader_get_uint32_be (&stream->stco, &stream->n_samples))
6643 /* skip number of entries */
6644 if (!gst_byte_reader_skip (&stream->stco, 4))
6647 /* make sure there are enough data in the stsz atom */
6648 if (!stream->sample_size) {
6649 /* different sizes for each sample */
6650 if (!qt_atom_parser_has_chunks (&stream->stsz, stream->n_samples, 4))
6655 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
6656 stream->n_samples, (guint) sizeof (QtDemuxSample),
6657 stream->n_samples * sizeof (QtDemuxSample) / (1024.0 * 1024.0));
6659 if (stream->n_samples >=
6660 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample)) {
6661 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
6662 "be larger than %uMB (broken file?)", stream->n_samples,
6663 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
6667 stream->samples = g_try_new0 (QtDemuxSample, stream->n_samples);
6668 if (!stream->samples) {
6669 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
6675 /* composition time-to-sample */
6676 if ((stream->ctts_present =
6677 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_ctts,
6678 &stream->ctts) ? TRUE : FALSE) == TRUE) {
6679 /* copy atom data into a new buffer for later use */
6680 stream->ctts.data = g_memdup (stream->ctts.data, stream->ctts.size);
6682 /* skip version + flags */
6683 if (!gst_byte_reader_skip (&stream->ctts, 1 + 3)
6684 || !gst_byte_reader_get_uint32_be (&stream->ctts,
6685 &stream->n_composition_times))
6688 /* make sure there's enough data */
6689 if (!qt_atom_parser_has_chunks (&stream->ctts, stream->n_composition_times,
6698 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
6699 (_("This file is corrupt and cannot be played.")), (NULL));
6704 gst_qtdemux_stbl_free (stream);
6705 if (!qtdemux->fragmented) {
6706 /* not quite good */
6707 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
6710 /* may pick up samples elsewhere */
6716 /* collect samples from the next sample to be parsed up to sample @n for @stream
6717 * by reading the info from @stbl
6719 * This code can be executed from both the streaming thread and the seeking
6720 * thread so it takes the object lock to protect itself
6723 qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream, guint32 n)
6726 QtDemuxSample *samples, *first, *cur, *last;
6727 guint32 n_samples_per_chunk;
6730 GST_LOG_OBJECT (qtdemux, "parsing samples for stream fourcc %"
6731 GST_FOURCC_FORMAT ", pad %s", GST_FOURCC_ARGS (stream->fourcc),
6732 stream->pad ? GST_PAD_NAME (stream->pad) : "(NULL)");
6734 n_samples = stream->n_samples;
6737 goto out_of_samples;
6739 GST_OBJECT_LOCK (qtdemux);
6740 if (n <= stream->stbl_index)
6741 goto already_parsed;
6743 GST_DEBUG_OBJECT (qtdemux, "parsing up to sample %u", n);
6745 if (!stream->stsz.data) {
6746 /* so we already parsed and passed all the moov samples;
6747 * onto fragmented ones */
6748 g_assert (qtdemux->fragmented);
6752 /* pointer to the sample table */
6753 samples = stream->samples;
6755 /* starts from -1, moves to the next sample index to parse */
6756 stream->stbl_index++;
6758 /* keep track of the first and last sample to fill */
6759 first = &samples[stream->stbl_index];
6762 if (!stream->chunks_are_samples) {
6763 /* set the sample sizes */
6764 if (stream->sample_size == 0) {
6765 /* different sizes for each sample */
6766 for (cur = first; cur <= last; cur++) {
6767 cur->size = gst_byte_reader_get_uint32_be_unchecked (&stream->stsz);
6768 GST_LOG_OBJECT (qtdemux, "sample %d has size %u",
6769 (guint) (cur - samples), cur->size);
6772 /* samples have the same size */
6773 GST_LOG_OBJECT (qtdemux, "all samples have size %u", stream->sample_size);
6774 for (cur = first; cur <= last; cur++)
6775 cur->size = stream->sample_size;
6779 n_samples_per_chunk = stream->n_samples_per_chunk;
6782 for (i = stream->stsc_index; i < n_samples_per_chunk; i++) {
6785 if (stream->stsc_chunk_index >= stream->last_chunk
6786 || stream->stsc_chunk_index < stream->first_chunk) {
6787 stream->first_chunk =
6788 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
6789 stream->samples_per_chunk =
6790 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
6791 gst_byte_reader_skip_unchecked (&stream->stsc, 4);
6793 /* chunk numbers are counted from 1 it seems */
6794 if (G_UNLIKELY (stream->first_chunk == 0))
6797 --stream->first_chunk;
6799 /* the last chunk of each entry is calculated by taking the first chunk
6800 * of the next entry; except if there is no next, where we fake it with
6802 if (G_UNLIKELY (i == (stream->n_samples_per_chunk - 1))) {
6803 stream->last_chunk = G_MAXUINT32;
6805 stream->last_chunk =
6806 gst_byte_reader_peek_uint32_be_unchecked (&stream->stsc);
6807 if (G_UNLIKELY (stream->last_chunk == 0))
6810 --stream->last_chunk;
6813 GST_LOG_OBJECT (qtdemux,
6814 "entry %d has first_chunk %d, last_chunk %d, samples_per_chunk %d", i,
6815 stream->first_chunk, stream->last_chunk, stream->samples_per_chunk);
6817 if (G_UNLIKELY (stream->last_chunk < stream->first_chunk))
6820 if (stream->last_chunk != G_MAXUINT32) {
6821 if (!qt_atom_parser_peek_sub (&stream->stco,
6822 stream->first_chunk * stream->co_size,
6823 (stream->last_chunk - stream->first_chunk) * stream->co_size,
6828 stream->co_chunk = stream->stco;
6829 if (!gst_byte_reader_skip (&stream->co_chunk,
6830 stream->first_chunk * stream->co_size))
6834 stream->stsc_chunk_index = stream->first_chunk;
6837 last_chunk = stream->last_chunk;
6839 if (stream->chunks_are_samples) {
6840 cur = &samples[stream->stsc_chunk_index];
6842 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
6845 stream->stsc_chunk_index = j;
6850 qt_atom_parser_get_offset_unchecked (&stream->co_chunk,
6853 GST_LOG_OBJECT (qtdemux, "Created entry %d with offset "
6854 "%" G_GUINT64_FORMAT, j, cur->offset);
6856 if (stream->samples_per_frame * stream->bytes_per_frame) {
6858 (stream->samples_per_chunk * stream->n_channels) /
6859 stream->samples_per_frame * stream->bytes_per_frame;
6861 cur->size = stream->samples_per_chunk;
6864 GST_DEBUG_OBJECT (qtdemux,
6865 "keyframe sample %d: timestamp %" GST_TIME_FORMAT ", size %u",
6866 j, GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream,
6867 stream->stco_sample_index)), cur->size);
6869 cur->timestamp = stream->stco_sample_index;
6870 cur->duration = stream->samples_per_chunk;
6871 cur->keyframe = TRUE;
6874 stream->stco_sample_index += stream->samples_per_chunk;
6876 stream->stsc_chunk_index = j;
6878 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
6879 guint32 samples_per_chunk;
6880 guint64 chunk_offset;
6882 if (!stream->stsc_sample_index
6883 && !qt_atom_parser_get_offset (&stream->co_chunk, stream->co_size,
6884 &stream->chunk_offset))
6887 samples_per_chunk = stream->samples_per_chunk;
6888 chunk_offset = stream->chunk_offset;
6890 for (k = stream->stsc_sample_index; k < samples_per_chunk; k++) {
6891 GST_LOG_OBJECT (qtdemux, "creating entry %d with offset %"
6892 G_GUINT64_FORMAT " and size %d",
6893 (guint) (cur - samples), chunk_offset, cur->size);
6895 cur->offset = chunk_offset;
6896 chunk_offset += cur->size;
6899 if (G_UNLIKELY (cur > last)) {
6901 stream->stsc_sample_index = k + 1;
6902 stream->chunk_offset = chunk_offset;
6903 stream->stsc_chunk_index = j;
6907 stream->stsc_sample_index = 0;
6909 stream->stsc_chunk_index = j;
6911 stream->stsc_index++;
6914 if (stream->chunks_are_samples)
6918 guint32 n_sample_times;
6920 n_sample_times = stream->n_sample_times;
6923 for (i = stream->stts_index; i < n_sample_times; i++) {
6924 guint32 stts_samples;
6925 gint32 stts_duration;
6928 if (stream->stts_sample_index >= stream->stts_samples
6929 || !stream->stts_sample_index) {
6931 stream->stts_samples =
6932 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
6933 stream->stts_duration =
6934 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
6936 GST_LOG_OBJECT (qtdemux, "block %d, %u timestamps, duration %u",
6937 i, stream->stts_samples, stream->stts_duration);
6939 stream->stts_sample_index = 0;
6942 stts_samples = stream->stts_samples;
6943 stts_duration = stream->stts_duration;
6944 stts_time = stream->stts_time;
6946 for (j = stream->stts_sample_index; j < stts_samples; j++) {
6947 GST_DEBUG_OBJECT (qtdemux,
6948 "sample %d: index %d, timestamp %" GST_TIME_FORMAT,
6949 (guint) (cur - samples), j,
6950 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stts_time)));
6952 cur->timestamp = stts_time;
6953 cur->duration = stts_duration;
6955 /* avoid 32-bit wrap-around,
6956 * but still mind possible 'negative' duration */
6957 stts_time += (gint64) stts_duration;
6960 if (G_UNLIKELY (cur > last)) {
6962 stream->stts_time = stts_time;
6963 stream->stts_sample_index = j + 1;
6967 stream->stts_sample_index = 0;
6968 stream->stts_time = stts_time;
6969 stream->stts_index++;
6971 /* fill up empty timestamps with the last timestamp, this can happen when
6972 * the last samples do not decode and so we don't have timestamps for them.
6973 * We however look at the last timestamp to estimate the track length so we
6974 * need something in here. */
6975 for (; cur < last; cur++) {
6976 GST_DEBUG_OBJECT (qtdemux,
6977 "fill sample %d: timestamp %" GST_TIME_FORMAT,
6978 (guint) (cur - samples),
6979 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stream->stts_time)));
6980 cur->timestamp = stream->stts_time;
6986 /* sample sync, can be NULL */
6987 if (stream->stss_present == TRUE) {
6988 guint32 n_sample_syncs;
6990 n_sample_syncs = stream->n_sample_syncs;
6992 if (!n_sample_syncs) {
6993 GST_DEBUG_OBJECT (qtdemux, "all samples are keyframes");
6994 stream->all_keyframe = TRUE;
6996 for (i = stream->stss_index; i < n_sample_syncs; i++) {
6997 /* note that the first sample is index 1, not 0 */
7000 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stss);
7002 if (G_LIKELY (index > 0 && index <= n_samples)) {
7004 samples[index].keyframe = TRUE;
7005 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
7006 /* and exit if we have enough samples */
7007 if (G_UNLIKELY (index >= n)) {
7014 stream->stss_index = i;
7017 /* stps marks partial sync frames like open GOP I-Frames */
7018 if (stream->stps_present == TRUE) {
7019 guint32 n_sample_partial_syncs;
7021 n_sample_partial_syncs = stream->n_sample_partial_syncs;
7023 /* if there are no entries, the stss table contains the real
7025 if (n_sample_partial_syncs) {
7026 for (i = stream->stps_index; i < n_sample_partial_syncs; i++) {
7027 /* note that the first sample is index 1, not 0 */
7030 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stps);
7032 if (G_LIKELY (index > 0 && index <= n_samples)) {
7034 samples[index].keyframe = TRUE;
7035 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
7036 /* and exit if we have enough samples */
7037 if (G_UNLIKELY (index >= n)) {
7044 stream->stps_index = i;
7048 /* no stss, all samples are keyframes */
7049 stream->all_keyframe = TRUE;
7050 GST_DEBUG_OBJECT (qtdemux, "setting all keyframes");
7055 /* composition time to sample */
7056 if (stream->ctts_present == TRUE) {
7057 guint32 n_composition_times;
7059 gint32 ctts_soffset;
7061 /* Fill in the pts_offsets */
7063 n_composition_times = stream->n_composition_times;
7065 for (i = stream->ctts_index; i < n_composition_times; i++) {
7066 if (stream->ctts_sample_index >= stream->ctts_count
7067 || !stream->ctts_sample_index) {
7068 stream->ctts_count =
7069 gst_byte_reader_get_uint32_be_unchecked (&stream->ctts);
7070 stream->ctts_soffset =
7071 gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
7072 stream->ctts_sample_index = 0;
7075 ctts_count = stream->ctts_count;
7076 ctts_soffset = stream->ctts_soffset;
7078 for (j = stream->ctts_sample_index; j < ctts_count; j++) {
7079 cur->pts_offset = ctts_soffset;
7082 if (G_UNLIKELY (cur > last)) {
7084 stream->ctts_sample_index = j + 1;
7088 stream->ctts_sample_index = 0;
7089 stream->ctts_index++;
7093 stream->stbl_index = n;
7094 /* if index has been completely parsed, free data that is no-longer needed */
7095 if (n + 1 == stream->n_samples) {
7096 gst_qtdemux_stbl_free (stream);
7097 GST_DEBUG_OBJECT (qtdemux,
7098 "parsed all available samples; checking for more");
7099 while (n + 1 == stream->n_samples)
7100 if (qtdemux_add_fragmented_samples (qtdemux) != GST_FLOW_OK)
7103 GST_OBJECT_UNLOCK (qtdemux);
7110 GST_LOG_OBJECT (qtdemux,
7111 "Tried to parse up to sample %u but this sample has already been parsed",
7113 /* if fragmented, there may be more */
7114 if (qtdemux->fragmented && n == stream->stbl_index)
7116 GST_OBJECT_UNLOCK (qtdemux);
7122 GST_LOG_OBJECT (qtdemux,
7123 "Tried to parse up to sample %u but there are only %u samples", n + 1,
7125 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
7126 (_("This file is corrupt and cannot be played.")), (NULL));
7131 GST_OBJECT_UNLOCK (qtdemux);
7132 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
7133 (_("This file is corrupt and cannot be played.")), (NULL));
7138 /* collect all segment info for @stream.
7141 qtdemux_parse_segments (GstQTDemux * qtdemux, QtDemuxStream * stream,
7146 /* parse and prepare segment info from the edit list */
7147 GST_DEBUG_OBJECT (qtdemux, "looking for edit list container");
7148 stream->n_segments = 0;
7149 stream->segments = NULL;
7150 if ((edts = qtdemux_tree_get_child_by_type (trak, FOURCC_edts))) {
7158 GST_DEBUG_OBJECT (qtdemux, "looking for edit list");
7159 if (!(elst = qtdemux_tree_get_child_by_type (edts, FOURCC_elst)))
7162 buffer = elst->data;
7164 n_segments = QT_UINT32 (buffer + 12);
7166 /* we might allocate a bit too much, at least allocate 1 segment */
7167 stream->segments = g_new (QtDemuxSegment, MAX (n_segments, 1));
7169 /* segments always start from 0 */
7173 for (i = 0; i < n_segments; i++) {
7176 QtDemuxSegment *segment;
7179 media_time = QT_UINT32 (buffer + 20 + i * 12);
7180 duration = QT_UINT32 (buffer + 16 + i * 12);
7182 segment = &stream->segments[count++];
7184 /* time and duration expressed in global timescale */
7185 segment->time = stime;
7186 /* add non scaled values so we don't cause roundoff errors */
7188 stime = QTTIME_TO_GSTTIME (qtdemux, time);
7189 segment->stop_time = stime;
7190 segment->duration = stime - segment->time;
7192 segment->trak_media_start = media_time;
7193 /* media_time expressed in stream timescale */
7194 if (media_time != G_MAXUINT32) {
7195 segment->media_start = QTSTREAMTIME_TO_GSTTIME (stream, media_time);
7196 segment->media_stop = segment->media_start + segment->duration;
7198 segment->media_start = GST_CLOCK_TIME_NONE;
7199 segment->media_stop = GST_CLOCK_TIME_NONE;
7201 rate_int = GST_READ_UINT32_BE (buffer + 24 + i * 12);
7203 if (rate_int <= 1) {
7204 /* 0 is not allowed, some programs write 1 instead of the floating point
7206 GST_WARNING_OBJECT (qtdemux, "found suspicious rate %" G_GUINT32_FORMAT,
7210 segment->rate = rate_int / 65536.0;
7213 GST_DEBUG_OBJECT (qtdemux, "created segment %d time %" GST_TIME_FORMAT
7214 ", duration %" GST_TIME_FORMAT ", media_start %" GST_TIME_FORMAT
7215 " (%" G_GUINT64_FORMAT ") , media_stop %" GST_TIME_FORMAT
7216 " stop_time %" GST_TIME_FORMAT " rate %g, (%d) timescale %u",
7217 i, GST_TIME_ARGS (segment->time),
7218 GST_TIME_ARGS (segment->duration),
7219 GST_TIME_ARGS (segment->media_start), media_time,
7220 GST_TIME_ARGS (segment->media_stop),
7221 GST_TIME_ARGS (segment->stop_time), segment->rate, rate_int,
7223 if (segment->stop_time > qtdemux->segment.stop) {
7224 GST_WARNING_OBJECT (qtdemux, "Segment %d "
7225 " extends to %" GST_TIME_FORMAT
7226 " past the end of the file duration %" GST_TIME_FORMAT
7227 " it will be truncated", i, GST_TIME_ARGS (segment->stop_time),
7228 GST_TIME_ARGS (qtdemux->segment.stop));
7229 qtdemux->segment.stop = segment->stop_time;
7232 GST_DEBUG_OBJECT (qtdemux, "found %d segments", count);
7233 stream->n_segments = count;
7237 /* push based does not handle segments, so act accordingly here,
7238 * and warn if applicable */
7239 if (!qtdemux->pullbased) {
7240 GST_WARNING_OBJECT (qtdemux, "streaming; discarding edit list segments");
7241 /* remove and use default one below, we stream like it anyway */
7242 g_free (stream->segments);
7243 stream->segments = NULL;
7244 stream->n_segments = 0;
7247 /* no segments, create one to play the complete trak */
7248 if (stream->n_segments == 0) {
7249 GstClockTime stream_duration =
7250 QTSTREAMTIME_TO_GSTTIME (stream, stream->duration);
7252 if (stream->segments == NULL)
7253 stream->segments = g_new (QtDemuxSegment, 1);
7255 /* represent unknown our way */
7256 if (stream_duration == 0)
7257 stream_duration = GST_CLOCK_TIME_NONE;
7259 stream->segments[0].time = 0;
7260 stream->segments[0].stop_time = stream_duration;
7261 stream->segments[0].duration = stream_duration;
7262 stream->segments[0].media_start = 0;
7263 stream->segments[0].media_stop = stream_duration;
7264 stream->segments[0].rate = 1.0;
7265 stream->segments[0].trak_media_start = 0;
7267 GST_DEBUG_OBJECT (qtdemux, "created dummy segment %" GST_TIME_FORMAT,
7268 GST_TIME_ARGS (stream_duration));
7269 stream->n_segments = 1;
7270 stream->dummy_segment = TRUE;
7272 GST_DEBUG_OBJECT (qtdemux, "using %d segments", stream->n_segments);
7278 * Parses the stsd atom of a svq3 trak looking for
7279 * the SMI and gama atoms.
7282 qtdemux_parse_svq3_stsd_data (GstQTDemux * qtdemux, GNode * stsd,
7283 guint8 ** gamma, GstBuffer ** seqh)
7285 guint8 *_gamma = NULL;
7286 GstBuffer *_seqh = NULL;
7287 guint8 *stsd_data = stsd->data;
7288 guint32 length = QT_UINT32 (stsd_data);
7292 GST_WARNING_OBJECT (qtdemux, "stsd too short");
7298 version = QT_UINT16 (stsd_data);
7303 while (length > 8) {
7304 guint32 fourcc, size;
7306 size = QT_UINT32 (stsd_data);
7307 fourcc = QT_FOURCC (stsd_data + 4);
7308 data = stsd_data + 8;
7311 GST_WARNING_OBJECT (qtdemux, "Atom of size 0 found, aborting "
7312 "svq3 atom parsing");
7321 GST_WARNING_OBJECT (qtdemux, "Unexpected size %" G_GUINT32_FORMAT
7322 " for gama atom, expected 12", size);
7327 if (size > 16 && QT_FOURCC (data) == FOURCC_SEQH) {
7329 if (_seqh != NULL) {
7330 GST_WARNING_OBJECT (qtdemux, "Unexpected second SEQH SMI atom "
7331 " found, ignoring");
7333 seqh_size = QT_UINT32 (data + 4);
7334 if (seqh_size > 0) {
7335 _seqh = gst_buffer_new_and_alloc (seqh_size);
7336 gst_buffer_fill (_seqh, 0, data + 8, seqh_size);
7343 GST_WARNING_OBJECT (qtdemux, "Unhandled atom %" GST_FOURCC_FORMAT
7344 " in SVQ3 entry in stsd atom", GST_FOURCC_ARGS (fourcc));
7348 if (size <= length) {
7354 GST_WARNING_OBJECT (qtdemux, "SVQ3 entry too short in stsd atom");
7357 GST_WARNING_OBJECT (qtdemux, "Unexpected version for SVQ3 entry %"
7358 G_GUINT16_FORMAT, version);
7369 gst_buffer_unref (_seqh);
7374 qtdemux_get_rtsp_uri_from_hndl (GstQTDemux * qtdemux, GNode * minf)
7381 * Get 'dinf', to get its child 'dref', that might contain a 'hndl'
7382 * atom that might contain a 'data' atom with the rtsp uri.
7383 * This case was reported in bug #597497, some info about
7384 * the hndl atom can be found in TN1195
7386 dinf = qtdemux_tree_get_child_by_type (minf, FOURCC_dinf);
7387 GST_DEBUG_OBJECT (qtdemux, "Trying to obtain rtsp URI for stream trak");
7390 guint32 dref_num_entries = 0;
7391 if (qtdemux_tree_get_child_by_type_full (dinf, FOURCC_dref, &dref) &&
7392 gst_byte_reader_skip (&dref, 4) &&
7393 gst_byte_reader_get_uint32_be (&dref, &dref_num_entries)) {
7396 /* search dref entries for hndl atom */
7397 for (i = 0; i < dref_num_entries; i++) {
7398 guint32 size = 0, type;
7399 guint8 string_len = 0;
7400 if (gst_byte_reader_get_uint32_be (&dref, &size) &&
7401 qt_atom_parser_get_fourcc (&dref, &type)) {
7402 if (type == FOURCC_hndl) {
7403 GST_DEBUG_OBJECT (qtdemux, "Found hndl atom");
7405 /* skip data reference handle bytes and the
7406 * following pascal string and some extra 4
7407 * bytes I have no idea what are */
7408 if (!gst_byte_reader_skip (&dref, 4) ||
7409 !gst_byte_reader_get_uint8 (&dref, &string_len) ||
7410 !gst_byte_reader_skip (&dref, string_len + 4)) {
7411 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl atom");
7415 /* iterate over the atoms to find the data atom */
7416 while (gst_byte_reader_get_remaining (&dref) >= 8) {
7420 if (gst_byte_reader_get_uint32_be (&dref, &atom_size) &&
7421 qt_atom_parser_get_fourcc (&dref, &atom_type)) {
7422 if (atom_type == FOURCC_data) {
7423 const guint8 *uri_aux = NULL;
7425 /* found the data atom that might contain the rtsp uri */
7426 GST_DEBUG_OBJECT (qtdemux, "Found data atom inside "
7427 "hndl atom, interpreting it as an URI");
7428 if (gst_byte_reader_peek_data (&dref, atom_size - 8,
7430 if (g_strstr_len ((gchar *) uri_aux, 7, "rtsp://") != NULL)
7431 uri = g_strndup ((gchar *) uri_aux, atom_size - 8);
7433 GST_WARNING_OBJECT (qtdemux, "Data atom in hndl atom "
7434 "didn't contain a rtsp address");
7436 GST_WARNING_OBJECT (qtdemux, "Failed to get the data "
7441 /* skipping to the next entry */
7442 if (!gst_byte_reader_skip (&dref, atom_size - 8))
7445 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl child "
7452 /* skip to the next entry */
7453 if (!gst_byte_reader_skip (&dref, size - 8))
7456 GST_WARNING_OBJECT (qtdemux, "Error parsing dref atom");
7459 GST_DEBUG_OBJECT (qtdemux, "Finished parsing dref atom");
7465 #define AMR_NB_ALL_MODES 0x81ff
7466 #define AMR_WB_ALL_MODES 0x83ff
7468 qtdemux_parse_amr_bitrate (GstBuffer * buf, gboolean wb)
7470 /* The 'damr' atom is of the form:
7472 * | vendor | decoder_ver | mode_set | mode_change_period | frames/sample |
7473 * 32 b 8 b 16 b 8 b 8 b
7475 * The highest set bit of the first 7 (AMR-NB) or 8 (AMR-WB) bits of mode_set
7476 * represents the highest mode used in the stream (and thus the maximum
7477 * bitrate), with a couple of special cases as seen below.
7480 /* Map of frame type ID -> bitrate */
7481 static const guint nb_bitrates[] = {
7482 4750, 5150, 5900, 6700, 7400, 7950, 10200, 12200
7484 static const guint wb_bitrates[] = {
7485 6600, 8850, 12650, 14250, 15850, 18250, 19850, 23050, 23850
7491 gst_buffer_map (buf, &map, GST_MAP_READ);
7493 if (map.size != 0x11) {
7494 GST_DEBUG ("Atom should have size 0x11, not %" G_GSIZE_FORMAT, map.size);
7498 if (QT_FOURCC (map.data + 4) != GST_MAKE_FOURCC ('d', 'a', 'm', 'r')) {
7499 GST_DEBUG ("Unknown atom in %" GST_FOURCC_FORMAT,
7500 GST_FOURCC_ARGS (QT_UINT32 (map.data + 4)));
7504 mode_set = QT_UINT16 (map.data + 13);
7506 if (mode_set == (wb ? AMR_WB_ALL_MODES : AMR_NB_ALL_MODES))
7507 max_mode = 7 + (wb ? 1 : 0);
7509 /* AMR-NB modes fo from 0-7, and AMR-WB modes go from 0-8 */
7510 max_mode = g_bit_nth_msf ((gulong) mode_set & (wb ? 0x1ff : 0xff), -1);
7512 if (max_mode == -1) {
7513 GST_DEBUG ("No mode indication was found (mode set) = %x",
7518 gst_buffer_unmap (buf, &map);
7519 return wb ? wb_bitrates[max_mode] : nb_bitrates[max_mode];
7522 gst_buffer_unmap (buf, &map);
7527 qtdemux_parse_transformation_matrix (GstQTDemux * qtdemux,
7528 GstByteReader * reader, guint32 * matrix, const gchar * atom)
7531 * 9 values of 32 bits (fixed point 16.16, except 2 5 and 8 that are 2.30)
7537 if (gst_byte_reader_get_remaining (reader) < 36)
7540 matrix[0] = gst_byte_reader_get_uint32_be_unchecked (reader);
7541 matrix[1] = gst_byte_reader_get_uint32_be_unchecked (reader);
7542 matrix[2] = gst_byte_reader_get_uint32_be_unchecked (reader);
7543 matrix[3] = gst_byte_reader_get_uint32_be_unchecked (reader);
7544 matrix[4] = gst_byte_reader_get_uint32_be_unchecked (reader);
7545 matrix[5] = gst_byte_reader_get_uint32_be_unchecked (reader);
7546 matrix[6] = gst_byte_reader_get_uint32_be_unchecked (reader);
7547 matrix[7] = gst_byte_reader_get_uint32_be_unchecked (reader);
7548 matrix[8] = gst_byte_reader_get_uint32_be_unchecked (reader);
7550 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix from atom %s", atom);
7551 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[0] >> 16,
7552 matrix[0] & 0xFFFF, matrix[1] >> 16, matrix[1] & 0xFF, matrix[2] >> 16,
7554 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[3] >> 16,
7555 matrix[3] & 0xFFFF, matrix[4] >> 16, matrix[4] & 0xFF, matrix[5] >> 16,
7557 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[6] >> 16,
7558 matrix[6] & 0xFFFF, matrix[7] >> 16, matrix[7] & 0xFF, matrix[8] >> 16,
7565 qtdemux_inspect_transformation_matrix (GstQTDemux * qtdemux,
7566 QtDemuxStream * stream, guint32 * matrix, GstTagList ** taglist)
7573 * This macro will only compare value abdegh, it expects cfi to have already
7576 #define QTCHECK_MATRIX(m,a,b,d,e,g,h) ((m)[0] == (a << 16) && (m)[1] == (b << 16) && \
7577 (m)[3] == (d << 16) && (m)[4] == (e << 16) && \
7578 (m)[6] == (g << 16) && (m)[7] == (h << 16))
7580 /* only handle the cases where the last column has standard values */
7581 if (matrix[2] == 0 && matrix[5] == 0 && matrix[8] == 1 << 30) {
7582 const gchar *rotation_tag = NULL;
7584 /* no rotation needed */
7585 if (QTCHECK_MATRIX (matrix, 1, 0, 0, 1, 0, 0)) {
7587 } else if (QTCHECK_MATRIX (matrix, 0, 1, G_MAXUINT16, 0,
7588 stream->display_height, 0)) {
7589 rotation_tag = "rotate-90";
7590 } else if (QTCHECK_MATRIX (matrix, G_MAXUINT16, 0, 0, G_MAXUINT16,
7591 stream->display_width, stream->display_height)) {
7592 rotation_tag = "rotate-180";
7593 } else if (QTCHECK_MATRIX (matrix, 0, G_MAXUINT16, 1, 0, 0,
7594 stream->display_width)) {
7595 rotation_tag = "rotate-270";
7597 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
7600 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix rotation %s",
7602 if (rotation_tag != NULL) {
7603 if (*taglist == NULL)
7604 *taglist = gst_tag_list_new_empty ();
7605 gst_tag_list_add (*taglist, GST_TAG_MERGE_REPLACE,
7606 GST_TAG_IMAGE_ORIENTATION, rotation_tag, NULL);
7609 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
7614 * With each track we associate a new QtDemuxStream that contains all the info
7616 * traks that do not decode to something (like strm traks) will not have a pad.
7619 qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
7637 QtDemuxStream *stream = NULL;
7638 gboolean new_stream = FALSE;
7639 gchar *codec = NULL;
7640 const guint8 *stsd_data;
7641 guint16 lang_code; /* quicktime lang code or packed iso code */
7643 guint32 tkhd_flags = 0;
7644 guint8 tkhd_version = 0;
7646 guint value_size, stsd_len, len;
7649 GST_DEBUG_OBJECT (qtdemux, "parse_trak");
7651 if (!qtdemux_tree_get_child_by_type_full (trak, FOURCC_tkhd, &tkhd)
7652 || !gst_byte_reader_get_uint8 (&tkhd, &tkhd_version)
7653 || !gst_byte_reader_get_uint24_be (&tkhd, &tkhd_flags))
7656 /* pick between 64 or 32 bits */
7657 value_size = tkhd_version == 1 ? 8 : 4;
7658 if (!gst_byte_reader_skip (&tkhd, value_size * 2) ||
7659 !gst_byte_reader_get_uint32_be (&tkhd, &track_id))
7662 if (!qtdemux->got_moov) {
7663 if (qtdemux_find_stream (qtdemux, track_id))
7664 goto existing_stream;
7665 stream = _create_stream ();
7666 stream->track_id = track_id;
7669 stream = qtdemux_find_stream (qtdemux, track_id);
7671 GST_WARNING_OBJECT (qtdemux, "Stream not found, going to ignore it");
7676 if (stream->pending_tags == NULL)
7677 stream->pending_tags = gst_tag_list_new_empty ();
7679 if ((tkhd_flags & 1) == 0)
7680 stream->disabled = TRUE;
7682 GST_LOG_OBJECT (qtdemux, "track[tkhd] version/flags/id: 0x%02x/%06x/%u",
7683 tkhd_version, tkhd_flags, stream->track_id);
7685 if (!(mdia = qtdemux_tree_get_child_by_type (trak, FOURCC_mdia)))
7688 if (!(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mdhd))) {
7689 /* be nice for some crooked mjp2 files that use mhdr for mdhd */
7690 if (qtdemux->major_brand != FOURCC_mjp2 ||
7691 !(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mhdr)))
7695 len = QT_UINT32 ((guint8 *) mdhd->data);
7696 version = QT_UINT32 ((guint8 *) mdhd->data + 8);
7697 GST_LOG_OBJECT (qtdemux, "track version/flags: %08x", version);
7698 if (version == 0x01000000) {
7701 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 28);
7702 stream->duration = QT_UINT64 ((guint8 *) mdhd->data + 32);
7703 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 36);
7707 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 20);
7708 stream->duration = QT_UINT32 ((guint8 *) mdhd->data + 24);
7709 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 28);
7712 if (lang_code < 0x400) {
7713 qtdemux_lang_map_qt_code_to_iso (stream->lang_id, lang_code);
7714 } else if (lang_code == 0x7fff) {
7715 stream->lang_id[0] = 0; /* unspecified */
7717 stream->lang_id[0] = 0x60 + ((lang_code >> 10) & 0x1F);
7718 stream->lang_id[1] = 0x60 + ((lang_code >> 5) & 0x1F);
7719 stream->lang_id[2] = 0x60 + (lang_code & 0x1F);
7720 stream->lang_id[3] = 0;
7723 GST_LOG_OBJECT (qtdemux, "track timescale: %" G_GUINT32_FORMAT,
7725 GST_LOG_OBJECT (qtdemux, "track duration: %" G_GUINT64_FORMAT,
7727 GST_LOG_OBJECT (qtdemux, "track language code/id: 0x%04x/%s",
7728 lang_code, stream->lang_id);
7730 if (G_UNLIKELY (stream->timescale == 0 || qtdemux->timescale == 0))
7733 if ((tref = qtdemux_tree_get_child_by_type (trak, FOURCC_tref))) {
7734 /* chapters track reference */
7735 GNode *chap = qtdemux_tree_get_child_by_type (tref, FOURCC_chap);
7737 gsize length = GST_READ_UINT32_BE (chap->data);
7738 if (qtdemux->chapters_track_id)
7739 GST_FIXME_OBJECT (qtdemux, "Multiple CHAP tracks");
7742 qtdemux->chapters_track_id =
7743 GST_READ_UINT32_BE ((gint8 *) chap->data + 8);
7748 /* fragmented files may have bogus duration in moov */
7749 if (!qtdemux->fragmented &&
7750 qtdemux->duration != G_MAXINT64 && stream->duration != G_MAXINT32) {
7751 guint64 tdur1, tdur2;
7753 /* don't overflow */
7754 tdur1 = stream->timescale * (guint64) qtdemux->duration;
7755 tdur2 = qtdemux->timescale * (guint64) stream->duration;
7758 * some of those trailers, nowadays, have prologue images that are
7759 * themselves vide tracks as well. I haven't really found a way to
7760 * identify those yet, except for just looking at their duration. */
7761 if (tdur1 != 0 && (tdur2 * 10 / tdur1) < 2) {
7762 GST_WARNING_OBJECT (qtdemux,
7763 "Track shorter than 20%% (%" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT
7764 " vs. %" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT ") of the stream "
7765 "found, assuming preview image or something; skipping track",
7766 stream->duration, stream->timescale, qtdemux->duration,
7767 qtdemux->timescale);
7773 if (!(hdlr = qtdemux_tree_get_child_by_type (mdia, FOURCC_hdlr)))
7776 GST_LOG_OBJECT (qtdemux, "track type: %" GST_FOURCC_FORMAT,
7777 GST_FOURCC_ARGS (QT_FOURCC ((guint8 *) hdlr->data + 12)));
7779 len = QT_UINT32 ((guint8 *) hdlr->data);
7781 stream->subtype = QT_FOURCC ((guint8 *) hdlr->data + 16);
7782 GST_LOG_OBJECT (qtdemux, "track subtype: %" GST_FOURCC_FORMAT,
7783 GST_FOURCC_ARGS (stream->subtype));
7785 if (!(minf = qtdemux_tree_get_child_by_type (mdia, FOURCC_minf)))
7788 if (!(stbl = qtdemux_tree_get_child_by_type (minf, FOURCC_stbl)))
7792 if (!(stsd = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsd)))
7794 stsd_data = (const guint8 *) stsd->data;
7796 /* stsd should at least have one entry */
7797 stsd_len = QT_UINT32 (stsd_data);
7798 if (stsd_len < 24) {
7799 /* .. but skip stream with empty stsd produced by some Vivotek cameras */
7800 if (stream->subtype == FOURCC_vivo) {
7808 GST_LOG_OBJECT (qtdemux, "stsd len: %d", stsd_len);
7810 /* and that entry should fit within stsd */
7811 len = QT_UINT32 (stsd_data + 16);
7812 if (len > stsd_len + 16)
7815 stream->fourcc = fourcc = QT_FOURCC (stsd_data + 16 + 4);
7816 GST_LOG_OBJECT (qtdemux, "stsd type: %" GST_FOURCC_FORMAT,
7817 GST_FOURCC_ARGS (stream->fourcc));
7818 GST_LOG_OBJECT (qtdemux, "stsd type len: %d", len);
7820 if ((fourcc == FOURCC_drms) || (fourcc == FOURCC_drmi) ||
7821 ((fourcc & 0x00FFFFFF) == GST_MAKE_FOURCC ('e', 'n', 'c', 0)))
7822 goto error_encrypted;
7824 if (stream->subtype == FOURCC_vide) {
7825 guint32 w = 0, h = 0;
7827 gint depth, palette_size, palette_count;
7829 guint32 *palette_data = NULL;
7831 stream->sampled = TRUE;
7833 /* version 1 uses some 64-bit ints */
7834 if (!gst_byte_reader_skip (&tkhd, 20 + value_size))
7837 if (!qtdemux_parse_transformation_matrix (qtdemux, &tkhd, matrix, "tkhd"))
7840 if (!gst_byte_reader_get_uint32_be (&tkhd, &w)
7841 || !gst_byte_reader_get_uint32_be (&tkhd, &h))
7844 stream->display_width = w >> 16;
7845 stream->display_height = h >> 16;
7847 qtdemux_inspect_transformation_matrix (qtdemux, stream, matrix,
7848 &stream->pending_tags);
7854 stream->width = QT_UINT16 (stsd_data + offset + 32);
7855 stream->height = QT_UINT16 (stsd_data + offset + 34);
7856 stream->fps_n = 0; /* this is filled in later */
7857 stream->fps_d = 0; /* this is filled in later */
7858 stream->bits_per_sample = QT_UINT16 (stsd_data + offset + 82);
7859 stream->color_table_id = QT_UINT16 (stsd_data + offset + 84);
7861 GST_LOG_OBJECT (qtdemux, "width %d, height %d, bps %d, color table id %d",
7862 stream->width, stream->height, stream->bits_per_sample,
7863 stream->color_table_id);
7865 depth = stream->bits_per_sample;
7867 /* more than 32 bits means grayscale */
7868 gray = (depth > 32);
7869 /* low 32 bits specify the depth */
7872 /* different number of palette entries is determined by depth. */
7874 if ((depth == 1) || (depth == 2) || (depth == 4) || (depth == 8))
7875 palette_count = (1 << depth);
7876 palette_size = palette_count * 4;
7878 if (stream->color_table_id) {
7879 switch (palette_count) {
7883 palette_data = g_memdup (ff_qt_default_palette_2, palette_size);
7886 palette_data = g_memdup (ff_qt_default_palette_4, palette_size);
7890 palette_data = g_memdup (ff_qt_grayscale_palette_16, palette_size);
7892 palette_data = g_memdup (ff_qt_default_palette_16, palette_size);
7896 palette_data = g_memdup (ff_qt_grayscale_palette_256, palette_size);
7898 palette_data = g_memdup (ff_qt_default_palette_256, palette_size);
7901 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
7902 (_("The video in this file might not play correctly.")),
7903 ("unsupported palette depth %d", depth));
7907 gint i, j, start, end;
7913 start = QT_UINT32 (stsd_data + offset + 86);
7914 palette_count = QT_UINT16 (stsd_data + offset + 90);
7915 end = QT_UINT16 (stsd_data + offset + 92);
7917 GST_LOG_OBJECT (qtdemux, "start %d, end %d, palette_count %d",
7918 start, end, palette_count);
7925 if (len < 94 + (end - start) * 8)
7928 /* palette is always the same size */
7929 palette_data = g_malloc0 (256 * 4);
7930 palette_size = 256 * 4;
7932 for (j = 0, i = start; i <= end; j++, i++) {
7935 a = QT_UINT16 (stsd_data + offset + 94 + (j * 8));
7936 r = QT_UINT16 (stsd_data + offset + 96 + (j * 8));
7937 g = QT_UINT16 (stsd_data + offset + 98 + (j * 8));
7938 b = QT_UINT16 (stsd_data + offset + 100 + (j * 8));
7940 palette_data[i] = ((a & 0xff00) << 16) | ((r & 0xff00) << 8) |
7941 (g & 0xff00) | (b >> 8);
7946 qtdemux_video_caps (qtdemux, stream, fourcc, stsd_data, &codec);
7947 if (G_UNLIKELY (!stream->caps)) {
7948 g_free (palette_data);
7949 goto unknown_stream;
7953 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
7954 GST_TAG_VIDEO_CODEC, codec, NULL);
7963 if (stream->rgb8_palette)
7964 gst_memory_unref (stream->rgb8_palette);
7965 stream->rgb8_palette = gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY,
7966 palette_data, palette_size, 0, palette_size, palette_data, g_free);
7968 s = gst_caps_get_structure (stream->caps, 0);
7970 /* non-raw video has a palette_data property. raw video has the palette as
7971 * an extra plane that we append to the output buffers before we push
7973 if (!gst_structure_has_name (s, "video/x-raw")) {
7976 palette = gst_buffer_new ();
7977 gst_buffer_append_memory (palette, stream->rgb8_palette);
7978 stream->rgb8_palette = NULL;
7980 gst_caps_set_simple (stream->caps, "palette_data",
7981 GST_TYPE_BUFFER, palette, NULL);
7982 gst_buffer_unref (palette);
7984 } else if (palette_count != 0) {
7985 GST_ELEMENT_WARNING (qtdemux, STREAM, NOT_IMPLEMENTED,
7986 (NULL), ("Unsupported palette depth %d", depth));
7989 GST_LOG_OBJECT (qtdemux, "frame count: %u",
7990 QT_UINT16 (stsd_data + offset + 48));
7994 /* pick 'the' stsd child */
7995 mp4v = qtdemux_tree_get_child_by_type (stsd, fourcc);
7997 esds = qtdemux_tree_get_child_by_type (mp4v, FOURCC_esds);
7998 pasp = qtdemux_tree_get_child_by_type (mp4v, FOURCC_pasp);
8002 const guint8 *pasp_data = (const guint8 *) pasp->data;
8004 stream->par_w = QT_UINT32 (pasp_data + 8);
8005 stream->par_h = QT_UINT32 (pasp_data + 12);
8012 gst_qtdemux_handle_esds (qtdemux, stream, esds, stream->pending_tags);
8019 gint len = QT_UINT32 (stsd_data) - 0x66;
8020 const guint8 *avc_data = stsd_data + 0x66;
8023 while (len >= 0x8) {
8026 if (QT_UINT32 (avc_data) <= len)
8027 size = QT_UINT32 (avc_data) - 0x8;
8032 /* No real data, so break out */
8035 switch (QT_FOURCC (avc_data + 0x4)) {
8038 /* parse, if found */
8041 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
8043 /* First 4 bytes are the length of the atom, the next 4 bytes
8044 * are the fourcc, the next 1 byte is the version, and the
8045 * subsequent bytes are profile_tier_level structure like data. */
8046 gst_codec_utils_h264_caps_set_level_and_profile (stream->caps,
8047 avc_data + 8 + 1, size - 1);
8048 buf = gst_buffer_new_and_alloc (size);
8049 gst_buffer_fill (buf, 0, avc_data + 0x8, size);
8050 gst_caps_set_simple (stream->caps,
8051 "codec_data", GST_TYPE_BUFFER, buf, NULL);
8052 gst_buffer_unref (buf);
8060 GST_DEBUG_OBJECT (qtdemux, "found strf codec_data in stsd");
8062 /* First 4 bytes are the length of the atom, the next 4 bytes
8063 * are the fourcc, next 40 bytes are BITMAPINFOHEADER,
8064 * next 1 byte is the version, and the
8065 * subsequent bytes are sequence parameter set like data. */
8067 size -= 40; /* we'll be skipping BITMAPINFOHEADER */
8069 gst_codec_utils_h264_caps_set_level_and_profile (stream->caps,
8070 avc_data + 8 + 40 + 1, size - 1);
8072 buf = gst_buffer_new_and_alloc (size);
8073 gst_buffer_fill (buf, 0, avc_data + 8 + 40, size);
8074 gst_caps_set_simple (stream->caps,
8075 "codec_data", GST_TYPE_BUFFER, buf, NULL);
8076 gst_buffer_unref (buf);
8082 guint avg_bitrate, max_bitrate;
8084 /* bufferSizeDB, maxBitrate and avgBitrate - 4 bytes each */
8088 max_bitrate = QT_UINT32 (avc_data + 0xc);
8089 avg_bitrate = QT_UINT32 (avc_data + 0x10);
8091 if (!max_bitrate && !avg_bitrate)
8094 /* Some muxers seem to swap the average and maximum bitrates
8095 * (I'm looking at you, YouTube), so we swap for sanity. */
8096 if (max_bitrate > 0 && max_bitrate < avg_bitrate) {
8097 guint temp = avg_bitrate;
8099 avg_bitrate = max_bitrate;
8103 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
8104 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
8105 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
8107 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
8108 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
8109 GST_TAG_BITRATE, avg_bitrate, NULL);
8120 avc_data += size + 8;
8129 gint len = QT_UINT32 (stsd_data) - 0x66;
8130 const guint8 *hevc_data = stsd_data + 0x66;
8133 while (len >= 0x8) {
8136 if (QT_UINT32 (hevc_data) <= len)
8137 size = QT_UINT32 (hevc_data) - 0x8;
8142 /* No real data, so break out */
8145 switch (QT_FOURCC (hevc_data + 0x4)) {
8148 /* parse, if found */
8151 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
8153 /* First 4 bytes are the length of the atom, the next 4 bytes
8154 * are the fourcc, the next 1 byte is the version, and the
8155 * subsequent bytes are sequence parameter set like data. */
8156 gst_codec_utils_h265_caps_set_level_tier_and_profile
8157 (stream->caps, hevc_data + 8 + 1, size - 1);
8159 buf = gst_buffer_new_and_alloc (size);
8160 gst_buffer_fill (buf, 0, hevc_data + 0x8, size);
8161 gst_caps_set_simple (stream->caps,
8162 "codec_data", GST_TYPE_BUFFER, buf, NULL);
8163 gst_buffer_unref (buf);
8170 hevc_data += size + 8;
8181 GST_DEBUG_OBJECT (qtdemux, "found %" GST_FOURCC_FORMAT,
8182 GST_FOURCC_ARGS (fourcc));
8184 /* codec data might be in glbl extension atom */
8186 qtdemux_tree_get_child_by_type (mp4v, FOURCC_glbl) : NULL;
8192 GST_DEBUG_OBJECT (qtdemux, "found glbl data in stsd");
8194 len = QT_UINT32 (data);
8197 buf = gst_buffer_new_and_alloc (len);
8198 gst_buffer_fill (buf, 0, data + 8, len);
8199 gst_caps_set_simple (stream->caps,
8200 "codec_data", GST_TYPE_BUFFER, buf, NULL);
8201 gst_buffer_unref (buf);
8208 /* see annex I of the jpeg2000 spec */
8209 GNode *jp2h, *ihdr, *colr, *mjp2, *field, *prefix, *cmap, *cdef;
8211 const gchar *colorspace = NULL;
8213 guint32 ncomp_map = 0;
8214 gint32 *comp_map = NULL;
8215 guint32 nchan_def = 0;
8216 gint32 *chan_def = NULL;
8218 GST_DEBUG_OBJECT (qtdemux, "found mjp2");
8219 /* some required atoms */
8220 mjp2 = qtdemux_tree_get_child_by_type (stsd, FOURCC_mjp2);
8223 jp2h = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2h);
8227 /* number of components; redundant with info in codestream, but useful
8229 ihdr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_ihdr);
8230 if (!ihdr || QT_UINT32 (ihdr->data) != 22)
8232 ncomp = QT_UINT16 (((guint8 *) ihdr->data) + 16);
8234 colr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_colr);
8237 GST_DEBUG_OBJECT (qtdemux, "found colr");
8238 /* extract colour space info */
8239 if (QT_UINT8 ((guint8 *) colr->data + 8) == 1) {
8240 switch (QT_UINT32 ((guint8 *) colr->data + 11)) {
8242 colorspace = "sRGB";
8245 colorspace = "GRAY";
8248 colorspace = "sYUV";
8256 /* colr is required, and only values 16, 17, and 18 are specified,
8257 so error if we have no colorspace */
8260 /* extract component mapping */
8261 cmap = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cmap);
8263 guint32 cmap_len = 0;
8265 cmap_len = QT_UINT32 (cmap->data);
8266 if (cmap_len >= 8) {
8267 /* normal box, subtract off header */
8269 /* cmap: { u16 cmp; u8 mtyp; u8 pcol; }* */
8270 if (cmap_len % 4 == 0) {
8271 ncomp_map = (cmap_len / 4);
8272 comp_map = g_new0 (gint32, ncomp_map);
8273 for (i = 0; i < ncomp_map; i++) {
8276 cmp = QT_UINT16 (((guint8 *) cmap->data) + 8 + i * 4);
8277 mtyp = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 2);
8278 pcol = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 3);
8279 comp_map[i] = (mtyp << 24) | (pcol << 16) | cmp;
8284 /* extract channel definitions */
8285 cdef = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cdef);
8287 guint32 cdef_len = 0;
8289 cdef_len = QT_UINT32 (cdef->data);
8290 if (cdef_len >= 10) {
8291 /* normal box, subtract off header and len */
8293 /* cdef: u16 n; { u16 cn; u16 typ; u16 asoc; }* */
8294 if (cdef_len % 6 == 0) {
8295 nchan_def = (cdef_len / 6);
8296 chan_def = g_new0 (gint32, nchan_def);
8297 for (i = 0; i < nchan_def; i++)
8299 for (i = 0; i < nchan_def; i++) {
8300 guint16 cn, typ, asoc;
8301 cn = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6);
8302 typ = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 2);
8303 asoc = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 4);
8304 if (cn < nchan_def) {
8307 chan_def[cn] = asoc;
8310 chan_def[cn] = 0; /* alpha */
8313 chan_def[cn] = -typ;
8321 gst_caps_set_simple (stream->caps,
8322 "num-components", G_TYPE_INT, ncomp, NULL);
8323 gst_caps_set_simple (stream->caps,
8324 "colorspace", G_TYPE_STRING, colorspace, NULL);
8327 GValue arr = { 0, };
8328 GValue elt = { 0, };
8330 g_value_init (&arr, GST_TYPE_ARRAY);
8331 g_value_init (&elt, G_TYPE_INT);
8332 for (i = 0; i < ncomp_map; i++) {
8333 g_value_set_int (&elt, comp_map[i]);
8334 gst_value_array_append_value (&arr, &elt);
8336 gst_structure_set_value (gst_caps_get_structure (stream->caps, 0),
8337 "component-map", &arr);
8338 g_value_unset (&elt);
8339 g_value_unset (&arr);
8344 GValue arr = { 0, };
8345 GValue elt = { 0, };
8347 g_value_init (&arr, GST_TYPE_ARRAY);
8348 g_value_init (&elt, G_TYPE_INT);
8349 for (i = 0; i < nchan_def; i++) {
8350 g_value_set_int (&elt, chan_def[i]);
8351 gst_value_array_append_value (&arr, &elt);
8353 gst_structure_set_value (gst_caps_get_structure (stream->caps, 0),
8354 "channel-definitions", &arr);
8355 g_value_unset (&elt);
8356 g_value_unset (&arr);
8360 /* some optional atoms */
8361 field = qtdemux_tree_get_child_by_type (mjp2, FOURCC_fiel);
8362 prefix = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2x);
8364 /* indicate possible fields in caps */
8366 data = (guint8 *) field->data + 8;
8368 gst_caps_set_simple (stream->caps, "fields", G_TYPE_INT,
8369 (gint) * data, NULL);
8371 /* add codec_data if provided */
8376 GST_DEBUG_OBJECT (qtdemux, "found prefix data in stsd");
8377 data = prefix->data;
8378 len = QT_UINT32 (data);
8381 buf = gst_buffer_new_and_alloc (len);
8382 gst_buffer_fill (buf, 0, data + 8, len);
8383 gst_caps_set_simple (stream->caps,
8384 "codec_data", GST_TYPE_BUFFER, buf, NULL);
8385 gst_buffer_unref (buf);
8394 GstBuffer *seqh = NULL;
8395 guint8 *gamma_data = NULL;
8396 gint len = QT_UINT32 (stsd_data);
8398 qtdemux_parse_svq3_stsd_data (qtdemux, stsd, &gamma_data, &seqh);
8400 gst_caps_set_simple (stream->caps, "applied-gamma", G_TYPE_DOUBLE,
8401 QT_FP32 (gamma_data), NULL);
8404 /* sorry for the bad name, but we don't know what this is, other
8405 * than its own fourcc */
8406 gst_caps_set_simple (stream->caps, "seqh", GST_TYPE_BUFFER, seqh,
8410 GST_DEBUG_OBJECT (qtdemux, "found codec_data in stsd");
8411 buf = gst_buffer_new_and_alloc (len);
8412 gst_buffer_fill (buf, 0, stsd_data, len);
8413 gst_caps_set_simple (stream->caps,
8414 "codec_data", GST_TYPE_BUFFER, buf, NULL);
8415 gst_buffer_unref (buf);
8421 gst_caps_set_simple (stream->caps,
8422 "depth", G_TYPE_INT, QT_UINT16 (stsd_data + offset + 82), NULL);
8429 GST_DEBUG_OBJECT (qtdemux, "found XiTh");
8430 xith = qtdemux_tree_get_child_by_type (stsd, FOURCC_XiTh);
8434 xdxt = qtdemux_tree_get_child_by_type (xith, FOURCC_XdxT);
8438 GST_DEBUG_OBJECT (qtdemux, "found XdxT node");
8439 /* collect the headers and store them in a stream list so that we can
8440 * send them out first */
8441 qtdemux_parse_theora_extension (qtdemux, stream, xdxt);
8451 GST_DEBUG_OBJECT (qtdemux, "parse ovc1 header");
8452 ovc1 = qtdemux_tree_get_child_by_type (stsd, FOURCC_ovc1);
8455 ovc1_data = ovc1->data;
8456 ovc1_len = QT_UINT32 (ovc1_data);
8457 if (ovc1_len <= 198) {
8458 GST_WARNING_OBJECT (qtdemux, "Too small ovc1 header, skipping");
8461 buf = gst_buffer_new_and_alloc (ovc1_len - 198);
8462 gst_buffer_fill (buf, 0, ovc1_data + 198, ovc1_len - 198);
8463 gst_caps_set_simple (stream->caps,
8464 "codec_data", GST_TYPE_BUFFER, buf, NULL);
8465 gst_buffer_unref (buf);
8468 case GST_MAKE_FOURCC ('v', 'c', '-', '1'):
8470 gint len = QT_UINT32 (stsd_data) - 0x66;
8471 const guint8 *vc1_data = stsd_data + 0x66;
8477 if (QT_UINT32 (vc1_data) <= len)
8478 size = QT_UINT32 (vc1_data) - 8;
8483 /* No real data, so break out */
8486 switch (QT_FOURCC (vc1_data + 0x4)) {
8487 case GST_MAKE_FOURCC ('d', 'v', 'c', '1'):
8491 GST_DEBUG_OBJECT (qtdemux, "found dvc1 codec_data in stsd");
8492 buf = gst_buffer_new_and_alloc (size);
8493 gst_buffer_fill (buf, 0, vc1_data + 8, size);
8494 gst_caps_set_simple (stream->caps,
8495 "codec_data", GST_TYPE_BUFFER, buf, NULL);
8496 gst_buffer_unref (buf);
8503 vc1_data += size + 8;
8512 GST_INFO_OBJECT (qtdemux,
8513 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
8514 GST_FOURCC_ARGS (fourcc), stream->caps);
8516 } else if (stream->subtype == FOURCC_soun) {
8517 int version, samplesize;
8518 guint16 compression_id;
8519 gboolean amrwb = FALSE;
8522 /* sample description entry (16) + sound sample description v0 (20) */
8526 version = QT_UINT32 (stsd_data + offset);
8527 stream->n_channels = QT_UINT16 (stsd_data + offset + 8);
8528 samplesize = QT_UINT16 (stsd_data + offset + 10);
8529 compression_id = QT_UINT16 (stsd_data + offset + 12);
8530 stream->rate = QT_FP32 (stsd_data + offset + 16);
8532 GST_LOG_OBJECT (qtdemux, "version/rev: %08x", version);
8533 GST_LOG_OBJECT (qtdemux, "vendor: %08x",
8534 QT_UINT32 (stsd_data + offset + 4));
8535 GST_LOG_OBJECT (qtdemux, "n_channels: %d", stream->n_channels);
8536 GST_LOG_OBJECT (qtdemux, "sample_size: %d", samplesize);
8537 GST_LOG_OBJECT (qtdemux, "compression_id: %d", compression_id);
8538 GST_LOG_OBJECT (qtdemux, "packet size: %d",
8539 QT_UINT16 (stsd_data + offset + 14));
8540 GST_LOG_OBJECT (qtdemux, "sample rate: %g", stream->rate);
8542 if (compression_id == 0xfffe)
8543 stream->sampled = TRUE;
8545 /* first assume uncompressed audio */
8546 stream->bytes_per_sample = samplesize / 8;
8547 stream->samples_per_frame = stream->n_channels;
8548 stream->bytes_per_frame = stream->n_channels * stream->bytes_per_sample;
8549 stream->samples_per_packet = stream->samples_per_frame;
8550 stream->bytes_per_packet = stream->bytes_per_sample;
8554 /* Yes, these have to be hard-coded */
8557 stream->samples_per_packet = 6;
8558 stream->bytes_per_packet = 1;
8559 stream->bytes_per_frame = 1 * stream->n_channels;
8560 stream->bytes_per_sample = 1;
8561 stream->samples_per_frame = 6 * stream->n_channels;
8566 stream->samples_per_packet = 3;
8567 stream->bytes_per_packet = 1;
8568 stream->bytes_per_frame = 1 * stream->n_channels;
8569 stream->bytes_per_sample = 1;
8570 stream->samples_per_frame = 3 * stream->n_channels;
8575 stream->samples_per_packet = 64;
8576 stream->bytes_per_packet = 34;
8577 stream->bytes_per_frame = 34 * stream->n_channels;
8578 stream->bytes_per_sample = 2;
8579 stream->samples_per_frame = 64 * stream->n_channels;
8585 stream->samples_per_packet = 1;
8586 stream->bytes_per_packet = 1;
8587 stream->bytes_per_frame = 1 * stream->n_channels;
8588 stream->bytes_per_sample = 1;
8589 stream->samples_per_frame = 1 * stream->n_channels;
8594 stream->samples_per_packet = 160;
8595 stream->bytes_per_packet = 33;
8596 stream->bytes_per_frame = 33 * stream->n_channels;
8597 stream->bytes_per_sample = 2;
8598 stream->samples_per_frame = 160 * stream->n_channels;
8605 if (version == 0x00010000) {
8606 /* sample description entry (16) + sound sample description v1 (20+16) */
8617 /* only parse extra decoding config for non-pcm audio */
8618 stream->samples_per_packet = QT_UINT32 (stsd_data + offset);
8619 stream->bytes_per_packet = QT_UINT32 (stsd_data + offset + 4);
8620 stream->bytes_per_frame = QT_UINT32 (stsd_data + offset + 8);
8621 stream->bytes_per_sample = QT_UINT32 (stsd_data + offset + 12);
8623 GST_LOG_OBJECT (qtdemux, "samples/packet: %d",
8624 stream->samples_per_packet);
8625 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
8626 stream->bytes_per_packet);
8627 GST_LOG_OBJECT (qtdemux, "bytes/frame: %d",
8628 stream->bytes_per_frame);
8629 GST_LOG_OBJECT (qtdemux, "bytes/sample: %d",
8630 stream->bytes_per_sample);
8632 if (!stream->sampled && stream->bytes_per_packet) {
8633 stream->samples_per_frame = (stream->bytes_per_frame /
8634 stream->bytes_per_packet) * stream->samples_per_packet;
8635 GST_LOG_OBJECT (qtdemux, "samples/frame: %d",
8636 stream->samples_per_frame);
8641 } else if (version == 0x00020000) {
8648 /* sample description entry (16) + sound sample description v2 (56) */
8652 qtfp.val = QT_UINT64 (stsd_data + offset + 4);
8653 stream->rate = qtfp.fp;
8654 stream->n_channels = QT_UINT32 (stsd_data + offset + 12);
8656 GST_LOG_OBJECT (qtdemux, "Sound sample description Version 2");
8657 GST_LOG_OBJECT (qtdemux, "sample rate: %g", stream->rate);
8658 GST_LOG_OBJECT (qtdemux, "n_channels: %d", stream->n_channels);
8659 GST_LOG_OBJECT (qtdemux, "bits/channel: %d",
8660 QT_UINT32 (stsd_data + offset + 20));
8661 GST_LOG_OBJECT (qtdemux, "format flags: %X",
8662 QT_UINT32 (stsd_data + offset + 24));
8663 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
8664 QT_UINT32 (stsd_data + offset + 28));
8665 GST_LOG_OBJECT (qtdemux, "LPCM frames/packet: %d",
8666 QT_UINT32 (stsd_data + offset + 32));
8667 } else if (version != 0x00000) {
8668 GST_WARNING_OBJECT (qtdemux, "unknown audio STSD version %08x", version);
8671 stream->caps = qtdemux_audio_caps (qtdemux, stream, fourcc,
8672 stsd_data + 32, len - 16, &codec);
8680 in24 = qtdemux_tree_get_child_by_type (stsd, FOURCC_in24);
8682 enda = qtdemux_tree_get_child_by_type (in24, FOURCC_enda);
8684 wave = qtdemux_tree_get_child_by_type (in24, FOURCC_wave);
8686 enda = qtdemux_tree_get_child_by_type (wave, FOURCC_enda);
8689 int enda_value = QT_UINT16 ((guint8 *) enda->data + 8);
8690 gst_caps_set_simple (stream->caps,
8691 "format", G_TYPE_STRING, (enda_value) ? "S24LE" : "S24BE", NULL);
8698 const guint8 *owma_data;
8699 const gchar *codec_name = NULL;
8703 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
8704 /* FIXME this should also be gst_riff_strf_auds,
8705 * but the latter one is actually missing bits-per-sample :( */
8710 gint32 nSamplesPerSec;
8711 gint32 nAvgBytesPerSec;
8713 gint16 wBitsPerSample;
8718 GST_DEBUG_OBJECT (qtdemux, "parse owma");
8719 owma = qtdemux_tree_get_child_by_type (stsd, FOURCC_owma);
8722 owma_data = owma->data;
8723 owma_len = QT_UINT32 (owma_data);
8724 if (owma_len <= 54) {
8725 GST_WARNING_OBJECT (qtdemux, "Too small owma header, skipping");
8728 wfex = (WAVEFORMATEX *) (owma_data + 36);
8729 buf = gst_buffer_new_and_alloc (owma_len - 54);
8730 gst_buffer_fill (buf, 0, owma_data + 54, owma_len - 54);
8731 if (wfex->wFormatTag == 0x0161) {
8732 codec_name = "Windows Media Audio";
8734 } else if (wfex->wFormatTag == 0x0162) {
8735 codec_name = "Windows Media Audio 9 Pro";
8737 } else if (wfex->wFormatTag == 0x0163) {
8738 codec_name = "Windows Media Audio 9 Lossless";
8739 /* is that correct? gstffmpegcodecmap.c is missing it, but
8740 * fluendo codec seems to support it */
8744 gst_caps_set_simple (stream->caps,
8745 "codec_data", GST_TYPE_BUFFER, buf,
8746 "wmaversion", G_TYPE_INT, version,
8747 "block_align", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->nBlockAlign),
8748 "bitrate", G_TYPE_INT, GST_READ_UINT32_LE (&wfex->nAvgBytesPerSec),
8749 "width", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->wBitsPerSample),
8750 "depth", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->wBitsPerSample),
8752 gst_buffer_unref (buf);
8756 codec = g_strdup (codec_name);
8760 case GST_MAKE_FOURCC ('w', 'm', 'a', ' '):
8762 gint len = QT_UINT32 (stsd_data) - offset;
8763 const guint8 *wfex_data = stsd_data + offset;
8764 const gchar *codec_name = NULL;
8766 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
8767 /* FIXME this should also be gst_riff_strf_auds,
8768 * but the latter one is actually missing bits-per-sample :( */
8773 gint32 nSamplesPerSec;
8774 gint32 nAvgBytesPerSec;
8776 gint16 wBitsPerSample;
8781 /* FIXME: unify with similar wavformatex parsing code above */
8782 GST_DEBUG_OBJECT (qtdemux, "parse wma, looking for wfex");
8788 if (QT_UINT32 (wfex_data) <= len)
8789 size = QT_UINT32 (wfex_data) - 8;
8794 /* No real data, so break out */
8797 switch (QT_FOURCC (wfex_data + 4)) {
8798 case GST_MAKE_FOURCC ('w', 'f', 'e', 'x'):
8800 GST_DEBUG_OBJECT (qtdemux, "found wfex in stsd");
8805 wfex.wFormatTag = GST_READ_UINT16_LE (wfex_data + 8 + 0);
8806 wfex.nChannels = GST_READ_UINT16_LE (wfex_data + 8 + 2);
8807 wfex.nSamplesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 4);
8808 wfex.nAvgBytesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 8);
8809 wfex.nBlockAlign = GST_READ_UINT16_LE (wfex_data + 8 + 12);
8810 wfex.wBitsPerSample = GST_READ_UINT16_LE (wfex_data + 8 + 14);
8811 wfex.cbSize = GST_READ_UINT16_LE (wfex_data + 8 + 16);
8813 GST_LOG_OBJECT (qtdemux, "Found wfex box in stsd:");
8814 GST_LOG_OBJECT (qtdemux, "FormatTag = 0x%04x, Channels = %u, "
8815 "SamplesPerSec = %u, AvgBytesPerSec = %u, BlockAlign = %u, "
8816 "BitsPerSample = %u, Size = %u", wfex.wFormatTag,
8817 wfex.nChannels, wfex.nSamplesPerSec, wfex.nAvgBytesPerSec,
8818 wfex.nBlockAlign, wfex.wBitsPerSample, wfex.cbSize);
8820 if (wfex.wFormatTag == 0x0161) {
8821 codec_name = "Windows Media Audio";
8823 } else if (wfex.wFormatTag == 0x0162) {
8824 codec_name = "Windows Media Audio 9 Pro";
8826 } else if (wfex.wFormatTag == 0x0163) {
8827 codec_name = "Windows Media Audio 9 Lossless";
8828 /* is that correct? gstffmpegcodecmap.c is missing it, but
8829 * fluendo codec seems to support it */
8833 gst_caps_set_simple (stream->caps,
8834 "wmaversion", G_TYPE_INT, version,
8835 "block_align", G_TYPE_INT, wfex.nBlockAlign,
8836 "bitrate", G_TYPE_INT, wfex.nAvgBytesPerSec,
8837 "width", G_TYPE_INT, wfex.wBitsPerSample,
8838 "depth", G_TYPE_INT, wfex.wBitsPerSample, NULL);
8840 if (size > wfex.cbSize) {
8843 buf = gst_buffer_new_and_alloc (size - wfex.cbSize);
8844 gst_buffer_fill (buf, 0, wfex_data + 8 + wfex.cbSize,
8845 size - wfex.cbSize);
8846 gst_caps_set_simple (stream->caps,
8847 "codec_data", GST_TYPE_BUFFER, buf, NULL);
8848 gst_buffer_unref (buf);
8850 GST_WARNING_OBJECT (qtdemux, "no codec data");
8855 codec = g_strdup (codec_name);
8863 wfex_data += size + 8;
8875 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
8876 GST_TAG_AUDIO_CODEC, codec, NULL);
8880 /* some bitrate info may have ended up in caps */
8881 s = gst_caps_get_structure (stream->caps, 0);
8882 gst_structure_get_int (s, "bitrate", &bitrate);
8884 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
8885 GST_TAG_BITRATE, bitrate, NULL);
8888 mp4a = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4a);
8892 wave = qtdemux_tree_get_child_by_type (mp4a, FOURCC_wave);
8894 esds = qtdemux_tree_get_child_by_type (wave, FOURCC_esds);
8896 esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
8900 /* If the fourcc's bottom 16 bits gives 'sm', then the top
8901 16 bits is a byte-swapped wave-style codec identifier,
8902 and we can find a WAVE header internally to a 'wave' atom here.
8903 This can more clearly be thought of as 'ms' as the top 16 bits, and a
8904 codec id as the bottom 16 bits - but byte-swapped to store in QT (which
8907 if ((fourcc & 0xffff) == (('s' << 8) | 'm')) {
8908 if (len < offset + 20) {
8909 GST_WARNING_OBJECT (qtdemux, "No wave atom in MS-style audio");
8911 guint32 datalen = QT_UINT32 (stsd_data + offset + 16);
8912 const guint8 *data = stsd_data + offset + 16;
8914 GNode *waveheadernode;
8916 wavenode = g_node_new ((guint8 *) data);
8917 if (qtdemux_parse_node (qtdemux, wavenode, data, datalen)) {
8918 const guint8 *waveheader;
8921 waveheadernode = qtdemux_tree_get_child_by_type (wavenode, fourcc);
8922 if (waveheadernode) {
8923 waveheader = (const guint8 *) waveheadernode->data;
8924 headerlen = QT_UINT32 (waveheader);
8926 if (headerlen > 8) {
8927 gst_riff_strf_auds *header = NULL;
8928 GstBuffer *headerbuf;
8934 headerbuf = gst_buffer_new_and_alloc (headerlen);
8935 gst_buffer_fill (headerbuf, 0, waveheader, headerlen);
8937 if (gst_riff_parse_strf_auds (GST_ELEMENT_CAST (qtdemux),
8938 headerbuf, &header, &extra)) {
8939 gst_caps_unref (stream->caps);
8940 /* FIXME: Need to do something with the channel reorder map */
8941 stream->caps = gst_riff_create_audio_caps (header->format, NULL,
8942 header, extra, NULL, NULL, NULL);
8945 gst_buffer_unref (extra);
8950 GST_DEBUG ("Didn't find waveheadernode for this codec");
8952 g_node_destroy (wavenode);
8955 gst_qtdemux_handle_esds (qtdemux, stream, esds, stream->pending_tags);
8959 /* FIXME: what is in the chunk? */
8962 gint len = QT_UINT32 (stsd_data);
8964 /* seems to be always = 116 = 0x74 */
8970 gint len = QT_UINT32 (stsd_data);
8973 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x4C);
8975 gst_buffer_fill (buf, 0, stsd_data + 0x4C, len - 0x4C);
8976 gst_caps_set_simple (stream->caps,
8977 "codec_data", GST_TYPE_BUFFER, buf, NULL);
8978 gst_buffer_unref (buf);
8980 gst_caps_set_simple (stream->caps,
8981 "samplesize", G_TYPE_INT, samplesize, NULL);
8986 GNode *alac, *wave = NULL;
8988 /* apparently, m4a has this atom appended directly in the stsd entry,
8989 * while mov has it in a wave atom */
8990 alac = qtdemux_tree_get_child_by_type (stsd, FOURCC_alac);
8992 /* alac now refers to stsd entry atom */
8993 wave = qtdemux_tree_get_child_by_type (alac, FOURCC_wave);
8995 alac = qtdemux_tree_get_child_by_type (wave, FOURCC_alac);
8997 alac = qtdemux_tree_get_child_by_type (alac, FOURCC_alac);
9000 const guint8 *alac_data = alac->data;
9001 gint len = QT_UINT32 (alac->data);
9005 GST_DEBUG_OBJECT (qtdemux,
9006 "discarding alac atom with unexpected len %d", len);
9008 /* codec-data contains alac atom size and prefix,
9009 * ffmpeg likes it that way, not quite gst-ish though ...*/
9010 buf = gst_buffer_new_and_alloc (len);
9011 gst_buffer_fill (buf, 0, alac->data, len);
9012 gst_caps_set_simple (stream->caps,
9013 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9014 gst_buffer_unref (buf);
9016 stream->bytes_per_frame = QT_UINT32 (alac_data + 12);
9017 stream->n_channels = QT_UINT8 (alac_data + 21);
9018 stream->rate = QT_UINT32 (alac_data + 32);
9021 gst_caps_set_simple (stream->caps,
9022 "samplesize", G_TYPE_INT, samplesize, NULL);
9030 gint len = QT_UINT32 (stsd_data);
9033 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x34);
9036 gst_buffer_fill (buf, 0, stsd_data + 0x34, len - 0x34);
9038 /* If we have enough data, let's try to get the 'damr' atom. See
9039 * the 3GPP container spec (26.244) for more details. */
9040 if ((len - 0x34) > 8 &&
9041 (bitrate = qtdemux_parse_amr_bitrate (buf, amrwb))) {
9042 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
9043 GST_TAG_MAXIMUM_BITRATE, bitrate, NULL);
9046 gst_caps_set_simple (stream->caps,
9047 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9048 gst_buffer_unref (buf);
9054 /* mp4a atom withtout ESDS; Attempt to build codec data from atom */
9055 gint len = QT_UINT32 (stsd_data);
9058 guint16 sound_version = QT_UINT16 (stsd_data + 32);
9060 if (sound_version == 1) {
9061 guint16 channels = QT_UINT16 (stsd_data + 40);
9062 guint32 time_scale = QT_UINT32 (stsd_data + 46);
9063 guint8 codec_data[2];
9065 gint profile = 2; /* FIXME: Can this be determined somehow? There doesn't seem to be anything in mp4a atom that specifis compression */
9067 gint sample_rate_index =
9068 gst_codec_utils_aac_get_index_from_sample_rate (time_scale);
9070 /* build AAC codec data */
9071 codec_data[0] = profile << 3;
9072 codec_data[0] |= ((sample_rate_index >> 1) & 0x7);
9073 codec_data[1] = (sample_rate_index & 0x01) << 7;
9074 codec_data[1] |= (channels & 0xF) << 3;
9076 buf = gst_buffer_new_and_alloc (2);
9077 gst_buffer_fill (buf, 0, codec_data, 2);
9078 gst_caps_set_simple (stream->caps,
9079 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9080 gst_buffer_unref (buf);
9086 GST_INFO_OBJECT (qtdemux,
9087 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
9091 GST_INFO_OBJECT (qtdemux,
9092 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
9093 GST_FOURCC_ARGS (fourcc), stream->caps);
9095 } else if (stream->subtype == FOURCC_strm) {
9096 if (fourcc == FOURCC_rtsp) {
9097 stream->redirect_uri = qtdemux_get_rtsp_uri_from_hndl (qtdemux, minf);
9099 GST_INFO_OBJECT (qtdemux, "unhandled stream type %" GST_FOURCC_FORMAT,
9100 GST_FOURCC_ARGS (fourcc));
9101 goto unknown_stream;
9103 stream->sampled = TRUE;
9104 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
9105 || stream->subtype == FOURCC_sbtl) {
9107 stream->sampled = TRUE;
9108 stream->sparse = TRUE;
9111 qtdemux_sub_caps (qtdemux, stream, fourcc, stsd_data, &codec);
9113 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
9114 GST_TAG_SUBTITLE_CODEC, codec, NULL);
9119 /* hunt for sort-of codec data */
9126 /* look for palette in a stsd->mp4s->esds sub-atom */
9127 mp4s = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4s);
9129 esds = qtdemux_tree_get_child_by_type (mp4s, FOURCC_esds);
9132 GST_LOG_OBJECT (qtdemux, "Skipping invalid stsd: no esds child");
9136 gst_qtdemux_handle_esds (qtdemux, stream, esds, stream->pending_tags);
9140 GST_INFO_OBJECT (qtdemux,
9141 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
9144 GST_INFO_OBJECT (qtdemux,
9145 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
9146 GST_FOURCC_ARGS (fourcc), stream->caps);
9148 /* everything in 1 sample */
9149 stream->sampled = TRUE;
9152 qtdemux_generic_caps (qtdemux, stream, fourcc, stsd_data, &codec);
9154 if (stream->caps == NULL)
9155 goto unknown_stream;
9158 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
9159 GST_TAG_SUBTITLE_CODEC, codec, NULL);
9165 /* promote to sampled format */
9166 if (stream->fourcc == FOURCC_samr) {
9167 /* force mono 8000 Hz for AMR */
9168 stream->sampled = TRUE;
9169 stream->n_channels = 1;
9170 stream->rate = 8000;
9171 } else if (stream->fourcc == FOURCC_sawb) {
9172 /* force mono 16000 Hz for AMR-WB */
9173 stream->sampled = TRUE;
9174 stream->n_channels = 1;
9175 stream->rate = 16000;
9176 } else if (stream->fourcc == FOURCC_mp4a) {
9177 stream->sampled = TRUE;
9180 /* collect sample information */
9181 if (!qtdemux_stbl_init (qtdemux, stream, stbl))
9182 goto samples_failed;
9184 if (qtdemux->fragmented) {
9188 /* need all moov samples as basis; probably not many if any at all */
9189 /* prevent moof parsing taking of at this time */
9190 offset = qtdemux->moof_offset;
9191 qtdemux->moof_offset = 0;
9192 if (stream->n_samples &&
9193 !qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
9194 qtdemux->moof_offset = offset;
9195 goto samples_failed;
9197 qtdemux->moof_offset = 0;
9198 /* movie duration more reliable in this case (e.g. mehd) */
9199 if (qtdemux->segment.duration &&
9200 GST_CLOCK_TIME_IS_VALID (qtdemux->segment.duration))
9202 GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->segment.duration);
9203 /* need defaults for fragments */
9204 qtdemux_parse_trex (qtdemux, stream, &dummy, &dummy, &dummy);
9207 /* configure segments */
9208 if (!qtdemux_parse_segments (qtdemux, stream, trak))
9209 goto segments_failed;
9211 /* add some language tag, if useful */
9212 if (stream->lang_id[0] != '\0' && strcmp (stream->lang_id, "unk") &&
9213 strcmp (stream->lang_id, "und")) {
9214 const gchar *lang_code;
9216 /* convert ISO 639-2 code to ISO 639-1 */
9217 lang_code = gst_tag_get_language_code (stream->lang_id);
9218 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
9219 GST_TAG_LANGUAGE_CODE, (lang_code) ? lang_code : stream->lang_id, NULL);
9222 /* Check for UDTA tags */
9223 if ((udta = qtdemux_tree_get_child_by_type (trak, FOURCC_udta))) {
9224 qtdemux_parse_udta (qtdemux, stream->pending_tags, udta);
9227 /* now we are ready to add the stream */
9228 if (qtdemux->n_streams >= GST_QTDEMUX_MAX_STREAMS)
9229 goto too_many_streams;
9231 if (!qtdemux->got_moov) {
9232 qtdemux->streams[qtdemux->n_streams] = stream;
9233 qtdemux->n_streams++;
9234 GST_DEBUG_OBJECT (qtdemux, "n_streams is now %d", qtdemux->n_streams);
9242 GST_INFO_OBJECT (qtdemux, "skip disabled track");
9249 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
9250 (_("This file is corrupt and cannot be played.")), (NULL));
9257 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT, (NULL), (NULL));
9265 /* we posted an error already */
9266 /* free stbl sub-atoms */
9267 gst_qtdemux_stbl_free (stream);
9274 GST_INFO_OBJECT (qtdemux, "stream with track id %i already exists",
9282 GST_INFO_OBJECT (qtdemux, "unknown subtype %" GST_FOURCC_FORMAT,
9283 GST_FOURCC_ARGS (stream->subtype));
9290 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
9291 (_("This file contains too many streams. Only playing first %d"),
9292 GST_QTDEMUX_MAX_STREAMS), (NULL));
9297 /* If we can estimate the overall bitrate, and don't have information about the
9298 * stream bitrate for exactly one stream, this guesses the stream bitrate as
9299 * the overall bitrate minus the sum of the bitrates of all other streams. This
9300 * should be useful for the common case where we have one audio and one video
9301 * stream and can estimate the bitrate of one, but not the other. */
9303 gst_qtdemux_guess_bitrate (GstQTDemux * qtdemux)
9305 QtDemuxStream *stream = NULL;
9306 gint64 size, sys_bitrate, sum_bitrate = 0;
9307 GstClockTime duration;
9311 if (qtdemux->fragmented)
9314 GST_DEBUG_OBJECT (qtdemux, "Looking for streams with unknown bitrate");
9316 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &size)
9318 GST_DEBUG_OBJECT (qtdemux,
9319 "Size in bytes of the stream not known - bailing");
9323 /* Subtract the header size */
9324 GST_DEBUG_OBJECT (qtdemux, "Total size %" G_GINT64_FORMAT ", header size %u",
9325 size, qtdemux->header_size);
9327 if (size < qtdemux->header_size)
9330 size = size - qtdemux->header_size;
9332 if (!gst_qtdemux_get_duration (qtdemux, &duration) ||
9333 duration == GST_CLOCK_TIME_NONE) {
9334 GST_DEBUG_OBJECT (qtdemux, "Stream duration not known - bailing");
9338 for (i = 0; i < qtdemux->n_streams; i++) {
9339 switch (qtdemux->streams[i]->subtype) {
9342 GST_DEBUG_OBJECT (qtdemux, "checking bitrate for %" GST_PTR_FORMAT,
9343 qtdemux->streams[i]->caps);
9344 /* retrieve bitrate, prefer avg then max */
9346 if (qtdemux->streams[i]->pending_tags) {
9347 gst_tag_list_get_uint (qtdemux->streams[i]->pending_tags,
9348 GST_TAG_MAXIMUM_BITRATE, &bitrate);
9349 GST_DEBUG_OBJECT (qtdemux, "max-bitrate: %u", bitrate);
9350 gst_tag_list_get_uint (qtdemux->streams[i]->pending_tags,
9351 GST_TAG_NOMINAL_BITRATE, &bitrate);
9352 GST_DEBUG_OBJECT (qtdemux, "nominal-bitrate: %u", bitrate);
9353 gst_tag_list_get_uint (qtdemux->streams[i]->pending_tags,
9354 GST_TAG_BITRATE, &bitrate);
9355 GST_DEBUG_OBJECT (qtdemux, "bitrate: %u", bitrate);
9358 sum_bitrate += bitrate;
9361 GST_DEBUG_OBJECT (qtdemux,
9362 ">1 stream with unknown bitrate - bailing");
9365 stream = qtdemux->streams[i];
9369 /* For other subtypes, we assume no significant impact on bitrate */
9375 GST_DEBUG_OBJECT (qtdemux, "All stream bitrates are known");
9379 sys_bitrate = gst_util_uint64_scale (size, GST_SECOND * 8, duration);
9381 if (sys_bitrate < sum_bitrate) {
9382 /* This can happen, since sum_bitrate might be derived from maximum
9383 * bitrates and not average bitrates */
9384 GST_DEBUG_OBJECT (qtdemux,
9385 "System bitrate less than sum bitrate - bailing");
9389 bitrate = sys_bitrate - sum_bitrate;
9390 GST_DEBUG_OBJECT (qtdemux, "System bitrate = %" G_GINT64_FORMAT
9391 ", Stream bitrate = %u", sys_bitrate, bitrate);
9393 if (!stream->pending_tags)
9394 stream->pending_tags = gst_tag_list_new_empty ();
9396 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
9397 GST_TAG_BITRATE, bitrate, NULL);
9400 static GstFlowReturn
9401 qtdemux_prepare_streams (GstQTDemux * qtdemux)
9404 GstFlowReturn ret = GST_FLOW_OK;
9406 GST_DEBUG_OBJECT (qtdemux, "prepare streams");
9408 for (i = 0; ret == GST_FLOW_OK && i < qtdemux->n_streams; i++) {
9409 QtDemuxStream *stream = qtdemux->streams[i];
9410 guint32 sample_num = 0;
9412 GST_DEBUG_OBJECT (qtdemux, "stream %d, id %d, fourcc %" GST_FOURCC_FORMAT,
9413 i, stream->track_id, GST_FOURCC_ARGS (stream->fourcc));
9415 if (qtdemux->fragmented) {
9416 /* need all moov samples first */
9417 GST_OBJECT_LOCK (qtdemux);
9418 while (stream->n_samples == 0)
9419 if ((ret = qtdemux_add_fragmented_samples (qtdemux)) != GST_FLOW_OK)
9421 GST_OBJECT_UNLOCK (qtdemux);
9423 /* discard any stray moof */
9424 qtdemux->moof_offset = 0;
9427 /* prepare braking */
9428 if (ret != GST_FLOW_ERROR)
9431 /* in pull mode, we should have parsed some sample info by now;
9432 * and quite some code will not handle no samples.
9433 * in push mode, we'll just have to deal with it */
9434 if (G_UNLIKELY (qtdemux->pullbased && !stream->n_samples)) {
9435 GST_DEBUG_OBJECT (qtdemux, "no samples for stream; discarding");
9436 gst_qtdemux_remove_stream (qtdemux, i);
9441 /* parse the initial sample for use in setting the frame rate cap */
9442 while (sample_num == 0 && sample_num < stream->n_samples) {
9443 if (!qtdemux_parse_samples (qtdemux, stream, sample_num))
9447 if (stream->n_samples > 0 && stream->stbl_index > 0) {
9448 stream->first_duration = stream->samples[0].duration;
9449 GST_LOG_OBJECT (qtdemux, "stream %d first duration %u",
9450 stream->track_id, stream->first_duration);
9457 static GstFlowReturn
9458 qtdemux_expose_streams (GstQTDemux * qtdemux)
9461 GstFlowReturn ret = GST_FLOW_OK;
9462 GSList *oldpads = NULL;
9465 GST_DEBUG_OBJECT (qtdemux, "exposing streams");
9467 for (i = 0; ret == GST_FLOW_OK && i < qtdemux->n_streams; i++) {
9468 QtDemuxStream *stream = qtdemux->streams[i];
9469 GstPad *oldpad = stream->pad;
9472 GST_DEBUG_OBJECT (qtdemux, "stream %d, id %d, fourcc %" GST_FOURCC_FORMAT,
9473 i, stream->track_id, GST_FOURCC_ARGS (stream->fourcc));
9475 if ((stream->subtype == FOURCC_text || stream->subtype == FOURCC_sbtl) &&
9476 stream->track_id == qtdemux->chapters_track_id) {
9477 /* TODO - parse chapters track and expose it as GstToc; For now just ignore it
9478 so that it doesn't look like a subtitle track */
9479 gst_qtdemux_remove_stream (qtdemux, i);
9484 /* now we have all info and can expose */
9485 list = stream->pending_tags;
9486 stream->pending_tags = NULL;
9488 oldpads = g_slist_prepend (oldpads, oldpad);
9489 gst_qtdemux_add_stream (qtdemux, stream, list);
9492 gst_qtdemux_guess_bitrate (qtdemux);
9494 gst_element_no_more_pads (GST_ELEMENT_CAST (qtdemux));
9496 for (iter = oldpads; iter; iter = g_slist_next (iter)) {
9497 GstPad *oldpad = iter->data;
9499 gst_pad_push_event (oldpad, gst_event_new_eos ());
9500 gst_pad_set_active (oldpad, FALSE);
9501 gst_element_remove_pad (GST_ELEMENT (qtdemux), oldpad);
9502 gst_flow_combiner_remove_pad (qtdemux->flowcombiner, oldpad);
9503 gst_object_unref (oldpad);
9506 /* check if we should post a redirect in case there is a single trak
9507 * and it is a redirecting trak */
9508 if (qtdemux->n_streams == 1 && qtdemux->streams[0]->redirect_uri != NULL) {
9511 GST_INFO_OBJECT (qtdemux, "Issuing a redirect due to a single track with "
9512 "an external content");
9513 m = gst_message_new_element (GST_OBJECT_CAST (qtdemux),
9514 gst_structure_new ("redirect",
9515 "new-location", G_TYPE_STRING, qtdemux->streams[0]->redirect_uri,
9517 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), m);
9518 qtdemux->posted_redirect = TRUE;
9521 for (i = 0; i < qtdemux->n_streams; i++) {
9522 QtDemuxStream *stream = qtdemux->streams[i];
9524 qtdemux_do_allocation (qtdemux, stream);
9527 qtdemux->exposed = TRUE;
9531 /* check if major or compatible brand is 3GP */
9532 static inline gboolean
9533 qtdemux_is_brand_3gp (GstQTDemux * qtdemux, gboolean major)
9536 return ((qtdemux->major_brand & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
9537 GST_MAKE_FOURCC ('3', 'g', 0, 0));
9538 } else if (qtdemux->comp_brands != NULL) {
9542 gboolean res = FALSE;
9544 gst_buffer_map (qtdemux->comp_brands, &map, GST_MAP_READ);
9548 res = res || ((QT_FOURCC (data) & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
9549 GST_MAKE_FOURCC ('3', 'g', 0, 0));
9553 gst_buffer_unmap (qtdemux->comp_brands, &map);
9560 /* check if tag is a spec'ed 3GP tag keyword storing a string */
9561 static inline gboolean
9562 qtdemux_is_string_tag_3gp (GstQTDemux * qtdemux, guint32 fourcc)
9564 return fourcc == FOURCC_cprt || fourcc == FOURCC_gnre || fourcc == FOURCC_titl
9565 || fourcc == FOURCC_dscp || fourcc == FOURCC_perf || fourcc == FOURCC_auth
9566 || fourcc == FOURCC_albm;
9570 qtdemux_tag_add_location (GstQTDemux * qtdemux, GstTagList * taglist,
9571 const char *tag, const char *dummy, GNode * node)
9573 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
9577 gdouble longitude, latitude, altitude;
9580 len = QT_UINT32 (node->data);
9587 /* TODO: language code skipped */
9589 name = gst_tag_freeform_string_to_utf8 (data + offset, -1, env_vars);
9592 /* do not alarm in trivial case, but bail out otherwise */
9593 if (*(data + offset) != 0) {
9594 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8, "
9598 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
9599 GST_TAG_GEO_LOCATION_NAME, name, NULL);
9600 offset += strlen (name);
9604 if (len < offset + 2 + 4 + 4 + 4)
9607 /* +1 +1 = skip null-terminator and location role byte */
9609 /* table in spec says unsigned, semantics say negative has meaning ... */
9610 longitude = QT_SFP32 (data + offset);
9613 latitude = QT_SFP32 (data + offset);
9616 altitude = QT_SFP32 (data + offset);
9618 /* one invalid means all are invalid */
9619 if (longitude >= -180.0 && longitude <= 180.0 &&
9620 latitude >= -90.0 && latitude <= 90.0) {
9621 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
9622 GST_TAG_GEO_LOCATION_LATITUDE, latitude,
9623 GST_TAG_GEO_LOCATION_LONGITUDE, longitude,
9624 GST_TAG_GEO_LOCATION_ELEVATION, altitude, NULL);
9627 /* TODO: no GST_TAG_, so astronomical body and additional notes skipped */
9634 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP location");
9641 qtdemux_tag_add_year (GstQTDemux * qtdemux, GstTagList * taglist,
9642 const char *tag, const char *dummy, GNode * node)
9648 len = QT_UINT32 (node->data);
9652 y = QT_UINT16 ((guint8 *) node->data + 12);
9654 GST_DEBUG_OBJECT (qtdemux, "year: %u is not a valid year", y);
9657 GST_DEBUG_OBJECT (qtdemux, "year: %u", y);
9659 date = g_date_new_dmy (1, 1, y);
9660 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, date, NULL);
9665 qtdemux_tag_add_classification (GstQTDemux * qtdemux, GstTagList * taglist,
9666 const char *tag, const char *dummy, GNode * node)
9669 char *tag_str = NULL;
9674 len = QT_UINT32 (node->data);
9679 entity = (guint8 *) node->data + offset;
9680 if (entity[0] == 0 || entity[1] == 0 || entity[2] == 0 || entity[3] == 0) {
9681 GST_DEBUG_OBJECT (qtdemux,
9682 "classification info: %c%c%c%c invalid classification entity",
9683 entity[0], entity[1], entity[2], entity[3]);
9688 table = QT_UINT16 ((guint8 *) node->data + offset);
9690 /* Language code skipped */
9694 /* Tag format: "XXXX://Y[YYYY]/classification info string"
9695 * XXXX: classification entity, fixed length 4 chars.
9696 * Y[YYYY]: classification table, max 5 chars.
9698 tag_str = g_strdup_printf ("----://%u/%s",
9699 table, (char *) node->data + offset);
9701 /* memcpy To be sure we're preserving byte order */
9702 memcpy (tag_str, entity, 4);
9703 GST_DEBUG_OBJECT (qtdemux, "classification info: %s", tag_str);
9705 gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND, tag, tag_str, NULL);
9714 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP classification");
9720 qtdemux_tag_add_str_full (GstQTDemux * qtdemux, GstTagList * taglist,
9721 const char *tag, const char *dummy, GNode * node)
9723 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
9729 gboolean ret = TRUE;
9730 const gchar *charset = NULL;
9732 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
9734 len = QT_UINT32 (data->data);
9735 type = QT_UINT32 ((guint8 *) data->data + 8);
9736 if (type == 0x00000001 && len > 16) {
9737 s = gst_tag_freeform_string_to_utf8 ((char *) data->data + 16, len - 16,
9740 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
9741 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, s, NULL);
9744 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
9748 len = QT_UINT32 (node->data);
9749 type = QT_UINT32 ((guint8 *) node->data + 4);
9750 if ((type >> 24) == 0xa9) {
9754 /* Type starts with the (C) symbol, so the next data is a list
9755 * of (string size(16), language code(16), string) */
9757 str_len = QT_UINT16 ((guint8 *) node->data + 8);
9758 lang_code = QT_UINT16 ((guint8 *) node->data + 10);
9760 /* the string + fourcc + size + 2 16bit fields,
9761 * means that there are more tags in this atom */
9762 if (len > str_len + 8 + 4) {
9763 /* TODO how to represent the same tag in different languages? */
9764 GST_WARNING_OBJECT (qtdemux, "Ignoring metadata entry with multiple "
9765 "text alternatives, reading only first one");
9769 len = str_len + 8 + 4; /* remove trailing strings that we don't use */
9770 GST_DEBUG_OBJECT (qtdemux, "found international text tag");
9772 if (lang_code < 0x800) { /* MAC encoded string */
9775 } else if (len > 14 && qtdemux_is_string_tag_3gp (qtdemux,
9776 QT_FOURCC ((guint8 *) node->data + 4))) {
9777 guint32 type = QT_UINT32 ((guint8 *) node->data + 8);
9779 /* we go for 3GP style encoding if major brands claims so,
9780 * or if no hope for data be ok UTF-8, and compatible 3GP brand present */
9781 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
9782 (qtdemux_is_brand_3gp (qtdemux, FALSE) &&
9783 ((type & 0x00FFFFFF) == 0x0) && (type >> 24 <= 0xF))) {
9785 /* 16-bit Language code is ignored here as well */
9786 GST_DEBUG_OBJECT (qtdemux, "found 3gpp text tag");
9793 GST_DEBUG_OBJECT (qtdemux, "found normal text tag");
9794 ret = FALSE; /* may have to fallback */
9799 s = g_convert ((gchar *) node->data + offset, len - offset, "utf8",
9800 charset, NULL, NULL, &err);
9802 GST_DEBUG_OBJECT (qtdemux, "Failed to convert string from charset %s:"
9803 " %s(%d): %s", charset, g_quark_to_string (err->domain), err->code,
9808 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
9809 len - offset, env_vars);
9812 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
9813 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, s, NULL);
9817 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
9824 qtdemux_tag_add_str (GstQTDemux * qtdemux, GstTagList * taglist,
9825 const char *tag, const char *dummy, GNode * node)
9827 qtdemux_tag_add_str_full (qtdemux, taglist, tag, dummy, node);
9831 qtdemux_tag_add_keywords (GstQTDemux * qtdemux, GstTagList * taglist,
9832 const char *tag, const char *dummy, GNode * node)
9834 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
9836 char *s, *t, *k = NULL;
9841 /* first try normal string tag if major brand not 3GP */
9842 if (!qtdemux_is_brand_3gp (qtdemux, TRUE)) {
9843 if (!qtdemux_tag_add_str_full (qtdemux, taglist, tag, dummy, node)) {
9844 /* hm, that did not work, maybe 3gpp storage in non-3gpp major brand;
9845 * let's try it 3gpp way after minor safety check */
9847 if (QT_UINT32 (data) < 15 || !qtdemux_is_brand_3gp (qtdemux, FALSE))
9853 GST_DEBUG_OBJECT (qtdemux, "found 3gpp keyword tag");
9857 len = QT_UINT32 (data);
9861 count = QT_UINT8 (data + 14);
9863 for (; count; count--) {
9866 if (offset + 1 > len)
9868 slen = QT_UINT8 (data + offset);
9870 if (offset + slen > len)
9872 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
9875 GST_DEBUG_OBJECT (qtdemux, "adding keyword %s", GST_STR_NULL (s));
9877 t = g_strjoin (",", k, s, NULL);
9885 GST_DEBUG_OBJECT (qtdemux, "failed to convert keyword to UTF-8");
9892 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (k));
9893 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, k, NULL);
9902 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP keywords");
9908 qtdemux_tag_add_num (GstQTDemux * qtdemux, GstTagList * taglist,
9909 const char *tag1, const char *tag2, GNode * node)
9916 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
9918 len = QT_UINT32 (data->data);
9919 type = QT_UINT32 ((guint8 *) data->data + 8);
9920 if (type == 0x00000000 && len >= 22) {
9921 n1 = QT_UINT16 ((guint8 *) data->data + 18);
9922 n2 = QT_UINT16 ((guint8 *) data->data + 20);
9924 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag1, n1);
9925 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, n1, NULL);
9928 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag2, n2);
9929 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag2, n2, NULL);
9936 qtdemux_tag_add_tmpo (GstQTDemux * qtdemux, GstTagList * taglist,
9937 const char *tag1, const char *dummy, GNode * node)
9944 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
9946 len = QT_UINT32 (data->data);
9947 type = QT_UINT32 ((guint8 *) data->data + 8);
9948 GST_DEBUG_OBJECT (qtdemux, "have tempo tag, type=%d,len=%d", type, len);
9949 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
9950 if ((type == 0x00000015 || type == 0x0000000f) && len >= 18) {
9951 n1 = QT_UINT16 ((guint8 *) data->data + 16);
9953 /* do not add bpm=0 */
9954 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", n1);
9955 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, (gdouble) n1,
9963 qtdemux_tag_add_uint32 (GstQTDemux * qtdemux, GstTagList * taglist,
9964 const char *tag1, const char *dummy, GNode * node)
9971 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
9973 len = QT_UINT32 (data->data);
9974 type = QT_UINT32 ((guint8 *) data->data + 8);
9975 GST_DEBUG_OBJECT (qtdemux, "have %s tag, type=%d,len=%d", tag1, type, len);
9976 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
9977 if ((type == 0x00000015 || type == 0x0000000f) && len >= 20) {
9978 num = QT_UINT32 ((guint8 *) data->data + 16);
9980 /* do not add num=0 */
9981 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", num);
9982 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, num, NULL);
9989 qtdemux_tag_add_covr (GstQTDemux * qtdemux, GstTagList * taglist,
9990 const char *tag1, const char *dummy, GNode * node)
9997 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
9999 len = QT_UINT32 (data->data);
10000 type = QT_UINT32 ((guint8 *) data->data + 8);
10001 GST_DEBUG_OBJECT (qtdemux, "have covr tag, type=%d,len=%d", type, len);
10002 if ((type == 0x0000000d || type == 0x0000000e) && len > 16) {
10004 gst_tag_image_data_to_image_sample ((guint8 *) data->data + 16,
10005 len - 16, GST_TAG_IMAGE_TYPE_NONE))) {
10006 GST_DEBUG_OBJECT (qtdemux, "adding tag size %d", len - 16);
10007 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, sample, NULL);
10008 gst_sample_unref (sample);
10015 qtdemux_tag_add_date (GstQTDemux * qtdemux, GstTagList * taglist,
10016 const char *tag, const char *dummy, GNode * node)
10023 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
10025 len = QT_UINT32 (data->data);
10026 type = QT_UINT32 ((guint8 *) data->data + 8);
10027 if (type == 0x00000001 && len > 16) {
10028 guint y, m = 1, d = 1;
10031 s = g_strndup ((char *) data->data + 16, len - 16);
10032 GST_DEBUG_OBJECT (qtdemux, "adding date '%s'", s);
10033 ret = sscanf (s, "%u-%u-%u", &y, &m, &d);
10034 if (ret >= 1 && y > 1500 && y < 3000) {
10037 date = g_date_new_dmy (d, m, y);
10038 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, date, NULL);
10039 g_date_free (date);
10041 GST_DEBUG_OBJECT (qtdemux, "could not parse date string '%s'", s);
10049 qtdemux_tag_add_gnre (GstQTDemux * qtdemux, GstTagList * taglist,
10050 const char *tag, const char *dummy, GNode * node)
10054 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
10056 /* re-route to normal string tag if major brand says so
10057 * or no data atom and compatible brand suggests so */
10058 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
10059 (qtdemux_is_brand_3gp (qtdemux, FALSE) && !data)) {
10060 qtdemux_tag_add_str (qtdemux, taglist, tag, dummy, node);
10065 guint len, type, n;
10067 len = QT_UINT32 (data->data);
10068 type = QT_UINT32 ((guint8 *) data->data + 8);
10069 if (type == 0x00000000 && len >= 18) {
10070 n = QT_UINT16 ((guint8 *) data->data + 16);
10072 const gchar *genre;
10074 genre = gst_tag_id3_genre_get (n - 1);
10075 if (genre != NULL) {
10076 GST_DEBUG_OBJECT (qtdemux, "adding %d [%s]", n, genre);
10077 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, genre, NULL);
10085 qtdemux_add_double_tag_from_str (GstQTDemux * demux, GstTagList * taglist,
10086 const gchar * tag, guint8 * data, guint32 datasize)
10091 /* make a copy to have \0 at the end */
10092 datacopy = g_strndup ((gchar *) data, datasize);
10094 /* convert the str to double */
10095 if (sscanf (datacopy, "%lf", &value) == 1) {
10096 GST_DEBUG_OBJECT (demux, "adding tag: %s [%s]", tag, datacopy);
10097 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, value, NULL);
10099 GST_WARNING_OBJECT (demux, "Failed to parse double from string: %s",
10107 qtdemux_tag_add_revdns (GstQTDemux * demux, GstTagList * taglist,
10108 const char *tag, const char *tag_bis, GNode * node)
10117 const gchar *meanstr;
10118 const gchar *namestr;
10120 /* checking the whole ---- atom size for consistency */
10121 if (QT_UINT32 (node->data) <= 4 + 12 + 12 + 16) {
10122 GST_WARNING_OBJECT (demux, "Tag ---- atom is too small, ignoring");
10126 mean = qtdemux_tree_get_child_by_type (node, FOURCC_mean);
10128 GST_WARNING_OBJECT (demux, "No 'mean' atom found");
10132 meansize = QT_UINT32 (mean->data);
10133 if (meansize <= 12) {
10134 GST_WARNING_OBJECT (demux, "Small mean atom, ignoring the whole tag");
10137 meanstr = ((gchar *) mean->data) + 12;
10140 name = qtdemux_tree_get_child_by_type (node, FOURCC_name);
10142 GST_WARNING_OBJECT (demux, "'name' atom not found, ignoring tag");
10146 namesize = QT_UINT32 (name->data);
10147 if (namesize <= 12) {
10148 GST_WARNING_OBJECT (demux, "'name' atom is too small, ignoring tag");
10151 namestr = ((gchar *) name->data) + 12;
10159 * uint24 - data type
10163 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
10165 GST_WARNING_OBJECT (demux, "No data atom in this tag");
10168 datasize = QT_UINT32 (data->data);
10169 if (datasize <= 16) {
10170 GST_WARNING_OBJECT (demux, "Data atom too small");
10173 datatype = QT_UINT32 (((gchar *) data->data) + 8) & 0xFFFFFF;
10175 if ((strncmp (meanstr, "com.apple.iTunes", meansize) == 0) ||
10176 (strncmp (meanstr, "org.hydrogenaudio.replaygain", meansize) == 0)) {
10177 static const struct
10179 const gchar name[28];
10180 const gchar tag[28];
10183 "replaygain_track_gain", GST_TAG_TRACK_GAIN}, {
10184 "replaygain_track_peak", GST_TAG_TRACK_PEAK}, {
10185 "replaygain_album_gain", GST_TAG_ALBUM_GAIN}, {
10186 "replaygain_album_peak", GST_TAG_ALBUM_PEAK}, {
10187 "MusicBrainz Track Id", GST_TAG_MUSICBRAINZ_TRACKID}, {
10188 "MusicBrainz Artist Id", GST_TAG_MUSICBRAINZ_ARTISTID}, {
10189 "MusicBrainz Album Id", GST_TAG_MUSICBRAINZ_ALBUMID}, {
10190 "MusicBrainz Album Artist Id", GST_TAG_MUSICBRAINZ_ALBUMARTISTID}
10194 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
10195 if (!g_ascii_strncasecmp (tags[i].name, namestr, namesize)) {
10196 switch (gst_tag_get_type (tags[i].tag)) {
10197 case G_TYPE_DOUBLE:
10198 qtdemux_add_double_tag_from_str (demux, taglist, tags[i].tag,
10199 ((guint8 *) data->data) + 16, datasize - 16);
10201 case G_TYPE_STRING:
10202 qtdemux_tag_add_str (demux, taglist, tags[i].tag, NULL, node);
10211 if (i == G_N_ELEMENTS (tags))
10221 #ifndef GST_DISABLE_GST_DEBUG
10223 gchar *namestr_dbg;
10224 gchar *meanstr_dbg;
10226 meanstr_dbg = g_strndup (meanstr, meansize);
10227 namestr_dbg = g_strndup (namestr, namesize);
10229 GST_WARNING_OBJECT (demux, "This tag %s:%s type:%u is not mapped, "
10230 "file a bug at bugzilla.gnome.org", meanstr_dbg, namestr_dbg, datatype);
10232 g_free (namestr_dbg);
10233 g_free (meanstr_dbg);
10240 qtdemux_tag_add_id32 (GstQTDemux * demux, GstTagList * taglist, const char *tag,
10241 const char *tag_bis, GNode * node)
10246 GstTagList *id32_taglist = NULL;
10248 GST_LOG_OBJECT (demux, "parsing ID32");
10251 len = GST_READ_UINT32_BE (data);
10253 /* need at least full box and language tag */
10257 buf = gst_buffer_new_allocate (NULL, len - 14, NULL);
10258 gst_buffer_fill (buf, 0, data + 14, len - 14);
10260 id32_taglist = gst_tag_list_from_id3v2_tag (buf);
10261 if (id32_taglist) {
10262 GST_LOG_OBJECT (demux, "parsing ok");
10263 gst_tag_list_insert (taglist, id32_taglist, GST_TAG_MERGE_KEEP);
10264 gst_tag_list_unref (id32_taglist);
10266 GST_LOG_OBJECT (demux, "parsing failed");
10269 gst_buffer_unref (buf);
10272 typedef void (*GstQTDemuxAddTagFunc) (GstQTDemux * demux, GstTagList * taglist,
10273 const char *tag, const char *tag_bis, GNode * node);
10276 FOURCC_pcst -> if media is a podcast -> bool
10277 FOURCC_cpil -> if media is part of a compilation -> bool
10278 FOURCC_pgap -> if media is part of a gapless context -> bool
10279 FOURCC_tven -> the tv episode id e.g. S01E23 -> str
10282 static const struct
10285 const gchar *gst_tag;
10286 const gchar *gst_tag_bis;
10287 const GstQTDemuxAddTagFunc func;
10290 FOURCC__nam, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
10291 FOURCC_titl, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
10292 FOURCC__grp, GST_TAG_GROUPING, NULL, qtdemux_tag_add_str}, {
10293 FOURCC__wrt, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
10294 FOURCC__ART, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
10295 FOURCC_aART, GST_TAG_ALBUM_ARTIST, NULL, qtdemux_tag_add_str}, {
10296 FOURCC_perf, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
10297 FOURCC_auth, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
10298 FOURCC__alb, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
10299 FOURCC_albm, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
10300 FOURCC_cprt, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
10301 FOURCC__cpy, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
10302 FOURCC__cmt, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
10303 FOURCC__des, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
10304 FOURCC_desc, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
10305 FOURCC_dscp, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
10306 FOURCC__lyr, GST_TAG_LYRICS, NULL, qtdemux_tag_add_str}, {
10307 FOURCC__day, GST_TAG_DATE, NULL, qtdemux_tag_add_date}, {
10308 FOURCC_yrrc, GST_TAG_DATE, NULL, qtdemux_tag_add_year}, {
10309 FOURCC__too, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
10310 FOURCC__inf, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
10311 FOURCC_trkn, GST_TAG_TRACK_NUMBER, GST_TAG_TRACK_COUNT, qtdemux_tag_add_num}, {
10312 FOURCC_disk, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
10313 qtdemux_tag_add_num}, {
10314 FOURCC_disc, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
10315 qtdemux_tag_add_num}, {
10316 FOURCC__gen, GST_TAG_GENRE, NULL, qtdemux_tag_add_str}, {
10317 FOURCC_gnre, GST_TAG_GENRE, NULL, qtdemux_tag_add_gnre}, {
10318 FOURCC_tmpo, GST_TAG_BEATS_PER_MINUTE, NULL, qtdemux_tag_add_tmpo}, {
10319 FOURCC_covr, GST_TAG_PREVIEW_IMAGE, NULL, qtdemux_tag_add_covr}, {
10320 FOURCC_sonm, GST_TAG_TITLE_SORTNAME, NULL, qtdemux_tag_add_str}, {
10321 FOURCC_soal, GST_TAG_ALBUM_SORTNAME, NULL, qtdemux_tag_add_str}, {
10322 FOURCC_soar, GST_TAG_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
10323 FOURCC_soaa, GST_TAG_ALBUM_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
10324 FOURCC_soco, GST_TAG_COMPOSER_SORTNAME, NULL, qtdemux_tag_add_str}, {
10325 FOURCC_sosn, GST_TAG_SHOW_SORTNAME, NULL, qtdemux_tag_add_str}, {
10326 FOURCC_tvsh, GST_TAG_SHOW_NAME, NULL, qtdemux_tag_add_str}, {
10327 FOURCC_tvsn, GST_TAG_SHOW_SEASON_NUMBER, NULL, qtdemux_tag_add_uint32}, {
10328 FOURCC_tves, GST_TAG_SHOW_EPISODE_NUMBER, NULL, qtdemux_tag_add_uint32}, {
10329 FOURCC_kywd, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_keywords}, {
10330 FOURCC_keyw, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_str}, {
10331 FOURCC__enc, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
10332 FOURCC_loci, GST_TAG_GEO_LOCATION_NAME, NULL, qtdemux_tag_add_location}, {
10333 FOURCC_clsf, GST_QT_DEMUX_CLASSIFICATION_TAG, NULL,
10334 qtdemux_tag_add_classification}, {
10335 FOURCC__mak, GST_TAG_DEVICE_MANUFACTURER, NULL, qtdemux_tag_add_str}, {
10336 FOURCC__mod, GST_TAG_DEVICE_MODEL, NULL, qtdemux_tag_add_str}, {
10337 FOURCC__swr, GST_TAG_APPLICATION_NAME, NULL, qtdemux_tag_add_str}, {
10339 /* This is a special case, some tags are stored in this
10340 * 'reverse dns naming', according to:
10341 * http://atomicparsley.sourceforge.net/mpeg-4files.html and
10344 FOURCC_____, "", NULL, qtdemux_tag_add_revdns}, {
10345 /* see http://www.mp4ra.org/specs.html for ID32 in meta box */
10346 FOURCC_ID32, "", NULL, qtdemux_tag_add_id32}
10349 struct _GstQtDemuxTagList
10352 GstTagList *taglist;
10354 typedef struct _GstQtDemuxTagList GstQtDemuxTagList;
10357 qtdemux_tag_add_blob (GNode * node, GstQtDemuxTagList * qtdemuxtaglist)
10363 const gchar *style;
10368 GstQTDemux *demux = qtdemuxtaglist->demux;
10369 GstTagList *taglist = qtdemuxtaglist->taglist;
10372 len = QT_UINT32 (data);
10373 buf = gst_buffer_new_and_alloc (len);
10374 gst_buffer_fill (buf, 0, data, len);
10376 /* heuristic to determine style of tag */
10377 if (QT_FOURCC (data + 4) == FOURCC_____ ||
10378 (len > 8 + 12 && QT_FOURCC (data + 12) == FOURCC_data))
10380 else if (demux->major_brand == FOURCC_qt__)
10381 style = "quicktime";
10382 /* fall back to assuming iso/3gp tag style */
10386 /* santize the name for the caps. */
10387 for (i = 0; i < 4; i++) {
10388 guint8 d = data[4 + i];
10389 if (g_ascii_isalnum (d))
10390 ndata[i] = g_ascii_tolower (d);
10395 media_type = g_strdup_printf ("application/x-gst-qt-%c%c%c%c-tag",
10396 ndata[0], ndata[1], ndata[2], ndata[3]);
10397 GST_DEBUG_OBJECT (demux, "media type %s", media_type);
10399 s = gst_structure_new (media_type, "style", G_TYPE_STRING, style, NULL);
10400 sample = gst_sample_new (buf, NULL, NULL, s);
10401 gst_buffer_unref (buf);
10402 g_free (media_type);
10404 GST_DEBUG_OBJECT (demux, "adding private tag; size %d, info %" GST_PTR_FORMAT,
10407 gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND,
10408 GST_QT_DEMUX_PRIVATE_TAG, sample, NULL);
10410 gst_sample_unref (sample);
10414 qtdemux_parse_udta (GstQTDemux * qtdemux, GstTagList * taglist, GNode * udta)
10421 GstQtDemuxTagList demuxtaglist;
10423 demuxtaglist.demux = qtdemux;
10424 demuxtaglist.taglist = taglist;
10426 meta = qtdemux_tree_get_child_by_type (udta, FOURCC_meta);
10427 if (meta != NULL) {
10428 ilst = qtdemux_tree_get_child_by_type (meta, FOURCC_ilst);
10429 if (ilst == NULL) {
10430 GST_LOG_OBJECT (qtdemux, "no ilst");
10435 GST_LOG_OBJECT (qtdemux, "no meta so using udta itself");
10439 while (i < G_N_ELEMENTS (add_funcs)) {
10440 node = qtdemux_tree_get_child_by_type (ilst, add_funcs[i].fourcc);
10444 len = QT_UINT32 (node->data);
10446 GST_DEBUG_OBJECT (qtdemux, "too small tag atom %" GST_FOURCC_FORMAT,
10447 GST_FOURCC_ARGS (add_funcs[i].fourcc));
10449 add_funcs[i].func (qtdemux, taglist, add_funcs[i].gst_tag,
10450 add_funcs[i].gst_tag_bis, node);
10452 g_node_destroy (node);
10458 /* parsed nodes have been removed, pass along remainder as blob */
10459 g_node_children_foreach (ilst, G_TRAVERSE_ALL,
10460 (GNodeForeachFunc) qtdemux_tag_add_blob, &demuxtaglist);
10462 /* parse up XMP_ node if existing */
10463 xmp_ = qtdemux_tree_get_child_by_type (udta, FOURCC_XMP_);
10464 if (xmp_ != NULL) {
10466 GstTagList *xmptaglist;
10468 buf = _gst_buffer_new_wrapped (((guint8 *) xmp_->data) + 8,
10469 QT_UINT32 ((guint8 *) xmp_->data) - 8, NULL);
10470 xmptaglist = gst_tag_list_from_xmp_buffer (buf);
10471 gst_buffer_unref (buf);
10473 qtdemux_handle_xmp_taglist (qtdemux, taglist, xmptaglist);
10475 GST_DEBUG_OBJECT (qtdemux, "No XMP_ node found");
10481 GstStructure *structure; /* helper for sort function */
10483 guint min_req_bitrate;
10484 guint min_req_qt_version;
10488 qtdemux_redirects_sort_func (gconstpointer a, gconstpointer b)
10490 GstQtReference *ref_a = (GstQtReference *) a;
10491 GstQtReference *ref_b = (GstQtReference *) b;
10493 if (ref_b->min_req_qt_version != ref_a->min_req_qt_version)
10494 return ref_b->min_req_qt_version - ref_a->min_req_qt_version;
10496 /* known bitrates go before unknown; higher bitrates go first */
10497 return ref_b->min_req_bitrate - ref_a->min_req_bitrate;
10500 /* sort the redirects and post a message for the application.
10503 qtdemux_process_redirects (GstQTDemux * qtdemux, GList * references)
10505 GstQtReference *best;
10508 GValue list_val = { 0, };
10511 g_assert (references != NULL);
10513 references = g_list_sort (references, qtdemux_redirects_sort_func);
10515 best = (GstQtReference *) references->data;
10517 g_value_init (&list_val, GST_TYPE_LIST);
10519 for (l = references; l != NULL; l = l->next) {
10520 GstQtReference *ref = (GstQtReference *) l->data;
10521 GValue struct_val = { 0, };
10523 ref->structure = gst_structure_new ("redirect",
10524 "new-location", G_TYPE_STRING, ref->location, NULL);
10526 if (ref->min_req_bitrate > 0) {
10527 gst_structure_set (ref->structure, "minimum-bitrate", G_TYPE_INT,
10528 ref->min_req_bitrate, NULL);
10531 g_value_init (&struct_val, GST_TYPE_STRUCTURE);
10532 g_value_set_boxed (&struct_val, ref->structure);
10533 gst_value_list_append_value (&list_val, &struct_val);
10534 g_value_unset (&struct_val);
10535 /* don't free anything here yet, since we need best->structure below */
10538 g_assert (best != NULL);
10539 s = gst_structure_copy (best->structure);
10541 if (g_list_length (references) > 1) {
10542 gst_structure_set_value (s, "locations", &list_val);
10545 g_value_unset (&list_val);
10547 for (l = references; l != NULL; l = l->next) {
10548 GstQtReference *ref = (GstQtReference *) l->data;
10550 gst_structure_free (ref->structure);
10551 g_free (ref->location);
10554 g_list_free (references);
10556 GST_INFO_OBJECT (qtdemux, "posting redirect message: %" GST_PTR_FORMAT, s);
10557 msg = gst_message_new_element (GST_OBJECT_CAST (qtdemux), s);
10558 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
10559 qtdemux->posted_redirect = TRUE;
10562 /* look for redirect nodes, collect all redirect information and
10566 qtdemux_parse_redirects (GstQTDemux * qtdemux)
10568 GNode *rmra, *rmda, *rdrf;
10570 rmra = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_rmra);
10572 GList *redirects = NULL;
10574 rmda = qtdemux_tree_get_child_by_type (rmra, FOURCC_rmda);
10576 GstQtReference ref = { NULL, NULL, 0, 0 };
10577 GNode *rmdr, *rmvc;
10579 if ((rmdr = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmdr))) {
10580 ref.min_req_bitrate = QT_UINT32 ((guint8 *) rmdr->data + 12);
10581 GST_LOG_OBJECT (qtdemux, "data rate atom, required bitrate = %u",
10582 ref.min_req_bitrate);
10585 if ((rmvc = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmvc))) {
10586 guint32 package = QT_FOURCC ((guint8 *) rmvc->data + 12);
10587 guint version = QT_UINT32 ((guint8 *) rmvc->data + 16);
10589 #ifndef GST_DISABLE_GST_DEBUG
10590 guint bitmask = QT_UINT32 ((guint8 *) rmvc->data + 20);
10592 guint check_type = QT_UINT16 ((guint8 *) rmvc->data + 24);
10594 GST_LOG_OBJECT (qtdemux,
10595 "version check atom [%" GST_FOURCC_FORMAT "], version=0x%08x"
10596 ", mask=%08x, check_type=%u", GST_FOURCC_ARGS (package), version,
10597 bitmask, check_type);
10598 if (package == FOURCC_qtim && check_type == 0) {
10599 ref.min_req_qt_version = version;
10603 rdrf = qtdemux_tree_get_child_by_type (rmda, FOURCC_rdrf);
10608 ref_type = QT_FOURCC ((guint8 *) rdrf->data + 12);
10609 ref_data = (guint8 *) rdrf->data + 20;
10610 if (ref_type == FOURCC_alis) {
10611 guint record_len, record_version, fn_len;
10613 /* MacOSX alias record, google for alias-layout.txt */
10614 record_len = QT_UINT16 (ref_data + 4);
10615 record_version = QT_UINT16 (ref_data + 4 + 2);
10616 fn_len = QT_UINT8 (ref_data + 50);
10617 if (record_len > 50 && record_version == 2 && fn_len > 0) {
10618 ref.location = g_strndup ((gchar *) ref_data + 51, fn_len);
10620 } else if (ref_type == FOURCC_url_) {
10621 ref.location = g_strdup ((gchar *) ref_data);
10623 GST_DEBUG_OBJECT (qtdemux,
10624 "unknown rdrf reference type %" GST_FOURCC_FORMAT,
10625 GST_FOURCC_ARGS (ref_type));
10627 if (ref.location != NULL) {
10628 GST_INFO_OBJECT (qtdemux, "New location: %s", ref.location);
10629 redirects = g_list_prepend (redirects, g_memdup (&ref, sizeof (ref)));
10631 GST_WARNING_OBJECT (qtdemux,
10632 "Failed to extract redirect location from rdrf atom");
10636 /* look for others */
10637 rmda = qtdemux_tree_get_sibling_by_type (rmda, FOURCC_rmda);
10640 if (redirects != NULL) {
10641 qtdemux_process_redirects (qtdemux, redirects);
10647 static GstTagList *
10648 qtdemux_add_container_format (GstQTDemux * qtdemux, GstTagList * tags)
10652 if (tags == NULL) {
10653 tags = gst_tag_list_new_empty ();
10654 gst_tag_list_set_scope (tags, GST_TAG_SCOPE_GLOBAL);
10657 if (qtdemux->major_brand == FOURCC_mjp2)
10658 fmt = "Motion JPEG 2000";
10659 else if ((qtdemux->major_brand & 0xffff) == GST_MAKE_FOURCC ('3', 'g', 0, 0))
10661 else if (qtdemux->major_brand == FOURCC_qt__)
10663 else if (qtdemux->fragmented)
10666 fmt = "ISO MP4/M4A";
10668 GST_LOG_OBJECT (qtdemux, "mapped %" GST_FOURCC_FORMAT " to '%s'",
10669 GST_FOURCC_ARGS (qtdemux->major_brand), fmt);
10671 gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_CONTAINER_FORMAT,
10677 /* we have read th complete moov node now.
10678 * This function parses all of the relevant info, creates the traks and
10679 * prepares all data structures for playback
10682 qtdemux_parse_tree (GstQTDemux * qtdemux)
10688 GstClockTime duration;
10689 guint64 creation_time;
10690 GstDateTime *datetime = NULL;
10693 /* make sure we have a usable taglist */
10694 if (!qtdemux->tag_list) {
10695 qtdemux->tag_list = gst_tag_list_new_empty ();
10696 gst_tag_list_set_scope (qtdemux->tag_list, GST_TAG_SCOPE_GLOBAL);
10698 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
10701 mvhd = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvhd);
10702 if (mvhd == NULL) {
10703 GST_LOG_OBJECT (qtdemux, "No mvhd node found, looking for redirects.");
10704 return qtdemux_parse_redirects (qtdemux);
10707 version = QT_UINT8 ((guint8 *) mvhd->data + 8);
10708 if (version == 1) {
10709 creation_time = QT_UINT64 ((guint8 *) mvhd->data + 12);
10710 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 28);
10711 qtdemux->duration = QT_UINT64 ((guint8 *) mvhd->data + 32);
10712 } else if (version == 0) {
10713 creation_time = QT_UINT32 ((guint8 *) mvhd->data + 12);
10714 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 20);
10715 qtdemux->duration = QT_UINT32 ((guint8 *) mvhd->data + 24);
10717 GST_WARNING_OBJECT (qtdemux, "Unhandled mvhd version %d", version);
10721 /* Moving qt creation time (secs since 1904) to unix time */
10722 if (creation_time != 0) {
10723 /* Try to use epoch first as it should be faster and more commonly found */
10724 if (creation_time >= QTDEMUX_SECONDS_FROM_1904_TO_1970) {
10727 creation_time -= QTDEMUX_SECONDS_FROM_1904_TO_1970;
10728 /* some data cleansing sanity */
10729 g_get_current_time (&now);
10730 if (now.tv_sec + 24 * 3600 < creation_time) {
10731 GST_DEBUG_OBJECT (qtdemux, "discarding bogus future creation time");
10733 datetime = gst_date_time_new_from_unix_epoch_utc (creation_time);
10736 GDateTime *base_dt = g_date_time_new_utc (1904, 1, 1, 0, 0, 0);
10737 GDateTime *dt, *dt_local;
10739 dt = g_date_time_add_seconds (base_dt, creation_time);
10740 dt_local = g_date_time_to_local (dt);
10741 datetime = gst_date_time_new_from_g_date_time (dt_local);
10743 g_date_time_unref (base_dt);
10744 g_date_time_unref (dt);
10748 /* Use KEEP as explicit tags should have a higher priority than mvhd tag */
10749 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_KEEP, GST_TAG_DATE_TIME,
10751 gst_date_time_unref (datetime);
10754 GST_INFO_OBJECT (qtdemux, "timescale: %u", qtdemux->timescale);
10755 GST_INFO_OBJECT (qtdemux, "duration: %" G_GUINT64_FORMAT, qtdemux->duration);
10757 /* check for fragmented file and get some (default) data */
10758 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
10761 GstByteReader mehd_data;
10763 /* let track parsing or anyone know weird stuff might happen ... */
10764 qtdemux->fragmented = TRUE;
10766 /* compensate for total duration */
10767 mehd = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_mehd, &mehd_data);
10769 qtdemux_parse_mehd (qtdemux, &mehd_data);
10772 /* set duration in the segment info */
10773 gst_qtdemux_get_duration (qtdemux, &duration);
10775 qtdemux->segment.duration = duration;
10776 /* also do not exceed duration; stop is set that way post seek anyway,
10777 * and segment activation falls back to duration,
10778 * whereas loop only checks stop, so let's align this here as well */
10779 qtdemux->segment.stop = duration;
10782 /* parse all traks */
10783 trak = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_trak);
10785 qtdemux_parse_trak (qtdemux, trak);
10786 /* iterate all siblings */
10787 trak = qtdemux_tree_get_sibling_by_type (trak, FOURCC_trak);
10790 if (!qtdemux->tag_list) {
10791 GST_DEBUG_OBJECT (qtdemux, "new tag list");
10792 qtdemux->tag_list = gst_tag_list_new_empty ();
10793 gst_tag_list_set_scope (qtdemux->tag_list, GST_TAG_SCOPE_GLOBAL);
10795 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
10799 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_udta);
10801 qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
10803 GST_LOG_OBJECT (qtdemux, "No udta node found.");
10806 /* maybe also some tags in meta box */
10807 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_meta);
10809 GST_DEBUG_OBJECT (qtdemux, "Parsing meta box for tags.");
10810 qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
10812 GST_LOG_OBJECT (qtdemux, "No meta node found.");
10815 qtdemux->tag_list = qtdemux_add_container_format (qtdemux, qtdemux->tag_list);
10820 /* taken from ffmpeg */
10822 read_descr_size (guint8 * ptr, guint8 * end, guint8 ** end_out)
10834 len = (len << 7) | (c & 0x7f);
10842 /* this can change the codec originally present in @list */
10844 gst_qtdemux_handle_esds (GstQTDemux * qtdemux, QtDemuxStream * stream,
10845 GNode * esds, GstTagList * list)
10847 int len = QT_UINT32 (esds->data);
10848 guint8 *ptr = esds->data;
10849 guint8 *end = ptr + len;
10851 guint8 *data_ptr = NULL;
10853 guint8 object_type_id = 0;
10854 const char *codec_name = NULL;
10855 GstCaps *caps = NULL;
10857 GST_MEMDUMP_OBJECT (qtdemux, "esds", ptr, len);
10859 GST_DEBUG_OBJECT (qtdemux, "version/flags = %08x", QT_UINT32 (ptr));
10861 while (ptr + 1 < end) {
10862 tag = QT_UINT8 (ptr);
10863 GST_DEBUG_OBJECT (qtdemux, "tag = %02x", tag);
10865 len = read_descr_size (ptr, end, &ptr);
10866 GST_DEBUG_OBJECT (qtdemux, "len = %d", len);
10868 /* Check the stated amount of data is available for reading */
10869 if (len < 0 || ptr + len > end)
10873 case ES_DESCRIPTOR_TAG:
10874 GST_DEBUG_OBJECT (qtdemux, "ID %04x", QT_UINT16 (ptr));
10875 GST_DEBUG_OBJECT (qtdemux, "priority %04x", QT_UINT8 (ptr + 2));
10878 case DECODER_CONFIG_DESC_TAG:{
10879 guint max_bitrate, avg_bitrate;
10881 object_type_id = QT_UINT8 (ptr);
10882 max_bitrate = QT_UINT32 (ptr + 5);
10883 avg_bitrate = QT_UINT32 (ptr + 9);
10884 GST_DEBUG_OBJECT (qtdemux, "object_type_id %02x", object_type_id);
10885 GST_DEBUG_OBJECT (qtdemux, "stream_type %02x", QT_UINT8 (ptr + 1));
10886 GST_DEBUG_OBJECT (qtdemux, "buffer_size_db %02x", QT_UINT24 (ptr + 2));
10887 GST_DEBUG_OBJECT (qtdemux, "max bitrate %u", max_bitrate);
10888 GST_DEBUG_OBJECT (qtdemux, "avg bitrate %u", avg_bitrate);
10889 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
10890 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
10891 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
10893 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
10894 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
10895 avg_bitrate, NULL);
10900 case DECODER_SPECIFIC_INFO_TAG:
10901 GST_MEMDUMP_OBJECT (qtdemux, "data", ptr, len);
10902 if (object_type_id == 0xe0 && len == 0x40) {
10908 GST_DEBUG_OBJECT (qtdemux,
10909 "Have VOBSUB palette. Creating palette event");
10910 /* move to decConfigDescr data and read palette */
10912 for (i = 0; i < 16; i++) {
10913 clut[i] = QT_UINT32 (data);
10917 s = gst_structure_new ("application/x-gst-dvd", "event",
10918 G_TYPE_STRING, "dvd-spu-clut-change",
10919 "clut00", G_TYPE_INT, clut[0], "clut01", G_TYPE_INT, clut[1],
10920 "clut02", G_TYPE_INT, clut[2], "clut03", G_TYPE_INT, clut[3],
10921 "clut04", G_TYPE_INT, clut[4], "clut05", G_TYPE_INT, clut[5],
10922 "clut06", G_TYPE_INT, clut[6], "clut07", G_TYPE_INT, clut[7],
10923 "clut08", G_TYPE_INT, clut[8], "clut09", G_TYPE_INT, clut[9],
10924 "clut10", G_TYPE_INT, clut[10], "clut11", G_TYPE_INT, clut[11],
10925 "clut12", G_TYPE_INT, clut[12], "clut13", G_TYPE_INT, clut[13],
10926 "clut14", G_TYPE_INT, clut[14], "clut15", G_TYPE_INT, clut[15],
10929 /* store event and trigger custom processing */
10930 stream->pending_event =
10931 gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s);
10933 /* Generic codec_data handler puts it on the caps */
10940 case SL_CONFIG_DESC_TAG:
10941 GST_DEBUG_OBJECT (qtdemux, "data %02x", QT_UINT8 (ptr));
10945 GST_DEBUG_OBJECT (qtdemux, "Unknown/unhandled descriptor tag %02x",
10947 GST_MEMDUMP_OBJECT (qtdemux, "descriptor data", ptr, len);
10953 /* object_type_id in the esds atom in mp4a and mp4v tells us which codec is
10954 * in use, and should also be used to override some other parameters for some
10956 switch (object_type_id) {
10957 case 0x20: /* MPEG-4 */
10958 /* 4 bytes for the visual_object_sequence_start_code and 1 byte for the
10959 * profile_and_level_indication */
10960 if (data_ptr != NULL && data_len >= 5 &&
10961 GST_READ_UINT32_BE (data_ptr) == 0x000001b0) {
10962 gst_codec_utils_mpeg4video_caps_set_level_and_profile (stream->caps,
10963 data_ptr + 4, data_len - 4);
10965 break; /* Nothing special needed here */
10966 case 0x21: /* H.264 */
10967 codec_name = "H.264 / AVC";
10968 caps = gst_caps_new_simple ("video/x-h264",
10969 "stream-format", G_TYPE_STRING, "avc",
10970 "alignment", G_TYPE_STRING, "au", NULL);
10972 case 0x40: /* AAC (any) */
10973 case 0x66: /* AAC Main */
10974 case 0x67: /* AAC LC */
10975 case 0x68: /* AAC SSR */
10976 /* Override channels and rate based on the codec_data, as it's often
10978 /* Only do so for basic setup without HE-AAC extension */
10979 if (data_ptr && data_len == 2) {
10980 guint channels, rateindex, rate;
10982 /* FIXME: add gst_codec_utils_aac_get_{channels|sample_rate}()? */
10983 channels = (data_ptr[1] & 0x7f) >> 3;
10984 if (channels > 0 && channels < 7) {
10985 stream->n_channels = channels;
10986 } else if (channels == 7) {
10987 stream->n_channels = 8;
10990 rateindex = ((data_ptr[0] & 0x7) << 1) | ((data_ptr[1] & 0x80) >> 7);
10991 rate = gst_codec_utils_aac_get_sample_rate_from_index (rateindex);
10993 stream->rate = rate;
10996 /* Set level and profile if possible */
10997 if (data_ptr != NULL && data_len >= 2) {
10998 gst_codec_utils_aac_caps_set_level_and_profile (stream->caps,
10999 data_ptr, data_len);
11002 case 0x60: /* MPEG-2, various profiles */
11008 codec_name = "MPEG-2 video";
11009 caps = gst_caps_new_simple ("video/mpeg",
11010 "mpegversion", G_TYPE_INT, 2,
11011 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
11013 case 0x69: /* MPEG-2 BC audio */
11014 case 0x6B: /* MPEG-1 audio */
11015 caps = gst_caps_new_simple ("audio/mpeg",
11016 "mpegversion", G_TYPE_INT, 1, "parsed", G_TYPE_BOOLEAN, TRUE, NULL);
11017 codec_name = "MPEG-1 audio";
11019 case 0x6A: /* MPEG-1 */
11020 codec_name = "MPEG-1 video";
11021 caps = gst_caps_new_simple ("video/mpeg",
11022 "mpegversion", G_TYPE_INT, 1,
11023 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
11025 case 0x6C: /* MJPEG */
11027 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
11029 codec_name = "Motion-JPEG";
11031 case 0x6D: /* PNG */
11033 gst_caps_new_simple ("image/png", "parsed", G_TYPE_BOOLEAN, TRUE,
11035 codec_name = "PNG still images";
11037 case 0x6E: /* JPEG2000 */
11038 codec_name = "JPEG-2000";
11039 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
11041 case 0xA4: /* Dirac */
11042 codec_name = "Dirac";
11043 caps = gst_caps_new_empty_simple ("video/x-dirac");
11045 case 0xA5: /* AC3 */
11046 codec_name = "AC-3 audio";
11047 caps = gst_caps_new_simple ("audio/x-ac3",
11048 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
11050 case 0xA9: /* AC3 */
11051 codec_name = "DTS audio";
11052 caps = gst_caps_new_simple ("audio/x-dts",
11053 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
11055 case 0xE1: /* QCELP */
11056 /* QCELP, the codec_data is a riff tag (little endian) with
11057 * 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). */
11058 caps = gst_caps_new_empty_simple ("audio/qcelp");
11059 codec_name = "QCELP";
11065 /* If we have a replacement caps, then change our caps for this stream */
11067 gst_caps_unref (stream->caps);
11068 stream->caps = caps;
11071 if (codec_name && list)
11072 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
11073 GST_TAG_AUDIO_CODEC, codec_name, NULL);
11075 /* Add the codec_data attribute to caps, if we have it */
11079 buffer = gst_buffer_new_and_alloc (data_len);
11080 gst_buffer_fill (buffer, 0, data_ptr, data_len);
11082 GST_DEBUG_OBJECT (qtdemux, "setting codec_data from esds");
11083 GST_MEMDUMP_OBJECT (qtdemux, "codec_data from esds", data_ptr, data_len);
11085 gst_caps_set_simple (stream->caps, "codec_data", GST_TYPE_BUFFER,
11087 gst_buffer_unref (buffer);
11092 #define _codec(name) \
11094 if (codec_name) { \
11095 *codec_name = g_strdup (name); \
11100 qtdemux_video_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
11101 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
11103 GstCaps *caps = NULL;
11104 GstVideoFormat format = GST_VIDEO_FORMAT_UNKNOWN;
11107 case GST_MAKE_FOURCC ('p', 'n', 'g', ' '):
11108 _codec ("PNG still images");
11109 caps = gst_caps_new_empty_simple ("image/png");
11111 case GST_MAKE_FOURCC ('j', 'p', 'e', 'g'):
11112 _codec ("JPEG still images");
11114 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
11117 case GST_MAKE_FOURCC ('m', 'j', 'p', 'a'):
11118 case GST_MAKE_FOURCC ('A', 'V', 'D', 'J'):
11119 case GST_MAKE_FOURCC ('M', 'J', 'P', 'G'):
11120 case GST_MAKE_FOURCC ('d', 'm', 'b', '1'):
11121 _codec ("Motion-JPEG");
11123 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
11126 case GST_MAKE_FOURCC ('m', 'j', 'p', 'b'):
11127 _codec ("Motion-JPEG format B");
11128 caps = gst_caps_new_empty_simple ("video/x-mjpeg-b");
11130 case GST_MAKE_FOURCC ('m', 'j', 'p', '2'):
11131 _codec ("JPEG-2000");
11132 /* override to what it should be according to spec, avoid palette_data */
11133 stream->bits_per_sample = 24;
11134 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
11136 case GST_MAKE_FOURCC ('S', 'V', 'Q', '3'):
11137 _codec ("Sorensen video v.3");
11138 caps = gst_caps_new_simple ("video/x-svq",
11139 "svqversion", G_TYPE_INT, 3, NULL);
11141 case GST_MAKE_FOURCC ('s', 'v', 'q', 'i'):
11142 case GST_MAKE_FOURCC ('S', 'V', 'Q', '1'):
11143 _codec ("Sorensen video v.1");
11144 caps = gst_caps_new_simple ("video/x-svq",
11145 "svqversion", G_TYPE_INT, 1, NULL);
11147 case GST_MAKE_FOURCC ('W', 'R', 'A', 'W'):
11148 caps = gst_caps_new_empty_simple ("video/x-raw");
11149 gst_caps_set_simple (caps, "format", G_TYPE_STRING, "RGB8P", NULL);
11150 _codec ("Windows Raw RGB");
11152 case GST_MAKE_FOURCC ('r', 'a', 'w', ' '):
11156 bps = QT_UINT16 (stsd_data + 98);
11159 format = GST_VIDEO_FORMAT_RGB15;
11162 format = GST_VIDEO_FORMAT_RGB16;
11165 format = GST_VIDEO_FORMAT_RGB;
11168 format = GST_VIDEO_FORMAT_ARGB;
11176 case GST_MAKE_FOURCC ('y', 'v', '1', '2'):
11177 format = GST_VIDEO_FORMAT_I420;
11179 case GST_MAKE_FOURCC ('y', 'u', 'v', '2'):
11180 case GST_MAKE_FOURCC ('Y', 'u', 'v', '2'):
11181 format = GST_VIDEO_FORMAT_I420;
11183 case GST_MAKE_FOURCC ('2', 'v', 'u', 'y'):
11184 case GST_MAKE_FOURCC ('2', 'V', 'u', 'y'):
11185 format = GST_VIDEO_FORMAT_UYVY;
11187 case GST_MAKE_FOURCC ('v', '3', '0', '8'):
11188 format = GST_VIDEO_FORMAT_v308;
11190 case GST_MAKE_FOURCC ('v', '2', '1', '6'):
11191 format = GST_VIDEO_FORMAT_v216;
11193 case GST_MAKE_FOURCC ('v', '2', '1', '0'):
11194 format = GST_VIDEO_FORMAT_v210;
11196 case GST_MAKE_FOURCC ('r', '2', '1', '0'):
11197 format = GST_VIDEO_FORMAT_r210;
11199 /* Packed YUV 4:4:4 10 bit in 32 bits, complex
11200 case GST_MAKE_FOURCC ('v', '4', '1', '0'):
11201 format = GST_VIDEO_FORMAT_v410;
11204 /* Packed YUV 4:4:4:4 8 bit in 32 bits
11205 * but different order than AYUV
11206 case GST_MAKE_FOURCC ('v', '4', '0', '8'):
11207 format = GST_VIDEO_FORMAT_v408;
11210 case GST_MAKE_FOURCC ('m', 'p', 'e', 'g'):
11211 case GST_MAKE_FOURCC ('m', 'p', 'g', '1'):
11212 _codec ("MPEG-1 video");
11213 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
11214 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
11216 case GST_MAKE_FOURCC ('h', 'd', 'v', '1'): /* HDV 720p30 */
11217 case GST_MAKE_FOURCC ('h', 'd', 'v', '2'): /* HDV 1080i60 */
11218 case GST_MAKE_FOURCC ('h', 'd', 'v', '3'): /* HDV 1080i50 */
11219 case GST_MAKE_FOURCC ('h', 'd', 'v', '4'): /* HDV 720p24 */
11220 case GST_MAKE_FOURCC ('h', 'd', 'v', '5'): /* HDV 720p25 */
11221 case GST_MAKE_FOURCC ('h', 'd', 'v', '6'): /* HDV 1080p24 */
11222 case GST_MAKE_FOURCC ('h', 'd', 'v', '7'): /* HDV 1080p25 */
11223 case GST_MAKE_FOURCC ('h', 'd', 'v', '8'): /* HDV 1080p30 */
11224 case GST_MAKE_FOURCC ('h', 'd', 'v', '9'): /* HDV 720p60 */
11225 case GST_MAKE_FOURCC ('h', 'd', 'v', 'a'): /* HDV 720p50 */
11226 case GST_MAKE_FOURCC ('m', 'x', '5', 'n'): /* MPEG2 IMX NTSC 525/60 50mb/s produced by FCP */
11227 case GST_MAKE_FOURCC ('m', 'x', '5', 'p'): /* MPEG2 IMX PAL 625/60 50mb/s produced by FCP */
11228 case GST_MAKE_FOURCC ('m', 'x', '4', 'n'): /* MPEG2 IMX NTSC 525/60 40mb/s produced by FCP */
11229 case GST_MAKE_FOURCC ('m', 'x', '4', 'p'): /* MPEG2 IMX PAL 625/60 40mb/s produced by FCP */
11230 case GST_MAKE_FOURCC ('m', 'x', '3', 'n'): /* MPEG2 IMX NTSC 525/60 30mb/s produced by FCP */
11231 case GST_MAKE_FOURCC ('m', 'x', '3', 'p'): /* MPEG2 IMX PAL 625/50 30mb/s produced by FCP */
11232 case GST_MAKE_FOURCC ('x', 'd', 'v', '1'): /* XDCAM HD 720p30 35Mb/s */
11233 case GST_MAKE_FOURCC ('x', 'd', 'v', '2'): /* XDCAM HD 1080i60 35Mb/s */
11234 case GST_MAKE_FOURCC ('x', 'd', 'v', '3'): /* XDCAM HD 1080i50 35Mb/s */
11235 case GST_MAKE_FOURCC ('x', 'd', 'v', '4'): /* XDCAM HD 720p24 35Mb/s */
11236 case GST_MAKE_FOURCC ('x', 'd', 'v', '5'): /* XDCAM HD 720p25 35Mb/s */
11237 case GST_MAKE_FOURCC ('x', 'd', 'v', '6'): /* XDCAM HD 1080p24 35Mb/s */
11238 case GST_MAKE_FOURCC ('x', 'd', 'v', '7'): /* XDCAM HD 1080p25 35Mb/s */
11239 case GST_MAKE_FOURCC ('x', 'd', 'v', '8'): /* XDCAM HD 1080p30 35Mb/s */
11240 case GST_MAKE_FOURCC ('x', 'd', 'v', '9'): /* XDCAM HD 720p60 35Mb/s */
11241 case GST_MAKE_FOURCC ('x', 'd', 'v', 'a'): /* XDCAM HD 720p50 35Mb/s */
11242 case GST_MAKE_FOURCC ('x', 'd', 'v', 'b'): /* XDCAM EX 1080i60 50Mb/s CBR */
11243 case GST_MAKE_FOURCC ('x', 'd', 'v', 'c'): /* XDCAM EX 1080i50 50Mb/s CBR */
11244 case GST_MAKE_FOURCC ('x', 'd', 'v', 'd'): /* XDCAM HD 1080p24 50Mb/s CBR */
11245 case GST_MAKE_FOURCC ('x', 'd', 'v', 'e'): /* XDCAM HD 1080p25 50Mb/s CBR */
11246 case GST_MAKE_FOURCC ('x', 'd', 'v', 'f'): /* XDCAM HD 1080p30 50Mb/s CBR */
11247 case GST_MAKE_FOURCC ('x', 'd', '5', '1'): /* XDCAM HD422 720p30 50Mb/s CBR */
11248 case GST_MAKE_FOURCC ('x', 'd', '5', '4'): /* XDCAM HD422 720p24 50Mb/s CBR */
11249 case GST_MAKE_FOURCC ('x', 'd', '5', '5'): /* XDCAM HD422 720p25 50Mb/s CBR */
11250 case GST_MAKE_FOURCC ('x', 'd', '5', '9'): /* XDCAM HD422 720p60 50Mb/s CBR */
11251 case GST_MAKE_FOURCC ('x', 'd', '5', 'a'): /* XDCAM HD422 720p50 50Mb/s CBR */
11252 case GST_MAKE_FOURCC ('x', 'd', '5', 'b'): /* XDCAM HD422 1080i50 50Mb/s CBR */
11253 case GST_MAKE_FOURCC ('x', 'd', '5', 'c'): /* XDCAM HD422 1080i50 50Mb/s CBR */
11254 case GST_MAKE_FOURCC ('x', 'd', '5', 'd'): /* XDCAM HD422 1080p24 50Mb/s CBR */
11255 case GST_MAKE_FOURCC ('x', 'd', '5', 'e'): /* XDCAM HD422 1080p25 50Mb/s CBR */
11256 case GST_MAKE_FOURCC ('x', 'd', '5', 'f'): /* XDCAM HD422 1080p30 50Mb/s CBR */
11257 case GST_MAKE_FOURCC ('x', 'd', 'h', 'd'): /* XDCAM HD 540p */
11258 case GST_MAKE_FOURCC ('x', 'd', 'h', '2'): /* XDCAM HD422 540p */
11259 case GST_MAKE_FOURCC ('A', 'V', 'm', 'p'): /* AVID IMX PAL */
11260 case GST_MAKE_FOURCC ('m', 'p', 'g', '2'): /* AVID IMX PAL */
11261 case GST_MAKE_FOURCC ('m', 'p', '2', 'v'): /* AVID IMX PAL */
11262 _codec ("MPEG-2 video");
11263 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 2,
11264 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
11266 case GST_MAKE_FOURCC ('g', 'i', 'f', ' '):
11267 _codec ("GIF still images");
11268 caps = gst_caps_new_empty_simple ("image/gif");
11270 case GST_MAKE_FOURCC ('h', '2', '6', '3'):
11271 case GST_MAKE_FOURCC ('H', '2', '6', '3'):
11272 case GST_MAKE_FOURCC ('s', '2', '6', '3'):
11273 case GST_MAKE_FOURCC ('U', '2', '6', '3'):
11275 /* ffmpeg uses the height/width props, don't know why */
11276 caps = gst_caps_new_simple ("video/x-h263",
11277 "variant", G_TYPE_STRING, "itu", NULL);
11279 case GST_MAKE_FOURCC ('m', 'p', '4', 'v'):
11280 case GST_MAKE_FOURCC ('M', 'P', '4', 'V'):
11281 _codec ("MPEG-4 video");
11282 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
11283 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
11285 case GST_MAKE_FOURCC ('3', 'i', 'v', 'd'):
11286 case GST_MAKE_FOURCC ('3', 'I', 'V', 'D'):
11287 _codec ("Microsoft MPEG-4 4.3"); /* FIXME? */
11288 caps = gst_caps_new_simple ("video/x-msmpeg",
11289 "msmpegversion", G_TYPE_INT, 43, NULL);
11291 case GST_MAKE_FOURCC ('D', 'I', 'V', '3'):
11293 caps = gst_caps_new_simple ("video/x-divx",
11294 "divxversion", G_TYPE_INT, 3, NULL);
11296 case GST_MAKE_FOURCC ('D', 'I', 'V', 'X'):
11297 case GST_MAKE_FOURCC ('d', 'i', 'v', 'x'):
11299 caps = gst_caps_new_simple ("video/x-divx",
11300 "divxversion", G_TYPE_INT, 4, NULL);
11302 case GST_MAKE_FOURCC ('D', 'X', '5', '0'):
11304 caps = gst_caps_new_simple ("video/x-divx",
11305 "divxversion", G_TYPE_INT, 5, NULL);
11308 case GST_MAKE_FOURCC ('3', 'I', 'V', '1'):
11309 case GST_MAKE_FOURCC ('3', 'I', 'V', '2'):
11310 case GST_MAKE_FOURCC ('X', 'V', 'I', 'D'):
11311 case GST_MAKE_FOURCC ('x', 'v', 'i', 'd'):
11312 case GST_MAKE_FOURCC ('F', 'M', 'P', '4'):
11313 case GST_MAKE_FOURCC ('U', 'M', 'P', '4'):
11314 caps = gst_caps_new_simple ("video/mpeg",
11315 "mpegversion", G_TYPE_INT, 4, NULL);
11317 *codec_name = g_strdup ("MPEG-4");
11320 case GST_MAKE_FOURCC ('c', 'v', 'i', 'd'):
11321 _codec ("Cinepak");
11322 caps = gst_caps_new_empty_simple ("video/x-cinepak");
11324 case GST_MAKE_FOURCC ('q', 'd', 'r', 'w'):
11325 _codec ("Apple QuickDraw");
11326 caps = gst_caps_new_empty_simple ("video/x-qdrw");
11328 case GST_MAKE_FOURCC ('r', 'p', 'z', 'a'):
11329 _codec ("Apple video");
11330 caps = gst_caps_new_empty_simple ("video/x-apple-video");
11332 case GST_MAKE_FOURCC ('H', '2', '6', '4'):
11333 case GST_MAKE_FOURCC ('a', 'v', 'c', '1'):
11334 _codec ("H.264 / AVC");
11335 caps = gst_caps_new_simple ("video/x-h264",
11336 "stream-format", G_TYPE_STRING, "avc",
11337 "alignment", G_TYPE_STRING, "au", NULL);
11339 case GST_MAKE_FOURCC ('a', 'v', 'c', '3'):
11340 _codec ("H.264 / AVC");
11341 caps = gst_caps_new_simple ("video/x-h264",
11342 "stream-format", G_TYPE_STRING, "avc3",
11343 "alignment", G_TYPE_STRING, "au", NULL);
11345 case GST_MAKE_FOURCC ('H', '2', '6', '5'):
11346 case GST_MAKE_FOURCC ('h', 'v', 'c', '1'):
11347 _codec ("H.265 / HEVC");
11348 caps = gst_caps_new_simple ("video/x-h265",
11349 "stream-format", G_TYPE_STRING, "hvc1",
11350 "alignment", G_TYPE_STRING, "au", NULL);
11352 case GST_MAKE_FOURCC ('h', 'e', 'v', '1'):
11353 _codec ("H.265 / HEVC");
11354 caps = gst_caps_new_simple ("video/x-h265",
11355 "stream-format", G_TYPE_STRING, "hev1",
11356 "alignment", G_TYPE_STRING, "au", NULL);
11358 case GST_MAKE_FOURCC ('r', 'l', 'e', ' '):
11359 _codec ("Run-length encoding");
11360 caps = gst_caps_new_simple ("video/x-rle",
11361 "layout", G_TYPE_STRING, "quicktime", NULL);
11363 case GST_MAKE_FOURCC ('W', 'R', 'L', 'E'):
11364 _codec ("Run-length encoding");
11365 caps = gst_caps_new_simple ("video/x-rle",
11366 "layout", G_TYPE_STRING, "microsoft", NULL);
11368 case GST_MAKE_FOURCC ('I', 'V', '3', '2'):
11369 case GST_MAKE_FOURCC ('i', 'v', '3', '2'):
11370 _codec ("Indeo Video 3");
11371 caps = gst_caps_new_simple ("video/x-indeo",
11372 "indeoversion", G_TYPE_INT, 3, NULL);
11374 case GST_MAKE_FOURCC ('I', 'V', '4', '1'):
11375 case GST_MAKE_FOURCC ('i', 'v', '4', '1'):
11376 _codec ("Intel Video 4");
11377 caps = gst_caps_new_simple ("video/x-indeo",
11378 "indeoversion", G_TYPE_INT, 4, NULL);
11380 case GST_MAKE_FOURCC ('d', 'v', 'c', 'p'):
11381 case GST_MAKE_FOURCC ('d', 'v', 'c', ' '):
11382 case GST_MAKE_FOURCC ('d', 'v', 's', 'd'):
11383 case GST_MAKE_FOURCC ('D', 'V', 'S', 'D'):
11384 case GST_MAKE_FOURCC ('d', 'v', 'c', 's'):
11385 case GST_MAKE_FOURCC ('D', 'V', 'C', 'S'):
11386 case GST_MAKE_FOURCC ('d', 'v', '2', '5'):
11387 case GST_MAKE_FOURCC ('d', 'v', 'p', 'p'):
11388 _codec ("DV Video");
11389 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 25,
11390 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
11392 case GST_MAKE_FOURCC ('d', 'v', '5', 'n'): /* DVCPRO50 NTSC */
11393 case GST_MAKE_FOURCC ('d', 'v', '5', 'p'): /* DVCPRO50 PAL */
11394 _codec ("DVCPro50 Video");
11395 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 50,
11396 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
11398 case GST_MAKE_FOURCC ('d', 'v', 'h', '5'): /* DVCPRO HD 50i produced by FCP */
11399 case GST_MAKE_FOURCC ('d', 'v', 'h', '6'): /* DVCPRO HD 60i produced by FCP */
11400 _codec ("DVCProHD Video");
11401 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 100,
11402 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
11404 case GST_MAKE_FOURCC ('s', 'm', 'c', ' '):
11405 _codec ("Apple Graphics (SMC)");
11406 caps = gst_caps_new_empty_simple ("video/x-smc");
11408 case GST_MAKE_FOURCC ('V', 'P', '3', '1'):
11410 caps = gst_caps_new_empty_simple ("video/x-vp3");
11412 case GST_MAKE_FOURCC ('V', 'P', '6', 'F'):
11413 _codec ("VP6 Flash");
11414 caps = gst_caps_new_empty_simple ("video/x-vp6-flash");
11416 case GST_MAKE_FOURCC ('X', 'i', 'T', 'h'):
11418 caps = gst_caps_new_empty_simple ("video/x-theora");
11419 /* theora uses one byte of padding in the data stream because it does not
11420 * allow 0 sized packets while theora does */
11421 stream->padding = 1;
11423 case GST_MAKE_FOURCC ('d', 'r', 'a', 'c'):
11425 caps = gst_caps_new_empty_simple ("video/x-dirac");
11427 case GST_MAKE_FOURCC ('t', 'i', 'f', 'f'):
11428 _codec ("TIFF still images");
11429 caps = gst_caps_new_empty_simple ("image/tiff");
11431 case GST_MAKE_FOURCC ('i', 'c', 'o', 'd'):
11432 _codec ("Apple Intermediate Codec");
11433 caps = gst_caps_from_string ("video/x-apple-intermediate-codec");
11435 case GST_MAKE_FOURCC ('A', 'V', 'd', 'n'):
11436 _codec ("AVID DNxHD");
11437 caps = gst_caps_from_string ("video/x-dnxhd");
11439 case GST_MAKE_FOURCC ('V', 'P', '8', '0'):
11440 _codec ("On2 VP8");
11441 caps = gst_caps_from_string ("video/x-vp8");
11443 case GST_MAKE_FOURCC ('a', 'p', 'c', 's'):
11444 _codec ("Apple ProRes LT");
11446 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "lt",
11449 case GST_MAKE_FOURCC ('a', 'p', 'c', 'h'):
11450 _codec ("Apple ProRes HQ");
11452 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "hq",
11455 case GST_MAKE_FOURCC ('a', 'p', 'c', 'n'):
11456 _codec ("Apple ProRes");
11458 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
11461 case GST_MAKE_FOURCC ('a', 'p', 'c', 'o'):
11462 _codec ("Apple ProRes Proxy");
11464 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
11467 case GST_MAKE_FOURCC ('a', 'p', '4', 'h'):
11468 _codec ("Apple ProRes 4444");
11470 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
11473 case GST_MAKE_FOURCC ('v', 'c', '-', '1'):
11476 caps = gst_caps_new_simple ("video/x-wmv",
11477 "wmvversion", G_TYPE_INT, 3, "format", G_TYPE_STRING, "WVC1", NULL);
11479 case GST_MAKE_FOURCC ('k', 'p', 'c', 'd'):
11482 char *s, fourstr[5];
11484 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
11485 s = g_strdup_printf ("video/x-gst-fourcc-%s", g_strstrip (fourstr));
11486 caps = gst_caps_new_empty_simple (s);
11491 if (format != GST_VIDEO_FORMAT_UNKNOWN) {
11494 gst_video_info_init (&info);
11495 gst_video_info_set_format (&info, format, stream->width, stream->height);
11496 caps = gst_video_info_to_caps (&info);
11497 *codec_name = gst_pb_utils_get_codec_description (caps);
11499 /* enable clipping for raw video streams */
11500 stream->need_clip = TRUE;
11507 qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
11508 guint32 fourcc, const guint8 * data, int len, gchar ** codec_name)
11511 const GstStructure *s;
11515 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
11518 case GST_MAKE_FOURCC ('N', 'O', 'N', 'E'):
11519 case GST_MAKE_FOURCC ('r', 'a', 'w', ' '):
11520 _codec ("Raw 8-bit PCM audio");
11521 caps = gst_caps_new_simple ("audio/x-raw",
11522 "format", G_TYPE_STRING, "U8",
11523 "layout", G_TYPE_STRING, "interleaved", NULL);
11525 case GST_MAKE_FOURCC ('t', 'w', 'o', 's'):
11526 endian = G_BIG_ENDIAN;
11528 case GST_MAKE_FOURCC ('s', 'o', 'w', 't'):
11532 GstAudioFormat format;
11535 endian = G_LITTLE_ENDIAN;
11537 depth = stream->bytes_per_packet * 8;
11538 format = gst_audio_format_build_integer (TRUE, endian, depth, depth);
11540 str = g_strdup_printf ("Raw %d-bit PCM audio", depth);
11544 caps = gst_caps_new_simple ("audio/x-raw",
11545 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
11546 "layout", G_TYPE_STRING, "interleaved", NULL);
11549 case GST_MAKE_FOURCC ('f', 'l', '6', '4'):
11550 _codec ("Raw 64-bit floating-point audio");
11551 caps = gst_caps_new_simple ("audio/x-raw",
11552 "format", G_TYPE_STRING, "F64BE",
11553 "layout", G_TYPE_STRING, "interleaved", NULL);
11555 case GST_MAKE_FOURCC ('f', 'l', '3', '2'):
11556 _codec ("Raw 32-bit floating-point audio");
11557 caps = gst_caps_new_simple ("audio/x-raw",
11558 "format", G_TYPE_STRING, "F32BE",
11559 "layout", G_TYPE_STRING, "interleaved", NULL);
11562 _codec ("Raw 24-bit PCM audio");
11563 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
11565 caps = gst_caps_new_simple ("audio/x-raw",
11566 "format", G_TYPE_STRING, "S24BE",
11567 "layout", G_TYPE_STRING, "interleaved", NULL);
11569 case GST_MAKE_FOURCC ('i', 'n', '3', '2'):
11570 _codec ("Raw 32-bit PCM audio");
11571 caps = gst_caps_new_simple ("audio/x-raw",
11572 "format", G_TYPE_STRING, "S32BE",
11573 "layout", G_TYPE_STRING, "interleaved", NULL);
11575 case GST_MAKE_FOURCC ('u', 'l', 'a', 'w'):
11576 _codec ("Mu-law audio");
11577 caps = gst_caps_new_empty_simple ("audio/x-mulaw");
11579 case GST_MAKE_FOURCC ('a', 'l', 'a', 'w'):
11580 _codec ("A-law audio");
11581 caps = gst_caps_new_empty_simple ("audio/x-alaw");
11585 _codec ("Microsoft ADPCM");
11586 /* Microsoft ADPCM-ACM code 2 */
11587 caps = gst_caps_new_simple ("audio/x-adpcm",
11588 "layout", G_TYPE_STRING, "microsoft", NULL);
11592 _codec ("DVI/IMA ADPCM");
11593 caps = gst_caps_new_simple ("audio/x-adpcm",
11594 "layout", G_TYPE_STRING, "dvi", NULL);
11598 _codec ("DVI/Intel IMA ADPCM");
11599 /* FIXME DVI/Intel IMA ADPCM/ACM code 17 */
11600 caps = gst_caps_new_simple ("audio/x-adpcm",
11601 "layout", G_TYPE_STRING, "quicktime", NULL);
11605 /* MPEG layer 3, CBR only (pre QT4.1) */
11606 case GST_MAKE_FOURCC ('.', 'm', 'p', '3'):
11607 _codec ("MPEG-1 layer 3");
11608 /* MPEG layer 3, CBR & VBR (QT4.1 and later) */
11609 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 3,
11610 "mpegversion", G_TYPE_INT, 1, NULL);
11613 case GST_MAKE_FOURCC ('e', 'c', '-', '3'):
11614 _codec ("EAC-3 audio");
11615 caps = gst_caps_new_simple ("audio/x-eac3",
11616 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
11617 stream->sampled = TRUE;
11619 case GST_MAKE_FOURCC ('s', 'a', 'c', '3'): // Nero Recode
11620 case GST_MAKE_FOURCC ('a', 'c', '-', '3'):
11621 _codec ("AC-3 audio");
11622 caps = gst_caps_new_simple ("audio/x-ac3",
11623 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
11624 stream->sampled = TRUE;
11626 case GST_MAKE_FOURCC ('d', 't', 's', 'c'):
11627 case GST_MAKE_FOURCC ('D', 'T', 'S', ' '):
11628 _codec ("DTS audio");
11629 caps = gst_caps_new_simple ("audio/x-dts",
11630 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
11631 stream->sampled = TRUE;
11633 case GST_MAKE_FOURCC ('d', 't', 's', 'h'): // DTS-HD
11634 case GST_MAKE_FOURCC ('d', 't', 's', 'l'): // DTS-HD Lossless
11635 _codec ("DTS-HD audio");
11636 caps = gst_caps_new_simple ("audio/x-dts",
11637 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
11638 stream->sampled = TRUE;
11640 case GST_MAKE_FOURCC ('M', 'A', 'C', '3'):
11642 caps = gst_caps_new_simple ("audio/x-mace",
11643 "maceversion", G_TYPE_INT, 3, NULL);
11645 case GST_MAKE_FOURCC ('M', 'A', 'C', '6'):
11647 caps = gst_caps_new_simple ("audio/x-mace",
11648 "maceversion", G_TYPE_INT, 6, NULL);
11650 case GST_MAKE_FOURCC ('O', 'g', 'g', 'V'):
11652 caps = gst_caps_new_empty_simple ("application/ogg");
11654 case GST_MAKE_FOURCC ('d', 'v', 'c', 'a'):
11655 _codec ("DV audio");
11656 caps = gst_caps_new_empty_simple ("audio/x-dv");
11658 case GST_MAKE_FOURCC ('m', 'p', '4', 'a'):
11659 _codec ("MPEG-4 AAC audio");
11660 caps = gst_caps_new_simple ("audio/mpeg",
11661 "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE,
11662 "stream-format", G_TYPE_STRING, "raw", NULL);
11664 case GST_MAKE_FOURCC ('Q', 'D', 'M', 'C'):
11665 _codec ("QDesign Music");
11666 caps = gst_caps_new_empty_simple ("audio/x-qdm");
11668 case GST_MAKE_FOURCC ('Q', 'D', 'M', '2'):
11669 _codec ("QDesign Music v.2");
11670 /* FIXME: QDesign music version 2 (no constant) */
11671 if (FALSE && data) {
11672 caps = gst_caps_new_simple ("audio/x-qdm2",
11673 "framesize", G_TYPE_INT, QT_UINT32 (data + 52),
11674 "bitrate", G_TYPE_INT, QT_UINT32 (data + 40),
11675 "blocksize", G_TYPE_INT, QT_UINT32 (data + 44), NULL);
11677 caps = gst_caps_new_empty_simple ("audio/x-qdm2");
11680 case GST_MAKE_FOURCC ('a', 'g', 's', 'm'):
11681 _codec ("GSM audio");
11682 caps = gst_caps_new_empty_simple ("audio/x-gsm");
11684 case GST_MAKE_FOURCC ('s', 'a', 'm', 'r'):
11685 _codec ("AMR audio");
11686 caps = gst_caps_new_empty_simple ("audio/AMR");
11688 case GST_MAKE_FOURCC ('s', 'a', 'w', 'b'):
11689 _codec ("AMR-WB audio");
11690 caps = gst_caps_new_empty_simple ("audio/AMR-WB");
11692 case GST_MAKE_FOURCC ('i', 'm', 'a', '4'):
11693 _codec ("Quicktime IMA ADPCM");
11694 caps = gst_caps_new_simple ("audio/x-adpcm",
11695 "layout", G_TYPE_STRING, "quicktime", NULL);
11697 case GST_MAKE_FOURCC ('a', 'l', 'a', 'c'):
11698 _codec ("Apple lossless audio");
11699 caps = gst_caps_new_empty_simple ("audio/x-alac");
11701 case GST_MAKE_FOURCC ('Q', 'c', 'l', 'p'):
11702 _codec ("QualComm PureVoice");
11703 caps = gst_caps_from_string ("audio/qcelp");
11705 case GST_MAKE_FOURCC ('w', 'm', 'a', ' '):
11708 caps = gst_caps_new_empty_simple ("audio/x-wma");
11710 case GST_MAKE_FOURCC ('l', 'p', 'c', 'm'):
11715 GstAudioFormat format;
11718 FLAG_IS_FLOAT = 0x1,
11719 FLAG_IS_BIG_ENDIAN = 0x2,
11720 FLAG_IS_SIGNED = 0x4,
11721 FLAG_IS_PACKED = 0x8,
11722 FLAG_IS_ALIGNED_HIGH = 0x10,
11723 FLAG_IS_NON_INTERLEAVED = 0x20
11725 _codec ("Raw LPCM audio");
11727 if (data && len >= 56) {
11728 depth = QT_UINT32 (data + 40);
11729 flags = QT_UINT32 (data + 44);
11730 width = QT_UINT32 (data + 48) * 8 / stream->n_channels;
11732 if ((flags & FLAG_IS_FLOAT) == 0) {
11737 format = gst_audio_format_build_integer ((flags & FLAG_IS_SIGNED) ?
11738 TRUE : FALSE, (flags & FLAG_IS_BIG_ENDIAN) ?
11739 G_BIG_ENDIAN : G_LITTLE_ENDIAN, width, depth);
11740 caps = gst_caps_new_simple ("audio/x-raw",
11741 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
11742 "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
11743 "non-interleaved" : "interleaved", NULL);
11748 if (flags & FLAG_IS_BIG_ENDIAN)
11749 format = GST_AUDIO_FORMAT_F64BE;
11751 format = GST_AUDIO_FORMAT_F64LE;
11753 if (flags & FLAG_IS_BIG_ENDIAN)
11754 format = GST_AUDIO_FORMAT_F32BE;
11756 format = GST_AUDIO_FORMAT_F32LE;
11758 caps = gst_caps_new_simple ("audio/x-raw",
11759 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
11760 "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
11761 "non-interleaved" : "interleaved", NULL);
11765 case GST_MAKE_FOURCC ('q', 't', 'v', 'r'):
11769 char *s, fourstr[5];
11771 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
11772 s = g_strdup_printf ("audio/x-gst-fourcc-%s", g_strstrip (fourstr));
11773 caps = gst_caps_new_empty_simple (s);
11779 GstCaps *templ_caps =
11780 gst_static_pad_template_get_caps (&gst_qtdemux_audiosrc_template);
11781 GstCaps *intersection = gst_caps_intersect (caps, templ_caps);
11782 gst_caps_unref (caps);
11783 gst_caps_unref (templ_caps);
11784 caps = intersection;
11787 /* enable clipping for raw audio streams */
11788 s = gst_caps_get_structure (caps, 0);
11789 name = gst_structure_get_name (s);
11790 if (g_str_has_prefix (name, "audio/x-raw")) {
11791 stream->need_clip = TRUE;
11792 stream->max_buffer_size = 4096 * stream->bytes_per_frame;
11793 GST_DEBUG ("setting max buffer size to %d", stream->max_buffer_size);
11799 qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
11800 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
11804 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
11807 case GST_MAKE_FOURCC ('m', 'p', '4', 's'):
11808 _codec ("DVD subtitle");
11809 caps = gst_caps_new_empty_simple ("subpicture/x-dvd");
11810 stream->need_process = TRUE;
11812 case GST_MAKE_FOURCC ('t', 'e', 'x', 't'):
11813 _codec ("Quicktime timed text");
11815 case GST_MAKE_FOURCC ('t', 'x', '3', 'g'):
11816 _codec ("3GPP timed text");
11818 caps = gst_caps_new_simple ("text/x-raw", "format", G_TYPE_STRING,
11820 /* actual text piece needs to be extracted */
11821 stream->need_process = TRUE;
11825 char *s, fourstr[5];
11827 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
11828 s = g_strdup_printf ("text/x-gst-fourcc-%s", g_strstrip (fourstr));
11829 caps = gst_caps_new_empty_simple (s);
11837 qtdemux_generic_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
11838 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
11843 case GST_MAKE_FOURCC ('m', '1', 'v', ' '):
11844 _codec ("MPEG 1 video");
11845 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
11846 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);