2 * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
3 * Copyright (C) <2003> David A. Schleef <ds@schleef.org>
4 * Copyright (C) <2006> Wim Taymans <wim@fluendo.com>
5 * Copyright (C) <2007> Julien Moutte <julien@fluendo.com>
6 * Copyright (C) <2009> Tim-Philipp Müller <tim centricular net>
7 * Copyright (C) <2009> STEricsson <benjamin.gaignard@stericsson.com>
8 * Copyright (C) <2013> Sreerenj Balachandran <sreerenj.balachandran@intel.com>
9 * Copyright (C) <2013> Intel Corporation
10 * Copyright (C) <2014> Centricular Ltd
11 * Copyright (C) <2015> YouView TV Ltd.
13 * This library is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU Library General Public
15 * License as published by the Free Software Foundation; either
16 * version 2 of the License, or (at your option) any later version.
18 * This library is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * Library General Public License for more details.
23 * You should have received a copy of the GNU Library General Public
24 * License along with this library; if not, write to the
25 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
26 * Boston, MA 02110-1301, USA.
30 * SECTION:element-qtdemux
32 * Demuxes a .mov file into raw or compressed audio and/or video streams.
34 * This element supports both push and pull-based scheduling, depending on the
35 * capabilities of the upstream elements.
38 * <title>Example launch line</title>
40 * gst-launch-1.0 filesrc location=test.mov ! qtdemux name=demux demux.audio_0 ! queue ! decodebin ! audioconvert ! audioresample ! autoaudiosink demux.video_0 ! queue ! decodebin ! videoconvert ! videoscale ! autovideosink
41 * ]| Play (parse and decode) a .mov file and try to output it to
42 * an automatically detected soundcard and videosink. If the MOV file contains
43 * compressed audio or video data, this will only work if you have the
44 * right decoder elements/plugins installed.
52 #include "gst/gst-i18n-plugin.h"
54 #include <glib/gprintf.h>
55 #include <gst/tag/tag.h>
56 #include <gst/audio/audio.h>
57 #include <gst/video/video.h>
59 #include "qtatomparser.h"
60 #include "qtdemux_types.h"
61 #include "qtdemux_dump.h"
63 #include "descriptors.h"
64 #include "qtdemux_lang.h"
66 #include "qtpalette.h"
68 #include "gst/riff/riff-media.h"
69 #include "gst/riff/riff-read.h"
71 #include <gst/pbutils/pbutils.h>
78 #include <gst/math-compat.h>
84 /* max. size considered 'sane' for non-mdat atoms */
85 #define QTDEMUX_MAX_ATOM_SIZE (25*1024*1024)
87 /* if the sample index is larger than this, something is likely wrong */
88 #define QTDEMUX_MAX_SAMPLE_INDEX_SIZE (50*1024*1024)
90 /* For converting qt creation times to unix epoch times */
91 #define QTDEMUX_SECONDS_PER_DAY (60 * 60 * 24)
92 #define QTDEMUX_LEAP_YEARS_FROM_1904_TO_1970 17
93 #define QTDEMUX_SECONDS_FROM_1904_TO_1970 (((1970 - 1904) * (guint64) 365 + \
94 QTDEMUX_LEAP_YEARS_FROM_1904_TO_1970) * QTDEMUX_SECONDS_PER_DAY)
96 #define STREAM_IS_EOS(s) (s->time_position == GST_CLOCK_TIME_NONE)
98 GST_DEBUG_CATEGORY (qtdemux_debug);
100 /*typedef struct _QtNode QtNode; */
101 typedef struct _QtDemuxSegment QtDemuxSegment;
102 typedef struct _QtDemuxSample QtDemuxSample;
104 typedef struct _QtDemuxCencSampleSetInfo QtDemuxCencSampleSetInfo;
113 struct _QtDemuxSample
116 gint32 pts_offset; /* Add this value to timestamp to get the pts */
118 guint64 timestamp; /* DTS In mov time */
119 guint32 duration; /* In mov time */
120 gboolean keyframe; /* TRUE when this packet is a keyframe */
123 /* Macros for converting to/from timescale */
124 #define QTSTREAMTIME_TO_GSTTIME(stream, value) (gst_util_uint64_scale((value), GST_SECOND, (stream)->timescale))
125 #define GSTTIME_TO_QTSTREAMTIME(stream, value) (gst_util_uint64_scale((value), (stream)->timescale, GST_SECOND))
127 #define QTTIME_TO_GSTTIME(qtdemux, value) (gst_util_uint64_scale((value), GST_SECOND, (qtdemux)->timescale))
128 #define GSTTIME_TO_QTTIME(qtdemux, value) (gst_util_uint64_scale((value), (qtdemux)->timescale, GST_SECOND))
130 /* timestamp is the DTS */
131 #define QTSAMPLE_DTS(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp))
132 /* timestamp + offset is the PTS */
133 #define QTSAMPLE_PTS(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp + (stream)->cslg_shift + (sample)->pts_offset))
134 /* timestamp + duration - dts is the duration */
135 #define QTSAMPLE_DUR_DTS(stream, sample, dts) (QTSTREAMTIME_TO_GSTTIME ((stream), (sample)->timestamp + (sample)->duration) - (dts))
137 #define QTSAMPLE_KEYFRAME(stream,sample) ((stream)->all_keyframe || (sample)->keyframe)
140 * Quicktime has tracks and segments. A track is a continuous piece of
141 * multimedia content. The track is not always played from start to finish but
142 * instead, pieces of the track are 'cut out' and played in sequence. This is
143 * what the segments do.
145 * Inside the track we have keyframes (K) and delta frames. The track has its
146 * own timing, which starts from 0 and extends to end. The position in the track
147 * is called the media_time.
149 * The segments now describe the pieces that should be played from this track
150 * and are basically tuples of media_time/duration/rate entries. We can have
151 * multiple segments and they are all played after one another. An example:
153 * segment 1: media_time: 1 second, duration: 1 second, rate 1
154 * segment 2: media_time: 3 second, duration: 2 second, rate 2
156 * To correctly play back this track, one must play: 1 second of media starting
157 * from media_time 1 followed by 2 seconds of media starting from media_time 3
160 * Each of the segments will be played at a specific time, the first segment at
161 * time 0, the second one after the duration of the first one, etc.. Note that
162 * the time in resulting playback is not identical to the media_time of the
165 * Visually, assuming the track has 4 second of media_time:
168 * .-----------------------------------------------------------.
169 * track: | K.....K.........K........K.......K.......K...........K... |
170 * '-----------------------------------------------------------'
172 * .------------^ ^ .----------^ ^
173 * / .-------------' / .------------------'
175 * .--------------. .--------------.
176 * | segment 1 | | segment 2 |
177 * '--------------' '--------------'
179 * The challenge here is to cut out the right pieces of the track for each of
180 * the playback segments. This fortunately can easily be done with the SEGMENT
181 * events of GStreamer.
183 * For playback of segment 1, we need to provide the decoder with the keyframe
184 * (a), in the above figure, but we must instruct it only to output the decoded
185 * data between second 1 and 2. We do this with a SEGMENT event for 1 to 2, time
186 * position set to the time of the segment: 0.
188 * We then proceed to push data from keyframe (a) to frame (b). The decoder
189 * decodes but clips all before media_time 1.
191 * After finishing a segment, we push out a new SEGMENT event with the clipping
192 * boundaries of the new data.
194 * This is a good usecase for the GStreamer accumulated SEGMENT events.
197 struct _QtDemuxSegment
199 /* global time and duration, all gst time */
201 GstClockTime stop_time;
202 GstClockTime duration;
203 /* media time of trak, all gst time */
204 GstClockTime media_start;
205 GstClockTime media_stop;
207 /* Media start time in trak timescale units */
208 guint32 trak_media_start;
211 #define QTSEGMENT_IS_EMPTY(s) ((s)->media_start == GST_CLOCK_TIME_NONE)
213 /* Used with fragmented MP4 files (mfra atom) */
218 } QtDemuxRandomAccessEntry;
220 struct _QtDemuxStream
231 gboolean new_stream; /* signals that a stream_start is required */
232 gboolean on_keyframe; /* if this stream last pushed buffer was a
233 * keyframe. This is important to identify
234 * where to stop pushing buffers after a
235 * segment stop time */
237 /* if the stream has a redirect URI in its headers, we store it here */
244 guint64 duration; /* in timescale */
248 gchar lang_id[4]; /* ISO 639-2T language code */
252 QtDemuxSample *samples;
253 gboolean all_keyframe; /* TRUE when all samples are keyframes (no stss) */
254 guint32 first_duration; /* duration in timescale of first sample, used for figuring out
255 the framerate, in timescale units */
256 guint32 n_samples_moof; /* sample count in a moof */
257 guint64 duration_moof; /* duration in timescale of a moof, used for figure out
258 * the framerate of fragmented format stream */
259 guint32 offset_in_sample;
260 guint32 max_buffer_size;
262 /* if we use chunks or samples */
274 /* Numerator/denominator framerate */
277 guint16 bits_per_sample;
278 guint16 color_table_id;
279 GstMemory *rgb8_palette;
284 guint samples_per_packet;
285 guint samples_per_frame;
286 guint bytes_per_packet;
287 guint bytes_per_sample;
288 guint bytes_per_frame;
292 gboolean use_allocator;
293 GstAllocator *allocator;
294 GstAllocationParams params;
296 /* when a discontinuity is pending */
299 /* list of buffers to push first */
302 /* if we need to clip this buffer. This is only needed for uncompressed
306 /* buffer needs some custom processing, e.g. subtitles */
307 gboolean need_process;
309 /* current position */
310 guint32 segment_index;
311 guint32 sample_index;
312 GstClockTime time_position; /* in gst time */
313 guint64 accumulated_base;
315 /* the Gst segment we are processing out, used for clipping */
318 /* quicktime segments */
320 QtDemuxSegment *segments;
321 gboolean dummy_segment;
326 GstTagList *pending_tags;
327 gboolean send_global_tags;
329 GstEvent *pending_event;
339 gboolean chunks_are_samples; /* TRUE means treat chunks as samples */
343 GstByteReader co_chunk;
345 guint32 current_chunk;
347 guint32 samples_per_chunk;
348 guint32 stco_sample_index;
350 guint32 sample_size; /* 0 means variable sizes are stored in stsz */
353 guint32 n_samples_per_chunk;
354 guint32 stsc_chunk_index;
355 guint32 stsc_sample_index;
356 guint64 chunk_offset;
359 guint32 stts_samples;
360 guint32 n_sample_times;
361 guint32 stts_sample_index;
363 guint32 stts_duration;
365 gboolean stss_present;
366 guint32 n_sample_syncs;
369 gboolean stps_present;
370 guint32 n_sample_partial_syncs;
372 QtDemuxRandomAccessEntry *ra_entries;
375 const QtDemuxRandomAccessEntry *pending_seek;
378 gboolean ctts_present;
379 guint32 n_composition_times;
381 guint32 ctts_sample_index;
389 gboolean parsed_trex;
390 guint32 def_sample_duration;
391 guint32 def_sample_size;
392 guint32 def_sample_flags;
396 /* stereoscopic video streams */
397 GstVideoMultiviewMode multiview_mode;
398 GstVideoMultiviewFlags multiview_flags;
400 /* protected streams */
402 guint32 protection_scheme_type;
403 guint32 protection_scheme_version;
404 gpointer protection_scheme_info; /* specific to the protection scheme */
405 GQueue protection_scheme_event_queue;
408 /* Contains properties and cryptographic info for a set of samples from a
409 * track protected using Common Encryption (cenc) */
410 struct _QtDemuxCencSampleSetInfo
412 GstStructure *default_properties;
414 /* @crypto_info holds one GstStructure per sample */
415 GPtrArray *crypto_info;
420 QTDEMUX_STATE_INITIAL, /* Initial state (haven't got the header yet) */
421 QTDEMUX_STATE_HEADER, /* Parsing the header */
422 QTDEMUX_STATE_MOVIE, /* Parsing/Playing the media data */
423 QTDEMUX_STATE_BUFFER_MDAT /* Buffering the mdat atom */
426 static GNode *qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc);
427 static GNode *qtdemux_tree_get_child_by_type_full (GNode * node,
428 guint32 fourcc, GstByteReader * parser);
429 static GNode *qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc);
430 static GNode *qtdemux_tree_get_sibling_by_type_full (GNode * node,
431 guint32 fourcc, GstByteReader * parser);
433 static GstFlowReturn qtdemux_add_fragmented_samples (GstQTDemux * qtdemux);
435 static GstStaticPadTemplate gst_qtdemux_sink_template =
436 GST_STATIC_PAD_TEMPLATE ("sink",
439 GST_STATIC_CAPS ("video/quicktime; video/mj2; audio/x-m4a; "
443 static GstStaticPadTemplate gst_qtdemux_videosrc_template =
444 GST_STATIC_PAD_TEMPLATE ("video_%u",
447 GST_STATIC_CAPS_ANY);
449 static GstStaticPadTemplate gst_qtdemux_audiosrc_template =
450 GST_STATIC_PAD_TEMPLATE ("audio_%u",
453 GST_STATIC_CAPS_ANY);
455 static GstStaticPadTemplate gst_qtdemux_subsrc_template =
456 GST_STATIC_PAD_TEMPLATE ("subtitle_%u",
459 GST_STATIC_CAPS_ANY);
461 #define gst_qtdemux_parent_class parent_class
462 G_DEFINE_TYPE (GstQTDemux, gst_qtdemux, GST_TYPE_ELEMENT);
464 static void gst_qtdemux_dispose (GObject * object);
467 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
468 GstClockTime media_time);
470 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
471 QtDemuxStream * str, gint64 media_offset);
474 static void gst_qtdemux_set_index (GstElement * element, GstIndex * index);
475 static GstIndex *gst_qtdemux_get_index (GstElement * element);
477 static GstStateChangeReturn gst_qtdemux_change_state (GstElement * element,
478 GstStateChange transition);
479 static gboolean qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent);
480 static gboolean qtdemux_sink_activate_mode (GstPad * sinkpad,
481 GstObject * parent, GstPadMode mode, gboolean active);
483 static void gst_qtdemux_loop (GstPad * pad);
484 static GstFlowReturn gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent,
486 static gboolean gst_qtdemux_handle_sink_event (GstPad * pad, GstObject * parent,
488 static gboolean gst_qtdemux_setcaps (GstQTDemux * qtdemux, GstCaps * caps);
489 static gboolean gst_qtdemux_configure_stream (GstQTDemux * qtdemux,
490 QtDemuxStream * stream);
491 static GstFlowReturn gst_qtdemux_process_adapter (GstQTDemux * demux,
494 static gboolean qtdemux_parse_moov (GstQTDemux * qtdemux,
495 const guint8 * buffer, guint length);
496 static gboolean qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node,
497 const guint8 * buffer, guint length);
498 static gboolean qtdemux_parse_tree (GstQTDemux * qtdemux);
499 static void qtdemux_parse_udta (GstQTDemux * qtdemux, GstTagList * taglist,
502 static void gst_qtdemux_handle_esds (GstQTDemux * qtdemux,
503 QtDemuxStream * stream, GNode * esds, GstTagList * list);
504 static GstCaps *qtdemux_video_caps (GstQTDemux * qtdemux,
505 QtDemuxStream * stream, guint32 fourcc, const guint8 * stsd_data,
506 gchar ** codec_name);
507 static GstCaps *qtdemux_audio_caps (GstQTDemux * qtdemux,
508 QtDemuxStream * stream, guint32 fourcc, const guint8 * data, int len,
509 gchar ** codec_name);
510 static GstCaps *qtdemux_sub_caps (GstQTDemux * qtdemux,
511 QtDemuxStream * stream, guint32 fourcc, const guint8 * data,
512 gchar ** codec_name);
513 static GstCaps *qtdemux_generic_caps (GstQTDemux * qtdemux,
514 QtDemuxStream * stream, guint32 fourcc, const guint8 * stsd_data,
515 gchar ** codec_name);
517 static gboolean qtdemux_parse_samples (GstQTDemux * qtdemux,
518 QtDemuxStream * stream, guint32 n);
519 static GstFlowReturn qtdemux_expose_streams (GstQTDemux * qtdemux);
520 static void gst_qtdemux_stream_free (GstQTDemux * qtdemux,
521 QtDemuxStream * stream);
522 static void gst_qtdemux_stream_clear (GstQTDemux * qtdemux,
523 QtDemuxStream * stream);
524 static void gst_qtdemux_remove_stream (GstQTDemux * qtdemux, int index);
525 static GstFlowReturn qtdemux_prepare_streams (GstQTDemux * qtdemux);
526 static void qtdemux_do_allocation (GstQTDemux * qtdemux,
527 QtDemuxStream * stream);
528 static gboolean gst_qtdemux_activate_segment (GstQTDemux * qtdemux,
529 QtDemuxStream * stream, guint32 seg_idx, GstClockTime offset);
530 static gboolean gst_qtdemux_stream_update_segment (GstQTDemux * qtdemux,
531 QtDemuxStream * stream, gint seg_idx, GstClockTime offset,
532 GstClockTime * _start, GstClockTime * _stop);
533 static void gst_qtdemux_send_gap_for_segment (GstQTDemux * demux,
534 QtDemuxStream * stream, gint segment_index, GstClockTime pos);
536 static gboolean qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux);
537 static void check_update_duration (GstQTDemux * qtdemux, GstClockTime duration);
539 static gchar *qtdemux_uuid_bytes_to_string (gconstpointer uuid_bytes);
541 static GstStructure *qtdemux_get_cenc_sample_properties (GstQTDemux * qtdemux,
542 QtDemuxStream * stream, guint sample_index);
543 static void gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux,
545 static void qtdemux_gst_structure_free (GstStructure * gststructure);
548 gst_qtdemux_class_init (GstQTDemuxClass * klass)
550 GObjectClass *gobject_class;
551 GstElementClass *gstelement_class;
553 gobject_class = (GObjectClass *) klass;
554 gstelement_class = (GstElementClass *) klass;
556 parent_class = g_type_class_peek_parent (klass);
558 gobject_class->dispose = gst_qtdemux_dispose;
560 gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_qtdemux_change_state);
562 gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_qtdemux_set_index);
563 gstelement_class->get_index = GST_DEBUG_FUNCPTR (gst_qtdemux_get_index);
566 gst_tag_register_musicbrainz_tags ();
568 gst_element_class_add_static_pad_template (gstelement_class,
569 &gst_qtdemux_sink_template);
570 gst_element_class_add_static_pad_template (gstelement_class,
571 &gst_qtdemux_videosrc_template);
572 gst_element_class_add_static_pad_template (gstelement_class,
573 &gst_qtdemux_audiosrc_template);
574 gst_element_class_add_static_pad_template (gstelement_class,
575 &gst_qtdemux_subsrc_template);
576 gst_element_class_set_static_metadata (gstelement_class, "QuickTime demuxer",
578 "Demultiplex a QuickTime file into audio and video streams",
579 "David Schleef <ds@schleef.org>, Wim Taymans <wim@fluendo.com>");
581 GST_DEBUG_CATEGORY_INIT (qtdemux_debug, "qtdemux", 0, "qtdemux plugin");
586 gst_qtdemux_init (GstQTDemux * qtdemux)
589 gst_pad_new_from_static_template (&gst_qtdemux_sink_template, "sink");
590 gst_pad_set_activate_function (qtdemux->sinkpad, qtdemux_sink_activate);
591 gst_pad_set_activatemode_function (qtdemux->sinkpad,
592 qtdemux_sink_activate_mode);
593 gst_pad_set_chain_function (qtdemux->sinkpad, gst_qtdemux_chain);
594 gst_pad_set_event_function (qtdemux->sinkpad, gst_qtdemux_handle_sink_event);
595 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), qtdemux->sinkpad);
597 qtdemux->state = QTDEMUX_STATE_INITIAL;
598 qtdemux->pullbased = FALSE;
599 qtdemux->posted_redirect = FALSE;
600 qtdemux->neededbytes = 16;
602 qtdemux->adapter = gst_adapter_new ();
604 qtdemux->first_mdat = -1;
605 qtdemux->got_moov = FALSE;
606 qtdemux->mdatoffset = -1;
607 qtdemux->mdatbuffer = NULL;
608 qtdemux->restoredata_buffer = NULL;
609 qtdemux->restoredata_offset = -1;
610 qtdemux->fragment_start = -1;
611 qtdemux->fragment_start_offset = -1;
612 qtdemux->media_caps = NULL;
613 qtdemux->exposed = FALSE;
614 qtdemux->mss_mode = FALSE;
615 qtdemux->pending_newsegment = NULL;
616 qtdemux->upstream_format_is_time = FALSE;
617 qtdemux->have_group_id = FALSE;
618 qtdemux->group_id = G_MAXUINT;
619 qtdemux->cenc_aux_info_offset = 0;
620 qtdemux->cenc_aux_info_sizes = NULL;
621 qtdemux->cenc_aux_sample_count = 0;
622 qtdemux->protection_system_ids = NULL;
623 g_queue_init (&qtdemux->protection_event_queue);
624 gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
625 qtdemux->flowcombiner = gst_flow_combiner_new ();
627 GST_OBJECT_FLAG_SET (qtdemux, GST_ELEMENT_FLAG_INDEXABLE);
631 gst_qtdemux_dispose (GObject * object)
633 GstQTDemux *qtdemux = GST_QTDEMUX (object);
635 if (qtdemux->adapter) {
636 g_object_unref (G_OBJECT (qtdemux->adapter));
637 qtdemux->adapter = NULL;
639 gst_flow_combiner_free (qtdemux->flowcombiner);
640 g_queue_foreach (&qtdemux->protection_event_queue, (GFunc) gst_event_unref,
642 g_queue_clear (&qtdemux->protection_event_queue);
644 g_free (qtdemux->cenc_aux_info_sizes);
645 qtdemux->cenc_aux_info_sizes = NULL;
647 G_OBJECT_CLASS (parent_class)->dispose (object);
651 gst_qtdemux_post_no_playable_stream_error (GstQTDemux * qtdemux)
653 if (qtdemux->posted_redirect) {
654 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
655 (_("This file contains no playable streams.")),
656 ("no known streams found, a redirect message has been posted"));
658 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
659 (_("This file contains no playable streams.")),
660 ("no known streams found"));
665 _gst_buffer_new_wrapped (gpointer mem, gsize size, GFreeFunc free_func)
667 return gst_buffer_new_wrapped_full (free_func ? 0 : GST_MEMORY_FLAG_READONLY,
668 mem, size, 0, size, mem, free_func);
672 gst_qtdemux_pull_atom (GstQTDemux * qtdemux, guint64 offset, guint64 size,
679 if (G_UNLIKELY (size == 0)) {
681 GstBuffer *tmp = NULL;
683 ret = gst_qtdemux_pull_atom (qtdemux, offset, sizeof (guint32), &tmp);
684 if (ret != GST_FLOW_OK)
687 gst_buffer_map (tmp, &map, GST_MAP_READ);
688 size = QT_UINT32 (map.data);
689 GST_DEBUG_OBJECT (qtdemux, "size 0x%08" G_GINT64_MODIFIER "x", size);
691 gst_buffer_unmap (tmp, &map);
692 gst_buffer_unref (tmp);
695 /* Sanity check: catch bogus sizes (fuzzed/broken files) */
696 if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
697 if (qtdemux->state != QTDEMUX_STATE_MOVIE && qtdemux->got_moov) {
698 /* we're pulling header but already got most interesting bits,
699 * so never mind the rest (e.g. tags) (that much) */
700 GST_WARNING_OBJECT (qtdemux, "atom has bogus size %" G_GUINT64_FORMAT,
704 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
705 (_("This file is invalid and cannot be played.")),
706 ("atom has bogus size %" G_GUINT64_FORMAT, size));
707 return GST_FLOW_ERROR;
711 flow = gst_pad_pull_range (qtdemux->sinkpad, offset, size, buf);
713 if (G_UNLIKELY (flow != GST_FLOW_OK))
716 bsize = gst_buffer_get_size (*buf);
717 /* Catch short reads - we don't want any partial atoms */
718 if (G_UNLIKELY (bsize < size)) {
719 GST_WARNING_OBJECT (qtdemux,
720 "short read: %" G_GSIZE_FORMAT " < %" G_GUINT64_FORMAT, bsize, size);
721 gst_buffer_unref (*buf);
731 gst_qtdemux_src_convert (GstQTDemux * qtdemux, GstPad * pad,
732 GstFormat src_format, gint64 src_value, GstFormat dest_format,
736 QtDemuxStream *stream = gst_pad_get_element_private (pad);
739 if (stream->subtype != FOURCC_vide) {
744 switch (src_format) {
745 case GST_FORMAT_TIME:
746 switch (dest_format) {
747 case GST_FORMAT_BYTES:{
748 index = gst_qtdemux_find_index_linear (qtdemux, stream, src_value);
754 *dest_value = stream->samples[index].offset;
756 GST_DEBUG_OBJECT (qtdemux, "Format Conversion Time->Offset :%"
757 GST_TIME_FORMAT "->%" G_GUINT64_FORMAT,
758 GST_TIME_ARGS (src_value), *dest_value);
766 case GST_FORMAT_BYTES:
767 switch (dest_format) {
768 case GST_FORMAT_TIME:{
770 gst_qtdemux_find_index_for_given_media_offset_linear (qtdemux,
779 QTSTREAMTIME_TO_GSTTIME (stream,
780 stream->samples[index].timestamp);
781 GST_DEBUG_OBJECT (qtdemux,
782 "Format Conversion Offset->Time :%" G_GUINT64_FORMAT "->%"
783 GST_TIME_FORMAT, src_value, GST_TIME_ARGS (*dest_value));
802 gst_qtdemux_get_duration (GstQTDemux * qtdemux, GstClockTime * duration)
804 gboolean res = FALSE;
806 *duration = GST_CLOCK_TIME_NONE;
808 if (qtdemux->duration != 0 &&
809 qtdemux->duration != G_MAXINT64 && qtdemux->timescale != 0) {
810 *duration = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
813 *duration = GST_CLOCK_TIME_NONE;
820 gst_qtdemux_handle_src_query (GstPad * pad, GstObject * parent,
823 gboolean res = FALSE;
824 GstQTDemux *qtdemux = GST_QTDEMUX (parent);
826 GST_LOG_OBJECT (pad, "%s query", GST_QUERY_TYPE_NAME (query));
828 switch (GST_QUERY_TYPE (query)) {
829 case GST_QUERY_POSITION:{
832 gst_query_parse_position (query, &fmt, NULL);
833 if (fmt == GST_FORMAT_TIME
834 && GST_CLOCK_TIME_IS_VALID (qtdemux->segment.position)) {
835 gst_query_set_position (query, GST_FORMAT_TIME,
836 qtdemux->segment.position);
841 case GST_QUERY_DURATION:{
844 gst_query_parse_duration (query, &fmt, NULL);
845 if (fmt == GST_FORMAT_TIME) {
846 /* First try to query upstream */
847 res = gst_pad_query_default (pad, parent, query);
849 GstClockTime duration;
850 if (gst_qtdemux_get_duration (qtdemux, &duration) && duration > 0) {
851 gst_query_set_duration (query, GST_FORMAT_TIME, duration);
858 case GST_QUERY_CONVERT:{
859 GstFormat src_fmt, dest_fmt;
860 gint64 src_value, dest_value = 0;
862 gst_query_parse_convert (query, &src_fmt, &src_value, &dest_fmt, NULL);
864 res = gst_qtdemux_src_convert (qtdemux, pad,
865 src_fmt, src_value, dest_fmt, &dest_value);
867 gst_query_set_convert (query, src_fmt, src_value, dest_fmt, dest_value);
872 case GST_QUERY_FORMATS:
873 gst_query_set_formats (query, 2, GST_FORMAT_TIME, GST_FORMAT_BYTES);
876 case GST_QUERY_SEEKING:{
880 /* try upstream first */
881 res = gst_pad_query_default (pad, parent, query);
884 gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
885 if (fmt == GST_FORMAT_TIME) {
886 GstClockTime duration;
888 gst_qtdemux_get_duration (qtdemux, &duration);
890 if (!qtdemux->pullbased) {
893 /* we might be able with help from upstream */
895 q = gst_query_new_seeking (GST_FORMAT_BYTES);
896 if (gst_pad_peer_query (qtdemux->sinkpad, q)) {
897 gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL);
898 GST_LOG_OBJECT (qtdemux, "upstream BYTE seekable %d", seekable);
902 gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0, duration);
908 case GST_QUERY_SEGMENT:
913 format = qtdemux->segment.format;
916 gst_segment_to_stream_time (&qtdemux->segment, format,
917 qtdemux->segment.start);
918 if ((stop = qtdemux->segment.stop) == -1)
919 stop = qtdemux->segment.duration;
921 stop = gst_segment_to_stream_time (&qtdemux->segment, format, stop);
923 gst_query_set_segment (query, qtdemux->segment.rate, format, start, stop);
928 res = gst_pad_query_default (pad, parent, query);
936 gst_qtdemux_push_tags (GstQTDemux * qtdemux, QtDemuxStream * stream)
938 if (G_LIKELY (stream->pad)) {
939 GST_DEBUG_OBJECT (qtdemux, "Checking pad %s:%s for tags",
940 GST_DEBUG_PAD_NAME (stream->pad));
942 if (G_UNLIKELY (stream->pending_tags)) {
943 GST_DEBUG_OBJECT (qtdemux, "Sending tags %" GST_PTR_FORMAT,
944 stream->pending_tags);
945 gst_pad_push_event (stream->pad,
946 gst_event_new_tag (stream->pending_tags));
947 stream->pending_tags = NULL;
950 if (G_UNLIKELY (stream->send_global_tags && qtdemux->tag_list)) {
951 GST_DEBUG_OBJECT (qtdemux, "Sending global tags %" GST_PTR_FORMAT,
953 gst_pad_push_event (stream->pad,
954 gst_event_new_tag (gst_tag_list_ref (qtdemux->tag_list)));
955 stream->send_global_tags = FALSE;
960 /* push event on all source pads; takes ownership of the event */
962 gst_qtdemux_push_event (GstQTDemux * qtdemux, GstEvent * event)
965 gboolean has_valid_stream = FALSE;
966 GstEventType etype = GST_EVENT_TYPE (event);
968 GST_DEBUG_OBJECT (qtdemux, "pushing %s event on all source pads",
969 GST_EVENT_TYPE_NAME (event));
971 for (n = 0; n < qtdemux->n_streams; n++) {
973 QtDemuxStream *stream = qtdemux->streams[n];
974 GST_DEBUG_OBJECT (qtdemux, "pushing on pad %i", n);
976 if ((pad = stream->pad)) {
977 has_valid_stream = TRUE;
979 if (etype == GST_EVENT_EOS) {
980 /* let's not send twice */
981 if (stream->sent_eos)
983 stream->sent_eos = TRUE;
986 gst_pad_push_event (pad, gst_event_ref (event));
990 gst_event_unref (event);
992 /* if it is EOS and there are no pads, post an error */
993 if (!has_valid_stream && etype == GST_EVENT_EOS) {
994 gst_qtdemux_post_no_playable_stream_error (qtdemux);
998 /* push a pending newsegment event, if any from the streaming thread */
1000 gst_qtdemux_push_pending_newsegment (GstQTDemux * qtdemux)
1002 if (qtdemux->pending_newsegment) {
1003 gst_qtdemux_push_event (qtdemux, qtdemux->pending_newsegment);
1004 qtdemux->pending_newsegment = NULL;
1014 find_func (QtDemuxSample * s1, gint64 * media_time, gpointer user_data)
1016 if ((gint64) s1->timestamp + s1->pts_offset > *media_time)
1018 if ((gint64) s1->timestamp + s1->pts_offset == *media_time)
1024 /* find the index of the sample that includes the data for @media_time using a
1025 * binary search. Only to be called in optimized cases of linear search below.
1027 * Returns the index of the sample.
1030 gst_qtdemux_find_index (GstQTDemux * qtdemux, QtDemuxStream * str,
1033 QtDemuxSample *result;
1036 /* convert media_time to mov format */
1038 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
1040 result = gst_util_array_binary_search (str->samples, str->stbl_index + 1,
1041 sizeof (QtDemuxSample), (GCompareDataFunc) find_func,
1042 GST_SEARCH_MODE_BEFORE, &media_time, NULL);
1044 if (G_LIKELY (result))
1045 index = result - str->samples;
1054 /* find the index of the sample that includes the data for @media_offset using a
1057 * Returns the index of the sample.
1060 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
1061 QtDemuxStream * str, gint64 media_offset)
1063 QtDemuxSample *result = str->samples;
1066 if (result == NULL || str->n_samples == 0)
1069 if (media_offset == result->offset)
1073 while (index < str->n_samples - 1) {
1074 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
1077 if (media_offset < result->offset)
1088 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
1093 /* find the index of the sample that includes the data for @media_time using a
1094 * linear search, and keeping in mind that not all samples may have been parsed
1095 * yet. If possible, it will delegate to binary search.
1097 * Returns the index of the sample.
1100 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
1101 GstClockTime media_time)
1105 QtDemuxSample *sample;
1107 /* convert media_time to mov format */
1109 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
1111 sample = str->samples;
1112 if (mov_time == sample->timestamp + sample->pts_offset)
1115 /* use faster search if requested time in already parsed range */
1116 sample = str->samples + str->stbl_index;
1117 if (str->stbl_index >= 0 &&
1118 mov_time <= (sample->timestamp + sample->pts_offset))
1119 return gst_qtdemux_find_index (qtdemux, str, media_time);
1121 while (index < str->n_samples - 1) {
1122 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
1125 sample = str->samples + index + 1;
1126 if (mov_time < (sample->timestamp + sample->pts_offset))
1136 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
1141 /* find the index of the keyframe needed to decode the sample at @index
1144 * Returns the index of the keyframe.
1147 gst_qtdemux_find_keyframe (GstQTDemux * qtdemux, QtDemuxStream * str,
1150 guint32 new_index = index;
1152 if (index >= str->n_samples) {
1153 new_index = str->n_samples;
1157 /* all keyframes, return index */
1158 if (str->all_keyframe) {
1163 /* else go back until we have a keyframe */
1165 if (str->samples[new_index].keyframe)
1175 GST_DEBUG_OBJECT (qtdemux, "searching for keyframe index before index %u "
1176 "gave %u", index, new_index);
1181 /* find the segment for @time_position for @stream
1183 * Returns the index of the segment containing @time_position.
1184 * Returns the last segment and sets the @eos variable to TRUE
1185 * if the time is beyond the end. @eos may be NULL
1188 gst_qtdemux_find_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
1189 GstClockTime time_position)
1194 GST_LOG_OBJECT (stream->pad, "finding segment for %" GST_TIME_FORMAT,
1195 GST_TIME_ARGS (time_position));
1198 for (i = 0; i < stream->n_segments; i++) {
1199 QtDemuxSegment *segment = &stream->segments[i];
1201 GST_LOG_OBJECT (stream->pad,
1202 "looking at segment %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT,
1203 GST_TIME_ARGS (segment->time), GST_TIME_ARGS (segment->stop_time));
1205 /* For the last segment we include stop_time in the last segment */
1206 if (i < stream->n_segments - 1) {
1207 if (segment->time <= time_position && time_position < segment->stop_time) {
1208 GST_LOG_OBJECT (stream->pad, "segment %d matches", i);
1213 /* Last segment always matches */
1221 /* move the stream @str to the sample position @index.
1223 * Updates @str->sample_index and marks discontinuity if needed.
1226 gst_qtdemux_move_stream (GstQTDemux * qtdemux, QtDemuxStream * str,
1229 /* no change needed */
1230 if (index == str->sample_index)
1233 GST_DEBUG_OBJECT (qtdemux, "moving to sample %u of %u", index,
1236 /* position changed, we have a discont */
1237 str->sample_index = index;
1238 str->offset_in_sample = 0;
1239 /* Each time we move in the stream we store the position where we are
1241 str->from_sample = index;
1242 str->discont = TRUE;
1246 gst_qtdemux_adjust_seek (GstQTDemux * qtdemux, gint64 desired_time,
1247 gboolean use_sparse, gint64 * key_time, gint64 * key_offset)
1250 gint64 min_byte_offset = -1;
1253 min_offset = desired_time;
1255 /* for each stream, find the index of the sample in the segment
1256 * and move back to the previous keyframe. */
1257 for (n = 0; n < qtdemux->n_streams; n++) {
1259 guint32 index, kindex;
1261 GstClockTime media_start;
1262 GstClockTime media_time;
1263 GstClockTime seg_time;
1264 QtDemuxSegment *seg;
1265 gboolean empty_segment = FALSE;
1267 str = qtdemux->streams[n];
1269 if (str->sparse && !use_sparse)
1272 seg_idx = gst_qtdemux_find_segment (qtdemux, str, desired_time);
1273 GST_DEBUG_OBJECT (qtdemux, "align segment %d", seg_idx);
1275 /* get segment and time in the segment */
1276 seg = &str->segments[seg_idx];
1277 seg_time = (desired_time - seg->time) * seg->rate;
1279 while (QTSEGMENT_IS_EMPTY (seg)) {
1281 empty_segment = TRUE;
1282 GST_DEBUG_OBJECT (str->pad, "Segment %d is empty, moving to next one",
1285 if (seg_idx == str->n_segments)
1287 seg = &str->segments[seg_idx];
1290 if (seg_idx == str->n_segments) {
1291 /* FIXME track shouldn't have the last segment as empty, but if it
1292 * happens we better handle it */
1296 /* get the media time in the segment */
1297 media_start = seg->media_start + seg_time;
1299 /* get the index of the sample with media time */
1300 index = gst_qtdemux_find_index_linear (qtdemux, str, media_start);
1301 GST_DEBUG_OBJECT (qtdemux, "sample for %" GST_TIME_FORMAT " at %u"
1302 " at offset %" G_GUINT64_FORMAT " (empty segment: %d)",
1303 GST_TIME_ARGS (media_start), index, str->samples[index].offset,
1306 if (!empty_segment) {
1307 /* find previous keyframe */
1308 kindex = gst_qtdemux_find_keyframe (qtdemux, str, index);
1310 /* if the keyframe is at a different position, we need to update the
1311 * requested seek time */
1312 if (index != kindex) {
1315 /* get timestamp of keyframe */
1316 media_time = QTSAMPLE_DTS (str, &str->samples[kindex]);
1317 GST_DEBUG_OBJECT (qtdemux,
1318 "keyframe at %u with time %" GST_TIME_FORMAT " at offset %"
1319 G_GUINT64_FORMAT, kindex, GST_TIME_ARGS (media_time),
1320 str->samples[kindex].offset);
1322 /* keyframes in the segment get a chance to change the
1323 * desired_offset. keyframes out of the segment are
1325 if (media_time >= seg->media_start) {
1326 GstClockTime seg_time;
1328 /* this keyframe is inside the segment, convert back to
1330 seg_time = (media_time - seg->media_start) + seg->time;
1331 if (seg_time < min_offset)
1332 min_offset = seg_time;
1337 if (min_byte_offset < 0 || str->samples[index].offset < min_byte_offset)
1338 min_byte_offset = str->samples[index].offset;
1342 *key_time = min_offset;
1344 *key_offset = min_byte_offset;
1348 gst_qtdemux_convert_seek (GstPad * pad, GstFormat * format,
1349 GstSeekType cur_type, gint64 * cur, GstSeekType stop_type, gint64 * stop)
1353 g_return_val_if_fail (format != NULL, FALSE);
1354 g_return_val_if_fail (cur != NULL, FALSE);
1355 g_return_val_if_fail (stop != NULL, FALSE);
1357 if (*format == GST_FORMAT_TIME)
1361 if (cur_type != GST_SEEK_TYPE_NONE)
1362 res = gst_pad_query_convert (pad, *format, *cur, GST_FORMAT_TIME, cur);
1363 if (res && stop_type != GST_SEEK_TYPE_NONE)
1364 res = gst_pad_query_convert (pad, *format, *stop, GST_FORMAT_TIME, stop);
1367 *format = GST_FORMAT_TIME;
1372 /* perform seek in push based mode:
1373 find BYTE position to move to based on time and delegate to upstream
1376 gst_qtdemux_do_push_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1381 GstSeekType cur_type, stop_type;
1382 gint64 cur, stop, key_cur;
1385 gint64 original_stop;
1388 GST_DEBUG_OBJECT (qtdemux, "doing push-based seek");
1390 gst_event_parse_seek (event, &rate, &format, &flags,
1391 &cur_type, &cur, &stop_type, &stop);
1392 seqnum = gst_event_get_seqnum (event);
1394 /* only forward streaming and seeking is possible */
1396 goto unsupported_seek;
1398 /* convert to TIME if needed and possible */
1399 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1403 /* Upstream seek in bytes will have undefined stop, but qtdemux stores
1404 * the original stop position to use when upstream pushes the new segment
1406 original_stop = stop;
1409 /* find reasonable corresponding BYTE position,
1410 * also try to mind about keyframes, since we can not go back a bit for them
1412 gst_qtdemux_adjust_seek (qtdemux, cur, FALSE, &key_cur, &byte_cur);
1417 GST_DEBUG_OBJECT (qtdemux, "Pushing BYTE seek rate %g, "
1418 "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, byte_cur,
1421 GST_OBJECT_LOCK (qtdemux);
1422 qtdemux->seek_offset = byte_cur;
1423 if (!(flags & GST_SEEK_FLAG_KEY_UNIT)) {
1424 qtdemux->push_seek_start = cur;
1426 qtdemux->push_seek_start = key_cur;
1429 if (stop_type == GST_SEEK_TYPE_NONE) {
1430 qtdemux->push_seek_stop = qtdemux->segment.stop;
1432 qtdemux->push_seek_stop = original_stop;
1434 GST_OBJECT_UNLOCK (qtdemux);
1436 /* BYTE seek event */
1437 event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type, byte_cur,
1439 gst_event_set_seqnum (event, seqnum);
1440 res = gst_pad_push_event (qtdemux->sinkpad, event);
1447 GST_DEBUG_OBJECT (qtdemux, "could not determine byte position to seek to, "
1453 GST_DEBUG_OBJECT (qtdemux, "unsupported seek, seek aborted.");
1458 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1463 /* perform the seek.
1465 * We set all segment_indexes in the streams to unknown and
1466 * adjust the time_position to the desired position. this is enough
1467 * to trigger a segment switch in the streaming thread to start
1468 * streaming from the desired position.
1470 * Keyframe seeking is a little more complicated when dealing with
1471 * segments. Ideally we want to move to the previous keyframe in
1472 * the segment but there might not be a keyframe in the segment. In
1473 * fact, none of the segments could contain a keyframe. We take a
1474 * practical approach: seek to the previous keyframe in the segment,
1475 * if there is none, seek to the beginning of the segment.
1477 * Called with STREAM_LOCK
1480 gst_qtdemux_perform_seek (GstQTDemux * qtdemux, GstSegment * segment,
1481 guint32 seqnum, GstSeekFlags flags)
1483 gint64 desired_offset;
1486 desired_offset = segment->position;
1488 GST_DEBUG_OBJECT (qtdemux, "seeking to %" GST_TIME_FORMAT,
1489 GST_TIME_ARGS (desired_offset));
1491 /* may not have enough fragmented info to do this adjustment,
1492 * and we can't scan (and probably should not) at this time with
1493 * possibly flushing upstream */
1494 if ((flags & GST_SEEK_FLAG_KEY_UNIT) && !qtdemux->fragmented) {
1497 gst_qtdemux_adjust_seek (qtdemux, desired_offset, TRUE, &min_offset, NULL);
1498 GST_DEBUG_OBJECT (qtdemux, "keyframe seek, align to %"
1499 GST_TIME_FORMAT, GST_TIME_ARGS (min_offset));
1500 desired_offset = min_offset;
1503 /* and set all streams to the final position */
1504 gst_flow_combiner_reset (qtdemux->flowcombiner);
1505 qtdemux->segment_seqnum = seqnum;
1506 for (n = 0; n < qtdemux->n_streams; n++) {
1507 QtDemuxStream *stream = qtdemux->streams[n];
1509 stream->time_position = desired_offset;
1510 stream->accumulated_base = 0;
1511 stream->sample_index = -1;
1512 stream->offset_in_sample = 0;
1513 stream->segment_index = -1;
1514 stream->sent_eos = FALSE;
1516 if (segment->flags & GST_SEEK_FLAG_FLUSH)
1517 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
1519 segment->position = desired_offset;
1520 segment->time = desired_offset;
1521 if (segment->rate >= 0) {
1522 segment->start = desired_offset;
1524 /* we stop at the end */
1525 if (segment->stop == -1)
1526 segment->stop = segment->duration;
1528 segment->stop = desired_offset;
1531 if (qtdemux->fragmented)
1532 qtdemux->fragmented_seek_pending = TRUE;
1537 /* do a seek in pull based mode */
1539 gst_qtdemux_do_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1544 GstSeekType cur_type, stop_type;
1548 GstSegment seeksegment;
1550 GstEvent *flush_event;
1553 GST_DEBUG_OBJECT (qtdemux, "doing seek with event");
1555 gst_event_parse_seek (event, &rate, &format, &flags,
1556 &cur_type, &cur, &stop_type, &stop);
1557 seqnum = gst_event_get_seqnum (event);
1559 /* we have to have a format as the segment format. Try to convert
1561 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1565 GST_DEBUG_OBJECT (qtdemux, "seek format %s", gst_format_get_name (format));
1567 GST_DEBUG_OBJECT (qtdemux, "doing seek without event");
1571 flush = flags & GST_SEEK_FLAG_FLUSH;
1573 /* stop streaming, either by flushing or by pausing the task */
1575 flush_event = gst_event_new_flush_start ();
1577 gst_event_set_seqnum (flush_event, seqnum);
1578 /* unlock upstream pull_range */
1579 gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event));
1580 /* make sure out loop function exits */
1581 gst_qtdemux_push_event (qtdemux, flush_event);
1583 /* non flushing seek, pause the task */
1584 gst_pad_pause_task (qtdemux->sinkpad);
1587 /* wait for streaming to finish */
1588 GST_PAD_STREAM_LOCK (qtdemux->sinkpad);
1590 /* copy segment, we need this because we still need the old
1591 * segment when we close the current segment. */
1592 memcpy (&seeksegment, &qtdemux->segment, sizeof (GstSegment));
1595 /* configure the segment with the seek variables */
1596 GST_DEBUG_OBJECT (qtdemux, "configuring seek");
1597 gst_segment_do_seek (&seeksegment, rate, format, flags,
1598 cur_type, cur, stop_type, stop, &update);
1601 /* now do the seek, this actually never returns FALSE */
1602 gst_qtdemux_perform_seek (qtdemux, &seeksegment, seqnum, flags);
1604 /* prepare for streaming again */
1606 flush_event = gst_event_new_flush_stop (TRUE);
1608 gst_event_set_seqnum (flush_event, seqnum);
1610 gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event));
1611 gst_qtdemux_push_event (qtdemux, flush_event);
1614 /* commit the new segment */
1615 memcpy (&qtdemux->segment, &seeksegment, sizeof (GstSegment));
1617 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
1618 GstMessage *msg = gst_message_new_segment_start (GST_OBJECT_CAST (qtdemux),
1619 qtdemux->segment.format, qtdemux->segment.position);
1621 gst_message_set_seqnum (msg, seqnum);
1622 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
1625 /* restart streaming, NEWSEGMENT will be sent from the streaming thread. */
1626 gst_pad_start_task (qtdemux->sinkpad, (GstTaskFunction) gst_qtdemux_loop,
1627 qtdemux->sinkpad, NULL);
1629 GST_PAD_STREAM_UNLOCK (qtdemux->sinkpad);
1636 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1642 qtdemux_ensure_index (GstQTDemux * qtdemux)
1646 GST_DEBUG_OBJECT (qtdemux, "collecting all metadata for all streams");
1648 /* Build complete index */
1649 for (i = 0; i < qtdemux->n_streams; i++) {
1650 QtDemuxStream *stream = qtdemux->streams[i];
1652 if (!qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1))
1660 GST_LOG_OBJECT (qtdemux,
1661 "Building complete index of stream %u for seeking failed!", i);
1667 gst_qtdemux_handle_src_event (GstPad * pad, GstObject * parent,
1670 gboolean res = TRUE;
1671 GstQTDemux *qtdemux = GST_QTDEMUX (parent);
1673 switch (GST_EVENT_TYPE (event)) {
1674 case GST_EVENT_SEEK:
1676 #ifndef GST_DISABLE_GST_DEBUG
1677 GstClockTime ts = gst_util_get_timestamp ();
1680 if (qtdemux->upstream_format_is_time && qtdemux->fragmented) {
1681 /* seek should be handled by upstream, we might need to re-download fragments */
1682 GST_DEBUG_OBJECT (qtdemux,
1683 "let upstream handle seek for fragmented playback");
1687 /* Build complete index for seeking;
1688 * if not a fragmented file at least */
1689 if (!qtdemux->fragmented)
1690 if (!qtdemux_ensure_index (qtdemux))
1692 #ifndef GST_DISABLE_GST_DEBUG
1693 ts = gst_util_get_timestamp () - ts;
1694 GST_INFO_OBJECT (qtdemux,
1695 "Time taken to parse index %" GST_TIME_FORMAT, GST_TIME_ARGS (ts));
1698 if (qtdemux->pullbased) {
1699 res = gst_qtdemux_do_seek (qtdemux, pad, event);
1700 } else if (gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (event))) {
1701 GST_DEBUG_OBJECT (qtdemux, "Upstream successfully seeked");
1703 } else if (qtdemux->state == QTDEMUX_STATE_MOVIE && qtdemux->n_streams
1704 && !qtdemux->fragmented) {
1705 res = gst_qtdemux_do_push_seek (qtdemux, pad, event);
1707 GST_DEBUG_OBJECT (qtdemux,
1708 "ignoring seek in push mode in current state");
1711 gst_event_unref (event);
1714 case GST_EVENT_NAVIGATION:
1716 gst_event_unref (event);
1720 res = gst_pad_event_default (pad, parent, event);
1730 GST_ERROR_OBJECT (qtdemux, "Index failed");
1731 gst_event_unref (event);
1737 /* stream/index return sample that is min/max w.r.t. byte position,
1738 * time is min/max w.r.t. time of samples,
1739 * the latter need not be time of the former sample */
1741 gst_qtdemux_find_sample (GstQTDemux * qtdemux, gint64 byte_pos, gboolean fw,
1742 gboolean set, QtDemuxStream ** _stream, gint * _index, gint64 * _time)
1745 gint64 time, min_time;
1746 QtDemuxStream *stream;
1752 for (n = 0; n < qtdemux->n_streams; ++n) {
1755 gboolean set_sample;
1757 str = qtdemux->streams[n];
1764 i = str->n_samples - 1;
1768 for (; (i >= 0) && (i < str->n_samples); i += inc) {
1769 if (str->samples[i].size == 0)
1772 if (fw && (str->samples[i].offset < byte_pos))
1775 if (!fw && (str->samples[i].offset + str->samples[i].size > byte_pos))
1778 /* move stream to first available sample */
1780 gst_qtdemux_move_stream (qtdemux, str, i);
1784 /* avoid index from sparse streams since they might be far away */
1786 /* determine min/max time */
1787 time = QTSAMPLE_PTS (str, &str->samples[i]);
1788 if (min_time == -1 || (!fw && time > min_time) ||
1789 (fw && time < min_time)) {
1793 /* determine stream with leading sample, to get its position */
1795 (fw && (str->samples[i].offset < stream->samples[index].offset)) ||
1796 (!fw && (str->samples[i].offset > stream->samples[index].offset))) {
1804 /* no sample for this stream, mark eos */
1806 gst_qtdemux_move_stream (qtdemux, str, str->n_samples);
1817 static QtDemuxStream *
1818 _create_stream (void)
1820 QtDemuxStream *stream;
1822 stream = g_new0 (QtDemuxStream, 1);
1823 /* new streams always need a discont */
1824 stream->discont = TRUE;
1825 /* we enable clipping for raw audio/video streams */
1826 stream->need_clip = FALSE;
1827 stream->need_process = FALSE;
1828 stream->segment_index = -1;
1829 stream->time_position = 0;
1830 stream->sample_index = -1;
1831 stream->offset_in_sample = 0;
1832 stream->new_stream = TRUE;
1833 stream->multiview_mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
1834 stream->multiview_flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
1835 stream->protected = FALSE;
1836 stream->protection_scheme_type = 0;
1837 stream->protection_scheme_version = 0;
1838 stream->protection_scheme_info = NULL;
1839 stream->n_samples_moof = 0;
1840 stream->duration_moof = 0;
1841 g_queue_init (&stream->protection_scheme_event_queue);
1846 gst_qtdemux_setcaps (GstQTDemux * demux, GstCaps * caps)
1848 GstStructure *structure;
1849 const gchar *variant;
1850 const GstCaps *mediacaps = NULL;
1852 GST_DEBUG_OBJECT (demux, "Sink set caps: %" GST_PTR_FORMAT, caps);
1854 structure = gst_caps_get_structure (caps, 0);
1855 variant = gst_structure_get_string (structure, "variant");
1857 if (variant && strcmp (variant, "mss-fragmented") == 0) {
1858 QtDemuxStream *stream;
1859 const GValue *value;
1861 demux->fragmented = TRUE;
1862 demux->mss_mode = TRUE;
1864 if (demux->n_streams > 1) {
1865 /* can't do this, we can only renegotiate for another mss format */
1869 value = gst_structure_get_value (structure, "media-caps");
1872 const GValue *timescale_v;
1874 /* TODO update when stream changes during playback */
1876 if (demux->n_streams == 0) {
1877 stream = _create_stream ();
1878 demux->streams[demux->n_streams] = stream;
1879 demux->n_streams = 1;
1881 stream = demux->streams[0];
1884 timescale_v = gst_structure_get_value (structure, "timescale");
1886 stream->timescale = g_value_get_uint64 (timescale_v);
1888 /* default mss timescale */
1889 stream->timescale = 10000000;
1891 demux->timescale = stream->timescale;
1893 mediacaps = gst_value_get_caps (value);
1894 if (!stream->caps || !gst_caps_is_equal_fixed (mediacaps, stream->caps)) {
1895 GST_DEBUG_OBJECT (demux, "We have a new caps %" GST_PTR_FORMAT,
1897 stream->new_caps = TRUE;
1899 gst_caps_replace (&stream->caps, (GstCaps *) mediacaps);
1900 structure = gst_caps_get_structure (mediacaps, 0);
1901 if (g_str_has_prefix (gst_structure_get_name (structure), "video")) {
1902 stream->subtype = FOURCC_vide;
1904 gst_structure_get_int (structure, "width", &stream->width);
1905 gst_structure_get_int (structure, "height", &stream->height);
1906 gst_structure_get_fraction (structure, "framerate", &stream->fps_n,
1908 } else if (g_str_has_prefix (gst_structure_get_name (structure), "audio")) {
1910 stream->subtype = FOURCC_soun;
1911 gst_structure_get_int (structure, "channels", &stream->n_channels);
1912 gst_structure_get_int (structure, "rate", &rate);
1913 stream->rate = rate;
1916 gst_caps_replace (&demux->media_caps, (GstCaps *) mediacaps);
1918 demux->mss_mode = FALSE;
1925 gst_qtdemux_reset (GstQTDemux * qtdemux, gboolean hard)
1929 GST_DEBUG_OBJECT (qtdemux, "Resetting demux");
1930 gst_pad_stop_task (qtdemux->sinkpad);
1932 if (hard || qtdemux->upstream_format_is_time) {
1933 qtdemux->state = QTDEMUX_STATE_INITIAL;
1934 qtdemux->neededbytes = 16;
1935 qtdemux->todrop = 0;
1936 qtdemux->pullbased = FALSE;
1937 qtdemux->posted_redirect = FALSE;
1938 qtdemux->first_mdat = -1;
1939 qtdemux->header_size = 0;
1940 qtdemux->mdatoffset = -1;
1941 qtdemux->restoredata_offset = -1;
1942 if (qtdemux->mdatbuffer)
1943 gst_buffer_unref (qtdemux->mdatbuffer);
1944 if (qtdemux->restoredata_buffer)
1945 gst_buffer_unref (qtdemux->restoredata_buffer);
1946 qtdemux->mdatbuffer = NULL;
1947 qtdemux->restoredata_buffer = NULL;
1948 qtdemux->mdatleft = 0;
1949 if (qtdemux->comp_brands)
1950 gst_buffer_unref (qtdemux->comp_brands);
1951 qtdemux->comp_brands = NULL;
1952 qtdemux->last_moov_offset = -1;
1953 if (qtdemux->moov_node)
1954 g_node_destroy (qtdemux->moov_node);
1955 qtdemux->moov_node = NULL;
1956 qtdemux->moov_node_compressed = NULL;
1957 if (qtdemux->tag_list)
1958 gst_mini_object_unref (GST_MINI_OBJECT_CAST (qtdemux->tag_list));
1959 qtdemux->tag_list = NULL;
1961 if (qtdemux->element_index)
1962 gst_object_unref (qtdemux->element_index);
1963 qtdemux->element_index = NULL;
1965 qtdemux->major_brand = 0;
1966 if (qtdemux->pending_newsegment)
1967 gst_event_unref (qtdemux->pending_newsegment);
1968 qtdemux->pending_newsegment = NULL;
1969 qtdemux->upstream_format_is_time = FALSE;
1970 qtdemux->upstream_seekable = FALSE;
1971 qtdemux->upstream_size = 0;
1973 qtdemux->fragment_start = -1;
1974 qtdemux->fragment_start_offset = -1;
1975 qtdemux->duration = 0;
1976 qtdemux->moof_offset = 0;
1977 qtdemux->chapters_track_id = 0;
1978 qtdemux->have_group_id = FALSE;
1979 qtdemux->group_id = G_MAXUINT;
1981 g_queue_foreach (&qtdemux->protection_event_queue, (GFunc) gst_event_unref,
1983 g_queue_clear (&qtdemux->protection_event_queue);
1985 qtdemux->offset = 0;
1986 gst_adapter_clear (qtdemux->adapter);
1987 gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
1988 qtdemux->segment_seqnum = 0;
1991 for (n = 0; n < qtdemux->n_streams; n++) {
1992 gst_qtdemux_stream_free (qtdemux, qtdemux->streams[n]);
1993 qtdemux->streams[n] = NULL;
1995 qtdemux->n_streams = 0;
1996 qtdemux->n_video_streams = 0;
1997 qtdemux->n_audio_streams = 0;
1998 qtdemux->n_sub_streams = 0;
1999 qtdemux->exposed = FALSE;
2000 qtdemux->fragmented = FALSE;
2001 qtdemux->mss_mode = FALSE;
2002 gst_caps_replace (&qtdemux->media_caps, NULL);
2003 qtdemux->timescale = 0;
2004 qtdemux->got_moov = FALSE;
2005 if (qtdemux->protection_system_ids) {
2006 g_ptr_array_free (qtdemux->protection_system_ids, TRUE);
2007 qtdemux->protection_system_ids = NULL;
2009 } else if (qtdemux->mss_mode) {
2010 gst_flow_combiner_reset (qtdemux->flowcombiner);
2011 for (n = 0; n < qtdemux->n_streams; n++)
2012 gst_qtdemux_stream_clear (qtdemux, qtdemux->streams[n]);
2014 gst_flow_combiner_reset (qtdemux->flowcombiner);
2015 for (n = 0; n < qtdemux->n_streams; n++) {
2016 qtdemux->streams[n]->sent_eos = FALSE;
2017 qtdemux->streams[n]->time_position = 0;
2018 qtdemux->streams[n]->accumulated_base = 0;
2020 if (!qtdemux->pending_newsegment) {
2021 qtdemux->pending_newsegment = gst_event_new_segment (&qtdemux->segment);
2022 if (qtdemux->segment_seqnum)
2023 gst_event_set_seqnum (qtdemux->pending_newsegment,
2024 qtdemux->segment_seqnum);
2030 /* Maps the @segment to the qt edts internal segments and pushes
2031 * the correspnding segment event.
2033 * If it ends up being at a empty segment, a gap will be pushed and the next
2034 * edts segment will be activated in sequence.
2036 * To be used in push-mode only */
2038 gst_qtdemux_map_and_push_segments (GstQTDemux * qtdemux, GstSegment * segment)
2042 for (n = 0; n < qtdemux->n_streams; n++) {
2043 QtDemuxStream *stream = qtdemux->streams[n];
2045 stream->time_position = segment->start;
2047 /* in push mode we should be guaranteed that we will have empty segments
2048 * at the beginning and then one segment after, other scenarios are not
2049 * supported and are discarded when parsing the edts */
2050 for (i = 0; i < stream->n_segments; i++) {
2051 if (stream->segments[i].stop_time > segment->start) {
2052 gst_qtdemux_activate_segment (qtdemux, stream, i,
2053 stream->time_position);
2054 if (QTSEGMENT_IS_EMPTY (&stream->segments[i])) {
2055 /* push the empty segment and move to the next one */
2056 gst_qtdemux_send_gap_for_segment (qtdemux, stream, i,
2057 stream->time_position);
2061 g_assert (i == stream->n_segments - 1);
2068 gst_qtdemux_handle_sink_event (GstPad * sinkpad, GstObject * parent,
2071 GstQTDemux *demux = GST_QTDEMUX (parent);
2072 gboolean res = TRUE;
2074 GST_LOG_OBJECT (demux, "handling %s event", GST_EVENT_TYPE_NAME (event));
2076 switch (GST_EVENT_TYPE (event)) {
2077 case GST_EVENT_SEGMENT:
2080 QtDemuxStream *stream;
2083 GstEvent *segment_event;
2085 /* some debug output */
2086 gst_event_copy_segment (event, &segment);
2087 GST_DEBUG_OBJECT (demux, "received newsegment %" GST_SEGMENT_FORMAT,
2090 if (segment.format == GST_FORMAT_TIME) {
2091 GST_DEBUG_OBJECT (demux, "new pending_newsegment");
2092 gst_event_replace (&demux->pending_newsegment, event);
2093 demux->upstream_format_is_time = TRUE;
2095 GST_DEBUG_OBJECT (demux, "Not storing upstream newsegment, "
2096 "not in time format");
2098 /* chain will send initial newsegment after pads have been added */
2099 if (demux->state != QTDEMUX_STATE_MOVIE || !demux->n_streams) {
2100 GST_DEBUG_OBJECT (demux, "still starting, eating event");
2105 /* check if this matches a time seek we received previously
2106 * FIXME for backwards compatibility reasons we use the
2107 * seek_offset here to compare. In the future we might want to
2108 * change this to use the seqnum as it uniquely should identify
2109 * the segment that corresponds to the seek. */
2110 GST_DEBUG_OBJECT (demux, "Stored seek offset: %" G_GINT64_FORMAT
2111 ", received segment offset %" G_GINT64_FORMAT,
2112 demux->seek_offset, segment.start);
2113 if (segment.format == GST_FORMAT_BYTES
2114 && demux->seek_offset == segment.start) {
2115 GST_OBJECT_LOCK (demux);
2116 offset = segment.start;
2118 segment.format = GST_FORMAT_TIME;
2119 segment.start = demux->push_seek_start;
2120 segment.stop = demux->push_seek_stop;
2121 GST_DEBUG_OBJECT (demux, "Replaced segment with stored seek "
2122 "segment %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT,
2123 GST_TIME_ARGS (segment.start), GST_TIME_ARGS (segment.stop));
2124 GST_OBJECT_UNLOCK (demux);
2127 /* we only expect a BYTE segment, e.g. following a seek */
2128 if (segment.format == GST_FORMAT_BYTES) {
2129 if (GST_CLOCK_TIME_IS_VALID (segment.start)) {
2130 offset = segment.start;
2132 gst_qtdemux_find_sample (demux, segment.start, TRUE, FALSE, NULL,
2133 NULL, (gint64 *) & segment.start);
2134 if ((gint64) segment.start < 0)
2137 if (GST_CLOCK_TIME_IS_VALID (segment.stop)) {
2138 gst_qtdemux_find_sample (demux, segment.stop, FALSE, FALSE, NULL,
2139 NULL, (gint64 *) & segment.stop);
2140 /* keyframe seeking should already arrange for start >= stop,
2141 * but make sure in other rare cases */
2142 segment.stop = MAX (segment.stop, segment.start);
2144 } else if (segment.format == GST_FORMAT_TIME) {
2145 /* push all data on the adapter before starting this
2147 gst_qtdemux_process_adapter (demux, TRUE);
2149 GST_DEBUG_OBJECT (demux, "unsupported segment format, ignoring");
2153 /* accept upstream's notion of segment and distribute along */
2154 segment.format = GST_FORMAT_TIME;
2155 segment.position = segment.time = segment.start;
2156 segment.duration = demux->segment.duration;
2157 segment.base = gst_segment_to_running_time (&demux->segment,
2158 GST_FORMAT_TIME, demux->segment.position);
2160 gst_segment_copy_into (&segment, &demux->segment);
2161 GST_DEBUG_OBJECT (demux, "Pushing newseg %" GST_SEGMENT_FORMAT, &segment);
2162 /* erase any previously set segment */
2163 gst_event_replace (&demux->pending_newsegment, NULL);
2165 /* For pull mode, segment activation will be handled in the looping task
2166 * For push mode, need to do it here */
2167 if (demux->pullbased) {
2168 segment_event = gst_event_new_segment (&segment);
2169 gst_event_set_seqnum (segment_event, gst_event_get_seqnum (event));
2170 gst_qtdemux_push_event (demux, segment_event);
2172 /* map segment to internal qt segments and push on each stream */
2173 gst_qtdemux_map_and_push_segments (demux, &segment);
2176 /* clear leftover in current segment, if any */
2177 gst_adapter_clear (demux->adapter);
2179 /* set up streaming thread */
2180 demux->offset = offset;
2181 if (demux->upstream_format_is_time) {
2182 GST_DEBUG_OBJECT (demux, "Upstream is driving in time format, "
2183 "set values to restart reading from a new atom");
2184 demux->neededbytes = 16;
2187 gst_qtdemux_find_sample (demux, offset, TRUE, TRUE, &stream, &idx,
2190 demux->todrop = stream->samples[idx].offset - offset;
2191 demux->neededbytes = demux->todrop + stream->samples[idx].size;
2193 /* set up for EOS */
2194 demux->neededbytes = -1;
2199 gst_event_unref (event);
2203 case GST_EVENT_FLUSH_START:
2205 if (gst_event_get_seqnum (event) == demux->offset_seek_seqnum) {
2206 gst_event_unref (event);
2211 case GST_EVENT_FLUSH_STOP:
2215 dur = demux->segment.duration;
2216 gst_qtdemux_reset (demux, FALSE);
2217 demux->segment.duration = dur;
2219 if (gst_event_get_seqnum (event) == demux->offset_seek_seqnum) {
2220 gst_event_unref (event);
2226 /* If we are in push mode, and get an EOS before we've seen any streams,
2227 * then error out - we have nowhere to send the EOS */
2228 if (!demux->pullbased) {
2230 gboolean has_valid_stream = FALSE;
2231 for (i = 0; i < demux->n_streams; i++) {
2232 if (demux->streams[i]->pad != NULL) {
2233 has_valid_stream = TRUE;
2237 if (!has_valid_stream)
2238 gst_qtdemux_post_no_playable_stream_error (demux);
2240 GST_DEBUG_OBJECT (demux, "Data still available after EOS: %u",
2241 (guint) gst_adapter_available (demux->adapter));
2242 if (gst_qtdemux_process_adapter (demux, TRUE) != GST_FLOW_OK) {
2248 case GST_EVENT_CAPS:{
2249 GstCaps *caps = NULL;
2251 gst_event_parse_caps (event, &caps);
2252 gst_qtdemux_setcaps (demux, caps);
2254 gst_event_unref (event);
2257 case GST_EVENT_PROTECTION:
2259 const gchar *system_id = NULL;
2261 gst_event_parse_protection (event, &system_id, NULL, NULL);
2262 GST_DEBUG_OBJECT (demux, "Received protection event for system ID %s",
2264 gst_qtdemux_append_protection_system_id (demux, system_id);
2265 /* save the event for later, for source pads that have not been created */
2266 g_queue_push_tail (&demux->protection_event_queue, gst_event_ref (event));
2267 /* send it to all pads that already exist */
2268 gst_qtdemux_push_event (demux, event);
2276 res = gst_pad_event_default (demux->sinkpad, parent, event) & res;
2284 gst_qtdemux_set_index (GstElement * element, GstIndex * index)
2286 GstQTDemux *demux = GST_QTDEMUX (element);
2288 GST_OBJECT_LOCK (demux);
2289 if (demux->element_index)
2290 gst_object_unref (demux->element_index);
2292 demux->element_index = gst_object_ref (index);
2294 demux->element_index = NULL;
2296 GST_OBJECT_UNLOCK (demux);
2297 /* object lock might be taken again */
2299 gst_index_get_writer_id (index, GST_OBJECT (element), &demux->index_id);
2300 GST_DEBUG_OBJECT (demux, "Set index %" GST_PTR_FORMAT "for writer id %d",
2301 demux->element_index, demux->index_id);
2305 gst_qtdemux_get_index (GstElement * element)
2307 GstIndex *result = NULL;
2308 GstQTDemux *demux = GST_QTDEMUX (element);
2310 GST_OBJECT_LOCK (demux);
2311 if (demux->element_index)
2312 result = gst_object_ref (demux->element_index);
2313 GST_OBJECT_UNLOCK (demux);
2315 GST_DEBUG_OBJECT (demux, "Returning index %" GST_PTR_FORMAT, result);
2322 gst_qtdemux_stbl_free (QtDemuxStream * stream)
2324 g_free ((gpointer) stream->stco.data);
2325 stream->stco.data = NULL;
2326 g_free ((gpointer) stream->stsz.data);
2327 stream->stsz.data = NULL;
2328 g_free ((gpointer) stream->stsc.data);
2329 stream->stsc.data = NULL;
2330 g_free ((gpointer) stream->stts.data);
2331 stream->stts.data = NULL;
2332 g_free ((gpointer) stream->stss.data);
2333 stream->stss.data = NULL;
2334 g_free ((gpointer) stream->stps.data);
2335 stream->stps.data = NULL;
2336 g_free ((gpointer) stream->ctts.data);
2337 stream->ctts.data = NULL;
2341 gst_qtdemux_stream_flush_segments_data (GstQTDemux * qtdemux,
2342 QtDemuxStream * stream)
2344 g_free (stream->segments);
2345 stream->segments = NULL;
2346 stream->segment_index = -1;
2347 stream->accumulated_base = 0;
2351 gst_qtdemux_stream_flush_samples_data (GstQTDemux * qtdemux,
2352 QtDemuxStream * stream)
2354 g_free (stream->samples);
2355 stream->samples = NULL;
2356 gst_qtdemux_stbl_free (stream);
2359 g_free (stream->ra_entries);
2360 stream->ra_entries = NULL;
2361 stream->n_ra_entries = 0;
2363 stream->sample_index = -1;
2364 stream->stbl_index = -1;
2365 stream->n_samples = 0;
2366 stream->time_position = 0;
2368 stream->n_samples_moof = 0;
2369 stream->duration_moof = 0;
2373 gst_qtdemux_stream_clear (GstQTDemux * qtdemux, QtDemuxStream * stream)
2375 if (stream->allocator)
2376 gst_object_unref (stream->allocator);
2377 while (stream->buffers) {
2378 gst_buffer_unref (GST_BUFFER_CAST (stream->buffers->data));
2379 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
2381 if (stream->rgb8_palette) {
2382 gst_memory_unref (stream->rgb8_palette);
2383 stream->rgb8_palette = NULL;
2386 if (stream->pending_tags)
2387 gst_tag_list_unref (stream->pending_tags);
2388 stream->pending_tags = NULL;
2389 g_free (stream->redirect_uri);
2390 stream->redirect_uri = NULL;
2391 stream->sent_eos = FALSE;
2392 stream->sparse = FALSE;
2393 stream->protected = FALSE;
2394 if (stream->protection_scheme_info) {
2395 if (stream->protection_scheme_type == FOURCC_cenc) {
2396 QtDemuxCencSampleSetInfo *info =
2397 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
2398 if (info->default_properties)
2399 gst_structure_free (info->default_properties);
2400 if (info->crypto_info)
2401 g_ptr_array_free (info->crypto_info, TRUE);
2403 g_free (stream->protection_scheme_info);
2404 stream->protection_scheme_info = NULL;
2406 stream->protection_scheme_type = 0;
2407 stream->protection_scheme_version = 0;
2408 g_queue_foreach (&stream->protection_scheme_event_queue,
2409 (GFunc) gst_event_unref, NULL);
2410 g_queue_clear (&stream->protection_scheme_event_queue);
2411 gst_qtdemux_stream_flush_segments_data (qtdemux, stream);
2412 gst_qtdemux_stream_flush_samples_data (qtdemux, stream);
2416 gst_qtdemux_stream_free (GstQTDemux * qtdemux, QtDemuxStream * stream)
2418 gst_qtdemux_stream_clear (qtdemux, stream);
2420 gst_caps_unref (stream->caps);
2421 stream->caps = NULL;
2423 gst_element_remove_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
2424 gst_flow_combiner_remove_pad (qtdemux->flowcombiner, stream->pad);
2430 gst_qtdemux_remove_stream (GstQTDemux * qtdemux, int i)
2432 g_assert (i >= 0 && i < qtdemux->n_streams && qtdemux->streams[i] != NULL);
2434 gst_qtdemux_stream_free (qtdemux, qtdemux->streams[i]);
2435 qtdemux->streams[i] = qtdemux->streams[qtdemux->n_streams - 1];
2436 qtdemux->streams[qtdemux->n_streams - 1] = NULL;
2437 qtdemux->n_streams--;
2440 static GstStateChangeReturn
2441 gst_qtdemux_change_state (GstElement * element, GstStateChange transition)
2443 GstQTDemux *qtdemux = GST_QTDEMUX (element);
2444 GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
2446 switch (transition) {
2447 case GST_STATE_CHANGE_PAUSED_TO_READY:
2453 result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
2455 switch (transition) {
2456 case GST_STATE_CHANGE_PAUSED_TO_READY:{
2457 gst_qtdemux_reset (qtdemux, TRUE);
2468 qtdemux_parse_ftyp (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2470 /* counts as header data */
2471 qtdemux->header_size += length;
2473 /* only consider at least a sufficiently complete ftyp atom */
2477 qtdemux->major_brand = QT_FOURCC (buffer + 8);
2478 GST_DEBUG_OBJECT (qtdemux, "major brand: %" GST_FOURCC_FORMAT,
2479 GST_FOURCC_ARGS (qtdemux->major_brand));
2480 if (qtdemux->comp_brands)
2481 gst_buffer_unref (qtdemux->comp_brands);
2482 buf = qtdemux->comp_brands = gst_buffer_new_and_alloc (length - 16);
2483 gst_buffer_fill (buf, 0, buffer + 16, length - 16);
2488 qtdemux_handle_xmp_taglist (GstQTDemux * qtdemux, GstTagList * taglist,
2489 GstTagList * xmptaglist)
2491 /* Strip out bogus fields */
2493 if (gst_tag_list_get_scope (taglist) == GST_TAG_SCOPE_GLOBAL) {
2494 gst_tag_list_remove_tag (xmptaglist, GST_TAG_VIDEO_CODEC);
2495 gst_tag_list_remove_tag (xmptaglist, GST_TAG_AUDIO_CODEC);
2497 gst_tag_list_remove_tag (xmptaglist, GST_TAG_CONTAINER_FORMAT);
2500 GST_DEBUG_OBJECT (qtdemux, "Found XMP tags %" GST_PTR_FORMAT, xmptaglist);
2502 /* prioritize native tags using _KEEP mode */
2503 gst_tag_list_insert (taglist, xmptaglist, GST_TAG_MERGE_KEEP);
2504 gst_tag_list_unref (xmptaglist);
2509 qtdemux_parse_piff (GstQTDemux * qtdemux, const guint8 * buffer, gint length,
2517 QtDemuxStream *stream;
2518 GstStructure *structure;
2519 QtDemuxCencSampleSetInfo *ss_info = NULL;
2520 const gchar *system_id;
2521 gboolean uses_sub_sample_encryption = FALSE;
2523 if (qtdemux->n_streams == 0)
2526 stream = qtdemux->streams[0];
2528 structure = gst_caps_get_structure (stream->caps, 0);
2529 if (!gst_structure_has_name (structure, "application/x-cenc")) {
2530 GST_WARNING_OBJECT (qtdemux,
2531 "Attempting PIFF box parsing on an unencrypted stream.");
2535 gst_structure_get (structure, GST_PROTECTION_SYSTEM_ID_CAPS_FIELD,
2536 G_TYPE_STRING, &system_id, NULL);
2537 gst_qtdemux_append_protection_system_id (qtdemux, system_id);
2539 stream->protected = TRUE;
2540 stream->protection_scheme_type = FOURCC_cenc;
2542 if (!stream->protection_scheme_info)
2543 stream->protection_scheme_info = g_new0 (QtDemuxCencSampleSetInfo, 1);
2545 ss_info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
2547 if (ss_info->default_properties)
2548 gst_structure_free (ss_info->default_properties);
2550 ss_info->default_properties =
2551 gst_structure_new ("application/x-cenc",
2552 "iv_size", G_TYPE_UINT, iv_size, "encrypted", G_TYPE_BOOLEAN, TRUE, NULL);
2554 if (ss_info->crypto_info) {
2555 GST_LOG_OBJECT (qtdemux, "unreffing existing crypto_info");
2556 g_ptr_array_free (ss_info->crypto_info, TRUE);
2557 ss_info->crypto_info = NULL;
2561 gst_byte_reader_init (&br, buffer + offset + 16, length - offset - 16);
2563 if (!gst_byte_reader_get_uint8 (&br, &version)) {
2564 GST_ERROR_OBJECT (qtdemux, "Error getting box's version field");
2568 if (!gst_byte_reader_get_uint24_be (&br, &flags)) {
2569 GST_ERROR_OBJECT (qtdemux, "Error getting box's flags field");
2573 if ((flags & 0x000001)) {
2574 guint32 algorithm_id = 0;
2577 gboolean is_encrypted = TRUE;
2579 if (!gst_byte_reader_get_uint24_le (&br, &algorithm_id)) {
2580 GST_ERROR_OBJECT (qtdemux, "Error getting box's algorithm ID field");
2585 if (algorithm_id == 0) {
2586 is_encrypted = FALSE;
2587 } else if (algorithm_id == 1) {
2588 /* FIXME: maybe store this in properties? */
2589 GST_DEBUG_OBJECT (qtdemux, "AES 128-bits CTR encrypted stream");
2590 } else if (algorithm_id == 2) {
2591 /* FIXME: maybe store this in properties? */
2592 GST_DEBUG_OBJECT (qtdemux, "AES 128-bits CBC encrypted stream");
2595 if (!gst_byte_reader_get_uint8 (&br, &iv_size))
2598 if (!gst_byte_reader_get_data (&br, 16, &kid))
2601 kid_buf = gst_buffer_new_allocate (NULL, 16, NULL);
2602 gst_buffer_fill (kid_buf, 0, kid, 16);
2603 if (ss_info->default_properties)
2604 gst_structure_free (ss_info->default_properties);
2605 ss_info->default_properties =
2606 gst_structure_new ("application/x-cenc",
2607 "iv_size", G_TYPE_UINT, iv_size,
2608 "encrypted", G_TYPE_BOOLEAN, is_encrypted,
2609 "kid", GST_TYPE_BUFFER, kid_buf, NULL);
2610 GST_DEBUG_OBJECT (qtdemux, "default sample properties: "
2611 "is_encrypted=%u, iv_size=%u", is_encrypted, iv_size);
2612 gst_buffer_unref (kid_buf);
2613 } else if ((flags & 0x000002)) {
2614 uses_sub_sample_encryption = TRUE;
2617 if (!gst_byte_reader_get_uint32_be (&br, &qtdemux->cenc_aux_sample_count)) {
2618 GST_ERROR_OBJECT (qtdemux, "Error getting box's sample count field");
2622 ss_info->crypto_info =
2623 g_ptr_array_new_full (qtdemux->cenc_aux_sample_count,
2624 (GDestroyNotify) qtdemux_gst_structure_free);
2626 for (i = 0; i < qtdemux->cenc_aux_sample_count; ++i) {
2627 GstStructure *properties;
2631 properties = qtdemux_get_cenc_sample_properties (qtdemux, stream, i);
2632 if (properties == NULL) {
2633 GST_ERROR_OBJECT (qtdemux, "failed to get properties for sample %u", i);
2637 if (!gst_byte_reader_dup_data (&br, iv_size, &data)) {
2638 GST_ERROR_OBJECT (qtdemux, "IV data not present for sample %u", i);
2639 gst_structure_free (properties);
2642 buf = gst_buffer_new_wrapped (data, iv_size);
2643 gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL);
2644 gst_buffer_unref (buf);
2646 if (uses_sub_sample_encryption) {
2647 guint16 n_subsamples;
2649 if (!gst_byte_reader_get_uint16_be (&br, &n_subsamples)
2650 || n_subsamples == 0) {
2651 GST_ERROR_OBJECT (qtdemux,
2652 "failed to get subsample count for sample %u", i);
2653 gst_structure_free (properties);
2656 GST_LOG_OBJECT (qtdemux, "subsample count: %u", n_subsamples);
2657 if (!gst_byte_reader_dup_data (&br, n_subsamples * 6, &data)) {
2658 GST_ERROR_OBJECT (qtdemux, "failed to get subsample data for sample %u",
2660 gst_structure_free (properties);
2663 buf = gst_buffer_new_wrapped (data, n_subsamples * 6);
2664 gst_structure_set (properties,
2665 "subsample_count", G_TYPE_UINT, n_subsamples,
2666 "subsamples", GST_TYPE_BUFFER, buf, NULL);
2667 gst_buffer_unref (buf);
2669 gst_structure_set (properties, "subsample_count", G_TYPE_UINT, 0, NULL);
2672 g_ptr_array_add (ss_info->crypto_info, properties);
2677 qtdemux_parse_uuid (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2679 static const guint8 xmp_uuid[] = { 0xBE, 0x7A, 0xCF, 0xCB,
2680 0x97, 0xA9, 0x42, 0xE8,
2681 0x9C, 0x71, 0x99, 0x94,
2682 0x91, 0xE3, 0xAF, 0xAC
2684 static const guint8 playready_uuid[] = {
2685 0xd0, 0x8a, 0x4f, 0x18, 0x10, 0xf3, 0x4a, 0x82,
2686 0xb6, 0xc8, 0x32, 0xd8, 0xab, 0xa1, 0x83, 0xd3
2689 static const guint8 piff_sample_encryption_uuid[] = {
2690 0xa2, 0x39, 0x4f, 0x52, 0x5a, 0x9b, 0x4f, 0x14,
2691 0xa2, 0x44, 0x6c, 0x42, 0x7c, 0x64, 0x8d, 0xf4
2696 /* counts as header data */
2697 qtdemux->header_size += length;
2699 offset = (QT_UINT32 (buffer) == 0) ? 16 : 8;
2701 if (length <= offset + 16) {
2702 GST_DEBUG_OBJECT (qtdemux, "uuid atom is too short, skipping");
2706 if (memcmp (buffer + offset, xmp_uuid, 16) == 0) {
2708 GstTagList *taglist;
2710 buf = _gst_buffer_new_wrapped ((guint8 *) buffer + offset + 16,
2711 length - offset - 16, NULL);
2712 taglist = gst_tag_list_from_xmp_buffer (buf);
2713 gst_buffer_unref (buf);
2715 qtdemux_handle_xmp_taglist (qtdemux, qtdemux->tag_list, taglist);
2717 } else if (memcmp (buffer + offset, playready_uuid, 16) == 0) {
2719 const gunichar2 *s_utf16;
2722 len = GST_READ_UINT16_LE (buffer + offset + 0x30);
2723 s_utf16 = (const gunichar2 *) (buffer + offset + 0x32);
2724 contents = g_utf16_to_utf8 (s_utf16, len / 2, NULL, NULL, NULL);
2725 GST_ERROR_OBJECT (qtdemux, "contents: %s", contents);
2729 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT,
2730 (_("Cannot play stream because it is encrypted with PlayReady DRM.")),
2732 } else if (memcmp (buffer + offset, piff_sample_encryption_uuid, 16) == 0) {
2733 qtdemux_parse_piff (qtdemux, buffer, length, offset);
2735 GST_DEBUG_OBJECT (qtdemux, "Ignoring unknown uuid: %08x-%08x-%08x-%08x",
2736 GST_READ_UINT32_LE (buffer + offset),
2737 GST_READ_UINT32_LE (buffer + offset + 4),
2738 GST_READ_UINT32_LE (buffer + offset + 8),
2739 GST_READ_UINT32_LE (buffer + offset + 12));
2744 qtdemux_parse_sidx (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2746 GstSidxParser sidx_parser;
2747 GstIsoffParserResult res;
2750 gst_isoff_qt_sidx_parser_init (&sidx_parser);
2753 gst_isoff_qt_sidx_parser_add_data (&sidx_parser, buffer, length,
2755 GST_DEBUG_OBJECT (qtdemux, "sidx parse result: %d", res);
2756 if (res == GST_ISOFF_QT_PARSER_DONE) {
2757 check_update_duration (qtdemux, sidx_parser.cumulative_pts);
2759 gst_isoff_qt_sidx_parser_clear (&sidx_parser);
2762 /* caller verifies at least 8 bytes in buf */
2764 extract_initial_length_and_fourcc (const guint8 * data, guint size,
2765 guint64 * plength, guint32 * pfourcc)
2770 length = QT_UINT32 (data);
2771 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
2772 fourcc = QT_FOURCC (data + 4);
2773 GST_DEBUG ("atom type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
2776 length = G_MAXUINT64;
2777 } else if (length == 1 && size >= 16) {
2778 /* this means we have an extended size, which is the 64 bit value of
2779 * the next 8 bytes */
2780 length = QT_UINT64 (data + 8);
2781 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
2791 qtdemux_parse_mehd (GstQTDemux * qtdemux, GstByteReader * br)
2793 guint32 version = 0;
2794 GstClockTime duration = 0;
2796 if (!gst_byte_reader_get_uint32_be (br, &version))
2801 if (!gst_byte_reader_get_uint64_be (br, &duration))
2806 if (!gst_byte_reader_get_uint32_be (br, &dur))
2811 GST_INFO_OBJECT (qtdemux, "mehd duration: %" G_GUINT64_FORMAT, duration);
2812 qtdemux->duration = duration;
2818 GST_DEBUG_OBJECT (qtdemux, "parsing mehd failed");
2824 qtdemux_parse_trex (GstQTDemux * qtdemux, QtDemuxStream * stream,
2825 guint32 * ds_duration, guint32 * ds_size, guint32 * ds_flags)
2827 if (!stream->parsed_trex && qtdemux->moov_node) {
2829 GstByteReader trex_data;
2831 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
2833 trex = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_trex,
2836 guint32 id = 0, dur = 0, size = 0, flags = 0, dummy = 0;
2838 /* skip version/flags */
2839 if (!gst_byte_reader_skip (&trex_data, 4))
2841 if (!gst_byte_reader_get_uint32_be (&trex_data, &id))
2843 if (id != stream->track_id)
2845 /* sample description index; ignore */
2846 if (!gst_byte_reader_get_uint32_be (&trex_data, &dummy))
2848 if (!gst_byte_reader_get_uint32_be (&trex_data, &dur))
2850 if (!gst_byte_reader_get_uint32_be (&trex_data, &size))
2852 if (!gst_byte_reader_get_uint32_be (&trex_data, &flags))
2855 GST_DEBUG_OBJECT (qtdemux, "fragment defaults for stream %d; "
2856 "duration %d, size %d, flags 0x%x", stream->track_id,
2859 stream->parsed_trex = TRUE;
2860 stream->def_sample_duration = dur;
2861 stream->def_sample_size = size;
2862 stream->def_sample_flags = flags;
2865 /* iterate all siblings */
2866 trex = qtdemux_tree_get_sibling_by_type_full (trex, FOURCC_trex,
2872 *ds_duration = stream->def_sample_duration;
2873 *ds_size = stream->def_sample_size;
2874 *ds_flags = stream->def_sample_flags;
2876 /* even then, above values are better than random ... */
2877 if (G_UNLIKELY (!stream->parsed_trex)) {
2878 GST_WARNING_OBJECT (qtdemux,
2879 "failed to find fragment defaults for stream %d", stream->track_id);
2886 /* This method should be called whenever a more accurate duration might
2887 * have been found. It will update all relevant variables if/where needed
2890 check_update_duration (GstQTDemux * qtdemux, GstClockTime duration)
2894 GstClockTime prevdur;
2896 movdur = GSTTIME_TO_QTTIME (qtdemux, duration);
2898 if (movdur > qtdemux->duration) {
2899 prevdur = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
2900 GST_DEBUG_OBJECT (qtdemux,
2901 "Updating total duration to %" GST_TIME_FORMAT " was %" GST_TIME_FORMAT,
2902 GST_TIME_ARGS (duration), GST_TIME_ARGS (prevdur));
2903 qtdemux->duration = movdur;
2904 GST_DEBUG_OBJECT (qtdemux,
2905 "qtdemux->segment.duration: %" GST_TIME_FORMAT " .stop: %"
2906 GST_TIME_FORMAT, GST_TIME_ARGS (qtdemux->segment.duration),
2907 GST_TIME_ARGS (qtdemux->segment.stop));
2908 if (qtdemux->segment.duration == prevdur) {
2909 /* If the current segment has duration/stop identical to previous duration
2910 * update them also (because they were set at that point in time with
2911 * the wrong duration */
2912 /* We convert the value *from* the timescale version to avoid rounding errors */
2913 GstClockTime fixeddur = QTTIME_TO_GSTTIME (qtdemux, movdur);
2914 GST_DEBUG_OBJECT (qtdemux, "Updated segment.duration and segment.stop");
2915 qtdemux->segment.duration = fixeddur;
2916 qtdemux->segment.stop = fixeddur;
2919 for (i = 0; i < qtdemux->n_streams; i++) {
2920 QtDemuxStream *stream = qtdemux->streams[i];
2922 movdur = GSTTIME_TO_QTSTREAMTIME (stream, duration);
2923 if (movdur > stream->duration) {
2924 GST_DEBUG_OBJECT (qtdemux,
2925 "Updating stream #%d duration to %" GST_TIME_FORMAT, i,
2926 GST_TIME_ARGS (duration));
2927 stream->duration = movdur;
2928 if (stream->dummy_segment) {
2929 /* Update all dummy values to new duration */
2930 stream->segments[0].stop_time = duration;
2931 stream->segments[0].duration = duration;
2932 stream->segments[0].media_stop = duration;
2934 /* let downstream know we possibly have a new stop time */
2935 if (stream->segment_index != -1) {
2938 if (qtdemux->segment.rate >= 0) {
2939 pos = stream->segment.start;
2941 pos = stream->segment.stop;
2944 gst_qtdemux_stream_update_segment (qtdemux, stream,
2945 stream->segment_index, pos, NULL, NULL);
2954 qtdemux_parse_trun (GstQTDemux * qtdemux, GstByteReader * trun,
2955 QtDemuxStream * stream, guint32 d_sample_duration, guint32 d_sample_size,
2956 guint32 d_sample_flags, gint64 moof_offset, gint64 moof_length,
2957 gint64 * base_offset, gint64 * running_offset, gint64 decode_ts)
2959 GstClockTime gst_ts = GST_CLOCK_TIME_NONE;
2961 gint32 data_offset = 0;
2962 guint32 flags = 0, first_flags = 0, samples_count = 0;
2965 guint entry_size, dur_offset, size_offset, flags_offset = 0, ct_offset = 0;
2966 QtDemuxSample *sample;
2967 gboolean ismv = FALSE;
2969 GST_LOG_OBJECT (qtdemux, "parsing trun stream %d; "
2970 "default dur %d, size %d, flags 0x%x, base offset %" G_GINT64_FORMAT ", "
2971 "decode ts %" G_GINT64_FORMAT, stream->track_id, d_sample_duration,
2972 d_sample_size, d_sample_flags, *base_offset, decode_ts);
2974 if (stream->pending_seek && moof_offset < stream->pending_seek->moof_offset) {
2975 GST_INFO_OBJECT (stream->pad, "skipping trun before seek target fragment");
2979 /* presence of stss or not can't really tell us much,
2980 * and flags and so on tend to be marginally reliable in these files */
2981 if (stream->subtype == FOURCC_soun) {
2982 GST_DEBUG_OBJECT (qtdemux,
2983 "sound track in fragmented file; marking all keyframes");
2984 stream->all_keyframe = TRUE;
2987 if (!gst_byte_reader_skip (trun, 1) ||
2988 !gst_byte_reader_get_uint24_be (trun, &flags))
2991 if (!gst_byte_reader_get_uint32_be (trun, &samples_count))
2994 if (flags & TR_DATA_OFFSET) {
2995 /* note this is really signed */
2996 if (!gst_byte_reader_get_int32_be (trun, &data_offset))
2998 GST_LOG_OBJECT (qtdemux, "trun data offset %d", data_offset);
2999 /* default base offset = first byte of moof */
3000 if (*base_offset == -1) {
3001 GST_LOG_OBJECT (qtdemux, "base_offset at moof");
3002 *base_offset = moof_offset;
3004 *running_offset = *base_offset + data_offset;
3006 /* if no offset at all, that would mean data starts at moof start,
3007 * which is a bit wrong and is ismv crappy way, so compensate
3008 * assuming data is in mdat following moof */
3009 if (*base_offset == -1) {
3010 *base_offset = moof_offset + moof_length + 8;
3011 GST_LOG_OBJECT (qtdemux, "base_offset assumed in mdat after moof");
3014 if (*running_offset == -1)
3015 *running_offset = *base_offset;
3018 GST_LOG_OBJECT (qtdemux, "running offset now %" G_GINT64_FORMAT,
3020 GST_LOG_OBJECT (qtdemux, "trun offset %d, flags 0x%x, entries %d",
3021 data_offset, flags, samples_count);
3023 if (flags & TR_FIRST_SAMPLE_FLAGS) {
3024 if (G_UNLIKELY (flags & TR_SAMPLE_FLAGS)) {
3025 GST_DEBUG_OBJECT (qtdemux,
3026 "invalid flags; SAMPLE and FIRST_SAMPLE present, discarding latter");
3027 flags ^= TR_FIRST_SAMPLE_FLAGS;
3029 if (!gst_byte_reader_get_uint32_be (trun, &first_flags))
3031 GST_LOG_OBJECT (qtdemux, "first flags: 0x%x", first_flags);
3035 /* FIXME ? spec says other bits should also be checked to determine
3036 * entry size (and prefix size for that matter) */
3038 dur_offset = size_offset = 0;
3039 if (flags & TR_SAMPLE_DURATION) {
3040 GST_LOG_OBJECT (qtdemux, "entry duration present");
3041 dur_offset = entry_size;
3044 if (flags & TR_SAMPLE_SIZE) {
3045 GST_LOG_OBJECT (qtdemux, "entry size present");
3046 size_offset = entry_size;
3049 if (flags & TR_SAMPLE_FLAGS) {
3050 GST_LOG_OBJECT (qtdemux, "entry flags present");
3051 flags_offset = entry_size;
3054 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
3055 GST_LOG_OBJECT (qtdemux, "entry ct offset present");
3056 ct_offset = entry_size;
3060 if (!qt_atom_parser_has_chunks (trun, samples_count, entry_size))
3062 data = (guint8 *) gst_byte_reader_peek_data_unchecked (trun);
3064 if (stream->n_samples + samples_count >=
3065 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample))
3068 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
3069 stream->n_samples + samples_count, (guint) sizeof (QtDemuxSample),
3070 (stream->n_samples + samples_count) *
3071 sizeof (QtDemuxSample) / (1024.0 * 1024.0));
3073 /* create a new array of samples if it's the first sample parsed */
3074 if (stream->n_samples == 0) {
3075 g_assert (stream->samples == NULL);
3076 stream->samples = g_try_new0 (QtDemuxSample, samples_count);
3077 /* or try to reallocate it with space enough to insert the new samples */
3079 stream->samples = g_try_renew (QtDemuxSample, stream->samples,
3080 stream->n_samples + samples_count);
3081 if (stream->samples == NULL)
3084 if (qtdemux->fragment_start != -1) {
3085 timestamp = GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->fragment_start);
3086 qtdemux->fragment_start = -1;
3088 if (stream->n_samples == 0) {
3089 if (decode_ts > 0) {
3090 timestamp = decode_ts;
3091 } else if (stream->pending_seek != NULL) {
3092 /* if we don't have a timestamp from a tfdt box, we'll use the one
3093 * from the mfra seek table */
3094 GST_INFO_OBJECT (stream->pad, "pending seek ts = %" GST_TIME_FORMAT,
3095 GST_TIME_ARGS (stream->pending_seek->ts));
3097 /* FIXME: this is not fully correct, the timestamp refers to the random
3098 * access sample refered to in the tfra entry, which may not necessarily
3099 * be the first sample in the tfrag/trun (but hopefully/usually is) */
3100 timestamp = GSTTIME_TO_QTSTREAMTIME (stream, stream->pending_seek->ts);
3105 gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
3106 GST_INFO_OBJECT (stream->pad, "first sample ts %" GST_TIME_FORMAT,
3107 GST_TIME_ARGS (gst_ts));
3109 /* subsequent fragments extend stream */
3111 stream->samples[stream->n_samples - 1].timestamp +
3112 stream->samples[stream->n_samples - 1].duration;
3114 gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
3115 GST_INFO_OBJECT (qtdemux, "first sample ts %" GST_TIME_FORMAT
3116 " (extends previous samples)", GST_TIME_ARGS (gst_ts));
3120 sample = stream->samples + stream->n_samples;
3121 for (i = 0; i < samples_count; i++) {
3122 guint32 dur, size, sflags, ct;
3124 /* first read sample data */
3125 if (flags & TR_SAMPLE_DURATION) {
3126 dur = QT_UINT32 (data + dur_offset);
3128 dur = d_sample_duration;
3130 if (flags & TR_SAMPLE_SIZE) {
3131 size = QT_UINT32 (data + size_offset);
3133 size = d_sample_size;
3135 if (flags & TR_FIRST_SAMPLE_FLAGS) {
3137 sflags = first_flags;
3139 sflags = d_sample_flags;
3141 } else if (flags & TR_SAMPLE_FLAGS) {
3142 sflags = QT_UINT32 (data + flags_offset);
3144 sflags = d_sample_flags;
3146 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
3147 ct = QT_UINT32 (data + ct_offset);
3153 /* fill the sample information */
3154 sample->offset = *running_offset;
3155 sample->pts_offset = ct;
3156 sample->size = size;
3157 sample->timestamp = timestamp;
3158 sample->duration = dur;
3159 /* sample-is-difference-sample */
3160 /* ismv seems to use 0x40 for keyframe, 0xc0 for non-keyframe,
3161 * now idea how it relates to bitfield other than massive LE/BE confusion */
3162 sample->keyframe = ismv ? ((sflags & 0xff) == 0x40) : !(sflags & 0x10000);
3163 *running_offset += size;
3165 stream->duration_moof += dur;
3169 /* Update total duration if needed */
3170 check_update_duration (qtdemux, QTSTREAMTIME_TO_GSTTIME (stream, timestamp));
3172 stream->n_samples += samples_count;
3173 stream->n_samples_moof += samples_count;
3175 if (stream->pending_seek != NULL)
3176 stream->pending_seek = NULL;
3182 GST_WARNING_OBJECT (qtdemux, "failed to parse trun");
3187 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
3193 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
3194 "be larger than %uMB (broken file?)", stream->n_samples,
3195 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
3200 /* find stream with @id */
3201 static inline QtDemuxStream *
3202 qtdemux_find_stream (GstQTDemux * qtdemux, guint32 id)
3204 QtDemuxStream *stream;
3208 if (G_UNLIKELY (!id)) {
3209 GST_DEBUG_OBJECT (qtdemux, "invalid track id 0");
3213 /* try to get it fast and simple */
3214 if (G_LIKELY (id <= qtdemux->n_streams)) {
3215 stream = qtdemux->streams[id - 1];
3216 if (G_LIKELY (stream->track_id == id))
3220 /* linear search otherwise */
3221 for (i = 0; i < qtdemux->n_streams; i++) {
3222 stream = qtdemux->streams[i];
3223 if (stream->track_id == id)
3226 if (qtdemux->mss_mode) {
3227 /* mss should have only 1 stream anyway */
3228 return qtdemux->streams[0];
3235 qtdemux_parse_mfhd (GstQTDemux * qtdemux, GstByteReader * mfhd,
3236 guint32 * fragment_number)
3238 if (!gst_byte_reader_skip (mfhd, 4))
3240 if (!gst_byte_reader_get_uint32_be (mfhd, fragment_number))
3245 GST_WARNING_OBJECT (qtdemux, "Failed to parse mfhd atom");
3251 qtdemux_parse_tfhd (GstQTDemux * qtdemux, GstByteReader * tfhd,
3252 QtDemuxStream ** stream, guint32 * default_sample_duration,
3253 guint32 * default_sample_size, guint32 * default_sample_flags,
3254 gint64 * base_offset)
3257 guint32 track_id = 0;
3259 if (!gst_byte_reader_skip (tfhd, 1) ||
3260 !gst_byte_reader_get_uint24_be (tfhd, &flags))
3263 if (!gst_byte_reader_get_uint32_be (tfhd, &track_id))
3266 *stream = qtdemux_find_stream (qtdemux, track_id);
3267 if (G_UNLIKELY (!*stream))
3268 goto unknown_stream;
3270 if (flags & TF_DEFAULT_BASE_IS_MOOF)
3271 *base_offset = qtdemux->moof_offset;
3273 if (flags & TF_BASE_DATA_OFFSET)
3274 if (!gst_byte_reader_get_uint64_be (tfhd, (guint64 *) base_offset))
3277 /* obtain stream defaults */
3278 qtdemux_parse_trex (qtdemux, *stream,
3279 default_sample_duration, default_sample_size, default_sample_flags);
3281 /* FIXME: Handle TF_SAMPLE_DESCRIPTION_INDEX properly */
3282 if (flags & TF_SAMPLE_DESCRIPTION_INDEX)
3283 if (!gst_byte_reader_skip (tfhd, 4))
3286 if (flags & TF_DEFAULT_SAMPLE_DURATION)
3287 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_duration))
3290 if (flags & TF_DEFAULT_SAMPLE_SIZE)
3291 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_size))
3294 if (flags & TF_DEFAULT_SAMPLE_FLAGS)
3295 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_flags))
3302 GST_WARNING_OBJECT (qtdemux, "invalid track fragment header");
3307 GST_DEBUG_OBJECT (qtdemux, "unknown stream in tfhd");
3313 qtdemux_parse_tfdt (GstQTDemux * qtdemux, GstByteReader * br,
3314 guint64 * decode_time)
3316 guint32 version = 0;
3318 if (!gst_byte_reader_get_uint32_be (br, &version))
3323 if (!gst_byte_reader_get_uint64_be (br, decode_time))
3326 guint32 dec_time = 0;
3327 if (!gst_byte_reader_get_uint32_be (br, &dec_time))
3329 *decode_time = dec_time;
3332 GST_INFO_OBJECT (qtdemux, "Track fragment decode time: %" G_GUINT64_FORMAT,
3339 GST_DEBUG_OBJECT (qtdemux, "parsing tfdt failed");
3344 /* Returns a pointer to a GstStructure containing the properties of
3345 * the stream sample identified by @sample_index. The caller must unref
3346 * the returned object after use. Returns NULL if unsuccessful. */
3347 static GstStructure *
3348 qtdemux_get_cenc_sample_properties (GstQTDemux * qtdemux,
3349 QtDemuxStream * stream, guint sample_index)
3351 QtDemuxCencSampleSetInfo *info = NULL;
3353 g_return_val_if_fail (stream != NULL, NULL);
3354 g_return_val_if_fail (stream->protected, NULL);
3355 g_return_val_if_fail (stream->protection_scheme_info != NULL, NULL);
3357 info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
3359 /* Currently, cenc properties for groups of samples are not supported, so
3360 * simply return a copy of the default sample properties */
3361 return gst_structure_copy (info->default_properties);
3364 /* Parses the sizes of sample auxiliary information contained within a stream,
3365 * as given in a saiz box. Returns array of sample_count guint8 size values,
3366 * or NULL on failure */
3368 qtdemux_parse_saiz (GstQTDemux * qtdemux, QtDemuxStream * stream,
3369 GstByteReader * br, guint32 * sample_count)
3373 guint8 default_info_size;
3375 g_return_val_if_fail (qtdemux != NULL, NULL);
3376 g_return_val_if_fail (stream != NULL, NULL);
3377 g_return_val_if_fail (br != NULL, NULL);
3378 g_return_val_if_fail (sample_count != NULL, NULL);
3380 if (!gst_byte_reader_get_uint32_be (br, &flags))
3384 /* aux_info_type and aux_info_type_parameter are ignored */
3385 if (!gst_byte_reader_skip (br, 8))
3389 if (!gst_byte_reader_get_uint8 (br, &default_info_size))
3391 GST_DEBUG_OBJECT (qtdemux, "default_info_size: %u", default_info_size);
3393 if (!gst_byte_reader_get_uint32_be (br, sample_count))
3395 GST_DEBUG_OBJECT (qtdemux, "sample_count: %u", *sample_count);
3398 if (default_info_size == 0) {
3399 if (!gst_byte_reader_dup_data (br, *sample_count, &info_sizes)) {
3403 info_sizes = g_new (guint8, *sample_count);
3404 memset (info_sizes, default_info_size, *sample_count);
3410 /* Parses the offset of sample auxiliary information contained within a stream,
3411 * as given in a saio box. Returns TRUE if successful; FALSE otherwise. */
3413 qtdemux_parse_saio (GstQTDemux * qtdemux, QtDemuxStream * stream,
3414 GstByteReader * br, guint32 * info_type, guint32 * info_type_parameter,
3419 guint32 aux_info_type = 0;
3420 guint32 aux_info_type_parameter = 0;
3421 guint32 entry_count;
3424 const guint8 *aux_info_type_data = NULL;
3426 g_return_val_if_fail (qtdemux != NULL, FALSE);
3427 g_return_val_if_fail (stream != NULL, FALSE);
3428 g_return_val_if_fail (br != NULL, FALSE);
3429 g_return_val_if_fail (offset != NULL, FALSE);
3431 if (!gst_byte_reader_get_uint8 (br, &version))
3434 if (!gst_byte_reader_get_uint24_be (br, &flags))
3439 if (!gst_byte_reader_get_data (br, 4, &aux_info_type_data))
3441 aux_info_type = QT_FOURCC (aux_info_type_data);
3443 if (!gst_byte_reader_get_uint32_be (br, &aux_info_type_parameter))
3445 } else if (stream->protected) {
3446 aux_info_type = stream->protection_scheme_type;
3448 aux_info_type = stream->fourcc;
3452 *info_type = aux_info_type;
3453 if (info_type_parameter)
3454 *info_type_parameter = aux_info_type_parameter;
3456 GST_DEBUG_OBJECT (qtdemux, "aux_info_type: '%" GST_FOURCC_FORMAT "', "
3457 "aux_info_type_parameter: %#06x",
3458 GST_FOURCC_ARGS (aux_info_type), aux_info_type_parameter);
3460 if (!gst_byte_reader_get_uint32_be (br, &entry_count))
3463 if (entry_count != 1) {
3464 GST_ERROR_OBJECT (qtdemux, "multiple offsets are not supported");
3469 if (!gst_byte_reader_get_uint32_be (br, &off_32))
3471 *offset = (guint64) off_32;
3473 if (!gst_byte_reader_get_uint64_be (br, &off_64))
3478 GST_DEBUG_OBJECT (qtdemux, "offset: %" G_GUINT64_FORMAT, *offset);
3483 qtdemux_gst_structure_free (GstStructure * gststructure)
3486 gst_structure_free (gststructure);
3490 /* Parses auxiliary information relating to samples protected using Common
3491 * Encryption (cenc); the format of this information is defined in
3492 * ISO/IEC 23001-7. Returns TRUE if successful; FALSE otherwise. */
3494 qtdemux_parse_cenc_aux_info (GstQTDemux * qtdemux, QtDemuxStream * stream,
3495 GstByteReader * br, guint8 * info_sizes, guint32 sample_count)
3497 QtDemuxCencSampleSetInfo *ss_info = NULL;
3501 g_return_val_if_fail (qtdemux != NULL, FALSE);
3502 g_return_val_if_fail (stream != NULL, FALSE);
3503 g_return_val_if_fail (br != NULL, FALSE);
3504 g_return_val_if_fail (stream->protected, FALSE);
3505 g_return_val_if_fail (stream->protection_scheme_info != NULL, FALSE);
3507 ss_info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
3509 if (ss_info->crypto_info) {
3510 GST_LOG_OBJECT (qtdemux, "unreffing existing crypto_info");
3511 g_ptr_array_free (ss_info->crypto_info, TRUE);
3514 ss_info->crypto_info =
3515 g_ptr_array_new_full (sample_count,
3516 (GDestroyNotify) qtdemux_gst_structure_free);
3518 for (i = 0; i < sample_count; ++i) {
3519 GstStructure *properties;
3520 guint16 n_subsamples = 0;
3525 properties = qtdemux_get_cenc_sample_properties (qtdemux, stream, i);
3526 if (properties == NULL) {
3527 GST_ERROR_OBJECT (qtdemux, "failed to get properties for sample %u", i);
3530 if (!gst_structure_get_uint (properties, "iv_size", &iv_size)) {
3531 GST_ERROR_OBJECT (qtdemux, "failed to get iv_size for sample %u", i);
3532 gst_structure_free (properties);
3535 if (!gst_byte_reader_dup_data (br, iv_size, &data)) {
3536 GST_ERROR_OBJECT (qtdemux, "failed to get IV for sample %u", i);
3537 gst_structure_free (properties);
3540 buf = gst_buffer_new_wrapped (data, iv_size);
3541 gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL);
3542 gst_buffer_unref (buf);
3543 size = info_sizes[i];
3544 if (size > iv_size) {
3545 if (!gst_byte_reader_get_uint16_be (br, &n_subsamples)
3546 || !(n_subsamples > 0)) {
3547 gst_structure_free (properties);
3548 GST_ERROR_OBJECT (qtdemux,
3549 "failed to get subsample count for sample %u", i);
3552 GST_LOG_OBJECT (qtdemux, "subsample count: %u", n_subsamples);
3553 if (!gst_byte_reader_dup_data (br, n_subsamples * 6, &data)) {
3554 GST_ERROR_OBJECT (qtdemux, "failed to get subsample data for sample %u",
3556 gst_structure_free (properties);
3559 buf = gst_buffer_new_wrapped (data, n_subsamples * 6);
3561 gst_structure_free (properties);
3564 gst_structure_set (properties,
3565 "subsample_count", G_TYPE_UINT, n_subsamples,
3566 "subsamples", GST_TYPE_BUFFER, buf, NULL);
3567 gst_buffer_unref (buf);
3569 gst_structure_set (properties, "subsample_count", G_TYPE_UINT, 0, NULL);
3571 g_ptr_array_add (ss_info->crypto_info, properties);
3576 /* Converts a UUID in raw byte form to a string representation, as defined in
3577 * RFC 4122. The caller takes ownership of the returned string and is
3578 * responsible for freeing it after use. */
3580 qtdemux_uuid_bytes_to_string (gconstpointer uuid_bytes)
3582 const guint8 *uuid = (const guint8 *) uuid_bytes;
3584 return g_strdup_printf ("%02x%02x%02x%02x-%02x%02x-%02x%02x-"
3585 "%02x%02x-%02x%02x%02x%02x%02x%02x",
3586 uuid[0], uuid[1], uuid[2], uuid[3],
3587 uuid[4], uuid[5], uuid[6], uuid[7],
3588 uuid[8], uuid[9], uuid[10], uuid[11],
3589 uuid[12], uuid[13], uuid[14], uuid[15]);
3592 /* Parses a Protection System Specific Header box (pssh), as defined in the
3593 * Common Encryption (cenc) standard (ISO/IEC 23001-7), which contains
3594 * information needed by a specific content protection system in order to
3595 * decrypt cenc-protected tracks. Returns TRUE if successful; FALSE
3598 qtdemux_parse_pssh (GstQTDemux * qtdemux, GNode * node)
3600 gchar *sysid_string;
3601 guint32 pssh_size = QT_UINT32 (node->data);
3602 GstBuffer *pssh = NULL;
3603 GstEvent *event = NULL;
3604 guint32 parent_box_type;
3607 if (G_UNLIKELY (pssh_size < 32U)) {
3608 GST_ERROR_OBJECT (qtdemux, "invalid box size");
3613 qtdemux_uuid_bytes_to_string ((const guint8 *) node->data + 12);
3615 gst_qtdemux_append_protection_system_id (qtdemux, sysid_string);
3617 pssh = gst_buffer_new_wrapped (g_memdup (node->data, pssh_size), pssh_size);
3618 GST_LOG_OBJECT (qtdemux, "cenc pssh size: %" G_GSIZE_FORMAT,
3619 gst_buffer_get_size (pssh));
3621 parent_box_type = QT_FOURCC ((const guint8 *) node->parent->data + 4);
3623 /* Push an event containing the pssh box onto the queues of all streams. */
3624 event = gst_event_new_protection (sysid_string, pssh,
3625 (parent_box_type == FOURCC_moov) ? "isobmff/moov" : "isobmff/moof");
3626 for (i = 0; i < qtdemux->n_streams; ++i) {
3627 g_queue_push_tail (&qtdemux->streams[i]->protection_scheme_event_queue,
3628 gst_event_ref (event));
3630 g_free (sysid_string);
3631 gst_event_unref (event);
3632 gst_buffer_unref (pssh);
3637 qtdemux_parse_moof (GstQTDemux * qtdemux, const guint8 * buffer, guint length,
3638 guint64 moof_offset, QtDemuxStream * stream)
3640 GNode *moof_node, *traf_node, *tfhd_node, *trun_node, *tfdt_node, *mfhd_node;
3642 GstByteReader mfhd_data, trun_data, tfhd_data, tfdt_data;
3643 GNode *saiz_node, *saio_node, *pssh_node;
3644 GstByteReader saiz_data, saio_data;
3645 guint32 ds_size = 0, ds_duration = 0, ds_flags = 0;
3646 gint64 base_offset, running_offset;
3649 /* NOTE @stream ignored */
3651 moof_node = g_node_new ((guint8 *) buffer);
3652 qtdemux_parse_node (qtdemux, moof_node, buffer, length);
3653 qtdemux_node_dump (qtdemux, moof_node);
3655 /* Get fragment number from mfhd and check it's valid */
3657 qtdemux_tree_get_child_by_type_full (moof_node, FOURCC_mfhd, &mfhd_data);
3658 if (mfhd_node == NULL)
3660 if (!qtdemux_parse_mfhd (qtdemux, &mfhd_data, &frag_num))
3662 GST_DEBUG_OBJECT (qtdemux, "Fragment #%d", frag_num);
3664 /* unknown base_offset to start with */
3665 base_offset = running_offset = -1;
3666 traf_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_traf);
3668 guint64 decode_time = 0;
3670 /* Fragment Header node */
3672 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfhd,
3676 if (!qtdemux_parse_tfhd (qtdemux, &tfhd_data, &stream, &ds_duration,
3677 &ds_size, &ds_flags, &base_offset))
3680 /* The following code assumes at most a single set of sample auxiliary
3681 * data in the fragment (consisting of a saiz box and a corresponding saio
3682 * box); in theory, however, there could be multiple sets of sample
3683 * auxiliary data in a fragment. */
3685 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saiz,
3688 guint32 info_type = 0;
3690 guint32 info_type_parameter = 0;
3692 g_free (qtdemux->cenc_aux_info_sizes);
3694 qtdemux->cenc_aux_info_sizes =
3695 qtdemux_parse_saiz (qtdemux, stream, &saiz_data,
3696 &qtdemux->cenc_aux_sample_count);
3697 if (qtdemux->cenc_aux_info_sizes == NULL) {
3698 GST_ERROR_OBJECT (qtdemux, "failed to parse saiz box");
3702 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saio,
3705 GST_ERROR_OBJECT (qtdemux, "saiz box without a corresponding saio box");
3706 g_free (qtdemux->cenc_aux_info_sizes);
3707 qtdemux->cenc_aux_info_sizes = NULL;
3711 if (G_UNLIKELY (!qtdemux_parse_saio (qtdemux, stream, &saio_data,
3712 &info_type, &info_type_parameter, &offset))) {
3713 GST_ERROR_OBJECT (qtdemux, "failed to parse saio box");
3714 g_free (qtdemux->cenc_aux_info_sizes);
3715 qtdemux->cenc_aux_info_sizes = NULL;
3718 if (base_offset > -1 && base_offset > qtdemux->moof_offset)
3719 offset += (guint64) (base_offset - qtdemux->moof_offset);
3720 if (info_type == FOURCC_cenc && info_type_parameter == 0U) {
3722 if (offset > length) {
3723 GST_DEBUG_OBJECT (qtdemux, "cenc auxiliary info stored out of moof");
3724 qtdemux->cenc_aux_info_offset = offset;
3726 gst_byte_reader_init (&br, buffer + offset, length - offset);
3727 if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
3728 qtdemux->cenc_aux_info_sizes,
3729 qtdemux->cenc_aux_sample_count)) {
3730 GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
3731 g_free (qtdemux->cenc_aux_info_sizes);
3732 qtdemux->cenc_aux_info_sizes = NULL;
3740 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfdt,
3743 GstClockTime decode_time_ts;
3745 /* We'll use decode_time to interpolate timestamps
3746 * in case the input timestamps are missing */
3747 qtdemux_parse_tfdt (qtdemux, &tfdt_data, &decode_time);
3749 decode_time_ts = QTSTREAMTIME_TO_GSTTIME (stream, decode_time);
3751 GST_DEBUG_OBJECT (qtdemux, "decode time %" G_GINT64_FORMAT
3752 " (%" GST_TIME_FORMAT ")", decode_time,
3753 GST_TIME_ARGS (decode_time_ts));
3755 /* Discard the fragment buffer timestamp info to avoid using it.
3756 * Rely on tfdt instead as it is more accurate than the timestamp
3757 * that is fetched from a manifest/playlist and is usually
3759 qtdemux->fragment_start = -1;
3762 if (G_UNLIKELY (!stream)) {
3763 /* we lost track of offset, we'll need to regain it,
3764 * but can delay complaining until later or avoid doing so altogether */
3768 if (G_UNLIKELY (base_offset < -1))
3771 if (qtdemux->upstream_format_is_time)
3772 gst_qtdemux_stream_flush_samples_data (qtdemux, stream);
3774 /* initialise moof sample data */
3775 stream->n_samples_moof = 0;
3776 stream->duration_moof = 0;
3778 /* Track Run node */
3780 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_trun,
3783 qtdemux_parse_trun (qtdemux, &trun_data, stream,
3784 ds_duration, ds_size, ds_flags, moof_offset, length, &base_offset,
3785 &running_offset, decode_time);
3786 /* iterate all siblings */
3787 trun_node = qtdemux_tree_get_sibling_by_type_full (trun_node, FOURCC_trun,
3791 uuid_node = qtdemux_tree_get_child_by_type (traf_node, FOURCC_uuid);
3793 guint8 *uuid_buffer = (guint8 *) uuid_node->data;
3794 guint32 box_length = QT_UINT32 (uuid_buffer);
3796 qtdemux_parse_uuid (qtdemux, uuid_buffer, box_length);
3799 /* if no new base_offset provided for next traf,
3800 * base is end of current traf */
3801 base_offset = running_offset;
3802 running_offset = -1;
3804 if (stream->n_samples_moof && stream->duration_moof)
3805 stream->new_caps = TRUE;
3808 /* iterate all siblings */
3809 traf_node = qtdemux_tree_get_sibling_by_type (traf_node, FOURCC_traf);
3812 /* parse any protection system info */
3813 pssh_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_pssh);
3815 GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
3816 qtdemux_parse_pssh (qtdemux, pssh_node);
3817 pssh_node = qtdemux_tree_get_sibling_by_type (pssh_node, FOURCC_pssh);
3820 g_node_destroy (moof_node);
3825 GST_DEBUG_OBJECT (qtdemux, "missing tfhd box");
3830 GST_DEBUG_OBJECT (qtdemux, "Missing mfhd box");
3835 GST_DEBUG_OBJECT (qtdemux, "lost offset");
3840 g_node_destroy (moof_node);
3841 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
3842 (_("This file is corrupt and cannot be played.")), (NULL));
3848 /* might be used if some day we actually use mfra & co
3849 * for random access to fragments,
3850 * but that will require quite some modifications and much less relying
3851 * on a sample array */
3855 qtdemux_parse_tfra (GstQTDemux * qtdemux, GNode * tfra_node)
3857 QtDemuxStream *stream;
3858 guint32 ver_flags, track_id, len, num_entries, i;
3859 guint value_size, traf_size, trun_size, sample_size;
3860 guint64 time = 0, moof_offset = 0;
3862 GstBuffer *buf = NULL;
3867 gst_byte_reader_init (&tfra, tfra_node->data, QT_UINT32 (tfra_node->data));
3869 if (!gst_byte_reader_skip (&tfra, 8))
3872 if (!gst_byte_reader_get_uint32_be (&tfra, &ver_flags))
3875 if (!gst_byte_reader_get_uint32_be (&tfra, &track_id)
3876 || !gst_byte_reader_get_uint32_be (&tfra, &len)
3877 || !gst_byte_reader_get_uint32_be (&tfra, &num_entries))
3880 GST_DEBUG_OBJECT (qtdemux, "parsing tfra box for track id %u", track_id);
3882 stream = qtdemux_find_stream (qtdemux, track_id);
3884 goto unknown_trackid;
3886 value_size = ((ver_flags >> 24) == 1) ? sizeof (guint64) : sizeof (guint32);
3887 sample_size = (len & 3) + 1;
3888 trun_size = ((len & 12) >> 2) + 1;
3889 traf_size = ((len & 48) >> 4) + 1;
3891 GST_DEBUG_OBJECT (qtdemux, "%u entries, sizes: value %u, traf %u, trun %u, "
3892 "sample %u", num_entries, value_size, traf_size, trun_size, sample_size);
3894 if (num_entries == 0)
3897 if (!qt_atom_parser_has_chunks (&tfra, num_entries,
3898 value_size + value_size + traf_size + trun_size + sample_size))
3901 g_free (stream->ra_entries);
3902 stream->ra_entries = g_new (QtDemuxRandomAccessEntry, num_entries);
3903 stream->n_ra_entries = num_entries;
3905 for (i = 0; i < num_entries; i++) {
3906 qt_atom_parser_get_offset (&tfra, value_size, &time);
3907 qt_atom_parser_get_offset (&tfra, value_size, &moof_offset);
3908 qt_atom_parser_get_uint_with_size_unchecked (&tfra, traf_size);
3909 qt_atom_parser_get_uint_with_size_unchecked (&tfra, trun_size);
3910 qt_atom_parser_get_uint_with_size_unchecked (&tfra, sample_size);
3912 time = QTSTREAMTIME_TO_GSTTIME (stream, time);
3914 GST_LOG_OBJECT (qtdemux, "fragment time: %" GST_TIME_FORMAT ", "
3915 " moof_offset: %" G_GUINT64_FORMAT, GST_TIME_ARGS (time), moof_offset);
3917 stream->ra_entries[i].ts = time;
3918 stream->ra_entries[i].moof_offset = moof_offset;
3920 /* don't want to go through the entire file and read all moofs at startup */
3922 ret = gst_qtdemux_pull_atom (qtdemux, moof_offset, 0, &buf);
3923 if (ret != GST_FLOW_OK)
3925 qtdemux_parse_moof (qtdemux, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf),
3926 moof_offset, stream);
3927 gst_buffer_unref (buf);
3931 check_update_duration (qtdemux, time);
3938 GST_WARNING_OBJECT (qtdemux, "Couldn't find stream for track %u", track_id);
3943 GST_WARNING_OBJECT (qtdemux, "broken traf box, ignoring");
3948 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
3954 qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux)
3956 GstMapInfo mfro_map = GST_MAP_INFO_INIT;
3957 GstMapInfo mfra_map = GST_MAP_INFO_INIT;
3958 GstBuffer *mfro = NULL, *mfra = NULL;
3960 gboolean ret = FALSE;
3961 GNode *mfra_node, *tfra_node;
3962 guint64 mfra_offset = 0;
3963 guint32 fourcc, mfra_size;
3966 /* query upstream size in bytes */
3967 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &len))
3968 goto size_query_failed;
3970 /* mfro box should be at the very end of the file */
3971 flow = gst_qtdemux_pull_atom (qtdemux, len - 16, 16, &mfro);
3972 if (flow != GST_FLOW_OK)
3975 gst_buffer_map (mfro, &mfro_map, GST_MAP_READ);
3977 fourcc = QT_FOURCC (mfro_map.data + 4);
3978 if (fourcc != FOURCC_mfro)
3981 GST_INFO_OBJECT (qtdemux, "Found mfro box");
3982 if (mfro_map.size < 16)
3983 goto invalid_mfro_size;
3985 mfra_size = QT_UINT32 (mfro_map.data + 12);
3986 if (mfra_size >= len)
3987 goto invalid_mfra_size;
3989 mfra_offset = len - mfra_size;
3991 GST_INFO_OBJECT (qtdemux, "mfra offset: %" G_GUINT64_FORMAT ", size %u",
3992 mfra_offset, mfra_size);
3994 /* now get and parse mfra box */
3995 flow = gst_qtdemux_pull_atom (qtdemux, mfra_offset, mfra_size, &mfra);
3996 if (flow != GST_FLOW_OK)
3999 gst_buffer_map (mfra, &mfra_map, GST_MAP_READ);
4001 mfra_node = g_node_new ((guint8 *) mfra_map.data);
4002 qtdemux_parse_node (qtdemux, mfra_node, mfra_map.data, mfra_map.size);
4004 tfra_node = qtdemux_tree_get_child_by_type (mfra_node, FOURCC_tfra);
4007 qtdemux_parse_tfra (qtdemux, tfra_node);
4008 /* iterate all siblings */
4009 tfra_node = qtdemux_tree_get_sibling_by_type (tfra_node, FOURCC_tfra);
4011 g_node_destroy (mfra_node);
4013 GST_INFO_OBJECT (qtdemux, "parsed movie fragment random access box (mfra)");
4019 if (mfro_map.memory != NULL)
4020 gst_buffer_unmap (mfro, &mfro_map);
4021 gst_buffer_unref (mfro);
4024 if (mfra_map.memory != NULL)
4025 gst_buffer_unmap (mfra, &mfra_map);
4026 gst_buffer_unref (mfra);
4033 GST_WARNING_OBJECT (qtdemux, "could not query upstream size");
4038 GST_WARNING_OBJECT (qtdemux, "mfro size is too small");
4043 GST_WARNING_OBJECT (qtdemux, "mfra_size in mfro box is invalid");
4048 GST_WARNING_OBJECT (qtdemux, "bogus mfra offset or size, broken file");
4054 add_offset (guint64 offset, guint64 advance)
4056 /* Avoid 64-bit overflow by clamping */
4057 if (offset > G_MAXUINT64 - advance)
4059 return offset + advance;
4062 static GstFlowReturn
4063 gst_qtdemux_loop_state_header (GstQTDemux * qtdemux)
4067 GstBuffer *buf = NULL;
4068 GstFlowReturn ret = GST_FLOW_OK;
4069 guint64 cur_offset = qtdemux->offset;
4072 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, 16, &buf);
4073 if (G_UNLIKELY (ret != GST_FLOW_OK))
4075 gst_buffer_map (buf, &map, GST_MAP_READ);
4076 if (G_LIKELY (map.size >= 8))
4077 extract_initial_length_and_fourcc (map.data, map.size, &length, &fourcc);
4078 gst_buffer_unmap (buf, &map);
4079 gst_buffer_unref (buf);
4081 /* maybe we already got most we needed, so only consider this eof */
4082 if (G_UNLIKELY (length == 0)) {
4083 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
4084 (_("Invalid atom size.")),
4085 ("Header atom '%" GST_FOURCC_FORMAT "' has empty length",
4086 GST_FOURCC_ARGS (fourcc)));
4093 /* record for later parsing when needed */
4094 if (!qtdemux->moof_offset) {
4095 qtdemux->moof_offset = qtdemux->offset;
4097 if (qtdemux_pull_mfro_mfra (qtdemux)) {
4100 qtdemux->offset += length; /* skip moof and keep going */
4102 if (qtdemux->got_moov) {
4103 GST_INFO_OBJECT (qtdemux, "moof header, got moov, done with headers");
4114 GST_LOG_OBJECT (qtdemux,
4115 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
4116 GST_FOURCC_ARGS (fourcc), cur_offset);
4117 qtdemux->offset = add_offset (qtdemux->offset, length);
4122 GstBuffer *moov = NULL;
4124 if (qtdemux->got_moov) {
4125 GST_DEBUG_OBJECT (qtdemux, "Skipping moov atom as we have one already");
4126 qtdemux->offset = add_offset (qtdemux->offset, length);
4130 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, length, &moov);
4131 if (ret != GST_FLOW_OK)
4133 gst_buffer_map (moov, &map, GST_MAP_READ);
4135 if (length != map.size) {
4136 /* Some files have a 'moov' atom at the end of the file which contains
4137 * a terminal 'free' atom where the body of the atom is missing.
4138 * Check for, and permit, this special case.
4140 if (map.size >= 8) {
4141 guint8 *final_data = map.data + (map.size - 8);
4142 guint32 final_length = QT_UINT32 (final_data);
4143 guint32 final_fourcc = QT_FOURCC (final_data + 4);
4145 if (final_fourcc == FOURCC_free
4146 && map.size + final_length - 8 == length) {
4147 /* Ok, we've found that special case. Allocate a new buffer with
4148 * that free atom actually present. */
4149 GstBuffer *newmoov = gst_buffer_new_and_alloc (length);
4150 gst_buffer_fill (newmoov, 0, map.data, map.size);
4151 gst_buffer_memset (newmoov, map.size, 0, final_length - 8);
4152 gst_buffer_unmap (moov, &map);
4153 gst_buffer_unref (moov);
4155 gst_buffer_map (moov, &map, GST_MAP_READ);
4160 if (length != map.size) {
4161 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4162 (_("This file is incomplete and cannot be played.")),
4163 ("We got less than expected (received %" G_GSIZE_FORMAT
4164 ", wanted %u, offset %" G_GUINT64_FORMAT ")", map.size,
4165 (guint) length, cur_offset));
4166 gst_buffer_unmap (moov, &map);
4167 gst_buffer_unref (moov);
4168 ret = GST_FLOW_ERROR;
4171 qtdemux->offset += length;
4173 qtdemux_parse_moov (qtdemux, map.data, length);
4174 qtdemux_node_dump (qtdemux, qtdemux->moov_node);
4176 qtdemux_parse_tree (qtdemux);
4177 g_node_destroy (qtdemux->moov_node);
4178 gst_buffer_unmap (moov, &map);
4179 gst_buffer_unref (moov);
4180 qtdemux->moov_node = NULL;
4181 qtdemux->got_moov = TRUE;
4187 GstBuffer *ftyp = NULL;
4189 /* extract major brand; might come in handy for ISO vs QT issues */
4190 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &ftyp);
4191 if (ret != GST_FLOW_OK)
4193 qtdemux->offset += length;
4194 gst_buffer_map (ftyp, &map, GST_MAP_READ);
4195 qtdemux_parse_ftyp (qtdemux, map.data, map.size);
4196 gst_buffer_unmap (ftyp, &map);
4197 gst_buffer_unref (ftyp);
4202 GstBuffer *uuid = NULL;
4204 /* uuid are extension atoms */
4205 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &uuid);
4206 if (ret != GST_FLOW_OK)
4208 qtdemux->offset += length;
4209 gst_buffer_map (uuid, &map, GST_MAP_READ);
4210 qtdemux_parse_uuid (qtdemux, map.data, map.size);
4211 gst_buffer_unmap (uuid, &map);
4212 gst_buffer_unref (uuid);
4217 GstBuffer *sidx = NULL;
4218 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &sidx);
4219 if (ret != GST_FLOW_OK)
4221 qtdemux->offset += length;
4222 gst_buffer_map (sidx, &map, GST_MAP_READ);
4223 qtdemux_parse_sidx (qtdemux, map.data, map.size);
4224 gst_buffer_unmap (sidx, &map);
4225 gst_buffer_unref (sidx);
4230 GstBuffer *unknown = NULL;
4232 GST_LOG_OBJECT (qtdemux,
4233 "unknown %08x '%" GST_FOURCC_FORMAT "' of size %" G_GUINT64_FORMAT
4234 " at %" G_GUINT64_FORMAT, fourcc, GST_FOURCC_ARGS (fourcc), length,
4236 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &unknown);
4237 if (ret != GST_FLOW_OK)
4239 gst_buffer_map (unknown, &map, GST_MAP_READ);
4240 GST_MEMDUMP ("Unknown tag", map.data, map.size);
4241 gst_buffer_unmap (unknown, &map);
4242 gst_buffer_unref (unknown);
4243 qtdemux->offset += length;
4249 if (ret == GST_FLOW_EOS && (qtdemux->got_moov || qtdemux->media_caps)) {
4250 /* digested all data, show what we have */
4251 qtdemux_prepare_streams (qtdemux);
4252 ret = qtdemux_expose_streams (qtdemux);
4254 qtdemux->state = QTDEMUX_STATE_MOVIE;
4255 GST_DEBUG_OBJECT (qtdemux, "switching state to STATE_MOVIE (%d)",
4262 /* Seeks to the previous keyframe of the indexed stream and
4263 * aligns other streams with respect to the keyframe timestamp
4264 * of indexed stream. Only called in case of Reverse Playback
4266 static GstFlowReturn
4267 gst_qtdemux_seek_to_previous_keyframe (GstQTDemux * qtdemux)
4270 guint32 seg_idx = 0, k_index = 0;
4271 guint32 ref_seg_idx, ref_k_index;
4272 GstClockTime k_pos = 0, last_stop = 0;
4273 QtDemuxSegment *seg = NULL;
4274 QtDemuxStream *ref_str = NULL;
4275 guint64 seg_media_start_mov; /* segment media start time in mov format */
4278 /* Now we choose an arbitrary stream, get the previous keyframe timestamp
4279 * and finally align all the other streams on that timestamp with their
4280 * respective keyframes */
4281 for (n = 0; n < qtdemux->n_streams; n++) {
4282 QtDemuxStream *str = qtdemux->streams[n];
4284 /* No candidate yet, take the first stream */
4290 /* So that stream has a segment, we prefer video streams */
4291 if (str->subtype == FOURCC_vide) {
4297 if (G_UNLIKELY (!ref_str)) {
4298 GST_DEBUG_OBJECT (qtdemux, "couldn't find any stream");
4302 if (G_UNLIKELY (!ref_str->from_sample)) {
4303 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of the file");
4307 /* So that stream has been playing from from_sample to to_sample. We will
4308 * get the timestamp of the previous sample and search for a keyframe before
4309 * that. For audio streams we do an arbitrary jump in the past (10 samples) */
4310 if (ref_str->subtype == FOURCC_vide) {
4311 k_index = gst_qtdemux_find_keyframe (qtdemux, ref_str,
4312 ref_str->from_sample - 1);
4314 if (ref_str->from_sample >= 10)
4315 k_index = ref_str->from_sample - 10;
4321 ref_str->samples[k_index].timestamp +
4322 ref_str->samples[k_index].pts_offset;
4324 /* get current segment for that stream */
4325 seg = &ref_str->segments[ref_str->segment_index];
4326 /* Use segment start in original timescale for comparisons */
4327 seg_media_start_mov = seg->trak_media_start;
4329 GST_LOG_OBJECT (qtdemux, "keyframe index %u ts %" G_GUINT64_FORMAT
4330 " seg start %" G_GUINT64_FORMAT " %" GST_TIME_FORMAT "\n",
4331 k_index, target_ts, seg_media_start_mov,
4332 GST_TIME_ARGS (seg->media_start));
4334 /* Crawl back through segments to find the one containing this I frame */
4335 while (target_ts < seg_media_start_mov) {
4336 GST_DEBUG_OBJECT (qtdemux,
4337 "keyframe position (sample %u) is out of segment %u " " target %"
4338 G_GUINT64_FORMAT " seg start %" G_GUINT64_FORMAT, k_index,
4339 ref_str->segment_index, target_ts, seg_media_start_mov);
4341 if (G_UNLIKELY (!ref_str->segment_index)) {
4342 /* Reached first segment, let's consider it's EOS */
4345 ref_str->segment_index--;
4346 seg = &ref_str->segments[ref_str->segment_index];
4347 /* Use segment start in original timescale for comparisons */
4348 seg_media_start_mov = seg->trak_media_start;
4350 /* Calculate time position of the keyframe and where we should stop */
4352 QTSTREAMTIME_TO_GSTTIME (ref_str,
4353 target_ts - seg->trak_media_start) + seg->time;
4355 QTSTREAMTIME_TO_GSTTIME (ref_str,
4356 ref_str->samples[ref_str->from_sample].timestamp -
4357 seg->trak_media_start) + seg->time;
4359 GST_DEBUG_OBJECT (qtdemux, "preferred stream played from sample %u, "
4360 "now going to sample %u (pts %" GST_TIME_FORMAT ")", ref_str->from_sample,
4361 k_index, GST_TIME_ARGS (k_pos));
4363 /* Set last_stop with the keyframe timestamp we pushed of that stream */
4364 qtdemux->segment.position = last_stop;
4365 GST_DEBUG_OBJECT (qtdemux, "last_stop now is %" GST_TIME_FORMAT,
4366 GST_TIME_ARGS (last_stop));
4368 if (G_UNLIKELY (last_stop < qtdemux->segment.start)) {
4369 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of segment");
4373 ref_seg_idx = ref_str->segment_index;
4374 ref_k_index = k_index;
4376 /* Align them all on this */
4377 for (n = 0; n < qtdemux->n_streams; n++) {
4379 GstClockTime seg_time = 0;
4380 QtDemuxStream *str = qtdemux->streams[n];
4382 /* aligning reference stream again might lead to backing up to yet another
4383 * keyframe (due to timestamp rounding issues),
4384 * potentially putting more load on downstream; so let's try to avoid */
4385 if (str == ref_str) {
4386 seg_idx = ref_seg_idx;
4387 seg = &str->segments[seg_idx];
4388 k_index = ref_k_index;
4389 GST_DEBUG_OBJECT (qtdemux, "reference stream %d segment %d, "
4390 "sample at index %d", n, ref_str->segment_index, k_index);
4392 seg_idx = gst_qtdemux_find_segment (qtdemux, str, k_pos);
4393 GST_DEBUG_OBJECT (qtdemux,
4394 "stream %d align segment %d for keyframe pos %" GST_TIME_FORMAT, n,
4395 seg_idx, GST_TIME_ARGS (k_pos));
4397 /* get segment and time in the segment */
4398 seg = &str->segments[seg_idx];
4399 seg_time = k_pos - seg->time;
4401 /* get the media time in the segment.
4402 * No adjustment for empty "filler" segments */
4403 if (seg->media_start != GST_CLOCK_TIME_NONE)
4404 seg_time += seg->media_start;
4406 /* get the index of the sample with media time */
4407 index = gst_qtdemux_find_index_linear (qtdemux, str, seg_time);
4408 GST_DEBUG_OBJECT (qtdemux,
4409 "stream %d sample for %" GST_TIME_FORMAT " at %u", n,
4410 GST_TIME_ARGS (seg_time), index);
4412 /* find previous keyframe */
4413 k_index = gst_qtdemux_find_keyframe (qtdemux, str, index);
4416 /* Remember until where we want to go */
4417 str->to_sample = str->from_sample - 1;
4418 /* Define our time position */
4420 str->samples[k_index].timestamp + str->samples[k_index].pts_offset;
4421 str->time_position = QTSTREAMTIME_TO_GSTTIME (str, target_ts) + seg->time;
4422 if (seg->media_start != GST_CLOCK_TIME_NONE)
4423 str->time_position -= seg->media_start;
4425 /* Now seek back in time */
4426 gst_qtdemux_move_stream (qtdemux, str, k_index);
4427 GST_DEBUG_OBJECT (qtdemux, "stream %d keyframe at %u, time position %"
4428 GST_TIME_FORMAT " playing from sample %u to %u", n, k_index,
4429 GST_TIME_ARGS (str->time_position), str->from_sample, str->to_sample);
4435 return GST_FLOW_EOS;
4439 * Gets the current qt segment start, stop and position for the
4440 * given time offset. This is used in update_segment()
4443 gst_qtdemux_stream_segment_get_boundaries (GstQTDemux * qtdemux,
4444 QtDemuxStream * stream, GstClockTime offset,
4445 GstClockTime * _start, GstClockTime * _stop, GstClockTime * _time)
4447 GstClockTime seg_time;
4448 GstClockTime start, stop, time;
4449 QtDemuxSegment *segment;
4451 segment = &stream->segments[stream->segment_index];
4453 /* get time in this segment */
4454 seg_time = (offset - segment->time) * segment->rate;
4456 GST_LOG_OBJECT (stream->pad, "seg_time %" GST_TIME_FORMAT,
4457 GST_TIME_ARGS (seg_time));
4459 if (G_UNLIKELY (seg_time > segment->duration)) {
4460 GST_LOG_OBJECT (stream->pad,
4461 "seg_time > segment->duration %" GST_TIME_FORMAT,
4462 GST_TIME_ARGS (segment->duration));
4463 seg_time = segment->duration;
4466 /* qtdemux->segment.stop is in outside-time-realm, whereas
4467 * segment->media_stop is in track-time-realm.
4469 * In order to compare the two, we need to bring segment.stop
4470 * into the track-time-realm
4472 * FIXME - does this comment still hold? Don't see any conversion here */
4474 stop = qtdemux->segment.stop;
4475 if (stop == GST_CLOCK_TIME_NONE)
4476 stop = qtdemux->segment.duration;
4477 if (stop == GST_CLOCK_TIME_NONE)
4478 stop = segment->media_stop;
4481 MIN (segment->media_stop, stop - segment->time + segment->media_start);
4483 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
4484 start = segment->time + seg_time;
4486 stop = start - seg_time + segment->duration;
4487 } else if (qtdemux->segment.rate >= 0) {
4488 start = MIN (segment->media_start + seg_time, stop);
4491 if (segment->media_start >= qtdemux->segment.start) {
4492 time = segment->time;
4494 time = segment->time + (qtdemux->segment.start - segment->media_start);
4497 start = MAX (segment->media_start, qtdemux->segment.start);
4498 stop = MIN (segment->media_start + seg_time, stop);
4507 * Updates the qt segment used for the stream and pushes a new segment event
4508 * downstream on this stream's pad.
4511 gst_qtdemux_stream_update_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
4512 gint seg_idx, GstClockTime offset, GstClockTime * _start,
4513 GstClockTime * _stop)
4515 QtDemuxSegment *segment;
4516 GstClockTime start = 0, stop = GST_CLOCK_TIME_NONE, time = 0;
4520 /* update the current segment */
4521 stream->segment_index = seg_idx;
4523 /* get the segment */
4524 segment = &stream->segments[seg_idx];
4526 if (G_UNLIKELY (offset < segment->time)) {
4527 GST_WARNING_OBJECT (stream->pad, "offset < segment->time %" GST_TIME_FORMAT,
4528 GST_TIME_ARGS (segment->time));
4532 /* segment lies beyond total indicated duration */
4533 if (G_UNLIKELY (qtdemux->segment.duration != GST_CLOCK_TIME_NONE &&
4534 segment->time > qtdemux->segment.duration)) {
4535 GST_WARNING_OBJECT (stream->pad, "file duration %" GST_TIME_FORMAT
4536 " < segment->time %" GST_TIME_FORMAT,
4537 GST_TIME_ARGS (qtdemux->segment.duration),
4538 GST_TIME_ARGS (segment->time));
4542 gst_qtdemux_stream_segment_get_boundaries (qtdemux, stream, offset,
4543 &start, &stop, &time);
4545 GST_DEBUG_OBJECT (stream->pad, "new segment %d from %" GST_TIME_FORMAT
4546 " to %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT, seg_idx,
4547 GST_TIME_ARGS (start), GST_TIME_ARGS (stop), GST_TIME_ARGS (time));
4549 /* combine global rate with that of the segment */
4550 rate = segment->rate * qtdemux->segment.rate;
4552 /* Copy flags from main segment */
4553 stream->segment.flags = qtdemux->segment.flags;
4555 /* update the segment values used for clipping */
4556 stream->segment.offset = qtdemux->segment.offset;
4557 stream->segment.base = qtdemux->segment.base + stream->accumulated_base;
4558 stream->segment.applied_rate = qtdemux->segment.applied_rate;
4559 stream->segment.rate = rate;
4560 stream->segment.start = start + QTSTREAMTIME_TO_GSTTIME (stream,
4561 stream->cslg_shift);
4562 stream->segment.stop = stop + QTSTREAMTIME_TO_GSTTIME (stream,
4563 stream->cslg_shift);
4564 stream->segment.time = time;
4565 stream->segment.position = stream->segment.start;
4567 GST_DEBUG_OBJECT (stream->pad, "New segment: %" GST_SEGMENT_FORMAT,
4570 /* now prepare and send the segment */
4572 event = gst_event_new_segment (&stream->segment);
4573 if (qtdemux->segment_seqnum) {
4574 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
4576 gst_pad_push_event (stream->pad, event);
4577 /* assume we can send more data now */
4578 GST_PAD_LAST_FLOW_RETURN (stream->pad) = GST_FLOW_OK;
4579 /* clear to send tags on this pad now */
4580 gst_qtdemux_push_tags (qtdemux, stream);
4591 /* activate the given segment number @seg_idx of @stream at time @offset.
4592 * @offset is an absolute global position over all the segments.
4594 * This will push out a NEWSEGMENT event with the right values and
4595 * position the stream index to the first decodable sample before
4599 gst_qtdemux_activate_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
4600 guint32 seg_idx, GstClockTime offset)
4602 QtDemuxSegment *segment;
4603 guint32 index, kf_index;
4604 GstClockTime start = 0, stop = GST_CLOCK_TIME_NONE;
4606 GST_LOG_OBJECT (stream->pad, "activate segment %d, offset %" GST_TIME_FORMAT,
4607 seg_idx, GST_TIME_ARGS (offset));
4609 if (!gst_qtdemux_stream_update_segment (qtdemux, stream, seg_idx, offset,
4613 segment = &stream->segments[stream->segment_index];
4615 /* in the fragmented case, we pick a fragment that starts before our
4616 * desired position and rely on downstream to wait for a keyframe
4617 * (FIXME: doesn't seem to work so well with ismv and wmv, as no parser; the
4618 * tfra entries tells us which trun/sample the key unit is in, but we don't
4619 * make use of this additional information at the moment) */
4620 if (qtdemux->fragmented) {
4621 stream->to_sample = G_MAXUINT32;
4625 /* We don't need to look for a sample in push-based */
4626 if (!qtdemux->pullbased)
4629 /* and move to the keyframe before the indicated media time of the
4631 if (G_LIKELY (!QTSEGMENT_IS_EMPTY (segment))) {
4632 if (qtdemux->segment.rate >= 0) {
4633 index = gst_qtdemux_find_index_linear (qtdemux, stream, start);
4634 stream->to_sample = G_MAXUINT32;
4635 GST_DEBUG_OBJECT (stream->pad,
4636 "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
4637 GST_TIME_FORMAT, GST_TIME_ARGS (start), index,
4638 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
4640 index = gst_qtdemux_find_index_linear (qtdemux, stream, stop);
4641 stream->to_sample = index;
4642 GST_DEBUG_OBJECT (stream->pad,
4643 "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
4644 GST_TIME_FORMAT, GST_TIME_ARGS (stop), index,
4645 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
4648 GST_DEBUG_OBJECT (stream->pad, "No need to look for keyframe, "
4649 "this is an empty segment");
4653 /* gst_qtdemux_parse_sample () called from gst_qtdemux_find_index_linear ()
4654 * encountered an error and printed a message so we return appropriately */
4658 /* we're at the right spot */
4659 if (index == stream->sample_index) {
4660 GST_DEBUG_OBJECT (stream->pad, "we are at the right index");
4664 /* find keyframe of the target index */
4665 kf_index = gst_qtdemux_find_keyframe (qtdemux, stream, index);
4668 /* indent does stupid stuff with stream->samples[].timestamp */
4670 /* if we move forwards, we don't have to go back to the previous
4671 * keyframe since we already sent that. We can also just jump to
4672 * the keyframe right before the target index if there is one. */
4673 if (index > stream->sample_index) {
4674 /* moving forwards check if we move past a keyframe */
4675 if (kf_index > stream->sample_index) {
4676 GST_DEBUG_OBJECT (stream->pad,
4677 "moving forwards to keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" )", kf_index,
4678 GST_TIME_ARGS (QTSAMPLE_PTS(stream, &stream->samples[kf_index])),
4679 GST_TIME_ARGS (QTSAMPLE_DTS(stream, &stream->samples[kf_index])));
4680 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
4682 GST_DEBUG_OBJECT (stream->pad,
4683 "moving forwards, keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" ) already sent", kf_index,
4684 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[kf_index])),
4685 GST_TIME_ARGS (QTSAMPLE_DTS (stream, &stream->samples[kf_index])));
4688 GST_DEBUG_OBJECT (stream->pad,
4689 "moving backwards to keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" )", kf_index,
4690 GST_TIME_ARGS (QTSAMPLE_PTS(stream, &stream->samples[kf_index])),
4691 GST_TIME_ARGS (QTSAMPLE_DTS(stream, &stream->samples[kf_index])));
4692 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
4700 /* prepare to get the current sample of @stream, getting essential values.
4702 * This function will also prepare and send the segment when needed.
4704 * Return FALSE if the stream is EOS.
4709 gst_qtdemux_prepare_current_sample (GstQTDemux * qtdemux,
4710 QtDemuxStream * stream, gboolean * empty, guint64 * offset, guint * size,
4711 GstClockTime * dts, GstClockTime * pts, GstClockTime * duration,
4712 gboolean * keyframe)
4714 QtDemuxSample *sample;
4715 GstClockTime time_position;
4718 g_return_val_if_fail (stream != NULL, FALSE);
4720 time_position = stream->time_position;
4721 if (G_UNLIKELY (time_position == GST_CLOCK_TIME_NONE))
4724 seg_idx = stream->segment_index;
4725 if (G_UNLIKELY (seg_idx == -1)) {
4726 /* find segment corresponding to time_position if we are looking
4728 seg_idx = gst_qtdemux_find_segment (qtdemux, stream, time_position);
4731 /* different segment, activate it, sample_index will be set. */
4732 if (G_UNLIKELY (stream->segment_index != seg_idx))
4733 gst_qtdemux_activate_segment (qtdemux, stream, seg_idx, time_position);
4735 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (&stream->segments[stream->
4737 QtDemuxSegment *seg = &stream->segments[stream->segment_index];
4739 GST_LOG_OBJECT (qtdemux, "Empty segment activated,"
4740 " prepare empty sample");
4743 *pts = *dts = time_position;
4744 *duration = seg->duration - (time_position - seg->time);
4751 if (stream->sample_index == -1)
4752 stream->sample_index = 0;
4754 GST_LOG_OBJECT (qtdemux, "segment active, index = %u of %u",
4755 stream->sample_index, stream->n_samples);
4757 if (G_UNLIKELY (stream->sample_index >= stream->n_samples)) {
4758 if (!qtdemux->fragmented)
4761 GST_INFO_OBJECT (qtdemux, "out of samples, trying to add more");
4765 GST_OBJECT_LOCK (qtdemux);
4766 flow = qtdemux_add_fragmented_samples (qtdemux);
4767 GST_OBJECT_UNLOCK (qtdemux);
4769 if (flow != GST_FLOW_OK)
4772 while (stream->sample_index >= stream->n_samples);
4775 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
4776 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
4777 stream->sample_index);
4781 /* now get the info for the sample we're at */
4782 sample = &stream->samples[stream->sample_index];
4784 *dts = QTSAMPLE_DTS (stream, sample);
4785 *pts = QTSAMPLE_PTS (stream, sample);
4786 *offset = sample->offset;
4787 *size = sample->size;
4788 *duration = QTSAMPLE_DUR_DTS (stream, sample, *dts);
4789 *keyframe = QTSAMPLE_KEYFRAME (stream, sample);
4796 stream->time_position = GST_CLOCK_TIME_NONE;
4801 /* move to the next sample in @stream.
4803 * Moves to the next segment when needed.
4806 gst_qtdemux_advance_sample (GstQTDemux * qtdemux, QtDemuxStream * stream)
4808 QtDemuxSample *sample;
4809 QtDemuxSegment *segment;
4811 /* get current segment */
4812 segment = &stream->segments[stream->segment_index];
4814 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
4815 GST_DEBUG_OBJECT (qtdemux, "Empty segment, no samples to advance");
4819 if (G_UNLIKELY (stream->sample_index >= stream->to_sample)) {
4820 /* Mark the stream as EOS */
4821 GST_DEBUG_OBJECT (qtdemux,
4822 "reached max allowed sample %u, mark EOS", stream->to_sample);
4823 stream->time_position = GST_CLOCK_TIME_NONE;
4827 /* move to next sample */
4828 stream->sample_index++;
4829 stream->offset_in_sample = 0;
4831 /* reached the last sample, we need the next segment */
4832 if (G_UNLIKELY (stream->sample_index >= stream->n_samples))
4835 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
4836 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
4837 stream->sample_index);
4841 /* get next sample */
4842 sample = &stream->samples[stream->sample_index];
4844 /* see if we are past the segment */
4845 if (G_UNLIKELY (QTSAMPLE_DTS (stream, sample) >= segment->media_stop))
4848 if (QTSAMPLE_DTS (stream, sample) >= segment->media_start) {
4849 /* inside the segment, update time_position, looks very familiar to
4850 * GStreamer segments, doesn't it? */
4851 stream->time_position =
4852 QTSAMPLE_DTS (stream, sample) - segment->media_start + segment->time;
4854 /* not yet in segment, time does not yet increment. This means
4855 * that we are still prerolling keyframes to the decoder so it can
4856 * decode the first sample of the segment. */
4857 stream->time_position = segment->time;
4861 /* move to the next segment */
4864 GST_DEBUG_OBJECT (qtdemux, "segment %d ended ", stream->segment_index);
4866 if (stream->segment_index == stream->n_segments - 1) {
4867 /* are we at the end of the last segment, we're EOS */
4868 stream->time_position = GST_CLOCK_TIME_NONE;
4870 /* else we're only at the end of the current segment */
4871 stream->time_position = segment->stop_time;
4873 /* make sure we select a new segment */
4875 /* accumulate previous segments */
4876 if (GST_CLOCK_TIME_IS_VALID (stream->segment.stop))
4877 stream->accumulated_base +=
4878 (stream->segment.stop -
4879 stream->segment.start) / ABS (stream->segment.rate);
4881 stream->segment_index = -1;
4886 gst_qtdemux_sync_streams (GstQTDemux * demux)
4890 if (demux->n_streams <= 1)
4893 for (i = 0; i < demux->n_streams; i++) {
4894 QtDemuxStream *stream;
4895 GstClockTime end_time;
4897 stream = demux->streams[i];
4902 /* TODO advance time on subtitle streams here, if any some day */
4904 /* some clips/trailers may have unbalanced streams at the end,
4905 * so send EOS on shorter stream to prevent stalling others */
4907 /* do not mess with EOS if SEGMENT seeking */
4908 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT)
4911 if (demux->pullbased) {
4912 /* loop mode is sample time based */
4913 if (!STREAM_IS_EOS (stream))
4916 /* push mode is byte position based */
4917 if (stream->n_samples &&
4918 stream->samples[stream->n_samples - 1].offset >= demux->offset)
4922 if (stream->sent_eos)
4925 /* only act if some gap */
4926 end_time = stream->segments[stream->n_segments - 1].stop_time;
4927 GST_LOG_OBJECT (demux, "current position: %" GST_TIME_FORMAT
4928 ", stream end: %" GST_TIME_FORMAT,
4929 GST_TIME_ARGS (demux->segment.position), GST_TIME_ARGS (end_time));
4930 if (GST_CLOCK_TIME_IS_VALID (end_time)
4931 && (end_time + 2 * GST_SECOND < demux->segment.position)) {
4934 GST_DEBUG_OBJECT (demux, "sending EOS for stream %s",
4935 GST_PAD_NAME (stream->pad));
4936 stream->sent_eos = TRUE;
4937 event = gst_event_new_eos ();
4938 if (demux->segment_seqnum)
4939 gst_event_set_seqnum (event, demux->segment_seqnum);
4940 gst_pad_push_event (stream->pad, event);
4945 /* EOS and NOT_LINKED need to be combined. This means that we return:
4947 * GST_FLOW_NOT_LINKED: when all pads NOT_LINKED.
4948 * GST_FLOW_EOS: when all pads EOS or NOT_LINKED.
4950 static GstFlowReturn
4951 gst_qtdemux_combine_flows (GstQTDemux * demux, QtDemuxStream * stream,
4954 GST_LOG_OBJECT (demux, "flow return: %s", gst_flow_get_name (ret));
4957 ret = gst_flow_combiner_update_pad_flow (demux->flowcombiner, stream->pad,
4960 ret = gst_flow_combiner_update_flow (demux->flowcombiner, ret);
4962 GST_LOG_OBJECT (demux, "combined flow return: %s", gst_flow_get_name (ret));
4966 /* the input buffer metadata must be writable. Returns NULL when the buffer is
4967 * completely clipped
4969 * Should be used only with raw buffers */
4971 gst_qtdemux_clip_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
4974 guint64 start, stop, cstart, cstop, diff;
4975 GstClockTime pts, duration;
4977 gint num_rate, denom_rate;
4982 osize = size = gst_buffer_get_size (buf);
4985 /* depending on the type, setup the clip parameters */
4986 if (stream->subtype == FOURCC_soun) {
4987 frame_size = stream->bytes_per_frame;
4988 num_rate = GST_SECOND;
4989 denom_rate = (gint) stream->rate;
4991 } else if (stream->subtype == FOURCC_vide) {
4993 num_rate = stream->fps_n;
4994 denom_rate = stream->fps_d;
4999 if (frame_size <= 0)
5000 goto bad_frame_size;
5002 /* we can only clip if we have a valid pts */
5003 pts = GST_BUFFER_PTS (buf);
5004 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (pts)))
5007 duration = GST_BUFFER_DURATION (buf);
5009 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (duration))) {
5011 gst_util_uint64_scale_int (size / frame_size, num_rate, denom_rate);
5015 stop = start + duration;
5017 if (G_UNLIKELY (!gst_segment_clip (&stream->segment,
5018 GST_FORMAT_TIME, start, stop, &cstart, &cstop)))
5021 /* see if some clipping happened */
5022 diff = cstart - start;
5028 /* bring clipped time to samples and to bytes */
5029 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
5032 GST_DEBUG_OBJECT (qtdemux,
5033 "clipping start to %" GST_TIME_FORMAT " %"
5034 G_GUINT64_FORMAT " bytes", GST_TIME_ARGS (cstart), diff);
5040 diff = stop - cstop;
5045 /* bring clipped time to samples and then to bytes */
5046 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
5048 GST_DEBUG_OBJECT (qtdemux,
5049 "clipping stop to %" GST_TIME_FORMAT " %" G_GUINT64_FORMAT
5050 " bytes", GST_TIME_ARGS (cstop), diff);
5055 if (offset != 0 || size != osize)
5056 gst_buffer_resize (buf, offset, size);
5058 GST_BUFFER_DTS (buf) = GST_CLOCK_TIME_NONE;
5059 GST_BUFFER_PTS (buf) = pts;
5060 GST_BUFFER_DURATION (buf) = duration;
5064 /* dropped buffer */
5067 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
5072 GST_DEBUG_OBJECT (qtdemux, "bad frame size");
5077 GST_DEBUG_OBJECT (qtdemux, "no pts on buffer");
5082 GST_DEBUG_OBJECT (qtdemux, "clipped buffer");
5083 gst_buffer_unref (buf);
5088 /* the input buffer metadata must be writable,
5089 * but time/duration etc not yet set and need not be preserved */
5091 gst_qtdemux_process_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
5098 /* not many cases for now */
5099 if (G_UNLIKELY (stream->fourcc == FOURCC_mp4s)) {
5100 /* send a one time dvd clut event */
5101 if (stream->pending_event && stream->pad)
5102 gst_pad_push_event (stream->pad, stream->pending_event);
5103 stream->pending_event = NULL;
5106 if (G_UNLIKELY (stream->subtype != FOURCC_text
5107 && stream->subtype != FOURCC_sbtl &&
5108 stream->subtype != FOURCC_subp)) {
5112 gst_buffer_map (buf, &map, GST_MAP_READ);
5114 /* empty buffer is sent to terminate previous subtitle */
5115 if (map.size <= 2) {
5116 gst_buffer_unmap (buf, &map);
5117 gst_buffer_unref (buf);
5120 if (stream->subtype == FOURCC_subp) {
5121 /* That's all the processing needed for subpictures */
5122 gst_buffer_unmap (buf, &map);
5126 nsize = GST_READ_UINT16_BE (map.data);
5127 nsize = MIN (nsize, map.size - 2);
5129 GST_LOG_OBJECT (qtdemux, "3GPP timed text subtitle: %d/%" G_GSIZE_FORMAT "",
5132 /* takes care of UTF-8 validation or UTF-16 recognition,
5133 * no other encoding expected */
5134 str = gst_tag_freeform_string_to_utf8 ((gchar *) map.data + 2, nsize, NULL);
5135 gst_buffer_unmap (buf, &map);
5137 gst_buffer_unref (buf);
5138 buf = _gst_buffer_new_wrapped (str, strlen (str), g_free);
5140 /* this should not really happen unless the subtitle is corrupted */
5141 gst_buffer_unref (buf);
5145 /* FIXME ? convert optional subsequent style info to markup */
5150 /* Sets a buffer's attributes properly and pushes it downstream.
5151 * Also checks for additional actions and custom processing that may
5152 * need to be done first.
5154 static GstFlowReturn
5155 gst_qtdemux_decorate_and_push_buffer (GstQTDemux * qtdemux,
5156 QtDemuxStream * stream, GstBuffer * buf,
5157 GstClockTime dts, GstClockTime pts, GstClockTime duration,
5158 gboolean keyframe, GstClockTime position, guint64 byte_position)
5160 GstFlowReturn ret = GST_FLOW_OK;
5162 /* offset the timestamps according to the edit list */
5164 if (G_UNLIKELY (stream->fourcc == FOURCC_rtsp)) {
5168 gst_buffer_map (buf, &map, GST_MAP_READ);
5169 url = g_strndup ((gchar *) map.data, map.size);
5170 gst_buffer_unmap (buf, &map);
5171 if (url != NULL && strlen (url) != 0) {
5172 /* we have RTSP redirect now */
5173 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
5174 gst_message_new_element (GST_OBJECT_CAST (qtdemux),
5175 gst_structure_new ("redirect",
5176 "new-location", G_TYPE_STRING, url, NULL)));
5177 qtdemux->posted_redirect = TRUE;
5179 GST_WARNING_OBJECT (qtdemux, "Redirect URI of stream is empty, not "
5185 /* position reporting */
5186 if (qtdemux->segment.rate >= 0) {
5187 qtdemux->segment.position = position;
5188 gst_qtdemux_sync_streams (qtdemux);
5191 if (G_UNLIKELY (!stream->pad)) {
5192 GST_DEBUG_OBJECT (qtdemux, "No output pad for stream, ignoring");
5193 gst_buffer_unref (buf);
5197 /* send out pending buffers */
5198 while (stream->buffers) {
5199 GstBuffer *buffer = (GstBuffer *) stream->buffers->data;
5201 if (G_UNLIKELY (stream->discont)) {
5202 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
5203 GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
5204 stream->discont = FALSE;
5206 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
5209 gst_pad_push (stream->pad, buffer);
5211 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
5214 /* we're going to modify the metadata */
5215 buf = gst_buffer_make_writable (buf);
5217 if (G_UNLIKELY (stream->need_process))
5218 buf = gst_qtdemux_process_buffer (qtdemux, stream, buf);
5224 GST_BUFFER_DTS (buf) = dts;
5225 GST_BUFFER_PTS (buf) = pts;
5226 GST_BUFFER_DURATION (buf) = duration;
5227 GST_BUFFER_OFFSET (buf) = -1;
5228 GST_BUFFER_OFFSET_END (buf) = -1;
5230 if (G_UNLIKELY (stream->rgb8_palette))
5231 gst_buffer_append_memory (buf, gst_memory_ref (stream->rgb8_palette));
5233 if (G_UNLIKELY (stream->padding)) {
5234 gst_buffer_resize (buf, stream->padding, -1);
5237 if (G_UNLIKELY (qtdemux->element_index)) {
5238 GstClockTime stream_time;
5241 gst_segment_to_stream_time (&stream->segment, GST_FORMAT_TIME,
5243 if (GST_CLOCK_TIME_IS_VALID (stream_time)) {
5244 GST_LOG_OBJECT (qtdemux,
5245 "adding association %" GST_TIME_FORMAT "-> %"
5246 G_GUINT64_FORMAT, GST_TIME_ARGS (stream_time), byte_position);
5247 gst_index_add_association (qtdemux->element_index,
5249 keyframe ? GST_ASSOCIATION_FLAG_KEY_UNIT :
5250 GST_ASSOCIATION_FLAG_DELTA_UNIT, GST_FORMAT_TIME, stream_time,
5251 GST_FORMAT_BYTES, byte_position, NULL);
5256 if (stream->need_clip)
5257 buf = gst_qtdemux_clip_buffer (qtdemux, stream, buf);
5259 if (G_UNLIKELY (buf == NULL))
5262 if (G_UNLIKELY (stream->discont)) {
5263 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
5264 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
5265 stream->discont = FALSE;
5267 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
5271 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
5272 stream->on_keyframe = FALSE;
5274 stream->on_keyframe = TRUE;
5278 GST_LOG_OBJECT (qtdemux,
5279 "Pushing buffer with dts %" GST_TIME_FORMAT ", pts %" GST_TIME_FORMAT
5280 ", duration %" GST_TIME_FORMAT " on pad %s", GST_TIME_ARGS (dts),
5281 GST_TIME_ARGS (pts), GST_TIME_ARGS (duration),
5282 GST_PAD_NAME (stream->pad));
5284 if (stream->protected && stream->protection_scheme_type == FOURCC_cenc) {
5285 GstStructure *crypto_info;
5286 QtDemuxCencSampleSetInfo *info =
5287 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
5291 while ((event = g_queue_pop_head (&stream->protection_scheme_event_queue))) {
5292 gst_pad_push_event (stream->pad, event);
5295 if (qtdemux->cenc_aux_info_offset > 0 && info->crypto_info == NULL) {
5296 GST_DEBUG_OBJECT (qtdemux, "cenc metadata hasn't been parsed yet");
5297 gst_buffer_unref (buf);
5301 index = stream->sample_index - (stream->n_samples - info->crypto_info->len);
5302 if (G_LIKELY (index >= 0 && index < info->crypto_info->len)) {
5303 /* steal structure from array */
5304 crypto_info = g_ptr_array_index (info->crypto_info, index);
5305 g_ptr_array_index (info->crypto_info, index) = NULL;
5306 GST_LOG_OBJECT (qtdemux, "attaching cenc metadata [%u]", index);
5307 if (!crypto_info || !gst_buffer_add_protection_meta (buf, crypto_info))
5308 GST_ERROR_OBJECT (qtdemux, "failed to attach cenc metadata to buffer");
5312 ret = gst_pad_push (stream->pad, buf);
5314 if (GST_CLOCK_TIME_IS_VALID (pts) && GST_CLOCK_TIME_IS_VALID (duration)) {
5315 /* mark position in stream, we'll need this to know when to send GAP event */
5316 stream->segment.position = pts + duration;
5323 static const QtDemuxRandomAccessEntry *
5324 gst_qtdemux_stream_seek_fragment (GstQTDemux * qtdemux, QtDemuxStream * stream,
5325 GstClockTime pos, gboolean after)
5327 QtDemuxRandomAccessEntry *entries = stream->ra_entries;
5328 guint n_entries = stream->n_ra_entries;
5331 /* we assume the table is sorted */
5332 for (i = 0; i < n_entries; ++i) {
5333 if (entries[i].ts > pos)
5337 /* FIXME: maybe save first moof_offset somewhere instead, but for now it's
5338 * probably okay to assume that the index lists the very first fragment */
5345 return &entries[i - 1];
5349 gst_qtdemux_do_fragmented_seek (GstQTDemux * qtdemux)
5351 const QtDemuxRandomAccessEntry *best_entry = NULL;
5354 GST_OBJECT_LOCK (qtdemux);
5356 g_assert (qtdemux->n_streams > 0);
5358 for (i = 0; i < qtdemux->n_streams; i++) {
5359 const QtDemuxRandomAccessEntry *entry;
5360 QtDemuxStream *stream;
5361 gboolean is_audio_or_video;
5363 stream = qtdemux->streams[i];
5365 g_free (stream->samples);
5366 stream->samples = NULL;
5367 stream->n_samples = 0;
5368 stream->stbl_index = -1; /* no samples have yet been parsed */
5369 stream->sample_index = -1;
5371 if (stream->ra_entries == NULL)
5374 if (stream->subtype == FOURCC_vide || stream->subtype == FOURCC_soun)
5375 is_audio_or_video = TRUE;
5377 is_audio_or_video = FALSE;
5380 gst_qtdemux_stream_seek_fragment (qtdemux, stream,
5381 stream->time_position, !is_audio_or_video);
5383 GST_INFO_OBJECT (stream->pad, "%" GST_TIME_FORMAT " at offset "
5384 "%" G_GUINT64_FORMAT, GST_TIME_ARGS (entry->ts), entry->moof_offset);
5386 stream->pending_seek = entry;
5388 /* decide position to jump to just based on audio/video tracks, not subs */
5389 if (!is_audio_or_video)
5392 if (best_entry == NULL || entry->moof_offset < best_entry->moof_offset)
5396 if (best_entry == NULL) {
5397 GST_OBJECT_UNLOCK (qtdemux);
5401 GST_INFO_OBJECT (qtdemux, "seek to %" GST_TIME_FORMAT ", best fragment "
5402 "moof offset: %" G_GUINT64_FORMAT ", ts %" GST_TIME_FORMAT,
5403 GST_TIME_ARGS (qtdemux->streams[0]->time_position),
5404 best_entry->moof_offset, GST_TIME_ARGS (best_entry->ts));
5406 qtdemux->moof_offset = best_entry->moof_offset;
5408 qtdemux_add_fragmented_samples (qtdemux);
5410 GST_OBJECT_UNLOCK (qtdemux);
5414 static GstFlowReturn
5415 gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux)
5417 GstFlowReturn ret = GST_FLOW_OK;
5418 GstBuffer *buf = NULL;
5419 QtDemuxStream *stream;
5420 GstClockTime min_time;
5422 GstClockTime dts = GST_CLOCK_TIME_NONE;
5423 GstClockTime pts = GST_CLOCK_TIME_NONE;
5424 GstClockTime duration = 0;
5425 gboolean keyframe = FALSE;
5426 guint sample_size = 0;
5432 gst_qtdemux_push_pending_newsegment (qtdemux);
5434 if (qtdemux->fragmented_seek_pending) {
5435 GST_INFO_OBJECT (qtdemux, "pending fragmented seek");
5436 gst_qtdemux_do_fragmented_seek (qtdemux);
5437 GST_INFO_OBJECT (qtdemux, "fragmented seek done!");
5438 qtdemux->fragmented_seek_pending = FALSE;
5441 /* Figure out the next stream sample to output, min_time is expressed in
5442 * global time and runs over the edit list segments. */
5443 min_time = G_MAXUINT64;
5445 for (i = 0; i < qtdemux->n_streams; i++) {
5446 GstClockTime position;
5448 stream = qtdemux->streams[i];
5449 position = stream->time_position;
5451 /* position of -1 is EOS */
5452 if (position != GST_CLOCK_TIME_NONE && position < min_time) {
5453 min_time = position;
5458 if (G_UNLIKELY (index == -1)) {
5459 GST_DEBUG_OBJECT (qtdemux, "all streams are EOS");
5463 /* check for segment end */
5464 if (G_UNLIKELY (qtdemux->segment.stop != -1
5465 && ((qtdemux->segment.rate >= 0 && qtdemux->segment.stop <= min_time)
5466 || (qtdemux->segment.rate < 0
5467 && qtdemux->segment.start > min_time))
5468 && qtdemux->streams[index]->on_keyframe)) {
5469 GST_DEBUG_OBJECT (qtdemux, "we reached the end of our segment.");
5470 qtdemux->streams[index]->time_position = GST_CLOCK_TIME_NONE;
5474 /* gap events for subtitle streams */
5475 for (i = 0; i < qtdemux->n_streams; i++) {
5476 stream = qtdemux->streams[i];
5477 if (stream->pad && (stream->subtype == FOURCC_subp
5478 || stream->subtype == FOURCC_text
5479 || stream->subtype == FOURCC_sbtl)) {
5480 /* send one second gap events until the stream catches up */
5481 /* gaps can only be sent after segment is activated (segment.stop is no longer -1) */
5482 while (GST_CLOCK_TIME_IS_VALID (stream->segment.stop) &&
5483 GST_CLOCK_TIME_IS_VALID (stream->segment.position) &&
5484 stream->segment.position + GST_SECOND < min_time) {
5486 gst_event_new_gap (stream->segment.position, GST_SECOND);
5487 gst_pad_push_event (stream->pad, gap);
5488 stream->segment.position += GST_SECOND;
5493 stream = qtdemux->streams[index];
5494 if (stream->new_caps) {
5495 gst_qtdemux_configure_stream (qtdemux, stream);
5496 qtdemux_do_allocation (qtdemux, stream);
5499 /* fetch info for the current sample of this stream */
5500 if (G_UNLIKELY (!gst_qtdemux_prepare_current_sample (qtdemux, stream, &empty,
5501 &offset, &sample_size, &dts, &pts, &duration, &keyframe)))
5504 /* If we're doing a keyframe-only trickmode, only push keyframes on video streams */
5505 if (G_UNLIKELY (qtdemux->
5506 segment.flags & GST_SEGMENT_FLAG_TRICKMODE_KEY_UNITS)) {
5507 if (stream->subtype == FOURCC_vide && !keyframe) {
5508 GST_LOG_OBJECT (qtdemux, "Skipping non-keyframe on stream %d", index);
5513 GST_DEBUG_OBJECT (qtdemux,
5514 "pushing from stream %d, empty %d offset %" G_GUINT64_FORMAT
5515 ", size %d, dts=%" GST_TIME_FORMAT ", pts=%" GST_TIME_FORMAT
5516 ", duration %" GST_TIME_FORMAT, index, empty, offset, sample_size,
5517 GST_TIME_ARGS (dts), GST_TIME_ARGS (pts), GST_TIME_ARGS (duration));
5519 if (G_UNLIKELY (empty)) {
5520 /* empty segment, push a gap and move to the next one */
5521 gst_pad_push_event (stream->pad, gst_event_new_gap (pts, duration));
5522 stream->segment.position = pts + duration;
5526 /* hmm, empty sample, skip and move to next sample */
5527 if (G_UNLIKELY (sample_size <= 0))
5530 /* last pushed sample was out of boundary, goto next sample */
5531 if (G_UNLIKELY (GST_PAD_LAST_FLOW_RETURN (stream->pad) == GST_FLOW_EOS))
5534 if (stream->max_buffer_size == 0 || sample_size <= stream->max_buffer_size) {
5537 GST_DEBUG_OBJECT (qtdemux,
5538 "size %d larger than stream max_buffer_size %d, trimming",
5539 sample_size, stream->max_buffer_size);
5541 MIN (sample_size - stream->offset_in_sample, stream->max_buffer_size);
5544 if (qtdemux->cenc_aux_info_offset > 0) {
5547 GstBuffer *aux_info = NULL;
5549 /* pull the data stored before the sample */
5551 gst_qtdemux_pull_atom (qtdemux, qtdemux->offset,
5552 offset + stream->offset_in_sample - qtdemux->offset, &aux_info);
5553 if (G_UNLIKELY (ret != GST_FLOW_OK))
5555 gst_buffer_map (aux_info, &map, GST_MAP_READ);
5556 GST_DEBUG_OBJECT (qtdemux, "parsing cenc auxiliary info");
5557 gst_byte_reader_init (&br, map.data + 8, map.size);
5558 if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
5559 qtdemux->cenc_aux_info_sizes, qtdemux->cenc_aux_sample_count)) {
5560 GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
5561 gst_buffer_unmap (aux_info, &map);
5562 gst_buffer_unref (aux_info);
5563 ret = GST_FLOW_ERROR;
5566 gst_buffer_unmap (aux_info, &map);
5567 gst_buffer_unref (aux_info);
5570 GST_LOG_OBJECT (qtdemux, "reading %d bytes @ %" G_GUINT64_FORMAT, size,
5573 if (stream->use_allocator) {
5574 /* if we have a per-stream allocator, use it */
5575 buf = gst_buffer_new_allocate (stream->allocator, size, &stream->params);
5578 ret = gst_qtdemux_pull_atom (qtdemux, offset + stream->offset_in_sample,
5580 if (G_UNLIKELY (ret != GST_FLOW_OK))
5583 if (size != sample_size) {
5584 pts += gst_util_uint64_scale_int (GST_SECOND,
5585 stream->offset_in_sample / stream->bytes_per_frame, stream->timescale);
5586 dts += gst_util_uint64_scale_int (GST_SECOND,
5587 stream->offset_in_sample / stream->bytes_per_frame, stream->timescale);
5588 duration = gst_util_uint64_scale_int (GST_SECOND,
5589 size / stream->bytes_per_frame, stream->timescale);
5592 ret = gst_qtdemux_decorate_and_push_buffer (qtdemux, stream, buf,
5593 dts, pts, duration, keyframe, min_time, offset);
5595 if (size != sample_size) {
5596 QtDemuxSample *sample = &stream->samples[stream->sample_index];
5597 QtDemuxSegment *segment = &stream->segments[stream->segment_index];
5599 GstClockTime time_position = QTSTREAMTIME_TO_GSTTIME (stream,
5600 sample->timestamp + stream->offset_in_sample / stream->bytes_per_frame);
5601 if (time_position >= segment->media_start) {
5602 /* inside the segment, update time_position, looks very familiar to
5603 * GStreamer segments, doesn't it? */
5604 stream->time_position = (time_position - segment->media_start) +
5607 /* not yet in segment, time does not yet increment. This means
5608 * that we are still prerolling keyframes to the decoder so it can
5609 * decode the first sample of the segment. */
5610 stream->time_position = segment->time;
5615 ret = gst_qtdemux_combine_flows (qtdemux, stream, ret);
5616 /* ignore unlinked, we will not push on the pad anymore and we will EOS when
5617 * we have no more data for the pad to push */
5618 if (ret == GST_FLOW_EOS)
5621 stream->offset_in_sample += size;
5622 if (stream->offset_in_sample >= sample_size) {
5623 gst_qtdemux_advance_sample (qtdemux, stream);
5628 gst_qtdemux_advance_sample (qtdemux, stream);
5636 GST_DEBUG_OBJECT (qtdemux, "No samples left for any streams - EOS");
5642 GST_DEBUG_OBJECT (qtdemux, "No samples left for stream");
5643 /* EOS will be raised if all are EOS */
5650 gst_qtdemux_loop (GstPad * pad)
5652 GstQTDemux *qtdemux;
5656 qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
5658 cur_offset = qtdemux->offset;
5659 GST_LOG_OBJECT (qtdemux, "loop at position %" G_GUINT64_FORMAT ", state %d",
5660 cur_offset, qtdemux->state);
5662 switch (qtdemux->state) {
5663 case QTDEMUX_STATE_INITIAL:
5664 case QTDEMUX_STATE_HEADER:
5665 ret = gst_qtdemux_loop_state_header (qtdemux);
5667 case QTDEMUX_STATE_MOVIE:
5668 ret = gst_qtdemux_loop_state_movie (qtdemux);
5669 if (qtdemux->segment.rate < 0 && ret == GST_FLOW_EOS) {
5670 ret = gst_qtdemux_seek_to_previous_keyframe (qtdemux);
5678 /* if something went wrong, pause */
5679 if (ret != GST_FLOW_OK)
5683 gst_object_unref (qtdemux);
5689 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
5690 (NULL), ("streaming stopped, invalid state"));
5691 gst_pad_pause_task (pad);
5692 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
5697 const gchar *reason = gst_flow_get_name (ret);
5699 GST_LOG_OBJECT (qtdemux, "pausing task, reason %s", reason);
5701 gst_pad_pause_task (pad);
5703 /* fatal errors need special actions */
5705 if (ret == GST_FLOW_EOS) {
5706 if (qtdemux->n_streams == 0) {
5707 /* we have no streams, post an error */
5708 gst_qtdemux_post_no_playable_stream_error (qtdemux);
5710 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
5713 if ((stop = qtdemux->segment.stop) == -1)
5714 stop = qtdemux->segment.duration;
5716 if (qtdemux->segment.rate >= 0) {
5717 GstMessage *message;
5720 GST_LOG_OBJECT (qtdemux, "Sending segment done, at end of segment");
5721 message = gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
5722 GST_FORMAT_TIME, stop);
5723 event = gst_event_new_segment_done (GST_FORMAT_TIME, stop);
5724 if (qtdemux->segment_seqnum) {
5725 gst_message_set_seqnum (message, qtdemux->segment_seqnum);
5726 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
5728 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), message);
5729 gst_qtdemux_push_event (qtdemux, event);
5731 GstMessage *message;
5734 /* For Reverse Playback */
5735 GST_LOG_OBJECT (qtdemux, "Sending segment done, at start of segment");
5736 message = gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
5737 GST_FORMAT_TIME, qtdemux->segment.start);
5738 event = gst_event_new_segment_done (GST_FORMAT_TIME,
5739 qtdemux->segment.start);
5740 if (qtdemux->segment_seqnum) {
5741 gst_message_set_seqnum (message, qtdemux->segment_seqnum);
5742 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
5744 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), message);
5745 gst_qtdemux_push_event (qtdemux, event);
5750 GST_LOG_OBJECT (qtdemux, "Sending EOS at end of segment");
5751 event = gst_event_new_eos ();
5752 if (qtdemux->segment_seqnum)
5753 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
5754 gst_qtdemux_push_event (qtdemux, event);
5756 } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
5757 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
5758 (NULL), ("streaming stopped, reason %s", reason));
5759 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
5768 * Returns if there are samples to be played.
5771 has_next_entry (GstQTDemux * demux)
5773 QtDemuxStream *stream;
5776 GST_DEBUG_OBJECT (demux, "Checking if there are samples not played yet");
5778 for (i = 0; i < demux->n_streams; i++) {
5779 stream = demux->streams[i];
5781 if (stream->sample_index == -1) {
5782 stream->sample_index = 0;
5783 stream->offset_in_sample = 0;
5786 if (stream->sample_index >= stream->n_samples) {
5787 GST_LOG_OBJECT (demux, "stream %d samples exhausted", i);
5790 GST_DEBUG_OBJECT (demux, "Found a sample");
5794 GST_DEBUG_OBJECT (demux, "There wasn't any next sample");
5801 * Returns the size of the first entry at the current offset.
5802 * If -1, there are none (which means EOS or empty file).
5805 next_entry_size (GstQTDemux * demux)
5807 QtDemuxStream *stream;
5810 guint64 smalloffs = (guint64) - 1;
5811 QtDemuxSample *sample;
5813 GST_LOG_OBJECT (demux, "Finding entry at offset %" G_GUINT64_FORMAT,
5816 for (i = 0; i < demux->n_streams; i++) {
5817 stream = demux->streams[i];
5819 if (stream->sample_index == -1) {
5820 stream->sample_index = 0;
5821 stream->offset_in_sample = 0;
5824 if (stream->sample_index >= stream->n_samples) {
5825 GST_LOG_OBJECT (demux, "stream %d samples exhausted", i);
5829 if (!qtdemux_parse_samples (demux, stream, stream->sample_index)) {
5830 GST_LOG_OBJECT (demux, "Parsing of index %u from stbl atom failed!",
5831 stream->sample_index);
5835 sample = &stream->samples[stream->sample_index];
5837 GST_LOG_OBJECT (demux,
5838 "Checking Stream %d (sample_index:%d / offset:%" G_GUINT64_FORMAT
5839 " / size:%" G_GUINT32_FORMAT ")", i, stream->sample_index,
5840 sample->offset, sample->size);
5842 if (((smalloffs == -1)
5843 || (sample->offset < smalloffs)) && (sample->size)) {
5845 smalloffs = sample->offset;
5849 GST_LOG_OBJECT (demux,
5850 "stream %d offset %" G_GUINT64_FORMAT " demux->offset :%"
5851 G_GUINT64_FORMAT, smallidx, smalloffs, demux->offset);
5856 stream = demux->streams[smallidx];
5857 sample = &stream->samples[stream->sample_index];
5859 if (sample->offset >= demux->offset) {
5860 demux->todrop = sample->offset - demux->offset;
5861 return sample->size + demux->todrop;
5864 GST_DEBUG_OBJECT (demux,
5865 "There wasn't any entry at offset %" G_GUINT64_FORMAT, demux->offset);
5870 gst_qtdemux_post_progress (GstQTDemux * demux, gint num, gint denom)
5872 gint perc = (gint) ((gdouble) num * 100.0 / (gdouble) denom);
5874 gst_element_post_message (GST_ELEMENT_CAST (demux),
5875 gst_message_new_element (GST_OBJECT_CAST (demux),
5876 gst_structure_new ("progress", "percent", G_TYPE_INT, perc, NULL)));
5880 qtdemux_seek_offset (GstQTDemux * demux, guint64 offset)
5885 GST_DEBUG_OBJECT (demux, "Seeking to %" G_GUINT64_FORMAT, offset);
5888 gst_event_new_seek (1.0, GST_FORMAT_BYTES,
5889 GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset,
5890 GST_SEEK_TYPE_NONE, -1);
5892 /* store seqnum to drop flush events, they don't need to reach downstream */
5893 demux->offset_seek_seqnum = gst_event_get_seqnum (event);
5894 res = gst_pad_push_event (demux->sinkpad, event);
5895 demux->offset_seek_seqnum = 0;
5900 /* check for seekable upstream, above and beyond a mere query */
5902 gst_qtdemux_check_seekability (GstQTDemux * demux)
5905 gboolean seekable = FALSE;
5906 gint64 start = -1, stop = -1;
5908 if (demux->upstream_size)
5911 query = gst_query_new_seeking (GST_FORMAT_BYTES);
5912 if (!gst_pad_peer_query (demux->sinkpad, query)) {
5913 GST_DEBUG_OBJECT (demux, "seeking query failed");
5917 gst_query_parse_seeking (query, NULL, &seekable, &start, &stop);
5919 /* try harder to query upstream size if we didn't get it the first time */
5920 if (seekable && stop == -1) {
5921 GST_DEBUG_OBJECT (demux, "doing duration query to fix up unset stop");
5922 gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &stop);
5925 /* if upstream doesn't know the size, it's likely that it's not seekable in
5926 * practice even if it technically may be seekable */
5927 if (seekable && (start != 0 || stop <= start)) {
5928 GST_DEBUG_OBJECT (demux, "seekable but unknown start/stop -> disable");
5933 gst_query_unref (query);
5935 GST_DEBUG_OBJECT (demux, "seekable: %d (%" G_GUINT64_FORMAT " - %"
5936 G_GUINT64_FORMAT ")", seekable, start, stop);
5937 demux->upstream_seekable = seekable;
5938 demux->upstream_size = seekable ? stop : -1;
5942 gst_qtdemux_drop_data (GstQTDemux * demux, gint bytes)
5944 g_return_if_fail (bytes <= demux->todrop);
5946 GST_LOG_OBJECT (demux, "Dropping %d bytes", bytes);
5947 gst_adapter_flush (demux->adapter, bytes);
5948 demux->neededbytes -= bytes;
5949 demux->offset += bytes;
5950 demux->todrop -= bytes;
5954 gst_qtdemux_check_send_pending_segment (GstQTDemux * demux)
5956 if (G_UNLIKELY (demux->pending_newsegment)) {
5959 gst_qtdemux_push_pending_newsegment (demux);
5960 /* clear to send tags on all streams */
5961 for (i = 0; i < demux->n_streams; i++) {
5962 QtDemuxStream *stream;
5963 stream = demux->streams[i];
5964 gst_qtdemux_push_tags (demux, stream);
5965 if (stream->sparse) {
5966 GST_INFO_OBJECT (demux, "Sending gap event on stream %d", i);
5967 gst_pad_push_event (stream->pad,
5968 gst_event_new_gap (stream->segment.position, GST_CLOCK_TIME_NONE));
5975 gst_qtdemux_send_gap_for_segment (GstQTDemux * demux,
5976 QtDemuxStream * stream, gint segment_index, GstClockTime pos)
5978 GstClockTime ts, dur;
5983 stream->segments[segment_index].duration - (pos -
5984 stream->segments[segment_index].time);
5985 gap = gst_event_new_gap (ts, dur);
5986 stream->time_position += dur;
5988 GST_DEBUG_OBJECT (stream->pad, "Pushing gap for empty "
5989 "segment: %" GST_PTR_FORMAT, gap);
5990 gst_pad_push_event (stream->pad, gap);
5994 gst_qtdemux_stream_send_initial_gap_segments (GstQTDemux * demux,
5995 QtDemuxStream * stream)
5999 /* Push any initial gap segments before proceeding to the
6001 for (i = 0; i < stream->n_segments; i++) {
6002 gst_qtdemux_activate_segment (demux, stream, i, stream->time_position);
6004 if (QTSEGMENT_IS_EMPTY (&stream->segments[i])) {
6005 gst_qtdemux_send_gap_for_segment (demux, stream, i,
6006 stream->time_position);
6008 /* Only support empty segment at the beginning followed by
6009 * one non-empty segment, this was checked when parsing the
6010 * edts atom, arriving here is unexpected */
6011 g_assert (i + 1 == stream->n_segments);
6017 static GstFlowReturn
6018 gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent, GstBuffer * inbuf)
6022 demux = GST_QTDEMUX (parent);
6024 if (GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_DISCONT)) {
6027 GST_DEBUG_OBJECT (demux, "Got DISCONT, marking all streams as DISCONT");
6029 for (i = 0; i < demux->n_streams; i++) {
6030 demux->streams[i]->discont = TRUE;
6033 /* Reverse fragmented playback, need to flush all we have before
6034 * consuming a new fragment.
6035 * The samples array have the timestamps calculated by accumulating the
6036 * durations but this won't work for reverse playback of fragments as
6037 * the timestamps of a subsequent fragment should be smaller than the
6038 * previously received one. */
6039 if (demux->fragmented && demux->segment.rate < 0) {
6040 gst_qtdemux_process_adapter (demux, TRUE);
6041 for (i = 0; i < demux->n_streams; i++)
6042 gst_qtdemux_stream_flush_samples_data (demux, demux->streams[i]);
6046 gst_adapter_push (demux->adapter, inbuf);
6048 GST_DEBUG_OBJECT (demux,
6049 "pushing in inbuf %p, neededbytes:%u, available:%" G_GSIZE_FORMAT, inbuf,
6050 demux->neededbytes, gst_adapter_available (demux->adapter));
6052 return gst_qtdemux_process_adapter (demux, FALSE);
6055 static GstFlowReturn
6056 gst_qtdemux_process_adapter (GstQTDemux * demux, gboolean force)
6058 GstFlowReturn ret = GST_FLOW_OK;
6060 /* we never really mean to buffer that much */
6061 if (demux->neededbytes == -1) {
6065 while (((gst_adapter_available (demux->adapter)) >= demux->neededbytes) &&
6066 (ret == GST_FLOW_OK || (ret == GST_FLOW_NOT_LINKED && force))) {
6068 GST_DEBUG_OBJECT (demux,
6069 "state:%d , demux->neededbytes:%d, demux->offset:%" G_GUINT64_FORMAT,
6070 demux->state, demux->neededbytes, demux->offset);
6072 switch (demux->state) {
6073 case QTDEMUX_STATE_INITIAL:{
6078 gst_qtdemux_check_seekability (demux);
6080 data = gst_adapter_map (demux->adapter, demux->neededbytes);
6082 /* get fourcc/length, set neededbytes */
6083 extract_initial_length_and_fourcc ((guint8 *) data, demux->neededbytes,
6085 gst_adapter_unmap (demux->adapter);
6087 GST_DEBUG_OBJECT (demux, "Peeking found [%" GST_FOURCC_FORMAT "] "
6088 "size: %" G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), size);
6090 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
6091 (_("This file is invalid and cannot be played.")),
6092 ("initial atom '%" GST_FOURCC_FORMAT "' has empty length",
6093 GST_FOURCC_ARGS (fourcc)));
6094 ret = GST_FLOW_ERROR;
6097 if (fourcc == FOURCC_mdat) {
6098 gint next_entry = next_entry_size (demux);
6099 if (demux->n_streams > 0 && (next_entry != -1 || !demux->fragmented)) {
6100 /* we have the headers, start playback */
6101 demux->state = QTDEMUX_STATE_MOVIE;
6102 demux->neededbytes = next_entry;
6103 demux->mdatleft = size;
6105 /* no headers yet, try to get them */
6108 guint64 old, target;
6111 old = demux->offset;
6112 target = old + size;
6114 /* try to jump over the atom with a seek */
6115 /* only bother if it seems worth doing so,
6116 * and avoids possible upstream/server problems */
6117 if (demux->upstream_seekable &&
6118 demux->upstream_size > 4 * (1 << 20)) {
6119 res = qtdemux_seek_offset (demux, target);
6121 GST_DEBUG_OBJECT (demux, "skipping seek");
6126 GST_DEBUG_OBJECT (demux, "seek success");
6127 /* remember the offset fo the first mdat so we can seek back to it
6128 * after we have the headers */
6129 if (fourcc == FOURCC_mdat && demux->first_mdat == -1) {
6130 demux->first_mdat = old;
6131 GST_DEBUG_OBJECT (demux, "first mdat at %" G_GUINT64_FORMAT,
6134 /* seek worked, continue reading */
6135 demux->offset = target;
6136 demux->neededbytes = 16;
6137 demux->state = QTDEMUX_STATE_INITIAL;
6139 /* seek failed, need to buffer */
6140 demux->offset = old;
6141 GST_DEBUG_OBJECT (demux, "seek failed/skipped");
6142 /* there may be multiple mdat (or alike) buffers */
6144 if (demux->mdatbuffer)
6145 bs = gst_buffer_get_size (demux->mdatbuffer);
6148 if (size + bs > 10 * (1 << 20))
6150 demux->state = QTDEMUX_STATE_BUFFER_MDAT;
6151 demux->neededbytes = size;
6152 if (!demux->mdatbuffer)
6153 demux->mdatoffset = demux->offset;
6156 } else if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
6157 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
6158 (_("This file is invalid and cannot be played.")),
6159 ("atom %" GST_FOURCC_FORMAT " has bogus size %" G_GUINT64_FORMAT,
6160 GST_FOURCC_ARGS (fourcc), size));
6161 ret = GST_FLOW_ERROR;
6164 /* this means we already started buffering and still no moov header,
6165 * let's continue buffering everything till we get moov */
6166 if (demux->mdatbuffer && !(fourcc == FOURCC_moov
6167 || fourcc == FOURCC_moof))
6169 demux->neededbytes = size;
6170 demux->state = QTDEMUX_STATE_HEADER;
6174 case QTDEMUX_STATE_HEADER:{
6178 GST_DEBUG_OBJECT (demux, "In header");
6180 data = gst_adapter_map (demux->adapter, demux->neededbytes);
6182 /* parse the header */
6183 extract_initial_length_and_fourcc (data, demux->neededbytes, NULL,
6185 if (fourcc == FOURCC_moov) {
6188 /* in usual fragmented setup we could try to scan for more
6189 * and end up at the the moov (after mdat) again */
6190 if (demux->got_moov && demux->n_streams > 0 &&
6192 || demux->last_moov_offset == demux->offset)) {
6193 GST_DEBUG_OBJECT (demux,
6194 "Skipping moov atom as we have (this) one already");
6196 GST_DEBUG_OBJECT (demux, "Parsing [moov]");
6198 if (demux->got_moov && demux->fragmented) {
6199 GST_DEBUG_OBJECT (demux,
6200 "Got a second moov, clean up data from old one");
6201 if (demux->moov_node)
6202 g_node_destroy (demux->moov_node);
6203 demux->moov_node = NULL;
6204 demux->moov_node_compressed = NULL;
6206 /* prepare newsegment to send when streaming actually starts */
6207 if (!demux->pending_newsegment) {
6208 demux->pending_newsegment =
6209 gst_event_new_segment (&demux->segment);
6210 if (demux->segment_seqnum)
6211 gst_event_set_seqnum (demux->pending_newsegment,
6212 demux->segment_seqnum);
6216 demux->last_moov_offset = demux->offset;
6218 qtdemux_parse_moov (demux, data, demux->neededbytes);
6219 qtdemux_node_dump (demux, demux->moov_node);
6220 qtdemux_parse_tree (demux);
6221 qtdemux_prepare_streams (demux);
6222 if (!demux->got_moov)
6223 qtdemux_expose_streams (demux);
6226 for (n = 0; n < demux->n_streams; n++) {
6227 QtDemuxStream *stream = demux->streams[n];
6229 gst_qtdemux_configure_stream (demux, stream);
6233 demux->got_moov = TRUE;
6234 gst_qtdemux_check_send_pending_segment (demux);
6236 /* fragmented streams headers shouldn't contain edts atoms */
6237 if (!demux->fragmented) {
6238 for (n = 0; n < demux->n_streams; n++) {
6239 gst_qtdemux_stream_send_initial_gap_segments (demux,
6244 g_node_destroy (demux->moov_node);
6245 demux->moov_node = NULL;
6246 GST_DEBUG_OBJECT (demux, "Finished parsing the header");
6248 } else if (fourcc == FOURCC_moof) {
6249 if ((demux->got_moov || demux->media_caps) && demux->fragmented) {
6251 GstClockTime prev_pts;
6252 guint64 prev_offset;
6254 GST_DEBUG_OBJECT (demux, "Parsing [moof]");
6257 * The timestamp of the moof buffer is relevant as some scenarios
6258 * won't have the initial timestamp in the atoms. Whenever a new
6259 * buffer has started, we get that buffer's PTS and use it as a base
6260 * timestamp for the trun entries.
6262 * To keep track of the current buffer timestamp and starting point
6263 * we use gst_adapter_prev_pts that gives us the PTS and the distance
6264 * from the beggining of the buffer, with the distance and demux->offset
6265 * we know if it is still the same buffer or not.
6267 prev_pts = gst_adapter_prev_pts (demux->adapter, &dist);
6268 prev_offset = demux->offset - dist;
6269 if (demux->fragment_start_offset == -1
6270 || prev_offset > demux->fragment_start_offset) {
6271 demux->fragment_start_offset = prev_offset;
6272 demux->fragment_start = prev_pts;
6273 GST_DEBUG_OBJECT (demux,
6274 "New fragment start found at: %" G_GUINT64_FORMAT " : %"
6275 GST_TIME_FORMAT, demux->fragment_start_offset,
6276 GST_TIME_ARGS (demux->fragment_start));
6279 demux->moof_offset = demux->offset;
6280 if (!qtdemux_parse_moof (demux, data, demux->neededbytes,
6281 demux->offset, NULL)) {
6282 gst_adapter_unmap (demux->adapter);
6283 ret = GST_FLOW_ERROR;
6286 /* in MSS we need to expose the pads after the first moof as we won't get a moov */
6287 if (demux->mss_mode && !demux->exposed) {
6288 if (!demux->pending_newsegment) {
6290 gst_segment_init (&segment, GST_FORMAT_TIME);
6291 GST_DEBUG_OBJECT (demux, "new pending_newsegment");
6292 demux->pending_newsegment = gst_event_new_segment (&segment);
6293 if (demux->segment_seqnum)
6294 gst_event_set_seqnum (demux->pending_newsegment,
6295 demux->segment_seqnum);
6297 qtdemux_expose_streams (demux);
6300 GST_DEBUG_OBJECT (demux, "Discarding [moof]");
6302 } else if (fourcc == FOURCC_ftyp) {
6303 GST_DEBUG_OBJECT (demux, "Parsing [ftyp]");
6304 qtdemux_parse_ftyp (demux, data, demux->neededbytes);
6305 } else if (fourcc == FOURCC_uuid) {
6306 GST_DEBUG_OBJECT (demux, "Parsing [uuid]");
6307 qtdemux_parse_uuid (demux, data, demux->neededbytes);
6308 } else if (fourcc == FOURCC_sidx) {
6309 GST_DEBUG_OBJECT (demux, "Parsing [sidx]");
6310 qtdemux_parse_sidx (demux, data, demux->neededbytes);
6312 GST_WARNING_OBJECT (demux,
6313 "Unknown fourcc while parsing header : %" GST_FOURCC_FORMAT,
6314 GST_FOURCC_ARGS (fourcc));
6315 /* Let's jump that one and go back to initial state */
6317 gst_adapter_unmap (demux->adapter);
6320 if (demux->mdatbuffer && demux->n_streams) {
6321 gsize remaining_data_size = 0;
6323 /* the mdat was before the header */
6324 GST_DEBUG_OBJECT (demux, "We have n_streams:%d and mdatbuffer:%p",
6325 demux->n_streams, demux->mdatbuffer);
6326 /* restore our adapter/offset view of things with upstream;
6327 * put preceding buffered data ahead of current moov data.
6328 * This should also handle evil mdat, moov, mdat cases and alike */
6329 gst_adapter_flush (demux->adapter, demux->neededbytes);
6331 /* Store any remaining data after the mdat for later usage */
6332 remaining_data_size = gst_adapter_available (demux->adapter);
6333 if (remaining_data_size > 0) {
6334 g_assert (demux->restoredata_buffer == NULL);
6335 demux->restoredata_buffer =
6336 gst_adapter_take_buffer (demux->adapter, remaining_data_size);
6337 demux->restoredata_offset = demux->offset + demux->neededbytes;
6338 GST_DEBUG_OBJECT (demux,
6339 "Stored %" G_GSIZE_FORMAT " post mdat bytes at offset %"
6340 G_GUINT64_FORMAT, remaining_data_size,
6341 demux->restoredata_offset);
6344 gst_adapter_push (demux->adapter, demux->mdatbuffer);
6345 demux->mdatbuffer = NULL;
6346 demux->offset = demux->mdatoffset;
6347 demux->neededbytes = next_entry_size (demux);
6348 demux->state = QTDEMUX_STATE_MOVIE;
6349 demux->mdatleft = gst_adapter_available (demux->adapter);
6351 GST_DEBUG_OBJECT (demux, "Carrying on normally");
6352 gst_adapter_flush (demux->adapter, demux->neededbytes);
6354 /* only go back to the mdat if there are samples to play */
6355 if (demux->got_moov && demux->first_mdat != -1
6356 && has_next_entry (demux)) {
6359 /* we need to seek back */
6360 res = qtdemux_seek_offset (demux, demux->first_mdat);
6362 demux->offset = demux->first_mdat;
6364 GST_DEBUG_OBJECT (demux, "Seek back failed");
6367 demux->offset += demux->neededbytes;
6369 demux->neededbytes = 16;
6370 demux->state = QTDEMUX_STATE_INITIAL;
6375 case QTDEMUX_STATE_BUFFER_MDAT:{
6379 GST_DEBUG_OBJECT (demux, "Got our buffer at offset %" G_GUINT64_FORMAT,
6381 buf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
6382 gst_buffer_extract (buf, 0, fourcc, 4);
6383 GST_DEBUG_OBJECT (demux, "mdatbuffer starts with %" GST_FOURCC_FORMAT,
6384 GST_FOURCC_ARGS (QT_FOURCC (fourcc)));
6385 if (demux->mdatbuffer)
6386 demux->mdatbuffer = gst_buffer_append (demux->mdatbuffer, buf);
6388 demux->mdatbuffer = buf;
6389 demux->offset += demux->neededbytes;
6390 demux->neededbytes = 16;
6391 demux->state = QTDEMUX_STATE_INITIAL;
6392 gst_qtdemux_post_progress (demux, 1, 1);
6396 case QTDEMUX_STATE_MOVIE:{
6397 QtDemuxStream *stream = NULL;
6398 QtDemuxSample *sample;
6400 GstClockTime dts, pts, duration;
6403 GST_DEBUG_OBJECT (demux,
6404 "BEGIN // in MOVIE for offset %" G_GUINT64_FORMAT, demux->offset);
6406 if (demux->fragmented) {
6407 GST_DEBUG_OBJECT (demux, "mdat remaining %" G_GUINT64_FORMAT,
6409 if (G_LIKELY (demux->todrop < demux->mdatleft)) {
6410 /* if needed data starts within this atom,
6411 * then it should not exceed this atom */
6412 if (G_UNLIKELY (demux->neededbytes > demux->mdatleft)) {
6413 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
6414 (_("This file is invalid and cannot be played.")),
6415 ("sample data crosses atom boundary"));
6416 ret = GST_FLOW_ERROR;
6419 demux->mdatleft -= demux->neededbytes;
6421 GST_DEBUG_OBJECT (demux, "data atom emptied; resuming atom scan");
6422 /* so we are dropping more than left in this atom */
6423 gst_qtdemux_drop_data (demux, demux->mdatleft);
6424 demux->mdatleft = 0;
6426 /* need to resume atom parsing so we do not miss any other pieces */
6427 demux->state = QTDEMUX_STATE_INITIAL;
6428 demux->neededbytes = 16;
6430 /* check if there was any stored post mdat data from previous buffers */
6431 if (demux->restoredata_buffer) {
6432 g_assert (gst_adapter_available (demux->adapter) == 0);
6434 gst_adapter_push (demux->adapter, demux->restoredata_buffer);
6435 demux->restoredata_buffer = NULL;
6436 demux->offset = demux->restoredata_offset;
6443 if (demux->todrop) {
6444 if (demux->cenc_aux_info_offset > 0) {
6448 GST_DEBUG_OBJECT (demux, "parsing cenc auxiliary info");
6449 data = gst_adapter_map (demux->adapter, demux->todrop);
6450 gst_byte_reader_init (&br, data + 8, demux->todrop);
6451 if (!qtdemux_parse_cenc_aux_info (demux, demux->streams[0], &br,
6452 demux->cenc_aux_info_sizes, demux->cenc_aux_sample_count)) {
6453 GST_ERROR_OBJECT (demux, "failed to parse cenc auxiliary info");
6454 ret = GST_FLOW_ERROR;
6455 gst_adapter_unmap (demux->adapter);
6456 g_free (demux->cenc_aux_info_sizes);
6457 demux->cenc_aux_info_sizes = NULL;
6460 demux->cenc_aux_info_offset = 0;
6461 g_free (demux->cenc_aux_info_sizes);
6462 demux->cenc_aux_info_sizes = NULL;
6463 gst_adapter_unmap (demux->adapter);
6465 gst_qtdemux_drop_data (demux, demux->todrop);
6469 /* initial newsegment sent here after having added pads,
6470 * possible others in sink_event */
6471 gst_qtdemux_check_send_pending_segment (demux);
6473 /* Figure out which stream this packet belongs to */
6474 for (i = 0; i < demux->n_streams; i++) {
6475 stream = demux->streams[i];
6476 if (stream->sample_index >= stream->n_samples)
6478 GST_LOG_OBJECT (demux,
6479 "Checking stream %d (sample_index:%d / offset:%" G_GUINT64_FORMAT
6480 " / size:%d)", i, stream->sample_index,
6481 stream->samples[stream->sample_index].offset,
6482 stream->samples[stream->sample_index].size);
6484 if (stream->samples[stream->sample_index].offset == demux->offset)
6488 if (G_UNLIKELY (stream == NULL || i == demux->n_streams))
6489 goto unknown_stream;
6491 if (stream->new_caps) {
6492 gst_qtdemux_configure_stream (demux, stream);
6495 /* Put data in a buffer, set timestamps, caps, ... */
6496 sample = &stream->samples[stream->sample_index];
6498 if (G_LIKELY (!(STREAM_IS_EOS (stream)))) {
6499 GST_DEBUG_OBJECT (demux, "stream : %" GST_FOURCC_FORMAT,
6500 GST_FOURCC_ARGS (stream->fourcc));
6502 dts = QTSAMPLE_DTS (stream, sample);
6503 pts = QTSAMPLE_PTS (stream, sample);
6504 duration = QTSAMPLE_DUR_DTS (stream, sample, dts);
6505 keyframe = QTSAMPLE_KEYFRAME (stream, sample);
6507 /* check for segment end */
6508 if (G_UNLIKELY (demux->segment.stop != -1
6509 && demux->segment.stop <= pts && stream->on_keyframe)) {
6510 GST_DEBUG_OBJECT (demux, "we reached the end of our segment.");
6511 stream->time_position = GST_CLOCK_TIME_NONE; /* this means EOS */
6513 /* skip this data, stream is EOS */
6514 gst_adapter_flush (demux->adapter, demux->neededbytes);
6516 /* check if all streams are eos */
6518 for (i = 0; i < demux->n_streams; i++) {
6519 if (!STREAM_IS_EOS (demux->streams[i])) {
6525 if (ret == GST_FLOW_EOS) {
6526 GST_DEBUG_OBJECT (demux, "All streams are EOS, signal upstream");
6533 gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
6535 /* FIXME: should either be an assert or a plain check */
6536 g_return_val_if_fail (outbuf != NULL, GST_FLOW_ERROR);
6538 ret = gst_qtdemux_decorate_and_push_buffer (demux, stream, outbuf,
6539 dts, pts, duration, keyframe, dts, demux->offset);
6543 ret = gst_qtdemux_combine_flows (demux, stream, ret);
6544 if (ret != GST_FLOW_OK && ret != GST_FLOW_NOT_LINKED)
6545 goto non_ok_unlinked_flow;
6547 /* skip this data, stream is EOS */
6548 gst_adapter_flush (demux->adapter, demux->neededbytes);
6551 stream->sample_index++;
6552 stream->offset_in_sample = 0;
6554 /* update current offset and figure out size of next buffer */
6555 GST_LOG_OBJECT (demux, "increasing offset %" G_GUINT64_FORMAT " by %u",
6556 demux->offset, demux->neededbytes);
6557 demux->offset += demux->neededbytes;
6558 GST_LOG_OBJECT (demux, "offset is now %" G_GUINT64_FORMAT,
6561 if ((demux->neededbytes = next_entry_size (demux)) == -1) {
6562 if (demux->fragmented) {
6563 GST_DEBUG_OBJECT (demux, "(temporarily) out of fragmented samples");
6564 /* there may be more to follow, only finish this atom */
6565 demux->todrop = demux->mdatleft;
6566 demux->neededbytes = demux->todrop;
6578 /* when buffering movie data, at least show user something is happening */
6579 if (ret == GST_FLOW_OK && demux->state == QTDEMUX_STATE_BUFFER_MDAT &&
6580 gst_adapter_available (demux->adapter) <= demux->neededbytes) {
6581 gst_qtdemux_post_progress (demux, gst_adapter_available (demux->adapter),
6582 demux->neededbytes);
6589 non_ok_unlinked_flow:
6591 GST_DEBUG_OBJECT (demux, "Stopping, combined return flow %s",
6592 gst_flow_get_name (ret));
6597 GST_ELEMENT_ERROR (demux, STREAM, FAILED, (NULL), ("unknown stream found"));
6598 ret = GST_FLOW_ERROR;
6603 GST_DEBUG_OBJECT (demux, "no next entry, EOS");
6609 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
6610 (NULL), ("qtdemuxer invalid state %d", demux->state));
6611 ret = GST_FLOW_ERROR;
6616 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
6617 (NULL), ("no 'moov' atom within the first 10 MB"));
6618 ret = GST_FLOW_ERROR;
6624 qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent)
6629 query = gst_query_new_scheduling ();
6631 if (!gst_pad_peer_query (sinkpad, query)) {
6632 gst_query_unref (query);
6636 pull_mode = gst_query_has_scheduling_mode_with_flags (query,
6637 GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
6638 gst_query_unref (query);
6643 GST_DEBUG_OBJECT (sinkpad, "activating pull");
6644 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
6648 GST_DEBUG_OBJECT (sinkpad, "activating push");
6649 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
6654 qtdemux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
6655 GstPadMode mode, gboolean active)
6658 GstQTDemux *demux = GST_QTDEMUX (parent);
6661 case GST_PAD_MODE_PUSH:
6662 demux->pullbased = FALSE;
6665 case GST_PAD_MODE_PULL:
6667 demux->pullbased = TRUE;
6668 res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_qtdemux_loop,
6671 res = gst_pad_stop_task (sinkpad);
6683 qtdemux_zalloc (void *opaque, unsigned int items, unsigned int size)
6685 return g_malloc (items * size);
6689 qtdemux_zfree (void *opaque, void *addr)
6695 qtdemux_inflate (void *z_buffer, guint z_length, guint length)
6701 z = g_new0 (z_stream, 1);
6702 z->zalloc = qtdemux_zalloc;
6703 z->zfree = qtdemux_zfree;
6706 z->next_in = z_buffer;
6707 z->avail_in = z_length;
6709 buffer = (guint8 *) g_malloc (length);
6710 ret = inflateInit (z);
6711 while (z->avail_in > 0) {
6712 if (z->avail_out == 0) {
6714 buffer = (guint8 *) g_realloc (buffer, length);
6715 z->next_out = buffer + z->total_out;
6716 z->avail_out = 1024;
6718 ret = inflate (z, Z_SYNC_FLUSH);
6722 if (ret != Z_STREAM_END) {
6723 g_warning ("inflate() returned %d", ret);
6729 #endif /* HAVE_ZLIB */
6732 qtdemux_parse_moov (GstQTDemux * qtdemux, const guint8 * buffer, guint length)
6736 qtdemux->moov_node = g_node_new ((guint8 *) buffer);
6738 /* counts as header data */
6739 qtdemux->header_size += length;
6741 GST_DEBUG_OBJECT (qtdemux, "parsing 'moov' atom");
6742 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buffer, length);
6744 cmov = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_cmov);
6750 dcom = qtdemux_tree_get_child_by_type (cmov, FOURCC_dcom);
6751 cmvd = qtdemux_tree_get_child_by_type (cmov, FOURCC_cmvd);
6752 if (dcom == NULL || cmvd == NULL)
6753 goto invalid_compression;
6755 method = QT_FOURCC ((guint8 *) dcom->data + 8);
6759 guint uncompressed_length;
6760 guint compressed_length;
6763 uncompressed_length = QT_UINT32 ((guint8 *) cmvd->data + 8);
6764 compressed_length = QT_UINT32 ((guint8 *) cmvd->data + 4) - 12;
6765 GST_LOG ("length = %u", uncompressed_length);
6768 (guint8 *) qtdemux_inflate ((guint8 *) cmvd->data + 12,
6769 compressed_length, uncompressed_length);
6771 qtdemux->moov_node_compressed = qtdemux->moov_node;
6772 qtdemux->moov_node = g_node_new (buf);
6774 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buf,
6775 uncompressed_length);
6778 #endif /* HAVE_ZLIB */
6780 GST_WARNING_OBJECT (qtdemux, "unknown or unhandled header compression "
6781 "type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (method));
6788 invalid_compression:
6790 GST_ERROR_OBJECT (qtdemux, "invalid compressed header");
6796 qtdemux_parse_container (GstQTDemux * qtdemux, GNode * node, const guint8 * buf,
6799 while (G_UNLIKELY (buf < end)) {
6803 if (G_UNLIKELY (buf + 4 > end)) {
6804 GST_LOG_OBJECT (qtdemux, "buffer overrun");
6807 len = QT_UINT32 (buf);
6808 if (G_UNLIKELY (len == 0)) {
6809 GST_LOG_OBJECT (qtdemux, "empty container");
6812 if (G_UNLIKELY (len < 8)) {
6813 GST_WARNING_OBJECT (qtdemux, "length too short (%d < 8)", len);
6816 if (G_UNLIKELY (len > (end - buf))) {
6817 GST_WARNING_OBJECT (qtdemux, "length too long (%d > %d)", len,
6818 (gint) (end - buf));
6822 child = g_node_new ((guint8 *) buf);
6823 g_node_append (node, child);
6824 GST_LOG_OBJECT (qtdemux, "adding new node of len %d", len);
6825 qtdemux_parse_node (qtdemux, child, buf, len);
6833 qtdemux_parse_theora_extension (GstQTDemux * qtdemux, QtDemuxStream * stream,
6836 int len = QT_UINT32 (xdxt->data);
6837 guint8 *buf = xdxt->data;
6838 guint8 *end = buf + len;
6841 /* skip size and type */
6849 size = QT_UINT32 (buf);
6850 type = QT_FOURCC (buf + 4);
6852 GST_LOG_OBJECT (qtdemux, "%p %p", buf, end);
6854 if (buf + size > end || size <= 0)
6860 GST_WARNING_OBJECT (qtdemux, "have cookie %" GST_FOURCC_FORMAT,
6861 GST_FOURCC_ARGS (type));
6865 buffer = gst_buffer_new_and_alloc (size);
6866 gst_buffer_fill (buffer, 0, buf, size);
6867 stream->buffers = g_slist_append (stream->buffers, buffer);
6868 GST_LOG_OBJECT (qtdemux, "parsing theora header");
6871 buffer = gst_buffer_new_and_alloc (size);
6872 gst_buffer_fill (buffer, 0, buf, size);
6873 stream->buffers = g_slist_append (stream->buffers, buffer);
6874 GST_LOG_OBJECT (qtdemux, "parsing theora comment");
6877 buffer = gst_buffer_new_and_alloc (size);
6878 gst_buffer_fill (buffer, 0, buf, size);
6879 stream->buffers = g_slist_append (stream->buffers, buffer);
6880 GST_LOG_OBJECT (qtdemux, "parsing theora codebook");
6883 GST_WARNING_OBJECT (qtdemux,
6884 "unknown theora cookie %" GST_FOURCC_FORMAT,
6885 GST_FOURCC_ARGS (type));
6894 qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node, const guint8 * buffer,
6898 guint32 node_length = 0;
6899 const QtNodeType *type;
6902 GST_LOG_OBJECT (qtdemux, "qtdemux_parse buffer %p length %u", buffer, length);
6904 if (G_UNLIKELY (length < 8))
6905 goto not_enough_data;
6907 node_length = QT_UINT32 (buffer);
6908 fourcc = QT_FOURCC (buffer + 4);
6910 /* ignore empty nodes */
6911 if (G_UNLIKELY (fourcc == 0 || node_length == 8))
6914 type = qtdemux_type_get (fourcc);
6916 end = buffer + length;
6918 GST_LOG_OBJECT (qtdemux,
6919 "parsing '%" GST_FOURCC_FORMAT "', length=%u, name '%s'",
6920 GST_FOURCC_ARGS (fourcc), node_length, type->name);
6922 if (node_length > length)
6923 goto broken_atom_size;
6925 if (type->flags & QT_FLAG_CONTAINER) {
6926 qtdemux_parse_container (qtdemux, node, buffer + 8, end);
6931 if (node_length < 20) {
6932 GST_LOG_OBJECT (qtdemux, "skipping small stsd box");
6935 GST_DEBUG_OBJECT (qtdemux,
6936 "parsing stsd (sample table, sample description) atom");
6937 /* Skip over 8 byte atom hdr + 1 byte version, 3 bytes flags, 4 byte num_entries */
6938 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
6948 /* also read alac (or whatever) in stead of mp4a in the following,
6949 * since a similar layout is used in other cases as well */
6950 if (fourcc == FOURCC_mp4a)
6955 /* There are two things we might encounter here: a true mp4a atom, and
6956 an mp4a entry in an stsd atom. The latter is what we're interested
6957 in, and it looks like an atom, but isn't really one. The true mp4a
6958 atom is short, so we detect it based on length here. */
6959 if (length < min_size) {
6960 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
6961 GST_FOURCC_ARGS (fourcc));
6965 /* 'version' here is the sound sample description version. Types 0 and
6966 1 are documented in the QTFF reference, but type 2 is not: it's
6967 described in Apple header files instead (struct SoundDescriptionV2
6969 version = QT_UINT16 (buffer + 16);
6971 GST_DEBUG_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT " version 0x%08x",
6972 GST_FOURCC_ARGS (fourcc), version);
6974 /* parse any esds descriptors */
6986 GST_WARNING_OBJECT (qtdemux,
6987 "unhandled %" GST_FOURCC_FORMAT " version 0x%08x",
6988 GST_FOURCC_ARGS (fourcc), version);
6993 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
7010 /* codec_data is contained inside these atoms, which all have
7011 * the same format. */
7013 GST_DEBUG_OBJECT (qtdemux, "parsing in %" GST_FOURCC_FORMAT,
7014 GST_FOURCC_ARGS (fourcc));
7015 version = QT_UINT32 (buffer + 16);
7016 GST_DEBUG_OBJECT (qtdemux, "version %08x", version);
7017 if (1 || version == 0x00000000) {
7018 buf = buffer + 0x32;
7020 /* FIXME Quicktime uses PASCAL string while
7021 * the iso format uses C strings. Check the file
7022 * type before attempting to parse the string here. */
7023 tlen = QT_UINT8 (buf);
7024 GST_DEBUG_OBJECT (qtdemux, "tlen = %d", tlen);
7026 GST_DEBUG_OBJECT (qtdemux, "string = %.*s", tlen, (char *) buf);
7027 /* the string has a reserved space of 32 bytes so skip
7028 * the remaining 31 */
7030 buf += 4; /* and 4 bytes reserved */
7032 GST_MEMDUMP_OBJECT (qtdemux, "mp4v", buf, end - buf);
7034 qtdemux_parse_container (qtdemux, node, buf, end);
7040 GST_MEMDUMP_OBJECT (qtdemux, "H264", buffer, end - buffer);
7041 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
7046 GST_MEMDUMP_OBJECT (qtdemux, "avc1", buffer, end - buffer);
7047 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
7052 GST_MEMDUMP_OBJECT (qtdemux, "avc3", buffer, end - buffer);
7053 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
7058 GST_MEMDUMP_OBJECT (qtdemux, "H265", buffer, end - buffer);
7059 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
7064 GST_MEMDUMP_OBJECT (qtdemux, "hvc1", buffer, end - buffer);
7065 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
7070 GST_MEMDUMP_OBJECT (qtdemux, "hev1", buffer, end - buffer);
7071 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
7076 qtdemux_parse_container (qtdemux, node, buffer + 86, end);
7081 GST_DEBUG_OBJECT (qtdemux, "parsing meta atom");
7082 qtdemux_parse_container (qtdemux, node, buffer + 12, end);
7087 GST_MEMDUMP_OBJECT (qtdemux, "mp4s", buffer, end - buffer);
7088 /* Skip 8 byte header, plus 8 byte version + flags + entry_count */
7089 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
7097 version = QT_UINT32 (buffer + 12);
7098 GST_DEBUG_OBJECT (qtdemux, "parsing XiTh atom version 0x%08x", version);
7105 GST_DEBUG_OBJECT (qtdemux, "unknown version 0x%08x", version);
7110 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
7115 qtdemux_parse_container (qtdemux, node, buffer + 0x34, end);
7120 qtdemux_parse_uuid (qtdemux, buffer, end - buffer);
7125 qtdemux_parse_container (qtdemux, node, buffer + 86, end);
7130 qtdemux_parse_container (qtdemux, node, buffer + 36, end);
7134 if (!strcmp (type->name, "unknown"))
7135 GST_MEMDUMP ("Unknown tag", buffer + 4, end - buffer - 4);
7139 GST_LOG_OBJECT (qtdemux, "parsed '%" GST_FOURCC_FORMAT "'",
7140 GST_FOURCC_ARGS (fourcc));
7146 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
7147 (_("This file is corrupt and cannot be played.")),
7148 ("Not enough data for an atom header, got only %u bytes", length));
7153 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
7154 (_("This file is corrupt and cannot be played.")),
7155 ("Atom '%" GST_FOURCC_FORMAT "' has size of %u bytes, but we have only "
7156 "%u bytes available.", GST_FOURCC_ARGS (fourcc), node_length,
7163 qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc)
7167 guint32 child_fourcc;
7169 for (child = g_node_first_child (node); child;
7170 child = g_node_next_sibling (child)) {
7171 buffer = (guint8 *) child->data;
7173 child_fourcc = QT_FOURCC (buffer + 4);
7175 if (G_UNLIKELY (child_fourcc == fourcc)) {
7183 qtdemux_tree_get_child_by_type_full (GNode * node, guint32 fourcc,
7184 GstByteReader * parser)
7188 guint32 child_fourcc, child_len;
7190 for (child = g_node_first_child (node); child;
7191 child = g_node_next_sibling (child)) {
7192 buffer = (guint8 *) child->data;
7194 child_len = QT_UINT32 (buffer);
7195 child_fourcc = QT_FOURCC (buffer + 4);
7197 if (G_UNLIKELY (child_fourcc == fourcc)) {
7198 if (G_UNLIKELY (child_len < (4 + 4)))
7200 /* FIXME: must verify if atom length < parent atom length */
7201 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
7209 qtdemux_tree_get_sibling_by_type_full (GNode * node, guint32 fourcc,
7210 GstByteReader * parser)
7214 guint32 child_fourcc, child_len;
7216 for (child = g_node_next_sibling (node); child;
7217 child = g_node_next_sibling (child)) {
7218 buffer = (guint8 *) child->data;
7220 child_fourcc = QT_FOURCC (buffer + 4);
7222 if (child_fourcc == fourcc) {
7224 child_len = QT_UINT32 (buffer);
7225 if (G_UNLIKELY (child_len < (4 + 4)))
7227 /* FIXME: must verify if atom length < parent atom length */
7228 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
7237 qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc)
7239 return qtdemux_tree_get_sibling_by_type_full (node, fourcc, NULL);
7243 qtdemux_do_allocation (GstQTDemux * qtdemux, QtDemuxStream * stream)
7245 /* FIXME: This can only reliably work if demuxers have a
7246 * separate streaming thread per srcpad. This should be
7247 * done in a demuxer base class, which integrates parts
7250 * https://bugzilla.gnome.org/show_bug.cgi?id=701856
7255 query = gst_query_new_allocation (stream->caps, FALSE);
7257 if (!gst_pad_peer_query (stream->pad, query)) {
7258 /* not a problem, just debug a little */
7259 GST_DEBUG_OBJECT (qtdemux, "peer ALLOCATION query failed");
7262 if (stream->allocator)
7263 gst_object_unref (stream->allocator);
7265 if (gst_query_get_n_allocation_params (query) > 0) {
7266 /* try the allocator */
7267 gst_query_parse_nth_allocation_param (query, 0, &stream->allocator,
7269 stream->use_allocator = TRUE;
7271 stream->allocator = NULL;
7272 gst_allocation_params_init (&stream->params);
7273 stream->use_allocator = FALSE;
7275 gst_query_unref (query);
7280 gst_qtdemux_configure_protected_caps (GstQTDemux * qtdemux,
7281 QtDemuxStream * stream)
7284 const gchar *selected_system;
7286 g_return_val_if_fail (qtdemux != NULL, FALSE);
7287 g_return_val_if_fail (stream != NULL, FALSE);
7288 g_return_val_if_fail (gst_caps_get_size (stream->caps) == 1, FALSE);
7290 if (stream->protection_scheme_type != FOURCC_cenc) {
7291 GST_ERROR_OBJECT (qtdemux, "unsupported protection scheme");
7294 if (qtdemux->protection_system_ids == NULL) {
7295 GST_ERROR_OBJECT (qtdemux, "stream is protected using cenc, but no "
7296 "cenc protection system information has been found");
7299 g_ptr_array_add (qtdemux->protection_system_ids, NULL);
7300 selected_system = gst_protection_select_system ((const gchar **)
7301 qtdemux->protection_system_ids->pdata);
7302 g_ptr_array_remove_index (qtdemux->protection_system_ids,
7303 qtdemux->protection_system_ids->len - 1);
7304 if (!selected_system) {
7305 GST_ERROR_OBJECT (qtdemux, "stream is protected, but no "
7306 "suitable decryptor element has been found");
7310 s = gst_caps_get_structure (stream->caps, 0);
7311 if (!gst_structure_has_name (s, "application/x-cenc")) {
7312 gst_structure_set (s,
7313 "original-media-type", G_TYPE_STRING, gst_structure_get_name (s),
7314 GST_PROTECTION_SYSTEM_ID_CAPS_FIELD, G_TYPE_STRING, selected_system,
7316 gst_structure_set_name (s, "application/x-cenc");
7322 gst_qtdemux_configure_stream (GstQTDemux * qtdemux, QtDemuxStream * stream)
7324 if (stream->subtype == FOURCC_vide) {
7325 /* fps is calculated base on the duration of the average framerate since
7326 * qt does not have a fixed framerate. */
7327 gboolean fps_available = TRUE;
7329 if ((stream->n_samples == 1) && (stream->first_duration == 0)) {
7334 if (stream->duration == 0 || stream->n_samples < 2) {
7335 stream->fps_n = stream->timescale;
7337 fps_available = FALSE;
7339 GstClockTime avg_duration;
7343 /* duration and n_samples can be updated for fragmented format
7344 * so, framerate of fragmented format is calculated using data in a moof */
7345 if (qtdemux->fragmented && stream->n_samples_moof > 0
7346 && stream->duration_moof > 0) {
7347 n_samples = stream->n_samples_moof;
7348 duration = stream->duration_moof;
7350 n_samples = stream->n_samples;
7351 duration = stream->duration;
7354 /* Calculate a framerate, ignoring the first sample which is sometimes truncated */
7355 /* stream->duration is guint64, timescale, n_samples are guint32 */
7357 gst_util_uint64_scale_round (duration -
7358 stream->first_duration, GST_SECOND,
7359 (guint64) (stream->timescale) * (n_samples - 1));
7361 GST_LOG_OBJECT (qtdemux,
7362 "Calculating avg sample duration based on stream (or moof) duration %"
7364 " minus first sample %u, leaving %d samples gives %"
7365 GST_TIME_FORMAT, duration, stream->first_duration,
7366 n_samples - 1, GST_TIME_ARGS (avg_duration));
7368 gst_video_guess_framerate (avg_duration, &stream->fps_n,
7371 GST_DEBUG_OBJECT (qtdemux,
7372 "Calculating framerate, timescale %u gave fps_n %d fps_d %d",
7373 stream->timescale, stream->fps_n, stream->fps_d);
7378 stream->caps = gst_caps_make_writable (stream->caps);
7380 gst_caps_set_simple (stream->caps,
7381 "width", G_TYPE_INT, stream->width,
7382 "height", G_TYPE_INT, stream->height, NULL);
7384 /* set framerate if calculated framerate is reliable */
7385 if (fps_available) {
7386 gst_caps_set_simple (stream->caps,
7387 "framerate", GST_TYPE_FRACTION, stream->fps_n, stream->fps_d, NULL);
7390 /* calculate pixel-aspect-ratio using display width and height */
7391 GST_DEBUG_OBJECT (qtdemux,
7392 "video size %dx%d, target display size %dx%d", stream->width,
7393 stream->height, stream->display_width, stream->display_height);
7394 /* qt file might have pasp atom */
7395 if (stream->par_w > 0 && stream->par_h > 0) {
7396 GST_DEBUG_OBJECT (qtdemux, "par %d:%d", stream->par_w, stream->par_h);
7397 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
7398 GST_TYPE_FRACTION, stream->par_w, stream->par_h, NULL);
7399 } else if (stream->display_width > 0 && stream->display_height > 0 &&
7400 stream->width > 0 && stream->height > 0) {
7403 /* calculate the pixel aspect ratio using the display and pixel w/h */
7404 n = stream->display_width * stream->height;
7405 d = stream->display_height * stream->width;
7408 GST_DEBUG_OBJECT (qtdemux, "setting PAR to %d/%d", n, d);
7411 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
7412 GST_TYPE_FRACTION, stream->par_w, stream->par_h, NULL);
7415 if (stream->multiview_mode != GST_VIDEO_MULTIVIEW_MODE_NONE) {
7416 guint par_w = 1, par_h = 1;
7418 if (stream->par_w > 0 && stream->par_h > 0) {
7419 par_w = stream->par_w;
7420 par_h = stream->par_h;
7423 if (gst_video_multiview_guess_half_aspect (stream->multiview_mode,
7424 stream->width, stream->height, par_w, par_h)) {
7425 stream->multiview_flags |= GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT;
7428 gst_caps_set_simple (stream->caps,
7429 "multiview-mode", G_TYPE_STRING,
7430 gst_video_multiview_mode_to_caps_string (stream->multiview_mode),
7431 "multiview-flags", GST_TYPE_VIDEO_MULTIVIEW_FLAGSET,
7432 stream->multiview_flags, GST_FLAG_SET_MASK_EXACT, NULL);
7437 else if (stream->subtype == FOURCC_soun) {
7439 stream->caps = gst_caps_make_writable (stream->caps);
7440 if (stream->rate > 0)
7441 gst_caps_set_simple (stream->caps,
7442 "rate", G_TYPE_INT, (int) stream->rate, NULL);
7443 if (stream->n_channels > 0)
7444 gst_caps_set_simple (stream->caps,
7445 "channels", G_TYPE_INT, stream->n_channels, NULL);
7446 if (stream->n_channels > 2) {
7447 /* FIXME: Need to parse the 'chan' atom to get channel layouts
7448 * correctly; this is just the minimum we can do - assume
7449 * we don't actually have any channel positions. */
7450 gst_caps_set_simple (stream->caps,
7451 "channel-mask", GST_TYPE_BITMASK, G_GUINT64_CONSTANT (0), NULL);
7457 GST_PAD_ELEMENT_PRIVATE (stream->pad) = stream;
7458 gst_pad_set_event_function (stream->pad, gst_qtdemux_handle_src_event);
7459 gst_pad_set_query_function (stream->pad, gst_qtdemux_handle_src_query);
7460 gst_pad_set_active (stream->pad, TRUE);
7462 gst_pad_use_fixed_caps (stream->pad);
7464 if (stream->protected) {
7465 if (!gst_qtdemux_configure_protected_caps (qtdemux, stream)) {
7466 GST_ERROR_OBJECT (qtdemux,
7467 "Failed to configure protected stream caps.");
7472 GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT, stream->caps);
7473 if (stream->new_stream) {
7476 GstStreamFlags stream_flags;
7479 gst_pad_get_sticky_event (qtdemux->sinkpad, GST_EVENT_STREAM_START,
7482 if (gst_event_parse_group_id (event, &qtdemux->group_id))
7483 qtdemux->have_group_id = TRUE;
7485 qtdemux->have_group_id = FALSE;
7486 gst_event_unref (event);
7487 } else if (!qtdemux->have_group_id) {
7488 qtdemux->have_group_id = TRUE;
7489 qtdemux->group_id = gst_util_group_id_next ();
7492 stream->new_stream = FALSE;
7494 gst_pad_create_stream_id_printf (stream->pad,
7495 GST_ELEMENT_CAST (qtdemux), "%03u", stream->track_id);
7496 event = gst_event_new_stream_start (stream_id);
7497 if (qtdemux->have_group_id)
7498 gst_event_set_group_id (event, qtdemux->group_id);
7499 stream_flags = GST_STREAM_FLAG_NONE;
7500 if (stream->disabled)
7501 stream_flags |= GST_STREAM_FLAG_UNSELECT;
7503 stream_flags |= GST_STREAM_FLAG_SPARSE;
7504 gst_event_set_stream_flags (event, stream_flags);
7505 gst_pad_push_event (stream->pad, event);
7508 gst_pad_set_caps (stream->pad, stream->caps);
7509 stream->new_caps = FALSE;
7515 gst_qtdemux_add_stream (GstQTDemux * qtdemux,
7516 QtDemuxStream * stream, GstTagList * list)
7518 gboolean ret = TRUE;
7519 /* consistent default for push based mode */
7520 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
7522 if (stream->subtype == FOURCC_vide) {
7523 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
7526 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
7529 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
7530 gst_object_unref (stream->pad);
7536 qtdemux->n_video_streams++;
7537 } else if (stream->subtype == FOURCC_soun) {
7538 gchar *name = g_strdup_printf ("audio_%u", qtdemux->n_audio_streams);
7541 gst_pad_new_from_static_template (&gst_qtdemux_audiosrc_template, name);
7543 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
7544 gst_object_unref (stream->pad);
7549 qtdemux->n_audio_streams++;
7550 } else if (stream->subtype == FOURCC_strm) {
7551 GST_DEBUG_OBJECT (qtdemux, "stream type, not creating pad");
7552 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
7553 || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt) {
7554 gchar *name = g_strdup_printf ("subtitle_%u", qtdemux->n_sub_streams);
7557 gst_pad_new_from_static_template (&gst_qtdemux_subsrc_template, name);
7559 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
7560 gst_object_unref (stream->pad);
7565 qtdemux->n_sub_streams++;
7566 } else if (stream->caps) {
7567 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
7570 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
7572 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
7573 gst_object_unref (stream->pad);
7578 qtdemux->n_video_streams++;
7580 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
7587 GST_DEBUG_OBJECT (qtdemux, "adding pad %s %p to qtdemux %p",
7588 GST_OBJECT_NAME (stream->pad), stream->pad, qtdemux);
7589 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
7590 gst_flow_combiner_add_pad (qtdemux->flowcombiner, stream->pad);
7592 if (stream->pending_tags)
7593 gst_tag_list_unref (stream->pending_tags);
7594 stream->pending_tags = list;
7596 /* global tags go on each pad anyway */
7597 stream->send_global_tags = TRUE;
7598 /* send upstream GST_EVENT_PROTECTION events that were received before
7599 this source pad was created */
7600 for (l = qtdemux->protection_event_queue.head; l != NULL; l = l->next)
7601 gst_pad_push_event (stream->pad, gst_event_ref (l->data));
7605 gst_tag_list_unref (list);
7609 /* find next atom with @fourcc starting at @offset */
7610 static GstFlowReturn
7611 qtdemux_find_atom (GstQTDemux * qtdemux, guint64 * offset,
7612 guint64 * length, guint32 fourcc)
7618 GST_LOG_OBJECT (qtdemux, "finding fourcc %" GST_FOURCC_FORMAT " at offset %"
7619 G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), *offset);
7625 ret = gst_pad_pull_range (qtdemux->sinkpad, *offset, 16, &buf);
7626 if (G_UNLIKELY (ret != GST_FLOW_OK))
7628 if (G_UNLIKELY (gst_buffer_get_size (buf) != 16)) {
7631 gst_buffer_unref (buf);
7634 gst_buffer_map (buf, &map, GST_MAP_READ);
7635 extract_initial_length_and_fourcc (map.data, 16, length, &lfourcc);
7636 gst_buffer_unmap (buf, &map);
7637 gst_buffer_unref (buf);
7639 if (G_UNLIKELY (*length == 0)) {
7640 GST_DEBUG_OBJECT (qtdemux, "invalid length 0");
7641 ret = GST_FLOW_ERROR;
7645 if (lfourcc == fourcc) {
7646 GST_DEBUG_OBJECT (qtdemux, "found fourcc at offset %" G_GUINT64_FORMAT,
7650 GST_LOG_OBJECT (qtdemux,
7651 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
7652 GST_FOURCC_ARGS (fourcc), *offset);
7661 /* might simply have had last one */
7662 GST_DEBUG_OBJECT (qtdemux, "fourcc not found");
7667 /* should only do something in pull mode */
7668 /* call with OBJECT lock */
7669 static GstFlowReturn
7670 qtdemux_add_fragmented_samples (GstQTDemux * qtdemux)
7672 guint64 length, offset;
7673 GstBuffer *buf = NULL;
7674 GstFlowReturn ret = GST_FLOW_OK;
7675 GstFlowReturn res = GST_FLOW_OK;
7678 offset = qtdemux->moof_offset;
7679 GST_DEBUG_OBJECT (qtdemux, "next moof at offset %" G_GUINT64_FORMAT, offset);
7682 GST_DEBUG_OBJECT (qtdemux, "no next moof");
7683 return GST_FLOW_EOS;
7686 /* best not do pull etc with lock held */
7687 GST_OBJECT_UNLOCK (qtdemux);
7689 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
7690 if (ret != GST_FLOW_OK)
7693 ret = gst_qtdemux_pull_atom (qtdemux, offset, length, &buf);
7694 if (G_UNLIKELY (ret != GST_FLOW_OK))
7696 gst_buffer_map (buf, &map, GST_MAP_READ);
7697 if (!qtdemux_parse_moof (qtdemux, map.data, map.size, offset, NULL)) {
7698 gst_buffer_unmap (buf, &map);
7699 gst_buffer_unref (buf);
7704 gst_buffer_unmap (buf, &map);
7705 gst_buffer_unref (buf);
7709 /* look for next moof */
7710 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
7711 if (G_UNLIKELY (ret != GST_FLOW_OK))
7715 GST_OBJECT_LOCK (qtdemux);
7717 qtdemux->moof_offset = offset;
7723 GST_DEBUG_OBJECT (qtdemux, "failed to parse moof");
7725 res = GST_FLOW_ERROR;
7730 /* maybe upstream temporarily flushing */
7731 if (ret != GST_FLOW_FLUSHING) {
7732 GST_DEBUG_OBJECT (qtdemux, "no next moof");
7735 GST_DEBUG_OBJECT (qtdemux, "upstream WRONG_STATE");
7736 /* resume at current position next time */
7743 /* initialise bytereaders for stbl sub-atoms */
7745 qtdemux_stbl_init (GstQTDemux * qtdemux, QtDemuxStream * stream, GNode * stbl)
7747 stream->stbl_index = -1; /* no samples have yet been parsed */
7748 stream->sample_index = -1;
7750 /* time-to-sample atom */
7751 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stts, &stream->stts))
7754 /* copy atom data into a new buffer for later use */
7755 stream->stts.data = g_memdup (stream->stts.data, stream->stts.size);
7757 /* skip version + flags */
7758 if (!gst_byte_reader_skip (&stream->stts, 1 + 3) ||
7759 !gst_byte_reader_get_uint32_be (&stream->stts, &stream->n_sample_times))
7761 GST_LOG_OBJECT (qtdemux, "%u timestamp blocks", stream->n_sample_times);
7763 /* make sure there's enough data */
7764 if (!qt_atom_parser_has_chunks (&stream->stts, stream->n_sample_times, 8)) {
7765 stream->n_sample_times = gst_byte_reader_get_remaining (&stream->stts) / 8;
7766 GST_LOG_OBJECT (qtdemux, "overriding to %u timestamp blocks",
7767 stream->n_sample_times);
7768 if (!stream->n_sample_times)
7772 /* sync sample atom */
7773 stream->stps_present = FALSE;
7774 if ((stream->stss_present =
7775 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stss,
7776 &stream->stss) ? TRUE : FALSE) == TRUE) {
7777 /* copy atom data into a new buffer for later use */
7778 stream->stss.data = g_memdup (stream->stss.data, stream->stss.size);
7780 /* skip version + flags */
7781 if (!gst_byte_reader_skip (&stream->stss, 1 + 3) ||
7782 !gst_byte_reader_get_uint32_be (&stream->stss, &stream->n_sample_syncs))
7785 if (stream->n_sample_syncs) {
7786 /* make sure there's enough data */
7787 if (!qt_atom_parser_has_chunks (&stream->stss, stream->n_sample_syncs, 4))
7791 /* partial sync sample atom */
7792 if ((stream->stps_present =
7793 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stps,
7794 &stream->stps) ? TRUE : FALSE) == TRUE) {
7795 /* copy atom data into a new buffer for later use */
7796 stream->stps.data = g_memdup (stream->stps.data, stream->stps.size);
7798 /* skip version + flags */
7799 if (!gst_byte_reader_skip (&stream->stps, 1 + 3) ||
7800 !gst_byte_reader_get_uint32_be (&stream->stps,
7801 &stream->n_sample_partial_syncs))
7804 /* if there are no entries, the stss table contains the real
7806 if (stream->n_sample_partial_syncs) {
7807 /* make sure there's enough data */
7808 if (!qt_atom_parser_has_chunks (&stream->stps,
7809 stream->n_sample_partial_syncs, 4))
7816 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsz, &stream->stsz))
7819 /* copy atom data into a new buffer for later use */
7820 stream->stsz.data = g_memdup (stream->stsz.data, stream->stsz.size);
7822 /* skip version + flags */
7823 if (!gst_byte_reader_skip (&stream->stsz, 1 + 3) ||
7824 !gst_byte_reader_get_uint32_be (&stream->stsz, &stream->sample_size))
7827 if (!gst_byte_reader_get_uint32_be (&stream->stsz, &stream->n_samples))
7830 if (!stream->n_samples)
7833 /* sample-to-chunk atom */
7834 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsc, &stream->stsc))
7837 /* copy atom data into a new buffer for later use */
7838 stream->stsc.data = g_memdup (stream->stsc.data, stream->stsc.size);
7840 /* skip version + flags */
7841 if (!gst_byte_reader_skip (&stream->stsc, 1 + 3) ||
7842 !gst_byte_reader_get_uint32_be (&stream->stsc,
7843 &stream->n_samples_per_chunk))
7846 GST_DEBUG_OBJECT (qtdemux, "n_samples_per_chunk %u",
7847 stream->n_samples_per_chunk);
7849 /* make sure there's enough data */
7850 if (!qt_atom_parser_has_chunks (&stream->stsc, stream->n_samples_per_chunk,
7856 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stco, &stream->stco))
7857 stream->co_size = sizeof (guint32);
7858 else if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_co64,
7860 stream->co_size = sizeof (guint64);
7864 /* copy atom data into a new buffer for later use */
7865 stream->stco.data = g_memdup (stream->stco.data, stream->stco.size);
7867 /* skip version + flags */
7868 if (!gst_byte_reader_skip (&stream->stco, 1 + 3))
7871 /* chunks_are_samples == TRUE means treat chunks as samples */
7872 stream->chunks_are_samples = stream->sample_size && !stream->sampled;
7873 if (stream->chunks_are_samples) {
7874 /* treat chunks as samples */
7875 if (!gst_byte_reader_get_uint32_be (&stream->stco, &stream->n_samples))
7878 /* skip number of entries */
7879 if (!gst_byte_reader_skip (&stream->stco, 4))
7882 /* make sure there are enough data in the stsz atom */
7883 if (!stream->sample_size) {
7884 /* different sizes for each sample */
7885 if (!qt_atom_parser_has_chunks (&stream->stsz, stream->n_samples, 4))
7890 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
7891 stream->n_samples, (guint) sizeof (QtDemuxSample),
7892 stream->n_samples * sizeof (QtDemuxSample) / (1024.0 * 1024.0));
7894 if (stream->n_samples >=
7895 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample)) {
7896 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
7897 "be larger than %uMB (broken file?)", stream->n_samples,
7898 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
7902 g_assert (stream->samples == NULL);
7903 stream->samples = g_try_new0 (QtDemuxSample, stream->n_samples);
7904 if (!stream->samples) {
7905 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
7910 /* composition time-to-sample */
7911 if ((stream->ctts_present =
7912 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_ctts,
7913 &stream->ctts) ? TRUE : FALSE) == TRUE) {
7914 GstByteReader cslg = GST_BYTE_READER_INIT (NULL, 0);
7916 /* copy atom data into a new buffer for later use */
7917 stream->ctts.data = g_memdup (stream->ctts.data, stream->ctts.size);
7919 /* skip version + flags */
7920 if (!gst_byte_reader_skip (&stream->ctts, 1 + 3)
7921 || !gst_byte_reader_get_uint32_be (&stream->ctts,
7922 &stream->n_composition_times))
7925 /* make sure there's enough data */
7926 if (!qt_atom_parser_has_chunks (&stream->ctts, stream->n_composition_times,
7930 /* This is optional, if missing we iterate the ctts */
7931 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_cslg, &cslg)) {
7932 if (!gst_byte_reader_skip (&cslg, 1 + 3)
7933 || !gst_byte_reader_get_uint32_be (&cslg, &stream->cslg_shift)) {
7934 g_free ((gpointer) cslg.data);
7938 gint32 cslg_least = 0;
7939 guint num_entries, pos;
7942 pos = gst_byte_reader_get_pos (&stream->ctts);
7943 num_entries = stream->n_composition_times;
7945 stream->cslg_shift = 0;
7947 for (i = 0; i < num_entries; i++) {
7950 gst_byte_reader_skip_unchecked (&stream->ctts, 4);
7951 offset = gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
7953 if (offset < cslg_least)
7954 cslg_least = offset;
7958 stream->cslg_shift = ABS (cslg_least);
7960 stream->cslg_shift = 0;
7962 /* reset the reader so we can generate sample table */
7963 gst_byte_reader_set_pos (&stream->ctts, pos);
7966 /* Ensure the cslg_shift value is consistent so we can use it
7967 * unconditionnally to produce TS and Segment */
7968 stream->cslg_shift = 0;
7975 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
7976 (_("This file is corrupt and cannot be played.")), (NULL));
7981 gst_qtdemux_stbl_free (stream);
7982 if (!qtdemux->fragmented) {
7983 /* not quite good */
7984 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
7987 /* may pick up samples elsewhere */
7993 /* collect samples from the next sample to be parsed up to sample @n for @stream
7994 * by reading the info from @stbl
7996 * This code can be executed from both the streaming thread and the seeking
7997 * thread so it takes the object lock to protect itself
8000 qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream, guint32 n)
8003 QtDemuxSample *samples, *first, *cur, *last;
8004 guint32 n_samples_per_chunk;
8007 GST_LOG_OBJECT (qtdemux, "parsing samples for stream fourcc %"
8008 GST_FOURCC_FORMAT ", pad %s", GST_FOURCC_ARGS (stream->fourcc),
8009 stream->pad ? GST_PAD_NAME (stream->pad) : "(NULL)");
8011 n_samples = stream->n_samples;
8014 goto out_of_samples;
8016 GST_OBJECT_LOCK (qtdemux);
8017 if (n <= stream->stbl_index)
8018 goto already_parsed;
8020 GST_DEBUG_OBJECT (qtdemux, "parsing up to sample %u", n);
8022 if (!stream->stsz.data) {
8023 /* so we already parsed and passed all the moov samples;
8024 * onto fragmented ones */
8025 g_assert (qtdemux->fragmented);
8029 /* pointer to the sample table */
8030 samples = stream->samples;
8032 /* starts from -1, moves to the next sample index to parse */
8033 stream->stbl_index++;
8035 /* keep track of the first and last sample to fill */
8036 first = &samples[stream->stbl_index];
8039 if (!stream->chunks_are_samples) {
8040 /* set the sample sizes */
8041 if (stream->sample_size == 0) {
8042 /* different sizes for each sample */
8043 for (cur = first; cur <= last; cur++) {
8044 cur->size = gst_byte_reader_get_uint32_be_unchecked (&stream->stsz);
8045 GST_LOG_OBJECT (qtdemux, "sample %d has size %u",
8046 (guint) (cur - samples), cur->size);
8049 /* samples have the same size */
8050 GST_LOG_OBJECT (qtdemux, "all samples have size %u", stream->sample_size);
8051 for (cur = first; cur <= last; cur++)
8052 cur->size = stream->sample_size;
8056 n_samples_per_chunk = stream->n_samples_per_chunk;
8059 for (i = stream->stsc_index; i < n_samples_per_chunk; i++) {
8062 if (stream->stsc_chunk_index >= stream->last_chunk
8063 || stream->stsc_chunk_index < stream->first_chunk) {
8064 stream->first_chunk =
8065 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
8066 stream->samples_per_chunk =
8067 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
8068 gst_byte_reader_skip_unchecked (&stream->stsc, 4);
8070 /* chunk numbers are counted from 1 it seems */
8071 if (G_UNLIKELY (stream->first_chunk == 0))
8074 --stream->first_chunk;
8076 /* the last chunk of each entry is calculated by taking the first chunk
8077 * of the next entry; except if there is no next, where we fake it with
8079 if (G_UNLIKELY (i == (stream->n_samples_per_chunk - 1))) {
8080 stream->last_chunk = G_MAXUINT32;
8082 stream->last_chunk =
8083 gst_byte_reader_peek_uint32_be_unchecked (&stream->stsc);
8084 if (G_UNLIKELY (stream->last_chunk == 0))
8087 --stream->last_chunk;
8090 GST_LOG_OBJECT (qtdemux,
8091 "entry %d has first_chunk %d, last_chunk %d, samples_per_chunk %d", i,
8092 stream->first_chunk, stream->last_chunk, stream->samples_per_chunk);
8094 if (G_UNLIKELY (stream->last_chunk < stream->first_chunk))
8097 if (stream->last_chunk != G_MAXUINT32) {
8098 if (!qt_atom_parser_peek_sub (&stream->stco,
8099 stream->first_chunk * stream->co_size,
8100 (stream->last_chunk - stream->first_chunk) * stream->co_size,
8105 stream->co_chunk = stream->stco;
8106 if (!gst_byte_reader_skip (&stream->co_chunk,
8107 stream->first_chunk * stream->co_size))
8111 stream->stsc_chunk_index = stream->first_chunk;
8114 last_chunk = stream->last_chunk;
8116 if (stream->chunks_are_samples) {
8117 cur = &samples[stream->stsc_chunk_index];
8119 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
8122 stream->stsc_chunk_index = j;
8127 qt_atom_parser_get_offset_unchecked (&stream->co_chunk,
8130 GST_LOG_OBJECT (qtdemux, "Created entry %d with offset "
8131 "%" G_GUINT64_FORMAT, j, cur->offset);
8133 if (stream->samples_per_frame * stream->bytes_per_frame) {
8135 (stream->samples_per_chunk * stream->n_channels) /
8136 stream->samples_per_frame * stream->bytes_per_frame;
8138 cur->size = stream->samples_per_chunk;
8141 GST_DEBUG_OBJECT (qtdemux,
8142 "keyframe sample %d: timestamp %" GST_TIME_FORMAT ", size %u",
8143 j, GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream,
8144 stream->stco_sample_index)), cur->size);
8146 cur->timestamp = stream->stco_sample_index;
8147 cur->duration = stream->samples_per_chunk;
8148 cur->keyframe = TRUE;
8151 stream->stco_sample_index += stream->samples_per_chunk;
8153 stream->stsc_chunk_index = j;
8155 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
8156 guint32 samples_per_chunk;
8157 guint64 chunk_offset;
8159 if (!stream->stsc_sample_index
8160 && !qt_atom_parser_get_offset (&stream->co_chunk, stream->co_size,
8161 &stream->chunk_offset))
8164 samples_per_chunk = stream->samples_per_chunk;
8165 chunk_offset = stream->chunk_offset;
8167 for (k = stream->stsc_sample_index; k < samples_per_chunk; k++) {
8168 GST_LOG_OBJECT (qtdemux, "creating entry %d with offset %"
8169 G_GUINT64_FORMAT " and size %d",
8170 (guint) (cur - samples), chunk_offset, cur->size);
8172 cur->offset = chunk_offset;
8173 chunk_offset += cur->size;
8176 if (G_UNLIKELY (cur > last)) {
8178 stream->stsc_sample_index = k + 1;
8179 stream->chunk_offset = chunk_offset;
8180 stream->stsc_chunk_index = j;
8184 stream->stsc_sample_index = 0;
8186 stream->stsc_chunk_index = j;
8188 stream->stsc_index++;
8191 if (stream->chunks_are_samples)
8195 guint32 n_sample_times;
8197 n_sample_times = stream->n_sample_times;
8200 for (i = stream->stts_index; i < n_sample_times; i++) {
8201 guint32 stts_samples;
8202 gint32 stts_duration;
8205 if (stream->stts_sample_index >= stream->stts_samples
8206 || !stream->stts_sample_index) {
8208 stream->stts_samples =
8209 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
8210 stream->stts_duration =
8211 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
8213 GST_LOG_OBJECT (qtdemux, "block %d, %u timestamps, duration %u",
8214 i, stream->stts_samples, stream->stts_duration);
8216 stream->stts_sample_index = 0;
8219 stts_samples = stream->stts_samples;
8220 stts_duration = stream->stts_duration;
8221 stts_time = stream->stts_time;
8223 for (j = stream->stts_sample_index; j < stts_samples; j++) {
8224 GST_DEBUG_OBJECT (qtdemux,
8225 "sample %d: index %d, timestamp %" GST_TIME_FORMAT,
8226 (guint) (cur - samples), j,
8227 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stts_time)));
8229 cur->timestamp = stts_time;
8230 cur->duration = stts_duration;
8232 /* avoid 32-bit wrap-around,
8233 * but still mind possible 'negative' duration */
8234 stts_time += (gint64) stts_duration;
8237 if (G_UNLIKELY (cur > last)) {
8239 stream->stts_time = stts_time;
8240 stream->stts_sample_index = j + 1;
8244 stream->stts_sample_index = 0;
8245 stream->stts_time = stts_time;
8246 stream->stts_index++;
8248 /* fill up empty timestamps with the last timestamp, this can happen when
8249 * the last samples do not decode and so we don't have timestamps for them.
8250 * We however look at the last timestamp to estimate the track length so we
8251 * need something in here. */
8252 for (; cur < last; cur++) {
8253 GST_DEBUG_OBJECT (qtdemux,
8254 "fill sample %d: timestamp %" GST_TIME_FORMAT,
8255 (guint) (cur - samples),
8256 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stream->stts_time)));
8257 cur->timestamp = stream->stts_time;
8263 /* sample sync, can be NULL */
8264 if (stream->stss_present == TRUE) {
8265 guint32 n_sample_syncs;
8267 n_sample_syncs = stream->n_sample_syncs;
8269 if (!n_sample_syncs) {
8270 GST_DEBUG_OBJECT (qtdemux, "all samples are keyframes");
8271 stream->all_keyframe = TRUE;
8273 for (i = stream->stss_index; i < n_sample_syncs; i++) {
8274 /* note that the first sample is index 1, not 0 */
8277 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stss);
8279 if (G_LIKELY (index > 0 && index <= n_samples)) {
8281 samples[index].keyframe = TRUE;
8282 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
8283 /* and exit if we have enough samples */
8284 if (G_UNLIKELY (index >= n)) {
8291 stream->stss_index = i;
8294 /* stps marks partial sync frames like open GOP I-Frames */
8295 if (stream->stps_present == TRUE) {
8296 guint32 n_sample_partial_syncs;
8298 n_sample_partial_syncs = stream->n_sample_partial_syncs;
8300 /* if there are no entries, the stss table contains the real
8302 if (n_sample_partial_syncs) {
8303 for (i = stream->stps_index; i < n_sample_partial_syncs; i++) {
8304 /* note that the first sample is index 1, not 0 */
8307 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stps);
8309 if (G_LIKELY (index > 0 && index <= n_samples)) {
8311 samples[index].keyframe = TRUE;
8312 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
8313 /* and exit if we have enough samples */
8314 if (G_UNLIKELY (index >= n)) {
8321 stream->stps_index = i;
8325 /* no stss, all samples are keyframes */
8326 stream->all_keyframe = TRUE;
8327 GST_DEBUG_OBJECT (qtdemux, "setting all keyframes");
8332 /* composition time to sample */
8333 if (stream->ctts_present == TRUE) {
8334 guint32 n_composition_times;
8336 gint32 ctts_soffset;
8338 /* Fill in the pts_offsets */
8340 n_composition_times = stream->n_composition_times;
8342 for (i = stream->ctts_index; i < n_composition_times; i++) {
8343 if (stream->ctts_sample_index >= stream->ctts_count
8344 || !stream->ctts_sample_index) {
8345 stream->ctts_count =
8346 gst_byte_reader_get_uint32_be_unchecked (&stream->ctts);
8347 stream->ctts_soffset =
8348 gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
8349 stream->ctts_sample_index = 0;
8352 ctts_count = stream->ctts_count;
8353 ctts_soffset = stream->ctts_soffset;
8355 for (j = stream->ctts_sample_index; j < ctts_count; j++) {
8356 cur->pts_offset = ctts_soffset;
8359 if (G_UNLIKELY (cur > last)) {
8361 stream->ctts_sample_index = j + 1;
8365 stream->ctts_sample_index = 0;
8366 stream->ctts_index++;
8370 stream->stbl_index = n;
8371 /* if index has been completely parsed, free data that is no-longer needed */
8372 if (n + 1 == stream->n_samples) {
8373 gst_qtdemux_stbl_free (stream);
8374 GST_DEBUG_OBJECT (qtdemux, "parsed all available samples;");
8375 if (qtdemux->pullbased) {
8376 GST_DEBUG_OBJECT (qtdemux, "checking for more samples");
8377 while (n + 1 == stream->n_samples)
8378 if (qtdemux_add_fragmented_samples (qtdemux) != GST_FLOW_OK)
8382 GST_OBJECT_UNLOCK (qtdemux);
8389 GST_LOG_OBJECT (qtdemux,
8390 "Tried to parse up to sample %u but this sample has already been parsed",
8392 /* if fragmented, there may be more */
8393 if (qtdemux->fragmented && n == stream->stbl_index)
8395 GST_OBJECT_UNLOCK (qtdemux);
8401 GST_LOG_OBJECT (qtdemux,
8402 "Tried to parse up to sample %u but there are only %u samples", n + 1,
8404 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8405 (_("This file is corrupt and cannot be played.")), (NULL));
8410 GST_OBJECT_UNLOCK (qtdemux);
8411 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8412 (_("This file is corrupt and cannot be played.")), (NULL));
8417 /* collect all segment info for @stream.
8420 qtdemux_parse_segments (GstQTDemux * qtdemux, QtDemuxStream * stream,
8424 /* accept edts if they contain gaps at start and there is only
8425 * one media segment */
8426 gboolean allow_pushbased_edts = TRUE;
8427 gint media_segments_count = 0;
8429 /* parse and prepare segment info from the edit list */
8430 GST_DEBUG_OBJECT (qtdemux, "looking for edit list container");
8431 stream->n_segments = 0;
8432 stream->segments = NULL;
8433 if ((edts = qtdemux_tree_get_child_by_type (trak, FOURCC_edts))) {
8436 gint i, count, entry_size;
8442 GST_DEBUG_OBJECT (qtdemux, "looking for edit list");
8443 if (!(elst = qtdemux_tree_get_child_by_type (edts, FOURCC_elst)))
8446 buffer = elst->data;
8448 version = QT_UINT8 (buffer + 8);
8449 entry_size = (version == 1) ? 20 : 12;
8451 n_segments = QT_UINT32 (buffer + 12);
8453 /* we might allocate a bit too much, at least allocate 1 segment */
8454 stream->segments = g_new (QtDemuxSegment, MAX (n_segments, 1));
8456 /* segments always start from 0 */
8460 for (i = 0; i < n_segments; i++) {
8463 gboolean time_valid = TRUE;
8464 QtDemuxSegment *segment;
8466 GstClockTime media_start = GST_CLOCK_TIME_NONE;
8469 media_time = QT_UINT64 (buffer + 24 + i * entry_size);
8470 duration = QT_UINT64 (buffer + 16 + i * entry_size);
8471 if (media_time == G_MAXUINT64)
8474 media_time = QT_UINT32 (buffer + 20 + i * entry_size);
8475 duration = QT_UINT32 (buffer + 16 + i * entry_size);
8476 if (media_time == G_MAXUINT32)
8481 media_start = QTSTREAMTIME_TO_GSTTIME (stream, media_time);
8483 segment = &stream->segments[count++];
8485 /* time and duration expressed in global timescale */
8486 segment->time = stime;
8487 /* add non scaled values so we don't cause roundoff errors */
8488 if (duration || media_start == GST_CLOCK_TIME_NONE) {
8490 stime = QTTIME_TO_GSTTIME (qtdemux, time);
8491 segment->duration = stime - segment->time;
8493 /* zero duration does not imply media_start == media_stop
8494 * but, only specify media_start.*/
8495 stime = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
8496 if (GST_CLOCK_TIME_IS_VALID (stime) && time_valid
8497 && stime >= media_start) {
8498 segment->duration = stime - media_start;
8500 segment->duration = GST_CLOCK_TIME_NONE;
8503 segment->stop_time = stime;
8505 segment->trak_media_start = media_time;
8506 /* media_time expressed in stream timescale */
8508 segment->media_start = media_start;
8509 segment->media_stop = segment->media_start + segment->duration;
8510 media_segments_count++;
8512 segment->media_start = GST_CLOCK_TIME_NONE;
8513 segment->media_stop = GST_CLOCK_TIME_NONE;
8516 QT_UINT32 (buffer + ((version == 1) ? 32 : 24) + i * entry_size);
8518 if (rate_int <= 1) {
8519 /* 0 is not allowed, some programs write 1 instead of the floating point
8521 GST_WARNING_OBJECT (qtdemux, "found suspicious rate %" G_GUINT32_FORMAT,
8525 segment->rate = rate_int / 65536.0;
8528 GST_DEBUG_OBJECT (qtdemux, "created segment %d time %" GST_TIME_FORMAT
8529 ", duration %" GST_TIME_FORMAT ", media_start %" GST_TIME_FORMAT
8530 " (%" G_GUINT64_FORMAT ") , media_stop %" GST_TIME_FORMAT
8531 " stop_time %" GST_TIME_FORMAT " rate %g, (%d) timescale %u",
8532 i, GST_TIME_ARGS (segment->time),
8533 GST_TIME_ARGS (segment->duration),
8534 GST_TIME_ARGS (segment->media_start), media_time,
8535 GST_TIME_ARGS (segment->media_stop),
8536 GST_TIME_ARGS (segment->stop_time), segment->rate, rate_int,
8538 if (segment->stop_time > qtdemux->segment.stop) {
8539 GST_WARNING_OBJECT (qtdemux, "Segment %d "
8540 " extends to %" GST_TIME_FORMAT
8541 " past the end of the file duration %" GST_TIME_FORMAT
8542 " it will be truncated", i, GST_TIME_ARGS (segment->stop_time),
8543 GST_TIME_ARGS (qtdemux->segment.stop));
8544 qtdemux->segment.stop = segment->stop_time;
8547 GST_DEBUG_OBJECT (qtdemux, "found %d segments", count);
8548 stream->n_segments = count;
8549 if (media_segments_count != 1)
8550 allow_pushbased_edts = FALSE;
8554 /* push based does not handle segments, so act accordingly here,
8555 * and warn if applicable */
8556 if (!qtdemux->pullbased && !allow_pushbased_edts) {
8557 GST_WARNING_OBJECT (qtdemux, "streaming; discarding edit list segments");
8558 /* remove and use default one below, we stream like it anyway */
8559 g_free (stream->segments);
8560 stream->segments = NULL;
8561 stream->n_segments = 0;
8564 /* no segments, create one to play the complete trak */
8565 if (stream->n_segments == 0) {
8566 GstClockTime stream_duration =
8567 QTSTREAMTIME_TO_GSTTIME (stream, stream->duration);
8569 if (stream->segments == NULL)
8570 stream->segments = g_new (QtDemuxSegment, 1);
8572 /* represent unknown our way */
8573 if (stream_duration == 0)
8574 stream_duration = GST_CLOCK_TIME_NONE;
8576 stream->segments[0].time = 0;
8577 stream->segments[0].stop_time = stream_duration;
8578 stream->segments[0].duration = stream_duration;
8579 stream->segments[0].media_start = 0;
8580 stream->segments[0].media_stop = stream_duration;
8581 stream->segments[0].rate = 1.0;
8582 stream->segments[0].trak_media_start = 0;
8584 GST_DEBUG_OBJECT (qtdemux, "created dummy segment %" GST_TIME_FORMAT,
8585 GST_TIME_ARGS (stream_duration));
8586 stream->n_segments = 1;
8587 stream->dummy_segment = TRUE;
8589 GST_DEBUG_OBJECT (qtdemux, "using %d segments", stream->n_segments);
8595 * Parses the stsd atom of a svq3 trak looking for
8596 * the SMI and gama atoms.
8599 qtdemux_parse_svq3_stsd_data (GstQTDemux * qtdemux, GNode * stsd,
8600 guint8 ** gamma, GstBuffer ** seqh)
8602 guint8 *_gamma = NULL;
8603 GstBuffer *_seqh = NULL;
8604 guint8 *stsd_data = stsd->data;
8605 guint32 length = QT_UINT32 (stsd_data);
8609 GST_WARNING_OBJECT (qtdemux, "stsd too short");
8615 version = QT_UINT16 (stsd_data);
8620 while (length > 8) {
8621 guint32 fourcc, size;
8623 size = QT_UINT32 (stsd_data);
8624 fourcc = QT_FOURCC (stsd_data + 4);
8625 data = stsd_data + 8;
8628 GST_WARNING_OBJECT (qtdemux, "Atom of size 0 found, aborting "
8629 "svq3 atom parsing");
8638 GST_WARNING_OBJECT (qtdemux, "Unexpected size %" G_GUINT32_FORMAT
8639 " for gama atom, expected 12", size);
8644 if (size > 16 && QT_FOURCC (data) == FOURCC_SEQH) {
8646 if (_seqh != NULL) {
8647 GST_WARNING_OBJECT (qtdemux, "Unexpected second SEQH SMI atom "
8648 " found, ignoring");
8650 seqh_size = QT_UINT32 (data + 4);
8651 if (seqh_size > 0) {
8652 _seqh = gst_buffer_new_and_alloc (seqh_size);
8653 gst_buffer_fill (_seqh, 0, data + 8, seqh_size);
8660 GST_WARNING_OBJECT (qtdemux, "Unhandled atom %" GST_FOURCC_FORMAT
8661 " in SVQ3 entry in stsd atom", GST_FOURCC_ARGS (fourcc));
8665 if (size <= length) {
8671 GST_WARNING_OBJECT (qtdemux, "SVQ3 entry too short in stsd atom");
8674 GST_WARNING_OBJECT (qtdemux, "Unexpected version for SVQ3 entry %"
8675 G_GUINT16_FORMAT, version);
8686 gst_buffer_unref (_seqh);
8691 qtdemux_get_rtsp_uri_from_hndl (GstQTDemux * qtdemux, GNode * minf)
8698 * Get 'dinf', to get its child 'dref', that might contain a 'hndl'
8699 * atom that might contain a 'data' atom with the rtsp uri.
8700 * This case was reported in bug #597497, some info about
8701 * the hndl atom can be found in TN1195
8703 dinf = qtdemux_tree_get_child_by_type (minf, FOURCC_dinf);
8704 GST_DEBUG_OBJECT (qtdemux, "Trying to obtain rtsp URI for stream trak");
8707 guint32 dref_num_entries = 0;
8708 if (qtdemux_tree_get_child_by_type_full (dinf, FOURCC_dref, &dref) &&
8709 gst_byte_reader_skip (&dref, 4) &&
8710 gst_byte_reader_get_uint32_be (&dref, &dref_num_entries)) {
8713 /* search dref entries for hndl atom */
8714 for (i = 0; i < dref_num_entries; i++) {
8715 guint32 size = 0, type;
8716 guint8 string_len = 0;
8717 if (gst_byte_reader_get_uint32_be (&dref, &size) &&
8718 qt_atom_parser_get_fourcc (&dref, &type)) {
8719 if (type == FOURCC_hndl) {
8720 GST_DEBUG_OBJECT (qtdemux, "Found hndl atom");
8722 /* skip data reference handle bytes and the
8723 * following pascal string and some extra 4
8724 * bytes I have no idea what are */
8725 if (!gst_byte_reader_skip (&dref, 4) ||
8726 !gst_byte_reader_get_uint8 (&dref, &string_len) ||
8727 !gst_byte_reader_skip (&dref, string_len + 4)) {
8728 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl atom");
8732 /* iterate over the atoms to find the data atom */
8733 while (gst_byte_reader_get_remaining (&dref) >= 8) {
8737 if (gst_byte_reader_get_uint32_be (&dref, &atom_size) &&
8738 qt_atom_parser_get_fourcc (&dref, &atom_type)) {
8739 if (atom_type == FOURCC_data) {
8740 const guint8 *uri_aux = NULL;
8742 /* found the data atom that might contain the rtsp uri */
8743 GST_DEBUG_OBJECT (qtdemux, "Found data atom inside "
8744 "hndl atom, interpreting it as an URI");
8745 if (gst_byte_reader_peek_data (&dref, atom_size - 8,
8747 if (g_strstr_len ((gchar *) uri_aux, 7, "rtsp://") != NULL)
8748 uri = g_strndup ((gchar *) uri_aux, atom_size - 8);
8750 GST_WARNING_OBJECT (qtdemux, "Data atom in hndl atom "
8751 "didn't contain a rtsp address");
8753 GST_WARNING_OBJECT (qtdemux, "Failed to get the data "
8758 /* skipping to the next entry */
8759 if (!gst_byte_reader_skip (&dref, atom_size - 8))
8762 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl child "
8769 /* skip to the next entry */
8770 if (!gst_byte_reader_skip (&dref, size - 8))
8773 GST_WARNING_OBJECT (qtdemux, "Error parsing dref atom");
8776 GST_DEBUG_OBJECT (qtdemux, "Finished parsing dref atom");
8782 #define AMR_NB_ALL_MODES 0x81ff
8783 #define AMR_WB_ALL_MODES 0x83ff
8785 qtdemux_parse_amr_bitrate (GstBuffer * buf, gboolean wb)
8787 /* The 'damr' atom is of the form:
8789 * | vendor | decoder_ver | mode_set | mode_change_period | frames/sample |
8790 * 32 b 8 b 16 b 8 b 8 b
8792 * The highest set bit of the first 7 (AMR-NB) or 8 (AMR-WB) bits of mode_set
8793 * represents the highest mode used in the stream (and thus the maximum
8794 * bitrate), with a couple of special cases as seen below.
8797 /* Map of frame type ID -> bitrate */
8798 static const guint nb_bitrates[] = {
8799 4750, 5150, 5900, 6700, 7400, 7950, 10200, 12200
8801 static const guint wb_bitrates[] = {
8802 6600, 8850, 12650, 14250, 15850, 18250, 19850, 23050, 23850
8808 gst_buffer_map (buf, &map, GST_MAP_READ);
8810 if (map.size != 0x11) {
8811 GST_DEBUG ("Atom should have size 0x11, not %" G_GSIZE_FORMAT, map.size);
8815 if (QT_FOURCC (map.data + 4) != FOURCC_damr) {
8816 GST_DEBUG ("Unknown atom in %" GST_FOURCC_FORMAT,
8817 GST_FOURCC_ARGS (QT_UINT32 (map.data + 4)));
8821 mode_set = QT_UINT16 (map.data + 13);
8823 if (mode_set == (wb ? AMR_WB_ALL_MODES : AMR_NB_ALL_MODES))
8824 max_mode = 7 + (wb ? 1 : 0);
8826 /* AMR-NB modes fo from 0-7, and AMR-WB modes go from 0-8 */
8827 max_mode = g_bit_nth_msf ((gulong) mode_set & (wb ? 0x1ff : 0xff), -1);
8829 if (max_mode == -1) {
8830 GST_DEBUG ("No mode indication was found (mode set) = %x",
8835 gst_buffer_unmap (buf, &map);
8836 return wb ? wb_bitrates[max_mode] : nb_bitrates[max_mode];
8839 gst_buffer_unmap (buf, &map);
8844 qtdemux_parse_transformation_matrix (GstQTDemux * qtdemux,
8845 GstByteReader * reader, guint32 * matrix, const gchar * atom)
8848 * 9 values of 32 bits (fixed point 16.16, except 2 5 and 8 that are 2.30)
8854 if (gst_byte_reader_get_remaining (reader) < 36)
8857 matrix[0] = gst_byte_reader_get_uint32_be_unchecked (reader);
8858 matrix[1] = gst_byte_reader_get_uint32_be_unchecked (reader);
8859 matrix[2] = gst_byte_reader_get_uint32_be_unchecked (reader);
8860 matrix[3] = gst_byte_reader_get_uint32_be_unchecked (reader);
8861 matrix[4] = gst_byte_reader_get_uint32_be_unchecked (reader);
8862 matrix[5] = gst_byte_reader_get_uint32_be_unchecked (reader);
8863 matrix[6] = gst_byte_reader_get_uint32_be_unchecked (reader);
8864 matrix[7] = gst_byte_reader_get_uint32_be_unchecked (reader);
8865 matrix[8] = gst_byte_reader_get_uint32_be_unchecked (reader);
8867 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix from atom %s", atom);
8868 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[0] >> 16,
8869 matrix[0] & 0xFFFF, matrix[1] >> 16, matrix[1] & 0xFF, matrix[2] >> 16,
8871 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[3] >> 16,
8872 matrix[3] & 0xFFFF, matrix[4] >> 16, matrix[4] & 0xFF, matrix[5] >> 16,
8874 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[6] >> 16,
8875 matrix[6] & 0xFFFF, matrix[7] >> 16, matrix[7] & 0xFF, matrix[8] >> 16,
8882 qtdemux_inspect_transformation_matrix (GstQTDemux * qtdemux,
8883 QtDemuxStream * stream, guint32 * matrix, GstTagList ** taglist)
8890 * This macro will only compare value abdegh, it expects cfi to have already
8893 #define QTCHECK_MATRIX(m,a,b,d,e) ((m)[0] == (a << 16) && (m)[1] == (b << 16) && \
8894 (m)[3] == (d << 16) && (m)[4] == (e << 16))
8896 /* only handle the cases where the last column has standard values */
8897 if (matrix[2] == 0 && matrix[5] == 0 && matrix[8] == 1 << 30) {
8898 const gchar *rotation_tag = NULL;
8900 /* no rotation needed */
8901 if (QTCHECK_MATRIX (matrix, 1, 0, 0, 1)) {
8903 } else if (QTCHECK_MATRIX (matrix, 0, 1, G_MAXUINT16, 0)) {
8904 rotation_tag = "rotate-90";
8905 } else if (QTCHECK_MATRIX (matrix, G_MAXUINT16, 0, 0, G_MAXUINT16)) {
8906 rotation_tag = "rotate-180";
8907 } else if (QTCHECK_MATRIX (matrix, 0, G_MAXUINT16, 1, 0)) {
8908 rotation_tag = "rotate-270";
8910 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
8913 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix rotation %s",
8915 if (rotation_tag != NULL) {
8916 if (*taglist == NULL)
8917 *taglist = gst_tag_list_new_empty ();
8918 gst_tag_list_add (*taglist, GST_TAG_MERGE_REPLACE,
8919 GST_TAG_IMAGE_ORIENTATION, rotation_tag, NULL);
8922 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
8926 /* Parses the boxes defined in ISO/IEC 14496-12 that enable support for
8927 * protected streams (sinf, frma, schm and schi); if the protection scheme is
8928 * Common Encryption (cenc), the function will also parse the tenc box (defined
8929 * in ISO/IEC 23001-7). @container points to the node that contains these boxes
8930 * (typically an enc[v|a|t|s] sample entry); the function will set
8931 * @original_fmt to the fourcc of the original unencrypted stream format.
8932 * Returns TRUE if successful; FALSE otherwise. */
8934 qtdemux_parse_protection_scheme_info (GstQTDemux * qtdemux,
8935 QtDemuxStream * stream, GNode * container, guint32 * original_fmt)
8942 g_return_val_if_fail (qtdemux != NULL, FALSE);
8943 g_return_val_if_fail (stream != NULL, FALSE);
8944 g_return_val_if_fail (container != NULL, FALSE);
8945 g_return_val_if_fail (original_fmt != NULL, FALSE);
8947 sinf = qtdemux_tree_get_child_by_type (container, FOURCC_sinf);
8948 if (G_UNLIKELY (!sinf)) {
8949 if (stream->protection_scheme_type == FOURCC_cenc) {
8950 GST_ERROR_OBJECT (qtdemux, "sinf box does not contain schi box, which is "
8951 "mandatory for Common Encryption");
8957 frma = qtdemux_tree_get_child_by_type (sinf, FOURCC_frma);
8958 if (G_UNLIKELY (!frma)) {
8959 GST_ERROR_OBJECT (qtdemux, "sinf box does not contain mandatory frma box");
8963 *original_fmt = QT_FOURCC ((const guint8 *) frma->data + 8);
8964 GST_DEBUG_OBJECT (qtdemux, "original stream format: '%" GST_FOURCC_FORMAT "'",
8965 GST_FOURCC_ARGS (*original_fmt));
8967 schm = qtdemux_tree_get_child_by_type (sinf, FOURCC_schm);
8969 GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schm box");
8972 stream->protection_scheme_type = QT_FOURCC ((const guint8 *) schm->data + 12);
8973 stream->protection_scheme_version =
8974 QT_UINT32 ((const guint8 *) schm->data + 16);
8976 GST_DEBUG_OBJECT (qtdemux,
8977 "protection_scheme_type: %" GST_FOURCC_FORMAT ", "
8978 "protection_scheme_version: %#010x",
8979 GST_FOURCC_ARGS (stream->protection_scheme_type),
8980 stream->protection_scheme_version);
8982 schi = qtdemux_tree_get_child_by_type (sinf, FOURCC_schi);
8984 GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schi box");
8987 if (stream->protection_scheme_type == FOURCC_cenc) {
8988 QtDemuxCencSampleSetInfo *info;
8990 const guint8 *tenc_data;
8991 guint32 isEncrypted;
8993 const guint8 *default_kid;
8996 if (G_UNLIKELY (!stream->protection_scheme_info))
8997 stream->protection_scheme_info =
8998 g_malloc0 (sizeof (QtDemuxCencSampleSetInfo));
9000 info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
9002 tenc = qtdemux_tree_get_child_by_type (schi, FOURCC_tenc);
9004 GST_ERROR_OBJECT (qtdemux, "schi box does not contain tenc box, "
9005 "which is mandatory for Common Encryption");
9008 tenc_data = (const guint8 *) tenc->data + 12;
9009 isEncrypted = QT_UINT24 (tenc_data);
9010 iv_size = QT_UINT8 (tenc_data + 3);
9011 default_kid = (tenc_data + 4);
9012 kid_buf = gst_buffer_new_allocate (NULL, 16, NULL);
9013 gst_buffer_fill (kid_buf, 0, default_kid, 16);
9014 if (info->default_properties)
9015 gst_structure_free (info->default_properties);
9016 info->default_properties =
9017 gst_structure_new ("application/x-cenc",
9018 "iv_size", G_TYPE_UINT, iv_size,
9019 "encrypted", G_TYPE_BOOLEAN, (isEncrypted == 1),
9020 "kid", GST_TYPE_BUFFER, kid_buf, NULL);
9021 GST_DEBUG_OBJECT (qtdemux, "default sample properties: "
9022 "is_encrypted=%u, iv_size=%u", isEncrypted, iv_size);
9023 gst_buffer_unref (kid_buf);
9029 * With each track we associate a new QtDemuxStream that contains all the info
9031 * traks that do not decode to something (like strm traks) will not have a pad.
9034 qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
9053 QtDemuxStream *stream = NULL;
9054 gboolean new_stream = FALSE;
9055 gchar *codec = NULL;
9056 const guint8 *stsd_data;
9057 guint16 lang_code; /* quicktime lang code or packed iso code */
9059 guint32 tkhd_flags = 0;
9060 guint8 tkhd_version = 0;
9062 guint value_size, stsd_len, len;
9066 GST_DEBUG_OBJECT (qtdemux, "parse_trak");
9068 if (!qtdemux_tree_get_child_by_type_full (trak, FOURCC_tkhd, &tkhd)
9069 || !gst_byte_reader_get_uint8 (&tkhd, &tkhd_version)
9070 || !gst_byte_reader_get_uint24_be (&tkhd, &tkhd_flags))
9073 /* pick between 64 or 32 bits */
9074 value_size = tkhd_version == 1 ? 8 : 4;
9075 if (!gst_byte_reader_skip (&tkhd, value_size * 2) ||
9076 !gst_byte_reader_get_uint32_be (&tkhd, &track_id))
9079 if (!qtdemux->got_moov) {
9080 if (qtdemux_find_stream (qtdemux, track_id))
9081 goto existing_stream;
9082 stream = _create_stream ();
9083 stream->track_id = track_id;
9086 stream = qtdemux_find_stream (qtdemux, track_id);
9088 GST_WARNING_OBJECT (qtdemux, "Stream not found, going to ignore it");
9092 /* flush samples data from this track from previous moov */
9093 gst_qtdemux_stream_flush_segments_data (qtdemux, stream);
9094 gst_qtdemux_stream_flush_samples_data (qtdemux, stream);
9096 /* need defaults for fragments */
9097 qtdemux_parse_trex (qtdemux, stream, &dummy, &dummy, &dummy);
9099 if (stream->pending_tags == NULL)
9100 stream->pending_tags = gst_tag_list_new_empty ();
9102 if ((tkhd_flags & 1) == 0)
9103 stream->disabled = TRUE;
9105 GST_LOG_OBJECT (qtdemux, "track[tkhd] version/flags/id: 0x%02x/%06x/%u",
9106 tkhd_version, tkhd_flags, stream->track_id);
9108 if (!(mdia = qtdemux_tree_get_child_by_type (trak, FOURCC_mdia)))
9111 if (!(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mdhd))) {
9112 /* be nice for some crooked mjp2 files that use mhdr for mdhd */
9113 if (qtdemux->major_brand != FOURCC_mjp2 ||
9114 !(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mhdr)))
9118 len = QT_UINT32 ((guint8 *) mdhd->data);
9119 version = QT_UINT32 ((guint8 *) mdhd->data + 8);
9120 GST_LOG_OBJECT (qtdemux, "track version/flags: %08x", version);
9121 if (version == 0x01000000) {
9124 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 28);
9125 stream->duration = QT_UINT64 ((guint8 *) mdhd->data + 32);
9126 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 36);
9130 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 20);
9131 stream->duration = QT_UINT32 ((guint8 *) mdhd->data + 24);
9132 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 28);
9135 if (lang_code < 0x400) {
9136 qtdemux_lang_map_qt_code_to_iso (stream->lang_id, lang_code);
9137 } else if (lang_code == 0x7fff) {
9138 stream->lang_id[0] = 0; /* unspecified */
9140 stream->lang_id[0] = 0x60 + ((lang_code >> 10) & 0x1F);
9141 stream->lang_id[1] = 0x60 + ((lang_code >> 5) & 0x1F);
9142 stream->lang_id[2] = 0x60 + (lang_code & 0x1F);
9143 stream->lang_id[3] = 0;
9146 GST_LOG_OBJECT (qtdemux, "track timescale: %" G_GUINT32_FORMAT,
9148 GST_LOG_OBJECT (qtdemux, "track duration: %" G_GUINT64_FORMAT,
9150 GST_LOG_OBJECT (qtdemux, "track language code/id: 0x%04x/%s",
9151 lang_code, stream->lang_id);
9153 if (G_UNLIKELY (stream->timescale == 0 || qtdemux->timescale == 0))
9156 if ((tref = qtdemux_tree_get_child_by_type (trak, FOURCC_tref))) {
9157 /* chapters track reference */
9158 GNode *chap = qtdemux_tree_get_child_by_type (tref, FOURCC_chap);
9160 gsize length = GST_READ_UINT32_BE (chap->data);
9161 if (qtdemux->chapters_track_id)
9162 GST_FIXME_OBJECT (qtdemux, "Multiple CHAP tracks");
9165 qtdemux->chapters_track_id =
9166 GST_READ_UINT32_BE ((gint8 *) chap->data + 8);
9171 /* fragmented files may have bogus duration in moov */
9172 if (!qtdemux->fragmented &&
9173 qtdemux->duration != G_MAXINT64 && stream->duration != G_MAXINT32) {
9174 guint64 tdur1, tdur2;
9176 /* don't overflow */
9177 tdur1 = stream->timescale * (guint64) qtdemux->duration;
9178 tdur2 = qtdemux->timescale * (guint64) stream->duration;
9181 * some of those trailers, nowadays, have prologue images that are
9182 * themselves vide tracks as well. I haven't really found a way to
9183 * identify those yet, except for just looking at their duration. */
9184 if (tdur1 != 0 && (tdur2 * 10 / tdur1) < 2) {
9185 GST_WARNING_OBJECT (qtdemux,
9186 "Track shorter than 20%% (%" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT
9187 " vs. %" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT ") of the stream "
9188 "found, assuming preview image or something; skipping track",
9189 stream->duration, stream->timescale, qtdemux->duration,
9190 qtdemux->timescale);
9192 gst_qtdemux_stream_free (qtdemux, stream);
9197 if (!(hdlr = qtdemux_tree_get_child_by_type (mdia, FOURCC_hdlr)))
9200 GST_LOG_OBJECT (qtdemux, "track type: %" GST_FOURCC_FORMAT,
9201 GST_FOURCC_ARGS (QT_FOURCC ((guint8 *) hdlr->data + 12)));
9203 len = QT_UINT32 ((guint8 *) hdlr->data);
9205 stream->subtype = QT_FOURCC ((guint8 *) hdlr->data + 16);
9206 GST_LOG_OBJECT (qtdemux, "track subtype: %" GST_FOURCC_FORMAT,
9207 GST_FOURCC_ARGS (stream->subtype));
9209 if (!(minf = qtdemux_tree_get_child_by_type (mdia, FOURCC_minf)))
9212 if (!(stbl = qtdemux_tree_get_child_by_type (minf, FOURCC_stbl)))
9215 /*parse svmi header if existing */
9216 svmi = qtdemux_tree_get_child_by_type (stbl, FOURCC_svmi);
9218 len = QT_UINT32 ((guint8 *) svmi->data);
9219 version = QT_UINT32 ((guint8 *) svmi->data + 8);
9221 GstVideoMultiviewMode mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
9222 GstVideoMultiviewFlags flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
9223 guint8 frame_type, frame_layout;
9225 /* MPEG-A stereo video */
9226 if (qtdemux->major_brand == FOURCC_ss02)
9227 flags |= GST_VIDEO_MULTIVIEW_FLAGS_MIXED_MONO;
9229 frame_type = QT_UINT8 ((guint8 *) svmi->data + 12);
9230 frame_layout = QT_UINT8 ((guint8 *) svmi->data + 13) & 0x01;
9231 switch (frame_type) {
9233 mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
9236 mode = GST_VIDEO_MULTIVIEW_MODE_ROW_INTERLEAVED;
9239 mode = GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME;
9242 /* mode 3 is primary/secondary view sequence, ie
9243 * left/right views in separate tracks. See section 7.2
9244 * of ISO/IEC 23000-11:2009 */
9245 GST_FIXME_OBJECT (qtdemux,
9246 "Implement stereo video in separate streams");
9249 if ((frame_layout & 0x1) == 0)
9250 flags |= GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
9252 GST_LOG_OBJECT (qtdemux,
9253 "StereoVideo: composition type: %u, is_left_first: %u",
9254 frame_type, frame_layout);
9255 stream->multiview_mode = mode;
9256 stream->multiview_flags = flags;
9261 if (!(stsd = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsd)))
9263 stsd_data = (const guint8 *) stsd->data;
9265 /* stsd should at least have one entry */
9266 stsd_len = QT_UINT32 (stsd_data);
9267 if (stsd_len < 24) {
9268 /* .. but skip stream with empty stsd produced by some Vivotek cameras */
9269 if (stream->subtype == FOURCC_vivo) {
9271 gst_qtdemux_stream_free (qtdemux, stream);
9278 GST_LOG_OBJECT (qtdemux, "stsd len: %d", stsd_len);
9280 /* and that entry should fit within stsd */
9281 len = QT_UINT32 (stsd_data + 16);
9282 if (len > stsd_len + 16)
9285 stream->fourcc = fourcc = QT_FOURCC (stsd_data + 16 + 4);
9286 GST_LOG_OBJECT (qtdemux, "stsd type: %" GST_FOURCC_FORMAT,
9287 GST_FOURCC_ARGS (stream->fourcc));
9288 GST_LOG_OBJECT (qtdemux, "stsd type len: %d", len);
9290 if ((fourcc == FOURCC_drms) || (fourcc == FOURCC_drmi))
9291 goto error_encrypted;
9293 if (fourcc == FOURCC_encv || fourcc == FOURCC_enca) {
9294 GNode *enc = qtdemux_tree_get_child_by_type (stsd, fourcc);
9295 stream->protected = TRUE;
9296 if (!qtdemux_parse_protection_scheme_info (qtdemux, stream, enc, &fourcc))
9297 GST_ERROR_OBJECT (qtdemux, "Failed to parse protection scheme info");
9300 if (stream->subtype == FOURCC_vide) {
9301 guint32 w = 0, h = 0;
9303 gint depth, palette_size, palette_count;
9305 guint32 *palette_data = NULL;
9307 stream->sampled = TRUE;
9309 /* version 1 uses some 64-bit ints */
9310 if (!gst_byte_reader_skip (&tkhd, 20 + value_size))
9313 if (!qtdemux_parse_transformation_matrix (qtdemux, &tkhd, matrix, "tkhd"))
9316 if (!gst_byte_reader_get_uint32_be (&tkhd, &w)
9317 || !gst_byte_reader_get_uint32_be (&tkhd, &h))
9320 stream->display_width = w >> 16;
9321 stream->display_height = h >> 16;
9323 qtdemux_inspect_transformation_matrix (qtdemux, stream, matrix,
9324 &stream->pending_tags);
9330 stream->width = QT_UINT16 (stsd_data + offset + 32);
9331 stream->height = QT_UINT16 (stsd_data + offset + 34);
9332 stream->fps_n = 0; /* this is filled in later */
9333 stream->fps_d = 0; /* this is filled in later */
9334 stream->bits_per_sample = QT_UINT16 (stsd_data + offset + 82);
9335 stream->color_table_id = QT_UINT16 (stsd_data + offset + 84);
9337 /* if color_table_id is 0, ctab atom must follow; however some files
9338 * produced by TMPEGEnc have color_table_id = 0 and no ctab atom, so
9339 * if color table is not present we'll correct the value */
9340 if (stream->color_table_id == 0 &&
9341 (len < 90 || QT_FOURCC (stsd_data + offset + 86) != FOURCC_ctab)) {
9342 stream->color_table_id = -1;
9345 GST_LOG_OBJECT (qtdemux, "width %d, height %d, bps %d, color table id %d",
9346 stream->width, stream->height, stream->bits_per_sample,
9347 stream->color_table_id);
9349 depth = stream->bits_per_sample;
9351 /* more than 32 bits means grayscale */
9352 gray = (depth > 32);
9353 /* low 32 bits specify the depth */
9356 /* different number of palette entries is determined by depth. */
9358 if ((depth == 1) || (depth == 2) || (depth == 4) || (depth == 8))
9359 palette_count = (1 << depth);
9360 palette_size = palette_count * 4;
9362 if (stream->color_table_id) {
9363 switch (palette_count) {
9367 palette_data = g_memdup (ff_qt_default_palette_2, palette_size);
9370 palette_data = g_memdup (ff_qt_default_palette_4, palette_size);
9374 palette_data = g_memdup (ff_qt_grayscale_palette_16, palette_size);
9376 palette_data = g_memdup (ff_qt_default_palette_16, palette_size);
9380 palette_data = g_memdup (ff_qt_grayscale_palette_256, palette_size);
9382 palette_data = g_memdup (ff_qt_default_palette_256, palette_size);
9385 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
9386 (_("The video in this file might not play correctly.")),
9387 ("unsupported palette depth %d", depth));
9391 gint i, j, start, end;
9397 start = QT_UINT32 (stsd_data + offset + 86);
9398 palette_count = QT_UINT16 (stsd_data + offset + 90);
9399 end = QT_UINT16 (stsd_data + offset + 92);
9401 GST_LOG_OBJECT (qtdemux, "start %d, end %d, palette_count %d",
9402 start, end, palette_count);
9409 if (len < 94 + (end - start) * 8)
9412 /* palette is always the same size */
9413 palette_data = g_malloc0 (256 * 4);
9414 palette_size = 256 * 4;
9416 for (j = 0, i = start; i <= end; j++, i++) {
9419 a = QT_UINT16 (stsd_data + offset + 94 + (j * 8));
9420 r = QT_UINT16 (stsd_data + offset + 96 + (j * 8));
9421 g = QT_UINT16 (stsd_data + offset + 98 + (j * 8));
9422 b = QT_UINT16 (stsd_data + offset + 100 + (j * 8));
9424 palette_data[i] = ((a & 0xff00) << 16) | ((r & 0xff00) << 8) |
9425 (g & 0xff00) | (b >> 8);
9430 gst_caps_unref (stream->caps);
9433 qtdemux_video_caps (qtdemux, stream, fourcc, stsd_data, &codec);
9434 if (G_UNLIKELY (!stream->caps)) {
9435 g_free (palette_data);
9436 goto unknown_stream;
9440 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
9441 GST_TAG_VIDEO_CODEC, codec, NULL);
9450 if (stream->rgb8_palette)
9451 gst_memory_unref (stream->rgb8_palette);
9452 stream->rgb8_palette = gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY,
9453 palette_data, palette_size, 0, palette_size, palette_data, g_free);
9455 s = gst_caps_get_structure (stream->caps, 0);
9457 /* non-raw video has a palette_data property. raw video has the palette as
9458 * an extra plane that we append to the output buffers before we push
9460 if (!gst_structure_has_name (s, "video/x-raw")) {
9463 palette = gst_buffer_new ();
9464 gst_buffer_append_memory (palette, stream->rgb8_palette);
9465 stream->rgb8_palette = NULL;
9467 gst_caps_set_simple (stream->caps, "palette_data",
9468 GST_TYPE_BUFFER, palette, NULL);
9469 gst_buffer_unref (palette);
9471 } else if (palette_count != 0) {
9472 GST_ELEMENT_WARNING (qtdemux, STREAM, NOT_IMPLEMENTED,
9473 (NULL), ("Unsupported palette depth %d", depth));
9476 GST_LOG_OBJECT (qtdemux, "frame count: %u",
9477 QT_UINT16 (stsd_data + offset + 48));
9481 /* pick 'the' stsd child */
9482 if (!stream->protected)
9483 mp4v = qtdemux_tree_get_child_by_type (stsd, fourcc);
9485 mp4v = qtdemux_tree_get_child_by_type (stsd, FOURCC_encv);
9488 esds = qtdemux_tree_get_child_by_type (mp4v, FOURCC_esds);
9489 pasp = qtdemux_tree_get_child_by_type (mp4v, FOURCC_pasp);
9493 const guint8 *pasp_data = (const guint8 *) pasp->data;
9495 stream->par_w = QT_UINT32 (pasp_data + 8);
9496 stream->par_h = QT_UINT32 (pasp_data + 12);
9503 gst_qtdemux_handle_esds (qtdemux, stream, esds, stream->pending_tags);
9510 gint len = QT_UINT32 (stsd_data) - 0x66;
9511 const guint8 *avc_data = stsd_data + 0x66;
9514 while (len >= 0x8) {
9517 if (QT_UINT32 (avc_data) <= len)
9518 size = QT_UINT32 (avc_data) - 0x8;
9523 /* No real data, so break out */
9526 switch (QT_FOURCC (avc_data + 0x4)) {
9529 /* parse, if found */
9532 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
9534 /* First 4 bytes are the length of the atom, the next 4 bytes
9535 * are the fourcc, the next 1 byte is the version, and the
9536 * subsequent bytes are profile_tier_level structure like data. */
9537 gst_codec_utils_h264_caps_set_level_and_profile (stream->caps,
9538 avc_data + 8 + 1, size - 1);
9539 buf = gst_buffer_new_and_alloc (size);
9540 gst_buffer_fill (buf, 0, avc_data + 0x8, size);
9541 gst_caps_set_simple (stream->caps,
9542 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9543 gst_buffer_unref (buf);
9551 GST_DEBUG_OBJECT (qtdemux, "found strf codec_data in stsd");
9553 /* First 4 bytes are the length of the atom, the next 4 bytes
9554 * are the fourcc, next 40 bytes are BITMAPINFOHEADER,
9555 * next 1 byte is the version, and the
9556 * subsequent bytes are sequence parameter set like data. */
9558 size -= 40; /* we'll be skipping BITMAPINFOHEADER */
9560 gst_codec_utils_h264_caps_set_level_and_profile (stream->caps,
9561 avc_data + 8 + 40 + 1, size - 1);
9563 buf = gst_buffer_new_and_alloc (size);
9564 gst_buffer_fill (buf, 0, avc_data + 8 + 40, size);
9565 gst_caps_set_simple (stream->caps,
9566 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9567 gst_buffer_unref (buf);
9573 guint avg_bitrate, max_bitrate;
9575 /* bufferSizeDB, maxBitrate and avgBitrate - 4 bytes each */
9579 max_bitrate = QT_UINT32 (avc_data + 0xc);
9580 avg_bitrate = QT_UINT32 (avc_data + 0x10);
9582 if (!max_bitrate && !avg_bitrate)
9585 /* Some muxers seem to swap the average and maximum bitrates
9586 * (I'm looking at you, YouTube), so we swap for sanity. */
9587 if (max_bitrate > 0 && max_bitrate < avg_bitrate) {
9588 guint temp = avg_bitrate;
9590 avg_bitrate = max_bitrate;
9594 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
9595 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
9596 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
9598 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
9599 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
9600 GST_TAG_BITRATE, avg_bitrate, NULL);
9611 avc_data += size + 8;
9620 gint len = QT_UINT32 (stsd_data) - 0x66;
9621 const guint8 *hevc_data = stsd_data + 0x66;
9624 while (len >= 0x8) {
9627 if (QT_UINT32 (hevc_data) <= len)
9628 size = QT_UINT32 (hevc_data) - 0x8;
9633 /* No real data, so break out */
9636 switch (QT_FOURCC (hevc_data + 0x4)) {
9639 /* parse, if found */
9642 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
9644 /* First 4 bytes are the length of the atom, the next 4 bytes
9645 * are the fourcc, the next 1 byte is the version, and the
9646 * subsequent bytes are sequence parameter set like data. */
9647 gst_codec_utils_h265_caps_set_level_tier_and_profile
9648 (stream->caps, hevc_data + 8 + 1, size - 1);
9650 buf = gst_buffer_new_and_alloc (size);
9651 gst_buffer_fill (buf, 0, hevc_data + 0x8, size);
9652 gst_caps_set_simple (stream->caps,
9653 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9654 gst_buffer_unref (buf);
9661 hevc_data += size + 8;
9672 GST_DEBUG_OBJECT (qtdemux, "found %" GST_FOURCC_FORMAT,
9673 GST_FOURCC_ARGS (fourcc));
9675 /* codec data might be in glbl extension atom */
9677 qtdemux_tree_get_child_by_type (mp4v, FOURCC_glbl) : NULL;
9683 GST_DEBUG_OBJECT (qtdemux, "found glbl data in stsd");
9685 len = QT_UINT32 (data);
9688 buf = gst_buffer_new_and_alloc (len);
9689 gst_buffer_fill (buf, 0, data + 8, len);
9690 gst_caps_set_simple (stream->caps,
9691 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9692 gst_buffer_unref (buf);
9699 /* see annex I of the jpeg2000 spec */
9700 GNode *jp2h, *ihdr, *colr, *mjp2, *field, *prefix, *cmap, *cdef;
9702 const gchar *colorspace = NULL;
9704 guint32 ncomp_map = 0;
9705 gint32 *comp_map = NULL;
9706 guint32 nchan_def = 0;
9707 gint32 *chan_def = NULL;
9709 GST_DEBUG_OBJECT (qtdemux, "found mjp2");
9710 /* some required atoms */
9711 mjp2 = qtdemux_tree_get_child_by_type (stsd, FOURCC_mjp2);
9714 jp2h = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2h);
9718 /* number of components; redundant with info in codestream, but useful
9720 ihdr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_ihdr);
9721 if (!ihdr || QT_UINT32 (ihdr->data) != 22)
9723 ncomp = QT_UINT16 (((guint8 *) ihdr->data) + 16);
9725 colr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_colr);
9728 GST_DEBUG_OBJECT (qtdemux, "found colr");
9729 /* extract colour space info */
9730 if (QT_UINT8 ((guint8 *) colr->data + 8) == 1) {
9731 switch (QT_UINT32 ((guint8 *) colr->data + 11)) {
9733 colorspace = "sRGB";
9736 colorspace = "GRAY";
9739 colorspace = "sYUV";
9747 /* colr is required, and only values 16, 17, and 18 are specified,
9748 so error if we have no colorspace */
9751 /* extract component mapping */
9752 cmap = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cmap);
9754 guint32 cmap_len = 0;
9756 cmap_len = QT_UINT32 (cmap->data);
9757 if (cmap_len >= 8) {
9758 /* normal box, subtract off header */
9760 /* cmap: { u16 cmp; u8 mtyp; u8 pcol; }* */
9761 if (cmap_len % 4 == 0) {
9762 ncomp_map = (cmap_len / 4);
9763 comp_map = g_new0 (gint32, ncomp_map);
9764 for (i = 0; i < ncomp_map; i++) {
9767 cmp = QT_UINT16 (((guint8 *) cmap->data) + 8 + i * 4);
9768 mtyp = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 2);
9769 pcol = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 3);
9770 comp_map[i] = (mtyp << 24) | (pcol << 16) | cmp;
9775 /* extract channel definitions */
9776 cdef = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cdef);
9778 guint32 cdef_len = 0;
9780 cdef_len = QT_UINT32 (cdef->data);
9781 if (cdef_len >= 10) {
9782 /* normal box, subtract off header and len */
9784 /* cdef: u16 n; { u16 cn; u16 typ; u16 asoc; }* */
9785 if (cdef_len % 6 == 0) {
9786 nchan_def = (cdef_len / 6);
9787 chan_def = g_new0 (gint32, nchan_def);
9788 for (i = 0; i < nchan_def; i++)
9790 for (i = 0; i < nchan_def; i++) {
9791 guint16 cn, typ, asoc;
9792 cn = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6);
9793 typ = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 2);
9794 asoc = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 4);
9795 if (cn < nchan_def) {
9798 chan_def[cn] = asoc;
9801 chan_def[cn] = 0; /* alpha */
9804 chan_def[cn] = -typ;
9812 gst_caps_set_simple (stream->caps,
9813 "num-components", G_TYPE_INT, ncomp, NULL);
9814 gst_caps_set_simple (stream->caps,
9815 "colorspace", G_TYPE_STRING, colorspace, NULL);
9818 GValue arr = { 0, };
9819 GValue elt = { 0, };
9821 g_value_init (&arr, GST_TYPE_ARRAY);
9822 g_value_init (&elt, G_TYPE_INT);
9823 for (i = 0; i < ncomp_map; i++) {
9824 g_value_set_int (&elt, comp_map[i]);
9825 gst_value_array_append_value (&arr, &elt);
9827 gst_structure_set_value (gst_caps_get_structure (stream->caps, 0),
9828 "component-map", &arr);
9829 g_value_unset (&elt);
9830 g_value_unset (&arr);
9835 GValue arr = { 0, };
9836 GValue elt = { 0, };
9838 g_value_init (&arr, GST_TYPE_ARRAY);
9839 g_value_init (&elt, G_TYPE_INT);
9840 for (i = 0; i < nchan_def; i++) {
9841 g_value_set_int (&elt, chan_def[i]);
9842 gst_value_array_append_value (&arr, &elt);
9844 gst_structure_set_value (gst_caps_get_structure (stream->caps, 0),
9845 "channel-definitions", &arr);
9846 g_value_unset (&elt);
9847 g_value_unset (&arr);
9851 /* some optional atoms */
9852 field = qtdemux_tree_get_child_by_type (mjp2, FOURCC_fiel);
9853 prefix = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2x);
9855 /* indicate possible fields in caps */
9857 data = (guint8 *) field->data + 8;
9859 gst_caps_set_simple (stream->caps, "fields", G_TYPE_INT,
9860 (gint) * data, NULL);
9862 /* add codec_data if provided */
9867 GST_DEBUG_OBJECT (qtdemux, "found prefix data in stsd");
9868 data = prefix->data;
9869 len = QT_UINT32 (data);
9872 buf = gst_buffer_new_and_alloc (len);
9873 gst_buffer_fill (buf, 0, data + 8, len);
9874 gst_caps_set_simple (stream->caps,
9875 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9876 gst_buffer_unref (buf);
9885 GstBuffer *seqh = NULL;
9886 guint8 *gamma_data = NULL;
9887 gint len = QT_UINT32 (stsd_data);
9889 qtdemux_parse_svq3_stsd_data (qtdemux, stsd, &gamma_data, &seqh);
9891 gst_caps_set_simple (stream->caps, "applied-gamma", G_TYPE_DOUBLE,
9892 QT_FP32 (gamma_data), NULL);
9895 /* sorry for the bad name, but we don't know what this is, other
9896 * than its own fourcc */
9897 gst_caps_set_simple (stream->caps, "seqh", GST_TYPE_BUFFER, seqh,
9901 GST_DEBUG_OBJECT (qtdemux, "found codec_data in stsd");
9902 buf = gst_buffer_new_and_alloc (len);
9903 gst_buffer_fill (buf, 0, stsd_data, len);
9904 gst_caps_set_simple (stream->caps,
9905 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9906 gst_buffer_unref (buf);
9912 gst_caps_set_simple (stream->caps,
9913 "depth", G_TYPE_INT, QT_UINT16 (stsd_data + offset + 82), NULL);
9920 GST_DEBUG_OBJECT (qtdemux, "found XiTh");
9921 xith = qtdemux_tree_get_child_by_type (stsd, FOURCC_XiTh);
9925 xdxt = qtdemux_tree_get_child_by_type (xith, FOURCC_XdxT);
9929 GST_DEBUG_OBJECT (qtdemux, "found XdxT node");
9930 /* collect the headers and store them in a stream list so that we can
9931 * send them out first */
9932 qtdemux_parse_theora_extension (qtdemux, stream, xdxt);
9942 GST_DEBUG_OBJECT (qtdemux, "parse ovc1 header");
9943 ovc1 = qtdemux_tree_get_child_by_type (stsd, FOURCC_ovc1);
9946 ovc1_data = ovc1->data;
9947 ovc1_len = QT_UINT32 (ovc1_data);
9948 if (ovc1_len <= 198) {
9949 GST_WARNING_OBJECT (qtdemux, "Too small ovc1 header, skipping");
9952 buf = gst_buffer_new_and_alloc (ovc1_len - 198);
9953 gst_buffer_fill (buf, 0, ovc1_data + 198, ovc1_len - 198);
9954 gst_caps_set_simple (stream->caps,
9955 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9956 gst_buffer_unref (buf);
9961 gint len = QT_UINT32 (stsd_data) - 0x66;
9962 const guint8 *vc1_data = stsd_data + 0x66;
9968 if (QT_UINT32 (vc1_data) <= len)
9969 size = QT_UINT32 (vc1_data) - 8;
9974 /* No real data, so break out */
9977 switch (QT_FOURCC (vc1_data + 0x4)) {
9978 case GST_MAKE_FOURCC ('d', 'v', 'c', '1'):
9982 GST_DEBUG_OBJECT (qtdemux, "found dvc1 codec_data in stsd");
9983 buf = gst_buffer_new_and_alloc (size);
9984 gst_buffer_fill (buf, 0, vc1_data + 8, size);
9985 gst_caps_set_simple (stream->caps,
9986 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9987 gst_buffer_unref (buf);
9994 vc1_data += size + 8;
10003 GST_INFO_OBJECT (qtdemux,
10004 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
10005 GST_FOURCC_ARGS (fourcc), stream->caps);
10007 } else if (stream->subtype == FOURCC_soun) {
10008 int version, samplesize;
10009 guint16 compression_id;
10010 gboolean amrwb = FALSE;
10013 /* sample description entry (16) + sound sample description v0 (20) */
10017 version = QT_UINT32 (stsd_data + offset);
10018 stream->n_channels = QT_UINT16 (stsd_data + offset + 8);
10019 samplesize = QT_UINT16 (stsd_data + offset + 10);
10020 compression_id = QT_UINT16 (stsd_data + offset + 12);
10021 stream->rate = QT_FP32 (stsd_data + offset + 16);
10023 GST_LOG_OBJECT (qtdemux, "version/rev: %08x", version);
10024 GST_LOG_OBJECT (qtdemux, "vendor: %08x",
10025 QT_UINT32 (stsd_data + offset + 4));
10026 GST_LOG_OBJECT (qtdemux, "n_channels: %d", stream->n_channels);
10027 GST_LOG_OBJECT (qtdemux, "sample_size: %d", samplesize);
10028 GST_LOG_OBJECT (qtdemux, "compression_id: %d", compression_id);
10029 GST_LOG_OBJECT (qtdemux, "packet size: %d",
10030 QT_UINT16 (stsd_data + offset + 14));
10031 GST_LOG_OBJECT (qtdemux, "sample rate: %g", stream->rate);
10033 if (compression_id == 0xfffe)
10034 stream->sampled = TRUE;
10036 /* first assume uncompressed audio */
10037 stream->bytes_per_sample = samplesize / 8;
10038 stream->samples_per_frame = stream->n_channels;
10039 stream->bytes_per_frame = stream->n_channels * stream->bytes_per_sample;
10040 stream->samples_per_packet = stream->samples_per_frame;
10041 stream->bytes_per_packet = stream->bytes_per_sample;
10045 /* Yes, these have to be hard-coded */
10048 stream->samples_per_packet = 6;
10049 stream->bytes_per_packet = 1;
10050 stream->bytes_per_frame = 1 * stream->n_channels;
10051 stream->bytes_per_sample = 1;
10052 stream->samples_per_frame = 6 * stream->n_channels;
10057 stream->samples_per_packet = 3;
10058 stream->bytes_per_packet = 1;
10059 stream->bytes_per_frame = 1 * stream->n_channels;
10060 stream->bytes_per_sample = 1;
10061 stream->samples_per_frame = 3 * stream->n_channels;
10066 stream->samples_per_packet = 64;
10067 stream->bytes_per_packet = 34;
10068 stream->bytes_per_frame = 34 * stream->n_channels;
10069 stream->bytes_per_sample = 2;
10070 stream->samples_per_frame = 64 * stream->n_channels;
10076 stream->samples_per_packet = 1;
10077 stream->bytes_per_packet = 1;
10078 stream->bytes_per_frame = 1 * stream->n_channels;
10079 stream->bytes_per_sample = 1;
10080 stream->samples_per_frame = 1 * stream->n_channels;
10085 stream->samples_per_packet = 160;
10086 stream->bytes_per_packet = 33;
10087 stream->bytes_per_frame = 33 * stream->n_channels;
10088 stream->bytes_per_sample = 2;
10089 stream->samples_per_frame = 160 * stream->n_channels;
10096 if (version == 0x00010000) {
10097 /* sample description entry (16) + sound sample description v1 (20+16) */
10108 /* only parse extra decoding config for non-pcm audio */
10109 stream->samples_per_packet = QT_UINT32 (stsd_data + offset);
10110 stream->bytes_per_packet = QT_UINT32 (stsd_data + offset + 4);
10111 stream->bytes_per_frame = QT_UINT32 (stsd_data + offset + 8);
10112 stream->bytes_per_sample = QT_UINT32 (stsd_data + offset + 12);
10114 GST_LOG_OBJECT (qtdemux, "samples/packet: %d",
10115 stream->samples_per_packet);
10116 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
10117 stream->bytes_per_packet);
10118 GST_LOG_OBJECT (qtdemux, "bytes/frame: %d",
10119 stream->bytes_per_frame);
10120 GST_LOG_OBJECT (qtdemux, "bytes/sample: %d",
10121 stream->bytes_per_sample);
10123 if (!stream->sampled && stream->bytes_per_packet) {
10124 stream->samples_per_frame = (stream->bytes_per_frame /
10125 stream->bytes_per_packet) * stream->samples_per_packet;
10126 GST_LOG_OBJECT (qtdemux, "samples/frame: %d",
10127 stream->samples_per_frame);
10132 } else if (version == 0x00020000) {
10139 /* sample description entry (16) + sound sample description v2 (56) */
10143 qtfp.val = QT_UINT64 (stsd_data + offset + 4);
10144 stream->rate = qtfp.fp;
10145 stream->n_channels = QT_UINT32 (stsd_data + offset + 12);
10147 GST_LOG_OBJECT (qtdemux, "Sound sample description Version 2");
10148 GST_LOG_OBJECT (qtdemux, "sample rate: %g", stream->rate);
10149 GST_LOG_OBJECT (qtdemux, "n_channels: %d", stream->n_channels);
10150 GST_LOG_OBJECT (qtdemux, "bits/channel: %d",
10151 QT_UINT32 (stsd_data + offset + 20));
10152 GST_LOG_OBJECT (qtdemux, "format flags: %X",
10153 QT_UINT32 (stsd_data + offset + 24));
10154 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
10155 QT_UINT32 (stsd_data + offset + 28));
10156 GST_LOG_OBJECT (qtdemux, "LPCM frames/packet: %d",
10157 QT_UINT32 (stsd_data + offset + 32));
10158 } else if (version != 0x00000) {
10159 GST_WARNING_OBJECT (qtdemux, "unknown audio STSD version %08x", version);
10163 gst_caps_unref (stream->caps);
10165 stream->caps = qtdemux_audio_caps (qtdemux, stream, fourcc,
10166 stsd_data + 32, len - 16, &codec);
10174 in24 = qtdemux_tree_get_child_by_type (stsd, FOURCC_in24);
10176 enda = qtdemux_tree_get_child_by_type (in24, FOURCC_enda);
10178 wave = qtdemux_tree_get_child_by_type (in24, FOURCC_wave);
10180 enda = qtdemux_tree_get_child_by_type (wave, FOURCC_enda);
10183 int enda_value = QT_UINT16 ((guint8 *) enda->data + 8);
10184 gst_caps_set_simple (stream->caps,
10185 "format", G_TYPE_STRING, (enda_value) ? "S24LE" : "S24BE", NULL);
10192 const guint8 *owma_data;
10193 const gchar *codec_name = NULL;
10197 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
10198 /* FIXME this should also be gst_riff_strf_auds,
10199 * but the latter one is actually missing bits-per-sample :( */
10204 gint32 nSamplesPerSec;
10205 gint32 nAvgBytesPerSec;
10206 gint16 nBlockAlign;
10207 gint16 wBitsPerSample;
10210 WAVEFORMATEX *wfex;
10212 GST_DEBUG_OBJECT (qtdemux, "parse owma");
10213 owma = qtdemux_tree_get_child_by_type (stsd, FOURCC_owma);
10216 owma_data = owma->data;
10217 owma_len = QT_UINT32 (owma_data);
10218 if (owma_len <= 54) {
10219 GST_WARNING_OBJECT (qtdemux, "Too small owma header, skipping");
10222 wfex = (WAVEFORMATEX *) (owma_data + 36);
10223 buf = gst_buffer_new_and_alloc (owma_len - 54);
10224 gst_buffer_fill (buf, 0, owma_data + 54, owma_len - 54);
10225 if (wfex->wFormatTag == 0x0161) {
10226 codec_name = "Windows Media Audio";
10228 } else if (wfex->wFormatTag == 0x0162) {
10229 codec_name = "Windows Media Audio 9 Pro";
10231 } else if (wfex->wFormatTag == 0x0163) {
10232 codec_name = "Windows Media Audio 9 Lossless";
10233 /* is that correct? gstffmpegcodecmap.c is missing it, but
10234 * fluendo codec seems to support it */
10238 gst_caps_set_simple (stream->caps,
10239 "codec_data", GST_TYPE_BUFFER, buf,
10240 "wmaversion", G_TYPE_INT, version,
10241 "block_align", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->nBlockAlign),
10242 "bitrate", G_TYPE_INT, GST_READ_UINT32_LE (&wfex->nAvgBytesPerSec),
10243 "width", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->wBitsPerSample),
10244 "depth", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->wBitsPerSample),
10246 gst_buffer_unref (buf);
10250 codec = g_strdup (codec_name);
10256 gint len = QT_UINT32 (stsd_data) - offset;
10257 const guint8 *wfex_data = stsd_data + offset;
10258 const gchar *codec_name = NULL;
10260 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
10261 /* FIXME this should also be gst_riff_strf_auds,
10262 * but the latter one is actually missing bits-per-sample :( */
10267 gint32 nSamplesPerSec;
10268 gint32 nAvgBytesPerSec;
10269 gint16 nBlockAlign;
10270 gint16 wBitsPerSample;
10275 /* FIXME: unify with similar wavformatex parsing code above */
10276 GST_DEBUG_OBJECT (qtdemux, "parse wma, looking for wfex");
10282 if (QT_UINT32 (wfex_data) <= len)
10283 size = QT_UINT32 (wfex_data) - 8;
10288 /* No real data, so break out */
10291 switch (QT_FOURCC (wfex_data + 4)) {
10292 case GST_MAKE_FOURCC ('w', 'f', 'e', 'x'):
10294 GST_DEBUG_OBJECT (qtdemux, "found wfex in stsd");
10299 wfex.wFormatTag = GST_READ_UINT16_LE (wfex_data + 8 + 0);
10300 wfex.nChannels = GST_READ_UINT16_LE (wfex_data + 8 + 2);
10301 wfex.nSamplesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 4);
10302 wfex.nAvgBytesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 8);
10303 wfex.nBlockAlign = GST_READ_UINT16_LE (wfex_data + 8 + 12);
10304 wfex.wBitsPerSample = GST_READ_UINT16_LE (wfex_data + 8 + 14);
10305 wfex.cbSize = GST_READ_UINT16_LE (wfex_data + 8 + 16);
10307 GST_LOG_OBJECT (qtdemux, "Found wfex box in stsd:");
10308 GST_LOG_OBJECT (qtdemux, "FormatTag = 0x%04x, Channels = %u, "
10309 "SamplesPerSec = %u, AvgBytesPerSec = %u, BlockAlign = %u, "
10310 "BitsPerSample = %u, Size = %u", wfex.wFormatTag,
10311 wfex.nChannels, wfex.nSamplesPerSec, wfex.nAvgBytesPerSec,
10312 wfex.nBlockAlign, wfex.wBitsPerSample, wfex.cbSize);
10314 if (wfex.wFormatTag == 0x0161) {
10315 codec_name = "Windows Media Audio";
10317 } else if (wfex.wFormatTag == 0x0162) {
10318 codec_name = "Windows Media Audio 9 Pro";
10320 } else if (wfex.wFormatTag == 0x0163) {
10321 codec_name = "Windows Media Audio 9 Lossless";
10322 /* is that correct? gstffmpegcodecmap.c is missing it, but
10323 * fluendo codec seems to support it */
10327 gst_caps_set_simple (stream->caps,
10328 "wmaversion", G_TYPE_INT, version,
10329 "block_align", G_TYPE_INT, wfex.nBlockAlign,
10330 "bitrate", G_TYPE_INT, wfex.nAvgBytesPerSec,
10331 "width", G_TYPE_INT, wfex.wBitsPerSample,
10332 "depth", G_TYPE_INT, wfex.wBitsPerSample, NULL);
10334 if (size > wfex.cbSize) {
10337 buf = gst_buffer_new_and_alloc (size - wfex.cbSize);
10338 gst_buffer_fill (buf, 0, wfex_data + 8 + wfex.cbSize,
10339 size - wfex.cbSize);
10340 gst_caps_set_simple (stream->caps,
10341 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10342 gst_buffer_unref (buf);
10344 GST_WARNING_OBJECT (qtdemux, "no codec data");
10349 codec = g_strdup (codec_name);
10357 wfex_data += size + 8;
10364 const guint8 *opus_data;
10365 guint8 *channel_mapping = NULL;
10368 guint8 channel_mapping_family;
10369 guint8 stream_count;
10370 guint8 coupled_count;
10373 opus = qtdemux_tree_get_child_by_type (stsd, FOURCC_opus);
10374 opus_data = opus->data;
10376 channels = GST_READ_UINT8 (opus_data + 45);
10377 rate = GST_READ_UINT32_LE (opus_data + 48);
10378 channel_mapping_family = GST_READ_UINT8 (opus_data + 54);
10379 stream_count = GST_READ_UINT8 (opus_data + 55);
10380 coupled_count = GST_READ_UINT8 (opus_data + 56);
10382 if (channels > 0) {
10383 channel_mapping = g_malloc (channels * sizeof (guint8));
10384 for (i = 0; i < channels; i++)
10385 channel_mapping[i] = GST_READ_UINT8 (opus_data + i + 57);
10388 stream->caps = gst_codec_utils_opus_create_caps (rate, channels,
10389 channel_mapping_family, stream_count, coupled_count,
10401 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
10402 GST_TAG_AUDIO_CODEC, codec, NULL);
10406 /* some bitrate info may have ended up in caps */
10407 s = gst_caps_get_structure (stream->caps, 0);
10408 gst_structure_get_int (s, "bitrate", &bitrate);
10410 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
10411 GST_TAG_BITRATE, bitrate, NULL);
10414 if (stream->protected && fourcc == FOURCC_mp4a)
10415 mp4a = qtdemux_tree_get_child_by_type (stsd, FOURCC_enca);
10417 mp4a = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4a);
10422 wave = qtdemux_tree_get_child_by_type (mp4a, FOURCC_wave);
10424 esds = qtdemux_tree_get_child_by_type (wave, FOURCC_esds);
10426 esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
10430 /* If the fourcc's bottom 16 bits gives 'sm', then the top
10431 16 bits is a byte-swapped wave-style codec identifier,
10432 and we can find a WAVE header internally to a 'wave' atom here.
10433 This can more clearly be thought of as 'ms' as the top 16 bits, and a
10434 codec id as the bottom 16 bits - but byte-swapped to store in QT (which
10437 if ((fourcc & 0xffff) == (('s' << 8) | 'm')) {
10438 if (len < offset + 20) {
10439 GST_WARNING_OBJECT (qtdemux, "No wave atom in MS-style audio");
10441 guint32 datalen = QT_UINT32 (stsd_data + offset + 16);
10442 const guint8 *data = stsd_data + offset + 16;
10444 GNode *waveheadernode;
10446 wavenode = g_node_new ((guint8 *) data);
10447 if (qtdemux_parse_node (qtdemux, wavenode, data, datalen)) {
10448 const guint8 *waveheader;
10451 waveheadernode = qtdemux_tree_get_child_by_type (wavenode, fourcc);
10452 if (waveheadernode) {
10453 waveheader = (const guint8 *) waveheadernode->data;
10454 headerlen = QT_UINT32 (waveheader);
10456 if (headerlen > 8) {
10457 gst_riff_strf_auds *header = NULL;
10458 GstBuffer *headerbuf;
10464 headerbuf = gst_buffer_new_and_alloc (headerlen);
10465 gst_buffer_fill (headerbuf, 0, waveheader, headerlen);
10467 if (gst_riff_parse_strf_auds (GST_ELEMENT_CAST (qtdemux),
10468 headerbuf, &header, &extra)) {
10469 gst_caps_unref (stream->caps);
10470 /* FIXME: Need to do something with the channel reorder map */
10471 stream->caps = gst_riff_create_audio_caps (header->format, NULL,
10472 header, extra, NULL, NULL, NULL);
10475 gst_buffer_unref (extra);
10480 GST_DEBUG ("Didn't find waveheadernode for this codec");
10482 g_node_destroy (wavenode);
10485 gst_qtdemux_handle_esds (qtdemux, stream, esds, stream->pending_tags);
10489 /* FIXME: what is in the chunk? */
10492 gint len = QT_UINT32 (stsd_data);
10494 /* seems to be always = 116 = 0x74 */
10500 gint len = QT_UINT32 (stsd_data);
10503 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x4C);
10505 gst_buffer_fill (buf, 0, stsd_data + 0x4C, len - 0x4C);
10506 gst_caps_set_simple (stream->caps,
10507 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10508 gst_buffer_unref (buf);
10510 gst_caps_set_simple (stream->caps,
10511 "samplesize", G_TYPE_INT, samplesize, NULL);
10516 GNode *alac, *wave = NULL;
10518 /* apparently, m4a has this atom appended directly in the stsd entry,
10519 * while mov has it in a wave atom */
10520 alac = qtdemux_tree_get_child_by_type (stsd, FOURCC_alac);
10522 /* alac now refers to stsd entry atom */
10523 wave = qtdemux_tree_get_child_by_type (alac, FOURCC_wave);
10525 alac = qtdemux_tree_get_child_by_type (wave, FOURCC_alac);
10527 alac = qtdemux_tree_get_child_by_type (alac, FOURCC_alac);
10530 const guint8 *alac_data = alac->data;
10531 gint len = QT_UINT32 (alac->data);
10535 GST_DEBUG_OBJECT (qtdemux,
10536 "discarding alac atom with unexpected len %d", len);
10538 /* codec-data contains alac atom size and prefix,
10539 * ffmpeg likes it that way, not quite gst-ish though ...*/
10540 buf = gst_buffer_new_and_alloc (len);
10541 gst_buffer_fill (buf, 0, alac->data, len);
10542 gst_caps_set_simple (stream->caps,
10543 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10544 gst_buffer_unref (buf);
10546 stream->bytes_per_frame = QT_UINT32 (alac_data + 12);
10547 stream->n_channels = QT_UINT8 (alac_data + 21);
10548 stream->rate = QT_UINT32 (alac_data + 32);
10551 gst_caps_set_simple (stream->caps,
10552 "samplesize", G_TYPE_INT, samplesize, NULL);
10560 gint len = QT_UINT32 (stsd_data);
10563 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x34);
10566 gst_buffer_fill (buf, 0, stsd_data + 0x34, len - 0x34);
10568 /* If we have enough data, let's try to get the 'damr' atom. See
10569 * the 3GPP container spec (26.244) for more details. */
10570 if ((len - 0x34) > 8 &&
10571 (bitrate = qtdemux_parse_amr_bitrate (buf, amrwb))) {
10572 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
10573 GST_TAG_MAXIMUM_BITRATE, bitrate, NULL);
10576 gst_caps_set_simple (stream->caps,
10577 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10578 gst_buffer_unref (buf);
10584 /* mp4a atom withtout ESDS; Attempt to build codec data from atom */
10585 gint len = QT_UINT32 (stsd_data);
10588 guint16 sound_version = QT_UINT16 (stsd_data + 32);
10590 if (sound_version == 1) {
10591 guint16 channels = QT_UINT16 (stsd_data + 40);
10592 guint32 time_scale = QT_UINT32 (stsd_data + 46);
10593 guint8 codec_data[2];
10595 gint profile = 2; /* FIXME: Can this be determined somehow? There doesn't seem to be anything in mp4a atom that specifis compression */
10597 gint sample_rate_index =
10598 gst_codec_utils_aac_get_index_from_sample_rate (time_scale);
10600 /* build AAC codec data */
10601 codec_data[0] = profile << 3;
10602 codec_data[0] |= ((sample_rate_index >> 1) & 0x7);
10603 codec_data[1] = (sample_rate_index & 0x01) << 7;
10604 codec_data[1] |= (channels & 0xF) << 3;
10606 buf = gst_buffer_new_and_alloc (2);
10607 gst_buffer_fill (buf, 0, codec_data, 2);
10608 gst_caps_set_simple (stream->caps,
10609 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10610 gst_buffer_unref (buf);
10616 GST_INFO_OBJECT (qtdemux,
10617 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
10621 GST_INFO_OBJECT (qtdemux,
10622 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
10623 GST_FOURCC_ARGS (fourcc), stream->caps);
10625 } else if (stream->subtype == FOURCC_strm) {
10626 if (fourcc == FOURCC_rtsp) {
10627 stream->redirect_uri = qtdemux_get_rtsp_uri_from_hndl (qtdemux, minf);
10629 GST_INFO_OBJECT (qtdemux, "unhandled stream type %" GST_FOURCC_FORMAT,
10630 GST_FOURCC_ARGS (fourcc));
10631 goto unknown_stream;
10633 stream->sampled = TRUE;
10634 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
10635 || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt) {
10637 stream->sampled = TRUE;
10638 stream->sparse = TRUE;
10641 qtdemux_sub_caps (qtdemux, stream, fourcc, stsd_data, &codec);
10643 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
10644 GST_TAG_SUBTITLE_CODEC, codec, NULL);
10649 /* hunt for sort-of codec data */
10653 GNode *mp4s = NULL;
10654 GNode *esds = NULL;
10656 /* look for palette in a stsd->mp4s->esds sub-atom */
10657 mp4s = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4s);
10659 esds = qtdemux_tree_get_child_by_type (mp4s, FOURCC_esds);
10660 if (esds == NULL) {
10662 GST_LOG_OBJECT (qtdemux, "Skipping invalid stsd: no esds child");
10666 gst_qtdemux_handle_esds (qtdemux, stream, esds, stream->pending_tags);
10670 GST_INFO_OBJECT (qtdemux,
10671 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
10674 GST_INFO_OBJECT (qtdemux,
10675 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
10676 GST_FOURCC_ARGS (fourcc), stream->caps);
10678 /* everything in 1 sample */
10679 stream->sampled = TRUE;
10682 qtdemux_generic_caps (qtdemux, stream, fourcc, stsd_data, &codec);
10684 if (stream->caps == NULL)
10685 goto unknown_stream;
10688 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
10689 GST_TAG_SUBTITLE_CODEC, codec, NULL);
10695 /* promote to sampled format */
10696 if (stream->fourcc == FOURCC_samr) {
10697 /* force mono 8000 Hz for AMR */
10698 stream->sampled = TRUE;
10699 stream->n_channels = 1;
10700 stream->rate = 8000;
10701 } else if (stream->fourcc == FOURCC_sawb) {
10702 /* force mono 16000 Hz for AMR-WB */
10703 stream->sampled = TRUE;
10704 stream->n_channels = 1;
10705 stream->rate = 16000;
10706 } else if (stream->fourcc == FOURCC_mp4a) {
10707 stream->sampled = TRUE;
10710 /* collect sample information */
10711 if (!qtdemux_stbl_init (qtdemux, stream, stbl))
10712 goto samples_failed;
10714 if (qtdemux->fragmented) {
10717 /* need all moov samples as basis; probably not many if any at all */
10718 /* prevent moof parsing taking of at this time */
10719 offset = qtdemux->moof_offset;
10720 qtdemux->moof_offset = 0;
10721 if (stream->n_samples &&
10722 !qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
10723 qtdemux->moof_offset = offset;
10724 goto samples_failed;
10726 qtdemux->moof_offset = 0;
10727 /* movie duration more reliable in this case (e.g. mehd) */
10728 if (qtdemux->segment.duration &&
10729 GST_CLOCK_TIME_IS_VALID (qtdemux->segment.duration))
10731 GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->segment.duration);
10734 /* configure segments */
10735 if (!qtdemux_parse_segments (qtdemux, stream, trak))
10736 goto segments_failed;
10738 /* add some language tag, if useful */
10739 if (stream->lang_id[0] != '\0' && strcmp (stream->lang_id, "unk") &&
10740 strcmp (stream->lang_id, "und")) {
10741 const gchar *lang_code;
10743 /* convert ISO 639-2 code to ISO 639-1 */
10744 lang_code = gst_tag_get_language_code (stream->lang_id);
10745 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
10746 GST_TAG_LANGUAGE_CODE, (lang_code) ? lang_code : stream->lang_id, NULL);
10749 /* Check for UDTA tags */
10750 if ((udta = qtdemux_tree_get_child_by_type (trak, FOURCC_udta))) {
10751 qtdemux_parse_udta (qtdemux, stream->pending_tags, udta);
10754 /* now we are ready to add the stream */
10755 if (qtdemux->n_streams >= GST_QTDEMUX_MAX_STREAMS)
10756 goto too_many_streams;
10758 if (!qtdemux->got_moov) {
10759 qtdemux->streams[qtdemux->n_streams] = stream;
10760 qtdemux->n_streams++;
10761 GST_DEBUG_OBJECT (qtdemux, "n_streams is now %d", qtdemux->n_streams);
10769 GST_INFO_OBJECT (qtdemux, "skip disabled track");
10771 gst_qtdemux_stream_free (qtdemux, stream);
10776 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
10777 (_("This file is corrupt and cannot be played.")), (NULL));
10779 gst_qtdemux_stream_free (qtdemux, stream);
10784 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT, (NULL), (NULL));
10786 gst_qtdemux_stream_free (qtdemux, stream);
10792 /* we posted an error already */
10793 /* free stbl sub-atoms */
10794 gst_qtdemux_stbl_free (stream);
10796 gst_qtdemux_stream_free (qtdemux, stream);
10801 GST_INFO_OBJECT (qtdemux, "stream with track id %i already exists",
10804 gst_qtdemux_stream_free (qtdemux, stream);
10809 GST_INFO_OBJECT (qtdemux, "unknown subtype %" GST_FOURCC_FORMAT,
10810 GST_FOURCC_ARGS (stream->subtype));
10812 gst_qtdemux_stream_free (qtdemux, stream);
10817 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
10818 (_("This file contains too many streams. Only playing first %d"),
10819 GST_QTDEMUX_MAX_STREAMS), (NULL));
10824 /* If we can estimate the overall bitrate, and don't have information about the
10825 * stream bitrate for exactly one stream, this guesses the stream bitrate as
10826 * the overall bitrate minus the sum of the bitrates of all other streams. This
10827 * should be useful for the common case where we have one audio and one video
10828 * stream and can estimate the bitrate of one, but not the other. */
10830 gst_qtdemux_guess_bitrate (GstQTDemux * qtdemux)
10832 QtDemuxStream *stream = NULL;
10833 gint64 size, sys_bitrate, sum_bitrate = 0;
10834 GstClockTime duration;
10838 if (qtdemux->fragmented)
10841 GST_DEBUG_OBJECT (qtdemux, "Looking for streams with unknown bitrate");
10843 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &size)
10845 GST_DEBUG_OBJECT (qtdemux,
10846 "Size in bytes of the stream not known - bailing");
10850 /* Subtract the header size */
10851 GST_DEBUG_OBJECT (qtdemux, "Total size %" G_GINT64_FORMAT ", header size %u",
10852 size, qtdemux->header_size);
10854 if (size < qtdemux->header_size)
10857 size = size - qtdemux->header_size;
10859 if (!gst_qtdemux_get_duration (qtdemux, &duration)) {
10860 GST_DEBUG_OBJECT (qtdemux, "Stream duration not known - bailing");
10864 for (i = 0; i < qtdemux->n_streams; i++) {
10865 switch (qtdemux->streams[i]->subtype) {
10868 GST_DEBUG_OBJECT (qtdemux, "checking bitrate for %" GST_PTR_FORMAT,
10869 qtdemux->streams[i]->caps);
10870 /* retrieve bitrate, prefer avg then max */
10872 if (qtdemux->streams[i]->pending_tags) {
10873 gst_tag_list_get_uint (qtdemux->streams[i]->pending_tags,
10874 GST_TAG_MAXIMUM_BITRATE, &bitrate);
10875 GST_DEBUG_OBJECT (qtdemux, "max-bitrate: %u", bitrate);
10876 gst_tag_list_get_uint (qtdemux->streams[i]->pending_tags,
10877 GST_TAG_NOMINAL_BITRATE, &bitrate);
10878 GST_DEBUG_OBJECT (qtdemux, "nominal-bitrate: %u", bitrate);
10879 gst_tag_list_get_uint (qtdemux->streams[i]->pending_tags,
10880 GST_TAG_BITRATE, &bitrate);
10881 GST_DEBUG_OBJECT (qtdemux, "bitrate: %u", bitrate);
10884 sum_bitrate += bitrate;
10887 GST_DEBUG_OBJECT (qtdemux,
10888 ">1 stream with unknown bitrate - bailing");
10891 stream = qtdemux->streams[i];
10895 /* For other subtypes, we assume no significant impact on bitrate */
10901 GST_DEBUG_OBJECT (qtdemux, "All stream bitrates are known");
10905 sys_bitrate = gst_util_uint64_scale (size, GST_SECOND * 8, duration);
10907 if (sys_bitrate < sum_bitrate) {
10908 /* This can happen, since sum_bitrate might be derived from maximum
10909 * bitrates and not average bitrates */
10910 GST_DEBUG_OBJECT (qtdemux,
10911 "System bitrate less than sum bitrate - bailing");
10915 bitrate = sys_bitrate - sum_bitrate;
10916 GST_DEBUG_OBJECT (qtdemux, "System bitrate = %" G_GINT64_FORMAT
10917 ", Stream bitrate = %u", sys_bitrate, bitrate);
10919 if (!stream->pending_tags)
10920 stream->pending_tags = gst_tag_list_new_empty ();
10922 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
10923 GST_TAG_BITRATE, bitrate, NULL);
10926 static GstFlowReturn
10927 qtdemux_prepare_streams (GstQTDemux * qtdemux)
10930 GstFlowReturn ret = GST_FLOW_OK;
10932 GST_DEBUG_OBJECT (qtdemux, "prepare streams");
10934 for (i = 0; ret == GST_FLOW_OK && i < qtdemux->n_streams; i++) {
10935 QtDemuxStream *stream = qtdemux->streams[i];
10936 guint32 sample_num = 0;
10938 GST_DEBUG_OBJECT (qtdemux, "stream %d, id %d, fourcc %" GST_FOURCC_FORMAT,
10939 i, stream->track_id, GST_FOURCC_ARGS (stream->fourcc));
10941 if (qtdemux->fragmented) {
10942 /* need all moov samples first */
10943 GST_OBJECT_LOCK (qtdemux);
10944 while (stream->n_samples == 0)
10945 if ((ret = qtdemux_add_fragmented_samples (qtdemux)) != GST_FLOW_OK)
10947 GST_OBJECT_UNLOCK (qtdemux);
10949 /* discard any stray moof */
10950 qtdemux->moof_offset = 0;
10953 /* prepare braking */
10954 if (ret != GST_FLOW_ERROR)
10957 /* in pull mode, we should have parsed some sample info by now;
10958 * and quite some code will not handle no samples.
10959 * in push mode, we'll just have to deal with it */
10960 if (G_UNLIKELY (qtdemux->pullbased && !stream->n_samples)) {
10961 GST_DEBUG_OBJECT (qtdemux, "no samples for stream; discarding");
10962 gst_qtdemux_remove_stream (qtdemux, i);
10967 /* parse the initial sample for use in setting the frame rate cap */
10968 while (sample_num == 0 && sample_num < stream->n_samples) {
10969 if (!qtdemux_parse_samples (qtdemux, stream, sample_num))
10973 if (stream->n_samples > 0 && stream->stbl_index >= 0) {
10974 stream->first_duration = stream->samples[0].duration;
10975 GST_LOG_OBJECT (qtdemux, "stream %d first duration %u",
10976 stream->track_id, stream->first_duration);
10983 static GstFlowReturn
10984 qtdemux_expose_streams (GstQTDemux * qtdemux)
10987 GstFlowReturn ret = GST_FLOW_OK;
10988 GSList *oldpads = NULL;
10991 GST_DEBUG_OBJECT (qtdemux, "exposing streams");
10993 for (i = 0; ret == GST_FLOW_OK && i < qtdemux->n_streams; i++) {
10994 QtDemuxStream *stream = qtdemux->streams[i];
10995 GstPad *oldpad = stream->pad;
10998 GST_DEBUG_OBJECT (qtdemux, "stream %d, id %d, fourcc %" GST_FOURCC_FORMAT,
10999 i, stream->track_id, GST_FOURCC_ARGS (stream->fourcc));
11001 if ((stream->subtype == FOURCC_text || stream->subtype == FOURCC_sbtl) &&
11002 stream->track_id == qtdemux->chapters_track_id) {
11003 /* TODO - parse chapters track and expose it as GstToc; For now just ignore it
11004 so that it doesn't look like a subtitle track */
11005 gst_qtdemux_remove_stream (qtdemux, i);
11010 /* now we have all info and can expose */
11011 list = stream->pending_tags;
11012 stream->pending_tags = NULL;
11014 oldpads = g_slist_prepend (oldpads, oldpad);
11015 if (!gst_qtdemux_add_stream (qtdemux, stream, list))
11016 return GST_FLOW_ERROR;
11019 gst_qtdemux_guess_bitrate (qtdemux);
11021 gst_element_no_more_pads (GST_ELEMENT_CAST (qtdemux));
11023 for (iter = oldpads; iter; iter = g_slist_next (iter)) {
11024 GstPad *oldpad = iter->data;
11027 event = gst_event_new_eos ();
11028 if (qtdemux->segment_seqnum)
11029 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
11031 gst_pad_push_event (oldpad, event);
11032 gst_pad_set_active (oldpad, FALSE);
11033 gst_element_remove_pad (GST_ELEMENT (qtdemux), oldpad);
11034 gst_flow_combiner_remove_pad (qtdemux->flowcombiner, oldpad);
11035 gst_object_unref (oldpad);
11038 /* check if we should post a redirect in case there is a single trak
11039 * and it is a redirecting trak */
11040 if (qtdemux->n_streams == 1 && qtdemux->streams[0]->redirect_uri != NULL) {
11043 GST_INFO_OBJECT (qtdemux, "Issuing a redirect due to a single track with "
11044 "an external content");
11045 m = gst_message_new_element (GST_OBJECT_CAST (qtdemux),
11046 gst_structure_new ("redirect",
11047 "new-location", G_TYPE_STRING, qtdemux->streams[0]->redirect_uri,
11049 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), m);
11050 qtdemux->posted_redirect = TRUE;
11053 for (i = 0; i < qtdemux->n_streams; i++) {
11054 QtDemuxStream *stream = qtdemux->streams[i];
11056 qtdemux_do_allocation (qtdemux, stream);
11059 qtdemux->exposed = TRUE;
11063 /* check if major or compatible brand is 3GP */
11064 static inline gboolean
11065 qtdemux_is_brand_3gp (GstQTDemux * qtdemux, gboolean major)
11068 return ((qtdemux->major_brand & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
11070 } else if (qtdemux->comp_brands != NULL) {
11074 gboolean res = FALSE;
11076 gst_buffer_map (qtdemux->comp_brands, &map, GST_MAP_READ);
11079 while (size >= 4) {
11080 res = res || ((QT_FOURCC (data) & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
11085 gst_buffer_unmap (qtdemux->comp_brands, &map);
11092 /* check if tag is a spec'ed 3GP tag keyword storing a string */
11093 static inline gboolean
11094 qtdemux_is_string_tag_3gp (GstQTDemux * qtdemux, guint32 fourcc)
11096 return fourcc == FOURCC_cprt || fourcc == FOURCC_gnre || fourcc == FOURCC_titl
11097 || fourcc == FOURCC_dscp || fourcc == FOURCC_perf || fourcc == FOURCC_auth
11098 || fourcc == FOURCC_albm;
11102 qtdemux_tag_add_location (GstQTDemux * qtdemux, GstTagList * taglist,
11103 const char *tag, const char *dummy, GNode * node)
11105 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
11109 gdouble longitude, latitude, altitude;
11112 len = QT_UINT32 (node->data);
11119 /* TODO: language code skipped */
11121 name = gst_tag_freeform_string_to_utf8 (data + offset, -1, env_vars);
11124 /* do not alarm in trivial case, but bail out otherwise */
11125 if (*(data + offset) != 0) {
11126 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8, "
11130 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
11131 GST_TAG_GEO_LOCATION_NAME, name, NULL);
11132 offset += strlen (name);
11136 if (len < offset + 2 + 4 + 4 + 4)
11139 /* +1 +1 = skip null-terminator and location role byte */
11141 /* table in spec says unsigned, semantics say negative has meaning ... */
11142 longitude = QT_SFP32 (data + offset);
11145 latitude = QT_SFP32 (data + offset);
11148 altitude = QT_SFP32 (data + offset);
11150 /* one invalid means all are invalid */
11151 if (longitude >= -180.0 && longitude <= 180.0 &&
11152 latitude >= -90.0 && latitude <= 90.0) {
11153 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
11154 GST_TAG_GEO_LOCATION_LATITUDE, latitude,
11155 GST_TAG_GEO_LOCATION_LONGITUDE, longitude,
11156 GST_TAG_GEO_LOCATION_ELEVATION, altitude, NULL);
11159 /* TODO: no GST_TAG_, so astronomical body and additional notes skipped */
11166 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP location");
11173 qtdemux_tag_add_year (GstQTDemux * qtdemux, GstTagList * taglist,
11174 const char *tag, const char *dummy, GNode * node)
11180 len = QT_UINT32 (node->data);
11184 y = QT_UINT16 ((guint8 *) node->data + 12);
11186 GST_DEBUG_OBJECT (qtdemux, "year: %u is not a valid year", y);
11189 GST_DEBUG_OBJECT (qtdemux, "year: %u", y);
11191 date = g_date_new_dmy (1, 1, y);
11192 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, date, NULL);
11193 g_date_free (date);
11197 qtdemux_tag_add_classification (GstQTDemux * qtdemux, GstTagList * taglist,
11198 const char *tag, const char *dummy, GNode * node)
11201 char *tag_str = NULL;
11206 len = QT_UINT32 (node->data);
11211 entity = (guint8 *) node->data + offset;
11212 if (entity[0] == 0 || entity[1] == 0 || entity[2] == 0 || entity[3] == 0) {
11213 GST_DEBUG_OBJECT (qtdemux,
11214 "classification info: %c%c%c%c invalid classification entity",
11215 entity[0], entity[1], entity[2], entity[3]);
11220 table = QT_UINT16 ((guint8 *) node->data + offset);
11222 /* Language code skipped */
11226 /* Tag format: "XXXX://Y[YYYY]/classification info string"
11227 * XXXX: classification entity, fixed length 4 chars.
11228 * Y[YYYY]: classification table, max 5 chars.
11230 tag_str = g_strdup_printf ("----://%u/%s",
11231 table, (char *) node->data + offset);
11233 /* memcpy To be sure we're preserving byte order */
11234 memcpy (tag_str, entity, 4);
11235 GST_DEBUG_OBJECT (qtdemux, "classification info: %s", tag_str);
11237 gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND, tag, tag_str, NULL);
11246 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP classification");
11252 qtdemux_tag_add_str_full (GstQTDemux * qtdemux, GstTagList * taglist,
11253 const char *tag, const char *dummy, GNode * node)
11255 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
11261 gboolean ret = TRUE;
11262 const gchar *charset = NULL;
11264 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
11266 len = QT_UINT32 (data->data);
11267 type = QT_UINT32 ((guint8 *) data->data + 8);
11268 if (type == 0x00000001 && len > 16) {
11269 s = gst_tag_freeform_string_to_utf8 ((char *) data->data + 16, len - 16,
11272 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
11273 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, s, NULL);
11276 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
11280 len = QT_UINT32 (node->data);
11281 type = QT_UINT32 ((guint8 *) node->data + 4);
11282 if ((type >> 24) == 0xa9) {
11286 /* Type starts with the (C) symbol, so the next data is a list
11287 * of (string size(16), language code(16), string) */
11289 str_len = QT_UINT16 ((guint8 *) node->data + 8);
11290 lang_code = QT_UINT16 ((guint8 *) node->data + 10);
11292 /* the string + fourcc + size + 2 16bit fields,
11293 * means that there are more tags in this atom */
11294 if (len > str_len + 8 + 4) {
11295 /* TODO how to represent the same tag in different languages? */
11296 GST_WARNING_OBJECT (qtdemux, "Ignoring metadata entry with multiple "
11297 "text alternatives, reading only first one");
11301 len = str_len + 8 + 4; /* remove trailing strings that we don't use */
11302 GST_DEBUG_OBJECT (qtdemux, "found international text tag");
11304 if (lang_code < 0x800) { /* MAC encoded string */
11307 } else if (len > 14 && qtdemux_is_string_tag_3gp (qtdemux,
11308 QT_FOURCC ((guint8 *) node->data + 4))) {
11309 guint32 type = QT_UINT32 ((guint8 *) node->data + 8);
11311 /* we go for 3GP style encoding if major brands claims so,
11312 * or if no hope for data be ok UTF-8, and compatible 3GP brand present */
11313 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
11314 (qtdemux_is_brand_3gp (qtdemux, FALSE) &&
11315 ((type & 0x00FFFFFF) == 0x0) && (type >> 24 <= 0xF))) {
11317 /* 16-bit Language code is ignored here as well */
11318 GST_DEBUG_OBJECT (qtdemux, "found 3gpp text tag");
11325 GST_DEBUG_OBJECT (qtdemux, "found normal text tag");
11326 ret = FALSE; /* may have to fallback */
11329 GError *err = NULL;
11331 s = g_convert ((gchar *) node->data + offset, len - offset, "utf8",
11332 charset, NULL, NULL, &err);
11334 GST_DEBUG_OBJECT (qtdemux, "Failed to convert string from charset %s:"
11335 " %s(%d): %s", charset, g_quark_to_string (err->domain), err->code,
11337 g_error_free (err);
11340 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
11341 len - offset, env_vars);
11344 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
11345 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, s, NULL);
11349 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
11356 qtdemux_tag_add_str (GstQTDemux * qtdemux, GstTagList * taglist,
11357 const char *tag, const char *dummy, GNode * node)
11359 qtdemux_tag_add_str_full (qtdemux, taglist, tag, dummy, node);
11363 qtdemux_tag_add_keywords (GstQTDemux * qtdemux, GstTagList * taglist,
11364 const char *tag, const char *dummy, GNode * node)
11366 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
11368 char *s, *t, *k = NULL;
11373 /* first try normal string tag if major brand not 3GP */
11374 if (!qtdemux_is_brand_3gp (qtdemux, TRUE)) {
11375 if (!qtdemux_tag_add_str_full (qtdemux, taglist, tag, dummy, node)) {
11376 /* hm, that did not work, maybe 3gpp storage in non-3gpp major brand;
11377 * let's try it 3gpp way after minor safety check */
11379 if (QT_UINT32 (data) < 15 || !qtdemux_is_brand_3gp (qtdemux, FALSE))
11385 GST_DEBUG_OBJECT (qtdemux, "found 3gpp keyword tag");
11389 len = QT_UINT32 (data);
11393 count = QT_UINT8 (data + 14);
11395 for (; count; count--) {
11398 if (offset + 1 > len)
11400 slen = QT_UINT8 (data + offset);
11402 if (offset + slen > len)
11404 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
11407 GST_DEBUG_OBJECT (qtdemux, "adding keyword %s", GST_STR_NULL (s));
11409 t = g_strjoin (",", k, s, NULL);
11417 GST_DEBUG_OBJECT (qtdemux, "failed to convert keyword to UTF-8");
11424 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (k));
11425 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, k, NULL);
11434 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP keywords");
11440 qtdemux_tag_add_num (GstQTDemux * qtdemux, GstTagList * taglist,
11441 const char *tag1, const char *tag2, GNode * node)
11448 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
11450 len = QT_UINT32 (data->data);
11451 type = QT_UINT32 ((guint8 *) data->data + 8);
11452 if (type == 0x00000000 && len >= 22) {
11453 n1 = QT_UINT16 ((guint8 *) data->data + 18);
11454 n2 = QT_UINT16 ((guint8 *) data->data + 20);
11456 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag1, n1);
11457 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, n1, NULL);
11460 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag2, n2);
11461 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag2, n2, NULL);
11468 qtdemux_tag_add_tmpo (GstQTDemux * qtdemux, GstTagList * taglist,
11469 const char *tag1, const char *dummy, GNode * node)
11476 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
11478 len = QT_UINT32 (data->data);
11479 type = QT_UINT32 ((guint8 *) data->data + 8);
11480 GST_DEBUG_OBJECT (qtdemux, "have tempo tag, type=%d,len=%d", type, len);
11481 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
11482 if ((type == 0x00000015 || type == 0x0000000f) && len >= 18) {
11483 n1 = QT_UINT16 ((guint8 *) data->data + 16);
11485 /* do not add bpm=0 */
11486 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", n1);
11487 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, (gdouble) n1,
11495 qtdemux_tag_add_uint32 (GstQTDemux * qtdemux, GstTagList * taglist,
11496 const char *tag1, const char *dummy, GNode * node)
11503 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
11505 len = QT_UINT32 (data->data);
11506 type = QT_UINT32 ((guint8 *) data->data + 8);
11507 GST_DEBUG_OBJECT (qtdemux, "have %s tag, type=%d,len=%d", tag1, type, len);
11508 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
11509 if ((type == 0x00000015 || type == 0x0000000f) && len >= 20) {
11510 num = QT_UINT32 ((guint8 *) data->data + 16);
11512 /* do not add num=0 */
11513 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", num);
11514 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, num, NULL);
11521 qtdemux_tag_add_covr (GstQTDemux * qtdemux, GstTagList * taglist,
11522 const char *tag1, const char *dummy, GNode * node)
11529 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
11531 len = QT_UINT32 (data->data);
11532 type = QT_UINT32 ((guint8 *) data->data + 8);
11533 GST_DEBUG_OBJECT (qtdemux, "have covr tag, type=%d,len=%d", type, len);
11534 if ((type == 0x0000000d || type == 0x0000000e) && len > 16) {
11536 gst_tag_image_data_to_image_sample ((guint8 *) data->data + 16,
11537 len - 16, GST_TAG_IMAGE_TYPE_NONE))) {
11538 GST_DEBUG_OBJECT (qtdemux, "adding tag size %d", len - 16);
11539 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, sample, NULL);
11540 gst_sample_unref (sample);
11547 qtdemux_tag_add_date (GstQTDemux * qtdemux, GstTagList * taglist,
11548 const char *tag, const char *dummy, GNode * node)
11555 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
11557 len = QT_UINT32 (data->data);
11558 type = QT_UINT32 ((guint8 *) data->data + 8);
11559 if (type == 0x00000001 && len > 16) {
11560 guint y, m = 1, d = 1;
11563 s = g_strndup ((char *) data->data + 16, len - 16);
11564 GST_DEBUG_OBJECT (qtdemux, "adding date '%s'", s);
11565 ret = sscanf (s, "%u-%u-%u", &y, &m, &d);
11566 if (ret >= 1 && y > 1500 && y < 3000) {
11569 date = g_date_new_dmy (d, m, y);
11570 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, date, NULL);
11571 g_date_free (date);
11573 GST_DEBUG_OBJECT (qtdemux, "could not parse date string '%s'", s);
11581 qtdemux_tag_add_gnre (GstQTDemux * qtdemux, GstTagList * taglist,
11582 const char *tag, const char *dummy, GNode * node)
11586 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
11588 /* re-route to normal string tag if major brand says so
11589 * or no data atom and compatible brand suggests so */
11590 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
11591 (qtdemux_is_brand_3gp (qtdemux, FALSE) && !data)) {
11592 qtdemux_tag_add_str (qtdemux, taglist, tag, dummy, node);
11597 guint len, type, n;
11599 len = QT_UINT32 (data->data);
11600 type = QT_UINT32 ((guint8 *) data->data + 8);
11601 if (type == 0x00000000 && len >= 18) {
11602 n = QT_UINT16 ((guint8 *) data->data + 16);
11604 const gchar *genre;
11606 genre = gst_tag_id3_genre_get (n - 1);
11607 if (genre != NULL) {
11608 GST_DEBUG_OBJECT (qtdemux, "adding %d [%s]", n, genre);
11609 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, genre, NULL);
11617 qtdemux_add_double_tag_from_str (GstQTDemux * demux, GstTagList * taglist,
11618 const gchar * tag, guint8 * data, guint32 datasize)
11623 /* make a copy to have \0 at the end */
11624 datacopy = g_strndup ((gchar *) data, datasize);
11626 /* convert the str to double */
11627 if (sscanf (datacopy, "%lf", &value) == 1) {
11628 GST_DEBUG_OBJECT (demux, "adding tag: %s [%s]", tag, datacopy);
11629 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, value, NULL);
11631 GST_WARNING_OBJECT (demux, "Failed to parse double from string: %s",
11639 qtdemux_tag_add_revdns (GstQTDemux * demux, GstTagList * taglist,
11640 const char *tag, const char *tag_bis, GNode * node)
11649 const gchar *meanstr;
11650 const gchar *namestr;
11652 /* checking the whole ---- atom size for consistency */
11653 if (QT_UINT32 (node->data) <= 4 + 12 + 12 + 16) {
11654 GST_WARNING_OBJECT (demux, "Tag ---- atom is too small, ignoring");
11658 mean = qtdemux_tree_get_child_by_type (node, FOURCC_mean);
11660 GST_WARNING_OBJECT (demux, "No 'mean' atom found");
11664 meansize = QT_UINT32 (mean->data);
11665 if (meansize <= 12) {
11666 GST_WARNING_OBJECT (demux, "Small mean atom, ignoring the whole tag");
11669 meanstr = ((gchar *) mean->data) + 12;
11672 name = qtdemux_tree_get_child_by_type (node, FOURCC_name);
11674 GST_WARNING_OBJECT (demux, "'name' atom not found, ignoring tag");
11678 namesize = QT_UINT32 (name->data);
11679 if (namesize <= 12) {
11680 GST_WARNING_OBJECT (demux, "'name' atom is too small, ignoring tag");
11683 namestr = ((gchar *) name->data) + 12;
11691 * uint24 - data type
11695 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
11697 GST_WARNING_OBJECT (demux, "No data atom in this tag");
11700 datasize = QT_UINT32 (data->data);
11701 if (datasize <= 16) {
11702 GST_WARNING_OBJECT (demux, "Data atom too small");
11705 datatype = QT_UINT32 (((gchar *) data->data) + 8) & 0xFFFFFF;
11707 if ((strncmp (meanstr, "com.apple.iTunes", meansize) == 0) ||
11708 (strncmp (meanstr, "org.hydrogenaudio.replaygain", meansize) == 0)) {
11709 static const struct
11711 const gchar name[28];
11712 const gchar tag[28];
11715 "replaygain_track_gain", GST_TAG_TRACK_GAIN}, {
11716 "replaygain_track_peak", GST_TAG_TRACK_PEAK}, {
11717 "replaygain_album_gain", GST_TAG_ALBUM_GAIN}, {
11718 "replaygain_album_peak", GST_TAG_ALBUM_PEAK}, {
11719 "MusicBrainz Track Id", GST_TAG_MUSICBRAINZ_TRACKID}, {
11720 "MusicBrainz Artist Id", GST_TAG_MUSICBRAINZ_ARTISTID}, {
11721 "MusicBrainz Album Id", GST_TAG_MUSICBRAINZ_ALBUMID}, {
11722 "MusicBrainz Album Artist Id", GST_TAG_MUSICBRAINZ_ALBUMARTISTID}
11726 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
11727 if (!g_ascii_strncasecmp (tags[i].name, namestr, namesize)) {
11728 switch (gst_tag_get_type (tags[i].tag)) {
11729 case G_TYPE_DOUBLE:
11730 qtdemux_add_double_tag_from_str (demux, taglist, tags[i].tag,
11731 ((guint8 *) data->data) + 16, datasize - 16);
11733 case G_TYPE_STRING:
11734 qtdemux_tag_add_str (demux, taglist, tags[i].tag, NULL, node);
11743 if (i == G_N_ELEMENTS (tags))
11753 #ifndef GST_DISABLE_GST_DEBUG
11755 gchar *namestr_dbg;
11756 gchar *meanstr_dbg;
11758 meanstr_dbg = g_strndup (meanstr, meansize);
11759 namestr_dbg = g_strndup (namestr, namesize);
11761 GST_WARNING_OBJECT (demux, "This tag %s:%s type:%u is not mapped, "
11762 "file a bug at bugzilla.gnome.org", meanstr_dbg, namestr_dbg, datatype);
11764 g_free (namestr_dbg);
11765 g_free (meanstr_dbg);
11772 qtdemux_tag_add_id32 (GstQTDemux * demux, GstTagList * taglist, const char *tag,
11773 const char *tag_bis, GNode * node)
11778 GstTagList *id32_taglist = NULL;
11780 GST_LOG_OBJECT (demux, "parsing ID32");
11783 len = GST_READ_UINT32_BE (data);
11785 /* need at least full box and language tag */
11789 buf = gst_buffer_new_allocate (NULL, len - 14, NULL);
11790 gst_buffer_fill (buf, 0, data + 14, len - 14);
11792 id32_taglist = gst_tag_list_from_id3v2_tag (buf);
11793 if (id32_taglist) {
11794 GST_LOG_OBJECT (demux, "parsing ok");
11795 gst_tag_list_insert (taglist, id32_taglist, GST_TAG_MERGE_KEEP);
11796 gst_tag_list_unref (id32_taglist);
11798 GST_LOG_OBJECT (demux, "parsing failed");
11801 gst_buffer_unref (buf);
11804 typedef void (*GstQTDemuxAddTagFunc) (GstQTDemux * demux, GstTagList * taglist,
11805 const char *tag, const char *tag_bis, GNode * node);
11808 FOURCC_pcst -> if media is a podcast -> bool
11809 FOURCC_cpil -> if media is part of a compilation -> bool
11810 FOURCC_pgap -> if media is part of a gapless context -> bool
11811 FOURCC_tven -> the tv episode id e.g. S01E23 -> str
11814 static const struct
11817 const gchar *gst_tag;
11818 const gchar *gst_tag_bis;
11819 const GstQTDemuxAddTagFunc func;
11822 FOURCC__nam, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
11823 FOURCC_titl, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
11824 FOURCC__grp, GST_TAG_GROUPING, NULL, qtdemux_tag_add_str}, {
11825 FOURCC__wrt, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
11826 FOURCC__ART, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
11827 FOURCC_aART, GST_TAG_ALBUM_ARTIST, NULL, qtdemux_tag_add_str}, {
11828 FOURCC_perf, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
11829 FOURCC_auth, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
11830 FOURCC__alb, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
11831 FOURCC_albm, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
11832 FOURCC_cprt, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
11833 FOURCC__cpy, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
11834 FOURCC__cmt, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
11835 FOURCC__des, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
11836 FOURCC_desc, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
11837 FOURCC_dscp, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
11838 FOURCC__lyr, GST_TAG_LYRICS, NULL, qtdemux_tag_add_str}, {
11839 FOURCC__day, GST_TAG_DATE, NULL, qtdemux_tag_add_date}, {
11840 FOURCC_yrrc, GST_TAG_DATE, NULL, qtdemux_tag_add_year}, {
11841 FOURCC__too, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
11842 FOURCC__inf, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
11843 FOURCC_trkn, GST_TAG_TRACK_NUMBER, GST_TAG_TRACK_COUNT, qtdemux_tag_add_num}, {
11844 FOURCC_disk, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
11845 qtdemux_tag_add_num}, {
11846 FOURCC_disc, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
11847 qtdemux_tag_add_num}, {
11848 FOURCC__gen, GST_TAG_GENRE, NULL, qtdemux_tag_add_str}, {
11849 FOURCC_gnre, GST_TAG_GENRE, NULL, qtdemux_tag_add_gnre}, {
11850 FOURCC_tmpo, GST_TAG_BEATS_PER_MINUTE, NULL, qtdemux_tag_add_tmpo}, {
11851 FOURCC_covr, GST_TAG_PREVIEW_IMAGE, NULL, qtdemux_tag_add_covr}, {
11852 FOURCC_sonm, GST_TAG_TITLE_SORTNAME, NULL, qtdemux_tag_add_str}, {
11853 FOURCC_soal, GST_TAG_ALBUM_SORTNAME, NULL, qtdemux_tag_add_str}, {
11854 FOURCC_soar, GST_TAG_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
11855 FOURCC_soaa, GST_TAG_ALBUM_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
11856 FOURCC_soco, GST_TAG_COMPOSER_SORTNAME, NULL, qtdemux_tag_add_str}, {
11857 FOURCC_sosn, GST_TAG_SHOW_SORTNAME, NULL, qtdemux_tag_add_str}, {
11858 FOURCC_tvsh, GST_TAG_SHOW_NAME, NULL, qtdemux_tag_add_str}, {
11859 FOURCC_tvsn, GST_TAG_SHOW_SEASON_NUMBER, NULL, qtdemux_tag_add_uint32}, {
11860 FOURCC_tves, GST_TAG_SHOW_EPISODE_NUMBER, NULL, qtdemux_tag_add_uint32}, {
11861 FOURCC_kywd, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_keywords}, {
11862 FOURCC_keyw, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_str}, {
11863 FOURCC__enc, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
11864 FOURCC_loci, GST_TAG_GEO_LOCATION_NAME, NULL, qtdemux_tag_add_location}, {
11865 FOURCC_clsf, GST_QT_DEMUX_CLASSIFICATION_TAG, NULL,
11866 qtdemux_tag_add_classification}, {
11867 FOURCC__mak, GST_TAG_DEVICE_MANUFACTURER, NULL, qtdemux_tag_add_str}, {
11868 FOURCC__mod, GST_TAG_DEVICE_MODEL, NULL, qtdemux_tag_add_str}, {
11869 FOURCC__swr, GST_TAG_APPLICATION_NAME, NULL, qtdemux_tag_add_str}, {
11871 /* This is a special case, some tags are stored in this
11872 * 'reverse dns naming', according to:
11873 * http://atomicparsley.sourceforge.net/mpeg-4files.html and
11876 FOURCC_____, "", NULL, qtdemux_tag_add_revdns}, {
11877 /* see http://www.mp4ra.org/specs.html for ID32 in meta box */
11878 FOURCC_ID32, "", NULL, qtdemux_tag_add_id32}
11881 struct _GstQtDemuxTagList
11884 GstTagList *taglist;
11886 typedef struct _GstQtDemuxTagList GstQtDemuxTagList;
11889 qtdemux_tag_add_blob (GNode * node, GstQtDemuxTagList * qtdemuxtaglist)
11895 const gchar *style;
11900 GstQTDemux *demux = qtdemuxtaglist->demux;
11901 GstTagList *taglist = qtdemuxtaglist->taglist;
11904 len = QT_UINT32 (data);
11905 buf = gst_buffer_new_and_alloc (len);
11906 gst_buffer_fill (buf, 0, data, len);
11908 /* heuristic to determine style of tag */
11909 if (QT_FOURCC (data + 4) == FOURCC_____ ||
11910 (len > 8 + 12 && QT_FOURCC (data + 12) == FOURCC_data))
11912 else if (demux->major_brand == FOURCC_qt__)
11913 style = "quicktime";
11914 /* fall back to assuming iso/3gp tag style */
11918 /* santize the name for the caps. */
11919 for (i = 0; i < 4; i++) {
11920 guint8 d = data[4 + i];
11921 if (g_ascii_isalnum (d))
11922 ndata[i] = g_ascii_tolower (d);
11927 media_type = g_strdup_printf ("application/x-gst-qt-%c%c%c%c-tag",
11928 ndata[0], ndata[1], ndata[2], ndata[3]);
11929 GST_DEBUG_OBJECT (demux, "media type %s", media_type);
11931 s = gst_structure_new (media_type, "style", G_TYPE_STRING, style, NULL);
11932 sample = gst_sample_new (buf, NULL, NULL, s);
11933 gst_buffer_unref (buf);
11934 g_free (media_type);
11936 GST_DEBUG_OBJECT (demux, "adding private tag; size %d, info %" GST_PTR_FORMAT,
11939 gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND,
11940 GST_QT_DEMUX_PRIVATE_TAG, sample, NULL);
11942 gst_sample_unref (sample);
11946 qtdemux_parse_udta (GstQTDemux * qtdemux, GstTagList * taglist, GNode * udta)
11953 GstQtDemuxTagList demuxtaglist;
11955 demuxtaglist.demux = qtdemux;
11956 demuxtaglist.taglist = taglist;
11958 meta = qtdemux_tree_get_child_by_type (udta, FOURCC_meta);
11959 if (meta != NULL) {
11960 ilst = qtdemux_tree_get_child_by_type (meta, FOURCC_ilst);
11961 if (ilst == NULL) {
11962 GST_LOG_OBJECT (qtdemux, "no ilst");
11967 GST_LOG_OBJECT (qtdemux, "no meta so using udta itself");
11971 while (i < G_N_ELEMENTS (add_funcs)) {
11972 node = qtdemux_tree_get_child_by_type (ilst, add_funcs[i].fourcc);
11976 len = QT_UINT32 (node->data);
11978 GST_DEBUG_OBJECT (qtdemux, "too small tag atom %" GST_FOURCC_FORMAT,
11979 GST_FOURCC_ARGS (add_funcs[i].fourcc));
11981 add_funcs[i].func (qtdemux, taglist, add_funcs[i].gst_tag,
11982 add_funcs[i].gst_tag_bis, node);
11984 g_node_destroy (node);
11990 /* parsed nodes have been removed, pass along remainder as blob */
11991 g_node_children_foreach (ilst, G_TRAVERSE_ALL,
11992 (GNodeForeachFunc) qtdemux_tag_add_blob, &demuxtaglist);
11994 /* parse up XMP_ node if existing */
11995 xmp_ = qtdemux_tree_get_child_by_type (udta, FOURCC_XMP_);
11996 if (xmp_ != NULL) {
11998 GstTagList *xmptaglist;
12000 buf = _gst_buffer_new_wrapped (((guint8 *) xmp_->data) + 8,
12001 QT_UINT32 ((guint8 *) xmp_->data) - 8, NULL);
12002 xmptaglist = gst_tag_list_from_xmp_buffer (buf);
12003 gst_buffer_unref (buf);
12005 qtdemux_handle_xmp_taglist (qtdemux, taglist, xmptaglist);
12007 GST_DEBUG_OBJECT (qtdemux, "No XMP_ node found");
12013 GstStructure *structure; /* helper for sort function */
12015 guint min_req_bitrate;
12016 guint min_req_qt_version;
12020 qtdemux_redirects_sort_func (gconstpointer a, gconstpointer b)
12022 GstQtReference *ref_a = (GstQtReference *) a;
12023 GstQtReference *ref_b = (GstQtReference *) b;
12025 if (ref_b->min_req_qt_version != ref_a->min_req_qt_version)
12026 return ref_b->min_req_qt_version - ref_a->min_req_qt_version;
12028 /* known bitrates go before unknown; higher bitrates go first */
12029 return ref_b->min_req_bitrate - ref_a->min_req_bitrate;
12032 /* sort the redirects and post a message for the application.
12035 qtdemux_process_redirects (GstQTDemux * qtdemux, GList * references)
12037 GstQtReference *best;
12040 GValue list_val = { 0, };
12043 g_assert (references != NULL);
12045 references = g_list_sort (references, qtdemux_redirects_sort_func);
12047 best = (GstQtReference *) references->data;
12049 g_value_init (&list_val, GST_TYPE_LIST);
12051 for (l = references; l != NULL; l = l->next) {
12052 GstQtReference *ref = (GstQtReference *) l->data;
12053 GValue struct_val = { 0, };
12055 ref->structure = gst_structure_new ("redirect",
12056 "new-location", G_TYPE_STRING, ref->location, NULL);
12058 if (ref->min_req_bitrate > 0) {
12059 gst_structure_set (ref->structure, "minimum-bitrate", G_TYPE_INT,
12060 ref->min_req_bitrate, NULL);
12063 g_value_init (&struct_val, GST_TYPE_STRUCTURE);
12064 g_value_set_boxed (&struct_val, ref->structure);
12065 gst_value_list_append_value (&list_val, &struct_val);
12066 g_value_unset (&struct_val);
12067 /* don't free anything here yet, since we need best->structure below */
12070 g_assert (best != NULL);
12071 s = gst_structure_copy (best->structure);
12073 if (g_list_length (references) > 1) {
12074 gst_structure_set_value (s, "locations", &list_val);
12077 g_value_unset (&list_val);
12079 for (l = references; l != NULL; l = l->next) {
12080 GstQtReference *ref = (GstQtReference *) l->data;
12082 gst_structure_free (ref->structure);
12083 g_free (ref->location);
12086 g_list_free (references);
12088 GST_INFO_OBJECT (qtdemux, "posting redirect message: %" GST_PTR_FORMAT, s);
12089 msg = gst_message_new_element (GST_OBJECT_CAST (qtdemux), s);
12090 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
12091 qtdemux->posted_redirect = TRUE;
12094 /* look for redirect nodes, collect all redirect information and
12098 qtdemux_parse_redirects (GstQTDemux * qtdemux)
12100 GNode *rmra, *rmda, *rdrf;
12102 rmra = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_rmra);
12104 GList *redirects = NULL;
12106 rmda = qtdemux_tree_get_child_by_type (rmra, FOURCC_rmda);
12108 GstQtReference ref = { NULL, NULL, 0, 0 };
12109 GNode *rmdr, *rmvc;
12111 if ((rmdr = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmdr))) {
12112 ref.min_req_bitrate = QT_UINT32 ((guint8 *) rmdr->data + 12);
12113 GST_LOG_OBJECT (qtdemux, "data rate atom, required bitrate = %u",
12114 ref.min_req_bitrate);
12117 if ((rmvc = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmvc))) {
12118 guint32 package = QT_FOURCC ((guint8 *) rmvc->data + 12);
12119 guint version = QT_UINT32 ((guint8 *) rmvc->data + 16);
12121 #ifndef GST_DISABLE_GST_DEBUG
12122 guint bitmask = QT_UINT32 ((guint8 *) rmvc->data + 20);
12124 guint check_type = QT_UINT16 ((guint8 *) rmvc->data + 24);
12126 GST_LOG_OBJECT (qtdemux,
12127 "version check atom [%" GST_FOURCC_FORMAT "], version=0x%08x"
12128 ", mask=%08x, check_type=%u", GST_FOURCC_ARGS (package), version,
12129 bitmask, check_type);
12130 if (package == FOURCC_qtim && check_type == 0) {
12131 ref.min_req_qt_version = version;
12135 rdrf = qtdemux_tree_get_child_by_type (rmda, FOURCC_rdrf);
12141 ref_len = QT_UINT32 ((guint8 *) rdrf->data);
12142 if (ref_len > 20) {
12143 ref_type = QT_FOURCC ((guint8 *) rdrf->data + 12);
12144 ref_data = (guint8 *) rdrf->data + 20;
12145 if (ref_type == FOURCC_alis) {
12146 guint record_len, record_version, fn_len;
12148 if (ref_len > 70) {
12149 /* MacOSX alias record, google for alias-layout.txt */
12150 record_len = QT_UINT16 (ref_data + 4);
12151 record_version = QT_UINT16 (ref_data + 4 + 2);
12152 fn_len = QT_UINT8 (ref_data + 50);
12153 if (record_len > 50 && record_version == 2 && fn_len > 0) {
12154 ref.location = g_strndup ((gchar *) ref_data + 51, fn_len);
12157 GST_WARNING_OBJECT (qtdemux, "Invalid rdrf/alis size (%u < 70)",
12160 } else if (ref_type == FOURCC_url_) {
12161 ref.location = g_strndup ((gchar *) ref_data, ref_len - 8);
12163 GST_DEBUG_OBJECT (qtdemux,
12164 "unknown rdrf reference type %" GST_FOURCC_FORMAT,
12165 GST_FOURCC_ARGS (ref_type));
12167 if (ref.location != NULL) {
12168 GST_INFO_OBJECT (qtdemux, "New location: %s", ref.location);
12170 g_list_prepend (redirects, g_memdup (&ref, sizeof (ref)));
12172 GST_WARNING_OBJECT (qtdemux,
12173 "Failed to extract redirect location from rdrf atom");
12176 GST_WARNING_OBJECT (qtdemux, "Invalid rdrf size (%u < 20)", ref_len);
12180 /* look for others */
12181 rmda = qtdemux_tree_get_sibling_by_type (rmda, FOURCC_rmda);
12184 if (redirects != NULL) {
12185 qtdemux_process_redirects (qtdemux, redirects);
12191 static GstTagList *
12192 qtdemux_add_container_format (GstQTDemux * qtdemux, GstTagList * tags)
12196 if (tags == NULL) {
12197 tags = gst_tag_list_new_empty ();
12198 gst_tag_list_set_scope (tags, GST_TAG_SCOPE_GLOBAL);
12201 if (qtdemux->major_brand == FOURCC_mjp2)
12202 fmt = "Motion JPEG 2000";
12203 else if ((qtdemux->major_brand & 0xffff) == FOURCC_3g__)
12205 else if (qtdemux->major_brand == FOURCC_qt__)
12207 else if (qtdemux->fragmented)
12210 fmt = "ISO MP4/M4A";
12212 GST_LOG_OBJECT (qtdemux, "mapped %" GST_FOURCC_FORMAT " to '%s'",
12213 GST_FOURCC_ARGS (qtdemux->major_brand), fmt);
12215 gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_CONTAINER_FORMAT,
12221 /* we have read th complete moov node now.
12222 * This function parses all of the relevant info, creates the traks and
12223 * prepares all data structures for playback
12226 qtdemux_parse_tree (GstQTDemux * qtdemux)
12232 GstClockTime duration;
12234 guint64 creation_time;
12235 GstDateTime *datetime = NULL;
12238 /* make sure we have a usable taglist */
12239 if (!qtdemux->tag_list) {
12240 qtdemux->tag_list = gst_tag_list_new_empty ();
12241 gst_tag_list_set_scope (qtdemux->tag_list, GST_TAG_SCOPE_GLOBAL);
12243 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
12246 mvhd = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvhd);
12247 if (mvhd == NULL) {
12248 GST_LOG_OBJECT (qtdemux, "No mvhd node found, looking for redirects.");
12249 return qtdemux_parse_redirects (qtdemux);
12252 version = QT_UINT8 ((guint8 *) mvhd->data + 8);
12253 if (version == 1) {
12254 creation_time = QT_UINT64 ((guint8 *) mvhd->data + 12);
12255 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 28);
12256 qtdemux->duration = QT_UINT64 ((guint8 *) mvhd->data + 32);
12257 } else if (version == 0) {
12258 creation_time = QT_UINT32 ((guint8 *) mvhd->data + 12);
12259 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 20);
12260 qtdemux->duration = QT_UINT32 ((guint8 *) mvhd->data + 24);
12262 GST_WARNING_OBJECT (qtdemux, "Unhandled mvhd version %d", version);
12266 /* Moving qt creation time (secs since 1904) to unix time */
12267 if (creation_time != 0) {
12268 /* Try to use epoch first as it should be faster and more commonly found */
12269 if (creation_time >= QTDEMUX_SECONDS_FROM_1904_TO_1970) {
12272 creation_time -= QTDEMUX_SECONDS_FROM_1904_TO_1970;
12273 /* some data cleansing sanity */
12274 g_get_current_time (&now);
12275 if (now.tv_sec + 24 * 3600 < creation_time) {
12276 GST_DEBUG_OBJECT (qtdemux, "discarding bogus future creation time");
12278 datetime = gst_date_time_new_from_unix_epoch_utc (creation_time);
12281 GDateTime *base_dt = g_date_time_new_utc (1904, 1, 1, 0, 0, 0);
12282 GDateTime *dt, *dt_local;
12284 dt = g_date_time_add_seconds (base_dt, creation_time);
12285 dt_local = g_date_time_to_local (dt);
12286 datetime = gst_date_time_new_from_g_date_time (dt_local);
12288 g_date_time_unref (base_dt);
12289 g_date_time_unref (dt);
12293 /* Use KEEP as explicit tags should have a higher priority than mvhd tag */
12294 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_KEEP, GST_TAG_DATE_TIME,
12296 gst_date_time_unref (datetime);
12299 GST_INFO_OBJECT (qtdemux, "timescale: %u", qtdemux->timescale);
12300 GST_INFO_OBJECT (qtdemux, "duration: %" G_GUINT64_FORMAT, qtdemux->duration);
12302 /* check for fragmented file and get some (default) data */
12303 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
12306 GstByteReader mehd_data;
12308 /* let track parsing or anyone know weird stuff might happen ... */
12309 qtdemux->fragmented = TRUE;
12311 /* compensate for total duration */
12312 mehd = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_mehd, &mehd_data);
12314 qtdemux_parse_mehd (qtdemux, &mehd_data);
12317 /* set duration in the segment info */
12318 gst_qtdemux_get_duration (qtdemux, &duration);
12320 qtdemux->segment.duration = duration;
12321 /* also do not exceed duration; stop is set that way post seek anyway,
12322 * and segment activation falls back to duration,
12323 * whereas loop only checks stop, so let's align this here as well */
12324 qtdemux->segment.stop = duration;
12327 /* parse all traks */
12328 trak = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_trak);
12330 qtdemux_parse_trak (qtdemux, trak);
12331 /* iterate all siblings */
12332 trak = qtdemux_tree_get_sibling_by_type (trak, FOURCC_trak);
12335 if (!qtdemux->tag_list) {
12336 GST_DEBUG_OBJECT (qtdemux, "new tag list");
12337 qtdemux->tag_list = gst_tag_list_new_empty ();
12338 gst_tag_list_set_scope (qtdemux->tag_list, GST_TAG_SCOPE_GLOBAL);
12340 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
12344 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_udta);
12346 qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
12348 GST_LOG_OBJECT (qtdemux, "No udta node found.");
12351 /* maybe also some tags in meta box */
12352 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_meta);
12354 GST_DEBUG_OBJECT (qtdemux, "Parsing meta box for tags.");
12355 qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
12357 GST_LOG_OBJECT (qtdemux, "No meta node found.");
12360 /* parse any protection system info */
12361 pssh = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_pssh);
12363 GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
12364 qtdemux_parse_pssh (qtdemux, pssh);
12365 pssh = qtdemux_tree_get_sibling_by_type (pssh, FOURCC_pssh);
12368 qtdemux->tag_list = qtdemux_add_container_format (qtdemux, qtdemux->tag_list);
12373 /* taken from ffmpeg */
12375 read_descr_size (guint8 * ptr, guint8 * end, guint8 ** end_out)
12387 len = (len << 7) | (c & 0x7f);
12395 /* this can change the codec originally present in @list */
12397 gst_qtdemux_handle_esds (GstQTDemux * qtdemux, QtDemuxStream * stream,
12398 GNode * esds, GstTagList * list)
12400 int len = QT_UINT32 (esds->data);
12401 guint8 *ptr = esds->data;
12402 guint8 *end = ptr + len;
12404 guint8 *data_ptr = NULL;
12406 guint8 object_type_id = 0;
12407 const char *codec_name = NULL;
12408 GstCaps *caps = NULL;
12410 GST_MEMDUMP_OBJECT (qtdemux, "esds", ptr, len);
12412 GST_DEBUG_OBJECT (qtdemux, "version/flags = %08x", QT_UINT32 (ptr));
12414 while (ptr + 1 < end) {
12415 tag = QT_UINT8 (ptr);
12416 GST_DEBUG_OBJECT (qtdemux, "tag = %02x", tag);
12418 len = read_descr_size (ptr, end, &ptr);
12419 GST_DEBUG_OBJECT (qtdemux, "len = %d", len);
12421 /* Check the stated amount of data is available for reading */
12422 if (len < 0 || ptr + len > end)
12426 case ES_DESCRIPTOR_TAG:
12427 GST_DEBUG_OBJECT (qtdemux, "ID %04x", QT_UINT16 (ptr));
12428 GST_DEBUG_OBJECT (qtdemux, "priority %04x", QT_UINT8 (ptr + 2));
12431 case DECODER_CONFIG_DESC_TAG:{
12432 guint max_bitrate, avg_bitrate;
12434 object_type_id = QT_UINT8 (ptr);
12435 max_bitrate = QT_UINT32 (ptr + 5);
12436 avg_bitrate = QT_UINT32 (ptr + 9);
12437 GST_DEBUG_OBJECT (qtdemux, "object_type_id %02x", object_type_id);
12438 GST_DEBUG_OBJECT (qtdemux, "stream_type %02x", QT_UINT8 (ptr + 1));
12439 GST_DEBUG_OBJECT (qtdemux, "buffer_size_db %02x", QT_UINT24 (ptr + 2));
12440 GST_DEBUG_OBJECT (qtdemux, "max bitrate %u", max_bitrate);
12441 GST_DEBUG_OBJECT (qtdemux, "avg bitrate %u", avg_bitrate);
12442 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
12443 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
12444 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
12446 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
12447 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
12448 avg_bitrate, NULL);
12453 case DECODER_SPECIFIC_INFO_TAG:
12454 GST_MEMDUMP_OBJECT (qtdemux, "data", ptr, len);
12455 if (object_type_id == 0xe0 && len == 0x40) {
12461 GST_DEBUG_OBJECT (qtdemux,
12462 "Have VOBSUB palette. Creating palette event");
12463 /* move to decConfigDescr data and read palette */
12465 for (i = 0; i < 16; i++) {
12466 clut[i] = QT_UINT32 (data);
12470 s = gst_structure_new ("application/x-gst-dvd", "event",
12471 G_TYPE_STRING, "dvd-spu-clut-change",
12472 "clut00", G_TYPE_INT, clut[0], "clut01", G_TYPE_INT, clut[1],
12473 "clut02", G_TYPE_INT, clut[2], "clut03", G_TYPE_INT, clut[3],
12474 "clut04", G_TYPE_INT, clut[4], "clut05", G_TYPE_INT, clut[5],
12475 "clut06", G_TYPE_INT, clut[6], "clut07", G_TYPE_INT, clut[7],
12476 "clut08", G_TYPE_INT, clut[8], "clut09", G_TYPE_INT, clut[9],
12477 "clut10", G_TYPE_INT, clut[10], "clut11", G_TYPE_INT, clut[11],
12478 "clut12", G_TYPE_INT, clut[12], "clut13", G_TYPE_INT, clut[13],
12479 "clut14", G_TYPE_INT, clut[14], "clut15", G_TYPE_INT, clut[15],
12482 /* store event and trigger custom processing */
12483 stream->pending_event =
12484 gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s);
12486 /* Generic codec_data handler puts it on the caps */
12493 case SL_CONFIG_DESC_TAG:
12494 GST_DEBUG_OBJECT (qtdemux, "data %02x", QT_UINT8 (ptr));
12498 GST_DEBUG_OBJECT (qtdemux, "Unknown/unhandled descriptor tag %02x",
12500 GST_MEMDUMP_OBJECT (qtdemux, "descriptor data", ptr, len);
12506 /* object_type_id in the esds atom in mp4a and mp4v tells us which codec is
12507 * in use, and should also be used to override some other parameters for some
12509 switch (object_type_id) {
12510 case 0x20: /* MPEG-4 */
12511 /* 4 bytes for the visual_object_sequence_start_code and 1 byte for the
12512 * profile_and_level_indication */
12513 if (data_ptr != NULL && data_len >= 5 &&
12514 GST_READ_UINT32_BE (data_ptr) == 0x000001b0) {
12515 gst_codec_utils_mpeg4video_caps_set_level_and_profile (stream->caps,
12516 data_ptr + 4, data_len - 4);
12518 break; /* Nothing special needed here */
12519 case 0x21: /* H.264 */
12520 codec_name = "H.264 / AVC";
12521 caps = gst_caps_new_simple ("video/x-h264",
12522 "stream-format", G_TYPE_STRING, "avc",
12523 "alignment", G_TYPE_STRING, "au", NULL);
12525 case 0x40: /* AAC (any) */
12526 case 0x66: /* AAC Main */
12527 case 0x67: /* AAC LC */
12528 case 0x68: /* AAC SSR */
12529 /* Override channels and rate based on the codec_data, as it's often
12531 /* Only do so for basic setup without HE-AAC extension */
12532 if (data_ptr && data_len == 2) {
12533 guint channels, rate;
12535 channels = gst_codec_utils_aac_get_channels (data_ptr, data_len);
12537 stream->n_channels = channels;
12539 rate = gst_codec_utils_aac_get_sample_rate (data_ptr, data_len);
12541 stream->rate = rate;
12544 /* Set level and profile if possible */
12545 if (data_ptr != NULL && data_len >= 2) {
12546 gst_codec_utils_aac_caps_set_level_and_profile (stream->caps,
12547 data_ptr, data_len);
12550 case 0x60: /* MPEG-2, various profiles */
12556 codec_name = "MPEG-2 video";
12557 caps = gst_caps_new_simple ("video/mpeg",
12558 "mpegversion", G_TYPE_INT, 2,
12559 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
12561 case 0x69: /* MPEG-2 BC audio */
12562 case 0x6B: /* MPEG-1 audio */
12563 caps = gst_caps_new_simple ("audio/mpeg",
12564 "mpegversion", G_TYPE_INT, 1, "parsed", G_TYPE_BOOLEAN, TRUE, NULL);
12565 codec_name = "MPEG-1 audio";
12567 case 0x6A: /* MPEG-1 */
12568 codec_name = "MPEG-1 video";
12569 caps = gst_caps_new_simple ("video/mpeg",
12570 "mpegversion", G_TYPE_INT, 1,
12571 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
12573 case 0x6C: /* MJPEG */
12575 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
12577 codec_name = "Motion-JPEG";
12579 case 0x6D: /* PNG */
12581 gst_caps_new_simple ("image/png", "parsed", G_TYPE_BOOLEAN, TRUE,
12583 codec_name = "PNG still images";
12585 case 0x6E: /* JPEG2000 */
12586 codec_name = "JPEG-2000";
12587 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
12589 case 0xA4: /* Dirac */
12590 codec_name = "Dirac";
12591 caps = gst_caps_new_empty_simple ("video/x-dirac");
12593 case 0xA5: /* AC3 */
12594 codec_name = "AC-3 audio";
12595 caps = gst_caps_new_simple ("audio/x-ac3",
12596 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
12598 case 0xA9: /* AC3 */
12599 codec_name = "DTS audio";
12600 caps = gst_caps_new_simple ("audio/x-dts",
12601 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
12603 case 0xE1: /* QCELP */
12604 /* QCELP, the codec_data is a riff tag (little endian) with
12605 * 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). */
12606 caps = gst_caps_new_empty_simple ("audio/qcelp");
12607 codec_name = "QCELP";
12613 /* If we have a replacement caps, then change our caps for this stream */
12615 gst_caps_unref (stream->caps);
12616 stream->caps = caps;
12619 if (codec_name && list)
12620 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
12621 GST_TAG_AUDIO_CODEC, codec_name, NULL);
12623 /* Add the codec_data attribute to caps, if we have it */
12627 buffer = gst_buffer_new_and_alloc (data_len);
12628 gst_buffer_fill (buffer, 0, data_ptr, data_len);
12630 GST_DEBUG_OBJECT (qtdemux, "setting codec_data from esds");
12631 GST_MEMDUMP_OBJECT (qtdemux, "codec_data from esds", data_ptr, data_len);
12633 gst_caps_set_simple (stream->caps, "codec_data", GST_TYPE_BUFFER,
12635 gst_buffer_unref (buffer);
12640 #define _codec(name) \
12642 if (codec_name) { \
12643 *codec_name = g_strdup (name); \
12648 qtdemux_video_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
12649 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
12651 GstCaps *caps = NULL;
12652 GstVideoFormat format = GST_VIDEO_FORMAT_UNKNOWN;
12655 case GST_MAKE_FOURCC ('p', 'n', 'g', ' '):
12656 _codec ("PNG still images");
12657 caps = gst_caps_new_empty_simple ("image/png");
12660 _codec ("JPEG still images");
12662 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
12665 case GST_MAKE_FOURCC ('m', 'j', 'p', 'a'):
12666 case GST_MAKE_FOURCC ('A', 'V', 'D', 'J'):
12667 case GST_MAKE_FOURCC ('M', 'J', 'P', 'G'):
12668 case GST_MAKE_FOURCC ('d', 'm', 'b', '1'):
12669 _codec ("Motion-JPEG");
12671 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
12674 case GST_MAKE_FOURCC ('m', 'j', 'p', 'b'):
12675 _codec ("Motion-JPEG format B");
12676 caps = gst_caps_new_empty_simple ("video/x-mjpeg-b");
12679 _codec ("JPEG-2000");
12680 /* override to what it should be according to spec, avoid palette_data */
12681 stream->bits_per_sample = 24;
12682 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
12685 _codec ("Sorensen video v.3");
12686 caps = gst_caps_new_simple ("video/x-svq",
12687 "svqversion", G_TYPE_INT, 3, NULL);
12689 case GST_MAKE_FOURCC ('s', 'v', 'q', 'i'):
12690 case GST_MAKE_FOURCC ('S', 'V', 'Q', '1'):
12691 _codec ("Sorensen video v.1");
12692 caps = gst_caps_new_simple ("video/x-svq",
12693 "svqversion", G_TYPE_INT, 1, NULL);
12695 case GST_MAKE_FOURCC ('W', 'R', 'A', 'W'):
12696 caps = gst_caps_new_empty_simple ("video/x-raw");
12697 gst_caps_set_simple (caps, "format", G_TYPE_STRING, "RGB8P", NULL);
12698 _codec ("Windows Raw RGB");
12704 bps = QT_UINT16 (stsd_data + 98);
12707 format = GST_VIDEO_FORMAT_RGB15;
12710 format = GST_VIDEO_FORMAT_RGB16;
12713 format = GST_VIDEO_FORMAT_RGB;
12716 format = GST_VIDEO_FORMAT_ARGB;
12724 case GST_MAKE_FOURCC ('y', 'v', '1', '2'):
12725 format = GST_VIDEO_FORMAT_I420;
12727 case GST_MAKE_FOURCC ('y', 'u', 'v', '2'):
12728 case GST_MAKE_FOURCC ('Y', 'u', 'v', '2'):
12729 format = GST_VIDEO_FORMAT_I420;
12732 case GST_MAKE_FOURCC ('2', 'V', 'u', 'y'):
12733 format = GST_VIDEO_FORMAT_UYVY;
12735 case GST_MAKE_FOURCC ('v', '3', '0', '8'):
12736 format = GST_VIDEO_FORMAT_v308;
12738 case GST_MAKE_FOURCC ('v', '2', '1', '6'):
12739 format = GST_VIDEO_FORMAT_v216;
12742 format = GST_VIDEO_FORMAT_v210;
12744 case GST_MAKE_FOURCC ('r', '2', '1', '0'):
12745 format = GST_VIDEO_FORMAT_r210;
12747 /* Packed YUV 4:4:4 10 bit in 32 bits, complex
12748 case GST_MAKE_FOURCC ('v', '4', '1', '0'):
12749 format = GST_VIDEO_FORMAT_v410;
12752 /* Packed YUV 4:4:4:4 8 bit in 32 bits
12753 * but different order than AYUV
12754 case GST_MAKE_FOURCC ('v', '4', '0', '8'):
12755 format = GST_VIDEO_FORMAT_v408;
12758 case GST_MAKE_FOURCC ('m', 'p', 'e', 'g'):
12759 case GST_MAKE_FOURCC ('m', 'p', 'g', '1'):
12760 _codec ("MPEG-1 video");
12761 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
12762 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
12764 case GST_MAKE_FOURCC ('h', 'd', 'v', '1'): /* HDV 720p30 */
12765 case GST_MAKE_FOURCC ('h', 'd', 'v', '2'): /* HDV 1080i60 */
12766 case GST_MAKE_FOURCC ('h', 'd', 'v', '3'): /* HDV 1080i50 */
12767 case GST_MAKE_FOURCC ('h', 'd', 'v', '4'): /* HDV 720p24 */
12768 case GST_MAKE_FOURCC ('h', 'd', 'v', '5'): /* HDV 720p25 */
12769 case GST_MAKE_FOURCC ('h', 'd', 'v', '6'): /* HDV 1080p24 */
12770 case GST_MAKE_FOURCC ('h', 'd', 'v', '7'): /* HDV 1080p25 */
12771 case GST_MAKE_FOURCC ('h', 'd', 'v', '8'): /* HDV 1080p30 */
12772 case GST_MAKE_FOURCC ('h', 'd', 'v', '9'): /* HDV 720p60 */
12773 case GST_MAKE_FOURCC ('h', 'd', 'v', 'a'): /* HDV 720p50 */
12774 case GST_MAKE_FOURCC ('m', 'x', '5', 'n'): /* MPEG2 IMX NTSC 525/60 50mb/s produced by FCP */
12775 case GST_MAKE_FOURCC ('m', 'x', '5', 'p'): /* MPEG2 IMX PAL 625/60 50mb/s produced by FCP */
12776 case GST_MAKE_FOURCC ('m', 'x', '4', 'n'): /* MPEG2 IMX NTSC 525/60 40mb/s produced by FCP */
12777 case GST_MAKE_FOURCC ('m', 'x', '4', 'p'): /* MPEG2 IMX PAL 625/60 40mb/s produced by FCP */
12778 case GST_MAKE_FOURCC ('m', 'x', '3', 'n'): /* MPEG2 IMX NTSC 525/60 30mb/s produced by FCP */
12779 case GST_MAKE_FOURCC ('m', 'x', '3', 'p'): /* MPEG2 IMX PAL 625/50 30mb/s produced by FCP */
12780 case GST_MAKE_FOURCC ('x', 'd', 'v', '1'): /* XDCAM HD 720p30 35Mb/s */
12781 case GST_MAKE_FOURCC ('x', 'd', 'v', '2'): /* XDCAM HD 1080i60 35Mb/s */
12782 case GST_MAKE_FOURCC ('x', 'd', 'v', '3'): /* XDCAM HD 1080i50 35Mb/s */
12783 case GST_MAKE_FOURCC ('x', 'd', 'v', '4'): /* XDCAM HD 720p24 35Mb/s */
12784 case GST_MAKE_FOURCC ('x', 'd', 'v', '5'): /* XDCAM HD 720p25 35Mb/s */
12785 case GST_MAKE_FOURCC ('x', 'd', 'v', '6'): /* XDCAM HD 1080p24 35Mb/s */
12786 case GST_MAKE_FOURCC ('x', 'd', 'v', '7'): /* XDCAM HD 1080p25 35Mb/s */
12787 case GST_MAKE_FOURCC ('x', 'd', 'v', '8'): /* XDCAM HD 1080p30 35Mb/s */
12788 case GST_MAKE_FOURCC ('x', 'd', 'v', '9'): /* XDCAM HD 720p60 35Mb/s */
12789 case GST_MAKE_FOURCC ('x', 'd', 'v', 'a'): /* XDCAM HD 720p50 35Mb/s */
12790 case GST_MAKE_FOURCC ('x', 'd', 'v', 'b'): /* XDCAM EX 1080i60 50Mb/s CBR */
12791 case GST_MAKE_FOURCC ('x', 'd', 'v', 'c'): /* XDCAM EX 1080i50 50Mb/s CBR */
12792 case GST_MAKE_FOURCC ('x', 'd', 'v', 'd'): /* XDCAM HD 1080p24 50Mb/s CBR */
12793 case GST_MAKE_FOURCC ('x', 'd', 'v', 'e'): /* XDCAM HD 1080p25 50Mb/s CBR */
12794 case GST_MAKE_FOURCC ('x', 'd', 'v', 'f'): /* XDCAM HD 1080p30 50Mb/s CBR */
12795 case GST_MAKE_FOURCC ('x', 'd', '5', '1'): /* XDCAM HD422 720p30 50Mb/s CBR */
12796 case GST_MAKE_FOURCC ('x', 'd', '5', '4'): /* XDCAM HD422 720p24 50Mb/s CBR */
12797 case GST_MAKE_FOURCC ('x', 'd', '5', '5'): /* XDCAM HD422 720p25 50Mb/s CBR */
12798 case GST_MAKE_FOURCC ('x', 'd', '5', '9'): /* XDCAM HD422 720p60 50Mb/s CBR */
12799 case GST_MAKE_FOURCC ('x', 'd', '5', 'a'): /* XDCAM HD422 720p50 50Mb/s CBR */
12800 case GST_MAKE_FOURCC ('x', 'd', '5', 'b'): /* XDCAM HD422 1080i50 50Mb/s CBR */
12801 case GST_MAKE_FOURCC ('x', 'd', '5', 'c'): /* XDCAM HD422 1080i50 50Mb/s CBR */
12802 case GST_MAKE_FOURCC ('x', 'd', '5', 'd'): /* XDCAM HD422 1080p24 50Mb/s CBR */
12803 case GST_MAKE_FOURCC ('x', 'd', '5', 'e'): /* XDCAM HD422 1080p25 50Mb/s CBR */
12804 case GST_MAKE_FOURCC ('x', 'd', '5', 'f'): /* XDCAM HD422 1080p30 50Mb/s CBR */
12805 case GST_MAKE_FOURCC ('x', 'd', 'h', 'd'): /* XDCAM HD 540p */
12806 case GST_MAKE_FOURCC ('x', 'd', 'h', '2'): /* XDCAM HD422 540p */
12807 case GST_MAKE_FOURCC ('A', 'V', 'm', 'p'): /* AVID IMX PAL */
12808 case GST_MAKE_FOURCC ('m', 'p', 'g', '2'): /* AVID IMX PAL */
12809 case GST_MAKE_FOURCC ('m', 'p', '2', 'v'): /* AVID IMX PAL */
12810 _codec ("MPEG-2 video");
12811 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 2,
12812 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
12814 case GST_MAKE_FOURCC ('g', 'i', 'f', ' '):
12815 _codec ("GIF still images");
12816 caps = gst_caps_new_empty_simple ("image/gif");
12819 case GST_MAKE_FOURCC ('H', '2', '6', '3'):
12821 case GST_MAKE_FOURCC ('U', '2', '6', '3'):
12823 /* ffmpeg uses the height/width props, don't know why */
12824 caps = gst_caps_new_simple ("video/x-h263",
12825 "variant", G_TYPE_STRING, "itu", NULL);
12829 _codec ("MPEG-4 video");
12830 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
12831 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
12833 case GST_MAKE_FOURCC ('3', 'i', 'v', 'd'):
12834 case GST_MAKE_FOURCC ('3', 'I', 'V', 'D'):
12835 _codec ("Microsoft MPEG-4 4.3"); /* FIXME? */
12836 caps = gst_caps_new_simple ("video/x-msmpeg",
12837 "msmpegversion", G_TYPE_INT, 43, NULL);
12839 case GST_MAKE_FOURCC ('D', 'I', 'V', '3'):
12841 caps = gst_caps_new_simple ("video/x-divx",
12842 "divxversion", G_TYPE_INT, 3, NULL);
12844 case GST_MAKE_FOURCC ('D', 'I', 'V', 'X'):
12845 case GST_MAKE_FOURCC ('d', 'i', 'v', 'x'):
12847 caps = gst_caps_new_simple ("video/x-divx",
12848 "divxversion", G_TYPE_INT, 4, NULL);
12850 case GST_MAKE_FOURCC ('D', 'X', '5', '0'):
12852 caps = gst_caps_new_simple ("video/x-divx",
12853 "divxversion", G_TYPE_INT, 5, NULL);
12856 case GST_MAKE_FOURCC ('F', 'F', 'V', '1'):
12858 caps = gst_caps_new_simple ("video/x-ffv",
12859 "ffvversion", G_TYPE_INT, 1, NULL);
12862 case GST_MAKE_FOURCC ('3', 'I', 'V', '1'):
12863 case GST_MAKE_FOURCC ('3', 'I', 'V', '2'):
12864 case GST_MAKE_FOURCC ('X', 'V', 'I', 'D'):
12865 case GST_MAKE_FOURCC ('x', 'v', 'i', 'd'):
12867 case GST_MAKE_FOURCC ('U', 'M', 'P', '4'):
12868 caps = gst_caps_new_simple ("video/mpeg",
12869 "mpegversion", G_TYPE_INT, 4, NULL);
12873 case GST_MAKE_FOURCC ('c', 'v', 'i', 'd'):
12874 _codec ("Cinepak");
12875 caps = gst_caps_new_empty_simple ("video/x-cinepak");
12877 case GST_MAKE_FOURCC ('q', 'd', 'r', 'w'):
12878 _codec ("Apple QuickDraw");
12879 caps = gst_caps_new_empty_simple ("video/x-qdrw");
12881 case GST_MAKE_FOURCC ('r', 'p', 'z', 'a'):
12882 _codec ("Apple video");
12883 caps = gst_caps_new_empty_simple ("video/x-apple-video");
12887 _codec ("H.264 / AVC");
12888 caps = gst_caps_new_simple ("video/x-h264",
12889 "stream-format", G_TYPE_STRING, "avc",
12890 "alignment", G_TYPE_STRING, "au", NULL);
12893 _codec ("H.264 / AVC");
12894 caps = gst_caps_new_simple ("video/x-h264",
12895 "stream-format", G_TYPE_STRING, "avc3",
12896 "alignment", G_TYPE_STRING, "au", NULL);
12900 _codec ("H.265 / HEVC");
12901 caps = gst_caps_new_simple ("video/x-h265",
12902 "stream-format", G_TYPE_STRING, "hvc1",
12903 "alignment", G_TYPE_STRING, "au", NULL);
12906 _codec ("H.265 / HEVC");
12907 caps = gst_caps_new_simple ("video/x-h265",
12908 "stream-format", G_TYPE_STRING, "hev1",
12909 "alignment", G_TYPE_STRING, "au", NULL);
12912 _codec ("Run-length encoding");
12913 caps = gst_caps_new_simple ("video/x-rle",
12914 "layout", G_TYPE_STRING, "quicktime", NULL);
12917 _codec ("Run-length encoding");
12918 caps = gst_caps_new_simple ("video/x-rle",
12919 "layout", G_TYPE_STRING, "microsoft", NULL);
12921 case GST_MAKE_FOURCC ('I', 'V', '3', '2'):
12922 case GST_MAKE_FOURCC ('i', 'v', '3', '2'):
12923 _codec ("Indeo Video 3");
12924 caps = gst_caps_new_simple ("video/x-indeo",
12925 "indeoversion", G_TYPE_INT, 3, NULL);
12927 case GST_MAKE_FOURCC ('I', 'V', '4', '1'):
12928 case GST_MAKE_FOURCC ('i', 'v', '4', '1'):
12929 _codec ("Intel Video 4");
12930 caps = gst_caps_new_simple ("video/x-indeo",
12931 "indeoversion", G_TYPE_INT, 4, NULL);
12935 case GST_MAKE_FOURCC ('d', 'v', 's', 'd'):
12936 case GST_MAKE_FOURCC ('D', 'V', 'S', 'D'):
12937 case GST_MAKE_FOURCC ('d', 'v', 'c', 's'):
12938 case GST_MAKE_FOURCC ('D', 'V', 'C', 'S'):
12939 case GST_MAKE_FOURCC ('d', 'v', '2', '5'):
12940 case GST_MAKE_FOURCC ('d', 'v', 'p', 'p'):
12941 _codec ("DV Video");
12942 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 25,
12943 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
12945 case FOURCC_dv5n: /* DVCPRO50 NTSC */
12946 case FOURCC_dv5p: /* DVCPRO50 PAL */
12947 _codec ("DVCPro50 Video");
12948 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 50,
12949 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
12951 case GST_MAKE_FOURCC ('d', 'v', 'h', '5'): /* DVCPRO HD 50i produced by FCP */
12952 case GST_MAKE_FOURCC ('d', 'v', 'h', '6'): /* DVCPRO HD 60i produced by FCP */
12953 _codec ("DVCProHD Video");
12954 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 100,
12955 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
12957 case GST_MAKE_FOURCC ('s', 'm', 'c', ' '):
12958 _codec ("Apple Graphics (SMC)");
12959 caps = gst_caps_new_empty_simple ("video/x-smc");
12961 case GST_MAKE_FOURCC ('V', 'P', '3', '1'):
12963 caps = gst_caps_new_empty_simple ("video/x-vp3");
12965 case GST_MAKE_FOURCC ('V', 'P', '6', 'F'):
12966 _codec ("VP6 Flash");
12967 caps = gst_caps_new_empty_simple ("video/x-vp6-flash");
12971 caps = gst_caps_new_empty_simple ("video/x-theora");
12972 /* theora uses one byte of padding in the data stream because it does not
12973 * allow 0 sized packets while theora does */
12974 stream->padding = 1;
12978 caps = gst_caps_new_empty_simple ("video/x-dirac");
12980 case GST_MAKE_FOURCC ('t', 'i', 'f', 'f'):
12981 _codec ("TIFF still images");
12982 caps = gst_caps_new_empty_simple ("image/tiff");
12984 case GST_MAKE_FOURCC ('i', 'c', 'o', 'd'):
12985 _codec ("Apple Intermediate Codec");
12986 caps = gst_caps_from_string ("video/x-apple-intermediate-codec");
12988 case GST_MAKE_FOURCC ('A', 'V', 'd', 'n'):
12989 _codec ("AVID DNxHD");
12990 caps = gst_caps_from_string ("video/x-dnxhd");
12993 _codec ("On2 VP8");
12994 caps = gst_caps_from_string ("video/x-vp8");
12997 _codec ("Apple ProRes LT");
12999 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "lt",
13003 _codec ("Apple ProRes HQ");
13005 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "hq",
13009 _codec ("Apple ProRes");
13011 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
13015 _codec ("Apple ProRes Proxy");
13017 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
13021 _codec ("Apple ProRes 4444");
13023 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
13029 caps = gst_caps_new_simple ("video/x-wmv",
13030 "wmvversion", G_TYPE_INT, 3, "format", G_TYPE_STRING, "WVC1", NULL);
13032 case GST_MAKE_FOURCC ('k', 'p', 'c', 'd'):
13035 char *s, fourstr[5];
13037 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
13038 s = g_strdup_printf ("video/x-gst-fourcc-%s", g_strstrip (fourstr));
13039 caps = gst_caps_new_empty_simple (s);
13045 if (format != GST_VIDEO_FORMAT_UNKNOWN) {
13048 gst_video_info_init (&info);
13049 gst_video_info_set_format (&info, format, stream->width, stream->height);
13051 caps = gst_video_info_to_caps (&info);
13052 *codec_name = gst_pb_utils_get_codec_description (caps);
13054 /* enable clipping for raw video streams */
13055 stream->need_clip = TRUE;
13062 qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
13063 guint32 fourcc, const guint8 * data, int len, gchar ** codec_name)
13066 const GstStructure *s;
13069 GstAudioFormat format = 0;
13072 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
13074 depth = stream->bytes_per_packet * 8;
13077 case GST_MAKE_FOURCC ('N', 'O', 'N', 'E'):
13079 /* 8-bit audio is unsigned */
13081 format = GST_AUDIO_FORMAT_U8;
13082 /* otherwise it's signed and big-endian just like 'twos' */
13084 endian = G_BIG_ENDIAN;
13091 endian = G_LITTLE_ENDIAN;
13094 format = gst_audio_format_build_integer (TRUE, endian, depth, depth);
13096 str = g_strdup_printf ("Raw %d-bit PCM audio", depth);
13100 caps = gst_caps_new_simple ("audio/x-raw",
13101 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
13102 "layout", G_TYPE_STRING, "interleaved", NULL);
13105 case GST_MAKE_FOURCC ('f', 'l', '6', '4'):
13106 _codec ("Raw 64-bit floating-point audio");
13107 caps = gst_caps_new_simple ("audio/x-raw",
13108 "format", G_TYPE_STRING, "F64BE",
13109 "layout", G_TYPE_STRING, "interleaved", NULL);
13111 case GST_MAKE_FOURCC ('f', 'l', '3', '2'):
13112 _codec ("Raw 32-bit floating-point audio");
13113 caps = gst_caps_new_simple ("audio/x-raw",
13114 "format", G_TYPE_STRING, "F32BE",
13115 "layout", G_TYPE_STRING, "interleaved", NULL);
13118 _codec ("Raw 24-bit PCM audio");
13119 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
13121 caps = gst_caps_new_simple ("audio/x-raw",
13122 "format", G_TYPE_STRING, "S24BE",
13123 "layout", G_TYPE_STRING, "interleaved", NULL);
13125 case GST_MAKE_FOURCC ('i', 'n', '3', '2'):
13126 _codec ("Raw 32-bit PCM audio");
13127 caps = gst_caps_new_simple ("audio/x-raw",
13128 "format", G_TYPE_STRING, "S32BE",
13129 "layout", G_TYPE_STRING, "interleaved", NULL);
13132 _codec ("Mu-law audio");
13133 caps = gst_caps_new_empty_simple ("audio/x-mulaw");
13136 _codec ("A-law audio");
13137 caps = gst_caps_new_empty_simple ("audio/x-alaw");
13141 _codec ("Microsoft ADPCM");
13142 /* Microsoft ADPCM-ACM code 2 */
13143 caps = gst_caps_new_simple ("audio/x-adpcm",
13144 "layout", G_TYPE_STRING, "microsoft", NULL);
13148 _codec ("DVI/IMA ADPCM");
13149 caps = gst_caps_new_simple ("audio/x-adpcm",
13150 "layout", G_TYPE_STRING, "dvi", NULL);
13154 _codec ("DVI/Intel IMA ADPCM");
13155 /* FIXME DVI/Intel IMA ADPCM/ACM code 17 */
13156 caps = gst_caps_new_simple ("audio/x-adpcm",
13157 "layout", G_TYPE_STRING, "quicktime", NULL);
13161 /* MPEG layer 3, CBR only (pre QT4.1) */
13163 _codec ("MPEG-1 layer 3");
13164 /* MPEG layer 3, CBR & VBR (QT4.1 and later) */
13165 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 3,
13166 "mpegversion", G_TYPE_INT, 1, NULL);
13169 case GST_MAKE_FOURCC ('e', 'c', '-', '3'):
13170 _codec ("EAC-3 audio");
13171 caps = gst_caps_new_simple ("audio/x-eac3",
13172 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
13173 stream->sampled = TRUE;
13175 case GST_MAKE_FOURCC ('s', 'a', 'c', '3'): // Nero Recode
13177 _codec ("AC-3 audio");
13178 caps = gst_caps_new_simple ("audio/x-ac3",
13179 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
13180 stream->sampled = TRUE;
13182 case GST_MAKE_FOURCC ('d', 't', 's', 'c'):
13183 case GST_MAKE_FOURCC ('D', 'T', 'S', ' '):
13184 _codec ("DTS audio");
13185 caps = gst_caps_new_simple ("audio/x-dts",
13186 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
13187 stream->sampled = TRUE;
13189 case GST_MAKE_FOURCC ('d', 't', 's', 'h'): // DTS-HD
13190 case GST_MAKE_FOURCC ('d', 't', 's', 'l'): // DTS-HD Lossless
13191 _codec ("DTS-HD audio");
13192 caps = gst_caps_new_simple ("audio/x-dts",
13193 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
13194 stream->sampled = TRUE;
13198 caps = gst_caps_new_simple ("audio/x-mace",
13199 "maceversion", G_TYPE_INT, 3, NULL);
13203 caps = gst_caps_new_simple ("audio/x-mace",
13204 "maceversion", G_TYPE_INT, 6, NULL);
13206 case GST_MAKE_FOURCC ('O', 'g', 'g', 'V'):
13208 caps = gst_caps_new_empty_simple ("application/ogg");
13210 case GST_MAKE_FOURCC ('d', 'v', 'c', 'a'):
13211 _codec ("DV audio");
13212 caps = gst_caps_new_empty_simple ("audio/x-dv");
13215 _codec ("MPEG-4 AAC audio");
13216 caps = gst_caps_new_simple ("audio/mpeg",
13217 "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE,
13218 "stream-format", G_TYPE_STRING, "raw", NULL);
13220 case GST_MAKE_FOURCC ('Q', 'D', 'M', 'C'):
13221 _codec ("QDesign Music");
13222 caps = gst_caps_new_empty_simple ("audio/x-qdm");
13225 _codec ("QDesign Music v.2");
13226 /* FIXME: QDesign music version 2 (no constant) */
13227 if (FALSE && data) {
13228 caps = gst_caps_new_simple ("audio/x-qdm2",
13229 "framesize", G_TYPE_INT, QT_UINT32 (data + 52),
13230 "bitrate", G_TYPE_INT, QT_UINT32 (data + 40),
13231 "blocksize", G_TYPE_INT, QT_UINT32 (data + 44), NULL);
13233 caps = gst_caps_new_empty_simple ("audio/x-qdm2");
13237 _codec ("GSM audio");
13238 caps = gst_caps_new_empty_simple ("audio/x-gsm");
13241 _codec ("AMR audio");
13242 caps = gst_caps_new_empty_simple ("audio/AMR");
13245 _codec ("AMR-WB audio");
13246 caps = gst_caps_new_empty_simple ("audio/AMR-WB");
13249 _codec ("Quicktime IMA ADPCM");
13250 caps = gst_caps_new_simple ("audio/x-adpcm",
13251 "layout", G_TYPE_STRING, "quicktime", NULL);
13254 _codec ("Apple lossless audio");
13255 caps = gst_caps_new_empty_simple ("audio/x-alac");
13257 case GST_MAKE_FOURCC ('Q', 'c', 'l', 'p'):
13258 _codec ("QualComm PureVoice");
13259 caps = gst_caps_from_string ("audio/qcelp");
13264 caps = gst_caps_new_empty_simple ("audio/x-wma");
13268 caps = gst_caps_new_empty_simple ("audio/x-opus");
13270 case GST_MAKE_FOURCC ('l', 'p', 'c', 'm'):
13275 GstAudioFormat format;
13278 FLAG_IS_FLOAT = 0x1,
13279 FLAG_IS_BIG_ENDIAN = 0x2,
13280 FLAG_IS_SIGNED = 0x4,
13281 FLAG_IS_PACKED = 0x8,
13282 FLAG_IS_ALIGNED_HIGH = 0x10,
13283 FLAG_IS_NON_INTERLEAVED = 0x20
13285 _codec ("Raw LPCM audio");
13287 if (data && len >= 56) {
13288 depth = QT_UINT32 (data + 40);
13289 flags = QT_UINT32 (data + 44);
13290 width = QT_UINT32 (data + 48) * 8 / stream->n_channels;
13292 if ((flags & FLAG_IS_FLOAT) == 0) {
13297 format = gst_audio_format_build_integer ((flags & FLAG_IS_SIGNED) ?
13298 TRUE : FALSE, (flags & FLAG_IS_BIG_ENDIAN) ?
13299 G_BIG_ENDIAN : G_LITTLE_ENDIAN, width, depth);
13300 caps = gst_caps_new_simple ("audio/x-raw",
13301 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
13302 "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
13303 "non-interleaved" : "interleaved", NULL);
13308 if (flags & FLAG_IS_BIG_ENDIAN)
13309 format = GST_AUDIO_FORMAT_F64BE;
13311 format = GST_AUDIO_FORMAT_F64LE;
13313 if (flags & FLAG_IS_BIG_ENDIAN)
13314 format = GST_AUDIO_FORMAT_F32BE;
13316 format = GST_AUDIO_FORMAT_F32LE;
13318 caps = gst_caps_new_simple ("audio/x-raw",
13319 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
13320 "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
13321 "non-interleaved" : "interleaved", NULL);
13325 case GST_MAKE_FOURCC ('q', 't', 'v', 'r'):
13329 char *s, fourstr[5];
13331 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
13332 s = g_strdup_printf ("audio/x-gst-fourcc-%s", g_strstrip (fourstr));
13333 caps = gst_caps_new_empty_simple (s);
13340 GstCaps *templ_caps =
13341 gst_static_pad_template_get_caps (&gst_qtdemux_audiosrc_template);
13342 GstCaps *intersection = gst_caps_intersect (caps, templ_caps);
13343 gst_caps_unref (caps);
13344 gst_caps_unref (templ_caps);
13345 caps = intersection;
13348 /* enable clipping for raw audio streams */
13349 s = gst_caps_get_structure (caps, 0);
13350 name = gst_structure_get_name (s);
13351 if (g_str_has_prefix (name, "audio/x-raw")) {
13352 stream->need_clip = TRUE;
13353 stream->max_buffer_size = 4096 * stream->bytes_per_frame;
13354 GST_DEBUG ("setting max buffer size to %d", stream->max_buffer_size);
13360 qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
13361 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
13365 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
13369 _codec ("DVD subtitle");
13370 caps = gst_caps_new_empty_simple ("subpicture/x-dvd");
13371 stream->need_process = TRUE;
13374 _codec ("Quicktime timed text");
13377 _codec ("3GPP timed text");
13379 caps = gst_caps_new_simple ("text/x-raw", "format", G_TYPE_STRING,
13381 /* actual text piece needs to be extracted */
13382 stream->need_process = TRUE;
13385 _codec ("XML subtitles");
13386 caps = gst_caps_new_empty_simple ("application/ttml+xml");
13390 char *s, fourstr[5];
13392 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
13393 s = g_strdup_printf ("text/x-gst-fourcc-%s", g_strstrip (fourstr));
13394 caps = gst_caps_new_empty_simple (s);
13403 qtdemux_generic_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
13404 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
13410 _codec ("MPEG 1 video");
13411 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
13412 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13422 gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux,
13423 const gchar * system_id)
13427 if (!qtdemux->protection_system_ids)
13428 qtdemux->protection_system_ids =
13429 g_ptr_array_new_with_free_func ((GDestroyNotify) g_free);
13430 /* Check whether we already have an entry for this system ID. */
13431 for (i = 0; i < qtdemux->protection_system_ids->len; ++i) {
13432 const gchar *id = g_ptr_array_index (qtdemux->protection_system_ids, i);
13433 if (g_ascii_strcasecmp (system_id, id) == 0) {
13437 GST_DEBUG_OBJECT (qtdemux, "Adding cenc protection system ID %s", system_id);
13438 g_ptr_array_add (qtdemux->protection_system_ids, g_ascii_strdown (system_id,