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 */
317 guint32 segment_seqnum; /* segment event seqnum obtained from seek */
319 /* quicktime segments */
321 QtDemuxSegment *segments;
322 gboolean dummy_segment;
327 GstTagList *pending_tags;
328 gboolean send_global_tags;
330 GstEvent *pending_event;
340 gboolean chunks_are_samples; /* TRUE means treat chunks as samples */
344 GstByteReader co_chunk;
346 guint32 current_chunk;
348 guint32 samples_per_chunk;
349 guint32 stco_sample_index;
351 guint32 sample_size; /* 0 means variable sizes are stored in stsz */
354 guint32 n_samples_per_chunk;
355 guint32 stsc_chunk_index;
356 guint32 stsc_sample_index;
357 guint64 chunk_offset;
360 guint32 stts_samples;
361 guint32 n_sample_times;
362 guint32 stts_sample_index;
364 guint32 stts_duration;
366 gboolean stss_present;
367 guint32 n_sample_syncs;
370 gboolean stps_present;
371 guint32 n_sample_partial_syncs;
373 QtDemuxRandomAccessEntry *ra_entries;
376 const QtDemuxRandomAccessEntry *pending_seek;
379 gboolean ctts_present;
380 guint32 n_composition_times;
382 guint32 ctts_sample_index;
390 gboolean parsed_trex;
391 guint32 def_sample_duration;
392 guint32 def_sample_size;
393 guint32 def_sample_flags;
397 /* stereoscopic video streams */
398 GstVideoMultiviewMode multiview_mode;
399 GstVideoMultiviewFlags multiview_flags;
401 /* protected streams */
403 guint32 protection_scheme_type;
404 guint32 protection_scheme_version;
405 gpointer protection_scheme_info; /* specific to the protection scheme */
406 GQueue protection_scheme_event_queue;
409 /* Contains properties and cryptographic info for a set of samples from a
410 * track protected using Common Encryption (cenc) */
411 struct _QtDemuxCencSampleSetInfo
413 GstStructure *default_properties;
415 /* @crypto_info holds one GstStructure per sample */
416 GPtrArray *crypto_info;
421 QTDEMUX_STATE_INITIAL, /* Initial state (haven't got the header yet) */
422 QTDEMUX_STATE_HEADER, /* Parsing the header */
423 QTDEMUX_STATE_MOVIE, /* Parsing/Playing the media data */
424 QTDEMUX_STATE_BUFFER_MDAT /* Buffering the mdat atom */
427 static GNode *qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc);
428 static GNode *qtdemux_tree_get_child_by_type_full (GNode * node,
429 guint32 fourcc, GstByteReader * parser);
430 static GNode *qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc);
431 static GNode *qtdemux_tree_get_sibling_by_type_full (GNode * node,
432 guint32 fourcc, GstByteReader * parser);
434 static GstFlowReturn qtdemux_add_fragmented_samples (GstQTDemux * qtdemux);
436 static GstStaticPadTemplate gst_qtdemux_sink_template =
437 GST_STATIC_PAD_TEMPLATE ("sink",
440 GST_STATIC_CAPS ("video/quicktime; video/mj2; audio/x-m4a; "
444 static GstStaticPadTemplate gst_qtdemux_videosrc_template =
445 GST_STATIC_PAD_TEMPLATE ("video_%u",
448 GST_STATIC_CAPS_ANY);
450 static GstStaticPadTemplate gst_qtdemux_audiosrc_template =
451 GST_STATIC_PAD_TEMPLATE ("audio_%u",
454 GST_STATIC_CAPS_ANY);
456 static GstStaticPadTemplate gst_qtdemux_subsrc_template =
457 GST_STATIC_PAD_TEMPLATE ("subtitle_%u",
460 GST_STATIC_CAPS_ANY);
462 #define gst_qtdemux_parent_class parent_class
463 G_DEFINE_TYPE (GstQTDemux, gst_qtdemux, GST_TYPE_ELEMENT);
465 static void gst_qtdemux_dispose (GObject * object);
468 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
469 GstClockTime media_time);
471 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
472 QtDemuxStream * str, gint64 media_offset);
475 static void gst_qtdemux_set_index (GstElement * element, GstIndex * index);
476 static GstIndex *gst_qtdemux_get_index (GstElement * element);
478 static GstStateChangeReturn gst_qtdemux_change_state (GstElement * element,
479 GstStateChange transition);
480 static gboolean qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent);
481 static gboolean qtdemux_sink_activate_mode (GstPad * sinkpad,
482 GstObject * parent, GstPadMode mode, gboolean active);
484 static void gst_qtdemux_loop (GstPad * pad);
485 static GstFlowReturn gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent,
487 static gboolean gst_qtdemux_handle_sink_event (GstPad * pad, GstObject * parent,
489 static gboolean gst_qtdemux_setcaps (GstQTDemux * qtdemux, GstCaps * caps);
490 static gboolean gst_qtdemux_configure_stream (GstQTDemux * qtdemux,
491 QtDemuxStream * stream);
492 static GstFlowReturn gst_qtdemux_process_adapter (GstQTDemux * demux,
495 static gboolean qtdemux_parse_moov (GstQTDemux * qtdemux,
496 const guint8 * buffer, guint length);
497 static gboolean qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node,
498 const guint8 * buffer, guint length);
499 static gboolean qtdemux_parse_tree (GstQTDemux * qtdemux);
500 static void qtdemux_parse_udta (GstQTDemux * qtdemux, GstTagList * taglist,
503 static void gst_qtdemux_handle_esds (GstQTDemux * qtdemux,
504 QtDemuxStream * stream, GNode * esds, GstTagList * list);
505 static GstCaps *qtdemux_video_caps (GstQTDemux * qtdemux,
506 QtDemuxStream * stream, guint32 fourcc, const guint8 * stsd_data,
507 gchar ** codec_name);
508 static GstCaps *qtdemux_audio_caps (GstQTDemux * qtdemux,
509 QtDemuxStream * stream, guint32 fourcc, const guint8 * data, int len,
510 gchar ** codec_name);
511 static GstCaps *qtdemux_sub_caps (GstQTDemux * qtdemux,
512 QtDemuxStream * stream, guint32 fourcc, const guint8 * data,
513 gchar ** codec_name);
514 static GstCaps *qtdemux_generic_caps (GstQTDemux * qtdemux,
515 QtDemuxStream * stream, guint32 fourcc, const guint8 * stsd_data,
516 gchar ** codec_name);
518 static gboolean qtdemux_parse_samples (GstQTDemux * qtdemux,
519 QtDemuxStream * stream, guint32 n);
520 static GstFlowReturn qtdemux_expose_streams (GstQTDemux * qtdemux);
521 static void gst_qtdemux_stream_free (GstQTDemux * qtdemux,
522 QtDemuxStream * stream);
523 static void gst_qtdemux_stream_clear (GstQTDemux * qtdemux,
524 QtDemuxStream * stream);
525 static void gst_qtdemux_remove_stream (GstQTDemux * qtdemux, int index);
526 static GstFlowReturn qtdemux_prepare_streams (GstQTDemux * qtdemux);
527 static void qtdemux_do_allocation (GstQTDemux * qtdemux,
528 QtDemuxStream * stream);
530 static gboolean qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux);
531 static void check_update_duration (GstQTDemux * qtdemux, GstClockTime duration);
533 static gchar *qtdemux_uuid_bytes_to_string (gconstpointer uuid_bytes);
535 static GstStructure *qtdemux_get_cenc_sample_properties (GstQTDemux * qtdemux,
536 QtDemuxStream * stream, guint sample_index);
537 static void gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux,
539 static void qtdemux_gst_structure_free (GstStructure * gststructure);
542 gst_qtdemux_class_init (GstQTDemuxClass * klass)
544 GObjectClass *gobject_class;
545 GstElementClass *gstelement_class;
547 gobject_class = (GObjectClass *) klass;
548 gstelement_class = (GstElementClass *) klass;
550 parent_class = g_type_class_peek_parent (klass);
552 gobject_class->dispose = gst_qtdemux_dispose;
554 gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_qtdemux_change_state);
556 gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_qtdemux_set_index);
557 gstelement_class->get_index = GST_DEBUG_FUNCPTR (gst_qtdemux_get_index);
560 gst_tag_register_musicbrainz_tags ();
562 gst_element_class_add_static_pad_template (gstelement_class,
563 &gst_qtdemux_sink_template);
564 gst_element_class_add_static_pad_template (gstelement_class,
565 &gst_qtdemux_videosrc_template);
566 gst_element_class_add_static_pad_template (gstelement_class,
567 &gst_qtdemux_audiosrc_template);
568 gst_element_class_add_static_pad_template (gstelement_class,
569 &gst_qtdemux_subsrc_template);
570 gst_element_class_set_static_metadata (gstelement_class, "QuickTime demuxer",
572 "Demultiplex a QuickTime file into audio and video streams",
573 "David Schleef <ds@schleef.org>, Wim Taymans <wim@fluendo.com>");
575 GST_DEBUG_CATEGORY_INIT (qtdemux_debug, "qtdemux", 0, "qtdemux plugin");
580 gst_qtdemux_init (GstQTDemux * qtdemux)
583 gst_pad_new_from_static_template (&gst_qtdemux_sink_template, "sink");
584 gst_pad_set_activate_function (qtdemux->sinkpad, qtdemux_sink_activate);
585 gst_pad_set_activatemode_function (qtdemux->sinkpad,
586 qtdemux_sink_activate_mode);
587 gst_pad_set_chain_function (qtdemux->sinkpad, gst_qtdemux_chain);
588 gst_pad_set_event_function (qtdemux->sinkpad, gst_qtdemux_handle_sink_event);
589 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), qtdemux->sinkpad);
591 qtdemux->state = QTDEMUX_STATE_INITIAL;
592 qtdemux->pullbased = FALSE;
593 qtdemux->posted_redirect = FALSE;
594 qtdemux->neededbytes = 16;
596 qtdemux->adapter = gst_adapter_new ();
598 qtdemux->first_mdat = -1;
599 qtdemux->got_moov = FALSE;
600 qtdemux->mdatoffset = -1;
601 qtdemux->mdatbuffer = NULL;
602 qtdemux->restoredata_buffer = NULL;
603 qtdemux->restoredata_offset = -1;
604 qtdemux->fragment_start = -1;
605 qtdemux->fragment_start_offset = -1;
606 qtdemux->media_caps = NULL;
607 qtdemux->exposed = FALSE;
608 qtdemux->mss_mode = FALSE;
609 qtdemux->pending_newsegment = NULL;
610 qtdemux->upstream_format_is_time = FALSE;
611 qtdemux->have_group_id = FALSE;
612 qtdemux->group_id = G_MAXUINT;
613 qtdemux->cenc_aux_info_offset = 0;
614 qtdemux->cenc_aux_info_sizes = NULL;
615 qtdemux->cenc_aux_sample_count = 0;
616 qtdemux->protection_system_ids = NULL;
617 g_queue_init (&qtdemux->protection_event_queue);
618 gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
619 qtdemux->flowcombiner = gst_flow_combiner_new ();
621 GST_OBJECT_FLAG_SET (qtdemux, GST_ELEMENT_FLAG_INDEXABLE);
625 gst_qtdemux_dispose (GObject * object)
627 GstQTDemux *qtdemux = GST_QTDEMUX (object);
629 if (qtdemux->adapter) {
630 g_object_unref (G_OBJECT (qtdemux->adapter));
631 qtdemux->adapter = NULL;
633 gst_flow_combiner_free (qtdemux->flowcombiner);
634 g_queue_foreach (&qtdemux->protection_event_queue, (GFunc) gst_event_unref,
636 g_queue_clear (&qtdemux->protection_event_queue);
638 g_free (qtdemux->cenc_aux_info_sizes);
639 qtdemux->cenc_aux_info_sizes = NULL;
641 G_OBJECT_CLASS (parent_class)->dispose (object);
645 gst_qtdemux_post_no_playable_stream_error (GstQTDemux * qtdemux)
647 if (qtdemux->posted_redirect) {
648 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
649 (_("This file contains no playable streams.")),
650 ("no known streams found, a redirect message has been posted"));
652 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
653 (_("This file contains no playable streams.")),
654 ("no known streams found"));
659 _gst_buffer_new_wrapped (gpointer mem, gsize size, GFreeFunc free_func)
661 return gst_buffer_new_wrapped_full (free_func ? 0 : GST_MEMORY_FLAG_READONLY,
662 mem, size, 0, size, mem, free_func);
666 gst_qtdemux_pull_atom (GstQTDemux * qtdemux, guint64 offset, guint64 size,
673 if (G_UNLIKELY (size == 0)) {
675 GstBuffer *tmp = NULL;
677 ret = gst_qtdemux_pull_atom (qtdemux, offset, sizeof (guint32), &tmp);
678 if (ret != GST_FLOW_OK)
681 gst_buffer_map (tmp, &map, GST_MAP_READ);
682 size = QT_UINT32 (map.data);
683 GST_DEBUG_OBJECT (qtdemux, "size 0x%08" G_GINT64_MODIFIER "x", size);
685 gst_buffer_unmap (tmp, &map);
686 gst_buffer_unref (tmp);
689 /* Sanity check: catch bogus sizes (fuzzed/broken files) */
690 if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
691 if (qtdemux->state != QTDEMUX_STATE_MOVIE && qtdemux->got_moov) {
692 /* we're pulling header but already got most interesting bits,
693 * so never mind the rest (e.g. tags) (that much) */
694 GST_WARNING_OBJECT (qtdemux, "atom has bogus size %" G_GUINT64_FORMAT,
698 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
699 (_("This file is invalid and cannot be played.")),
700 ("atom has bogus size %" G_GUINT64_FORMAT, size));
701 return GST_FLOW_ERROR;
705 flow = gst_pad_pull_range (qtdemux->sinkpad, offset, size, buf);
707 if (G_UNLIKELY (flow != GST_FLOW_OK))
710 bsize = gst_buffer_get_size (*buf);
711 /* Catch short reads - we don't want any partial atoms */
712 if (G_UNLIKELY (bsize < size)) {
713 GST_WARNING_OBJECT (qtdemux,
714 "short read: %" G_GSIZE_FORMAT " < %" G_GUINT64_FORMAT, bsize, size);
715 gst_buffer_unref (*buf);
725 gst_qtdemux_src_convert (GstQTDemux * qtdemux, GstPad * pad,
726 GstFormat src_format, gint64 src_value, GstFormat dest_format,
730 QtDemuxStream *stream = gst_pad_get_element_private (pad);
733 if (stream->subtype != FOURCC_vide) {
738 switch (src_format) {
739 case GST_FORMAT_TIME:
740 switch (dest_format) {
741 case GST_FORMAT_BYTES:{
742 index = gst_qtdemux_find_index_linear (qtdemux, stream, src_value);
748 *dest_value = stream->samples[index].offset;
750 GST_DEBUG_OBJECT (qtdemux, "Format Conversion Time->Offset :%"
751 GST_TIME_FORMAT "->%" G_GUINT64_FORMAT,
752 GST_TIME_ARGS (src_value), *dest_value);
760 case GST_FORMAT_BYTES:
761 switch (dest_format) {
762 case GST_FORMAT_TIME:{
764 gst_qtdemux_find_index_for_given_media_offset_linear (qtdemux,
773 QTSTREAMTIME_TO_GSTTIME (stream,
774 stream->samples[index].timestamp);
775 GST_DEBUG_OBJECT (qtdemux,
776 "Format Conversion Offset->Time :%" G_GUINT64_FORMAT "->%"
777 GST_TIME_FORMAT, src_value, GST_TIME_ARGS (*dest_value));
796 gst_qtdemux_get_duration (GstQTDemux * qtdemux, GstClockTime * duration)
798 gboolean res = FALSE;
800 *duration = GST_CLOCK_TIME_NONE;
802 if (qtdemux->duration != 0 &&
803 qtdemux->duration != G_MAXINT64 && qtdemux->timescale != 0) {
804 *duration = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
807 *duration = GST_CLOCK_TIME_NONE;
814 gst_qtdemux_handle_src_query (GstPad * pad, GstObject * parent,
817 gboolean res = FALSE;
818 GstQTDemux *qtdemux = GST_QTDEMUX (parent);
820 GST_LOG_OBJECT (pad, "%s query", GST_QUERY_TYPE_NAME (query));
822 switch (GST_QUERY_TYPE (query)) {
823 case GST_QUERY_POSITION:{
826 gst_query_parse_position (query, &fmt, NULL);
827 if (fmt == GST_FORMAT_TIME
828 && GST_CLOCK_TIME_IS_VALID (qtdemux->segment.position)) {
829 gst_query_set_position (query, GST_FORMAT_TIME,
830 qtdemux->segment.position);
835 case GST_QUERY_DURATION:{
838 gst_query_parse_duration (query, &fmt, NULL);
839 if (fmt == GST_FORMAT_TIME) {
840 /* First try to query upstream */
841 res = gst_pad_query_default (pad, parent, query);
843 GstClockTime duration;
844 if (gst_qtdemux_get_duration (qtdemux, &duration) && duration > 0) {
845 gst_query_set_duration (query, GST_FORMAT_TIME, duration);
852 case GST_QUERY_CONVERT:{
853 GstFormat src_fmt, dest_fmt;
854 gint64 src_value, dest_value = 0;
856 gst_query_parse_convert (query, &src_fmt, &src_value, &dest_fmt, NULL);
858 res = gst_qtdemux_src_convert (qtdemux, pad,
859 src_fmt, src_value, dest_fmt, &dest_value);
861 gst_query_set_convert (query, src_fmt, src_value, dest_fmt, dest_value);
866 case GST_QUERY_FORMATS:
867 gst_query_set_formats (query, 2, GST_FORMAT_TIME, GST_FORMAT_BYTES);
870 case GST_QUERY_SEEKING:{
874 /* try upstream first */
875 res = gst_pad_query_default (pad, parent, query);
878 gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
879 if (fmt == GST_FORMAT_TIME) {
880 GstClockTime duration;
882 gst_qtdemux_get_duration (qtdemux, &duration);
884 if (!qtdemux->pullbased) {
887 /* we might be able with help from upstream */
889 q = gst_query_new_seeking (GST_FORMAT_BYTES);
890 if (gst_pad_peer_query (qtdemux->sinkpad, q)) {
891 gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL);
892 GST_LOG_OBJECT (qtdemux, "upstream BYTE seekable %d", seekable);
896 gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0, duration);
902 case GST_QUERY_SEGMENT:
907 format = qtdemux->segment.format;
910 gst_segment_to_stream_time (&qtdemux->segment, format,
911 qtdemux->segment.start);
912 if ((stop = qtdemux->segment.stop) == -1)
913 stop = qtdemux->segment.duration;
915 stop = gst_segment_to_stream_time (&qtdemux->segment, format, stop);
917 gst_query_set_segment (query, qtdemux->segment.rate, format, start, stop);
922 res = gst_pad_query_default (pad, parent, query);
930 gst_qtdemux_push_tags (GstQTDemux * qtdemux, QtDemuxStream * stream)
932 if (G_LIKELY (stream->pad)) {
933 GST_DEBUG_OBJECT (qtdemux, "Checking pad %s:%s for tags",
934 GST_DEBUG_PAD_NAME (stream->pad));
936 if (G_UNLIKELY (stream->pending_tags)) {
937 GST_DEBUG_OBJECT (qtdemux, "Sending tags %" GST_PTR_FORMAT,
938 stream->pending_tags);
939 gst_pad_push_event (stream->pad,
940 gst_event_new_tag (stream->pending_tags));
941 stream->pending_tags = NULL;
944 if (G_UNLIKELY (stream->send_global_tags && qtdemux->tag_list)) {
945 GST_DEBUG_OBJECT (qtdemux, "Sending global tags %" GST_PTR_FORMAT,
947 gst_pad_push_event (stream->pad,
948 gst_event_new_tag (gst_tag_list_ref (qtdemux->tag_list)));
949 stream->send_global_tags = FALSE;
954 /* push event on all source pads; takes ownership of the event */
956 gst_qtdemux_push_event (GstQTDemux * qtdemux, GstEvent * event)
959 gboolean has_valid_stream = FALSE;
960 GstEventType etype = GST_EVENT_TYPE (event);
962 GST_DEBUG_OBJECT (qtdemux, "pushing %s event on all source pads",
963 GST_EVENT_TYPE_NAME (event));
965 for (n = 0; n < qtdemux->n_streams; n++) {
967 QtDemuxStream *stream = qtdemux->streams[n];
968 GST_DEBUG_OBJECT (qtdemux, "pushing on pad %i", n);
970 if ((pad = stream->pad)) {
971 has_valid_stream = TRUE;
973 if (etype == GST_EVENT_EOS) {
974 /* let's not send twice */
975 if (stream->sent_eos)
977 stream->sent_eos = TRUE;
980 gst_pad_push_event (pad, gst_event_ref (event));
984 gst_event_unref (event);
986 /* if it is EOS and there are no pads, post an error */
987 if (!has_valid_stream && etype == GST_EVENT_EOS) {
988 gst_qtdemux_post_no_playable_stream_error (qtdemux);
992 /* push a pending newsegment event, if any from the streaming thread */
994 gst_qtdemux_push_pending_newsegment (GstQTDemux * qtdemux)
996 if (qtdemux->pending_newsegment) {
997 gst_qtdemux_push_event (qtdemux, qtdemux->pending_newsegment);
998 qtdemux->pending_newsegment = NULL;
1008 find_func (QtDemuxSample * s1, gint64 * media_time, gpointer user_data)
1010 if ((gint64) s1->timestamp + s1->pts_offset > *media_time)
1012 if ((gint64) s1->timestamp + s1->pts_offset == *media_time)
1018 /* find the index of the sample that includes the data for @media_time using a
1019 * binary search. Only to be called in optimized cases of linear search below.
1021 * Returns the index of the sample.
1024 gst_qtdemux_find_index (GstQTDemux * qtdemux, QtDemuxStream * str,
1027 QtDemuxSample *result;
1030 /* convert media_time to mov format */
1032 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
1034 result = gst_util_array_binary_search (str->samples, str->stbl_index + 1,
1035 sizeof (QtDemuxSample), (GCompareDataFunc) find_func,
1036 GST_SEARCH_MODE_BEFORE, &media_time, NULL);
1038 if (G_LIKELY (result))
1039 index = result - str->samples;
1048 /* find the index of the sample that includes the data for @media_offset using a
1051 * Returns the index of the sample.
1054 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
1055 QtDemuxStream * str, gint64 media_offset)
1057 QtDemuxSample *result = str->samples;
1060 if (result == NULL || str->n_samples == 0)
1063 if (media_offset == result->offset)
1067 while (index < str->n_samples - 1) {
1068 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
1071 if (media_offset < result->offset)
1082 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
1087 /* find the index of the sample that includes the data for @media_time using a
1088 * linear search, and keeping in mind that not all samples may have been parsed
1089 * yet. If possible, it will delegate to binary search.
1091 * Returns the index of the sample.
1094 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
1095 GstClockTime media_time)
1099 QtDemuxSample *sample;
1101 /* convert media_time to mov format */
1103 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
1105 sample = str->samples;
1106 if (mov_time == sample->timestamp + sample->pts_offset)
1109 /* use faster search if requested time in already parsed range */
1110 sample = str->samples + str->stbl_index;
1111 if (str->stbl_index >= 0 &&
1112 mov_time <= (sample->timestamp + sample->pts_offset))
1113 return gst_qtdemux_find_index (qtdemux, str, media_time);
1115 while (index < str->n_samples - 1) {
1116 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
1119 sample = str->samples + index + 1;
1120 if (mov_time < (sample->timestamp + sample->pts_offset))
1130 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
1135 /* find the index of the keyframe needed to decode the sample at @index
1138 * Returns the index of the keyframe.
1141 gst_qtdemux_find_keyframe (GstQTDemux * qtdemux, QtDemuxStream * str,
1144 guint32 new_index = index;
1146 if (index >= str->n_samples) {
1147 new_index = str->n_samples;
1151 /* all keyframes, return index */
1152 if (str->all_keyframe) {
1157 /* else go back until we have a keyframe */
1159 if (str->samples[new_index].keyframe)
1169 GST_DEBUG_OBJECT (qtdemux, "searching for keyframe index before index %u "
1170 "gave %u", index, new_index);
1175 /* find the segment for @time_position for @stream
1177 * Returns the index of the segment containing @time_position.
1178 * Returns the last segment and sets the @eos variable to TRUE
1179 * if the time is beyond the end. @eos may be NULL
1182 gst_qtdemux_find_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
1183 GstClockTime time_position)
1188 GST_LOG_OBJECT (stream->pad, "finding segment for %" GST_TIME_FORMAT,
1189 GST_TIME_ARGS (time_position));
1192 for (i = 0; i < stream->n_segments; i++) {
1193 QtDemuxSegment *segment = &stream->segments[i];
1195 GST_LOG_OBJECT (stream->pad,
1196 "looking at segment %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT,
1197 GST_TIME_ARGS (segment->time), GST_TIME_ARGS (segment->stop_time));
1199 /* For the last segment we include stop_time in the last segment */
1200 if (i < stream->n_segments - 1) {
1201 if (segment->time <= time_position && time_position < segment->stop_time) {
1202 GST_LOG_OBJECT (stream->pad, "segment %d matches", i);
1207 /* Last segment always matches */
1215 /* move the stream @str to the sample position @index.
1217 * Updates @str->sample_index and marks discontinuity if needed.
1220 gst_qtdemux_move_stream (GstQTDemux * qtdemux, QtDemuxStream * str,
1223 /* no change needed */
1224 if (index == str->sample_index)
1227 GST_DEBUG_OBJECT (qtdemux, "moving to sample %u of %u", index,
1230 /* position changed, we have a discont */
1231 str->sample_index = index;
1232 str->offset_in_sample = 0;
1233 /* Each time we move in the stream we store the position where we are
1235 str->from_sample = index;
1236 str->discont = TRUE;
1240 gst_qtdemux_adjust_seek (GstQTDemux * qtdemux, gint64 desired_time,
1241 gboolean use_sparse, gint64 * key_time, gint64 * key_offset)
1244 gint64 min_byte_offset = -1;
1247 min_offset = desired_time;
1249 /* for each stream, find the index of the sample in the segment
1250 * and move back to the previous keyframe. */
1251 for (n = 0; n < qtdemux->n_streams; n++) {
1253 guint32 index, kindex;
1255 GstClockTime media_start;
1256 GstClockTime media_time;
1257 GstClockTime seg_time;
1258 QtDemuxSegment *seg;
1259 gboolean empty_segment = FALSE;
1261 str = qtdemux->streams[n];
1263 if (str->sparse && !use_sparse)
1266 seg_idx = gst_qtdemux_find_segment (qtdemux, str, desired_time);
1267 GST_DEBUG_OBJECT (qtdemux, "align segment %d", seg_idx);
1269 /* get segment and time in the segment */
1270 seg = &str->segments[seg_idx];
1271 seg_time = desired_time - seg->time;
1273 while (QTSEGMENT_IS_EMPTY (seg)) {
1275 empty_segment = TRUE;
1276 GST_DEBUG_OBJECT (str->pad, "Segment %d is empty, moving to next one",
1279 if (seg_idx == str->n_segments)
1281 seg = &str->segments[seg_idx];
1284 if (seg_idx == str->n_segments) {
1285 /* FIXME track shouldn't have the last segment as empty, but if it
1286 * happens we better handle it */
1290 /* get the media time in the segment */
1291 media_start = seg->media_start + seg_time;
1293 /* get the index of the sample with media time */
1294 index = gst_qtdemux_find_index_linear (qtdemux, str, media_start);
1295 GST_DEBUG_OBJECT (qtdemux, "sample for %" GST_TIME_FORMAT " at %u"
1296 " at offset %" G_GUINT64_FORMAT " (empty segment: %d)",
1297 GST_TIME_ARGS (media_start), index, str->samples[index].offset,
1300 if (!empty_segment) {
1301 /* find previous keyframe */
1302 kindex = gst_qtdemux_find_keyframe (qtdemux, str, index);
1304 /* if the keyframe is at a different position, we need to update the
1305 * requested seek time */
1306 if (index != kindex) {
1309 /* get timestamp of keyframe */
1310 media_time = QTSAMPLE_DTS (str, &str->samples[kindex]);
1311 GST_DEBUG_OBJECT (qtdemux,
1312 "keyframe at %u with time %" GST_TIME_FORMAT " at offset %"
1313 G_GUINT64_FORMAT, kindex, GST_TIME_ARGS (media_time),
1314 str->samples[kindex].offset);
1316 /* keyframes in the segment get a chance to change the
1317 * desired_offset. keyframes out of the segment are
1319 if (media_time >= seg->media_start) {
1320 GstClockTime seg_time;
1322 /* this keyframe is inside the segment, convert back to
1324 seg_time = (media_time - seg->media_start) + seg->time;
1325 if (seg_time < min_offset)
1326 min_offset = seg_time;
1331 if (min_byte_offset < 0 || str->samples[index].offset < min_byte_offset)
1332 min_byte_offset = str->samples[index].offset;
1336 *key_time = min_offset;
1338 *key_offset = min_byte_offset;
1342 gst_qtdemux_convert_seek (GstPad * pad, GstFormat * format,
1343 GstSeekType cur_type, gint64 * cur, GstSeekType stop_type, gint64 * stop)
1347 g_return_val_if_fail (format != NULL, FALSE);
1348 g_return_val_if_fail (cur != NULL, FALSE);
1349 g_return_val_if_fail (stop != NULL, FALSE);
1351 if (*format == GST_FORMAT_TIME)
1355 if (cur_type != GST_SEEK_TYPE_NONE)
1356 res = gst_pad_query_convert (pad, *format, *cur, GST_FORMAT_TIME, cur);
1357 if (res && stop_type != GST_SEEK_TYPE_NONE)
1358 res = gst_pad_query_convert (pad, *format, *stop, GST_FORMAT_TIME, stop);
1361 *format = GST_FORMAT_TIME;
1366 /* perform seek in push based mode:
1367 find BYTE position to move to based on time and delegate to upstream
1370 gst_qtdemux_do_push_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1375 GstSeekType cur_type, stop_type;
1376 gint64 cur, stop, key_cur;
1379 gint64 original_stop;
1382 GST_DEBUG_OBJECT (qtdemux, "doing push-based seek");
1384 gst_event_parse_seek (event, &rate, &format, &flags,
1385 &cur_type, &cur, &stop_type, &stop);
1386 seqnum = gst_event_get_seqnum (event);
1388 /* only forward streaming and seeking is possible */
1390 goto unsupported_seek;
1392 /* convert to TIME if needed and possible */
1393 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1397 /* Upstream seek in bytes will have undefined stop, but qtdemux stores
1398 * the original stop position to use when upstream pushes the new segment
1400 original_stop = stop;
1403 /* find reasonable corresponding BYTE position,
1404 * also try to mind about keyframes, since we can not go back a bit for them
1406 gst_qtdemux_adjust_seek (qtdemux, cur, FALSE, &key_cur, &byte_cur);
1411 GST_DEBUG_OBJECT (qtdemux, "Pushing BYTE seek rate %g, "
1412 "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, byte_cur,
1415 GST_OBJECT_LOCK (qtdemux);
1416 qtdemux->seek_offset = byte_cur;
1417 if (!(flags & GST_SEEK_FLAG_KEY_UNIT)) {
1418 qtdemux->push_seek_start = cur;
1420 qtdemux->push_seek_start = key_cur;
1423 if (stop_type == GST_SEEK_TYPE_NONE) {
1424 qtdemux->push_seek_stop = qtdemux->segment.stop;
1426 qtdemux->push_seek_stop = original_stop;
1428 GST_OBJECT_UNLOCK (qtdemux);
1430 /* BYTE seek event */
1431 event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type, byte_cur,
1433 gst_event_set_seqnum (event, seqnum);
1434 res = gst_pad_push_event (qtdemux->sinkpad, event);
1441 GST_DEBUG_OBJECT (qtdemux, "could not determine byte position to seek to, "
1447 GST_DEBUG_OBJECT (qtdemux, "unsupported seek, seek aborted.");
1452 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1457 /* perform the seek.
1459 * We set all segment_indexes in the streams to unknown and
1460 * adjust the time_position to the desired position. this is enough
1461 * to trigger a segment switch in the streaming thread to start
1462 * streaming from the desired position.
1464 * Keyframe seeking is a little more complicated when dealing with
1465 * segments. Ideally we want to move to the previous keyframe in
1466 * the segment but there might not be a keyframe in the segment. In
1467 * fact, none of the segments could contain a keyframe. We take a
1468 * practical approach: seek to the previous keyframe in the segment,
1469 * if there is none, seek to the beginning of the segment.
1471 * Called with STREAM_LOCK
1474 gst_qtdemux_perform_seek (GstQTDemux * qtdemux, GstSegment * segment,
1475 guint32 seqnum, GstSeekFlags flags)
1477 gint64 desired_offset;
1480 desired_offset = segment->position;
1482 GST_DEBUG_OBJECT (qtdemux, "seeking to %" GST_TIME_FORMAT,
1483 GST_TIME_ARGS (desired_offset));
1485 /* may not have enough fragmented info to do this adjustment,
1486 * and we can't scan (and probably should not) at this time with
1487 * possibly flushing upstream */
1488 if ((flags & GST_SEEK_FLAG_KEY_UNIT) && !qtdemux->fragmented) {
1491 gst_qtdemux_adjust_seek (qtdemux, desired_offset, TRUE, &min_offset, NULL);
1492 GST_DEBUG_OBJECT (qtdemux, "keyframe seek, align to %"
1493 GST_TIME_FORMAT, GST_TIME_ARGS (min_offset));
1494 desired_offset = min_offset;
1497 /* and set all streams to the final position */
1498 gst_flow_combiner_reset (qtdemux->flowcombiner);
1499 for (n = 0; n < qtdemux->n_streams; n++) {
1500 QtDemuxStream *stream = qtdemux->streams[n];
1502 stream->time_position = desired_offset;
1503 stream->accumulated_base = 0;
1504 stream->sample_index = -1;
1505 stream->offset_in_sample = 0;
1506 stream->segment_index = -1;
1507 stream->sent_eos = FALSE;
1508 stream->segment_seqnum = seqnum;
1510 if (segment->flags & GST_SEEK_FLAG_FLUSH)
1511 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
1513 segment->position = desired_offset;
1514 segment->time = desired_offset;
1515 if (segment->rate >= 0) {
1516 segment->start = desired_offset;
1518 /* we stop at the end */
1519 if (segment->stop == -1)
1520 segment->stop = segment->duration;
1522 segment->stop = desired_offset;
1525 if (qtdemux->fragmented)
1526 qtdemux->fragmented_seek_pending = TRUE;
1531 /* do a seek in pull based mode */
1533 gst_qtdemux_do_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1538 GstSeekType cur_type, stop_type;
1542 GstSegment seeksegment;
1544 GstEvent *flush_event;
1547 GST_DEBUG_OBJECT (qtdemux, "doing seek with event");
1549 gst_event_parse_seek (event, &rate, &format, &flags,
1550 &cur_type, &cur, &stop_type, &stop);
1551 seqnum = gst_event_get_seqnum (event);
1553 /* we have to have a format as the segment format. Try to convert
1555 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1559 GST_DEBUG_OBJECT (qtdemux, "seek format %s", gst_format_get_name (format));
1561 GST_DEBUG_OBJECT (qtdemux, "doing seek without event");
1565 flush = flags & GST_SEEK_FLAG_FLUSH;
1567 /* stop streaming, either by flushing or by pausing the task */
1569 flush_event = gst_event_new_flush_start ();
1571 gst_event_set_seqnum (flush_event, seqnum);
1572 /* unlock upstream pull_range */
1573 gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event));
1574 /* make sure out loop function exits */
1575 gst_qtdemux_push_event (qtdemux, flush_event);
1577 /* non flushing seek, pause the task */
1578 gst_pad_pause_task (qtdemux->sinkpad);
1581 /* wait for streaming to finish */
1582 GST_PAD_STREAM_LOCK (qtdemux->sinkpad);
1584 /* copy segment, we need this because we still need the old
1585 * segment when we close the current segment. */
1586 memcpy (&seeksegment, &qtdemux->segment, sizeof (GstSegment));
1589 /* configure the segment with the seek variables */
1590 GST_DEBUG_OBJECT (qtdemux, "configuring seek");
1591 gst_segment_do_seek (&seeksegment, rate, format, flags,
1592 cur_type, cur, stop_type, stop, &update);
1595 /* now do the seek, this actually never returns FALSE */
1596 gst_qtdemux_perform_seek (qtdemux, &seeksegment, seqnum, flags);
1598 /* prepare for streaming again */
1600 flush_event = gst_event_new_flush_stop (TRUE);
1602 gst_event_set_seqnum (flush_event, seqnum);
1604 gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event));
1605 gst_qtdemux_push_event (qtdemux, flush_event);
1608 /* commit the new segment */
1609 memcpy (&qtdemux->segment, &seeksegment, sizeof (GstSegment));
1611 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
1612 GstMessage *msg = gst_message_new_segment_start (GST_OBJECT_CAST (qtdemux),
1613 qtdemux->segment.format, qtdemux->segment.position);
1615 gst_message_set_seqnum (msg, seqnum);
1616 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
1619 /* restart streaming, NEWSEGMENT will be sent from the streaming thread. */
1620 gst_pad_start_task (qtdemux->sinkpad, (GstTaskFunction) gst_qtdemux_loop,
1621 qtdemux->sinkpad, NULL);
1623 GST_PAD_STREAM_UNLOCK (qtdemux->sinkpad);
1630 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1636 qtdemux_ensure_index (GstQTDemux * qtdemux)
1640 GST_DEBUG_OBJECT (qtdemux, "collecting all metadata for all streams");
1642 /* Build complete index */
1643 for (i = 0; i < qtdemux->n_streams; i++) {
1644 QtDemuxStream *stream = qtdemux->streams[i];
1646 if (!qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1))
1654 GST_LOG_OBJECT (qtdemux,
1655 "Building complete index of stream %u for seeking failed!", i);
1661 gst_qtdemux_handle_src_event (GstPad * pad, GstObject * parent,
1664 gboolean res = TRUE;
1665 GstQTDemux *qtdemux = GST_QTDEMUX (parent);
1667 switch (GST_EVENT_TYPE (event)) {
1668 case GST_EVENT_SEEK:
1670 #ifndef GST_DISABLE_GST_DEBUG
1671 GstClockTime ts = gst_util_get_timestamp ();
1674 if (qtdemux->upstream_format_is_time && qtdemux->fragmented) {
1675 /* seek should be handled by upstream, we might need to re-download fragments */
1676 GST_DEBUG_OBJECT (qtdemux,
1677 "let upstream handle seek for fragmented playback");
1681 /* Build complete index for seeking;
1682 * if not a fragmented file at least */
1683 if (!qtdemux->fragmented)
1684 if (!qtdemux_ensure_index (qtdemux))
1686 #ifndef GST_DISABLE_GST_DEBUG
1687 ts = gst_util_get_timestamp () - ts;
1688 GST_INFO_OBJECT (qtdemux,
1689 "Time taken to parse index %" GST_TIME_FORMAT, GST_TIME_ARGS (ts));
1692 if (qtdemux->pullbased) {
1693 res = gst_qtdemux_do_seek (qtdemux, pad, event);
1694 } else if (gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (event))) {
1695 GST_DEBUG_OBJECT (qtdemux, "Upstream successfully seeked");
1697 } else if (qtdemux->state == QTDEMUX_STATE_MOVIE && qtdemux->n_streams
1698 && !qtdemux->fragmented) {
1699 res = gst_qtdemux_do_push_seek (qtdemux, pad, event);
1701 GST_DEBUG_OBJECT (qtdemux,
1702 "ignoring seek in push mode in current state");
1705 gst_event_unref (event);
1708 case GST_EVENT_NAVIGATION:
1710 gst_event_unref (event);
1714 res = gst_pad_event_default (pad, parent, event);
1724 GST_ERROR_OBJECT (qtdemux, "Index failed");
1725 gst_event_unref (event);
1731 /* stream/index return sample that is min/max w.r.t. byte position,
1732 * time is min/max w.r.t. time of samples,
1733 * the latter need not be time of the former sample */
1735 gst_qtdemux_find_sample (GstQTDemux * qtdemux, gint64 byte_pos, gboolean fw,
1736 gboolean set, QtDemuxStream ** _stream, gint * _index, gint64 * _time)
1739 gint64 time, min_time;
1740 QtDemuxStream *stream;
1746 for (n = 0; n < qtdemux->n_streams; ++n) {
1749 gboolean set_sample;
1751 str = qtdemux->streams[n];
1758 i = str->n_samples - 1;
1762 for (; (i >= 0) && (i < str->n_samples); i += inc) {
1763 if (str->samples[i].size == 0)
1766 if (fw && (str->samples[i].offset < byte_pos))
1769 if (!fw && (str->samples[i].offset + str->samples[i].size > byte_pos))
1772 /* move stream to first available sample */
1774 gst_qtdemux_move_stream (qtdemux, str, i);
1778 /* avoid index from sparse streams since they might be far away */
1780 /* determine min/max time */
1781 time = QTSAMPLE_PTS (str, &str->samples[i]);
1782 if (min_time == -1 || (!fw && time > min_time) ||
1783 (fw && time < min_time)) {
1787 /* determine stream with leading sample, to get its position */
1789 (fw && (str->samples[i].offset < stream->samples[index].offset)) ||
1790 (!fw && (str->samples[i].offset > stream->samples[index].offset))) {
1798 /* no sample for this stream, mark eos */
1800 gst_qtdemux_move_stream (qtdemux, str, str->n_samples);
1811 static QtDemuxStream *
1812 _create_stream (void)
1814 QtDemuxStream *stream;
1816 stream = g_new0 (QtDemuxStream, 1);
1817 /* new streams always need a discont */
1818 stream->discont = TRUE;
1819 /* we enable clipping for raw audio/video streams */
1820 stream->need_clip = FALSE;
1821 stream->need_process = FALSE;
1822 stream->segment_index = -1;
1823 stream->time_position = 0;
1824 stream->sample_index = -1;
1825 stream->offset_in_sample = 0;
1826 stream->new_stream = TRUE;
1827 stream->multiview_mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
1828 stream->multiview_flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
1829 stream->protected = FALSE;
1830 stream->protection_scheme_type = 0;
1831 stream->protection_scheme_version = 0;
1832 stream->protection_scheme_info = NULL;
1833 stream->n_samples_moof = 0;
1834 stream->duration_moof = 0;
1835 g_queue_init (&stream->protection_scheme_event_queue);
1840 gst_qtdemux_setcaps (GstQTDemux * demux, GstCaps * caps)
1842 GstStructure *structure;
1843 const gchar *variant;
1844 const GstCaps *mediacaps = NULL;
1846 GST_DEBUG_OBJECT (demux, "Sink set caps: %" GST_PTR_FORMAT, caps);
1848 structure = gst_caps_get_structure (caps, 0);
1849 variant = gst_structure_get_string (structure, "variant");
1851 if (variant && strcmp (variant, "mss-fragmented") == 0) {
1852 QtDemuxStream *stream;
1853 const GValue *value;
1855 demux->fragmented = TRUE;
1856 demux->mss_mode = TRUE;
1858 if (demux->n_streams > 1) {
1859 /* can't do this, we can only renegotiate for another mss format */
1863 value = gst_structure_get_value (structure, "media-caps");
1866 const GValue *timescale_v;
1868 /* TODO update when stream changes during playback */
1870 if (demux->n_streams == 0) {
1871 stream = _create_stream ();
1872 demux->streams[demux->n_streams] = stream;
1873 demux->n_streams = 1;
1875 stream = demux->streams[0];
1878 timescale_v = gst_structure_get_value (structure, "timescale");
1880 stream->timescale = g_value_get_uint64 (timescale_v);
1882 /* default mss timescale */
1883 stream->timescale = 10000000;
1885 demux->timescale = stream->timescale;
1887 mediacaps = gst_value_get_caps (value);
1888 if (!stream->caps || !gst_caps_is_equal_fixed (mediacaps, stream->caps)) {
1889 GST_DEBUG_OBJECT (demux, "We have a new caps %" GST_PTR_FORMAT,
1891 stream->new_caps = TRUE;
1893 gst_caps_replace (&stream->caps, (GstCaps *) mediacaps);
1894 structure = gst_caps_get_structure (mediacaps, 0);
1895 if (g_str_has_prefix (gst_structure_get_name (structure), "video")) {
1896 stream->subtype = FOURCC_vide;
1898 gst_structure_get_int (structure, "width", &stream->width);
1899 gst_structure_get_int (structure, "height", &stream->height);
1900 gst_structure_get_fraction (structure, "framerate", &stream->fps_n,
1902 } else if (g_str_has_prefix (gst_structure_get_name (structure), "audio")) {
1904 stream->subtype = FOURCC_soun;
1905 gst_structure_get_int (structure, "channels", &stream->n_channels);
1906 gst_structure_get_int (structure, "rate", &rate);
1907 stream->rate = rate;
1910 gst_caps_replace (&demux->media_caps, (GstCaps *) mediacaps);
1912 demux->mss_mode = FALSE;
1919 gst_qtdemux_reset (GstQTDemux * qtdemux, gboolean hard)
1923 GST_DEBUG_OBJECT (qtdemux, "Resetting demux");
1924 gst_pad_stop_task (qtdemux->sinkpad);
1926 if (hard || qtdemux->upstream_format_is_time) {
1927 qtdemux->state = QTDEMUX_STATE_INITIAL;
1928 qtdemux->neededbytes = 16;
1929 qtdemux->todrop = 0;
1930 qtdemux->pullbased = FALSE;
1931 qtdemux->posted_redirect = FALSE;
1932 qtdemux->first_mdat = -1;
1933 qtdemux->header_size = 0;
1934 qtdemux->mdatoffset = -1;
1935 qtdemux->restoredata_offset = -1;
1936 if (qtdemux->mdatbuffer)
1937 gst_buffer_unref (qtdemux->mdatbuffer);
1938 if (qtdemux->restoredata_buffer)
1939 gst_buffer_unref (qtdemux->restoredata_buffer);
1940 qtdemux->mdatbuffer = NULL;
1941 qtdemux->restoredata_buffer = NULL;
1942 qtdemux->mdatleft = 0;
1943 if (qtdemux->comp_brands)
1944 gst_buffer_unref (qtdemux->comp_brands);
1945 qtdemux->comp_brands = NULL;
1946 qtdemux->last_moov_offset = -1;
1947 if (qtdemux->moov_node)
1948 g_node_destroy (qtdemux->moov_node);
1949 qtdemux->moov_node = NULL;
1950 qtdemux->moov_node_compressed = NULL;
1951 if (qtdemux->tag_list)
1952 gst_mini_object_unref (GST_MINI_OBJECT_CAST (qtdemux->tag_list));
1953 qtdemux->tag_list = NULL;
1955 if (qtdemux->element_index)
1956 gst_object_unref (qtdemux->element_index);
1957 qtdemux->element_index = NULL;
1959 qtdemux->major_brand = 0;
1960 if (qtdemux->pending_newsegment)
1961 gst_event_unref (qtdemux->pending_newsegment);
1962 qtdemux->pending_newsegment = NULL;
1963 qtdemux->upstream_format_is_time = FALSE;
1964 qtdemux->upstream_seekable = FALSE;
1965 qtdemux->upstream_size = 0;
1967 qtdemux->fragment_start = -1;
1968 qtdemux->fragment_start_offset = -1;
1969 qtdemux->duration = 0;
1970 qtdemux->moof_offset = 0;
1971 qtdemux->chapters_track_id = 0;
1972 qtdemux->have_group_id = FALSE;
1973 qtdemux->group_id = G_MAXUINT;
1975 g_queue_foreach (&qtdemux->protection_event_queue, (GFunc) gst_event_unref,
1977 g_queue_clear (&qtdemux->protection_event_queue);
1979 qtdemux->offset = 0;
1980 gst_adapter_clear (qtdemux->adapter);
1981 gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
1984 for (n = 0; n < qtdemux->n_streams; n++) {
1985 gst_qtdemux_stream_free (qtdemux, qtdemux->streams[n]);
1986 qtdemux->streams[n] = NULL;
1988 qtdemux->n_streams = 0;
1989 qtdemux->n_video_streams = 0;
1990 qtdemux->n_audio_streams = 0;
1991 qtdemux->n_sub_streams = 0;
1992 qtdemux->exposed = FALSE;
1993 qtdemux->fragmented = FALSE;
1994 qtdemux->mss_mode = FALSE;
1995 gst_caps_replace (&qtdemux->media_caps, NULL);
1996 qtdemux->timescale = 0;
1997 qtdemux->got_moov = FALSE;
1998 if (qtdemux->protection_system_ids) {
1999 g_ptr_array_free (qtdemux->protection_system_ids, TRUE);
2000 qtdemux->protection_system_ids = NULL;
2002 } else if (qtdemux->mss_mode) {
2003 gst_flow_combiner_reset (qtdemux->flowcombiner);
2004 for (n = 0; n < qtdemux->n_streams; n++)
2005 gst_qtdemux_stream_clear (qtdemux, qtdemux->streams[n]);
2007 gst_flow_combiner_reset (qtdemux->flowcombiner);
2008 for (n = 0; n < qtdemux->n_streams; n++) {
2009 qtdemux->streams[n]->sent_eos = FALSE;
2010 qtdemux->streams[n]->segment_seqnum = 0;
2011 qtdemux->streams[n]->time_position = 0;
2012 qtdemux->streams[n]->accumulated_base = 0;
2014 if (!qtdemux->pending_newsegment) {
2015 qtdemux->pending_newsegment = gst_event_new_segment (&qtdemux->segment);
2021 gst_qtdemux_handle_sink_event (GstPad * sinkpad, GstObject * parent,
2024 GstQTDemux *demux = GST_QTDEMUX (parent);
2025 gboolean res = TRUE;
2027 GST_LOG_OBJECT (demux, "handling %s event", GST_EVENT_TYPE_NAME (event));
2029 switch (GST_EVENT_TYPE (event)) {
2030 case GST_EVENT_SEGMENT:
2033 QtDemuxStream *stream;
2036 GstEvent *segment_event;
2038 /* some debug output */
2039 gst_event_copy_segment (event, &segment);
2040 GST_DEBUG_OBJECT (demux, "received newsegment %" GST_SEGMENT_FORMAT,
2043 if (segment.format == GST_FORMAT_TIME) {
2044 GST_DEBUG_OBJECT (demux, "new pending_newsegment");
2045 gst_event_replace (&demux->pending_newsegment, event);
2046 demux->upstream_format_is_time = TRUE;
2048 GST_DEBUG_OBJECT (demux, "Not storing upstream newsegment, "
2049 "not in time format");
2051 /* chain will send initial newsegment after pads have been added */
2052 if (demux->state != QTDEMUX_STATE_MOVIE || !demux->n_streams) {
2053 GST_DEBUG_OBJECT (demux, "still starting, eating event");
2058 /* check if this matches a time seek we received previously
2059 * FIXME for backwards compatibility reasons we use the
2060 * seek_offset here to compare. In the future we might want to
2061 * change this to use the seqnum as it uniquely should identify
2062 * the segment that corresponds to the seek. */
2063 GST_DEBUG_OBJECT (demux, "Stored seek offset: %" G_GINT64_FORMAT
2064 ", received segment offset %" G_GINT64_FORMAT,
2065 demux->seek_offset, segment.start);
2066 if (segment.format == GST_FORMAT_BYTES
2067 && demux->seek_offset == segment.start) {
2068 GST_OBJECT_LOCK (demux);
2069 offset = segment.start;
2071 segment.format = GST_FORMAT_TIME;
2072 segment.start = demux->push_seek_start;
2073 segment.stop = demux->push_seek_stop;
2074 GST_DEBUG_OBJECT (demux, "Replaced segment with stored seek "
2075 "segment %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT,
2076 GST_TIME_ARGS (segment.start), GST_TIME_ARGS (segment.stop));
2077 GST_OBJECT_UNLOCK (demux);
2080 /* we only expect a BYTE segment, e.g. following a seek */
2081 if (segment.format == GST_FORMAT_BYTES) {
2082 if (GST_CLOCK_TIME_IS_VALID (segment.start)) {
2083 offset = segment.start;
2085 gst_qtdemux_find_sample (demux, segment.start, TRUE, FALSE, NULL,
2086 NULL, (gint64 *) & segment.start);
2087 if ((gint64) segment.start < 0)
2090 if (GST_CLOCK_TIME_IS_VALID (segment.stop)) {
2091 gst_qtdemux_find_sample (demux, segment.stop, FALSE, FALSE, NULL,
2092 NULL, (gint64 *) & segment.stop);
2093 /* keyframe seeking should already arrange for start >= stop,
2094 * but make sure in other rare cases */
2095 segment.stop = MAX (segment.stop, segment.start);
2097 } else if (segment.format == GST_FORMAT_TIME) {
2098 /* push all data on the adapter before starting this
2100 gst_qtdemux_process_adapter (demux, TRUE);
2102 GST_DEBUG_OBJECT (demux, "unsupported segment format, ignoring");
2106 /* accept upstream's notion of segment and distribute along */
2107 segment.format = GST_FORMAT_TIME;
2108 segment.position = segment.time = segment.start;
2109 segment.duration = demux->segment.duration;
2110 segment.base = gst_segment_to_running_time (&demux->segment,
2111 GST_FORMAT_TIME, demux->segment.position);
2113 gst_segment_copy_into (&segment, &demux->segment);
2114 GST_DEBUG_OBJECT (demux, "Pushing newseg %" GST_SEGMENT_FORMAT, &segment);
2115 segment_event = gst_event_new_segment (&segment);
2116 gst_event_set_seqnum (segment_event, gst_event_get_seqnum (event));
2117 /* erase any previously set segment */
2118 gst_event_replace (&demux->pending_newsegment, NULL);
2119 gst_qtdemux_push_event (demux, segment_event);
2121 /* clear leftover in current segment, if any */
2122 gst_adapter_clear (demux->adapter);
2124 /* set up streaming thread */
2125 demux->offset = offset;
2126 if (demux->upstream_format_is_time) {
2127 GST_DEBUG_OBJECT (demux, "Upstream is driving in time format, "
2128 "set values to restart reading from a new atom");
2129 demux->neededbytes = 16;
2132 gst_qtdemux_find_sample (demux, offset, TRUE, TRUE, &stream, &idx,
2135 demux->todrop = stream->samples[idx].offset - offset;
2136 demux->neededbytes = demux->todrop + stream->samples[idx].size;
2138 /* set up for EOS */
2139 demux->neededbytes = -1;
2144 gst_event_unref (event);
2148 case GST_EVENT_FLUSH_START:
2150 if (gst_event_get_seqnum (event) == demux->offset_seek_seqnum) {
2151 gst_event_unref (event);
2156 case GST_EVENT_FLUSH_STOP:
2160 dur = demux->segment.duration;
2161 gst_qtdemux_reset (demux, FALSE);
2162 demux->segment.duration = dur;
2164 if (gst_event_get_seqnum (event) == demux->offset_seek_seqnum) {
2165 gst_event_unref (event);
2171 /* If we are in push mode, and get an EOS before we've seen any streams,
2172 * then error out - we have nowhere to send the EOS */
2173 if (!demux->pullbased) {
2175 gboolean has_valid_stream = FALSE;
2176 for (i = 0; i < demux->n_streams; i++) {
2177 if (demux->streams[i]->pad != NULL) {
2178 has_valid_stream = TRUE;
2182 if (!has_valid_stream)
2183 gst_qtdemux_post_no_playable_stream_error (demux);
2185 GST_DEBUG_OBJECT (demux, "Data still available after EOS: %u",
2186 (guint) gst_adapter_available (demux->adapter));
2187 if (gst_qtdemux_process_adapter (demux, TRUE) != GST_FLOW_OK) {
2193 case GST_EVENT_CAPS:{
2194 GstCaps *caps = NULL;
2196 gst_event_parse_caps (event, &caps);
2197 gst_qtdemux_setcaps (demux, caps);
2199 gst_event_unref (event);
2202 case GST_EVENT_PROTECTION:
2204 const gchar *system_id = NULL;
2206 gst_event_parse_protection (event, &system_id, NULL, NULL);
2207 GST_DEBUG_OBJECT (demux, "Received protection event for system ID %s",
2209 gst_qtdemux_append_protection_system_id (demux, system_id);
2210 /* save the event for later, for source pads that have not been created */
2211 g_queue_push_tail (&demux->protection_event_queue, gst_event_ref (event));
2212 /* send it to all pads that already exist */
2213 gst_qtdemux_push_event (demux, event);
2221 res = gst_pad_event_default (demux->sinkpad, parent, event) & res;
2229 gst_qtdemux_set_index (GstElement * element, GstIndex * index)
2231 GstQTDemux *demux = GST_QTDEMUX (element);
2233 GST_OBJECT_LOCK (demux);
2234 if (demux->element_index)
2235 gst_object_unref (demux->element_index);
2237 demux->element_index = gst_object_ref (index);
2239 demux->element_index = NULL;
2241 GST_OBJECT_UNLOCK (demux);
2242 /* object lock might be taken again */
2244 gst_index_get_writer_id (index, GST_OBJECT (element), &demux->index_id);
2245 GST_DEBUG_OBJECT (demux, "Set index %" GST_PTR_FORMAT "for writer id %d",
2246 demux->element_index, demux->index_id);
2250 gst_qtdemux_get_index (GstElement * element)
2252 GstIndex *result = NULL;
2253 GstQTDemux *demux = GST_QTDEMUX (element);
2255 GST_OBJECT_LOCK (demux);
2256 if (demux->element_index)
2257 result = gst_object_ref (demux->element_index);
2258 GST_OBJECT_UNLOCK (demux);
2260 GST_DEBUG_OBJECT (demux, "Returning index %" GST_PTR_FORMAT, result);
2267 gst_qtdemux_stbl_free (QtDemuxStream * stream)
2269 g_free ((gpointer) stream->stco.data);
2270 stream->stco.data = NULL;
2271 g_free ((gpointer) stream->stsz.data);
2272 stream->stsz.data = NULL;
2273 g_free ((gpointer) stream->stsc.data);
2274 stream->stsc.data = NULL;
2275 g_free ((gpointer) stream->stts.data);
2276 stream->stts.data = NULL;
2277 g_free ((gpointer) stream->stss.data);
2278 stream->stss.data = NULL;
2279 g_free ((gpointer) stream->stps.data);
2280 stream->stps.data = NULL;
2281 g_free ((gpointer) stream->ctts.data);
2282 stream->ctts.data = NULL;
2286 gst_qtdemux_stream_flush_segments_data (GstQTDemux * qtdemux,
2287 QtDemuxStream * stream)
2289 g_free (stream->segments);
2290 stream->segments = NULL;
2291 stream->segment_index = -1;
2292 stream->accumulated_base = 0;
2296 gst_qtdemux_stream_flush_samples_data (GstQTDemux * qtdemux,
2297 QtDemuxStream * stream)
2299 g_free (stream->samples);
2300 stream->samples = NULL;
2301 gst_qtdemux_stbl_free (stream);
2304 g_free (stream->ra_entries);
2305 stream->ra_entries = NULL;
2306 stream->n_ra_entries = 0;
2308 stream->sample_index = -1;
2309 stream->stbl_index = -1;
2310 stream->n_samples = 0;
2311 stream->time_position = 0;
2313 stream->n_samples_moof = 0;
2314 stream->duration_moof = 0;
2318 gst_qtdemux_stream_clear (GstQTDemux * qtdemux, QtDemuxStream * stream)
2320 if (stream->allocator)
2321 gst_object_unref (stream->allocator);
2322 while (stream->buffers) {
2323 gst_buffer_unref (GST_BUFFER_CAST (stream->buffers->data));
2324 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
2326 if (stream->rgb8_palette) {
2327 gst_memory_unref (stream->rgb8_palette);
2328 stream->rgb8_palette = NULL;
2331 if (stream->pending_tags)
2332 gst_tag_list_unref (stream->pending_tags);
2333 stream->pending_tags = NULL;
2334 g_free (stream->redirect_uri);
2335 stream->redirect_uri = NULL;
2336 stream->sent_eos = FALSE;
2337 stream->sparse = FALSE;
2338 stream->protected = FALSE;
2339 if (stream->protection_scheme_info) {
2340 if (stream->protection_scheme_type == FOURCC_cenc) {
2341 QtDemuxCencSampleSetInfo *info =
2342 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
2343 if (info->default_properties)
2344 gst_structure_free (info->default_properties);
2345 if (info->crypto_info)
2346 g_ptr_array_free (info->crypto_info, TRUE);
2348 g_free (stream->protection_scheme_info);
2349 stream->protection_scheme_info = NULL;
2351 stream->protection_scheme_type = 0;
2352 stream->protection_scheme_version = 0;
2353 g_queue_foreach (&stream->protection_scheme_event_queue,
2354 (GFunc) gst_event_unref, NULL);
2355 g_queue_clear (&stream->protection_scheme_event_queue);
2356 gst_qtdemux_stream_flush_segments_data (qtdemux, stream);
2357 gst_qtdemux_stream_flush_samples_data (qtdemux, stream);
2361 gst_qtdemux_stream_free (GstQTDemux * qtdemux, QtDemuxStream * stream)
2363 gst_qtdemux_stream_clear (qtdemux, stream);
2365 gst_caps_unref (stream->caps);
2366 stream->caps = NULL;
2368 gst_element_remove_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
2369 gst_flow_combiner_remove_pad (qtdemux->flowcombiner, stream->pad);
2375 gst_qtdemux_remove_stream (GstQTDemux * qtdemux, int i)
2377 g_assert (i >= 0 && i < qtdemux->n_streams && qtdemux->streams[i] != NULL);
2379 gst_qtdemux_stream_free (qtdemux, qtdemux->streams[i]);
2380 qtdemux->streams[i] = qtdemux->streams[qtdemux->n_streams - 1];
2381 qtdemux->streams[qtdemux->n_streams - 1] = NULL;
2382 qtdemux->n_streams--;
2385 static GstStateChangeReturn
2386 gst_qtdemux_change_state (GstElement * element, GstStateChange transition)
2388 GstQTDemux *qtdemux = GST_QTDEMUX (element);
2389 GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
2391 switch (transition) {
2392 case GST_STATE_CHANGE_PAUSED_TO_READY:
2398 result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
2400 switch (transition) {
2401 case GST_STATE_CHANGE_PAUSED_TO_READY:{
2402 gst_qtdemux_reset (qtdemux, TRUE);
2413 qtdemux_parse_ftyp (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2415 /* counts as header data */
2416 qtdemux->header_size += length;
2418 /* only consider at least a sufficiently complete ftyp atom */
2422 qtdemux->major_brand = QT_FOURCC (buffer + 8);
2423 GST_DEBUG_OBJECT (qtdemux, "major brand: %" GST_FOURCC_FORMAT,
2424 GST_FOURCC_ARGS (qtdemux->major_brand));
2425 if (qtdemux->comp_brands)
2426 gst_buffer_unref (qtdemux->comp_brands);
2427 buf = qtdemux->comp_brands = gst_buffer_new_and_alloc (length - 16);
2428 gst_buffer_fill (buf, 0, buffer + 16, length - 16);
2433 qtdemux_handle_xmp_taglist (GstQTDemux * qtdemux, GstTagList * taglist,
2434 GstTagList * xmptaglist)
2436 /* Strip out bogus fields */
2438 if (gst_tag_list_get_scope (taglist) == GST_TAG_SCOPE_GLOBAL) {
2439 gst_tag_list_remove_tag (xmptaglist, GST_TAG_VIDEO_CODEC);
2440 gst_tag_list_remove_tag (xmptaglist, GST_TAG_AUDIO_CODEC);
2442 gst_tag_list_remove_tag (xmptaglist, GST_TAG_CONTAINER_FORMAT);
2445 GST_DEBUG_OBJECT (qtdemux, "Found XMP tags %" GST_PTR_FORMAT, xmptaglist);
2447 /* prioritize native tags using _KEEP mode */
2448 gst_tag_list_insert (taglist, xmptaglist, GST_TAG_MERGE_KEEP);
2449 gst_tag_list_unref (xmptaglist);
2454 qtdemux_parse_piff (GstQTDemux * qtdemux, const guint8 * buffer, gint length,
2462 QtDemuxStream *stream;
2463 GstStructure *structure;
2464 QtDemuxCencSampleSetInfo *ss_info = NULL;
2465 const gchar *system_id;
2466 gboolean uses_sub_sample_encryption = FALSE;
2468 if (qtdemux->n_streams == 0)
2471 stream = qtdemux->streams[0];
2473 structure = gst_caps_get_structure (stream->caps, 0);
2474 if (!gst_structure_has_name (structure, "application/x-cenc")) {
2475 GST_WARNING_OBJECT (qtdemux,
2476 "Attempting PIFF box parsing on an unencrypted stream.");
2480 gst_structure_get (structure, GST_PROTECTION_SYSTEM_ID_CAPS_FIELD,
2481 G_TYPE_STRING, &system_id, NULL);
2482 gst_qtdemux_append_protection_system_id (qtdemux, system_id);
2484 stream->protected = TRUE;
2485 stream->protection_scheme_type = FOURCC_cenc;
2487 if (!stream->protection_scheme_info)
2488 stream->protection_scheme_info = g_new0 (QtDemuxCencSampleSetInfo, 1);
2490 ss_info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
2492 if (ss_info->default_properties)
2493 gst_structure_free (ss_info->default_properties);
2495 ss_info->default_properties =
2496 gst_structure_new ("application/x-cenc",
2497 "iv_size", G_TYPE_UINT, iv_size, "encrypted", G_TYPE_BOOLEAN, TRUE, NULL);
2499 if (ss_info->crypto_info) {
2500 GST_LOG_OBJECT (qtdemux, "unreffing existing crypto_info");
2501 g_ptr_array_free (ss_info->crypto_info, TRUE);
2502 ss_info->crypto_info = NULL;
2506 gst_byte_reader_init (&br, buffer + offset + 16, length - offset - 16);
2508 if (!gst_byte_reader_get_uint8 (&br, &version)) {
2509 GST_ERROR_OBJECT (qtdemux, "Error getting box's version field");
2513 if (!gst_byte_reader_get_uint24_be (&br, &flags)) {
2514 GST_ERROR_OBJECT (qtdemux, "Error getting box's flags field");
2518 if ((flags & 0x000001)) {
2519 guint32 algorithm_id = 0;
2522 gboolean is_encrypted = TRUE;
2524 if (!gst_byte_reader_get_uint24_le (&br, &algorithm_id)) {
2525 GST_ERROR_OBJECT (qtdemux, "Error getting box's algorithm ID field");
2530 if (algorithm_id == 0) {
2531 is_encrypted = FALSE;
2532 } else if (algorithm_id == 1) {
2533 /* FIXME: maybe store this in properties? */
2534 GST_DEBUG_OBJECT (qtdemux, "AES 128-bits CTR encrypted stream");
2535 } else if (algorithm_id == 2) {
2536 /* FIXME: maybe store this in properties? */
2537 GST_DEBUG_OBJECT (qtdemux, "AES 128-bits CBC encrypted stream");
2540 if (!gst_byte_reader_get_uint8 (&br, &iv_size))
2543 if (!gst_byte_reader_get_data (&br, 16, &kid))
2546 kid_buf = gst_buffer_new_allocate (NULL, 16, NULL);
2547 gst_buffer_fill (kid_buf, 0, kid, 16);
2548 if (ss_info->default_properties)
2549 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,
2553 "encrypted", G_TYPE_BOOLEAN, is_encrypted,
2554 "kid", GST_TYPE_BUFFER, kid_buf, NULL);
2555 GST_DEBUG_OBJECT (qtdemux, "default sample properties: "
2556 "is_encrypted=%u, iv_size=%u", is_encrypted, iv_size);
2557 gst_buffer_unref (kid_buf);
2558 } else if ((flags & 0x000002)) {
2559 uses_sub_sample_encryption = TRUE;
2562 if (!gst_byte_reader_get_uint32_be (&br, &qtdemux->cenc_aux_sample_count)) {
2563 GST_ERROR_OBJECT (qtdemux, "Error getting box's sample count field");
2567 ss_info->crypto_info =
2568 g_ptr_array_new_full (qtdemux->cenc_aux_sample_count,
2569 (GDestroyNotify) qtdemux_gst_structure_free);
2571 for (i = 0; i < qtdemux->cenc_aux_sample_count; ++i) {
2572 GstStructure *properties;
2576 properties = qtdemux_get_cenc_sample_properties (qtdemux, stream, i);
2577 if (properties == NULL) {
2578 GST_ERROR_OBJECT (qtdemux, "failed to get properties for sample %u", i);
2582 if (!gst_byte_reader_dup_data (&br, iv_size, &data)) {
2583 GST_ERROR_OBJECT (qtdemux, "IV data not present for sample %u", i);
2584 gst_structure_free (properties);
2587 buf = gst_buffer_new_wrapped (data, iv_size);
2588 gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL);
2589 gst_buffer_unref (buf);
2591 if (uses_sub_sample_encryption) {
2592 guint16 n_subsamples;
2594 if (!gst_byte_reader_get_uint16_be (&br, &n_subsamples)
2595 || n_subsamples == 0) {
2596 GST_ERROR_OBJECT (qtdemux,
2597 "failed to get subsample count for sample %u", i);
2598 gst_structure_free (properties);
2601 GST_LOG_OBJECT (qtdemux, "subsample count: %u", n_subsamples);
2602 if (!gst_byte_reader_dup_data (&br, n_subsamples * 6, &data)) {
2603 GST_ERROR_OBJECT (qtdemux, "failed to get subsample data for sample %u",
2605 gst_structure_free (properties);
2608 buf = gst_buffer_new_wrapped (data, n_subsamples * 6);
2609 gst_structure_set (properties,
2610 "subsample_count", G_TYPE_UINT, n_subsamples,
2611 "subsamples", GST_TYPE_BUFFER, buf, NULL);
2612 gst_buffer_unref (buf);
2614 gst_structure_set (properties, "subsample_count", G_TYPE_UINT, 0, NULL);
2617 g_ptr_array_add (ss_info->crypto_info, properties);
2622 qtdemux_parse_uuid (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2624 static const guint8 xmp_uuid[] = { 0xBE, 0x7A, 0xCF, 0xCB,
2625 0x97, 0xA9, 0x42, 0xE8,
2626 0x9C, 0x71, 0x99, 0x94,
2627 0x91, 0xE3, 0xAF, 0xAC
2629 static const guint8 playready_uuid[] = {
2630 0xd0, 0x8a, 0x4f, 0x18, 0x10, 0xf3, 0x4a, 0x82,
2631 0xb6, 0xc8, 0x32, 0xd8, 0xab, 0xa1, 0x83, 0xd3
2634 static const guint8 piff_sample_encryption_uuid[] = {
2635 0xa2, 0x39, 0x4f, 0x52, 0x5a, 0x9b, 0x4f, 0x14,
2636 0xa2, 0x44, 0x6c, 0x42, 0x7c, 0x64, 0x8d, 0xf4
2641 /* counts as header data */
2642 qtdemux->header_size += length;
2644 offset = (QT_UINT32 (buffer) == 0) ? 16 : 8;
2646 if (length <= offset + 16) {
2647 GST_DEBUG_OBJECT (qtdemux, "uuid atom is too short, skipping");
2651 if (memcmp (buffer + offset, xmp_uuid, 16) == 0) {
2653 GstTagList *taglist;
2655 buf = _gst_buffer_new_wrapped ((guint8 *) buffer + offset + 16,
2656 length - offset - 16, NULL);
2657 taglist = gst_tag_list_from_xmp_buffer (buf);
2658 gst_buffer_unref (buf);
2660 qtdemux_handle_xmp_taglist (qtdemux, qtdemux->tag_list, taglist);
2662 } else if (memcmp (buffer + offset, playready_uuid, 16) == 0) {
2664 const gunichar2 *s_utf16;
2667 len = GST_READ_UINT16_LE (buffer + offset + 0x30);
2668 s_utf16 = (const gunichar2 *) (buffer + offset + 0x32);
2669 contents = g_utf16_to_utf8 (s_utf16, len / 2, NULL, NULL, NULL);
2670 GST_ERROR_OBJECT (qtdemux, "contents: %s", contents);
2674 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT,
2675 (_("Cannot play stream because it is encrypted with PlayReady DRM.")),
2677 } else if (memcmp (buffer + offset, piff_sample_encryption_uuid, 16) == 0) {
2678 qtdemux_parse_piff (qtdemux, buffer, length, offset);
2680 GST_DEBUG_OBJECT (qtdemux, "Ignoring unknown uuid: %08x-%08x-%08x-%08x",
2681 GST_READ_UINT32_LE (buffer + offset),
2682 GST_READ_UINT32_LE (buffer + offset + 4),
2683 GST_READ_UINT32_LE (buffer + offset + 8),
2684 GST_READ_UINT32_LE (buffer + offset + 12));
2689 qtdemux_parse_sidx (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2691 GstSidxParser sidx_parser;
2692 GstIsoffParserResult res;
2695 gst_isoff_qt_sidx_parser_init (&sidx_parser);
2698 gst_isoff_qt_sidx_parser_add_data (&sidx_parser, buffer, length,
2700 GST_DEBUG_OBJECT (qtdemux, "sidx parse result: %d", res);
2701 if (res == GST_ISOFF_QT_PARSER_DONE) {
2702 check_update_duration (qtdemux, sidx_parser.cumulative_pts);
2704 gst_isoff_qt_sidx_parser_clear (&sidx_parser);
2707 /* caller verifies at least 8 bytes in buf */
2709 extract_initial_length_and_fourcc (const guint8 * data, guint size,
2710 guint64 * plength, guint32 * pfourcc)
2715 length = QT_UINT32 (data);
2716 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
2717 fourcc = QT_FOURCC (data + 4);
2718 GST_DEBUG ("atom type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
2721 length = G_MAXUINT64;
2722 } else if (length == 1 && size >= 16) {
2723 /* this means we have an extended size, which is the 64 bit value of
2724 * the next 8 bytes */
2725 length = QT_UINT64 (data + 8);
2726 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
2736 qtdemux_parse_mehd (GstQTDemux * qtdemux, GstByteReader * br)
2738 guint32 version = 0;
2739 GstClockTime duration = 0;
2741 if (!gst_byte_reader_get_uint32_be (br, &version))
2746 if (!gst_byte_reader_get_uint64_be (br, &duration))
2751 if (!gst_byte_reader_get_uint32_be (br, &dur))
2756 GST_INFO_OBJECT (qtdemux, "mehd duration: %" G_GUINT64_FORMAT, duration);
2757 qtdemux->duration = duration;
2763 GST_DEBUG_OBJECT (qtdemux, "parsing mehd failed");
2769 qtdemux_parse_trex (GstQTDemux * qtdemux, QtDemuxStream * stream,
2770 guint32 * ds_duration, guint32 * ds_size, guint32 * ds_flags)
2772 if (!stream->parsed_trex && qtdemux->moov_node) {
2774 GstByteReader trex_data;
2776 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
2778 trex = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_trex,
2781 guint32 id = 0, dur = 0, size = 0, flags = 0, dummy = 0;
2783 /* skip version/flags */
2784 if (!gst_byte_reader_skip (&trex_data, 4))
2786 if (!gst_byte_reader_get_uint32_be (&trex_data, &id))
2788 if (id != stream->track_id)
2790 /* sample description index; ignore */
2791 if (!gst_byte_reader_get_uint32_be (&trex_data, &dummy))
2793 if (!gst_byte_reader_get_uint32_be (&trex_data, &dur))
2795 if (!gst_byte_reader_get_uint32_be (&trex_data, &size))
2797 if (!gst_byte_reader_get_uint32_be (&trex_data, &flags))
2800 GST_DEBUG_OBJECT (qtdemux, "fragment defaults for stream %d; "
2801 "duration %d, size %d, flags 0x%x", stream->track_id,
2804 stream->parsed_trex = TRUE;
2805 stream->def_sample_duration = dur;
2806 stream->def_sample_size = size;
2807 stream->def_sample_flags = flags;
2810 /* iterate all siblings */
2811 trex = qtdemux_tree_get_sibling_by_type_full (trex, FOURCC_trex,
2817 *ds_duration = stream->def_sample_duration;
2818 *ds_size = stream->def_sample_size;
2819 *ds_flags = stream->def_sample_flags;
2821 /* even then, above values are better than random ... */
2822 if (G_UNLIKELY (!stream->parsed_trex)) {
2823 GST_WARNING_OBJECT (qtdemux,
2824 "failed to find fragment defaults for stream %d", stream->track_id);
2831 /* This method should be called whenever a more accurate duration might
2832 * have been found. It will update all relevant variables if/where needed
2835 check_update_duration (GstQTDemux * qtdemux, GstClockTime duration)
2839 GstClockTime prevdur;
2841 movdur = GSTTIME_TO_QTTIME (qtdemux, duration);
2843 if (movdur > qtdemux->duration) {
2844 prevdur = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
2845 GST_DEBUG_OBJECT (qtdemux,
2846 "Updating total duration to %" GST_TIME_FORMAT " was %" GST_TIME_FORMAT,
2847 GST_TIME_ARGS (duration), GST_TIME_ARGS (prevdur));
2848 qtdemux->duration = movdur;
2849 GST_DEBUG_OBJECT (qtdemux,
2850 "qtdemux->segment.duration: %" GST_TIME_FORMAT " .stop: %"
2851 GST_TIME_FORMAT, GST_TIME_ARGS (qtdemux->segment.duration),
2852 GST_TIME_ARGS (qtdemux->segment.stop));
2853 if (qtdemux->segment.duration == prevdur) {
2854 /* If the current segment has duration/stop identical to previous duration
2855 * update them also (because they were set at that point in time with
2856 * the wrong duration */
2857 /* We convert the value *from* the timescale version to avoid rounding errors */
2858 GstClockTime fixeddur = QTTIME_TO_GSTTIME (qtdemux, movdur);
2859 GST_DEBUG_OBJECT (qtdemux, "Updated segment.duration and segment.stop");
2860 qtdemux->segment.duration = fixeddur;
2861 qtdemux->segment.stop = fixeddur;
2864 for (i = 0; i < qtdemux->n_streams; i++) {
2865 QtDemuxStream *stream = qtdemux->streams[i];
2867 movdur = GSTTIME_TO_QTSTREAMTIME (stream, duration);
2868 if (movdur > stream->duration) {
2869 GST_DEBUG_OBJECT (qtdemux,
2870 "Updating stream #%d duration to %" GST_TIME_FORMAT, i,
2871 GST_TIME_ARGS (duration));
2872 stream->duration = movdur;
2873 if (stream->dummy_segment) {
2874 /* Update all dummy values to new duration */
2875 stream->segments[0].stop_time = duration;
2876 stream->segments[0].duration = duration;
2877 stream->segments[0].media_stop = duration;
2885 qtdemux_parse_trun (GstQTDemux * qtdemux, GstByteReader * trun,
2886 QtDemuxStream * stream, guint32 d_sample_duration, guint32 d_sample_size,
2887 guint32 d_sample_flags, gint64 moof_offset, gint64 moof_length,
2888 gint64 * base_offset, gint64 * running_offset, gint64 decode_ts)
2890 GstClockTime gst_ts = GST_CLOCK_TIME_NONE;
2892 gint32 data_offset = 0;
2893 guint32 flags = 0, first_flags = 0, samples_count = 0;
2896 guint entry_size, dur_offset, size_offset, flags_offset = 0, ct_offset = 0;
2897 QtDemuxSample *sample;
2898 gboolean ismv = FALSE;
2900 GST_LOG_OBJECT (qtdemux, "parsing trun stream %d; "
2901 "default dur %d, size %d, flags 0x%x, base offset %" G_GINT64_FORMAT ", "
2902 "decode ts %" G_GINT64_FORMAT, stream->track_id, d_sample_duration,
2903 d_sample_size, d_sample_flags, *base_offset, decode_ts);
2905 if (stream->pending_seek && moof_offset < stream->pending_seek->moof_offset) {
2906 GST_INFO_OBJECT (stream->pad, "skipping trun before seek target fragment");
2910 /* presence of stss or not can't really tell us much,
2911 * and flags and so on tend to be marginally reliable in these files */
2912 if (stream->subtype == FOURCC_soun) {
2913 GST_DEBUG_OBJECT (qtdemux,
2914 "sound track in fragmented file; marking all keyframes");
2915 stream->all_keyframe = TRUE;
2918 if (!gst_byte_reader_skip (trun, 1) ||
2919 !gst_byte_reader_get_uint24_be (trun, &flags))
2922 if (!gst_byte_reader_get_uint32_be (trun, &samples_count))
2925 if (flags & TR_DATA_OFFSET) {
2926 /* note this is really signed */
2927 if (!gst_byte_reader_get_int32_be (trun, &data_offset))
2929 GST_LOG_OBJECT (qtdemux, "trun data offset %d", data_offset);
2930 /* default base offset = first byte of moof */
2931 if (*base_offset == -1) {
2932 GST_LOG_OBJECT (qtdemux, "base_offset at moof");
2933 *base_offset = moof_offset;
2935 *running_offset = *base_offset + data_offset;
2937 /* if no offset at all, that would mean data starts at moof start,
2938 * which is a bit wrong and is ismv crappy way, so compensate
2939 * assuming data is in mdat following moof */
2940 if (*base_offset == -1) {
2941 *base_offset = moof_offset + moof_length + 8;
2942 GST_LOG_OBJECT (qtdemux, "base_offset assumed in mdat after moof");
2945 if (*running_offset == -1)
2946 *running_offset = *base_offset;
2949 GST_LOG_OBJECT (qtdemux, "running offset now %" G_GINT64_FORMAT,
2951 GST_LOG_OBJECT (qtdemux, "trun offset %d, flags 0x%x, entries %d",
2952 data_offset, flags, samples_count);
2954 if (flags & TR_FIRST_SAMPLE_FLAGS) {
2955 if (G_UNLIKELY (flags & TR_SAMPLE_FLAGS)) {
2956 GST_DEBUG_OBJECT (qtdemux,
2957 "invalid flags; SAMPLE and FIRST_SAMPLE present, discarding latter");
2958 flags ^= TR_FIRST_SAMPLE_FLAGS;
2960 if (!gst_byte_reader_get_uint32_be (trun, &first_flags))
2962 GST_LOG_OBJECT (qtdemux, "first flags: 0x%x", first_flags);
2966 /* FIXME ? spec says other bits should also be checked to determine
2967 * entry size (and prefix size for that matter) */
2969 dur_offset = size_offset = 0;
2970 if (flags & TR_SAMPLE_DURATION) {
2971 GST_LOG_OBJECT (qtdemux, "entry duration present");
2972 dur_offset = entry_size;
2975 if (flags & TR_SAMPLE_SIZE) {
2976 GST_LOG_OBJECT (qtdemux, "entry size present");
2977 size_offset = entry_size;
2980 if (flags & TR_SAMPLE_FLAGS) {
2981 GST_LOG_OBJECT (qtdemux, "entry flags present");
2982 flags_offset = entry_size;
2985 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
2986 GST_LOG_OBJECT (qtdemux, "entry ct offset present");
2987 ct_offset = entry_size;
2991 if (!qt_atom_parser_has_chunks (trun, samples_count, entry_size))
2993 data = (guint8 *) gst_byte_reader_peek_data_unchecked (trun);
2995 if (stream->n_samples + samples_count >=
2996 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample))
2999 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
3000 stream->n_samples + samples_count, (guint) sizeof (QtDemuxSample),
3001 (stream->n_samples + samples_count) *
3002 sizeof (QtDemuxSample) / (1024.0 * 1024.0));
3004 /* create a new array of samples if it's the first sample parsed */
3005 if (stream->n_samples == 0) {
3006 g_assert (stream->samples == NULL);
3007 stream->samples = g_try_new0 (QtDemuxSample, samples_count);
3008 /* or try to reallocate it with space enough to insert the new samples */
3010 stream->samples = g_try_renew (QtDemuxSample, stream->samples,
3011 stream->n_samples + samples_count);
3012 if (stream->samples == NULL)
3015 if (qtdemux->fragment_start != -1) {
3016 timestamp = GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->fragment_start);
3017 qtdemux->fragment_start = -1;
3019 if (stream->n_samples == 0) {
3020 if (decode_ts > 0) {
3021 timestamp = decode_ts;
3022 } else if (stream->pending_seek != NULL) {
3023 /* if we don't have a timestamp from a tfdt box, we'll use the one
3024 * from the mfra seek table */
3025 GST_INFO_OBJECT (stream->pad, "pending seek ts = %" GST_TIME_FORMAT,
3026 GST_TIME_ARGS (stream->pending_seek->ts));
3028 /* FIXME: this is not fully correct, the timestamp refers to the random
3029 * access sample refered to in the tfra entry, which may not necessarily
3030 * be the first sample in the tfrag/trun (but hopefully/usually is) */
3031 timestamp = GSTTIME_TO_QTSTREAMTIME (stream, stream->pending_seek->ts);
3036 gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
3037 GST_INFO_OBJECT (stream->pad, "first sample ts %" GST_TIME_FORMAT,
3038 GST_TIME_ARGS (gst_ts));
3040 /* subsequent fragments extend stream */
3042 stream->samples[stream->n_samples - 1].timestamp +
3043 stream->samples[stream->n_samples - 1].duration;
3045 gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
3046 GST_INFO_OBJECT (qtdemux, "first sample ts %" GST_TIME_FORMAT
3047 " (extends previous samples)", GST_TIME_ARGS (gst_ts));
3051 sample = stream->samples + stream->n_samples;
3052 for (i = 0; i < samples_count; i++) {
3053 guint32 dur, size, sflags, ct;
3055 /* first read sample data */
3056 if (flags & TR_SAMPLE_DURATION) {
3057 dur = QT_UINT32 (data + dur_offset);
3059 dur = d_sample_duration;
3061 if (flags & TR_SAMPLE_SIZE) {
3062 size = QT_UINT32 (data + size_offset);
3064 size = d_sample_size;
3066 if (flags & TR_FIRST_SAMPLE_FLAGS) {
3068 sflags = first_flags;
3070 sflags = d_sample_flags;
3072 } else if (flags & TR_SAMPLE_FLAGS) {
3073 sflags = QT_UINT32 (data + flags_offset);
3075 sflags = d_sample_flags;
3077 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
3078 ct = QT_UINT32 (data + ct_offset);
3084 /* fill the sample information */
3085 sample->offset = *running_offset;
3086 sample->pts_offset = ct;
3087 sample->size = size;
3088 sample->timestamp = timestamp;
3089 sample->duration = dur;
3090 /* sample-is-difference-sample */
3091 /* ismv seems to use 0x40 for keyframe, 0xc0 for non-keyframe,
3092 * now idea how it relates to bitfield other than massive LE/BE confusion */
3093 sample->keyframe = ismv ? ((sflags & 0xff) == 0x40) : !(sflags & 0x10000);
3094 *running_offset += size;
3096 stream->duration_moof += dur;
3100 /* Update total duration if needed */
3101 check_update_duration (qtdemux, QTSTREAMTIME_TO_GSTTIME (stream, timestamp));
3103 stream->n_samples += samples_count;
3104 stream->n_samples_moof += samples_count;
3106 if (stream->pending_seek != NULL)
3107 stream->pending_seek = NULL;
3113 GST_WARNING_OBJECT (qtdemux, "failed to parse trun");
3118 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
3124 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
3125 "be larger than %uMB (broken file?)", stream->n_samples,
3126 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
3131 /* find stream with @id */
3132 static inline QtDemuxStream *
3133 qtdemux_find_stream (GstQTDemux * qtdemux, guint32 id)
3135 QtDemuxStream *stream;
3139 if (G_UNLIKELY (!id)) {
3140 GST_DEBUG_OBJECT (qtdemux, "invalid track id 0");
3144 /* try to get it fast and simple */
3145 if (G_LIKELY (id <= qtdemux->n_streams)) {
3146 stream = qtdemux->streams[id - 1];
3147 if (G_LIKELY (stream->track_id == id))
3151 /* linear search otherwise */
3152 for (i = 0; i < qtdemux->n_streams; i++) {
3153 stream = qtdemux->streams[i];
3154 if (stream->track_id == id)
3157 if (qtdemux->mss_mode) {
3158 /* mss should have only 1 stream anyway */
3159 return qtdemux->streams[0];
3166 qtdemux_parse_mfhd (GstQTDemux * qtdemux, GstByteReader * mfhd,
3167 guint32 * fragment_number)
3169 if (!gst_byte_reader_skip (mfhd, 4))
3171 if (!gst_byte_reader_get_uint32_be (mfhd, fragment_number))
3176 GST_WARNING_OBJECT (qtdemux, "Failed to parse mfhd atom");
3182 qtdemux_parse_tfhd (GstQTDemux * qtdemux, GstByteReader * tfhd,
3183 QtDemuxStream ** stream, guint32 * default_sample_duration,
3184 guint32 * default_sample_size, guint32 * default_sample_flags,
3185 gint64 * base_offset)
3188 guint32 track_id = 0;
3190 if (!gst_byte_reader_skip (tfhd, 1) ||
3191 !gst_byte_reader_get_uint24_be (tfhd, &flags))
3194 if (!gst_byte_reader_get_uint32_be (tfhd, &track_id))
3197 *stream = qtdemux_find_stream (qtdemux, track_id);
3198 if (G_UNLIKELY (!*stream))
3199 goto unknown_stream;
3201 if (flags & TF_DEFAULT_BASE_IS_MOOF)
3202 *base_offset = qtdemux->moof_offset;
3204 if (flags & TF_BASE_DATA_OFFSET)
3205 if (!gst_byte_reader_get_uint64_be (tfhd, (guint64 *) base_offset))
3208 /* obtain stream defaults */
3209 qtdemux_parse_trex (qtdemux, *stream,
3210 default_sample_duration, default_sample_size, default_sample_flags);
3212 /* FIXME: Handle TF_SAMPLE_DESCRIPTION_INDEX properly */
3213 if (flags & TF_SAMPLE_DESCRIPTION_INDEX)
3214 if (!gst_byte_reader_skip (tfhd, 4))
3217 if (flags & TF_DEFAULT_SAMPLE_DURATION)
3218 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_duration))
3221 if (flags & TF_DEFAULT_SAMPLE_SIZE)
3222 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_size))
3225 if (flags & TF_DEFAULT_SAMPLE_FLAGS)
3226 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_flags))
3233 GST_WARNING_OBJECT (qtdemux, "invalid track fragment header");
3238 GST_DEBUG_OBJECT (qtdemux, "unknown stream in tfhd");
3244 qtdemux_parse_tfdt (GstQTDemux * qtdemux, GstByteReader * br,
3245 guint64 * decode_time)
3247 guint32 version = 0;
3249 if (!gst_byte_reader_get_uint32_be (br, &version))
3254 if (!gst_byte_reader_get_uint64_be (br, decode_time))
3257 guint32 dec_time = 0;
3258 if (!gst_byte_reader_get_uint32_be (br, &dec_time))
3260 *decode_time = dec_time;
3263 GST_INFO_OBJECT (qtdemux, "Track fragment decode time: %" G_GUINT64_FORMAT,
3270 GST_DEBUG_OBJECT (qtdemux, "parsing tfdt failed");
3275 /* Returns a pointer to a GstStructure containing the properties of
3276 * the stream sample identified by @sample_index. The caller must unref
3277 * the returned object after use. Returns NULL if unsuccessful. */
3278 static GstStructure *
3279 qtdemux_get_cenc_sample_properties (GstQTDemux * qtdemux,
3280 QtDemuxStream * stream, guint sample_index)
3282 QtDemuxCencSampleSetInfo *info = NULL;
3284 g_return_val_if_fail (stream != NULL, NULL);
3285 g_return_val_if_fail (stream->protected, NULL);
3286 g_return_val_if_fail (stream->protection_scheme_info != NULL, NULL);
3288 info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
3290 /* Currently, cenc properties for groups of samples are not supported, so
3291 * simply return a copy of the default sample properties */
3292 return gst_structure_copy (info->default_properties);
3295 /* Parses the sizes of sample auxiliary information contained within a stream,
3296 * as given in a saiz box. Returns array of sample_count guint8 size values,
3297 * or NULL on failure */
3299 qtdemux_parse_saiz (GstQTDemux * qtdemux, QtDemuxStream * stream,
3300 GstByteReader * br, guint32 * sample_count)
3304 guint8 default_info_size;
3306 g_return_val_if_fail (qtdemux != NULL, NULL);
3307 g_return_val_if_fail (stream != NULL, NULL);
3308 g_return_val_if_fail (br != NULL, NULL);
3309 g_return_val_if_fail (sample_count != NULL, NULL);
3311 if (!gst_byte_reader_get_uint32_be (br, &flags))
3315 /* aux_info_type and aux_info_type_parameter are ignored */
3316 if (!gst_byte_reader_skip (br, 8))
3320 if (!gst_byte_reader_get_uint8 (br, &default_info_size))
3322 GST_DEBUG_OBJECT (qtdemux, "default_info_size: %u", default_info_size);
3324 if (!gst_byte_reader_get_uint32_be (br, sample_count))
3326 GST_DEBUG_OBJECT (qtdemux, "sample_count: %u", *sample_count);
3329 if (default_info_size == 0) {
3330 if (!gst_byte_reader_dup_data (br, *sample_count, &info_sizes)) {
3334 info_sizes = g_new (guint8, *sample_count);
3335 memset (info_sizes, default_info_size, *sample_count);
3341 /* Parses the offset of sample auxiliary information contained within a stream,
3342 * as given in a saio box. Returns TRUE if successful; FALSE otherwise. */
3344 qtdemux_parse_saio (GstQTDemux * qtdemux, QtDemuxStream * stream,
3345 GstByteReader * br, guint32 * info_type, guint32 * info_type_parameter,
3350 guint32 aux_info_type = 0;
3351 guint32 aux_info_type_parameter = 0;
3352 guint32 entry_count;
3355 const guint8 *aux_info_type_data = NULL;
3357 g_return_val_if_fail (qtdemux != NULL, FALSE);
3358 g_return_val_if_fail (stream != NULL, FALSE);
3359 g_return_val_if_fail (br != NULL, FALSE);
3360 g_return_val_if_fail (offset != NULL, FALSE);
3362 if (!gst_byte_reader_get_uint8 (br, &version))
3365 if (!gst_byte_reader_get_uint24_be (br, &flags))
3370 if (!gst_byte_reader_get_data (br, 4, &aux_info_type_data))
3372 aux_info_type = QT_FOURCC (aux_info_type_data);
3374 if (!gst_byte_reader_get_uint32_be (br, &aux_info_type_parameter))
3376 } else if (stream->protected) {
3377 aux_info_type = stream->protection_scheme_type;
3379 aux_info_type = stream->fourcc;
3383 *info_type = aux_info_type;
3384 if (info_type_parameter)
3385 *info_type_parameter = aux_info_type_parameter;
3387 GST_DEBUG_OBJECT (qtdemux, "aux_info_type: '%" GST_FOURCC_FORMAT "', "
3388 "aux_info_type_parameter: %#06x",
3389 GST_FOURCC_ARGS (aux_info_type), aux_info_type_parameter);
3391 if (!gst_byte_reader_get_uint32_be (br, &entry_count))
3394 if (entry_count != 1) {
3395 GST_ERROR_OBJECT (qtdemux, "multiple offsets are not supported");
3400 if (!gst_byte_reader_get_uint32_be (br, &off_32))
3402 *offset = (guint64) off_32;
3404 if (!gst_byte_reader_get_uint64_be (br, &off_64))
3409 GST_DEBUG_OBJECT (qtdemux, "offset: %" G_GUINT64_FORMAT, *offset);
3414 qtdemux_gst_structure_free (GstStructure * gststructure)
3417 gst_structure_free (gststructure);
3421 /* Parses auxiliary information relating to samples protected using Common
3422 * Encryption (cenc); the format of this information is defined in
3423 * ISO/IEC 23001-7. Returns TRUE if successful; FALSE otherwise. */
3425 qtdemux_parse_cenc_aux_info (GstQTDemux * qtdemux, QtDemuxStream * stream,
3426 GstByteReader * br, guint8 * info_sizes, guint32 sample_count)
3428 QtDemuxCencSampleSetInfo *ss_info = NULL;
3432 g_return_val_if_fail (qtdemux != NULL, FALSE);
3433 g_return_val_if_fail (stream != NULL, FALSE);
3434 g_return_val_if_fail (br != NULL, FALSE);
3435 g_return_val_if_fail (stream->protected, FALSE);
3436 g_return_val_if_fail (stream->protection_scheme_info != NULL, FALSE);
3438 ss_info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
3440 if (ss_info->crypto_info) {
3441 GST_LOG_OBJECT (qtdemux, "unreffing existing crypto_info");
3442 g_ptr_array_free (ss_info->crypto_info, TRUE);
3445 ss_info->crypto_info =
3446 g_ptr_array_new_full (sample_count,
3447 (GDestroyNotify) qtdemux_gst_structure_free);
3449 for (i = 0; i < sample_count; ++i) {
3450 GstStructure *properties;
3451 guint16 n_subsamples = 0;
3456 properties = qtdemux_get_cenc_sample_properties (qtdemux, stream, i);
3457 if (properties == NULL) {
3458 GST_ERROR_OBJECT (qtdemux, "failed to get properties for sample %u", i);
3461 if (!gst_structure_get_uint (properties, "iv_size", &iv_size)) {
3462 GST_ERROR_OBJECT (qtdemux, "failed to get iv_size for sample %u", i);
3463 gst_structure_free (properties);
3466 if (!gst_byte_reader_dup_data (br, iv_size, &data)) {
3467 GST_ERROR_OBJECT (qtdemux, "failed to get IV for sample %u", i);
3468 gst_structure_free (properties);
3471 buf = gst_buffer_new_wrapped (data, iv_size);
3472 gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL);
3473 gst_buffer_unref (buf);
3474 size = info_sizes[i];
3475 if (size > iv_size) {
3476 if (!gst_byte_reader_get_uint16_be (br, &n_subsamples)
3477 || !(n_subsamples > 0)) {
3478 gst_structure_free (properties);
3479 GST_ERROR_OBJECT (qtdemux,
3480 "failed to get subsample count for sample %u", i);
3483 GST_LOG_OBJECT (qtdemux, "subsample count: %u", n_subsamples);
3484 if (!gst_byte_reader_dup_data (br, n_subsamples * 6, &data)) {
3485 GST_ERROR_OBJECT (qtdemux, "failed to get subsample data for sample %u",
3487 gst_structure_free (properties);
3490 buf = gst_buffer_new_wrapped (data, n_subsamples * 6);
3492 gst_structure_free (properties);
3495 gst_structure_set (properties,
3496 "subsample_count", G_TYPE_UINT, n_subsamples,
3497 "subsamples", GST_TYPE_BUFFER, buf, NULL);
3498 gst_buffer_unref (buf);
3500 gst_structure_set (properties, "subsample_count", G_TYPE_UINT, 0, NULL);
3502 g_ptr_array_add (ss_info->crypto_info, properties);
3507 /* Converts a UUID in raw byte form to a string representation, as defined in
3508 * RFC 4122. The caller takes ownership of the returned string and is
3509 * responsible for freeing it after use. */
3511 qtdemux_uuid_bytes_to_string (gconstpointer uuid_bytes)
3513 const guint8 *uuid = (const guint8 *) uuid_bytes;
3515 return g_strdup_printf ("%02x%02x%02x%02x-%02x%02x-%02x%02x-"
3516 "%02x%02x-%02x%02x%02x%02x%02x%02x",
3517 uuid[0], uuid[1], uuid[2], uuid[3],
3518 uuid[4], uuid[5], uuid[6], uuid[7],
3519 uuid[8], uuid[9], uuid[10], uuid[11],
3520 uuid[12], uuid[13], uuid[14], uuid[15]);
3523 /* Parses a Protection System Specific Header box (pssh), as defined in the
3524 * Common Encryption (cenc) standard (ISO/IEC 23001-7), which contains
3525 * information needed by a specific content protection system in order to
3526 * decrypt cenc-protected tracks. Returns TRUE if successful; FALSE
3529 qtdemux_parse_pssh (GstQTDemux * qtdemux, GNode * node)
3531 gchar *sysid_string;
3532 guint32 pssh_size = QT_UINT32 (node->data);
3533 GstBuffer *pssh = NULL;
3534 GstEvent *event = NULL;
3535 guint32 parent_box_type;
3538 if (G_UNLIKELY (pssh_size < 32U)) {
3539 GST_ERROR_OBJECT (qtdemux, "invalid box size");
3544 qtdemux_uuid_bytes_to_string ((const guint8 *) node->data + 12);
3546 gst_qtdemux_append_protection_system_id (qtdemux, sysid_string);
3548 pssh = gst_buffer_new_wrapped (g_memdup (node->data, pssh_size), pssh_size);
3549 GST_LOG_OBJECT (qtdemux, "cenc pssh size: %" G_GSIZE_FORMAT,
3550 gst_buffer_get_size (pssh));
3552 parent_box_type = QT_FOURCC ((const guint8 *) node->parent->data + 4);
3554 /* Push an event containing the pssh box onto the queues of all streams. */
3555 event = gst_event_new_protection (sysid_string, pssh,
3556 (parent_box_type == FOURCC_moov) ? "isobmff/moov" : "isobmff/moof");
3557 for (i = 0; i < qtdemux->n_streams; ++i) {
3558 g_queue_push_tail (&qtdemux->streams[i]->protection_scheme_event_queue,
3559 gst_event_ref (event));
3561 g_free (sysid_string);
3562 gst_event_unref (event);
3563 gst_buffer_unref (pssh);
3568 qtdemux_parse_moof (GstQTDemux * qtdemux, const guint8 * buffer, guint length,
3569 guint64 moof_offset, QtDemuxStream * stream)
3571 GNode *moof_node, *traf_node, *tfhd_node, *trun_node, *tfdt_node, *mfhd_node;
3573 GstByteReader mfhd_data, trun_data, tfhd_data, tfdt_data;
3574 GNode *saiz_node, *saio_node, *pssh_node;
3575 GstByteReader saiz_data, saio_data;
3576 guint32 ds_size = 0, ds_duration = 0, ds_flags = 0;
3577 gint64 base_offset, running_offset;
3580 /* NOTE @stream ignored */
3582 moof_node = g_node_new ((guint8 *) buffer);
3583 qtdemux_parse_node (qtdemux, moof_node, buffer, length);
3584 qtdemux_node_dump (qtdemux, moof_node);
3586 /* Get fragment number from mfhd and check it's valid */
3588 qtdemux_tree_get_child_by_type_full (moof_node, FOURCC_mfhd, &mfhd_data);
3589 if (mfhd_node == NULL)
3591 if (!qtdemux_parse_mfhd (qtdemux, &mfhd_data, &frag_num))
3593 GST_DEBUG_OBJECT (qtdemux, "Fragment #%d", frag_num);
3595 /* unknown base_offset to start with */
3596 base_offset = running_offset = -1;
3597 traf_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_traf);
3599 guint64 decode_time = 0;
3601 /* Fragment Header node */
3603 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfhd,
3607 if (!qtdemux_parse_tfhd (qtdemux, &tfhd_data, &stream, &ds_duration,
3608 &ds_size, &ds_flags, &base_offset))
3611 /* The following code assumes at most a single set of sample auxiliary
3612 * data in the fragment (consisting of a saiz box and a corresponding saio
3613 * box); in theory, however, there could be multiple sets of sample
3614 * auxiliary data in a fragment. */
3616 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saiz,
3619 guint32 info_type = 0;
3621 guint32 info_type_parameter = 0;
3623 g_free (qtdemux->cenc_aux_info_sizes);
3625 qtdemux->cenc_aux_info_sizes =
3626 qtdemux_parse_saiz (qtdemux, stream, &saiz_data,
3627 &qtdemux->cenc_aux_sample_count);
3628 if (qtdemux->cenc_aux_info_sizes == NULL) {
3629 GST_ERROR_OBJECT (qtdemux, "failed to parse saiz box");
3633 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saio,
3636 GST_ERROR_OBJECT (qtdemux, "saiz box without a corresponding saio box");
3637 g_free (qtdemux->cenc_aux_info_sizes);
3638 qtdemux->cenc_aux_info_sizes = NULL;
3642 if (G_UNLIKELY (!qtdemux_parse_saio (qtdemux, stream, &saio_data,
3643 &info_type, &info_type_parameter, &offset))) {
3644 GST_ERROR_OBJECT (qtdemux, "failed to parse saio box");
3645 g_free (qtdemux->cenc_aux_info_sizes);
3646 qtdemux->cenc_aux_info_sizes = NULL;
3649 if (base_offset > -1 && base_offset > qtdemux->moof_offset)
3650 offset += (guint64) (base_offset - qtdemux->moof_offset);
3651 if (info_type == FOURCC_cenc && info_type_parameter == 0U) {
3653 if (offset > length) {
3654 GST_DEBUG_OBJECT (qtdemux, "cenc auxiliary info stored out of moof");
3655 qtdemux->cenc_aux_info_offset = offset;
3657 gst_byte_reader_init (&br, buffer + offset, length - offset);
3658 if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
3659 qtdemux->cenc_aux_info_sizes,
3660 qtdemux->cenc_aux_sample_count)) {
3661 GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
3662 g_free (qtdemux->cenc_aux_info_sizes);
3663 qtdemux->cenc_aux_info_sizes = NULL;
3671 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfdt,
3674 GstClockTime decode_time_ts;
3676 /* We'll use decode_time to interpolate timestamps
3677 * in case the input timestamps are missing */
3678 qtdemux_parse_tfdt (qtdemux, &tfdt_data, &decode_time);
3680 decode_time_ts = QTSTREAMTIME_TO_GSTTIME (stream, decode_time);
3682 GST_DEBUG_OBJECT (qtdemux, "decode time %" G_GINT64_FORMAT
3683 " (%" GST_TIME_FORMAT ")", decode_time,
3684 GST_TIME_ARGS (decode_time_ts));
3686 /* Discard the fragment buffer timestamp info to avoid using it.
3687 * Rely on tfdt instead as it is more accurate than the timestamp
3688 * that is fetched from a manifest/playlist and is usually
3690 qtdemux->fragment_start = -1;
3693 if (G_UNLIKELY (!stream)) {
3694 /* we lost track of offset, we'll need to regain it,
3695 * but can delay complaining until later or avoid doing so altogether */
3699 if (G_UNLIKELY (base_offset < -1))
3702 if (qtdemux->upstream_format_is_time)
3703 gst_qtdemux_stream_flush_samples_data (qtdemux, stream);
3705 /* initialise moof sample data */
3706 stream->n_samples_moof = 0;
3707 stream->duration_moof = 0;
3709 /* Track Run node */
3711 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_trun,
3714 qtdemux_parse_trun (qtdemux, &trun_data, stream,
3715 ds_duration, ds_size, ds_flags, moof_offset, length, &base_offset,
3716 &running_offset, decode_time);
3717 /* iterate all siblings */
3718 trun_node = qtdemux_tree_get_sibling_by_type_full (trun_node, FOURCC_trun,
3722 uuid_node = qtdemux_tree_get_child_by_type (traf_node, FOURCC_uuid);
3724 guint8 *uuid_buffer = (guint8 *) uuid_node->data;
3725 guint32 box_length = QT_UINT32 (uuid_buffer);
3727 qtdemux_parse_uuid (qtdemux, uuid_buffer, box_length);
3730 /* if no new base_offset provided for next traf,
3731 * base is end of current traf */
3732 base_offset = running_offset;
3733 running_offset = -1;
3735 if (stream->n_samples_moof && stream->duration_moof)
3736 stream->new_caps = TRUE;
3739 /* iterate all siblings */
3740 traf_node = qtdemux_tree_get_sibling_by_type (traf_node, FOURCC_traf);
3743 /* parse any protection system info */
3744 pssh_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_pssh);
3746 GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
3747 qtdemux_parse_pssh (qtdemux, pssh_node);
3748 pssh_node = qtdemux_tree_get_sibling_by_type (pssh_node, FOURCC_pssh);
3751 g_node_destroy (moof_node);
3756 GST_DEBUG_OBJECT (qtdemux, "missing tfhd box");
3761 GST_DEBUG_OBJECT (qtdemux, "Missing mfhd box");
3766 GST_DEBUG_OBJECT (qtdemux, "lost offset");
3771 g_node_destroy (moof_node);
3772 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
3773 (_("This file is corrupt and cannot be played.")), (NULL));
3779 /* might be used if some day we actually use mfra & co
3780 * for random access to fragments,
3781 * but that will require quite some modifications and much less relying
3782 * on a sample array */
3786 qtdemux_parse_tfra (GstQTDemux * qtdemux, GNode * tfra_node)
3788 QtDemuxStream *stream;
3789 guint32 ver_flags, track_id, len, num_entries, i;
3790 guint value_size, traf_size, trun_size, sample_size;
3791 guint64 time = 0, moof_offset = 0;
3793 GstBuffer *buf = NULL;
3798 gst_byte_reader_init (&tfra, tfra_node->data, QT_UINT32 (tfra_node->data));
3800 if (!gst_byte_reader_skip (&tfra, 8))
3803 if (!gst_byte_reader_get_uint32_be (&tfra, &ver_flags))
3806 if (!gst_byte_reader_get_uint32_be (&tfra, &track_id)
3807 || !gst_byte_reader_get_uint32_be (&tfra, &len)
3808 || !gst_byte_reader_get_uint32_be (&tfra, &num_entries))
3811 GST_DEBUG_OBJECT (qtdemux, "parsing tfra box for track id %u", track_id);
3813 stream = qtdemux_find_stream (qtdemux, track_id);
3815 goto unknown_trackid;
3817 value_size = ((ver_flags >> 24) == 1) ? sizeof (guint64) : sizeof (guint32);
3818 sample_size = (len & 3) + 1;
3819 trun_size = ((len & 12) >> 2) + 1;
3820 traf_size = ((len & 48) >> 4) + 1;
3822 GST_DEBUG_OBJECT (qtdemux, "%u entries, sizes: value %u, traf %u, trun %u, "
3823 "sample %u", num_entries, value_size, traf_size, trun_size, sample_size);
3825 if (num_entries == 0)
3828 if (!qt_atom_parser_has_chunks (&tfra, num_entries,
3829 value_size + value_size + traf_size + trun_size + sample_size))
3832 g_free (stream->ra_entries);
3833 stream->ra_entries = g_new (QtDemuxRandomAccessEntry, num_entries);
3834 stream->n_ra_entries = num_entries;
3836 for (i = 0; i < num_entries; i++) {
3837 qt_atom_parser_get_offset (&tfra, value_size, &time);
3838 qt_atom_parser_get_offset (&tfra, value_size, &moof_offset);
3839 qt_atom_parser_get_uint_with_size_unchecked (&tfra, traf_size);
3840 qt_atom_parser_get_uint_with_size_unchecked (&tfra, trun_size);
3841 qt_atom_parser_get_uint_with_size_unchecked (&tfra, sample_size);
3843 time = QTSTREAMTIME_TO_GSTTIME (stream, time);
3845 GST_LOG_OBJECT (qtdemux, "fragment time: %" GST_TIME_FORMAT ", "
3846 " moof_offset: %" G_GUINT64_FORMAT, GST_TIME_ARGS (time), moof_offset);
3848 stream->ra_entries[i].ts = time;
3849 stream->ra_entries[i].moof_offset = moof_offset;
3851 /* don't want to go through the entire file and read all moofs at startup */
3853 ret = gst_qtdemux_pull_atom (qtdemux, moof_offset, 0, &buf);
3854 if (ret != GST_FLOW_OK)
3856 qtdemux_parse_moof (qtdemux, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf),
3857 moof_offset, stream);
3858 gst_buffer_unref (buf);
3862 check_update_duration (qtdemux, time);
3869 GST_WARNING_OBJECT (qtdemux, "Couldn't find stream for track %u", track_id);
3874 GST_WARNING_OBJECT (qtdemux, "broken traf box, ignoring");
3879 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
3885 qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux)
3887 GstMapInfo mfro_map = GST_MAP_INFO_INIT;
3888 GstMapInfo mfra_map = GST_MAP_INFO_INIT;
3889 GstBuffer *mfro = NULL, *mfra = NULL;
3891 gboolean ret = FALSE;
3892 GNode *mfra_node, *tfra_node;
3893 guint64 mfra_offset = 0;
3894 guint32 fourcc, mfra_size;
3897 /* query upstream size in bytes */
3898 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &len))
3899 goto size_query_failed;
3901 /* mfro box should be at the very end of the file */
3902 flow = gst_qtdemux_pull_atom (qtdemux, len - 16, 16, &mfro);
3903 if (flow != GST_FLOW_OK)
3906 gst_buffer_map (mfro, &mfro_map, GST_MAP_READ);
3908 fourcc = QT_FOURCC (mfro_map.data + 4);
3909 if (fourcc != FOURCC_mfro)
3912 GST_INFO_OBJECT (qtdemux, "Found mfro box");
3913 if (mfro_map.size < 16)
3914 goto invalid_mfro_size;
3916 mfra_size = QT_UINT32 (mfro_map.data + 12);
3917 if (mfra_size >= len)
3918 goto invalid_mfra_size;
3920 mfra_offset = len - mfra_size;
3922 GST_INFO_OBJECT (qtdemux, "mfra offset: %" G_GUINT64_FORMAT ", size %u",
3923 mfra_offset, mfra_size);
3925 /* now get and parse mfra box */
3926 flow = gst_qtdemux_pull_atom (qtdemux, mfra_offset, mfra_size, &mfra);
3927 if (flow != GST_FLOW_OK)
3930 gst_buffer_map (mfra, &mfra_map, GST_MAP_READ);
3932 mfra_node = g_node_new ((guint8 *) mfra_map.data);
3933 qtdemux_parse_node (qtdemux, mfra_node, mfra_map.data, mfra_map.size);
3935 tfra_node = qtdemux_tree_get_child_by_type (mfra_node, FOURCC_tfra);
3938 qtdemux_parse_tfra (qtdemux, tfra_node);
3939 /* iterate all siblings */
3940 tfra_node = qtdemux_tree_get_sibling_by_type (tfra_node, FOURCC_tfra);
3942 g_node_destroy (mfra_node);
3944 GST_INFO_OBJECT (qtdemux, "parsed movie fragment random access box (mfra)");
3950 if (mfro_map.memory != NULL)
3951 gst_buffer_unmap (mfro, &mfro_map);
3952 gst_buffer_unref (mfro);
3955 if (mfra_map.memory != NULL)
3956 gst_buffer_unmap (mfra, &mfra_map);
3957 gst_buffer_unref (mfra);
3964 GST_WARNING_OBJECT (qtdemux, "could not query upstream size");
3969 GST_WARNING_OBJECT (qtdemux, "mfro size is too small");
3974 GST_WARNING_OBJECT (qtdemux, "mfra_size in mfro box is invalid");
3979 GST_WARNING_OBJECT (qtdemux, "bogus mfra offset or size, broken file");
3985 add_offset (guint64 offset, guint64 advance)
3987 /* Avoid 64-bit overflow by clamping */
3988 if (offset > G_MAXUINT64 - advance)
3990 return offset + advance;
3993 static GstFlowReturn
3994 gst_qtdemux_loop_state_header (GstQTDemux * qtdemux)
3998 GstBuffer *buf = NULL;
3999 GstFlowReturn ret = GST_FLOW_OK;
4000 guint64 cur_offset = qtdemux->offset;
4003 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, 16, &buf);
4004 if (G_UNLIKELY (ret != GST_FLOW_OK))
4006 gst_buffer_map (buf, &map, GST_MAP_READ);
4007 if (G_LIKELY (map.size >= 8))
4008 extract_initial_length_and_fourcc (map.data, map.size, &length, &fourcc);
4009 gst_buffer_unmap (buf, &map);
4010 gst_buffer_unref (buf);
4012 /* maybe we already got most we needed, so only consider this eof */
4013 if (G_UNLIKELY (length == 0)) {
4014 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
4015 (_("Invalid atom size.")),
4016 ("Header atom '%" GST_FOURCC_FORMAT "' has empty length",
4017 GST_FOURCC_ARGS (fourcc)));
4024 /* record for later parsing when needed */
4025 if (!qtdemux->moof_offset) {
4026 qtdemux->moof_offset = qtdemux->offset;
4028 if (qtdemux_pull_mfro_mfra (qtdemux)) {
4031 qtdemux->offset += length; /* skip moof and keep going */
4033 if (qtdemux->got_moov) {
4034 GST_INFO_OBJECT (qtdemux, "moof header, got moov, done with headers");
4045 GST_LOG_OBJECT (qtdemux,
4046 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
4047 GST_FOURCC_ARGS (fourcc), cur_offset);
4048 qtdemux->offset = add_offset (qtdemux->offset, length);
4053 GstBuffer *moov = NULL;
4055 if (qtdemux->got_moov) {
4056 GST_DEBUG_OBJECT (qtdemux, "Skipping moov atom as we have one already");
4057 qtdemux->offset = add_offset (qtdemux->offset, length);
4061 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, length, &moov);
4062 if (ret != GST_FLOW_OK)
4064 gst_buffer_map (moov, &map, GST_MAP_READ);
4066 if (length != map.size) {
4067 /* Some files have a 'moov' atom at the end of the file which contains
4068 * a terminal 'free' atom where the body of the atom is missing.
4069 * Check for, and permit, this special case.
4071 if (map.size >= 8) {
4072 guint8 *final_data = map.data + (map.size - 8);
4073 guint32 final_length = QT_UINT32 (final_data);
4074 guint32 final_fourcc = QT_FOURCC (final_data + 4);
4076 if (final_fourcc == FOURCC_free
4077 && map.size + final_length - 8 == length) {
4078 /* Ok, we've found that special case. Allocate a new buffer with
4079 * that free atom actually present. */
4080 GstBuffer *newmoov = gst_buffer_new_and_alloc (length);
4081 gst_buffer_fill (newmoov, 0, map.data, map.size);
4082 gst_buffer_memset (newmoov, map.size, 0, final_length - 8);
4083 gst_buffer_unmap (moov, &map);
4084 gst_buffer_unref (moov);
4086 gst_buffer_map (moov, &map, GST_MAP_READ);
4091 if (length != map.size) {
4092 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4093 (_("This file is incomplete and cannot be played.")),
4094 ("We got less than expected (received %" G_GSIZE_FORMAT
4095 ", wanted %u, offset %" G_GUINT64_FORMAT ")", map.size,
4096 (guint) length, cur_offset));
4097 gst_buffer_unmap (moov, &map);
4098 gst_buffer_unref (moov);
4099 ret = GST_FLOW_ERROR;
4102 qtdemux->offset += length;
4104 qtdemux_parse_moov (qtdemux, map.data, length);
4105 qtdemux_node_dump (qtdemux, qtdemux->moov_node);
4107 qtdemux_parse_tree (qtdemux);
4108 g_node_destroy (qtdemux->moov_node);
4109 gst_buffer_unmap (moov, &map);
4110 gst_buffer_unref (moov);
4111 qtdemux->moov_node = NULL;
4112 qtdemux->got_moov = TRUE;
4118 GstBuffer *ftyp = NULL;
4120 /* extract major brand; might come in handy for ISO vs QT issues */
4121 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &ftyp);
4122 if (ret != GST_FLOW_OK)
4124 qtdemux->offset += length;
4125 gst_buffer_map (ftyp, &map, GST_MAP_READ);
4126 qtdemux_parse_ftyp (qtdemux, map.data, map.size);
4127 gst_buffer_unmap (ftyp, &map);
4128 gst_buffer_unref (ftyp);
4133 GstBuffer *uuid = NULL;
4135 /* uuid are extension atoms */
4136 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &uuid);
4137 if (ret != GST_FLOW_OK)
4139 qtdemux->offset += length;
4140 gst_buffer_map (uuid, &map, GST_MAP_READ);
4141 qtdemux_parse_uuid (qtdemux, map.data, map.size);
4142 gst_buffer_unmap (uuid, &map);
4143 gst_buffer_unref (uuid);
4148 GstBuffer *sidx = NULL;
4149 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &sidx);
4150 if (ret != GST_FLOW_OK)
4152 qtdemux->offset += length;
4153 gst_buffer_map (sidx, &map, GST_MAP_READ);
4154 qtdemux_parse_sidx (qtdemux, map.data, map.size);
4155 gst_buffer_unmap (sidx, &map);
4156 gst_buffer_unref (sidx);
4161 GstBuffer *unknown = NULL;
4163 GST_LOG_OBJECT (qtdemux,
4164 "unknown %08x '%" GST_FOURCC_FORMAT "' of size %" G_GUINT64_FORMAT
4165 " at %" G_GUINT64_FORMAT, fourcc, GST_FOURCC_ARGS (fourcc), length,
4167 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &unknown);
4168 if (ret != GST_FLOW_OK)
4170 gst_buffer_map (unknown, &map, GST_MAP_READ);
4171 GST_MEMDUMP ("Unknown tag", map.data, map.size);
4172 gst_buffer_unmap (unknown, &map);
4173 gst_buffer_unref (unknown);
4174 qtdemux->offset += length;
4180 if (ret == GST_FLOW_EOS && (qtdemux->got_moov || qtdemux->media_caps)) {
4181 /* digested all data, show what we have */
4182 qtdemux_prepare_streams (qtdemux);
4183 ret = qtdemux_expose_streams (qtdemux);
4185 qtdemux->state = QTDEMUX_STATE_MOVIE;
4186 GST_DEBUG_OBJECT (qtdemux, "switching state to STATE_MOVIE (%d)",
4193 /* Seeks to the previous keyframe of the indexed stream and
4194 * aligns other streams with respect to the keyframe timestamp
4195 * of indexed stream. Only called in case of Reverse Playback
4197 static GstFlowReturn
4198 gst_qtdemux_seek_to_previous_keyframe (GstQTDemux * qtdemux)
4201 guint32 seg_idx = 0, k_index = 0;
4202 guint32 ref_seg_idx, ref_k_index;
4203 GstClockTime k_pos = 0, last_stop = 0;
4204 QtDemuxSegment *seg = NULL;
4205 QtDemuxStream *ref_str = NULL;
4206 guint64 seg_media_start_mov; /* segment media start time in mov format */
4209 /* Now we choose an arbitrary stream, get the previous keyframe timestamp
4210 * and finally align all the other streams on that timestamp with their
4211 * respective keyframes */
4212 for (n = 0; n < qtdemux->n_streams; n++) {
4213 QtDemuxStream *str = qtdemux->streams[n];
4215 /* No candidate yet, take the first stream */
4221 /* So that stream has a segment, we prefer video streams */
4222 if (str->subtype == FOURCC_vide) {
4228 if (G_UNLIKELY (!ref_str)) {
4229 GST_DEBUG_OBJECT (qtdemux, "couldn't find any stream");
4233 if (G_UNLIKELY (!ref_str->from_sample)) {
4234 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of the file");
4238 /* So that stream has been playing from from_sample to to_sample. We will
4239 * get the timestamp of the previous sample and search for a keyframe before
4240 * that. For audio streams we do an arbitrary jump in the past (10 samples) */
4241 if (ref_str->subtype == FOURCC_vide) {
4242 k_index = gst_qtdemux_find_keyframe (qtdemux, ref_str,
4243 ref_str->from_sample - 1);
4245 if (ref_str->from_sample >= 10)
4246 k_index = ref_str->from_sample - 10;
4252 ref_str->samples[k_index].timestamp +
4253 ref_str->samples[k_index].pts_offset;
4255 /* get current segment for that stream */
4256 seg = &ref_str->segments[ref_str->segment_index];
4257 /* Use segment start in original timescale for comparisons */
4258 seg_media_start_mov = seg->trak_media_start;
4260 GST_LOG_OBJECT (qtdemux, "keyframe index %u ts %" G_GUINT64_FORMAT
4261 " seg start %" G_GUINT64_FORMAT " %" GST_TIME_FORMAT "\n",
4262 k_index, target_ts, seg_media_start_mov,
4263 GST_TIME_ARGS (seg->media_start));
4265 /* Crawl back through segments to find the one containing this I frame */
4266 while (target_ts < seg_media_start_mov) {
4267 GST_DEBUG_OBJECT (qtdemux,
4268 "keyframe position (sample %u) is out of segment %u " " target %"
4269 G_GUINT64_FORMAT " seg start %" G_GUINT64_FORMAT, k_index,
4270 ref_str->segment_index, target_ts, seg_media_start_mov);
4272 if (G_UNLIKELY (!ref_str->segment_index)) {
4273 /* Reached first segment, let's consider it's EOS */
4276 ref_str->segment_index--;
4277 seg = &ref_str->segments[ref_str->segment_index];
4278 /* Use segment start in original timescale for comparisons */
4279 seg_media_start_mov = seg->trak_media_start;
4281 /* Calculate time position of the keyframe and where we should stop */
4283 QTSTREAMTIME_TO_GSTTIME (ref_str,
4284 target_ts - seg->trak_media_start) + seg->time;
4286 QTSTREAMTIME_TO_GSTTIME (ref_str,
4287 ref_str->samples[ref_str->from_sample].timestamp -
4288 seg->trak_media_start) + seg->time;
4290 GST_DEBUG_OBJECT (qtdemux, "preferred stream played from sample %u, "
4291 "now going to sample %u (pts %" GST_TIME_FORMAT ")", ref_str->from_sample,
4292 k_index, GST_TIME_ARGS (k_pos));
4294 /* Set last_stop with the keyframe timestamp we pushed of that stream */
4295 qtdemux->segment.position = last_stop;
4296 GST_DEBUG_OBJECT (qtdemux, "last_stop now is %" GST_TIME_FORMAT,
4297 GST_TIME_ARGS (last_stop));
4299 if (G_UNLIKELY (last_stop < qtdemux->segment.start)) {
4300 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of segment");
4304 ref_seg_idx = ref_str->segment_index;
4305 ref_k_index = k_index;
4307 /* Align them all on this */
4308 for (n = 0; n < qtdemux->n_streams; n++) {
4310 GstClockTime seg_time = 0;
4311 QtDemuxStream *str = qtdemux->streams[n];
4313 /* aligning reference stream again might lead to backing up to yet another
4314 * keyframe (due to timestamp rounding issues),
4315 * potentially putting more load on downstream; so let's try to avoid */
4316 if (str == ref_str) {
4317 seg_idx = ref_seg_idx;
4318 seg = &str->segments[seg_idx];
4319 k_index = ref_k_index;
4320 GST_DEBUG_OBJECT (qtdemux, "reference stream %d segment %d, "
4321 "sample at index %d", n, ref_str->segment_index, k_index);
4323 seg_idx = gst_qtdemux_find_segment (qtdemux, str, k_pos);
4324 GST_DEBUG_OBJECT (qtdemux,
4325 "stream %d align segment %d for keyframe pos %" GST_TIME_FORMAT, n,
4326 seg_idx, GST_TIME_ARGS (k_pos));
4328 /* get segment and time in the segment */
4329 seg = &str->segments[seg_idx];
4330 seg_time = k_pos - seg->time;
4332 /* get the media time in the segment.
4333 * No adjustment for empty "filler" segments */
4334 if (seg->media_start != GST_CLOCK_TIME_NONE)
4335 seg_time += seg->media_start;
4337 /* get the index of the sample with media time */
4338 index = gst_qtdemux_find_index_linear (qtdemux, str, seg_time);
4339 GST_DEBUG_OBJECT (qtdemux,
4340 "stream %d sample for %" GST_TIME_FORMAT " at %u", n,
4341 GST_TIME_ARGS (seg_time), index);
4343 /* find previous keyframe */
4344 k_index = gst_qtdemux_find_keyframe (qtdemux, str, index);
4347 /* Remember until where we want to go */
4348 str->to_sample = str->from_sample - 1;
4349 /* Define our time position */
4351 str->samples[k_index].timestamp + str->samples[k_index].pts_offset;
4352 str->time_position = QTSTREAMTIME_TO_GSTTIME (str, target_ts) + seg->time;
4353 if (seg->media_start != GST_CLOCK_TIME_NONE)
4354 str->time_position -= seg->media_start;
4356 /* Now seek back in time */
4357 gst_qtdemux_move_stream (qtdemux, str, k_index);
4358 GST_DEBUG_OBJECT (qtdemux, "stream %d keyframe at %u, time position %"
4359 GST_TIME_FORMAT " playing from sample %u to %u", n, k_index,
4360 GST_TIME_ARGS (str->time_position), str->from_sample, str->to_sample);
4366 return GST_FLOW_EOS;
4369 /* activate the given segment number @seg_idx of @stream at time @offset.
4370 * @offset is an absolute global position over all the segments.
4372 * This will push out a NEWSEGMENT event with the right values and
4373 * position the stream index to the first decodable sample before
4377 gst_qtdemux_activate_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
4378 guint32 seg_idx, GstClockTime offset)
4381 QtDemuxSegment *segment;
4382 guint32 index, kf_index;
4383 GstClockTime seg_time;
4384 GstClockTime start, stop, time;
4387 GST_LOG_OBJECT (stream->pad, "activate segment %d, offset %" GST_TIME_FORMAT,
4388 seg_idx, GST_TIME_ARGS (offset));
4390 /* update the current segment */
4391 stream->segment_index = seg_idx;
4393 /* get the segment */
4394 segment = &stream->segments[seg_idx];
4396 if (G_UNLIKELY (offset < segment->time)) {
4397 GST_WARNING_OBJECT (stream->pad, "offset < segment->time %" GST_TIME_FORMAT,
4398 GST_TIME_ARGS (segment->time));
4402 /* segment lies beyond total indicated duration */
4403 if (G_UNLIKELY (qtdemux->segment.duration != GST_CLOCK_TIME_NONE &&
4404 segment->time > qtdemux->segment.duration)) {
4405 GST_WARNING_OBJECT (stream->pad, "file duration %" GST_TIME_FORMAT
4406 " < segment->time %" GST_TIME_FORMAT,
4407 GST_TIME_ARGS (qtdemux->segment.duration),
4408 GST_TIME_ARGS (segment->time));
4412 /* get time in this segment */
4413 seg_time = offset - segment->time;
4415 GST_LOG_OBJECT (stream->pad, "seg_time %" GST_TIME_FORMAT,
4416 GST_TIME_ARGS (seg_time));
4418 if (G_UNLIKELY (seg_time > segment->duration)) {
4419 GST_LOG_OBJECT (stream->pad,
4420 "seg_time > segment->duration %" GST_TIME_FORMAT,
4421 GST_TIME_ARGS (segment->duration));
4422 seg_time = segment->duration;
4425 /* qtdemux->segment.stop is in outside-time-realm, whereas
4426 * segment->media_stop is in track-time-realm.
4428 * In order to compare the two, we need to bring segment.stop
4429 * into the track-time-realm */
4431 stop = qtdemux->segment.stop;
4432 if (stop == GST_CLOCK_TIME_NONE)
4433 stop = qtdemux->segment.duration;
4434 if (stop == GST_CLOCK_TIME_NONE)
4435 stop = segment->media_stop;
4438 MIN (segment->media_stop, stop - segment->time + segment->media_start);
4440 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
4441 start = segment->time + seg_time;
4443 stop = start - seg_time + segment->duration;
4444 } else if (qtdemux->segment.rate >= 0) {
4445 start = MIN (segment->media_start + seg_time, stop);
4448 if (segment->media_start >= qtdemux->segment.start) {
4449 time = segment->time;
4451 time = segment->time + (qtdemux->segment.start - segment->media_start);
4454 start = MAX (segment->media_start, qtdemux->segment.start);
4455 stop = MIN (segment->media_start + seg_time, stop);
4458 GST_DEBUG_OBJECT (stream->pad, "new segment %d from %" GST_TIME_FORMAT
4459 " to %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT, seg_idx,
4460 GST_TIME_ARGS (start), GST_TIME_ARGS (stop), GST_TIME_ARGS (time));
4462 /* combine global rate with that of the segment */
4463 rate = segment->rate * qtdemux->segment.rate;
4465 /* Copy flags from main segment */
4466 stream->segment.flags = qtdemux->segment.flags;
4468 /* update the segment values used for clipping */
4469 stream->segment.offset = qtdemux->segment.offset;
4470 stream->segment.base = qtdemux->segment.base + stream->accumulated_base;
4471 stream->segment.applied_rate = qtdemux->segment.applied_rate;
4472 stream->segment.rate = rate;
4473 stream->segment.start = start + QTSTREAMTIME_TO_GSTTIME (stream,
4474 stream->cslg_shift);
4475 stream->segment.stop = stop + QTSTREAMTIME_TO_GSTTIME (stream,
4476 stream->cslg_shift);
4477 stream->segment.time = time;
4478 stream->segment.position = stream->segment.start;
4480 GST_DEBUG_OBJECT (stream->pad, "New segment: %" GST_SEGMENT_FORMAT,
4483 /* now prepare and send the segment */
4485 event = gst_event_new_segment (&stream->segment);
4486 if (stream->segment_seqnum) {
4487 gst_event_set_seqnum (event, stream->segment_seqnum);
4489 gst_pad_push_event (stream->pad, event);
4490 /* assume we can send more data now */
4491 GST_PAD_LAST_FLOW_RETURN (stream->pad) = GST_FLOW_OK;
4492 /* clear to send tags on this pad now */
4493 gst_qtdemux_push_tags (qtdemux, stream);
4496 /* in the fragmented case, we pick a fragment that starts before our
4497 * desired position and rely on downstream to wait for a keyframe
4498 * (FIXME: doesn't seem to work so well with ismv and wmv, as no parser; the
4499 * tfra entries tells us which trun/sample the key unit is in, but we don't
4500 * make use of this additional information at the moment) */
4501 if (qtdemux->fragmented) {
4502 stream->to_sample = G_MAXUINT32;
4506 /* We don't need to look for a sample in push-based */
4507 if (!qtdemux->pullbased)
4510 /* and move to the keyframe before the indicated media time of the
4512 if (G_LIKELY (!QTSEGMENT_IS_EMPTY (segment))) {
4513 if (qtdemux->segment.rate >= 0) {
4514 index = gst_qtdemux_find_index_linear (qtdemux, stream, start);
4515 stream->to_sample = G_MAXUINT32;
4516 GST_DEBUG_OBJECT (stream->pad,
4517 "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
4518 GST_TIME_FORMAT, GST_TIME_ARGS (start), index,
4519 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
4521 index = gst_qtdemux_find_index_linear (qtdemux, stream, stop);
4522 stream->to_sample = index;
4523 GST_DEBUG_OBJECT (stream->pad,
4524 "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
4525 GST_TIME_FORMAT, GST_TIME_ARGS (stop), index,
4526 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
4529 GST_DEBUG_OBJECT (stream->pad, "No need to look for keyframe, "
4530 "this is an empty segment");
4534 /* gst_qtdemux_parse_sample () called from gst_qtdemux_find_index_linear ()
4535 * encountered an error and printed a message so we return appropriately */
4539 /* we're at the right spot */
4540 if (index == stream->sample_index) {
4541 GST_DEBUG_OBJECT (stream->pad, "we are at the right index");
4545 /* find keyframe of the target index */
4546 kf_index = gst_qtdemux_find_keyframe (qtdemux, stream, index);
4549 /* indent does stupid stuff with stream->samples[].timestamp */
4551 /* if we move forwards, we don't have to go back to the previous
4552 * keyframe since we already sent that. We can also just jump to
4553 * the keyframe right before the target index if there is one. */
4554 if (index > stream->sample_index) {
4555 /* moving forwards check if we move past a keyframe */
4556 if (kf_index > stream->sample_index) {
4557 GST_DEBUG_OBJECT (stream->pad,
4558 "moving forwards to keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" )", kf_index,
4559 GST_TIME_ARGS (QTSAMPLE_PTS(stream, &stream->samples[kf_index])),
4560 GST_TIME_ARGS (QTSAMPLE_DTS(stream, &stream->samples[kf_index])));
4561 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
4563 GST_DEBUG_OBJECT (stream->pad,
4564 "moving forwards, keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" ) already sent", kf_index,
4565 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[kf_index])),
4566 GST_TIME_ARGS (QTSAMPLE_DTS (stream, &stream->samples[kf_index])));
4569 GST_DEBUG_OBJECT (stream->pad,
4570 "moving backwards to keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" )", kf_index,
4571 GST_TIME_ARGS (QTSAMPLE_PTS(stream, &stream->samples[kf_index])),
4572 GST_TIME_ARGS (QTSAMPLE_DTS(stream, &stream->samples[kf_index])));
4573 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
4581 /* prepare to get the current sample of @stream, getting essential values.
4583 * This function will also prepare and send the segment when needed.
4585 * Return FALSE if the stream is EOS.
4590 gst_qtdemux_prepare_current_sample (GstQTDemux * qtdemux,
4591 QtDemuxStream * stream, gboolean * empty, guint64 * offset, guint * size,
4592 GstClockTime * dts, GstClockTime * pts, GstClockTime * duration,
4593 gboolean * keyframe)
4595 QtDemuxSample *sample;
4596 GstClockTime time_position;
4599 g_return_val_if_fail (stream != NULL, FALSE);
4601 time_position = stream->time_position;
4602 if (G_UNLIKELY (time_position == GST_CLOCK_TIME_NONE))
4605 seg_idx = stream->segment_index;
4606 if (G_UNLIKELY (seg_idx == -1)) {
4607 /* find segment corresponding to time_position if we are looking
4609 seg_idx = gst_qtdemux_find_segment (qtdemux, stream, time_position);
4612 /* different segment, activate it, sample_index will be set. */
4613 if (G_UNLIKELY (stream->segment_index != seg_idx))
4614 gst_qtdemux_activate_segment (qtdemux, stream, seg_idx, time_position);
4616 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (&stream->segments[stream->
4618 QtDemuxSegment *seg = &stream->segments[stream->segment_index];
4620 GST_LOG_OBJECT (qtdemux, "Empty segment activated,"
4621 " prepare empty sample");
4624 *pts = *dts = time_position;
4625 *duration = seg->duration - (time_position - seg->time);
4632 if (stream->sample_index == -1)
4633 stream->sample_index = 0;
4635 GST_LOG_OBJECT (qtdemux, "segment active, index = %u of %u",
4636 stream->sample_index, stream->n_samples);
4638 if (G_UNLIKELY (stream->sample_index >= stream->n_samples)) {
4639 if (!qtdemux->fragmented)
4642 GST_INFO_OBJECT (qtdemux, "out of samples, trying to add more");
4646 GST_OBJECT_LOCK (qtdemux);
4647 flow = qtdemux_add_fragmented_samples (qtdemux);
4648 GST_OBJECT_UNLOCK (qtdemux);
4650 if (flow != GST_FLOW_OK)
4653 while (stream->sample_index >= stream->n_samples);
4656 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
4657 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
4658 stream->sample_index);
4662 /* now get the info for the sample we're at */
4663 sample = &stream->samples[stream->sample_index];
4665 *dts = QTSAMPLE_DTS (stream, sample);
4666 *pts = QTSAMPLE_PTS (stream, sample);
4667 *offset = sample->offset;
4668 *size = sample->size;
4669 *duration = QTSAMPLE_DUR_DTS (stream, sample, *dts);
4670 *keyframe = QTSAMPLE_KEYFRAME (stream, sample);
4677 stream->time_position = GST_CLOCK_TIME_NONE;
4682 /* move to the next sample in @stream.
4684 * Moves to the next segment when needed.
4687 gst_qtdemux_advance_sample (GstQTDemux * qtdemux, QtDemuxStream * stream)
4689 QtDemuxSample *sample;
4690 QtDemuxSegment *segment;
4692 /* get current segment */
4693 segment = &stream->segments[stream->segment_index];
4695 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
4696 GST_DEBUG_OBJECT (qtdemux, "Empty segment, no samples to advance");
4700 if (G_UNLIKELY (stream->sample_index >= stream->to_sample)) {
4701 /* Mark the stream as EOS */
4702 GST_DEBUG_OBJECT (qtdemux,
4703 "reached max allowed sample %u, mark EOS", stream->to_sample);
4704 stream->time_position = GST_CLOCK_TIME_NONE;
4708 /* move to next sample */
4709 stream->sample_index++;
4710 stream->offset_in_sample = 0;
4712 /* reached the last sample, we need the next segment */
4713 if (G_UNLIKELY (stream->sample_index >= stream->n_samples))
4716 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
4717 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
4718 stream->sample_index);
4722 /* get next sample */
4723 sample = &stream->samples[stream->sample_index];
4725 /* see if we are past the segment */
4726 if (G_UNLIKELY (QTSAMPLE_DTS (stream, sample) >= segment->media_stop))
4729 if (QTSAMPLE_DTS (stream, sample) >= segment->media_start) {
4730 /* inside the segment, update time_position, looks very familiar to
4731 * GStreamer segments, doesn't it? */
4732 stream->time_position =
4733 QTSAMPLE_DTS (stream, sample) - segment->media_start + segment->time;
4735 /* not yet in segment, time does not yet increment. This means
4736 * that we are still prerolling keyframes to the decoder so it can
4737 * decode the first sample of the segment. */
4738 stream->time_position = segment->time;
4742 /* move to the next segment */
4745 GST_DEBUG_OBJECT (qtdemux, "segment %d ended ", stream->segment_index);
4747 if (stream->segment_index == stream->n_segments - 1) {
4748 /* are we at the end of the last segment, we're EOS */
4749 stream->time_position = GST_CLOCK_TIME_NONE;
4751 /* else we're only at the end of the current segment */
4752 stream->time_position = segment->stop_time;
4754 /* make sure we select a new segment */
4756 /* accumulate previous segments */
4757 if (GST_CLOCK_TIME_IS_VALID (stream->segment.stop))
4758 stream->accumulated_base +=
4759 (stream->segment.stop -
4760 stream->segment.start) / ABS (stream->segment.rate);
4762 stream->segment_index = -1;
4767 gst_qtdemux_sync_streams (GstQTDemux * demux)
4771 if (demux->n_streams <= 1)
4774 for (i = 0; i < demux->n_streams; i++) {
4775 QtDemuxStream *stream;
4776 GstClockTime end_time;
4778 stream = demux->streams[i];
4783 /* TODO advance time on subtitle streams here, if any some day */
4785 /* some clips/trailers may have unbalanced streams at the end,
4786 * so send EOS on shorter stream to prevent stalling others */
4788 /* do not mess with EOS if SEGMENT seeking */
4789 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT)
4792 if (demux->pullbased) {
4793 /* loop mode is sample time based */
4794 if (!STREAM_IS_EOS (stream))
4797 /* push mode is byte position based */
4798 if (stream->n_samples &&
4799 stream->samples[stream->n_samples - 1].offset >= demux->offset)
4803 if (stream->sent_eos)
4806 /* only act if some gap */
4807 end_time = stream->segments[stream->n_segments - 1].stop_time;
4808 GST_LOG_OBJECT (demux, "current position: %" GST_TIME_FORMAT
4809 ", stream end: %" GST_TIME_FORMAT,
4810 GST_TIME_ARGS (demux->segment.position), GST_TIME_ARGS (end_time));
4811 if (GST_CLOCK_TIME_IS_VALID (end_time)
4812 && (end_time + 2 * GST_SECOND < demux->segment.position)) {
4813 GST_DEBUG_OBJECT (demux, "sending EOS for stream %s",
4814 GST_PAD_NAME (stream->pad));
4815 stream->sent_eos = TRUE;
4816 gst_pad_push_event (stream->pad, gst_event_new_eos ());
4821 /* EOS and NOT_LINKED need to be combined. This means that we return:
4823 * GST_FLOW_NOT_LINKED: when all pads NOT_LINKED.
4824 * GST_FLOW_EOS: when all pads EOS or NOT_LINKED.
4826 static GstFlowReturn
4827 gst_qtdemux_combine_flows (GstQTDemux * demux, QtDemuxStream * stream,
4830 GST_LOG_OBJECT (demux, "flow return: %s", gst_flow_get_name (ret));
4833 ret = gst_flow_combiner_update_pad_flow (demux->flowcombiner, stream->pad,
4836 ret = gst_flow_combiner_update_flow (demux->flowcombiner, ret);
4838 GST_LOG_OBJECT (demux, "combined flow return: %s", gst_flow_get_name (ret));
4842 /* the input buffer metadata must be writable. Returns NULL when the buffer is
4843 * completely clipped
4845 * Should be used only with raw buffers */
4847 gst_qtdemux_clip_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
4850 guint64 start, stop, cstart, cstop, diff;
4851 GstClockTime pts, duration;
4853 gint num_rate, denom_rate;
4858 osize = size = gst_buffer_get_size (buf);
4861 /* depending on the type, setup the clip parameters */
4862 if (stream->subtype == FOURCC_soun) {
4863 frame_size = stream->bytes_per_frame;
4864 num_rate = GST_SECOND;
4865 denom_rate = (gint) stream->rate;
4867 } else if (stream->subtype == FOURCC_vide) {
4869 num_rate = stream->fps_n;
4870 denom_rate = stream->fps_d;
4875 if (frame_size <= 0)
4876 goto bad_frame_size;
4878 /* we can only clip if we have a valid pts */
4879 pts = GST_BUFFER_PTS (buf);
4880 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (pts)))
4883 duration = GST_BUFFER_DURATION (buf);
4885 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (duration))) {
4887 gst_util_uint64_scale_int (size / frame_size, num_rate, denom_rate);
4891 stop = start + duration;
4893 if (G_UNLIKELY (!gst_segment_clip (&stream->segment,
4894 GST_FORMAT_TIME, start, stop, &cstart, &cstop)))
4897 /* see if some clipping happened */
4898 diff = cstart - start;
4904 /* bring clipped time to samples and to bytes */
4905 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
4908 GST_DEBUG_OBJECT (qtdemux,
4909 "clipping start to %" GST_TIME_FORMAT " %"
4910 G_GUINT64_FORMAT " bytes", GST_TIME_ARGS (cstart), diff);
4916 diff = stop - cstop;
4921 /* bring clipped time to samples and then to bytes */
4922 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
4924 GST_DEBUG_OBJECT (qtdemux,
4925 "clipping stop to %" GST_TIME_FORMAT " %" G_GUINT64_FORMAT
4926 " bytes", GST_TIME_ARGS (cstop), diff);
4931 if (offset != 0 || size != osize)
4932 gst_buffer_resize (buf, offset, size);
4934 GST_BUFFER_DTS (buf) = GST_CLOCK_TIME_NONE;
4935 GST_BUFFER_PTS (buf) = pts;
4936 GST_BUFFER_DURATION (buf) = duration;
4940 /* dropped buffer */
4943 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
4948 GST_DEBUG_OBJECT (qtdemux, "bad frame size");
4953 GST_DEBUG_OBJECT (qtdemux, "no pts on buffer");
4958 GST_DEBUG_OBJECT (qtdemux, "clipped buffer");
4959 gst_buffer_unref (buf);
4964 /* the input buffer metadata must be writable,
4965 * but time/duration etc not yet set and need not be preserved */
4967 gst_qtdemux_process_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
4974 /* not many cases for now */
4975 if (G_UNLIKELY (stream->fourcc == FOURCC_mp4s)) {
4976 /* send a one time dvd clut event */
4977 if (stream->pending_event && stream->pad)
4978 gst_pad_push_event (stream->pad, stream->pending_event);
4979 stream->pending_event = NULL;
4982 if (G_UNLIKELY (stream->subtype != FOURCC_text
4983 && stream->subtype != FOURCC_sbtl &&
4984 stream->subtype != FOURCC_subp)) {
4988 gst_buffer_map (buf, &map, GST_MAP_READ);
4990 /* empty buffer is sent to terminate previous subtitle */
4991 if (map.size <= 2) {
4992 gst_buffer_unmap (buf, &map);
4993 gst_buffer_unref (buf);
4996 if (stream->subtype == FOURCC_subp) {
4997 /* That's all the processing needed for subpictures */
4998 gst_buffer_unmap (buf, &map);
5002 nsize = GST_READ_UINT16_BE (map.data);
5003 nsize = MIN (nsize, map.size - 2);
5005 GST_LOG_OBJECT (qtdemux, "3GPP timed text subtitle: %d/%" G_GSIZE_FORMAT "",
5008 /* takes care of UTF-8 validation or UTF-16 recognition,
5009 * no other encoding expected */
5010 str = gst_tag_freeform_string_to_utf8 ((gchar *) map.data + 2, nsize, NULL);
5011 gst_buffer_unmap (buf, &map);
5013 gst_buffer_unref (buf);
5014 buf = _gst_buffer_new_wrapped (str, strlen (str), g_free);
5016 /* this should not really happen unless the subtitle is corrupted */
5017 gst_buffer_unref (buf);
5021 /* FIXME ? convert optional subsequent style info to markup */
5026 /* Sets a buffer's attributes properly and pushes it downstream.
5027 * Also checks for additional actions and custom processing that may
5028 * need to be done first.
5030 static GstFlowReturn
5031 gst_qtdemux_decorate_and_push_buffer (GstQTDemux * qtdemux,
5032 QtDemuxStream * stream, GstBuffer * buf,
5033 GstClockTime dts, GstClockTime pts, GstClockTime duration,
5034 gboolean keyframe, GstClockTime position, guint64 byte_position)
5036 GstFlowReturn ret = GST_FLOW_OK;
5038 /* offset the timestamps according to the edit list */
5040 if (G_UNLIKELY (stream->fourcc == FOURCC_rtsp)) {
5044 gst_buffer_map (buf, &map, GST_MAP_READ);
5045 url = g_strndup ((gchar *) map.data, map.size);
5046 gst_buffer_unmap (buf, &map);
5047 if (url != NULL && strlen (url) != 0) {
5048 /* we have RTSP redirect now */
5049 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
5050 gst_message_new_element (GST_OBJECT_CAST (qtdemux),
5051 gst_structure_new ("redirect",
5052 "new-location", G_TYPE_STRING, url, NULL)));
5053 qtdemux->posted_redirect = TRUE;
5055 GST_WARNING_OBJECT (qtdemux, "Redirect URI of stream is empty, not "
5061 /* position reporting */
5062 if (qtdemux->segment.rate >= 0) {
5063 qtdemux->segment.position = position;
5064 gst_qtdemux_sync_streams (qtdemux);
5067 if (G_UNLIKELY (!stream->pad)) {
5068 GST_DEBUG_OBJECT (qtdemux, "No output pad for stream, ignoring");
5069 gst_buffer_unref (buf);
5073 /* send out pending buffers */
5074 while (stream->buffers) {
5075 GstBuffer *buffer = (GstBuffer *) stream->buffers->data;
5077 if (G_UNLIKELY (stream->discont)) {
5078 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
5079 GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
5080 stream->discont = FALSE;
5082 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
5085 gst_pad_push (stream->pad, buffer);
5087 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
5090 /* we're going to modify the metadata */
5091 buf = gst_buffer_make_writable (buf);
5093 if (G_UNLIKELY (stream->need_process))
5094 buf = gst_qtdemux_process_buffer (qtdemux, stream, buf);
5100 GST_BUFFER_DTS (buf) = dts;
5101 GST_BUFFER_PTS (buf) = pts;
5102 GST_BUFFER_DURATION (buf) = duration;
5103 GST_BUFFER_OFFSET (buf) = -1;
5104 GST_BUFFER_OFFSET_END (buf) = -1;
5106 if (G_UNLIKELY (stream->rgb8_palette))
5107 gst_buffer_append_memory (buf, gst_memory_ref (stream->rgb8_palette));
5109 if (G_UNLIKELY (stream->padding)) {
5110 gst_buffer_resize (buf, stream->padding, -1);
5113 if (G_UNLIKELY (qtdemux->element_index)) {
5114 GstClockTime stream_time;
5117 gst_segment_to_stream_time (&stream->segment, GST_FORMAT_TIME,
5119 if (GST_CLOCK_TIME_IS_VALID (stream_time)) {
5120 GST_LOG_OBJECT (qtdemux,
5121 "adding association %" GST_TIME_FORMAT "-> %"
5122 G_GUINT64_FORMAT, GST_TIME_ARGS (stream_time), byte_position);
5123 gst_index_add_association (qtdemux->element_index,
5125 keyframe ? GST_ASSOCIATION_FLAG_KEY_UNIT :
5126 GST_ASSOCIATION_FLAG_DELTA_UNIT, GST_FORMAT_TIME, stream_time,
5127 GST_FORMAT_BYTES, byte_position, NULL);
5132 if (stream->need_clip)
5133 buf = gst_qtdemux_clip_buffer (qtdemux, stream, buf);
5135 if (G_UNLIKELY (buf == NULL))
5138 if (G_UNLIKELY (stream->discont)) {
5139 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
5140 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
5141 stream->discont = FALSE;
5143 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
5147 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
5148 stream->on_keyframe = FALSE;
5150 stream->on_keyframe = TRUE;
5154 GST_LOG_OBJECT (qtdemux,
5155 "Pushing buffer with dts %" GST_TIME_FORMAT ", pts %" GST_TIME_FORMAT
5156 ", duration %" GST_TIME_FORMAT " on pad %s", GST_TIME_ARGS (dts),
5157 GST_TIME_ARGS (pts), GST_TIME_ARGS (duration),
5158 GST_PAD_NAME (stream->pad));
5160 if (stream->protected && stream->protection_scheme_type == FOURCC_cenc) {
5161 GstStructure *crypto_info;
5162 QtDemuxCencSampleSetInfo *info =
5163 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
5167 while ((event = g_queue_pop_head (&stream->protection_scheme_event_queue))) {
5168 gst_pad_push_event (stream->pad, event);
5171 if (qtdemux->cenc_aux_info_offset > 0 && info->crypto_info == NULL) {
5172 GST_DEBUG_OBJECT (qtdemux, "cenc metadata hasn't been parsed yet");
5173 gst_buffer_unref (buf);
5177 index = stream->sample_index - (stream->n_samples - info->crypto_info->len);
5178 if (G_LIKELY (index >= 0 && index < info->crypto_info->len)) {
5179 /* steal structure from array */
5180 crypto_info = g_ptr_array_index (info->crypto_info, index);
5181 g_ptr_array_index (info->crypto_info, index) = NULL;
5182 GST_LOG_OBJECT (qtdemux, "attaching cenc metadata [%u]", index);
5183 if (!crypto_info || !gst_buffer_add_protection_meta (buf, crypto_info))
5184 GST_ERROR_OBJECT (qtdemux, "failed to attach cenc metadata to buffer");
5188 ret = gst_pad_push (stream->pad, buf);
5190 if (GST_CLOCK_TIME_IS_VALID (pts) && GST_CLOCK_TIME_IS_VALID (duration)) {
5191 /* mark position in stream, we'll need this to know when to send GAP event */
5192 stream->segment.position = pts + duration;
5199 static const QtDemuxRandomAccessEntry *
5200 gst_qtdemux_stream_seek_fragment (GstQTDemux * qtdemux, QtDemuxStream * stream,
5201 GstClockTime pos, gboolean after)
5203 QtDemuxRandomAccessEntry *entries = stream->ra_entries;
5204 guint n_entries = stream->n_ra_entries;
5207 /* we assume the table is sorted */
5208 for (i = 0; i < n_entries; ++i) {
5209 if (entries[i].ts > pos)
5213 /* FIXME: maybe save first moof_offset somewhere instead, but for now it's
5214 * probably okay to assume that the index lists the very first fragment */
5221 return &entries[i - 1];
5225 gst_qtdemux_do_fragmented_seek (GstQTDemux * qtdemux)
5227 const QtDemuxRandomAccessEntry *best_entry = NULL;
5230 GST_OBJECT_LOCK (qtdemux);
5232 g_assert (qtdemux->n_streams > 0);
5234 for (i = 0; i < qtdemux->n_streams; i++) {
5235 const QtDemuxRandomAccessEntry *entry;
5236 QtDemuxStream *stream;
5237 gboolean is_audio_or_video;
5239 stream = qtdemux->streams[i];
5241 g_free (stream->samples);
5242 stream->samples = NULL;
5243 stream->n_samples = 0;
5244 stream->stbl_index = -1; /* no samples have yet been parsed */
5245 stream->sample_index = -1;
5247 if (stream->ra_entries == NULL)
5250 if (stream->subtype == FOURCC_vide || stream->subtype == FOURCC_soun)
5251 is_audio_or_video = TRUE;
5253 is_audio_or_video = FALSE;
5256 gst_qtdemux_stream_seek_fragment (qtdemux, stream,
5257 stream->time_position, !is_audio_or_video);
5259 GST_INFO_OBJECT (stream->pad, "%" GST_TIME_FORMAT " at offset "
5260 "%" G_GUINT64_FORMAT, GST_TIME_ARGS (entry->ts), entry->moof_offset);
5262 stream->pending_seek = entry;
5264 /* decide position to jump to just based on audio/video tracks, not subs */
5265 if (!is_audio_or_video)
5268 if (best_entry == NULL || entry->moof_offset < best_entry->moof_offset)
5272 if (best_entry == NULL) {
5273 GST_OBJECT_UNLOCK (qtdemux);
5277 GST_INFO_OBJECT (qtdemux, "seek to %" GST_TIME_FORMAT ", best fragment "
5278 "moof offset: %" G_GUINT64_FORMAT ", ts %" GST_TIME_FORMAT,
5279 GST_TIME_ARGS (qtdemux->streams[0]->time_position),
5280 best_entry->moof_offset, GST_TIME_ARGS (best_entry->ts));
5282 qtdemux->moof_offset = best_entry->moof_offset;
5284 qtdemux_add_fragmented_samples (qtdemux);
5286 GST_OBJECT_UNLOCK (qtdemux);
5290 static GstFlowReturn
5291 gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux)
5293 GstFlowReturn ret = GST_FLOW_OK;
5294 GstBuffer *buf = NULL;
5295 QtDemuxStream *stream;
5296 GstClockTime min_time;
5298 GstClockTime dts = GST_CLOCK_TIME_NONE;
5299 GstClockTime pts = GST_CLOCK_TIME_NONE;
5300 GstClockTime duration = 0;
5301 gboolean keyframe = FALSE;
5302 guint sample_size = 0;
5308 gst_qtdemux_push_pending_newsegment (qtdemux);
5310 if (qtdemux->fragmented_seek_pending) {
5311 GST_INFO_OBJECT (qtdemux, "pending fragmented seek");
5312 gst_qtdemux_do_fragmented_seek (qtdemux);
5313 GST_INFO_OBJECT (qtdemux, "fragmented seek done!");
5314 qtdemux->fragmented_seek_pending = FALSE;
5317 /* Figure out the next stream sample to output, min_time is expressed in
5318 * global time and runs over the edit list segments. */
5319 min_time = G_MAXUINT64;
5321 for (i = 0; i < qtdemux->n_streams; i++) {
5322 GstClockTime position;
5324 stream = qtdemux->streams[i];
5325 position = stream->time_position;
5327 /* position of -1 is EOS */
5328 if (position != GST_CLOCK_TIME_NONE && position < min_time) {
5329 min_time = position;
5334 if (G_UNLIKELY (index == -1)) {
5335 GST_DEBUG_OBJECT (qtdemux, "all streams are EOS");
5339 /* check for segment end */
5340 if (G_UNLIKELY (qtdemux->segment.stop != -1
5341 && ((qtdemux->segment.rate >= 0 && qtdemux->segment.stop <= min_time)
5342 || (qtdemux->segment.rate < 0
5343 && qtdemux->segment.start > min_time))
5344 && qtdemux->streams[index]->on_keyframe)) {
5345 GST_DEBUG_OBJECT (qtdemux, "we reached the end of our segment.");
5346 qtdemux->streams[index]->time_position = GST_CLOCK_TIME_NONE;
5350 /* gap events for subtitle streams */
5351 for (i = 0; i < qtdemux->n_streams; i++) {
5352 stream = qtdemux->streams[i];
5353 if (stream->pad && (stream->subtype == FOURCC_subp
5354 || stream->subtype == FOURCC_text
5355 || stream->subtype == FOURCC_sbtl)) {
5356 /* send one second gap events until the stream catches up */
5357 /* gaps can only be sent after segment is activated (segment.stop is no longer -1) */
5358 while (GST_CLOCK_TIME_IS_VALID (stream->segment.stop) &&
5359 GST_CLOCK_TIME_IS_VALID (stream->segment.position) &&
5360 stream->segment.position + GST_SECOND < min_time) {
5362 gst_event_new_gap (stream->segment.position, GST_SECOND);
5363 gst_pad_push_event (stream->pad, gap);
5364 stream->segment.position += GST_SECOND;
5369 stream = qtdemux->streams[index];
5370 if (stream->new_caps) {
5371 gst_qtdemux_configure_stream (qtdemux, stream);
5372 qtdemux_do_allocation (qtdemux, stream);
5375 /* fetch info for the current sample of this stream */
5376 if (G_UNLIKELY (!gst_qtdemux_prepare_current_sample (qtdemux, stream, &empty,
5377 &offset, &sample_size, &dts, &pts, &duration, &keyframe)))
5380 /* If we're doing a keyframe-only trickmode, only push keyframes on video streams */
5381 if (G_UNLIKELY (qtdemux->
5382 segment.flags & GST_SEGMENT_FLAG_TRICKMODE_KEY_UNITS)) {
5383 if (stream->subtype == FOURCC_vide && !keyframe) {
5384 GST_LOG_OBJECT (qtdemux, "Skipping non-keyframe on stream %d", index);
5389 GST_DEBUG_OBJECT (qtdemux,
5390 "pushing from stream %d, empty %d offset %" G_GUINT64_FORMAT
5391 ", size %d, dts=%" GST_TIME_FORMAT ", pts=%" GST_TIME_FORMAT
5392 ", duration %" GST_TIME_FORMAT, index, empty, offset, sample_size,
5393 GST_TIME_ARGS (dts), GST_TIME_ARGS (pts), GST_TIME_ARGS (duration));
5395 if (G_UNLIKELY (empty)) {
5396 /* empty segment, push a gap and move to the next one */
5397 gst_pad_push_event (stream->pad, gst_event_new_gap (pts, duration));
5398 stream->segment.position = pts + duration;
5402 /* hmm, empty sample, skip and move to next sample */
5403 if (G_UNLIKELY (sample_size <= 0))
5406 /* last pushed sample was out of boundary, goto next sample */
5407 if (G_UNLIKELY (GST_PAD_LAST_FLOW_RETURN (stream->pad) == GST_FLOW_EOS))
5410 if (stream->max_buffer_size == 0 || sample_size <= stream->max_buffer_size) {
5413 GST_DEBUG_OBJECT (qtdemux,
5414 "size %d larger than stream max_buffer_size %d, trimming",
5415 sample_size, stream->max_buffer_size);
5417 MIN (sample_size - stream->offset_in_sample, stream->max_buffer_size);
5420 if (qtdemux->cenc_aux_info_offset > 0) {
5423 GstBuffer *aux_info = NULL;
5425 /* pull the data stored before the sample */
5427 gst_qtdemux_pull_atom (qtdemux, qtdemux->offset,
5428 offset + stream->offset_in_sample - qtdemux->offset, &aux_info);
5429 if (G_UNLIKELY (ret != GST_FLOW_OK))
5431 gst_buffer_map (aux_info, &map, GST_MAP_READ);
5432 GST_DEBUG_OBJECT (qtdemux, "parsing cenc auxiliary info");
5433 gst_byte_reader_init (&br, map.data + 8, map.size);
5434 if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
5435 qtdemux->cenc_aux_info_sizes, qtdemux->cenc_aux_sample_count)) {
5436 GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
5437 gst_buffer_unmap (aux_info, &map);
5438 gst_buffer_unref (aux_info);
5439 ret = GST_FLOW_ERROR;
5442 gst_buffer_unmap (aux_info, &map);
5443 gst_buffer_unref (aux_info);
5446 GST_LOG_OBJECT (qtdemux, "reading %d bytes @ %" G_GUINT64_FORMAT, size,
5449 if (stream->use_allocator) {
5450 /* if we have a per-stream allocator, use it */
5451 buf = gst_buffer_new_allocate (stream->allocator, size, &stream->params);
5454 ret = gst_qtdemux_pull_atom (qtdemux, offset + stream->offset_in_sample,
5456 if (G_UNLIKELY (ret != GST_FLOW_OK))
5459 if (size != sample_size) {
5460 pts += gst_util_uint64_scale_int (GST_SECOND,
5461 stream->offset_in_sample / stream->bytes_per_frame, stream->timescale);
5462 dts += gst_util_uint64_scale_int (GST_SECOND,
5463 stream->offset_in_sample / stream->bytes_per_frame, stream->timescale);
5464 duration = gst_util_uint64_scale_int (GST_SECOND,
5465 size / stream->bytes_per_frame, stream->timescale);
5468 ret = gst_qtdemux_decorate_and_push_buffer (qtdemux, stream, buf,
5469 dts, pts, duration, keyframe, min_time, offset);
5471 if (size != sample_size) {
5472 QtDemuxSample *sample = &stream->samples[stream->sample_index];
5473 QtDemuxSegment *segment = &stream->segments[stream->segment_index];
5475 GstClockTime time_position = QTSTREAMTIME_TO_GSTTIME (stream,
5476 sample->timestamp + stream->offset_in_sample / stream->bytes_per_frame);
5477 if (time_position >= segment->media_start) {
5478 /* inside the segment, update time_position, looks very familiar to
5479 * GStreamer segments, doesn't it? */
5480 stream->time_position = (time_position - segment->media_start) +
5483 /* not yet in segment, time does not yet increment. This means
5484 * that we are still prerolling keyframes to the decoder so it can
5485 * decode the first sample of the segment. */
5486 stream->time_position = segment->time;
5491 ret = gst_qtdemux_combine_flows (qtdemux, stream, ret);
5492 /* ignore unlinked, we will not push on the pad anymore and we will EOS when
5493 * we have no more data for the pad to push */
5494 if (ret == GST_FLOW_EOS)
5497 stream->offset_in_sample += size;
5498 if (stream->offset_in_sample >= sample_size) {
5499 gst_qtdemux_advance_sample (qtdemux, stream);
5504 gst_qtdemux_advance_sample (qtdemux, stream);
5512 GST_DEBUG_OBJECT (qtdemux, "No samples left for any streams - EOS");
5518 GST_DEBUG_OBJECT (qtdemux, "No samples left for stream");
5519 /* EOS will be raised if all are EOS */
5526 gst_qtdemux_loop (GstPad * pad)
5528 GstQTDemux *qtdemux;
5532 qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
5534 cur_offset = qtdemux->offset;
5535 GST_LOG_OBJECT (qtdemux, "loop at position %" G_GUINT64_FORMAT ", state %d",
5536 cur_offset, qtdemux->state);
5538 switch (qtdemux->state) {
5539 case QTDEMUX_STATE_INITIAL:
5540 case QTDEMUX_STATE_HEADER:
5541 ret = gst_qtdemux_loop_state_header (qtdemux);
5543 case QTDEMUX_STATE_MOVIE:
5544 ret = gst_qtdemux_loop_state_movie (qtdemux);
5545 if (qtdemux->segment.rate < 0 && ret == GST_FLOW_EOS) {
5546 ret = gst_qtdemux_seek_to_previous_keyframe (qtdemux);
5554 /* if something went wrong, pause */
5555 if (ret != GST_FLOW_OK)
5559 gst_object_unref (qtdemux);
5565 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
5566 (NULL), ("streaming stopped, invalid state"));
5567 gst_pad_pause_task (pad);
5568 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
5573 const gchar *reason = gst_flow_get_name (ret);
5575 GST_LOG_OBJECT (qtdemux, "pausing task, reason %s", reason);
5577 gst_pad_pause_task (pad);
5579 /* fatal errors need special actions */
5581 if (ret == GST_FLOW_EOS) {
5582 if (qtdemux->n_streams == 0) {
5583 /* we have no streams, post an error */
5584 gst_qtdemux_post_no_playable_stream_error (qtdemux);
5586 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
5589 if ((stop = qtdemux->segment.stop) == -1)
5590 stop = qtdemux->segment.duration;
5592 if (qtdemux->segment.rate >= 0) {
5593 GST_LOG_OBJECT (qtdemux, "Sending segment done, at end of segment");
5594 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
5595 gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
5596 GST_FORMAT_TIME, stop));
5597 gst_qtdemux_push_event (qtdemux,
5598 gst_event_new_segment_done (GST_FORMAT_TIME, stop));
5600 /* For Reverse Playback */
5601 GST_LOG_OBJECT (qtdemux, "Sending segment done, at start of segment");
5602 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
5603 gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
5604 GST_FORMAT_TIME, qtdemux->segment.start));
5605 gst_qtdemux_push_event (qtdemux,
5606 gst_event_new_segment_done (GST_FORMAT_TIME,
5607 qtdemux->segment.start));
5610 GST_LOG_OBJECT (qtdemux, "Sending EOS at end of segment");
5611 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
5613 } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
5614 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
5615 (NULL), ("streaming stopped, reason %s", reason));
5616 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
5625 * Returns if there are samples to be played.
5628 has_next_entry (GstQTDemux * demux)
5630 QtDemuxStream *stream;
5633 GST_DEBUG_OBJECT (demux, "Checking if there are samples not played yet");
5635 for (i = 0; i < demux->n_streams; i++) {
5636 stream = demux->streams[i];
5638 if (stream->sample_index == -1) {
5639 stream->sample_index = 0;
5640 stream->offset_in_sample = 0;
5643 if (stream->sample_index >= stream->n_samples) {
5644 GST_LOG_OBJECT (demux, "stream %d samples exhausted", i);
5647 GST_DEBUG_OBJECT (demux, "Found a sample");
5651 GST_DEBUG_OBJECT (demux, "There wasn't any next sample");
5658 * Returns the size of the first entry at the current offset.
5659 * If -1, there are none (which means EOS or empty file).
5662 next_entry_size (GstQTDemux * demux)
5664 QtDemuxStream *stream;
5667 guint64 smalloffs = (guint64) - 1;
5668 QtDemuxSample *sample;
5670 GST_LOG_OBJECT (demux, "Finding entry at offset %" G_GUINT64_FORMAT,
5673 for (i = 0; i < demux->n_streams; i++) {
5674 stream = demux->streams[i];
5676 if (stream->sample_index == -1) {
5677 stream->sample_index = 0;
5678 stream->offset_in_sample = 0;
5681 if (stream->sample_index >= stream->n_samples) {
5682 GST_LOG_OBJECT (demux, "stream %d samples exhausted", i);
5686 if (!qtdemux_parse_samples (demux, stream, stream->sample_index)) {
5687 GST_LOG_OBJECT (demux, "Parsing of index %u from stbl atom failed!",
5688 stream->sample_index);
5692 sample = &stream->samples[stream->sample_index];
5694 GST_LOG_OBJECT (demux,
5695 "Checking Stream %d (sample_index:%d / offset:%" G_GUINT64_FORMAT
5696 " / size:%" G_GUINT32_FORMAT ")", i, stream->sample_index,
5697 sample->offset, sample->size);
5699 if (((smalloffs == -1)
5700 || (sample->offset < smalloffs)) && (sample->size)) {
5702 smalloffs = sample->offset;
5706 GST_LOG_OBJECT (demux,
5707 "stream %d offset %" G_GUINT64_FORMAT " demux->offset :%"
5708 G_GUINT64_FORMAT, smallidx, smalloffs, demux->offset);
5713 stream = demux->streams[smallidx];
5714 sample = &stream->samples[stream->sample_index];
5716 if (sample->offset >= demux->offset) {
5717 demux->todrop = sample->offset - demux->offset;
5718 return sample->size + demux->todrop;
5721 GST_DEBUG_OBJECT (demux,
5722 "There wasn't any entry at offset %" G_GUINT64_FORMAT, demux->offset);
5727 gst_qtdemux_post_progress (GstQTDemux * demux, gint num, gint denom)
5729 gint perc = (gint) ((gdouble) num * 100.0 / (gdouble) denom);
5731 gst_element_post_message (GST_ELEMENT_CAST (demux),
5732 gst_message_new_element (GST_OBJECT_CAST (demux),
5733 gst_structure_new ("progress", "percent", G_TYPE_INT, perc, NULL)));
5737 qtdemux_seek_offset (GstQTDemux * demux, guint64 offset)
5742 GST_DEBUG_OBJECT (demux, "Seeking to %" G_GUINT64_FORMAT, offset);
5745 gst_event_new_seek (1.0, GST_FORMAT_BYTES,
5746 GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset,
5747 GST_SEEK_TYPE_NONE, -1);
5749 /* store seqnum to drop flush events, they don't need to reach downstream */
5750 demux->offset_seek_seqnum = gst_event_get_seqnum (event);
5751 res = gst_pad_push_event (demux->sinkpad, event);
5752 demux->offset_seek_seqnum = 0;
5757 /* check for seekable upstream, above and beyond a mere query */
5759 gst_qtdemux_check_seekability (GstQTDemux * demux)
5762 gboolean seekable = FALSE;
5763 gint64 start = -1, stop = -1;
5765 if (demux->upstream_size)
5768 query = gst_query_new_seeking (GST_FORMAT_BYTES);
5769 if (!gst_pad_peer_query (demux->sinkpad, query)) {
5770 GST_DEBUG_OBJECT (demux, "seeking query failed");
5774 gst_query_parse_seeking (query, NULL, &seekable, &start, &stop);
5776 /* try harder to query upstream size if we didn't get it the first time */
5777 if (seekable && stop == -1) {
5778 GST_DEBUG_OBJECT (demux, "doing duration query to fix up unset stop");
5779 gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &stop);
5782 /* if upstream doesn't know the size, it's likely that it's not seekable in
5783 * practice even if it technically may be seekable */
5784 if (seekable && (start != 0 || stop <= start)) {
5785 GST_DEBUG_OBJECT (demux, "seekable but unknown start/stop -> disable");
5790 gst_query_unref (query);
5792 GST_DEBUG_OBJECT (demux, "seekable: %d (%" G_GUINT64_FORMAT " - %"
5793 G_GUINT64_FORMAT ")", seekable, start, stop);
5794 demux->upstream_seekable = seekable;
5795 demux->upstream_size = seekable ? stop : -1;
5799 gst_qtdemux_drop_data (GstQTDemux * demux, gint bytes)
5801 g_return_if_fail (bytes <= demux->todrop);
5803 GST_LOG_OBJECT (demux, "Dropping %d bytes", bytes);
5804 gst_adapter_flush (demux->adapter, bytes);
5805 demux->neededbytes -= bytes;
5806 demux->offset += bytes;
5807 demux->todrop -= bytes;
5811 gst_qtdemux_check_send_pending_segment (GstQTDemux * demux)
5813 if (G_UNLIKELY (demux->pending_newsegment)) {
5816 gst_qtdemux_push_pending_newsegment (demux);
5817 /* clear to send tags on all streams */
5818 for (i = 0; i < demux->n_streams; i++) {
5819 QtDemuxStream *stream;
5820 stream = demux->streams[i];
5821 gst_qtdemux_push_tags (demux, stream);
5822 if (stream->sparse) {
5823 GST_INFO_OBJECT (demux, "Sending gap event on stream %d", i);
5824 gst_pad_push_event (stream->pad,
5825 gst_event_new_gap (stream->segment.position, GST_CLOCK_TIME_NONE));
5832 gst_qtdemux_stream_send_initial_gap_segments (GstQTDemux * demux,
5833 QtDemuxStream * stream)
5837 /* Push any initial gap segments before proceeding to the
5839 for (i = 0; i < stream->n_segments; i++) {
5840 gst_qtdemux_activate_segment (demux, stream, i, stream->time_position);
5842 if (QTSEGMENT_IS_EMPTY (&stream->segments[i])) {
5843 GstClockTime ts, dur;
5846 ts = stream->time_position;
5848 stream->segments[i].duration - (stream->time_position -
5849 stream->segments[i].time);
5850 gap = gst_event_new_gap (ts, dur);
5851 stream->time_position += dur;
5853 GST_DEBUG_OBJECT (stream->pad, "Pushing gap for empty "
5854 "segment: %" GST_PTR_FORMAT, gap);
5855 gst_pad_push_event (stream->pad, gap);
5857 /* Only support empty segment at the beginning followed by
5858 * one non-empty segment, this was checked when parsing the
5859 * edts atom, arriving here is unexpected */
5860 g_assert (i + 1 == stream->n_segments);
5866 static GstFlowReturn
5867 gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent, GstBuffer * inbuf)
5871 demux = GST_QTDEMUX (parent);
5873 if (GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_DISCONT)) {
5876 GST_DEBUG_OBJECT (demux, "Got DISCONT, marking all streams as DISCONT");
5878 for (i = 0; i < demux->n_streams; i++) {
5879 demux->streams[i]->discont = TRUE;
5882 /* Reverse fragmented playback, need to flush all we have before
5883 * consuming a new fragment.
5884 * The samples array have the timestamps calculated by accumulating the
5885 * durations but this won't work for reverse playback of fragments as
5886 * the timestamps of a subsequent fragment should be smaller than the
5887 * previously received one. */
5888 if (demux->fragmented && demux->segment.rate < 0) {
5889 gst_qtdemux_process_adapter (demux, TRUE);
5890 for (i = 0; i < demux->n_streams; i++)
5891 gst_qtdemux_stream_flush_samples_data (demux, demux->streams[i]);
5895 gst_adapter_push (demux->adapter, inbuf);
5897 GST_DEBUG_OBJECT (demux,
5898 "pushing in inbuf %p, neededbytes:%u, available:%" G_GSIZE_FORMAT, inbuf,
5899 demux->neededbytes, gst_adapter_available (demux->adapter));
5901 return gst_qtdemux_process_adapter (demux, FALSE);
5904 static GstFlowReturn
5905 gst_qtdemux_process_adapter (GstQTDemux * demux, gboolean force)
5907 GstFlowReturn ret = GST_FLOW_OK;
5909 /* we never really mean to buffer that much */
5910 if (demux->neededbytes == -1) {
5914 while (((gst_adapter_available (demux->adapter)) >= demux->neededbytes) &&
5915 (ret == GST_FLOW_OK || (ret == GST_FLOW_NOT_LINKED && force))) {
5917 GST_DEBUG_OBJECT (demux,
5918 "state:%d , demux->neededbytes:%d, demux->offset:%" G_GUINT64_FORMAT,
5919 demux->state, demux->neededbytes, demux->offset);
5921 switch (demux->state) {
5922 case QTDEMUX_STATE_INITIAL:{
5927 gst_qtdemux_check_seekability (demux);
5929 data = gst_adapter_map (demux->adapter, demux->neededbytes);
5931 /* get fourcc/length, set neededbytes */
5932 extract_initial_length_and_fourcc ((guint8 *) data, demux->neededbytes,
5934 gst_adapter_unmap (demux->adapter);
5936 GST_DEBUG_OBJECT (demux, "Peeking found [%" GST_FOURCC_FORMAT "] "
5937 "size: %" G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), size);
5939 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
5940 (_("This file is invalid and cannot be played.")),
5941 ("initial atom '%" GST_FOURCC_FORMAT "' has empty length",
5942 GST_FOURCC_ARGS (fourcc)));
5943 ret = GST_FLOW_ERROR;
5946 if (fourcc == FOURCC_mdat) {
5947 gint next_entry = next_entry_size (demux);
5948 if (demux->n_streams > 0 && (next_entry != -1 || !demux->fragmented)) {
5949 /* we have the headers, start playback */
5950 demux->state = QTDEMUX_STATE_MOVIE;
5951 demux->neededbytes = next_entry;
5952 demux->mdatleft = size;
5954 /* no headers yet, try to get them */
5957 guint64 old, target;
5960 old = demux->offset;
5961 target = old + size;
5963 /* try to jump over the atom with a seek */
5964 /* only bother if it seems worth doing so,
5965 * and avoids possible upstream/server problems */
5966 if (demux->upstream_seekable &&
5967 demux->upstream_size > 4 * (1 << 20)) {
5968 res = qtdemux_seek_offset (demux, target);
5970 GST_DEBUG_OBJECT (demux, "skipping seek");
5975 GST_DEBUG_OBJECT (demux, "seek success");
5976 /* remember the offset fo the first mdat so we can seek back to it
5977 * after we have the headers */
5978 if (fourcc == FOURCC_mdat && demux->first_mdat == -1) {
5979 demux->first_mdat = old;
5980 GST_DEBUG_OBJECT (demux, "first mdat at %" G_GUINT64_FORMAT,
5983 /* seek worked, continue reading */
5984 demux->offset = target;
5985 demux->neededbytes = 16;
5986 demux->state = QTDEMUX_STATE_INITIAL;
5988 /* seek failed, need to buffer */
5989 demux->offset = old;
5990 GST_DEBUG_OBJECT (demux, "seek failed/skipped");
5991 /* there may be multiple mdat (or alike) buffers */
5993 if (demux->mdatbuffer)
5994 bs = gst_buffer_get_size (demux->mdatbuffer);
5997 if (size + bs > 10 * (1 << 20))
5999 demux->state = QTDEMUX_STATE_BUFFER_MDAT;
6000 demux->neededbytes = size;
6001 if (!demux->mdatbuffer)
6002 demux->mdatoffset = demux->offset;
6005 } else if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
6006 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
6007 (_("This file is invalid and cannot be played.")),
6008 ("atom %" GST_FOURCC_FORMAT " has bogus size %" G_GUINT64_FORMAT,
6009 GST_FOURCC_ARGS (fourcc), size));
6010 ret = GST_FLOW_ERROR;
6013 /* this means we already started buffering and still no moov header,
6014 * let's continue buffering everything till we get moov */
6015 if (demux->mdatbuffer && !(fourcc == FOURCC_moov
6016 || fourcc == FOURCC_moof))
6018 demux->neededbytes = size;
6019 demux->state = QTDEMUX_STATE_HEADER;
6023 case QTDEMUX_STATE_HEADER:{
6027 GST_DEBUG_OBJECT (demux, "In header");
6029 data = gst_adapter_map (demux->adapter, demux->neededbytes);
6031 /* parse the header */
6032 extract_initial_length_and_fourcc (data, demux->neededbytes, NULL,
6034 if (fourcc == FOURCC_moov) {
6037 /* in usual fragmented setup we could try to scan for more
6038 * and end up at the the moov (after mdat) again */
6039 if (demux->got_moov && demux->n_streams > 0 &&
6041 || demux->last_moov_offset == demux->offset)) {
6042 GST_DEBUG_OBJECT (demux,
6043 "Skipping moov atom as we have (this) one already");
6045 GST_DEBUG_OBJECT (demux, "Parsing [moov]");
6047 if (demux->got_moov && demux->fragmented) {
6048 GST_DEBUG_OBJECT (demux,
6049 "Got a second moov, clean up data from old one");
6050 if (demux->moov_node)
6051 g_node_destroy (demux->moov_node);
6052 demux->moov_node = NULL;
6053 demux->moov_node_compressed = NULL;
6055 /* prepare newsegment to send when streaming actually starts */
6056 if (!demux->pending_newsegment)
6057 demux->pending_newsegment =
6058 gst_event_new_segment (&demux->segment);
6061 demux->last_moov_offset = demux->offset;
6063 qtdemux_parse_moov (demux, data, demux->neededbytes);
6064 qtdemux_node_dump (demux, demux->moov_node);
6065 qtdemux_parse_tree (demux);
6066 qtdemux_prepare_streams (demux);
6067 if (!demux->got_moov)
6068 qtdemux_expose_streams (demux);
6071 for (n = 0; n < demux->n_streams; n++) {
6072 QtDemuxStream *stream = demux->streams[n];
6074 gst_qtdemux_configure_stream (demux, stream);
6078 demux->got_moov = TRUE;
6079 gst_qtdemux_check_send_pending_segment (demux);
6081 /* fragmented streams headers shouldn't contain edts atoms */
6082 if (!demux->fragmented) {
6083 for (n = 0; n < demux->n_streams; n++) {
6084 gst_qtdemux_stream_send_initial_gap_segments (demux,
6089 g_node_destroy (demux->moov_node);
6090 demux->moov_node = NULL;
6091 GST_DEBUG_OBJECT (demux, "Finished parsing the header");
6093 } else if (fourcc == FOURCC_moof) {
6094 if ((demux->got_moov || demux->media_caps) && demux->fragmented) {
6096 GstClockTime prev_pts;
6097 guint64 prev_offset;
6099 GST_DEBUG_OBJECT (demux, "Parsing [moof]");
6102 * The timestamp of the moof buffer is relevant as some scenarios
6103 * won't have the initial timestamp in the atoms. Whenever a new
6104 * buffer has started, we get that buffer's PTS and use it as a base
6105 * timestamp for the trun entries.
6107 * To keep track of the current buffer timestamp and starting point
6108 * we use gst_adapter_prev_pts that gives us the PTS and the distance
6109 * from the beggining of the buffer, with the distance and demux->offset
6110 * we know if it is still the same buffer or not.
6112 prev_pts = gst_adapter_prev_pts (demux->adapter, &dist);
6113 prev_offset = demux->offset - dist;
6114 if (demux->fragment_start_offset == -1
6115 || prev_offset > demux->fragment_start_offset) {
6116 demux->fragment_start_offset = prev_offset;
6117 demux->fragment_start = prev_pts;
6118 GST_DEBUG_OBJECT (demux,
6119 "New fragment start found at: %" G_GUINT64_FORMAT " : %"
6120 GST_TIME_FORMAT, demux->fragment_start_offset,
6121 GST_TIME_ARGS (demux->fragment_start));
6124 demux->moof_offset = demux->offset;
6125 if (!qtdemux_parse_moof (demux, data, demux->neededbytes,
6126 demux->offset, NULL)) {
6127 gst_adapter_unmap (demux->adapter);
6128 ret = GST_FLOW_ERROR;
6131 /* in MSS we need to expose the pads after the first moof as we won't get a moov */
6132 if (demux->mss_mode && !demux->exposed) {
6133 if (!demux->pending_newsegment) {
6135 gst_segment_init (&segment, GST_FORMAT_TIME);
6136 GST_DEBUG_OBJECT (demux, "new pending_newsegment");
6137 demux->pending_newsegment = gst_event_new_segment (&segment);
6139 qtdemux_expose_streams (demux);
6142 GST_DEBUG_OBJECT (demux, "Discarding [moof]");
6144 } else if (fourcc == FOURCC_ftyp) {
6145 GST_DEBUG_OBJECT (demux, "Parsing [ftyp]");
6146 qtdemux_parse_ftyp (demux, data, demux->neededbytes);
6147 } else if (fourcc == FOURCC_uuid) {
6148 GST_DEBUG_OBJECT (demux, "Parsing [uuid]");
6149 qtdemux_parse_uuid (demux, data, demux->neededbytes);
6150 } else if (fourcc == FOURCC_sidx) {
6151 GST_DEBUG_OBJECT (demux, "Parsing [sidx]");
6152 qtdemux_parse_sidx (demux, data, demux->neededbytes);
6154 GST_WARNING_OBJECT (demux,
6155 "Unknown fourcc while parsing header : %" GST_FOURCC_FORMAT,
6156 GST_FOURCC_ARGS (fourcc));
6157 /* Let's jump that one and go back to initial state */
6159 gst_adapter_unmap (demux->adapter);
6162 if (demux->mdatbuffer && demux->n_streams) {
6163 gsize remaining_data_size = 0;
6165 /* the mdat was before the header */
6166 GST_DEBUG_OBJECT (demux, "We have n_streams:%d and mdatbuffer:%p",
6167 demux->n_streams, demux->mdatbuffer);
6168 /* restore our adapter/offset view of things with upstream;
6169 * put preceding buffered data ahead of current moov data.
6170 * This should also handle evil mdat, moov, mdat cases and alike */
6171 gst_adapter_flush (demux->adapter, demux->neededbytes);
6173 /* Store any remaining data after the mdat for later usage */
6174 remaining_data_size = gst_adapter_available (demux->adapter);
6175 if (remaining_data_size > 0) {
6176 g_assert (demux->restoredata_buffer == NULL);
6177 demux->restoredata_buffer =
6178 gst_adapter_take_buffer (demux->adapter, remaining_data_size);
6179 demux->restoredata_offset = demux->offset + demux->neededbytes;
6180 GST_DEBUG_OBJECT (demux,
6181 "Stored %" G_GSIZE_FORMAT " post mdat bytes at offset %"
6182 G_GUINT64_FORMAT, remaining_data_size,
6183 demux->restoredata_offset);
6186 gst_adapter_push (demux->adapter, demux->mdatbuffer);
6187 demux->mdatbuffer = NULL;
6188 demux->offset = demux->mdatoffset;
6189 demux->neededbytes = next_entry_size (demux);
6190 demux->state = QTDEMUX_STATE_MOVIE;
6191 demux->mdatleft = gst_adapter_available (demux->adapter);
6193 GST_DEBUG_OBJECT (demux, "Carrying on normally");
6194 gst_adapter_flush (demux->adapter, demux->neededbytes);
6196 /* only go back to the mdat if there are samples to play */
6197 if (demux->got_moov && demux->first_mdat != -1
6198 && has_next_entry (demux)) {
6201 /* we need to seek back */
6202 res = qtdemux_seek_offset (demux, demux->first_mdat);
6204 demux->offset = demux->first_mdat;
6206 GST_DEBUG_OBJECT (demux, "Seek back failed");
6209 demux->offset += demux->neededbytes;
6211 demux->neededbytes = 16;
6212 demux->state = QTDEMUX_STATE_INITIAL;
6217 case QTDEMUX_STATE_BUFFER_MDAT:{
6221 GST_DEBUG_OBJECT (demux, "Got our buffer at offset %" G_GUINT64_FORMAT,
6223 buf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
6224 gst_buffer_extract (buf, 0, fourcc, 4);
6225 GST_DEBUG_OBJECT (demux, "mdatbuffer starts with %" GST_FOURCC_FORMAT,
6226 GST_FOURCC_ARGS (QT_FOURCC (fourcc)));
6227 if (demux->mdatbuffer)
6228 demux->mdatbuffer = gst_buffer_append (demux->mdatbuffer, buf);
6230 demux->mdatbuffer = buf;
6231 demux->offset += demux->neededbytes;
6232 demux->neededbytes = 16;
6233 demux->state = QTDEMUX_STATE_INITIAL;
6234 gst_qtdemux_post_progress (demux, 1, 1);
6238 case QTDEMUX_STATE_MOVIE:{
6239 QtDemuxStream *stream = NULL;
6240 QtDemuxSample *sample;
6242 GstClockTime dts, pts, duration;
6245 GST_DEBUG_OBJECT (demux,
6246 "BEGIN // in MOVIE for offset %" G_GUINT64_FORMAT, demux->offset);
6248 if (demux->fragmented) {
6249 GST_DEBUG_OBJECT (demux, "mdat remaining %" G_GUINT64_FORMAT,
6251 if (G_LIKELY (demux->todrop < demux->mdatleft)) {
6252 /* if needed data starts within this atom,
6253 * then it should not exceed this atom */
6254 if (G_UNLIKELY (demux->neededbytes > demux->mdatleft)) {
6255 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
6256 (_("This file is invalid and cannot be played.")),
6257 ("sample data crosses atom boundary"));
6258 ret = GST_FLOW_ERROR;
6261 demux->mdatleft -= demux->neededbytes;
6263 GST_DEBUG_OBJECT (demux, "data atom emptied; resuming atom scan");
6264 /* so we are dropping more than left in this atom */
6265 gst_qtdemux_drop_data (demux, demux->mdatleft);
6266 demux->mdatleft = 0;
6268 /* need to resume atom parsing so we do not miss any other pieces */
6269 demux->state = QTDEMUX_STATE_INITIAL;
6270 demux->neededbytes = 16;
6272 /* check if there was any stored post mdat data from previous buffers */
6273 if (demux->restoredata_buffer) {
6274 g_assert (gst_adapter_available (demux->adapter) == 0);
6276 gst_adapter_push (demux->adapter, demux->restoredata_buffer);
6277 demux->restoredata_buffer = NULL;
6278 demux->offset = demux->restoredata_offset;
6285 if (demux->todrop) {
6286 if (demux->cenc_aux_info_offset > 0) {
6290 GST_DEBUG_OBJECT (demux, "parsing cenc auxiliary info");
6291 data = gst_adapter_map (demux->adapter, demux->todrop);
6292 gst_byte_reader_init (&br, data + 8, demux->todrop);
6293 if (!qtdemux_parse_cenc_aux_info (demux, demux->streams[0], &br,
6294 demux->cenc_aux_info_sizes, demux->cenc_aux_sample_count)) {
6295 GST_ERROR_OBJECT (demux, "failed to parse cenc auxiliary info");
6296 ret = GST_FLOW_ERROR;
6297 gst_adapter_unmap (demux->adapter);
6298 g_free (demux->cenc_aux_info_sizes);
6299 demux->cenc_aux_info_sizes = NULL;
6302 demux->cenc_aux_info_offset = 0;
6303 g_free (demux->cenc_aux_info_sizes);
6304 demux->cenc_aux_info_sizes = NULL;
6305 gst_adapter_unmap (demux->adapter);
6307 gst_qtdemux_drop_data (demux, demux->todrop);
6311 /* initial newsegment sent here after having added pads,
6312 * possible others in sink_event */
6313 gst_qtdemux_check_send_pending_segment (demux);
6315 /* Figure out which stream this packet belongs to */
6316 for (i = 0; i < demux->n_streams; i++) {
6317 stream = demux->streams[i];
6318 if (stream->sample_index >= stream->n_samples)
6320 GST_LOG_OBJECT (demux,
6321 "Checking stream %d (sample_index:%d / offset:%" G_GUINT64_FORMAT
6322 " / size:%d)", i, stream->sample_index,
6323 stream->samples[stream->sample_index].offset,
6324 stream->samples[stream->sample_index].size);
6326 if (stream->samples[stream->sample_index].offset == demux->offset)
6330 if (G_UNLIKELY (stream == NULL || i == demux->n_streams))
6331 goto unknown_stream;
6333 if (stream->new_caps) {
6334 gst_qtdemux_configure_stream (demux, stream);
6337 /* Put data in a buffer, set timestamps, caps, ... */
6338 sample = &stream->samples[stream->sample_index];
6340 if (G_LIKELY (!(STREAM_IS_EOS (stream)))) {
6341 GST_DEBUG_OBJECT (demux, "stream : %" GST_FOURCC_FORMAT,
6342 GST_FOURCC_ARGS (stream->fourcc));
6344 dts = QTSAMPLE_DTS (stream, sample);
6345 pts = QTSAMPLE_PTS (stream, sample);
6346 duration = QTSAMPLE_DUR_DTS (stream, sample, dts);
6347 keyframe = QTSAMPLE_KEYFRAME (stream, sample);
6349 /* check for segment end */
6350 if (G_UNLIKELY (demux->segment.stop != -1
6351 && demux->segment.stop <= pts && stream->on_keyframe)) {
6352 GST_DEBUG_OBJECT (demux, "we reached the end of our segment.");
6353 stream->time_position = GST_CLOCK_TIME_NONE; /* this means EOS */
6355 /* skip this data, stream is EOS */
6356 gst_adapter_flush (demux->adapter, demux->neededbytes);
6358 /* check if all streams are eos */
6360 for (i = 0; i < demux->n_streams; i++) {
6361 if (!STREAM_IS_EOS (demux->streams[i])) {
6367 if (ret == GST_FLOW_EOS) {
6368 GST_DEBUG_OBJECT (demux, "All streams are EOS, signal upstream");
6375 gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
6377 /* FIXME: should either be an assert or a plain check */
6378 g_return_val_if_fail (outbuf != NULL, GST_FLOW_ERROR);
6380 ret = gst_qtdemux_decorate_and_push_buffer (demux, stream, outbuf,
6381 dts, pts, duration, keyframe, dts, demux->offset);
6385 ret = gst_qtdemux_combine_flows (demux, stream, ret);
6386 if (ret != GST_FLOW_OK && ret != GST_FLOW_NOT_LINKED)
6387 goto non_ok_unlinked_flow;
6389 /* skip this data, stream is EOS */
6390 gst_adapter_flush (demux->adapter, demux->neededbytes);
6393 stream->sample_index++;
6394 stream->offset_in_sample = 0;
6396 /* update current offset and figure out size of next buffer */
6397 GST_LOG_OBJECT (demux, "increasing offset %" G_GUINT64_FORMAT " by %u",
6398 demux->offset, demux->neededbytes);
6399 demux->offset += demux->neededbytes;
6400 GST_LOG_OBJECT (demux, "offset is now %" G_GUINT64_FORMAT,
6403 if ((demux->neededbytes = next_entry_size (demux)) == -1) {
6404 if (demux->fragmented) {
6405 GST_DEBUG_OBJECT (demux, "(temporarily) out of fragmented samples");
6406 /* there may be more to follow, only finish this atom */
6407 demux->todrop = demux->mdatleft;
6408 demux->neededbytes = demux->todrop;
6420 /* when buffering movie data, at least show user something is happening */
6421 if (ret == GST_FLOW_OK && demux->state == QTDEMUX_STATE_BUFFER_MDAT &&
6422 gst_adapter_available (demux->adapter) <= demux->neededbytes) {
6423 gst_qtdemux_post_progress (demux, gst_adapter_available (demux->adapter),
6424 demux->neededbytes);
6431 non_ok_unlinked_flow:
6433 GST_DEBUG_OBJECT (demux, "Stopping, combined return flow %s",
6434 gst_flow_get_name (ret));
6439 GST_ELEMENT_ERROR (demux, STREAM, FAILED, (NULL), ("unknown stream found"));
6440 ret = GST_FLOW_ERROR;
6445 GST_DEBUG_OBJECT (demux, "no next entry, EOS");
6451 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
6452 (NULL), ("qtdemuxer invalid state %d", demux->state));
6453 ret = GST_FLOW_ERROR;
6458 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
6459 (NULL), ("no 'moov' atom within the first 10 MB"));
6460 ret = GST_FLOW_ERROR;
6466 qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent)
6471 query = gst_query_new_scheduling ();
6473 if (!gst_pad_peer_query (sinkpad, query)) {
6474 gst_query_unref (query);
6478 pull_mode = gst_query_has_scheduling_mode_with_flags (query,
6479 GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
6480 gst_query_unref (query);
6485 GST_DEBUG_OBJECT (sinkpad, "activating pull");
6486 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
6490 GST_DEBUG_OBJECT (sinkpad, "activating push");
6491 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
6496 qtdemux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
6497 GstPadMode mode, gboolean active)
6500 GstQTDemux *demux = GST_QTDEMUX (parent);
6503 case GST_PAD_MODE_PUSH:
6504 demux->pullbased = FALSE;
6507 case GST_PAD_MODE_PULL:
6509 demux->pullbased = TRUE;
6510 res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_qtdemux_loop,
6513 res = gst_pad_stop_task (sinkpad);
6525 qtdemux_zalloc (void *opaque, unsigned int items, unsigned int size)
6527 return g_malloc (items * size);
6531 qtdemux_zfree (void *opaque, void *addr)
6537 qtdemux_inflate (void *z_buffer, guint z_length, guint length)
6543 z = g_new0 (z_stream, 1);
6544 z->zalloc = qtdemux_zalloc;
6545 z->zfree = qtdemux_zfree;
6548 z->next_in = z_buffer;
6549 z->avail_in = z_length;
6551 buffer = (guint8 *) g_malloc (length);
6552 ret = inflateInit (z);
6553 while (z->avail_in > 0) {
6554 if (z->avail_out == 0) {
6556 buffer = (guint8 *) g_realloc (buffer, length);
6557 z->next_out = buffer + z->total_out;
6558 z->avail_out = 1024;
6560 ret = inflate (z, Z_SYNC_FLUSH);
6564 if (ret != Z_STREAM_END) {
6565 g_warning ("inflate() returned %d", ret);
6571 #endif /* HAVE_ZLIB */
6574 qtdemux_parse_moov (GstQTDemux * qtdemux, const guint8 * buffer, guint length)
6578 qtdemux->moov_node = g_node_new ((guint8 *) buffer);
6580 /* counts as header data */
6581 qtdemux->header_size += length;
6583 GST_DEBUG_OBJECT (qtdemux, "parsing 'moov' atom");
6584 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buffer, length);
6586 cmov = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_cmov);
6592 dcom = qtdemux_tree_get_child_by_type (cmov, FOURCC_dcom);
6593 cmvd = qtdemux_tree_get_child_by_type (cmov, FOURCC_cmvd);
6594 if (dcom == NULL || cmvd == NULL)
6595 goto invalid_compression;
6597 method = QT_FOURCC ((guint8 *) dcom->data + 8);
6601 guint uncompressed_length;
6602 guint compressed_length;
6605 uncompressed_length = QT_UINT32 ((guint8 *) cmvd->data + 8);
6606 compressed_length = QT_UINT32 ((guint8 *) cmvd->data + 4) - 12;
6607 GST_LOG ("length = %u", uncompressed_length);
6610 (guint8 *) qtdemux_inflate ((guint8 *) cmvd->data + 12,
6611 compressed_length, uncompressed_length);
6613 qtdemux->moov_node_compressed = qtdemux->moov_node;
6614 qtdemux->moov_node = g_node_new (buf);
6616 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buf,
6617 uncompressed_length);
6620 #endif /* HAVE_ZLIB */
6622 GST_WARNING_OBJECT (qtdemux, "unknown or unhandled header compression "
6623 "type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (method));
6630 invalid_compression:
6632 GST_ERROR_OBJECT (qtdemux, "invalid compressed header");
6638 qtdemux_parse_container (GstQTDemux * qtdemux, GNode * node, const guint8 * buf,
6641 while (G_UNLIKELY (buf < end)) {
6645 if (G_UNLIKELY (buf + 4 > end)) {
6646 GST_LOG_OBJECT (qtdemux, "buffer overrun");
6649 len = QT_UINT32 (buf);
6650 if (G_UNLIKELY (len == 0)) {
6651 GST_LOG_OBJECT (qtdemux, "empty container");
6654 if (G_UNLIKELY (len < 8)) {
6655 GST_WARNING_OBJECT (qtdemux, "length too short (%d < 8)", len);
6658 if (G_UNLIKELY (len > (end - buf))) {
6659 GST_WARNING_OBJECT (qtdemux, "length too long (%d > %d)", len,
6660 (gint) (end - buf));
6664 child = g_node_new ((guint8 *) buf);
6665 g_node_append (node, child);
6666 GST_LOG_OBJECT (qtdemux, "adding new node of len %d", len);
6667 qtdemux_parse_node (qtdemux, child, buf, len);
6675 qtdemux_parse_theora_extension (GstQTDemux * qtdemux, QtDemuxStream * stream,
6678 int len = QT_UINT32 (xdxt->data);
6679 guint8 *buf = xdxt->data;
6680 guint8 *end = buf + len;
6683 /* skip size and type */
6691 size = QT_UINT32 (buf);
6692 type = QT_FOURCC (buf + 4);
6694 GST_LOG_OBJECT (qtdemux, "%p %p", buf, end);
6696 if (buf + size > end || size <= 0)
6702 GST_WARNING_OBJECT (qtdemux, "have cookie %" GST_FOURCC_FORMAT,
6703 GST_FOURCC_ARGS (type));
6707 buffer = gst_buffer_new_and_alloc (size);
6708 gst_buffer_fill (buffer, 0, buf, size);
6709 stream->buffers = g_slist_append (stream->buffers, buffer);
6710 GST_LOG_OBJECT (qtdemux, "parsing theora header");
6713 buffer = gst_buffer_new_and_alloc (size);
6714 gst_buffer_fill (buffer, 0, buf, size);
6715 stream->buffers = g_slist_append (stream->buffers, buffer);
6716 GST_LOG_OBJECT (qtdemux, "parsing theora comment");
6719 buffer = gst_buffer_new_and_alloc (size);
6720 gst_buffer_fill (buffer, 0, buf, size);
6721 stream->buffers = g_slist_append (stream->buffers, buffer);
6722 GST_LOG_OBJECT (qtdemux, "parsing theora codebook");
6725 GST_WARNING_OBJECT (qtdemux,
6726 "unknown theora cookie %" GST_FOURCC_FORMAT,
6727 GST_FOURCC_ARGS (type));
6736 qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node, const guint8 * buffer,
6740 guint32 node_length = 0;
6741 const QtNodeType *type;
6744 GST_LOG_OBJECT (qtdemux, "qtdemux_parse buffer %p length %u", buffer, length);
6746 if (G_UNLIKELY (length < 8))
6747 goto not_enough_data;
6749 node_length = QT_UINT32 (buffer);
6750 fourcc = QT_FOURCC (buffer + 4);
6752 /* ignore empty nodes */
6753 if (G_UNLIKELY (fourcc == 0 || node_length == 8))
6756 type = qtdemux_type_get (fourcc);
6758 end = buffer + length;
6760 GST_LOG_OBJECT (qtdemux,
6761 "parsing '%" GST_FOURCC_FORMAT "', length=%u, name '%s'",
6762 GST_FOURCC_ARGS (fourcc), node_length, type->name);
6764 if (node_length > length)
6765 goto broken_atom_size;
6767 if (type->flags & QT_FLAG_CONTAINER) {
6768 qtdemux_parse_container (qtdemux, node, buffer + 8, end);
6773 if (node_length < 20) {
6774 GST_LOG_OBJECT (qtdemux, "skipping small stsd box");
6777 GST_DEBUG_OBJECT (qtdemux,
6778 "parsing stsd (sample table, sample description) atom");
6779 /* Skip over 8 byte atom hdr + 1 byte version, 3 bytes flags, 4 byte num_entries */
6780 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
6790 /* also read alac (or whatever) in stead of mp4a in the following,
6791 * since a similar layout is used in other cases as well */
6792 if (fourcc == FOURCC_mp4a)
6797 /* There are two things we might encounter here: a true mp4a atom, and
6798 an mp4a entry in an stsd atom. The latter is what we're interested
6799 in, and it looks like an atom, but isn't really one. The true mp4a
6800 atom is short, so we detect it based on length here. */
6801 if (length < min_size) {
6802 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
6803 GST_FOURCC_ARGS (fourcc));
6807 /* 'version' here is the sound sample description version. Types 0 and
6808 1 are documented in the QTFF reference, but type 2 is not: it's
6809 described in Apple header files instead (struct SoundDescriptionV2
6811 version = QT_UINT16 (buffer + 16);
6813 GST_DEBUG_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT " version 0x%08x",
6814 GST_FOURCC_ARGS (fourcc), version);
6816 /* parse any esds descriptors */
6828 GST_WARNING_OBJECT (qtdemux,
6829 "unhandled %" GST_FOURCC_FORMAT " version 0x%08x",
6830 GST_FOURCC_ARGS (fourcc), version);
6835 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
6852 /* codec_data is contained inside these atoms, which all have
6853 * the same format. */
6855 GST_DEBUG_OBJECT (qtdemux, "parsing in %" GST_FOURCC_FORMAT,
6856 GST_FOURCC_ARGS (fourcc));
6857 version = QT_UINT32 (buffer + 16);
6858 GST_DEBUG_OBJECT (qtdemux, "version %08x", version);
6859 if (1 || version == 0x00000000) {
6860 buf = buffer + 0x32;
6862 /* FIXME Quicktime uses PASCAL string while
6863 * the iso format uses C strings. Check the file
6864 * type before attempting to parse the string here. */
6865 tlen = QT_UINT8 (buf);
6866 GST_DEBUG_OBJECT (qtdemux, "tlen = %d", tlen);
6868 GST_DEBUG_OBJECT (qtdemux, "string = %.*s", tlen, (char *) buf);
6869 /* the string has a reserved space of 32 bytes so skip
6870 * the remaining 31 */
6872 buf += 4; /* and 4 bytes reserved */
6874 GST_MEMDUMP_OBJECT (qtdemux, "mp4v", buf, end - buf);
6876 qtdemux_parse_container (qtdemux, node, buf, end);
6882 GST_MEMDUMP_OBJECT (qtdemux, "H264", buffer, end - buffer);
6883 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
6888 GST_MEMDUMP_OBJECT (qtdemux, "avc1", buffer, end - buffer);
6889 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
6894 GST_MEMDUMP_OBJECT (qtdemux, "avc3", buffer, end - buffer);
6895 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
6900 GST_MEMDUMP_OBJECT (qtdemux, "H265", buffer, end - buffer);
6901 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
6906 GST_MEMDUMP_OBJECT (qtdemux, "hvc1", buffer, end - buffer);
6907 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
6912 GST_MEMDUMP_OBJECT (qtdemux, "hev1", buffer, end - buffer);
6913 qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
6918 qtdemux_parse_container (qtdemux, node, buffer + 86, end);
6923 GST_DEBUG_OBJECT (qtdemux, "parsing meta atom");
6924 qtdemux_parse_container (qtdemux, node, buffer + 12, end);
6929 GST_MEMDUMP_OBJECT (qtdemux, "mp4s", buffer, end - buffer);
6930 /* Skip 8 byte header, plus 8 byte version + flags + entry_count */
6931 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
6939 version = QT_UINT32 (buffer + 12);
6940 GST_DEBUG_OBJECT (qtdemux, "parsing XiTh atom version 0x%08x", version);
6947 GST_DEBUG_OBJECT (qtdemux, "unknown version 0x%08x", version);
6952 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
6957 qtdemux_parse_container (qtdemux, node, buffer + 0x34, end);
6962 qtdemux_parse_uuid (qtdemux, buffer, end - buffer);
6967 qtdemux_parse_container (qtdemux, node, buffer + 86, end);
6972 qtdemux_parse_container (qtdemux, node, buffer + 36, end);
6976 if (!strcmp (type->name, "unknown"))
6977 GST_MEMDUMP ("Unknown tag", buffer + 4, end - buffer - 4);
6981 GST_LOG_OBJECT (qtdemux, "parsed '%" GST_FOURCC_FORMAT "'",
6982 GST_FOURCC_ARGS (fourcc));
6988 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
6989 (_("This file is corrupt and cannot be played.")),
6990 ("Not enough data for an atom header, got only %u bytes", length));
6995 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
6996 (_("This file is corrupt and cannot be played.")),
6997 ("Atom '%" GST_FOURCC_FORMAT "' has size of %u bytes, but we have only "
6998 "%u bytes available.", GST_FOURCC_ARGS (fourcc), node_length,
7005 qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc)
7009 guint32 child_fourcc;
7011 for (child = g_node_first_child (node); child;
7012 child = g_node_next_sibling (child)) {
7013 buffer = (guint8 *) child->data;
7015 child_fourcc = QT_FOURCC (buffer + 4);
7017 if (G_UNLIKELY (child_fourcc == fourcc)) {
7025 qtdemux_tree_get_child_by_type_full (GNode * node, guint32 fourcc,
7026 GstByteReader * parser)
7030 guint32 child_fourcc, child_len;
7032 for (child = g_node_first_child (node); child;
7033 child = g_node_next_sibling (child)) {
7034 buffer = (guint8 *) child->data;
7036 child_len = QT_UINT32 (buffer);
7037 child_fourcc = QT_FOURCC (buffer + 4);
7039 if (G_UNLIKELY (child_fourcc == fourcc)) {
7040 if (G_UNLIKELY (child_len < (4 + 4)))
7042 /* FIXME: must verify if atom length < parent atom length */
7043 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
7051 qtdemux_tree_get_sibling_by_type_full (GNode * node, guint32 fourcc,
7052 GstByteReader * parser)
7056 guint32 child_fourcc, child_len;
7058 for (child = g_node_next_sibling (node); child;
7059 child = g_node_next_sibling (child)) {
7060 buffer = (guint8 *) child->data;
7062 child_fourcc = QT_FOURCC (buffer + 4);
7064 if (child_fourcc == fourcc) {
7066 child_len = QT_UINT32 (buffer);
7067 if (G_UNLIKELY (child_len < (4 + 4)))
7069 /* FIXME: must verify if atom length < parent atom length */
7070 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
7079 qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc)
7081 return qtdemux_tree_get_sibling_by_type_full (node, fourcc, NULL);
7085 qtdemux_do_allocation (GstQTDemux * qtdemux, QtDemuxStream * stream)
7087 /* FIXME: This can only reliably work if demuxers have a
7088 * separate streaming thread per srcpad. This should be
7089 * done in a demuxer base class, which integrates parts
7092 * https://bugzilla.gnome.org/show_bug.cgi?id=701856
7097 query = gst_query_new_allocation (stream->caps, FALSE);
7099 if (!gst_pad_peer_query (stream->pad, query)) {
7100 /* not a problem, just debug a little */
7101 GST_DEBUG_OBJECT (qtdemux, "peer ALLOCATION query failed");
7104 if (stream->allocator)
7105 gst_object_unref (stream->allocator);
7107 if (gst_query_get_n_allocation_params (query) > 0) {
7108 /* try the allocator */
7109 gst_query_parse_nth_allocation_param (query, 0, &stream->allocator,
7111 stream->use_allocator = TRUE;
7113 stream->allocator = NULL;
7114 gst_allocation_params_init (&stream->params);
7115 stream->use_allocator = FALSE;
7117 gst_query_unref (query);
7122 gst_qtdemux_configure_protected_caps (GstQTDemux * qtdemux,
7123 QtDemuxStream * stream)
7126 const gchar *selected_system;
7128 g_return_val_if_fail (qtdemux != NULL, FALSE);
7129 g_return_val_if_fail (stream != NULL, FALSE);
7130 g_return_val_if_fail (gst_caps_get_size (stream->caps) == 1, FALSE);
7132 if (stream->protection_scheme_type != FOURCC_cenc) {
7133 GST_ERROR_OBJECT (qtdemux, "unsupported protection scheme");
7136 if (qtdemux->protection_system_ids == NULL) {
7137 GST_ERROR_OBJECT (qtdemux, "stream is protected using cenc, but no "
7138 "cenc protection system information has been found");
7141 g_ptr_array_add (qtdemux->protection_system_ids, NULL);
7142 selected_system = gst_protection_select_system ((const gchar **)
7143 qtdemux->protection_system_ids->pdata);
7144 g_ptr_array_remove_index (qtdemux->protection_system_ids,
7145 qtdemux->protection_system_ids->len - 1);
7146 if (!selected_system) {
7147 GST_ERROR_OBJECT (qtdemux, "stream is protected, but no "
7148 "suitable decryptor element has been found");
7152 s = gst_caps_get_structure (stream->caps, 0);
7153 if (!gst_structure_has_name (s, "application/x-cenc")) {
7154 gst_structure_set (s,
7155 "original-media-type", G_TYPE_STRING, gst_structure_get_name (s),
7156 GST_PROTECTION_SYSTEM_ID_CAPS_FIELD, G_TYPE_STRING, selected_system,
7158 gst_structure_set_name (s, "application/x-cenc");
7164 gst_qtdemux_configure_stream (GstQTDemux * qtdemux, QtDemuxStream * stream)
7166 if (stream->subtype == FOURCC_vide) {
7167 /* fps is calculated base on the duration of the average framerate since
7168 * qt does not have a fixed framerate. */
7169 gboolean fps_available = TRUE;
7171 if ((stream->n_samples == 1) && (stream->first_duration == 0)) {
7176 if (stream->duration == 0 || stream->n_samples < 2) {
7177 stream->fps_n = stream->timescale;
7179 fps_available = FALSE;
7181 GstClockTime avg_duration;
7185 /* duration and n_samples can be updated for fragmented format
7186 * so, framerate of fragmented format is calculated using data in a moof */
7187 if (qtdemux->fragmented && stream->n_samples_moof > 0
7188 && stream->duration_moof > 0) {
7189 n_samples = stream->n_samples_moof;
7190 duration = stream->duration_moof;
7192 n_samples = stream->n_samples;
7193 duration = stream->duration;
7196 /* Calculate a framerate, ignoring the first sample which is sometimes truncated */
7197 /* stream->duration is guint64, timescale, n_samples are guint32 */
7199 gst_util_uint64_scale_round (duration -
7200 stream->first_duration, GST_SECOND,
7201 (guint64) (stream->timescale) * (n_samples - 1));
7203 GST_LOG_OBJECT (qtdemux,
7204 "Calculating avg sample duration based on stream (or moof) duration %"
7206 " minus first sample %u, leaving %d samples gives %"
7207 GST_TIME_FORMAT, duration, stream->first_duration,
7208 n_samples - 1, GST_TIME_ARGS (avg_duration));
7210 gst_video_guess_framerate (avg_duration, &stream->fps_n,
7213 GST_DEBUG_OBJECT (qtdemux,
7214 "Calculating framerate, timescale %u gave fps_n %d fps_d %d",
7215 stream->timescale, stream->fps_n, stream->fps_d);
7220 stream->caps = gst_caps_make_writable (stream->caps);
7222 gst_caps_set_simple (stream->caps,
7223 "width", G_TYPE_INT, stream->width,
7224 "height", G_TYPE_INT, stream->height, NULL);
7226 /* set framerate if calculated framerate is reliable */
7227 if (fps_available) {
7228 gst_caps_set_simple (stream->caps,
7229 "framerate", GST_TYPE_FRACTION, stream->fps_n, stream->fps_d, NULL);
7232 /* calculate pixel-aspect-ratio using display width and height */
7233 GST_DEBUG_OBJECT (qtdemux,
7234 "video size %dx%d, target display size %dx%d", stream->width,
7235 stream->height, stream->display_width, stream->display_height);
7236 /* qt file might have pasp atom */
7237 if (stream->par_w > 0 && stream->par_h > 0) {
7238 GST_DEBUG_OBJECT (qtdemux, "par %d:%d", stream->par_w, stream->par_h);
7239 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
7240 GST_TYPE_FRACTION, stream->par_w, stream->par_h, NULL);
7241 } else if (stream->display_width > 0 && stream->display_height > 0 &&
7242 stream->width > 0 && stream->height > 0) {
7245 /* calculate the pixel aspect ratio using the display and pixel w/h */
7246 n = stream->display_width * stream->height;
7247 d = stream->display_height * stream->width;
7250 GST_DEBUG_OBJECT (qtdemux, "setting PAR to %d/%d", n, d);
7253 gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
7254 GST_TYPE_FRACTION, stream->par_w, stream->par_h, NULL);
7257 if (stream->multiview_mode != GST_VIDEO_MULTIVIEW_MODE_NONE) {
7258 guint par_w = 1, par_h = 1;
7260 if (stream->par_w > 0 && stream->par_h > 0) {
7261 par_w = stream->par_w;
7262 par_h = stream->par_h;
7265 if (gst_video_multiview_guess_half_aspect (stream->multiview_mode,
7266 stream->width, stream->height, par_w, par_h)) {
7267 stream->multiview_flags |= GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT;
7270 gst_caps_set_simple (stream->caps,
7271 "multiview-mode", G_TYPE_STRING,
7272 gst_video_multiview_mode_to_caps_string (stream->multiview_mode),
7273 "multiview-flags", GST_TYPE_VIDEO_MULTIVIEW_FLAGSET,
7274 stream->multiview_flags, GST_FLAG_SET_MASK_EXACT, NULL);
7279 else if (stream->subtype == FOURCC_soun) {
7281 stream->caps = gst_caps_make_writable (stream->caps);
7282 if (stream->rate > 0)
7283 gst_caps_set_simple (stream->caps,
7284 "rate", G_TYPE_INT, (int) stream->rate, NULL);
7285 if (stream->n_channels > 0)
7286 gst_caps_set_simple (stream->caps,
7287 "channels", G_TYPE_INT, stream->n_channels, NULL);
7288 if (stream->n_channels > 2) {
7289 /* FIXME: Need to parse the 'chan' atom to get channel layouts
7290 * correctly; this is just the minimum we can do - assume
7291 * we don't actually have any channel positions. */
7292 gst_caps_set_simple (stream->caps,
7293 "channel-mask", GST_TYPE_BITMASK, G_GUINT64_CONSTANT (0), NULL);
7299 GST_PAD_ELEMENT_PRIVATE (stream->pad) = stream;
7300 gst_pad_set_event_function (stream->pad, gst_qtdemux_handle_src_event);
7301 gst_pad_set_query_function (stream->pad, gst_qtdemux_handle_src_query);
7302 gst_pad_set_active (stream->pad, TRUE);
7304 gst_pad_use_fixed_caps (stream->pad);
7306 if (stream->protected) {
7307 if (!gst_qtdemux_configure_protected_caps (qtdemux, stream)) {
7308 GST_ERROR_OBJECT (qtdemux,
7309 "Failed to configure protected stream caps.");
7314 GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT, stream->caps);
7315 if (stream->new_stream) {
7318 GstStreamFlags stream_flags;
7321 gst_pad_get_sticky_event (qtdemux->sinkpad, GST_EVENT_STREAM_START,
7324 if (gst_event_parse_group_id (event, &qtdemux->group_id))
7325 qtdemux->have_group_id = TRUE;
7327 qtdemux->have_group_id = FALSE;
7328 gst_event_unref (event);
7329 } else if (!qtdemux->have_group_id) {
7330 qtdemux->have_group_id = TRUE;
7331 qtdemux->group_id = gst_util_group_id_next ();
7334 stream->new_stream = FALSE;
7336 gst_pad_create_stream_id_printf (stream->pad,
7337 GST_ELEMENT_CAST (qtdemux), "%03u", stream->track_id);
7338 event = gst_event_new_stream_start (stream_id);
7339 if (qtdemux->have_group_id)
7340 gst_event_set_group_id (event, qtdemux->group_id);
7341 stream_flags = GST_STREAM_FLAG_NONE;
7342 if (stream->disabled)
7343 stream_flags |= GST_STREAM_FLAG_UNSELECT;
7345 stream_flags |= GST_STREAM_FLAG_SPARSE;
7346 gst_event_set_stream_flags (event, stream_flags);
7347 gst_pad_push_event (stream->pad, event);
7350 gst_pad_set_caps (stream->pad, stream->caps);
7351 stream->new_caps = FALSE;
7357 gst_qtdemux_add_stream (GstQTDemux * qtdemux,
7358 QtDemuxStream * stream, GstTagList * list)
7360 gboolean ret = TRUE;
7361 /* consistent default for push based mode */
7362 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
7364 if (stream->subtype == FOURCC_vide) {
7365 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
7368 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
7371 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
7372 gst_object_unref (stream->pad);
7378 qtdemux->n_video_streams++;
7379 } else if (stream->subtype == FOURCC_soun) {
7380 gchar *name = g_strdup_printf ("audio_%u", qtdemux->n_audio_streams);
7383 gst_pad_new_from_static_template (&gst_qtdemux_audiosrc_template, name);
7385 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
7386 gst_object_unref (stream->pad);
7391 qtdemux->n_audio_streams++;
7392 } else if (stream->subtype == FOURCC_strm) {
7393 GST_DEBUG_OBJECT (qtdemux, "stream type, not creating pad");
7394 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
7395 || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt) {
7396 gchar *name = g_strdup_printf ("subtitle_%u", qtdemux->n_sub_streams);
7399 gst_pad_new_from_static_template (&gst_qtdemux_subsrc_template, name);
7401 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
7402 gst_object_unref (stream->pad);
7407 qtdemux->n_sub_streams++;
7408 } else if (stream->caps) {
7409 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
7412 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
7414 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
7415 gst_object_unref (stream->pad);
7420 qtdemux->n_video_streams++;
7422 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
7429 GST_DEBUG_OBJECT (qtdemux, "adding pad %s %p to qtdemux %p",
7430 GST_OBJECT_NAME (stream->pad), stream->pad, qtdemux);
7431 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
7432 gst_flow_combiner_add_pad (qtdemux->flowcombiner, stream->pad);
7434 if (stream->pending_tags)
7435 gst_tag_list_unref (stream->pending_tags);
7436 stream->pending_tags = list;
7438 /* global tags go on each pad anyway */
7439 stream->send_global_tags = TRUE;
7440 /* send upstream GST_EVENT_PROTECTION events that were received before
7441 this source pad was created */
7442 for (l = qtdemux->protection_event_queue.head; l != NULL; l = l->next)
7443 gst_pad_push_event (stream->pad, gst_event_ref (l->data));
7447 gst_tag_list_unref (list);
7451 /* find next atom with @fourcc starting at @offset */
7452 static GstFlowReturn
7453 qtdemux_find_atom (GstQTDemux * qtdemux, guint64 * offset,
7454 guint64 * length, guint32 fourcc)
7460 GST_LOG_OBJECT (qtdemux, "finding fourcc %" GST_FOURCC_FORMAT " at offset %"
7461 G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), *offset);
7467 ret = gst_pad_pull_range (qtdemux->sinkpad, *offset, 16, &buf);
7468 if (G_UNLIKELY (ret != GST_FLOW_OK))
7470 if (G_UNLIKELY (gst_buffer_get_size (buf) != 16)) {
7473 gst_buffer_unref (buf);
7476 gst_buffer_map (buf, &map, GST_MAP_READ);
7477 extract_initial_length_and_fourcc (map.data, 16, length, &lfourcc);
7478 gst_buffer_unmap (buf, &map);
7479 gst_buffer_unref (buf);
7481 if (G_UNLIKELY (*length == 0)) {
7482 GST_DEBUG_OBJECT (qtdemux, "invalid length 0");
7483 ret = GST_FLOW_ERROR;
7487 if (lfourcc == fourcc) {
7488 GST_DEBUG_OBJECT (qtdemux, "found fourcc at offset %" G_GUINT64_FORMAT,
7492 GST_LOG_OBJECT (qtdemux,
7493 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
7494 GST_FOURCC_ARGS (fourcc), *offset);
7503 /* might simply have had last one */
7504 GST_DEBUG_OBJECT (qtdemux, "fourcc not found");
7509 /* should only do something in pull mode */
7510 /* call with OBJECT lock */
7511 static GstFlowReturn
7512 qtdemux_add_fragmented_samples (GstQTDemux * qtdemux)
7514 guint64 length, offset;
7515 GstBuffer *buf = NULL;
7516 GstFlowReturn ret = GST_FLOW_OK;
7517 GstFlowReturn res = GST_FLOW_OK;
7520 offset = qtdemux->moof_offset;
7521 GST_DEBUG_OBJECT (qtdemux, "next moof at offset %" G_GUINT64_FORMAT, offset);
7524 GST_DEBUG_OBJECT (qtdemux, "no next moof");
7525 return GST_FLOW_EOS;
7528 /* best not do pull etc with lock held */
7529 GST_OBJECT_UNLOCK (qtdemux);
7531 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
7532 if (ret != GST_FLOW_OK)
7535 ret = gst_qtdemux_pull_atom (qtdemux, offset, length, &buf);
7536 if (G_UNLIKELY (ret != GST_FLOW_OK))
7538 gst_buffer_map (buf, &map, GST_MAP_READ);
7539 if (!qtdemux_parse_moof (qtdemux, map.data, map.size, offset, NULL)) {
7540 gst_buffer_unmap (buf, &map);
7541 gst_buffer_unref (buf);
7546 gst_buffer_unmap (buf, &map);
7547 gst_buffer_unref (buf);
7551 /* look for next moof */
7552 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
7553 if (G_UNLIKELY (ret != GST_FLOW_OK))
7557 GST_OBJECT_LOCK (qtdemux);
7559 qtdemux->moof_offset = offset;
7565 GST_DEBUG_OBJECT (qtdemux, "failed to parse moof");
7567 res = GST_FLOW_ERROR;
7572 /* maybe upstream temporarily flushing */
7573 if (ret != GST_FLOW_FLUSHING) {
7574 GST_DEBUG_OBJECT (qtdemux, "no next moof");
7577 GST_DEBUG_OBJECT (qtdemux, "upstream WRONG_STATE");
7578 /* resume at current position next time */
7585 /* initialise bytereaders for stbl sub-atoms */
7587 qtdemux_stbl_init (GstQTDemux * qtdemux, QtDemuxStream * stream, GNode * stbl)
7589 stream->stbl_index = -1; /* no samples have yet been parsed */
7590 stream->sample_index = -1;
7592 /* time-to-sample atom */
7593 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stts, &stream->stts))
7596 /* copy atom data into a new buffer for later use */
7597 stream->stts.data = g_memdup (stream->stts.data, stream->stts.size);
7599 /* skip version + flags */
7600 if (!gst_byte_reader_skip (&stream->stts, 1 + 3) ||
7601 !gst_byte_reader_get_uint32_be (&stream->stts, &stream->n_sample_times))
7603 GST_LOG_OBJECT (qtdemux, "%u timestamp blocks", stream->n_sample_times);
7605 /* make sure there's enough data */
7606 if (!qt_atom_parser_has_chunks (&stream->stts, stream->n_sample_times, 8)) {
7607 stream->n_sample_times = gst_byte_reader_get_remaining (&stream->stts) / 8;
7608 GST_LOG_OBJECT (qtdemux, "overriding to %u timestamp blocks",
7609 stream->n_sample_times);
7610 if (!stream->n_sample_times)
7614 /* sync sample atom */
7615 stream->stps_present = FALSE;
7616 if ((stream->stss_present =
7617 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stss,
7618 &stream->stss) ? TRUE : FALSE) == TRUE) {
7619 /* copy atom data into a new buffer for later use */
7620 stream->stss.data = g_memdup (stream->stss.data, stream->stss.size);
7622 /* skip version + flags */
7623 if (!gst_byte_reader_skip (&stream->stss, 1 + 3) ||
7624 !gst_byte_reader_get_uint32_be (&stream->stss, &stream->n_sample_syncs))
7627 if (stream->n_sample_syncs) {
7628 /* make sure there's enough data */
7629 if (!qt_atom_parser_has_chunks (&stream->stss, stream->n_sample_syncs, 4))
7633 /* partial sync sample atom */
7634 if ((stream->stps_present =
7635 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stps,
7636 &stream->stps) ? TRUE : FALSE) == TRUE) {
7637 /* copy atom data into a new buffer for later use */
7638 stream->stps.data = g_memdup (stream->stps.data, stream->stps.size);
7640 /* skip version + flags */
7641 if (!gst_byte_reader_skip (&stream->stps, 1 + 3) ||
7642 !gst_byte_reader_get_uint32_be (&stream->stps,
7643 &stream->n_sample_partial_syncs))
7646 /* if there are no entries, the stss table contains the real
7648 if (stream->n_sample_partial_syncs) {
7649 /* make sure there's enough data */
7650 if (!qt_atom_parser_has_chunks (&stream->stps,
7651 stream->n_sample_partial_syncs, 4))
7658 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsz, &stream->stsz))
7661 /* copy atom data into a new buffer for later use */
7662 stream->stsz.data = g_memdup (stream->stsz.data, stream->stsz.size);
7664 /* skip version + flags */
7665 if (!gst_byte_reader_skip (&stream->stsz, 1 + 3) ||
7666 !gst_byte_reader_get_uint32_be (&stream->stsz, &stream->sample_size))
7669 if (!gst_byte_reader_get_uint32_be (&stream->stsz, &stream->n_samples))
7672 if (!stream->n_samples)
7675 /* sample-to-chunk atom */
7676 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsc, &stream->stsc))
7679 /* copy atom data into a new buffer for later use */
7680 stream->stsc.data = g_memdup (stream->stsc.data, stream->stsc.size);
7682 /* skip version + flags */
7683 if (!gst_byte_reader_skip (&stream->stsc, 1 + 3) ||
7684 !gst_byte_reader_get_uint32_be (&stream->stsc,
7685 &stream->n_samples_per_chunk))
7688 GST_DEBUG_OBJECT (qtdemux, "n_samples_per_chunk %u",
7689 stream->n_samples_per_chunk);
7691 /* make sure there's enough data */
7692 if (!qt_atom_parser_has_chunks (&stream->stsc, stream->n_samples_per_chunk,
7698 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stco, &stream->stco))
7699 stream->co_size = sizeof (guint32);
7700 else if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_co64,
7702 stream->co_size = sizeof (guint64);
7706 /* copy atom data into a new buffer for later use */
7707 stream->stco.data = g_memdup (stream->stco.data, stream->stco.size);
7709 /* skip version + flags */
7710 if (!gst_byte_reader_skip (&stream->stco, 1 + 3))
7713 /* chunks_are_samples == TRUE means treat chunks as samples */
7714 stream->chunks_are_samples = stream->sample_size && !stream->sampled;
7715 if (stream->chunks_are_samples) {
7716 /* treat chunks as samples */
7717 if (!gst_byte_reader_get_uint32_be (&stream->stco, &stream->n_samples))
7720 /* skip number of entries */
7721 if (!gst_byte_reader_skip (&stream->stco, 4))
7724 /* make sure there are enough data in the stsz atom */
7725 if (!stream->sample_size) {
7726 /* different sizes for each sample */
7727 if (!qt_atom_parser_has_chunks (&stream->stsz, stream->n_samples, 4))
7732 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
7733 stream->n_samples, (guint) sizeof (QtDemuxSample),
7734 stream->n_samples * sizeof (QtDemuxSample) / (1024.0 * 1024.0));
7736 if (stream->n_samples >=
7737 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample)) {
7738 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
7739 "be larger than %uMB (broken file?)", stream->n_samples,
7740 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
7744 g_assert (stream->samples == NULL);
7745 stream->samples = g_try_new0 (QtDemuxSample, stream->n_samples);
7746 if (!stream->samples) {
7747 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
7752 /* composition time-to-sample */
7753 if ((stream->ctts_present =
7754 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_ctts,
7755 &stream->ctts) ? TRUE : FALSE) == TRUE) {
7756 GstByteReader cslg = GST_BYTE_READER_INIT (NULL, 0);
7758 /* copy atom data into a new buffer for later use */
7759 stream->ctts.data = g_memdup (stream->ctts.data, stream->ctts.size);
7761 /* skip version + flags */
7762 if (!gst_byte_reader_skip (&stream->ctts, 1 + 3)
7763 || !gst_byte_reader_get_uint32_be (&stream->ctts,
7764 &stream->n_composition_times))
7767 /* make sure there's enough data */
7768 if (!qt_atom_parser_has_chunks (&stream->ctts, stream->n_composition_times,
7772 /* This is optional, if missing we iterate the ctts */
7773 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_cslg, &cslg)) {
7774 if (!gst_byte_reader_skip (&cslg, 1 + 3)
7775 || !gst_byte_reader_get_uint32_be (&cslg, &stream->cslg_shift)) {
7776 g_free ((gpointer) cslg.data);
7780 gint32 cslg_least = 0;
7781 guint num_entries, pos;
7784 pos = gst_byte_reader_get_pos (&stream->ctts);
7785 num_entries = stream->n_composition_times;
7787 stream->cslg_shift = 0;
7789 for (i = 0; i < num_entries; i++) {
7792 gst_byte_reader_skip_unchecked (&stream->ctts, 4);
7793 offset = gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
7795 if (offset < cslg_least)
7796 cslg_least = offset;
7800 stream->cslg_shift = ABS (cslg_least);
7802 stream->cslg_shift = 0;
7804 /* reset the reader so we can generate sample table */
7805 gst_byte_reader_set_pos (&stream->ctts, pos);
7808 /* Ensure the cslg_shift value is consistent so we can use it
7809 * unconditionnally to produce TS and Segment */
7810 stream->cslg_shift = 0;
7817 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
7818 (_("This file is corrupt and cannot be played.")), (NULL));
7823 gst_qtdemux_stbl_free (stream);
7824 if (!qtdemux->fragmented) {
7825 /* not quite good */
7826 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
7829 /* may pick up samples elsewhere */
7835 /* collect samples from the next sample to be parsed up to sample @n for @stream
7836 * by reading the info from @stbl
7838 * This code can be executed from both the streaming thread and the seeking
7839 * thread so it takes the object lock to protect itself
7842 qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream, guint32 n)
7845 QtDemuxSample *samples, *first, *cur, *last;
7846 guint32 n_samples_per_chunk;
7849 GST_LOG_OBJECT (qtdemux, "parsing samples for stream fourcc %"
7850 GST_FOURCC_FORMAT ", pad %s", GST_FOURCC_ARGS (stream->fourcc),
7851 stream->pad ? GST_PAD_NAME (stream->pad) : "(NULL)");
7853 n_samples = stream->n_samples;
7856 goto out_of_samples;
7858 GST_OBJECT_LOCK (qtdemux);
7859 if (n <= stream->stbl_index)
7860 goto already_parsed;
7862 GST_DEBUG_OBJECT (qtdemux, "parsing up to sample %u", n);
7864 if (!stream->stsz.data) {
7865 /* so we already parsed and passed all the moov samples;
7866 * onto fragmented ones */
7867 g_assert (qtdemux->fragmented);
7871 /* pointer to the sample table */
7872 samples = stream->samples;
7874 /* starts from -1, moves to the next sample index to parse */
7875 stream->stbl_index++;
7877 /* keep track of the first and last sample to fill */
7878 first = &samples[stream->stbl_index];
7881 if (!stream->chunks_are_samples) {
7882 /* set the sample sizes */
7883 if (stream->sample_size == 0) {
7884 /* different sizes for each sample */
7885 for (cur = first; cur <= last; cur++) {
7886 cur->size = gst_byte_reader_get_uint32_be_unchecked (&stream->stsz);
7887 GST_LOG_OBJECT (qtdemux, "sample %d has size %u",
7888 (guint) (cur - samples), cur->size);
7891 /* samples have the same size */
7892 GST_LOG_OBJECT (qtdemux, "all samples have size %u", stream->sample_size);
7893 for (cur = first; cur <= last; cur++)
7894 cur->size = stream->sample_size;
7898 n_samples_per_chunk = stream->n_samples_per_chunk;
7901 for (i = stream->stsc_index; i < n_samples_per_chunk; i++) {
7904 if (stream->stsc_chunk_index >= stream->last_chunk
7905 || stream->stsc_chunk_index < stream->first_chunk) {
7906 stream->first_chunk =
7907 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
7908 stream->samples_per_chunk =
7909 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
7910 gst_byte_reader_skip_unchecked (&stream->stsc, 4);
7912 /* chunk numbers are counted from 1 it seems */
7913 if (G_UNLIKELY (stream->first_chunk == 0))
7916 --stream->first_chunk;
7918 /* the last chunk of each entry is calculated by taking the first chunk
7919 * of the next entry; except if there is no next, where we fake it with
7921 if (G_UNLIKELY (i == (stream->n_samples_per_chunk - 1))) {
7922 stream->last_chunk = G_MAXUINT32;
7924 stream->last_chunk =
7925 gst_byte_reader_peek_uint32_be_unchecked (&stream->stsc);
7926 if (G_UNLIKELY (stream->last_chunk == 0))
7929 --stream->last_chunk;
7932 GST_LOG_OBJECT (qtdemux,
7933 "entry %d has first_chunk %d, last_chunk %d, samples_per_chunk %d", i,
7934 stream->first_chunk, stream->last_chunk, stream->samples_per_chunk);
7936 if (G_UNLIKELY (stream->last_chunk < stream->first_chunk))
7939 if (stream->last_chunk != G_MAXUINT32) {
7940 if (!qt_atom_parser_peek_sub (&stream->stco,
7941 stream->first_chunk * stream->co_size,
7942 (stream->last_chunk - stream->first_chunk) * stream->co_size,
7947 stream->co_chunk = stream->stco;
7948 if (!gst_byte_reader_skip (&stream->co_chunk,
7949 stream->first_chunk * stream->co_size))
7953 stream->stsc_chunk_index = stream->first_chunk;
7956 last_chunk = stream->last_chunk;
7958 if (stream->chunks_are_samples) {
7959 cur = &samples[stream->stsc_chunk_index];
7961 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
7964 stream->stsc_chunk_index = j;
7969 qt_atom_parser_get_offset_unchecked (&stream->co_chunk,
7972 GST_LOG_OBJECT (qtdemux, "Created entry %d with offset "
7973 "%" G_GUINT64_FORMAT, j, cur->offset);
7975 if (stream->samples_per_frame * stream->bytes_per_frame) {
7977 (stream->samples_per_chunk * stream->n_channels) /
7978 stream->samples_per_frame * stream->bytes_per_frame;
7980 cur->size = stream->samples_per_chunk;
7983 GST_DEBUG_OBJECT (qtdemux,
7984 "keyframe sample %d: timestamp %" GST_TIME_FORMAT ", size %u",
7985 j, GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream,
7986 stream->stco_sample_index)), cur->size);
7988 cur->timestamp = stream->stco_sample_index;
7989 cur->duration = stream->samples_per_chunk;
7990 cur->keyframe = TRUE;
7993 stream->stco_sample_index += stream->samples_per_chunk;
7995 stream->stsc_chunk_index = j;
7997 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
7998 guint32 samples_per_chunk;
7999 guint64 chunk_offset;
8001 if (!stream->stsc_sample_index
8002 && !qt_atom_parser_get_offset (&stream->co_chunk, stream->co_size,
8003 &stream->chunk_offset))
8006 samples_per_chunk = stream->samples_per_chunk;
8007 chunk_offset = stream->chunk_offset;
8009 for (k = stream->stsc_sample_index; k < samples_per_chunk; k++) {
8010 GST_LOG_OBJECT (qtdemux, "creating entry %d with offset %"
8011 G_GUINT64_FORMAT " and size %d",
8012 (guint) (cur - samples), chunk_offset, cur->size);
8014 cur->offset = chunk_offset;
8015 chunk_offset += cur->size;
8018 if (G_UNLIKELY (cur > last)) {
8020 stream->stsc_sample_index = k + 1;
8021 stream->chunk_offset = chunk_offset;
8022 stream->stsc_chunk_index = j;
8026 stream->stsc_sample_index = 0;
8028 stream->stsc_chunk_index = j;
8030 stream->stsc_index++;
8033 if (stream->chunks_are_samples)
8037 guint32 n_sample_times;
8039 n_sample_times = stream->n_sample_times;
8042 for (i = stream->stts_index; i < n_sample_times; i++) {
8043 guint32 stts_samples;
8044 gint32 stts_duration;
8047 if (stream->stts_sample_index >= stream->stts_samples
8048 || !stream->stts_sample_index) {
8050 stream->stts_samples =
8051 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
8052 stream->stts_duration =
8053 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
8055 GST_LOG_OBJECT (qtdemux, "block %d, %u timestamps, duration %u",
8056 i, stream->stts_samples, stream->stts_duration);
8058 stream->stts_sample_index = 0;
8061 stts_samples = stream->stts_samples;
8062 stts_duration = stream->stts_duration;
8063 stts_time = stream->stts_time;
8065 for (j = stream->stts_sample_index; j < stts_samples; j++) {
8066 GST_DEBUG_OBJECT (qtdemux,
8067 "sample %d: index %d, timestamp %" GST_TIME_FORMAT,
8068 (guint) (cur - samples), j,
8069 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stts_time)));
8071 cur->timestamp = stts_time;
8072 cur->duration = stts_duration;
8074 /* avoid 32-bit wrap-around,
8075 * but still mind possible 'negative' duration */
8076 stts_time += (gint64) stts_duration;
8079 if (G_UNLIKELY (cur > last)) {
8081 stream->stts_time = stts_time;
8082 stream->stts_sample_index = j + 1;
8086 stream->stts_sample_index = 0;
8087 stream->stts_time = stts_time;
8088 stream->stts_index++;
8090 /* fill up empty timestamps with the last timestamp, this can happen when
8091 * the last samples do not decode and so we don't have timestamps for them.
8092 * We however look at the last timestamp to estimate the track length so we
8093 * need something in here. */
8094 for (; cur < last; cur++) {
8095 GST_DEBUG_OBJECT (qtdemux,
8096 "fill sample %d: timestamp %" GST_TIME_FORMAT,
8097 (guint) (cur - samples),
8098 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stream->stts_time)));
8099 cur->timestamp = stream->stts_time;
8105 /* sample sync, can be NULL */
8106 if (stream->stss_present == TRUE) {
8107 guint32 n_sample_syncs;
8109 n_sample_syncs = stream->n_sample_syncs;
8111 if (!n_sample_syncs) {
8112 GST_DEBUG_OBJECT (qtdemux, "all samples are keyframes");
8113 stream->all_keyframe = TRUE;
8115 for (i = stream->stss_index; i < n_sample_syncs; i++) {
8116 /* note that the first sample is index 1, not 0 */
8119 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stss);
8121 if (G_LIKELY (index > 0 && index <= n_samples)) {
8123 samples[index].keyframe = TRUE;
8124 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
8125 /* and exit if we have enough samples */
8126 if (G_UNLIKELY (index >= n)) {
8133 stream->stss_index = i;
8136 /* stps marks partial sync frames like open GOP I-Frames */
8137 if (stream->stps_present == TRUE) {
8138 guint32 n_sample_partial_syncs;
8140 n_sample_partial_syncs = stream->n_sample_partial_syncs;
8142 /* if there are no entries, the stss table contains the real
8144 if (n_sample_partial_syncs) {
8145 for (i = stream->stps_index; i < n_sample_partial_syncs; i++) {
8146 /* note that the first sample is index 1, not 0 */
8149 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stps);
8151 if (G_LIKELY (index > 0 && index <= n_samples)) {
8153 samples[index].keyframe = TRUE;
8154 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
8155 /* and exit if we have enough samples */
8156 if (G_UNLIKELY (index >= n)) {
8163 stream->stps_index = i;
8167 /* no stss, all samples are keyframes */
8168 stream->all_keyframe = TRUE;
8169 GST_DEBUG_OBJECT (qtdemux, "setting all keyframes");
8174 /* composition time to sample */
8175 if (stream->ctts_present == TRUE) {
8176 guint32 n_composition_times;
8178 gint32 ctts_soffset;
8180 /* Fill in the pts_offsets */
8182 n_composition_times = stream->n_composition_times;
8184 for (i = stream->ctts_index; i < n_composition_times; i++) {
8185 if (stream->ctts_sample_index >= stream->ctts_count
8186 || !stream->ctts_sample_index) {
8187 stream->ctts_count =
8188 gst_byte_reader_get_uint32_be_unchecked (&stream->ctts);
8189 stream->ctts_soffset =
8190 gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
8191 stream->ctts_sample_index = 0;
8194 ctts_count = stream->ctts_count;
8195 ctts_soffset = stream->ctts_soffset;
8197 for (j = stream->ctts_sample_index; j < ctts_count; j++) {
8198 cur->pts_offset = ctts_soffset;
8201 if (G_UNLIKELY (cur > last)) {
8203 stream->ctts_sample_index = j + 1;
8207 stream->ctts_sample_index = 0;
8208 stream->ctts_index++;
8212 stream->stbl_index = n;
8213 /* if index has been completely parsed, free data that is no-longer needed */
8214 if (n + 1 == stream->n_samples) {
8215 gst_qtdemux_stbl_free (stream);
8216 GST_DEBUG_OBJECT (qtdemux, "parsed all available samples;");
8217 if (qtdemux->pullbased) {
8218 GST_DEBUG_OBJECT (qtdemux, "checking for more samples");
8219 while (n + 1 == stream->n_samples)
8220 if (qtdemux_add_fragmented_samples (qtdemux) != GST_FLOW_OK)
8224 GST_OBJECT_UNLOCK (qtdemux);
8231 GST_LOG_OBJECT (qtdemux,
8232 "Tried to parse up to sample %u but this sample has already been parsed",
8234 /* if fragmented, there may be more */
8235 if (qtdemux->fragmented && n == stream->stbl_index)
8237 GST_OBJECT_UNLOCK (qtdemux);
8243 GST_LOG_OBJECT (qtdemux,
8244 "Tried to parse up to sample %u but there are only %u samples", n + 1,
8246 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8247 (_("This file is corrupt and cannot be played.")), (NULL));
8252 GST_OBJECT_UNLOCK (qtdemux);
8253 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8254 (_("This file is corrupt and cannot be played.")), (NULL));
8259 /* collect all segment info for @stream.
8262 qtdemux_parse_segments (GstQTDemux * qtdemux, QtDemuxStream * stream,
8266 /* accept edts if they contain gaps at start and there is only
8267 * one media segment */
8268 gboolean allow_pushbased_edts = TRUE;
8269 gint media_segments_count = 0;
8271 /* parse and prepare segment info from the edit list */
8272 GST_DEBUG_OBJECT (qtdemux, "looking for edit list container");
8273 stream->n_segments = 0;
8274 stream->segments = NULL;
8275 if ((edts = qtdemux_tree_get_child_by_type (trak, FOURCC_edts))) {
8283 GST_DEBUG_OBJECT (qtdemux, "looking for edit list");
8284 if (!(elst = qtdemux_tree_get_child_by_type (edts, FOURCC_elst)))
8287 buffer = elst->data;
8289 n_segments = QT_UINT32 (buffer + 12);
8291 /* we might allocate a bit too much, at least allocate 1 segment */
8292 stream->segments = g_new (QtDemuxSegment, MAX (n_segments, 1));
8294 /* segments always start from 0 */
8298 for (i = 0; i < n_segments; i++) {
8301 QtDemuxSegment *segment;
8303 GstClockTime media_start = GST_CLOCK_TIME_NONE;
8305 media_time = QT_UINT32 (buffer + 20 + i * 12);
8306 duration = QT_UINT32 (buffer + 16 + i * 12);
8308 if (media_time != G_MAXUINT32)
8309 media_start = QTSTREAMTIME_TO_GSTTIME (stream, media_time);
8311 segment = &stream->segments[count++];
8313 /* time and duration expressed in global timescale */
8314 segment->time = stime;
8315 /* add non scaled values so we don't cause roundoff errors */
8316 if (duration || media_start == GST_CLOCK_TIME_NONE) {
8318 stime = QTTIME_TO_GSTTIME (qtdemux, time);
8319 segment->duration = stime - segment->time;
8321 /* zero duration does not imply media_start == media_stop
8322 * but, only specify media_start.*/
8323 stime = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
8324 if (GST_CLOCK_TIME_IS_VALID (stime) && media_time != G_MAXUINT32
8325 && stime >= media_start) {
8326 segment->duration = stime - media_start;
8328 segment->duration = GST_CLOCK_TIME_NONE;
8331 segment->stop_time = stime;
8333 segment->trak_media_start = media_time;
8334 /* media_time expressed in stream timescale */
8335 if (media_time != G_MAXUINT32) {
8336 segment->media_start = media_start;
8337 segment->media_stop = segment->media_start + segment->duration;
8338 media_segments_count++;
8340 segment->media_start = GST_CLOCK_TIME_NONE;
8341 segment->media_stop = GST_CLOCK_TIME_NONE;
8343 rate_int = GST_READ_UINT32_BE (buffer + 24 + i * 12);
8345 if (rate_int <= 1) {
8346 /* 0 is not allowed, some programs write 1 instead of the floating point
8348 GST_WARNING_OBJECT (qtdemux, "found suspicious rate %" G_GUINT32_FORMAT,
8352 segment->rate = rate_int / 65536.0;
8355 GST_DEBUG_OBJECT (qtdemux, "created segment %d time %" GST_TIME_FORMAT
8356 ", duration %" GST_TIME_FORMAT ", media_start %" GST_TIME_FORMAT
8357 " (%" G_GUINT64_FORMAT ") , media_stop %" GST_TIME_FORMAT
8358 " stop_time %" GST_TIME_FORMAT " rate %g, (%d) timescale %u",
8359 i, GST_TIME_ARGS (segment->time),
8360 GST_TIME_ARGS (segment->duration),
8361 GST_TIME_ARGS (segment->media_start), media_time,
8362 GST_TIME_ARGS (segment->media_stop),
8363 GST_TIME_ARGS (segment->stop_time), segment->rate, rate_int,
8365 if (segment->stop_time > qtdemux->segment.stop) {
8366 GST_WARNING_OBJECT (qtdemux, "Segment %d "
8367 " extends to %" GST_TIME_FORMAT
8368 " past the end of the file duration %" GST_TIME_FORMAT
8369 " it will be truncated", i, GST_TIME_ARGS (segment->stop_time),
8370 GST_TIME_ARGS (qtdemux->segment.stop));
8371 qtdemux->segment.stop = segment->stop_time;
8374 GST_DEBUG_OBJECT (qtdemux, "found %d segments", count);
8375 stream->n_segments = count;
8376 if (media_segments_count != 1)
8377 allow_pushbased_edts = FALSE;
8381 /* push based does not handle segments, so act accordingly here,
8382 * and warn if applicable */
8383 if (!qtdemux->pullbased && !allow_pushbased_edts) {
8384 GST_WARNING_OBJECT (qtdemux, "streaming; discarding edit list segments");
8385 /* remove and use default one below, we stream like it anyway */
8386 g_free (stream->segments);
8387 stream->segments = NULL;
8388 stream->n_segments = 0;
8391 /* no segments, create one to play the complete trak */
8392 if (stream->n_segments == 0) {
8393 GstClockTime stream_duration =
8394 QTSTREAMTIME_TO_GSTTIME (stream, stream->duration);
8396 if (stream->segments == NULL)
8397 stream->segments = g_new (QtDemuxSegment, 1);
8399 /* represent unknown our way */
8400 if (stream_duration == 0)
8401 stream_duration = GST_CLOCK_TIME_NONE;
8403 stream->segments[0].time = 0;
8404 stream->segments[0].stop_time = stream_duration;
8405 stream->segments[0].duration = stream_duration;
8406 stream->segments[0].media_start = 0;
8407 stream->segments[0].media_stop = stream_duration;
8408 stream->segments[0].rate = 1.0;
8409 stream->segments[0].trak_media_start = 0;
8411 GST_DEBUG_OBJECT (qtdemux, "created dummy segment %" GST_TIME_FORMAT,
8412 GST_TIME_ARGS (stream_duration));
8413 stream->n_segments = 1;
8414 stream->dummy_segment = TRUE;
8416 GST_DEBUG_OBJECT (qtdemux, "using %d segments", stream->n_segments);
8422 * Parses the stsd atom of a svq3 trak looking for
8423 * the SMI and gama atoms.
8426 qtdemux_parse_svq3_stsd_data (GstQTDemux * qtdemux, GNode * stsd,
8427 guint8 ** gamma, GstBuffer ** seqh)
8429 guint8 *_gamma = NULL;
8430 GstBuffer *_seqh = NULL;
8431 guint8 *stsd_data = stsd->data;
8432 guint32 length = QT_UINT32 (stsd_data);
8436 GST_WARNING_OBJECT (qtdemux, "stsd too short");
8442 version = QT_UINT16 (stsd_data);
8447 while (length > 8) {
8448 guint32 fourcc, size;
8450 size = QT_UINT32 (stsd_data);
8451 fourcc = QT_FOURCC (stsd_data + 4);
8452 data = stsd_data + 8;
8455 GST_WARNING_OBJECT (qtdemux, "Atom of size 0 found, aborting "
8456 "svq3 atom parsing");
8465 GST_WARNING_OBJECT (qtdemux, "Unexpected size %" G_GUINT32_FORMAT
8466 " for gama atom, expected 12", size);
8471 if (size > 16 && QT_FOURCC (data) == FOURCC_SEQH) {
8473 if (_seqh != NULL) {
8474 GST_WARNING_OBJECT (qtdemux, "Unexpected second SEQH SMI atom "
8475 " found, ignoring");
8477 seqh_size = QT_UINT32 (data + 4);
8478 if (seqh_size > 0) {
8479 _seqh = gst_buffer_new_and_alloc (seqh_size);
8480 gst_buffer_fill (_seqh, 0, data + 8, seqh_size);
8487 GST_WARNING_OBJECT (qtdemux, "Unhandled atom %" GST_FOURCC_FORMAT
8488 " in SVQ3 entry in stsd atom", GST_FOURCC_ARGS (fourcc));
8492 if (size <= length) {
8498 GST_WARNING_OBJECT (qtdemux, "SVQ3 entry too short in stsd atom");
8501 GST_WARNING_OBJECT (qtdemux, "Unexpected version for SVQ3 entry %"
8502 G_GUINT16_FORMAT, version);
8513 gst_buffer_unref (_seqh);
8518 qtdemux_get_rtsp_uri_from_hndl (GstQTDemux * qtdemux, GNode * minf)
8525 * Get 'dinf', to get its child 'dref', that might contain a 'hndl'
8526 * atom that might contain a 'data' atom with the rtsp uri.
8527 * This case was reported in bug #597497, some info about
8528 * the hndl atom can be found in TN1195
8530 dinf = qtdemux_tree_get_child_by_type (minf, FOURCC_dinf);
8531 GST_DEBUG_OBJECT (qtdemux, "Trying to obtain rtsp URI for stream trak");
8534 guint32 dref_num_entries = 0;
8535 if (qtdemux_tree_get_child_by_type_full (dinf, FOURCC_dref, &dref) &&
8536 gst_byte_reader_skip (&dref, 4) &&
8537 gst_byte_reader_get_uint32_be (&dref, &dref_num_entries)) {
8540 /* search dref entries for hndl atom */
8541 for (i = 0; i < dref_num_entries; i++) {
8542 guint32 size = 0, type;
8543 guint8 string_len = 0;
8544 if (gst_byte_reader_get_uint32_be (&dref, &size) &&
8545 qt_atom_parser_get_fourcc (&dref, &type)) {
8546 if (type == FOURCC_hndl) {
8547 GST_DEBUG_OBJECT (qtdemux, "Found hndl atom");
8549 /* skip data reference handle bytes and the
8550 * following pascal string and some extra 4
8551 * bytes I have no idea what are */
8552 if (!gst_byte_reader_skip (&dref, 4) ||
8553 !gst_byte_reader_get_uint8 (&dref, &string_len) ||
8554 !gst_byte_reader_skip (&dref, string_len + 4)) {
8555 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl atom");
8559 /* iterate over the atoms to find the data atom */
8560 while (gst_byte_reader_get_remaining (&dref) >= 8) {
8564 if (gst_byte_reader_get_uint32_be (&dref, &atom_size) &&
8565 qt_atom_parser_get_fourcc (&dref, &atom_type)) {
8566 if (atom_type == FOURCC_data) {
8567 const guint8 *uri_aux = NULL;
8569 /* found the data atom that might contain the rtsp uri */
8570 GST_DEBUG_OBJECT (qtdemux, "Found data atom inside "
8571 "hndl atom, interpreting it as an URI");
8572 if (gst_byte_reader_peek_data (&dref, atom_size - 8,
8574 if (g_strstr_len ((gchar *) uri_aux, 7, "rtsp://") != NULL)
8575 uri = g_strndup ((gchar *) uri_aux, atom_size - 8);
8577 GST_WARNING_OBJECT (qtdemux, "Data atom in hndl atom "
8578 "didn't contain a rtsp address");
8580 GST_WARNING_OBJECT (qtdemux, "Failed to get the data "
8585 /* skipping to the next entry */
8586 if (!gst_byte_reader_skip (&dref, atom_size - 8))
8589 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl child "
8596 /* skip to the next entry */
8597 if (!gst_byte_reader_skip (&dref, size - 8))
8600 GST_WARNING_OBJECT (qtdemux, "Error parsing dref atom");
8603 GST_DEBUG_OBJECT (qtdemux, "Finished parsing dref atom");
8609 #define AMR_NB_ALL_MODES 0x81ff
8610 #define AMR_WB_ALL_MODES 0x83ff
8612 qtdemux_parse_amr_bitrate (GstBuffer * buf, gboolean wb)
8614 /* The 'damr' atom is of the form:
8616 * | vendor | decoder_ver | mode_set | mode_change_period | frames/sample |
8617 * 32 b 8 b 16 b 8 b 8 b
8619 * The highest set bit of the first 7 (AMR-NB) or 8 (AMR-WB) bits of mode_set
8620 * represents the highest mode used in the stream (and thus the maximum
8621 * bitrate), with a couple of special cases as seen below.
8624 /* Map of frame type ID -> bitrate */
8625 static const guint nb_bitrates[] = {
8626 4750, 5150, 5900, 6700, 7400, 7950, 10200, 12200
8628 static const guint wb_bitrates[] = {
8629 6600, 8850, 12650, 14250, 15850, 18250, 19850, 23050, 23850
8635 gst_buffer_map (buf, &map, GST_MAP_READ);
8637 if (map.size != 0x11) {
8638 GST_DEBUG ("Atom should have size 0x11, not %" G_GSIZE_FORMAT, map.size);
8642 if (QT_FOURCC (map.data + 4) != FOURCC_damr) {
8643 GST_DEBUG ("Unknown atom in %" GST_FOURCC_FORMAT,
8644 GST_FOURCC_ARGS (QT_UINT32 (map.data + 4)));
8648 mode_set = QT_UINT16 (map.data + 13);
8650 if (mode_set == (wb ? AMR_WB_ALL_MODES : AMR_NB_ALL_MODES))
8651 max_mode = 7 + (wb ? 1 : 0);
8653 /* AMR-NB modes fo from 0-7, and AMR-WB modes go from 0-8 */
8654 max_mode = g_bit_nth_msf ((gulong) mode_set & (wb ? 0x1ff : 0xff), -1);
8656 if (max_mode == -1) {
8657 GST_DEBUG ("No mode indication was found (mode set) = %x",
8662 gst_buffer_unmap (buf, &map);
8663 return wb ? wb_bitrates[max_mode] : nb_bitrates[max_mode];
8666 gst_buffer_unmap (buf, &map);
8671 qtdemux_parse_transformation_matrix (GstQTDemux * qtdemux,
8672 GstByteReader * reader, guint32 * matrix, const gchar * atom)
8675 * 9 values of 32 bits (fixed point 16.16, except 2 5 and 8 that are 2.30)
8681 if (gst_byte_reader_get_remaining (reader) < 36)
8684 matrix[0] = gst_byte_reader_get_uint32_be_unchecked (reader);
8685 matrix[1] = gst_byte_reader_get_uint32_be_unchecked (reader);
8686 matrix[2] = gst_byte_reader_get_uint32_be_unchecked (reader);
8687 matrix[3] = gst_byte_reader_get_uint32_be_unchecked (reader);
8688 matrix[4] = gst_byte_reader_get_uint32_be_unchecked (reader);
8689 matrix[5] = gst_byte_reader_get_uint32_be_unchecked (reader);
8690 matrix[6] = gst_byte_reader_get_uint32_be_unchecked (reader);
8691 matrix[7] = gst_byte_reader_get_uint32_be_unchecked (reader);
8692 matrix[8] = gst_byte_reader_get_uint32_be_unchecked (reader);
8694 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix from atom %s", atom);
8695 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[0] >> 16,
8696 matrix[0] & 0xFFFF, matrix[1] >> 16, matrix[1] & 0xFF, matrix[2] >> 16,
8698 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[3] >> 16,
8699 matrix[3] & 0xFFFF, matrix[4] >> 16, matrix[4] & 0xFF, matrix[5] >> 16,
8701 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[6] >> 16,
8702 matrix[6] & 0xFFFF, matrix[7] >> 16, matrix[7] & 0xFF, matrix[8] >> 16,
8709 qtdemux_inspect_transformation_matrix (GstQTDemux * qtdemux,
8710 QtDemuxStream * stream, guint32 * matrix, GstTagList ** taglist)
8717 * This macro will only compare value abdegh, it expects cfi to have already
8720 #define QTCHECK_MATRIX(m,a,b,d,e) ((m)[0] == (a << 16) && (m)[1] == (b << 16) && \
8721 (m)[3] == (d << 16) && (m)[4] == (e << 16))
8723 /* only handle the cases where the last column has standard values */
8724 if (matrix[2] == 0 && matrix[5] == 0 && matrix[8] == 1 << 30) {
8725 const gchar *rotation_tag = NULL;
8727 /* no rotation needed */
8728 if (QTCHECK_MATRIX (matrix, 1, 0, 0, 1)) {
8730 } else if (QTCHECK_MATRIX (matrix, 0, 1, G_MAXUINT16, 0)) {
8731 rotation_tag = "rotate-90";
8732 } else if (QTCHECK_MATRIX (matrix, G_MAXUINT16, 0, 0, G_MAXUINT16)) {
8733 rotation_tag = "rotate-180";
8734 } else if (QTCHECK_MATRIX (matrix, 0, G_MAXUINT16, 1, 0)) {
8735 rotation_tag = "rotate-270";
8737 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
8740 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix rotation %s",
8742 if (rotation_tag != NULL) {
8743 if (*taglist == NULL)
8744 *taglist = gst_tag_list_new_empty ();
8745 gst_tag_list_add (*taglist, GST_TAG_MERGE_REPLACE,
8746 GST_TAG_IMAGE_ORIENTATION, rotation_tag, NULL);
8749 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
8753 /* Parses the boxes defined in ISO/IEC 14496-12 that enable support for
8754 * protected streams (sinf, frma, schm and schi); if the protection scheme is
8755 * Common Encryption (cenc), the function will also parse the tenc box (defined
8756 * in ISO/IEC 23001-7). @container points to the node that contains these boxes
8757 * (typically an enc[v|a|t|s] sample entry); the function will set
8758 * @original_fmt to the fourcc of the original unencrypted stream format.
8759 * Returns TRUE if successful; FALSE otherwise. */
8761 qtdemux_parse_protection_scheme_info (GstQTDemux * qtdemux,
8762 QtDemuxStream * stream, GNode * container, guint32 * original_fmt)
8769 g_return_val_if_fail (qtdemux != NULL, FALSE);
8770 g_return_val_if_fail (stream != NULL, FALSE);
8771 g_return_val_if_fail (container != NULL, FALSE);
8772 g_return_val_if_fail (original_fmt != NULL, FALSE);
8774 sinf = qtdemux_tree_get_child_by_type (container, FOURCC_sinf);
8775 if (G_UNLIKELY (!sinf)) {
8776 if (stream->protection_scheme_type == FOURCC_cenc) {
8777 GST_ERROR_OBJECT (qtdemux, "sinf box does not contain schi box, which is "
8778 "mandatory for Common Encryption");
8784 frma = qtdemux_tree_get_child_by_type (sinf, FOURCC_frma);
8785 if (G_UNLIKELY (!frma)) {
8786 GST_ERROR_OBJECT (qtdemux, "sinf box does not contain mandatory frma box");
8790 *original_fmt = QT_FOURCC ((const guint8 *) frma->data + 8);
8791 GST_DEBUG_OBJECT (qtdemux, "original stream format: '%" GST_FOURCC_FORMAT "'",
8792 GST_FOURCC_ARGS (*original_fmt));
8794 schm = qtdemux_tree_get_child_by_type (sinf, FOURCC_schm);
8796 GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schm box");
8799 stream->protection_scheme_type = QT_FOURCC ((const guint8 *) schm->data + 12);
8800 stream->protection_scheme_version =
8801 QT_UINT32 ((const guint8 *) schm->data + 16);
8803 GST_DEBUG_OBJECT (qtdemux,
8804 "protection_scheme_type: %" GST_FOURCC_FORMAT ", "
8805 "protection_scheme_version: %#010x",
8806 GST_FOURCC_ARGS (stream->protection_scheme_type),
8807 stream->protection_scheme_version);
8809 schi = qtdemux_tree_get_child_by_type (sinf, FOURCC_schi);
8811 GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schi box");
8814 if (stream->protection_scheme_type == FOURCC_cenc) {
8815 QtDemuxCencSampleSetInfo *info;
8817 const guint8 *tenc_data;
8818 guint32 isEncrypted;
8820 const guint8 *default_kid;
8823 if (G_UNLIKELY (!stream->protection_scheme_info))
8824 stream->protection_scheme_info =
8825 g_malloc0 (sizeof (QtDemuxCencSampleSetInfo));
8827 info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
8829 tenc = qtdemux_tree_get_child_by_type (schi, FOURCC_tenc);
8831 GST_ERROR_OBJECT (qtdemux, "schi box does not contain tenc box, "
8832 "which is mandatory for Common Encryption");
8835 tenc_data = (const guint8 *) tenc->data + 12;
8836 isEncrypted = QT_UINT24 (tenc_data);
8837 iv_size = QT_UINT8 (tenc_data + 3);
8838 default_kid = (tenc_data + 4);
8839 kid_buf = gst_buffer_new_allocate (NULL, 16, NULL);
8840 gst_buffer_fill (kid_buf, 0, default_kid, 16);
8841 if (info->default_properties)
8842 gst_structure_free (info->default_properties);
8843 info->default_properties =
8844 gst_structure_new ("application/x-cenc",
8845 "iv_size", G_TYPE_UINT, iv_size,
8846 "encrypted", G_TYPE_BOOLEAN, (isEncrypted == 1),
8847 "kid", GST_TYPE_BUFFER, kid_buf, NULL);
8848 GST_DEBUG_OBJECT (qtdemux, "default sample properties: "
8849 "is_encrypted=%u, iv_size=%u", isEncrypted, iv_size);
8850 gst_buffer_unref (kid_buf);
8856 * With each track we associate a new QtDemuxStream that contains all the info
8858 * traks that do not decode to something (like strm traks) will not have a pad.
8861 qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
8880 QtDemuxStream *stream = NULL;
8881 gboolean new_stream = FALSE;
8882 gchar *codec = NULL;
8883 const guint8 *stsd_data;
8884 guint16 lang_code; /* quicktime lang code or packed iso code */
8886 guint32 tkhd_flags = 0;
8887 guint8 tkhd_version = 0;
8889 guint value_size, stsd_len, len;
8893 GST_DEBUG_OBJECT (qtdemux, "parse_trak");
8895 if (!qtdemux_tree_get_child_by_type_full (trak, FOURCC_tkhd, &tkhd)
8896 || !gst_byte_reader_get_uint8 (&tkhd, &tkhd_version)
8897 || !gst_byte_reader_get_uint24_be (&tkhd, &tkhd_flags))
8900 /* pick between 64 or 32 bits */
8901 value_size = tkhd_version == 1 ? 8 : 4;
8902 if (!gst_byte_reader_skip (&tkhd, value_size * 2) ||
8903 !gst_byte_reader_get_uint32_be (&tkhd, &track_id))
8906 if (!qtdemux->got_moov) {
8907 if (qtdemux_find_stream (qtdemux, track_id))
8908 goto existing_stream;
8909 stream = _create_stream ();
8910 stream->track_id = track_id;
8913 stream = qtdemux_find_stream (qtdemux, track_id);
8915 GST_WARNING_OBJECT (qtdemux, "Stream not found, going to ignore it");
8919 /* flush samples data from this track from previous moov */
8920 gst_qtdemux_stream_flush_segments_data (qtdemux, stream);
8921 gst_qtdemux_stream_flush_samples_data (qtdemux, stream);
8923 /* need defaults for fragments */
8924 qtdemux_parse_trex (qtdemux, stream, &dummy, &dummy, &dummy);
8926 if (stream->pending_tags == NULL)
8927 stream->pending_tags = gst_tag_list_new_empty ();
8929 if ((tkhd_flags & 1) == 0)
8930 stream->disabled = TRUE;
8932 GST_LOG_OBJECT (qtdemux, "track[tkhd] version/flags/id: 0x%02x/%06x/%u",
8933 tkhd_version, tkhd_flags, stream->track_id);
8935 if (!(mdia = qtdemux_tree_get_child_by_type (trak, FOURCC_mdia)))
8938 if (!(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mdhd))) {
8939 /* be nice for some crooked mjp2 files that use mhdr for mdhd */
8940 if (qtdemux->major_brand != FOURCC_mjp2 ||
8941 !(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mhdr)))
8945 len = QT_UINT32 ((guint8 *) mdhd->data);
8946 version = QT_UINT32 ((guint8 *) mdhd->data + 8);
8947 GST_LOG_OBJECT (qtdemux, "track version/flags: %08x", version);
8948 if (version == 0x01000000) {
8951 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 28);
8952 stream->duration = QT_UINT64 ((guint8 *) mdhd->data + 32);
8953 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 36);
8957 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 20);
8958 stream->duration = QT_UINT32 ((guint8 *) mdhd->data + 24);
8959 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 28);
8962 if (lang_code < 0x400) {
8963 qtdemux_lang_map_qt_code_to_iso (stream->lang_id, lang_code);
8964 } else if (lang_code == 0x7fff) {
8965 stream->lang_id[0] = 0; /* unspecified */
8967 stream->lang_id[0] = 0x60 + ((lang_code >> 10) & 0x1F);
8968 stream->lang_id[1] = 0x60 + ((lang_code >> 5) & 0x1F);
8969 stream->lang_id[2] = 0x60 + (lang_code & 0x1F);
8970 stream->lang_id[3] = 0;
8973 GST_LOG_OBJECT (qtdemux, "track timescale: %" G_GUINT32_FORMAT,
8975 GST_LOG_OBJECT (qtdemux, "track duration: %" G_GUINT64_FORMAT,
8977 GST_LOG_OBJECT (qtdemux, "track language code/id: 0x%04x/%s",
8978 lang_code, stream->lang_id);
8980 if (G_UNLIKELY (stream->timescale == 0 || qtdemux->timescale == 0))
8983 if ((tref = qtdemux_tree_get_child_by_type (trak, FOURCC_tref))) {
8984 /* chapters track reference */
8985 GNode *chap = qtdemux_tree_get_child_by_type (tref, FOURCC_chap);
8987 gsize length = GST_READ_UINT32_BE (chap->data);
8988 if (qtdemux->chapters_track_id)
8989 GST_FIXME_OBJECT (qtdemux, "Multiple CHAP tracks");
8992 qtdemux->chapters_track_id =
8993 GST_READ_UINT32_BE ((gint8 *) chap->data + 8);
8998 /* fragmented files may have bogus duration in moov */
8999 if (!qtdemux->fragmented &&
9000 qtdemux->duration != G_MAXINT64 && stream->duration != G_MAXINT32) {
9001 guint64 tdur1, tdur2;
9003 /* don't overflow */
9004 tdur1 = stream->timescale * (guint64) qtdemux->duration;
9005 tdur2 = qtdemux->timescale * (guint64) stream->duration;
9008 * some of those trailers, nowadays, have prologue images that are
9009 * themselves vide tracks as well. I haven't really found a way to
9010 * identify those yet, except for just looking at their duration. */
9011 if (tdur1 != 0 && (tdur2 * 10 / tdur1) < 2) {
9012 GST_WARNING_OBJECT (qtdemux,
9013 "Track shorter than 20%% (%" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT
9014 " vs. %" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT ") of the stream "
9015 "found, assuming preview image or something; skipping track",
9016 stream->duration, stream->timescale, qtdemux->duration,
9017 qtdemux->timescale);
9019 gst_qtdemux_stream_free (qtdemux, stream);
9024 if (!(hdlr = qtdemux_tree_get_child_by_type (mdia, FOURCC_hdlr)))
9027 GST_LOG_OBJECT (qtdemux, "track type: %" GST_FOURCC_FORMAT,
9028 GST_FOURCC_ARGS (QT_FOURCC ((guint8 *) hdlr->data + 12)));
9030 len = QT_UINT32 ((guint8 *) hdlr->data);
9032 stream->subtype = QT_FOURCC ((guint8 *) hdlr->data + 16);
9033 GST_LOG_OBJECT (qtdemux, "track subtype: %" GST_FOURCC_FORMAT,
9034 GST_FOURCC_ARGS (stream->subtype));
9036 if (!(minf = qtdemux_tree_get_child_by_type (mdia, FOURCC_minf)))
9039 if (!(stbl = qtdemux_tree_get_child_by_type (minf, FOURCC_stbl)))
9042 /*parse svmi header if existing */
9043 svmi = qtdemux_tree_get_child_by_type (stbl, FOURCC_svmi);
9045 len = QT_UINT32 ((guint8 *) svmi->data);
9046 version = QT_UINT32 ((guint8 *) svmi->data + 8);
9048 GstVideoMultiviewMode mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
9049 GstVideoMultiviewFlags flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
9050 guint8 frame_type, frame_layout;
9052 /* MPEG-A stereo video */
9053 if (qtdemux->major_brand == FOURCC_ss02)
9054 flags |= GST_VIDEO_MULTIVIEW_FLAGS_MIXED_MONO;
9056 frame_type = QT_UINT8 ((guint8 *) svmi->data + 12);
9057 frame_layout = QT_UINT8 ((guint8 *) svmi->data + 13) & 0x01;
9058 switch (frame_type) {
9060 mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
9063 mode = GST_VIDEO_MULTIVIEW_MODE_ROW_INTERLEAVED;
9066 mode = GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME;
9069 /* mode 3 is primary/secondary view sequence, ie
9070 * left/right views in separate tracks. See section 7.2
9071 * of ISO/IEC 23000-11:2009 */
9072 GST_FIXME_OBJECT (qtdemux,
9073 "Implement stereo video in separate streams");
9076 if ((frame_layout & 0x1) == 0)
9077 flags |= GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
9079 GST_LOG_OBJECT (qtdemux,
9080 "StereoVideo: composition type: %u, is_left_first: %u",
9081 frame_type, frame_layout);
9082 stream->multiview_mode = mode;
9083 stream->multiview_flags = flags;
9088 if (!(stsd = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsd)))
9090 stsd_data = (const guint8 *) stsd->data;
9092 /* stsd should at least have one entry */
9093 stsd_len = QT_UINT32 (stsd_data);
9094 if (stsd_len < 24) {
9095 /* .. but skip stream with empty stsd produced by some Vivotek cameras */
9096 if (stream->subtype == FOURCC_vivo) {
9098 gst_qtdemux_stream_free (qtdemux, stream);
9105 GST_LOG_OBJECT (qtdemux, "stsd len: %d", stsd_len);
9107 /* and that entry should fit within stsd */
9108 len = QT_UINT32 (stsd_data + 16);
9109 if (len > stsd_len + 16)
9112 stream->fourcc = fourcc = QT_FOURCC (stsd_data + 16 + 4);
9113 GST_LOG_OBJECT (qtdemux, "stsd type: %" GST_FOURCC_FORMAT,
9114 GST_FOURCC_ARGS (stream->fourcc));
9115 GST_LOG_OBJECT (qtdemux, "stsd type len: %d", len);
9117 if ((fourcc == FOURCC_drms) || (fourcc == FOURCC_drmi))
9118 goto error_encrypted;
9120 if (fourcc == FOURCC_encv || fourcc == FOURCC_enca) {
9121 GNode *enc = qtdemux_tree_get_child_by_type (stsd, fourcc);
9122 stream->protected = TRUE;
9123 if (!qtdemux_parse_protection_scheme_info (qtdemux, stream, enc, &fourcc))
9124 GST_ERROR_OBJECT (qtdemux, "Failed to parse protection scheme info");
9127 if (stream->subtype == FOURCC_vide) {
9128 guint32 w = 0, h = 0;
9130 gint depth, palette_size, palette_count;
9132 guint32 *palette_data = NULL;
9134 stream->sampled = TRUE;
9136 /* version 1 uses some 64-bit ints */
9137 if (!gst_byte_reader_skip (&tkhd, 20 + value_size))
9140 if (!qtdemux_parse_transformation_matrix (qtdemux, &tkhd, matrix, "tkhd"))
9143 if (!gst_byte_reader_get_uint32_be (&tkhd, &w)
9144 || !gst_byte_reader_get_uint32_be (&tkhd, &h))
9147 stream->display_width = w >> 16;
9148 stream->display_height = h >> 16;
9150 qtdemux_inspect_transformation_matrix (qtdemux, stream, matrix,
9151 &stream->pending_tags);
9157 stream->width = QT_UINT16 (stsd_data + offset + 32);
9158 stream->height = QT_UINT16 (stsd_data + offset + 34);
9159 stream->fps_n = 0; /* this is filled in later */
9160 stream->fps_d = 0; /* this is filled in later */
9161 stream->bits_per_sample = QT_UINT16 (stsd_data + offset + 82);
9162 stream->color_table_id = QT_UINT16 (stsd_data + offset + 84);
9164 /* if color_table_id is 0, ctab atom must follow; however some files
9165 * produced by TMPEGEnc have color_table_id = 0 and no ctab atom, so
9166 * if color table is not present we'll correct the value */
9167 if (stream->color_table_id == 0 &&
9168 (len < 90 || QT_FOURCC (stsd_data + offset + 86) != FOURCC_ctab)) {
9169 stream->color_table_id = -1;
9172 GST_LOG_OBJECT (qtdemux, "width %d, height %d, bps %d, color table id %d",
9173 stream->width, stream->height, stream->bits_per_sample,
9174 stream->color_table_id);
9176 depth = stream->bits_per_sample;
9178 /* more than 32 bits means grayscale */
9179 gray = (depth > 32);
9180 /* low 32 bits specify the depth */
9183 /* different number of palette entries is determined by depth. */
9185 if ((depth == 1) || (depth == 2) || (depth == 4) || (depth == 8))
9186 palette_count = (1 << depth);
9187 palette_size = palette_count * 4;
9189 if (stream->color_table_id) {
9190 switch (palette_count) {
9194 palette_data = g_memdup (ff_qt_default_palette_2, palette_size);
9197 palette_data = g_memdup (ff_qt_default_palette_4, palette_size);
9201 palette_data = g_memdup (ff_qt_grayscale_palette_16, palette_size);
9203 palette_data = g_memdup (ff_qt_default_palette_16, palette_size);
9207 palette_data = g_memdup (ff_qt_grayscale_palette_256, palette_size);
9209 palette_data = g_memdup (ff_qt_default_palette_256, palette_size);
9212 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
9213 (_("The video in this file might not play correctly.")),
9214 ("unsupported palette depth %d", depth));
9218 gint i, j, start, end;
9224 start = QT_UINT32 (stsd_data + offset + 86);
9225 palette_count = QT_UINT16 (stsd_data + offset + 90);
9226 end = QT_UINT16 (stsd_data + offset + 92);
9228 GST_LOG_OBJECT (qtdemux, "start %d, end %d, palette_count %d",
9229 start, end, palette_count);
9236 if (len < 94 + (end - start) * 8)
9239 /* palette is always the same size */
9240 palette_data = g_malloc0 (256 * 4);
9241 palette_size = 256 * 4;
9243 for (j = 0, i = start; i <= end; j++, i++) {
9246 a = QT_UINT16 (stsd_data + offset + 94 + (j * 8));
9247 r = QT_UINT16 (stsd_data + offset + 96 + (j * 8));
9248 g = QT_UINT16 (stsd_data + offset + 98 + (j * 8));
9249 b = QT_UINT16 (stsd_data + offset + 100 + (j * 8));
9251 palette_data[i] = ((a & 0xff00) << 16) | ((r & 0xff00) << 8) |
9252 (g & 0xff00) | (b >> 8);
9257 gst_caps_unref (stream->caps);
9260 qtdemux_video_caps (qtdemux, stream, fourcc, stsd_data, &codec);
9261 if (G_UNLIKELY (!stream->caps)) {
9262 g_free (palette_data);
9263 goto unknown_stream;
9267 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
9268 GST_TAG_VIDEO_CODEC, codec, NULL);
9277 if (stream->rgb8_palette)
9278 gst_memory_unref (stream->rgb8_palette);
9279 stream->rgb8_palette = gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY,
9280 palette_data, palette_size, 0, palette_size, palette_data, g_free);
9282 s = gst_caps_get_structure (stream->caps, 0);
9284 /* non-raw video has a palette_data property. raw video has the palette as
9285 * an extra plane that we append to the output buffers before we push
9287 if (!gst_structure_has_name (s, "video/x-raw")) {
9290 palette = gst_buffer_new ();
9291 gst_buffer_append_memory (palette, stream->rgb8_palette);
9292 stream->rgb8_palette = NULL;
9294 gst_caps_set_simple (stream->caps, "palette_data",
9295 GST_TYPE_BUFFER, palette, NULL);
9296 gst_buffer_unref (palette);
9298 } else if (palette_count != 0) {
9299 GST_ELEMENT_WARNING (qtdemux, STREAM, NOT_IMPLEMENTED,
9300 (NULL), ("Unsupported palette depth %d", depth));
9303 GST_LOG_OBJECT (qtdemux, "frame count: %u",
9304 QT_UINT16 (stsd_data + offset + 48));
9308 /* pick 'the' stsd child */
9309 if (!stream->protected)
9310 mp4v = qtdemux_tree_get_child_by_type (stsd, fourcc);
9312 mp4v = qtdemux_tree_get_child_by_type (stsd, FOURCC_encv);
9315 esds = qtdemux_tree_get_child_by_type (mp4v, FOURCC_esds);
9316 pasp = qtdemux_tree_get_child_by_type (mp4v, FOURCC_pasp);
9320 const guint8 *pasp_data = (const guint8 *) pasp->data;
9322 stream->par_w = QT_UINT32 (pasp_data + 8);
9323 stream->par_h = QT_UINT32 (pasp_data + 12);
9330 gst_qtdemux_handle_esds (qtdemux, stream, esds, stream->pending_tags);
9337 gint len = QT_UINT32 (stsd_data) - 0x66;
9338 const guint8 *avc_data = stsd_data + 0x66;
9341 while (len >= 0x8) {
9344 if (QT_UINT32 (avc_data) <= len)
9345 size = QT_UINT32 (avc_data) - 0x8;
9350 /* No real data, so break out */
9353 switch (QT_FOURCC (avc_data + 0x4)) {
9356 /* parse, if found */
9359 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
9361 /* First 4 bytes are the length of the atom, the next 4 bytes
9362 * are the fourcc, the next 1 byte is the version, and the
9363 * subsequent bytes are profile_tier_level structure like data. */
9364 gst_codec_utils_h264_caps_set_level_and_profile (stream->caps,
9365 avc_data + 8 + 1, size - 1);
9366 buf = gst_buffer_new_and_alloc (size);
9367 gst_buffer_fill (buf, 0, avc_data + 0x8, size);
9368 gst_caps_set_simple (stream->caps,
9369 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9370 gst_buffer_unref (buf);
9378 GST_DEBUG_OBJECT (qtdemux, "found strf codec_data in stsd");
9380 /* First 4 bytes are the length of the atom, the next 4 bytes
9381 * are the fourcc, next 40 bytes are BITMAPINFOHEADER,
9382 * next 1 byte is the version, and the
9383 * subsequent bytes are sequence parameter set like data. */
9385 size -= 40; /* we'll be skipping BITMAPINFOHEADER */
9387 gst_codec_utils_h264_caps_set_level_and_profile (stream->caps,
9388 avc_data + 8 + 40 + 1, size - 1);
9390 buf = gst_buffer_new_and_alloc (size);
9391 gst_buffer_fill (buf, 0, avc_data + 8 + 40, size);
9392 gst_caps_set_simple (stream->caps,
9393 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9394 gst_buffer_unref (buf);
9400 guint avg_bitrate, max_bitrate;
9402 /* bufferSizeDB, maxBitrate and avgBitrate - 4 bytes each */
9406 max_bitrate = QT_UINT32 (avc_data + 0xc);
9407 avg_bitrate = QT_UINT32 (avc_data + 0x10);
9409 if (!max_bitrate && !avg_bitrate)
9412 /* Some muxers seem to swap the average and maximum bitrates
9413 * (I'm looking at you, YouTube), so we swap for sanity. */
9414 if (max_bitrate > 0 && max_bitrate < avg_bitrate) {
9415 guint temp = avg_bitrate;
9417 avg_bitrate = max_bitrate;
9421 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
9422 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
9423 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
9425 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
9426 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
9427 GST_TAG_BITRATE, avg_bitrate, NULL);
9438 avc_data += size + 8;
9447 gint len = QT_UINT32 (stsd_data) - 0x66;
9448 const guint8 *hevc_data = stsd_data + 0x66;
9451 while (len >= 0x8) {
9454 if (QT_UINT32 (hevc_data) <= len)
9455 size = QT_UINT32 (hevc_data) - 0x8;
9460 /* No real data, so break out */
9463 switch (QT_FOURCC (hevc_data + 0x4)) {
9466 /* parse, if found */
9469 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
9471 /* First 4 bytes are the length of the atom, the next 4 bytes
9472 * are the fourcc, the next 1 byte is the version, and the
9473 * subsequent bytes are sequence parameter set like data. */
9474 gst_codec_utils_h265_caps_set_level_tier_and_profile
9475 (stream->caps, hevc_data + 8 + 1, size - 1);
9477 buf = gst_buffer_new_and_alloc (size);
9478 gst_buffer_fill (buf, 0, hevc_data + 0x8, size);
9479 gst_caps_set_simple (stream->caps,
9480 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9481 gst_buffer_unref (buf);
9488 hevc_data += size + 8;
9499 GST_DEBUG_OBJECT (qtdemux, "found %" GST_FOURCC_FORMAT,
9500 GST_FOURCC_ARGS (fourcc));
9502 /* codec data might be in glbl extension atom */
9504 qtdemux_tree_get_child_by_type (mp4v, FOURCC_glbl) : NULL;
9510 GST_DEBUG_OBJECT (qtdemux, "found glbl data in stsd");
9512 len = QT_UINT32 (data);
9515 buf = gst_buffer_new_and_alloc (len);
9516 gst_buffer_fill (buf, 0, data + 8, len);
9517 gst_caps_set_simple (stream->caps,
9518 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9519 gst_buffer_unref (buf);
9526 /* see annex I of the jpeg2000 spec */
9527 GNode *jp2h, *ihdr, *colr, *mjp2, *field, *prefix, *cmap, *cdef;
9529 const gchar *colorspace = NULL;
9531 guint32 ncomp_map = 0;
9532 gint32 *comp_map = NULL;
9533 guint32 nchan_def = 0;
9534 gint32 *chan_def = NULL;
9536 GST_DEBUG_OBJECT (qtdemux, "found mjp2");
9537 /* some required atoms */
9538 mjp2 = qtdemux_tree_get_child_by_type (stsd, FOURCC_mjp2);
9541 jp2h = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2h);
9545 /* number of components; redundant with info in codestream, but useful
9547 ihdr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_ihdr);
9548 if (!ihdr || QT_UINT32 (ihdr->data) != 22)
9550 ncomp = QT_UINT16 (((guint8 *) ihdr->data) + 16);
9552 colr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_colr);
9555 GST_DEBUG_OBJECT (qtdemux, "found colr");
9556 /* extract colour space info */
9557 if (QT_UINT8 ((guint8 *) colr->data + 8) == 1) {
9558 switch (QT_UINT32 ((guint8 *) colr->data + 11)) {
9560 colorspace = "sRGB";
9563 colorspace = "GRAY";
9566 colorspace = "sYUV";
9574 /* colr is required, and only values 16, 17, and 18 are specified,
9575 so error if we have no colorspace */
9578 /* extract component mapping */
9579 cmap = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cmap);
9581 guint32 cmap_len = 0;
9583 cmap_len = QT_UINT32 (cmap->data);
9584 if (cmap_len >= 8) {
9585 /* normal box, subtract off header */
9587 /* cmap: { u16 cmp; u8 mtyp; u8 pcol; }* */
9588 if (cmap_len % 4 == 0) {
9589 ncomp_map = (cmap_len / 4);
9590 comp_map = g_new0 (gint32, ncomp_map);
9591 for (i = 0; i < ncomp_map; i++) {
9594 cmp = QT_UINT16 (((guint8 *) cmap->data) + 8 + i * 4);
9595 mtyp = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 2);
9596 pcol = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 3);
9597 comp_map[i] = (mtyp << 24) | (pcol << 16) | cmp;
9602 /* extract channel definitions */
9603 cdef = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cdef);
9605 guint32 cdef_len = 0;
9607 cdef_len = QT_UINT32 (cdef->data);
9608 if (cdef_len >= 10) {
9609 /* normal box, subtract off header and len */
9611 /* cdef: u16 n; { u16 cn; u16 typ; u16 asoc; }* */
9612 if (cdef_len % 6 == 0) {
9613 nchan_def = (cdef_len / 6);
9614 chan_def = g_new0 (gint32, nchan_def);
9615 for (i = 0; i < nchan_def; i++)
9617 for (i = 0; i < nchan_def; i++) {
9618 guint16 cn, typ, asoc;
9619 cn = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6);
9620 typ = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 2);
9621 asoc = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 4);
9622 if (cn < nchan_def) {
9625 chan_def[cn] = asoc;
9628 chan_def[cn] = 0; /* alpha */
9631 chan_def[cn] = -typ;
9639 gst_caps_set_simple (stream->caps,
9640 "num-components", G_TYPE_INT, ncomp, NULL);
9641 gst_caps_set_simple (stream->caps,
9642 "colorspace", G_TYPE_STRING, colorspace, NULL);
9645 GValue arr = { 0, };
9646 GValue elt = { 0, };
9648 g_value_init (&arr, GST_TYPE_ARRAY);
9649 g_value_init (&elt, G_TYPE_INT);
9650 for (i = 0; i < ncomp_map; i++) {
9651 g_value_set_int (&elt, comp_map[i]);
9652 gst_value_array_append_value (&arr, &elt);
9654 gst_structure_set_value (gst_caps_get_structure (stream->caps, 0),
9655 "component-map", &arr);
9656 g_value_unset (&elt);
9657 g_value_unset (&arr);
9662 GValue arr = { 0, };
9663 GValue elt = { 0, };
9665 g_value_init (&arr, GST_TYPE_ARRAY);
9666 g_value_init (&elt, G_TYPE_INT);
9667 for (i = 0; i < nchan_def; i++) {
9668 g_value_set_int (&elt, chan_def[i]);
9669 gst_value_array_append_value (&arr, &elt);
9671 gst_structure_set_value (gst_caps_get_structure (stream->caps, 0),
9672 "channel-definitions", &arr);
9673 g_value_unset (&elt);
9674 g_value_unset (&arr);
9678 /* some optional atoms */
9679 field = qtdemux_tree_get_child_by_type (mjp2, FOURCC_fiel);
9680 prefix = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2x);
9682 /* indicate possible fields in caps */
9684 data = (guint8 *) field->data + 8;
9686 gst_caps_set_simple (stream->caps, "fields", G_TYPE_INT,
9687 (gint) * data, NULL);
9689 /* add codec_data if provided */
9694 GST_DEBUG_OBJECT (qtdemux, "found prefix data in stsd");
9695 data = prefix->data;
9696 len = QT_UINT32 (data);
9699 buf = gst_buffer_new_and_alloc (len);
9700 gst_buffer_fill (buf, 0, data + 8, len);
9701 gst_caps_set_simple (stream->caps,
9702 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9703 gst_buffer_unref (buf);
9712 GstBuffer *seqh = NULL;
9713 guint8 *gamma_data = NULL;
9714 gint len = QT_UINT32 (stsd_data);
9716 qtdemux_parse_svq3_stsd_data (qtdemux, stsd, &gamma_data, &seqh);
9718 gst_caps_set_simple (stream->caps, "applied-gamma", G_TYPE_DOUBLE,
9719 QT_FP32 (gamma_data), NULL);
9722 /* sorry for the bad name, but we don't know what this is, other
9723 * than its own fourcc */
9724 gst_caps_set_simple (stream->caps, "seqh", GST_TYPE_BUFFER, seqh,
9728 GST_DEBUG_OBJECT (qtdemux, "found codec_data in stsd");
9729 buf = gst_buffer_new_and_alloc (len);
9730 gst_buffer_fill (buf, 0, stsd_data, len);
9731 gst_caps_set_simple (stream->caps,
9732 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9733 gst_buffer_unref (buf);
9739 gst_caps_set_simple (stream->caps,
9740 "depth", G_TYPE_INT, QT_UINT16 (stsd_data + offset + 82), NULL);
9747 GST_DEBUG_OBJECT (qtdemux, "found XiTh");
9748 xith = qtdemux_tree_get_child_by_type (stsd, FOURCC_XiTh);
9752 xdxt = qtdemux_tree_get_child_by_type (xith, FOURCC_XdxT);
9756 GST_DEBUG_OBJECT (qtdemux, "found XdxT node");
9757 /* collect the headers and store them in a stream list so that we can
9758 * send them out first */
9759 qtdemux_parse_theora_extension (qtdemux, stream, xdxt);
9769 GST_DEBUG_OBJECT (qtdemux, "parse ovc1 header");
9770 ovc1 = qtdemux_tree_get_child_by_type (stsd, FOURCC_ovc1);
9773 ovc1_data = ovc1->data;
9774 ovc1_len = QT_UINT32 (ovc1_data);
9775 if (ovc1_len <= 198) {
9776 GST_WARNING_OBJECT (qtdemux, "Too small ovc1 header, skipping");
9779 buf = gst_buffer_new_and_alloc (ovc1_len - 198);
9780 gst_buffer_fill (buf, 0, ovc1_data + 198, ovc1_len - 198);
9781 gst_caps_set_simple (stream->caps,
9782 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9783 gst_buffer_unref (buf);
9788 gint len = QT_UINT32 (stsd_data) - 0x66;
9789 const guint8 *vc1_data = stsd_data + 0x66;
9795 if (QT_UINT32 (vc1_data) <= len)
9796 size = QT_UINT32 (vc1_data) - 8;
9801 /* No real data, so break out */
9804 switch (QT_FOURCC (vc1_data + 0x4)) {
9805 case GST_MAKE_FOURCC ('d', 'v', 'c', '1'):
9809 GST_DEBUG_OBJECT (qtdemux, "found dvc1 codec_data in stsd");
9810 buf = gst_buffer_new_and_alloc (size);
9811 gst_buffer_fill (buf, 0, vc1_data + 8, size);
9812 gst_caps_set_simple (stream->caps,
9813 "codec_data", GST_TYPE_BUFFER, buf, NULL);
9814 gst_buffer_unref (buf);
9821 vc1_data += size + 8;
9830 GST_INFO_OBJECT (qtdemux,
9831 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
9832 GST_FOURCC_ARGS (fourcc), stream->caps);
9834 } else if (stream->subtype == FOURCC_soun) {
9835 int version, samplesize;
9836 guint16 compression_id;
9837 gboolean amrwb = FALSE;
9840 /* sample description entry (16) + sound sample description v0 (20) */
9844 version = QT_UINT32 (stsd_data + offset);
9845 stream->n_channels = QT_UINT16 (stsd_data + offset + 8);
9846 samplesize = QT_UINT16 (stsd_data + offset + 10);
9847 compression_id = QT_UINT16 (stsd_data + offset + 12);
9848 stream->rate = QT_FP32 (stsd_data + offset + 16);
9850 GST_LOG_OBJECT (qtdemux, "version/rev: %08x", version);
9851 GST_LOG_OBJECT (qtdemux, "vendor: %08x",
9852 QT_UINT32 (stsd_data + offset + 4));
9853 GST_LOG_OBJECT (qtdemux, "n_channels: %d", stream->n_channels);
9854 GST_LOG_OBJECT (qtdemux, "sample_size: %d", samplesize);
9855 GST_LOG_OBJECT (qtdemux, "compression_id: %d", compression_id);
9856 GST_LOG_OBJECT (qtdemux, "packet size: %d",
9857 QT_UINT16 (stsd_data + offset + 14));
9858 GST_LOG_OBJECT (qtdemux, "sample rate: %g", stream->rate);
9860 if (compression_id == 0xfffe)
9861 stream->sampled = TRUE;
9863 /* first assume uncompressed audio */
9864 stream->bytes_per_sample = samplesize / 8;
9865 stream->samples_per_frame = stream->n_channels;
9866 stream->bytes_per_frame = stream->n_channels * stream->bytes_per_sample;
9867 stream->samples_per_packet = stream->samples_per_frame;
9868 stream->bytes_per_packet = stream->bytes_per_sample;
9872 /* Yes, these have to be hard-coded */
9875 stream->samples_per_packet = 6;
9876 stream->bytes_per_packet = 1;
9877 stream->bytes_per_frame = 1 * stream->n_channels;
9878 stream->bytes_per_sample = 1;
9879 stream->samples_per_frame = 6 * stream->n_channels;
9884 stream->samples_per_packet = 3;
9885 stream->bytes_per_packet = 1;
9886 stream->bytes_per_frame = 1 * stream->n_channels;
9887 stream->bytes_per_sample = 1;
9888 stream->samples_per_frame = 3 * stream->n_channels;
9893 stream->samples_per_packet = 64;
9894 stream->bytes_per_packet = 34;
9895 stream->bytes_per_frame = 34 * stream->n_channels;
9896 stream->bytes_per_sample = 2;
9897 stream->samples_per_frame = 64 * stream->n_channels;
9903 stream->samples_per_packet = 1;
9904 stream->bytes_per_packet = 1;
9905 stream->bytes_per_frame = 1 * stream->n_channels;
9906 stream->bytes_per_sample = 1;
9907 stream->samples_per_frame = 1 * stream->n_channels;
9912 stream->samples_per_packet = 160;
9913 stream->bytes_per_packet = 33;
9914 stream->bytes_per_frame = 33 * stream->n_channels;
9915 stream->bytes_per_sample = 2;
9916 stream->samples_per_frame = 160 * stream->n_channels;
9923 if (version == 0x00010000) {
9924 /* sample description entry (16) + sound sample description v1 (20+16) */
9935 /* only parse extra decoding config for non-pcm audio */
9936 stream->samples_per_packet = QT_UINT32 (stsd_data + offset);
9937 stream->bytes_per_packet = QT_UINT32 (stsd_data + offset + 4);
9938 stream->bytes_per_frame = QT_UINT32 (stsd_data + offset + 8);
9939 stream->bytes_per_sample = QT_UINT32 (stsd_data + offset + 12);
9941 GST_LOG_OBJECT (qtdemux, "samples/packet: %d",
9942 stream->samples_per_packet);
9943 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
9944 stream->bytes_per_packet);
9945 GST_LOG_OBJECT (qtdemux, "bytes/frame: %d",
9946 stream->bytes_per_frame);
9947 GST_LOG_OBJECT (qtdemux, "bytes/sample: %d",
9948 stream->bytes_per_sample);
9950 if (!stream->sampled && stream->bytes_per_packet) {
9951 stream->samples_per_frame = (stream->bytes_per_frame /
9952 stream->bytes_per_packet) * stream->samples_per_packet;
9953 GST_LOG_OBJECT (qtdemux, "samples/frame: %d",
9954 stream->samples_per_frame);
9959 } else if (version == 0x00020000) {
9966 /* sample description entry (16) + sound sample description v2 (56) */
9970 qtfp.val = QT_UINT64 (stsd_data + offset + 4);
9971 stream->rate = qtfp.fp;
9972 stream->n_channels = QT_UINT32 (stsd_data + offset + 12);
9974 GST_LOG_OBJECT (qtdemux, "Sound sample description Version 2");
9975 GST_LOG_OBJECT (qtdemux, "sample rate: %g", stream->rate);
9976 GST_LOG_OBJECT (qtdemux, "n_channels: %d", stream->n_channels);
9977 GST_LOG_OBJECT (qtdemux, "bits/channel: %d",
9978 QT_UINT32 (stsd_data + offset + 20));
9979 GST_LOG_OBJECT (qtdemux, "format flags: %X",
9980 QT_UINT32 (stsd_data + offset + 24));
9981 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
9982 QT_UINT32 (stsd_data + offset + 28));
9983 GST_LOG_OBJECT (qtdemux, "LPCM frames/packet: %d",
9984 QT_UINT32 (stsd_data + offset + 32));
9985 } else if (version != 0x00000) {
9986 GST_WARNING_OBJECT (qtdemux, "unknown audio STSD version %08x", version);
9990 gst_caps_unref (stream->caps);
9992 stream->caps = qtdemux_audio_caps (qtdemux, stream, fourcc,
9993 stsd_data + 32, len - 16, &codec);
10001 in24 = qtdemux_tree_get_child_by_type (stsd, FOURCC_in24);
10003 enda = qtdemux_tree_get_child_by_type (in24, FOURCC_enda);
10005 wave = qtdemux_tree_get_child_by_type (in24, FOURCC_wave);
10007 enda = qtdemux_tree_get_child_by_type (wave, FOURCC_enda);
10010 int enda_value = QT_UINT16 ((guint8 *) enda->data + 8);
10011 gst_caps_set_simple (stream->caps,
10012 "format", G_TYPE_STRING, (enda_value) ? "S24LE" : "S24BE", NULL);
10019 const guint8 *owma_data;
10020 const gchar *codec_name = NULL;
10024 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
10025 /* FIXME this should also be gst_riff_strf_auds,
10026 * but the latter one is actually missing bits-per-sample :( */
10031 gint32 nSamplesPerSec;
10032 gint32 nAvgBytesPerSec;
10033 gint16 nBlockAlign;
10034 gint16 wBitsPerSample;
10037 WAVEFORMATEX *wfex;
10039 GST_DEBUG_OBJECT (qtdemux, "parse owma");
10040 owma = qtdemux_tree_get_child_by_type (stsd, FOURCC_owma);
10043 owma_data = owma->data;
10044 owma_len = QT_UINT32 (owma_data);
10045 if (owma_len <= 54) {
10046 GST_WARNING_OBJECT (qtdemux, "Too small owma header, skipping");
10049 wfex = (WAVEFORMATEX *) (owma_data + 36);
10050 buf = gst_buffer_new_and_alloc (owma_len - 54);
10051 gst_buffer_fill (buf, 0, owma_data + 54, owma_len - 54);
10052 if (wfex->wFormatTag == 0x0161) {
10053 codec_name = "Windows Media Audio";
10055 } else if (wfex->wFormatTag == 0x0162) {
10056 codec_name = "Windows Media Audio 9 Pro";
10058 } else if (wfex->wFormatTag == 0x0163) {
10059 codec_name = "Windows Media Audio 9 Lossless";
10060 /* is that correct? gstffmpegcodecmap.c is missing it, but
10061 * fluendo codec seems to support it */
10065 gst_caps_set_simple (stream->caps,
10066 "codec_data", GST_TYPE_BUFFER, buf,
10067 "wmaversion", G_TYPE_INT, version,
10068 "block_align", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->nBlockAlign),
10069 "bitrate", G_TYPE_INT, GST_READ_UINT32_LE (&wfex->nAvgBytesPerSec),
10070 "width", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->wBitsPerSample),
10071 "depth", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->wBitsPerSample),
10073 gst_buffer_unref (buf);
10077 codec = g_strdup (codec_name);
10083 gint len = QT_UINT32 (stsd_data) - offset;
10084 const guint8 *wfex_data = stsd_data + offset;
10085 const gchar *codec_name = NULL;
10087 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
10088 /* FIXME this should also be gst_riff_strf_auds,
10089 * but the latter one is actually missing bits-per-sample :( */
10094 gint32 nSamplesPerSec;
10095 gint32 nAvgBytesPerSec;
10096 gint16 nBlockAlign;
10097 gint16 wBitsPerSample;
10102 /* FIXME: unify with similar wavformatex parsing code above */
10103 GST_DEBUG_OBJECT (qtdemux, "parse wma, looking for wfex");
10109 if (QT_UINT32 (wfex_data) <= len)
10110 size = QT_UINT32 (wfex_data) - 8;
10115 /* No real data, so break out */
10118 switch (QT_FOURCC (wfex_data + 4)) {
10119 case GST_MAKE_FOURCC ('w', 'f', 'e', 'x'):
10121 GST_DEBUG_OBJECT (qtdemux, "found wfex in stsd");
10126 wfex.wFormatTag = GST_READ_UINT16_LE (wfex_data + 8 + 0);
10127 wfex.nChannels = GST_READ_UINT16_LE (wfex_data + 8 + 2);
10128 wfex.nSamplesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 4);
10129 wfex.nAvgBytesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 8);
10130 wfex.nBlockAlign = GST_READ_UINT16_LE (wfex_data + 8 + 12);
10131 wfex.wBitsPerSample = GST_READ_UINT16_LE (wfex_data + 8 + 14);
10132 wfex.cbSize = GST_READ_UINT16_LE (wfex_data + 8 + 16);
10134 GST_LOG_OBJECT (qtdemux, "Found wfex box in stsd:");
10135 GST_LOG_OBJECT (qtdemux, "FormatTag = 0x%04x, Channels = %u, "
10136 "SamplesPerSec = %u, AvgBytesPerSec = %u, BlockAlign = %u, "
10137 "BitsPerSample = %u, Size = %u", wfex.wFormatTag,
10138 wfex.nChannels, wfex.nSamplesPerSec, wfex.nAvgBytesPerSec,
10139 wfex.nBlockAlign, wfex.wBitsPerSample, wfex.cbSize);
10141 if (wfex.wFormatTag == 0x0161) {
10142 codec_name = "Windows Media Audio";
10144 } else if (wfex.wFormatTag == 0x0162) {
10145 codec_name = "Windows Media Audio 9 Pro";
10147 } else if (wfex.wFormatTag == 0x0163) {
10148 codec_name = "Windows Media Audio 9 Lossless";
10149 /* is that correct? gstffmpegcodecmap.c is missing it, but
10150 * fluendo codec seems to support it */
10154 gst_caps_set_simple (stream->caps,
10155 "wmaversion", G_TYPE_INT, version,
10156 "block_align", G_TYPE_INT, wfex.nBlockAlign,
10157 "bitrate", G_TYPE_INT, wfex.nAvgBytesPerSec,
10158 "width", G_TYPE_INT, wfex.wBitsPerSample,
10159 "depth", G_TYPE_INT, wfex.wBitsPerSample, NULL);
10161 if (size > wfex.cbSize) {
10164 buf = gst_buffer_new_and_alloc (size - wfex.cbSize);
10165 gst_buffer_fill (buf, 0, wfex_data + 8 + wfex.cbSize,
10166 size - wfex.cbSize);
10167 gst_caps_set_simple (stream->caps,
10168 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10169 gst_buffer_unref (buf);
10171 GST_WARNING_OBJECT (qtdemux, "no codec data");
10176 codec = g_strdup (codec_name);
10184 wfex_data += size + 8;
10191 const guint8 *opus_data;
10192 guint8 *channel_mapping = NULL;
10195 guint8 channel_mapping_family;
10196 guint8 stream_count;
10197 guint8 coupled_count;
10200 opus = qtdemux_tree_get_child_by_type (stsd, FOURCC_opus);
10201 opus_data = opus->data;
10203 channels = GST_READ_UINT8 (opus_data + 45);
10204 rate = GST_READ_UINT32_LE (opus_data + 48);
10205 channel_mapping_family = GST_READ_UINT8 (opus_data + 54);
10206 stream_count = GST_READ_UINT8 (opus_data + 55);
10207 coupled_count = GST_READ_UINT8 (opus_data + 56);
10209 if (channels > 0) {
10210 channel_mapping = g_malloc (channels * sizeof (guint8));
10211 for (i = 0; i < channels; i++)
10212 channel_mapping[i] = GST_READ_UINT8 (opus_data + i + 57);
10215 stream->caps = gst_codec_utils_opus_create_caps (rate, channels,
10216 channel_mapping_family, stream_count, coupled_count,
10228 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
10229 GST_TAG_AUDIO_CODEC, codec, NULL);
10233 /* some bitrate info may have ended up in caps */
10234 s = gst_caps_get_structure (stream->caps, 0);
10235 gst_structure_get_int (s, "bitrate", &bitrate);
10237 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
10238 GST_TAG_BITRATE, bitrate, NULL);
10241 if (stream->protected && fourcc == FOURCC_mp4a)
10242 mp4a = qtdemux_tree_get_child_by_type (stsd, FOURCC_enca);
10244 mp4a = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4a);
10249 wave = qtdemux_tree_get_child_by_type (mp4a, FOURCC_wave);
10251 esds = qtdemux_tree_get_child_by_type (wave, FOURCC_esds);
10253 esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
10257 /* If the fourcc's bottom 16 bits gives 'sm', then the top
10258 16 bits is a byte-swapped wave-style codec identifier,
10259 and we can find a WAVE header internally to a 'wave' atom here.
10260 This can more clearly be thought of as 'ms' as the top 16 bits, and a
10261 codec id as the bottom 16 bits - but byte-swapped to store in QT (which
10264 if ((fourcc & 0xffff) == (('s' << 8) | 'm')) {
10265 if (len < offset + 20) {
10266 GST_WARNING_OBJECT (qtdemux, "No wave atom in MS-style audio");
10268 guint32 datalen = QT_UINT32 (stsd_data + offset + 16);
10269 const guint8 *data = stsd_data + offset + 16;
10271 GNode *waveheadernode;
10273 wavenode = g_node_new ((guint8 *) data);
10274 if (qtdemux_parse_node (qtdemux, wavenode, data, datalen)) {
10275 const guint8 *waveheader;
10278 waveheadernode = qtdemux_tree_get_child_by_type (wavenode, fourcc);
10279 if (waveheadernode) {
10280 waveheader = (const guint8 *) waveheadernode->data;
10281 headerlen = QT_UINT32 (waveheader);
10283 if (headerlen > 8) {
10284 gst_riff_strf_auds *header = NULL;
10285 GstBuffer *headerbuf;
10291 headerbuf = gst_buffer_new_and_alloc (headerlen);
10292 gst_buffer_fill (headerbuf, 0, waveheader, headerlen);
10294 if (gst_riff_parse_strf_auds (GST_ELEMENT_CAST (qtdemux),
10295 headerbuf, &header, &extra)) {
10296 gst_caps_unref (stream->caps);
10297 /* FIXME: Need to do something with the channel reorder map */
10298 stream->caps = gst_riff_create_audio_caps (header->format, NULL,
10299 header, extra, NULL, NULL, NULL);
10302 gst_buffer_unref (extra);
10307 GST_DEBUG ("Didn't find waveheadernode for this codec");
10309 g_node_destroy (wavenode);
10312 gst_qtdemux_handle_esds (qtdemux, stream, esds, stream->pending_tags);
10316 /* FIXME: what is in the chunk? */
10319 gint len = QT_UINT32 (stsd_data);
10321 /* seems to be always = 116 = 0x74 */
10327 gint len = QT_UINT32 (stsd_data);
10330 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x4C);
10332 gst_buffer_fill (buf, 0, stsd_data + 0x4C, len - 0x4C);
10333 gst_caps_set_simple (stream->caps,
10334 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10335 gst_buffer_unref (buf);
10337 gst_caps_set_simple (stream->caps,
10338 "samplesize", G_TYPE_INT, samplesize, NULL);
10343 GNode *alac, *wave = NULL;
10345 /* apparently, m4a has this atom appended directly in the stsd entry,
10346 * while mov has it in a wave atom */
10347 alac = qtdemux_tree_get_child_by_type (stsd, FOURCC_alac);
10349 /* alac now refers to stsd entry atom */
10350 wave = qtdemux_tree_get_child_by_type (alac, FOURCC_wave);
10352 alac = qtdemux_tree_get_child_by_type (wave, FOURCC_alac);
10354 alac = qtdemux_tree_get_child_by_type (alac, FOURCC_alac);
10357 const guint8 *alac_data = alac->data;
10358 gint len = QT_UINT32 (alac->data);
10362 GST_DEBUG_OBJECT (qtdemux,
10363 "discarding alac atom with unexpected len %d", len);
10365 /* codec-data contains alac atom size and prefix,
10366 * ffmpeg likes it that way, not quite gst-ish though ...*/
10367 buf = gst_buffer_new_and_alloc (len);
10368 gst_buffer_fill (buf, 0, alac->data, len);
10369 gst_caps_set_simple (stream->caps,
10370 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10371 gst_buffer_unref (buf);
10373 stream->bytes_per_frame = QT_UINT32 (alac_data + 12);
10374 stream->n_channels = QT_UINT8 (alac_data + 21);
10375 stream->rate = QT_UINT32 (alac_data + 32);
10378 gst_caps_set_simple (stream->caps,
10379 "samplesize", G_TYPE_INT, samplesize, NULL);
10387 gint len = QT_UINT32 (stsd_data);
10390 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x34);
10393 gst_buffer_fill (buf, 0, stsd_data + 0x34, len - 0x34);
10395 /* If we have enough data, let's try to get the 'damr' atom. See
10396 * the 3GPP container spec (26.244) for more details. */
10397 if ((len - 0x34) > 8 &&
10398 (bitrate = qtdemux_parse_amr_bitrate (buf, amrwb))) {
10399 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
10400 GST_TAG_MAXIMUM_BITRATE, bitrate, NULL);
10403 gst_caps_set_simple (stream->caps,
10404 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10405 gst_buffer_unref (buf);
10411 /* mp4a atom withtout ESDS; Attempt to build codec data from atom */
10412 gint len = QT_UINT32 (stsd_data);
10415 guint16 sound_version = QT_UINT16 (stsd_data + 32);
10417 if (sound_version == 1) {
10418 guint16 channels = QT_UINT16 (stsd_data + 40);
10419 guint32 time_scale = QT_UINT32 (stsd_data + 46);
10420 guint8 codec_data[2];
10422 gint profile = 2; /* FIXME: Can this be determined somehow? There doesn't seem to be anything in mp4a atom that specifis compression */
10424 gint sample_rate_index =
10425 gst_codec_utils_aac_get_index_from_sample_rate (time_scale);
10427 /* build AAC codec data */
10428 codec_data[0] = profile << 3;
10429 codec_data[0] |= ((sample_rate_index >> 1) & 0x7);
10430 codec_data[1] = (sample_rate_index & 0x01) << 7;
10431 codec_data[1] |= (channels & 0xF) << 3;
10433 buf = gst_buffer_new_and_alloc (2);
10434 gst_buffer_fill (buf, 0, codec_data, 2);
10435 gst_caps_set_simple (stream->caps,
10436 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10437 gst_buffer_unref (buf);
10443 GST_INFO_OBJECT (qtdemux,
10444 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
10448 GST_INFO_OBJECT (qtdemux,
10449 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
10450 GST_FOURCC_ARGS (fourcc), stream->caps);
10452 } else if (stream->subtype == FOURCC_strm) {
10453 if (fourcc == FOURCC_rtsp) {
10454 stream->redirect_uri = qtdemux_get_rtsp_uri_from_hndl (qtdemux, minf);
10456 GST_INFO_OBJECT (qtdemux, "unhandled stream type %" GST_FOURCC_FORMAT,
10457 GST_FOURCC_ARGS (fourcc));
10458 goto unknown_stream;
10460 stream->sampled = TRUE;
10461 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
10462 || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt) {
10464 stream->sampled = TRUE;
10465 stream->sparse = TRUE;
10468 qtdemux_sub_caps (qtdemux, stream, fourcc, stsd_data, &codec);
10470 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
10471 GST_TAG_SUBTITLE_CODEC, codec, NULL);
10476 /* hunt for sort-of codec data */
10480 GNode *mp4s = NULL;
10481 GNode *esds = NULL;
10483 /* look for palette in a stsd->mp4s->esds sub-atom */
10484 mp4s = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4s);
10486 esds = qtdemux_tree_get_child_by_type (mp4s, FOURCC_esds);
10487 if (esds == NULL) {
10489 GST_LOG_OBJECT (qtdemux, "Skipping invalid stsd: no esds child");
10493 gst_qtdemux_handle_esds (qtdemux, stream, esds, stream->pending_tags);
10497 GST_INFO_OBJECT (qtdemux,
10498 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
10501 GST_INFO_OBJECT (qtdemux,
10502 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
10503 GST_FOURCC_ARGS (fourcc), stream->caps);
10505 /* everything in 1 sample */
10506 stream->sampled = TRUE;
10509 qtdemux_generic_caps (qtdemux, stream, fourcc, stsd_data, &codec);
10511 if (stream->caps == NULL)
10512 goto unknown_stream;
10515 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
10516 GST_TAG_SUBTITLE_CODEC, codec, NULL);
10522 /* promote to sampled format */
10523 if (stream->fourcc == FOURCC_samr) {
10524 /* force mono 8000 Hz for AMR */
10525 stream->sampled = TRUE;
10526 stream->n_channels = 1;
10527 stream->rate = 8000;
10528 } else if (stream->fourcc == FOURCC_sawb) {
10529 /* force mono 16000 Hz for AMR-WB */
10530 stream->sampled = TRUE;
10531 stream->n_channels = 1;
10532 stream->rate = 16000;
10533 } else if (stream->fourcc == FOURCC_mp4a) {
10534 stream->sampled = TRUE;
10537 /* collect sample information */
10538 if (!qtdemux_stbl_init (qtdemux, stream, stbl))
10539 goto samples_failed;
10541 if (qtdemux->fragmented) {
10544 /* need all moov samples as basis; probably not many if any at all */
10545 /* prevent moof parsing taking of at this time */
10546 offset = qtdemux->moof_offset;
10547 qtdemux->moof_offset = 0;
10548 if (stream->n_samples &&
10549 !qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
10550 qtdemux->moof_offset = offset;
10551 goto samples_failed;
10553 qtdemux->moof_offset = 0;
10554 /* movie duration more reliable in this case (e.g. mehd) */
10555 if (qtdemux->segment.duration &&
10556 GST_CLOCK_TIME_IS_VALID (qtdemux->segment.duration))
10558 GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->segment.duration);
10561 /* configure segments */
10562 if (!qtdemux_parse_segments (qtdemux, stream, trak))
10563 goto segments_failed;
10565 /* add some language tag, if useful */
10566 if (stream->lang_id[0] != '\0' && strcmp (stream->lang_id, "unk") &&
10567 strcmp (stream->lang_id, "und")) {
10568 const gchar *lang_code;
10570 /* convert ISO 639-2 code to ISO 639-1 */
10571 lang_code = gst_tag_get_language_code (stream->lang_id);
10572 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
10573 GST_TAG_LANGUAGE_CODE, (lang_code) ? lang_code : stream->lang_id, NULL);
10576 /* Check for UDTA tags */
10577 if ((udta = qtdemux_tree_get_child_by_type (trak, FOURCC_udta))) {
10578 qtdemux_parse_udta (qtdemux, stream->pending_tags, udta);
10581 /* now we are ready to add the stream */
10582 if (qtdemux->n_streams >= GST_QTDEMUX_MAX_STREAMS)
10583 goto too_many_streams;
10585 if (!qtdemux->got_moov) {
10586 qtdemux->streams[qtdemux->n_streams] = stream;
10587 qtdemux->n_streams++;
10588 GST_DEBUG_OBJECT (qtdemux, "n_streams is now %d", qtdemux->n_streams);
10596 GST_INFO_OBJECT (qtdemux, "skip disabled track");
10598 gst_qtdemux_stream_free (qtdemux, stream);
10603 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
10604 (_("This file is corrupt and cannot be played.")), (NULL));
10606 gst_qtdemux_stream_free (qtdemux, stream);
10611 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT, (NULL), (NULL));
10613 gst_qtdemux_stream_free (qtdemux, stream);
10619 /* we posted an error already */
10620 /* free stbl sub-atoms */
10621 gst_qtdemux_stbl_free (stream);
10623 gst_qtdemux_stream_free (qtdemux, stream);
10628 GST_INFO_OBJECT (qtdemux, "stream with track id %i already exists",
10631 gst_qtdemux_stream_free (qtdemux, stream);
10636 GST_INFO_OBJECT (qtdemux, "unknown subtype %" GST_FOURCC_FORMAT,
10637 GST_FOURCC_ARGS (stream->subtype));
10639 gst_qtdemux_stream_free (qtdemux, stream);
10644 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
10645 (_("This file contains too many streams. Only playing first %d"),
10646 GST_QTDEMUX_MAX_STREAMS), (NULL));
10651 /* If we can estimate the overall bitrate, and don't have information about the
10652 * stream bitrate for exactly one stream, this guesses the stream bitrate as
10653 * the overall bitrate minus the sum of the bitrates of all other streams. This
10654 * should be useful for the common case where we have one audio and one video
10655 * stream and can estimate the bitrate of one, but not the other. */
10657 gst_qtdemux_guess_bitrate (GstQTDemux * qtdemux)
10659 QtDemuxStream *stream = NULL;
10660 gint64 size, sys_bitrate, sum_bitrate = 0;
10661 GstClockTime duration;
10665 if (qtdemux->fragmented)
10668 GST_DEBUG_OBJECT (qtdemux, "Looking for streams with unknown bitrate");
10670 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &size)
10672 GST_DEBUG_OBJECT (qtdemux,
10673 "Size in bytes of the stream not known - bailing");
10677 /* Subtract the header size */
10678 GST_DEBUG_OBJECT (qtdemux, "Total size %" G_GINT64_FORMAT ", header size %u",
10679 size, qtdemux->header_size);
10681 if (size < qtdemux->header_size)
10684 size = size - qtdemux->header_size;
10686 if (!gst_qtdemux_get_duration (qtdemux, &duration)) {
10687 GST_DEBUG_OBJECT (qtdemux, "Stream duration not known - bailing");
10691 for (i = 0; i < qtdemux->n_streams; i++) {
10692 switch (qtdemux->streams[i]->subtype) {
10695 GST_DEBUG_OBJECT (qtdemux, "checking bitrate for %" GST_PTR_FORMAT,
10696 qtdemux->streams[i]->caps);
10697 /* retrieve bitrate, prefer avg then max */
10699 if (qtdemux->streams[i]->pending_tags) {
10700 gst_tag_list_get_uint (qtdemux->streams[i]->pending_tags,
10701 GST_TAG_MAXIMUM_BITRATE, &bitrate);
10702 GST_DEBUG_OBJECT (qtdemux, "max-bitrate: %u", bitrate);
10703 gst_tag_list_get_uint (qtdemux->streams[i]->pending_tags,
10704 GST_TAG_NOMINAL_BITRATE, &bitrate);
10705 GST_DEBUG_OBJECT (qtdemux, "nominal-bitrate: %u", bitrate);
10706 gst_tag_list_get_uint (qtdemux->streams[i]->pending_tags,
10707 GST_TAG_BITRATE, &bitrate);
10708 GST_DEBUG_OBJECT (qtdemux, "bitrate: %u", bitrate);
10711 sum_bitrate += bitrate;
10714 GST_DEBUG_OBJECT (qtdemux,
10715 ">1 stream with unknown bitrate - bailing");
10718 stream = qtdemux->streams[i];
10722 /* For other subtypes, we assume no significant impact on bitrate */
10728 GST_DEBUG_OBJECT (qtdemux, "All stream bitrates are known");
10732 sys_bitrate = gst_util_uint64_scale (size, GST_SECOND * 8, duration);
10734 if (sys_bitrate < sum_bitrate) {
10735 /* This can happen, since sum_bitrate might be derived from maximum
10736 * bitrates and not average bitrates */
10737 GST_DEBUG_OBJECT (qtdemux,
10738 "System bitrate less than sum bitrate - bailing");
10742 bitrate = sys_bitrate - sum_bitrate;
10743 GST_DEBUG_OBJECT (qtdemux, "System bitrate = %" G_GINT64_FORMAT
10744 ", Stream bitrate = %u", sys_bitrate, bitrate);
10746 if (!stream->pending_tags)
10747 stream->pending_tags = gst_tag_list_new_empty ();
10749 gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
10750 GST_TAG_BITRATE, bitrate, NULL);
10753 static GstFlowReturn
10754 qtdemux_prepare_streams (GstQTDemux * qtdemux)
10757 GstFlowReturn ret = GST_FLOW_OK;
10759 GST_DEBUG_OBJECT (qtdemux, "prepare streams");
10761 for (i = 0; ret == GST_FLOW_OK && i < qtdemux->n_streams; i++) {
10762 QtDemuxStream *stream = qtdemux->streams[i];
10763 guint32 sample_num = 0;
10765 GST_DEBUG_OBJECT (qtdemux, "stream %d, id %d, fourcc %" GST_FOURCC_FORMAT,
10766 i, stream->track_id, GST_FOURCC_ARGS (stream->fourcc));
10768 if (qtdemux->fragmented) {
10769 /* need all moov samples first */
10770 GST_OBJECT_LOCK (qtdemux);
10771 while (stream->n_samples == 0)
10772 if ((ret = qtdemux_add_fragmented_samples (qtdemux)) != GST_FLOW_OK)
10774 GST_OBJECT_UNLOCK (qtdemux);
10776 /* discard any stray moof */
10777 qtdemux->moof_offset = 0;
10780 /* prepare braking */
10781 if (ret != GST_FLOW_ERROR)
10784 /* in pull mode, we should have parsed some sample info by now;
10785 * and quite some code will not handle no samples.
10786 * in push mode, we'll just have to deal with it */
10787 if (G_UNLIKELY (qtdemux->pullbased && !stream->n_samples)) {
10788 GST_DEBUG_OBJECT (qtdemux, "no samples for stream; discarding");
10789 gst_qtdemux_remove_stream (qtdemux, i);
10794 /* parse the initial sample for use in setting the frame rate cap */
10795 while (sample_num == 0 && sample_num < stream->n_samples) {
10796 if (!qtdemux_parse_samples (qtdemux, stream, sample_num))
10800 if (stream->n_samples > 0 && stream->stbl_index >= 0) {
10801 stream->first_duration = stream->samples[0].duration;
10802 GST_LOG_OBJECT (qtdemux, "stream %d first duration %u",
10803 stream->track_id, stream->first_duration);
10810 static GstFlowReturn
10811 qtdemux_expose_streams (GstQTDemux * qtdemux)
10814 GstFlowReturn ret = GST_FLOW_OK;
10815 GSList *oldpads = NULL;
10818 GST_DEBUG_OBJECT (qtdemux, "exposing streams");
10820 for (i = 0; ret == GST_FLOW_OK && i < qtdemux->n_streams; i++) {
10821 QtDemuxStream *stream = qtdemux->streams[i];
10822 GstPad *oldpad = stream->pad;
10825 GST_DEBUG_OBJECT (qtdemux, "stream %d, id %d, fourcc %" GST_FOURCC_FORMAT,
10826 i, stream->track_id, GST_FOURCC_ARGS (stream->fourcc));
10828 if ((stream->subtype == FOURCC_text || stream->subtype == FOURCC_sbtl) &&
10829 stream->track_id == qtdemux->chapters_track_id) {
10830 /* TODO - parse chapters track and expose it as GstToc; For now just ignore it
10831 so that it doesn't look like a subtitle track */
10832 gst_qtdemux_remove_stream (qtdemux, i);
10837 /* now we have all info and can expose */
10838 list = stream->pending_tags;
10839 stream->pending_tags = NULL;
10841 oldpads = g_slist_prepend (oldpads, oldpad);
10842 if (!gst_qtdemux_add_stream (qtdemux, stream, list))
10843 return GST_FLOW_ERROR;
10846 gst_qtdemux_guess_bitrate (qtdemux);
10848 gst_element_no_more_pads (GST_ELEMENT_CAST (qtdemux));
10850 for (iter = oldpads; iter; iter = g_slist_next (iter)) {
10851 GstPad *oldpad = iter->data;
10853 gst_pad_push_event (oldpad, gst_event_new_eos ());
10854 gst_pad_set_active (oldpad, FALSE);
10855 gst_element_remove_pad (GST_ELEMENT (qtdemux), oldpad);
10856 gst_flow_combiner_remove_pad (qtdemux->flowcombiner, oldpad);
10857 gst_object_unref (oldpad);
10860 /* check if we should post a redirect in case there is a single trak
10861 * and it is a redirecting trak */
10862 if (qtdemux->n_streams == 1 && qtdemux->streams[0]->redirect_uri != NULL) {
10865 GST_INFO_OBJECT (qtdemux, "Issuing a redirect due to a single track with "
10866 "an external content");
10867 m = gst_message_new_element (GST_OBJECT_CAST (qtdemux),
10868 gst_structure_new ("redirect",
10869 "new-location", G_TYPE_STRING, qtdemux->streams[0]->redirect_uri,
10871 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), m);
10872 qtdemux->posted_redirect = TRUE;
10875 for (i = 0; i < qtdemux->n_streams; i++) {
10876 QtDemuxStream *stream = qtdemux->streams[i];
10878 qtdemux_do_allocation (qtdemux, stream);
10881 qtdemux->exposed = TRUE;
10885 /* check if major or compatible brand is 3GP */
10886 static inline gboolean
10887 qtdemux_is_brand_3gp (GstQTDemux * qtdemux, gboolean major)
10890 return ((qtdemux->major_brand & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
10892 } else if (qtdemux->comp_brands != NULL) {
10896 gboolean res = FALSE;
10898 gst_buffer_map (qtdemux->comp_brands, &map, GST_MAP_READ);
10901 while (size >= 4) {
10902 res = res || ((QT_FOURCC (data) & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
10907 gst_buffer_unmap (qtdemux->comp_brands, &map);
10914 /* check if tag is a spec'ed 3GP tag keyword storing a string */
10915 static inline gboolean
10916 qtdemux_is_string_tag_3gp (GstQTDemux * qtdemux, guint32 fourcc)
10918 return fourcc == FOURCC_cprt || fourcc == FOURCC_gnre || fourcc == FOURCC_titl
10919 || fourcc == FOURCC_dscp || fourcc == FOURCC_perf || fourcc == FOURCC_auth
10920 || fourcc == FOURCC_albm;
10924 qtdemux_tag_add_location (GstQTDemux * qtdemux, GstTagList * taglist,
10925 const char *tag, const char *dummy, GNode * node)
10927 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
10931 gdouble longitude, latitude, altitude;
10934 len = QT_UINT32 (node->data);
10941 /* TODO: language code skipped */
10943 name = gst_tag_freeform_string_to_utf8 (data + offset, -1, env_vars);
10946 /* do not alarm in trivial case, but bail out otherwise */
10947 if (*(data + offset) != 0) {
10948 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8, "
10952 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
10953 GST_TAG_GEO_LOCATION_NAME, name, NULL);
10954 offset += strlen (name);
10958 if (len < offset + 2 + 4 + 4 + 4)
10961 /* +1 +1 = skip null-terminator and location role byte */
10963 /* table in spec says unsigned, semantics say negative has meaning ... */
10964 longitude = QT_SFP32 (data + offset);
10967 latitude = QT_SFP32 (data + offset);
10970 altitude = QT_SFP32 (data + offset);
10972 /* one invalid means all are invalid */
10973 if (longitude >= -180.0 && longitude <= 180.0 &&
10974 latitude >= -90.0 && latitude <= 90.0) {
10975 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
10976 GST_TAG_GEO_LOCATION_LATITUDE, latitude,
10977 GST_TAG_GEO_LOCATION_LONGITUDE, longitude,
10978 GST_TAG_GEO_LOCATION_ELEVATION, altitude, NULL);
10981 /* TODO: no GST_TAG_, so astronomical body and additional notes skipped */
10988 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP location");
10995 qtdemux_tag_add_year (GstQTDemux * qtdemux, GstTagList * taglist,
10996 const char *tag, const char *dummy, GNode * node)
11002 len = QT_UINT32 (node->data);
11006 y = QT_UINT16 ((guint8 *) node->data + 12);
11008 GST_DEBUG_OBJECT (qtdemux, "year: %u is not a valid year", y);
11011 GST_DEBUG_OBJECT (qtdemux, "year: %u", y);
11013 date = g_date_new_dmy (1, 1, y);
11014 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, date, NULL);
11015 g_date_free (date);
11019 qtdemux_tag_add_classification (GstQTDemux * qtdemux, GstTagList * taglist,
11020 const char *tag, const char *dummy, GNode * node)
11023 char *tag_str = NULL;
11028 len = QT_UINT32 (node->data);
11033 entity = (guint8 *) node->data + offset;
11034 if (entity[0] == 0 || entity[1] == 0 || entity[2] == 0 || entity[3] == 0) {
11035 GST_DEBUG_OBJECT (qtdemux,
11036 "classification info: %c%c%c%c invalid classification entity",
11037 entity[0], entity[1], entity[2], entity[3]);
11042 table = QT_UINT16 ((guint8 *) node->data + offset);
11044 /* Language code skipped */
11048 /* Tag format: "XXXX://Y[YYYY]/classification info string"
11049 * XXXX: classification entity, fixed length 4 chars.
11050 * Y[YYYY]: classification table, max 5 chars.
11052 tag_str = g_strdup_printf ("----://%u/%s",
11053 table, (char *) node->data + offset);
11055 /* memcpy To be sure we're preserving byte order */
11056 memcpy (tag_str, entity, 4);
11057 GST_DEBUG_OBJECT (qtdemux, "classification info: %s", tag_str);
11059 gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND, tag, tag_str, NULL);
11068 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP classification");
11074 qtdemux_tag_add_str_full (GstQTDemux * qtdemux, GstTagList * taglist,
11075 const char *tag, const char *dummy, GNode * node)
11077 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
11083 gboolean ret = TRUE;
11084 const gchar *charset = NULL;
11086 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
11088 len = QT_UINT32 (data->data);
11089 type = QT_UINT32 ((guint8 *) data->data + 8);
11090 if (type == 0x00000001 && len > 16) {
11091 s = gst_tag_freeform_string_to_utf8 ((char *) data->data + 16, len - 16,
11094 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
11095 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, s, NULL);
11098 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
11102 len = QT_UINT32 (node->data);
11103 type = QT_UINT32 ((guint8 *) node->data + 4);
11104 if ((type >> 24) == 0xa9) {
11108 /* Type starts with the (C) symbol, so the next data is a list
11109 * of (string size(16), language code(16), string) */
11111 str_len = QT_UINT16 ((guint8 *) node->data + 8);
11112 lang_code = QT_UINT16 ((guint8 *) node->data + 10);
11114 /* the string + fourcc + size + 2 16bit fields,
11115 * means that there are more tags in this atom */
11116 if (len > str_len + 8 + 4) {
11117 /* TODO how to represent the same tag in different languages? */
11118 GST_WARNING_OBJECT (qtdemux, "Ignoring metadata entry with multiple "
11119 "text alternatives, reading only first one");
11123 len = str_len + 8 + 4; /* remove trailing strings that we don't use */
11124 GST_DEBUG_OBJECT (qtdemux, "found international text tag");
11126 if (lang_code < 0x800) { /* MAC encoded string */
11129 } else if (len > 14 && qtdemux_is_string_tag_3gp (qtdemux,
11130 QT_FOURCC ((guint8 *) node->data + 4))) {
11131 guint32 type = QT_UINT32 ((guint8 *) node->data + 8);
11133 /* we go for 3GP style encoding if major brands claims so,
11134 * or if no hope for data be ok UTF-8, and compatible 3GP brand present */
11135 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
11136 (qtdemux_is_brand_3gp (qtdemux, FALSE) &&
11137 ((type & 0x00FFFFFF) == 0x0) && (type >> 24 <= 0xF))) {
11139 /* 16-bit Language code is ignored here as well */
11140 GST_DEBUG_OBJECT (qtdemux, "found 3gpp text tag");
11147 GST_DEBUG_OBJECT (qtdemux, "found normal text tag");
11148 ret = FALSE; /* may have to fallback */
11151 GError *err = NULL;
11153 s = g_convert ((gchar *) node->data + offset, len - offset, "utf8",
11154 charset, NULL, NULL, &err);
11156 GST_DEBUG_OBJECT (qtdemux, "Failed to convert string from charset %s:"
11157 " %s(%d): %s", charset, g_quark_to_string (err->domain), err->code,
11159 g_error_free (err);
11162 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
11163 len - offset, env_vars);
11166 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
11167 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, s, NULL);
11171 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
11178 qtdemux_tag_add_str (GstQTDemux * qtdemux, GstTagList * taglist,
11179 const char *tag, const char *dummy, GNode * node)
11181 qtdemux_tag_add_str_full (qtdemux, taglist, tag, dummy, node);
11185 qtdemux_tag_add_keywords (GstQTDemux * qtdemux, GstTagList * taglist,
11186 const char *tag, const char *dummy, GNode * node)
11188 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
11190 char *s, *t, *k = NULL;
11195 /* first try normal string tag if major brand not 3GP */
11196 if (!qtdemux_is_brand_3gp (qtdemux, TRUE)) {
11197 if (!qtdemux_tag_add_str_full (qtdemux, taglist, tag, dummy, node)) {
11198 /* hm, that did not work, maybe 3gpp storage in non-3gpp major brand;
11199 * let's try it 3gpp way after minor safety check */
11201 if (QT_UINT32 (data) < 15 || !qtdemux_is_brand_3gp (qtdemux, FALSE))
11207 GST_DEBUG_OBJECT (qtdemux, "found 3gpp keyword tag");
11211 len = QT_UINT32 (data);
11215 count = QT_UINT8 (data + 14);
11217 for (; count; count--) {
11220 if (offset + 1 > len)
11222 slen = QT_UINT8 (data + offset);
11224 if (offset + slen > len)
11226 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
11229 GST_DEBUG_OBJECT (qtdemux, "adding keyword %s", GST_STR_NULL (s));
11231 t = g_strjoin (",", k, s, NULL);
11239 GST_DEBUG_OBJECT (qtdemux, "failed to convert keyword to UTF-8");
11246 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (k));
11247 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, k, NULL);
11256 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP keywords");
11262 qtdemux_tag_add_num (GstQTDemux * qtdemux, GstTagList * taglist,
11263 const char *tag1, const char *tag2, GNode * node)
11270 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
11272 len = QT_UINT32 (data->data);
11273 type = QT_UINT32 ((guint8 *) data->data + 8);
11274 if (type == 0x00000000 && len >= 22) {
11275 n1 = QT_UINT16 ((guint8 *) data->data + 18);
11276 n2 = QT_UINT16 ((guint8 *) data->data + 20);
11278 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag1, n1);
11279 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, n1, NULL);
11282 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag2, n2);
11283 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag2, n2, NULL);
11290 qtdemux_tag_add_tmpo (GstQTDemux * qtdemux, GstTagList * taglist,
11291 const char *tag1, const char *dummy, GNode * node)
11298 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
11300 len = QT_UINT32 (data->data);
11301 type = QT_UINT32 ((guint8 *) data->data + 8);
11302 GST_DEBUG_OBJECT (qtdemux, "have tempo tag, type=%d,len=%d", type, len);
11303 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
11304 if ((type == 0x00000015 || type == 0x0000000f) && len >= 18) {
11305 n1 = QT_UINT16 ((guint8 *) data->data + 16);
11307 /* do not add bpm=0 */
11308 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", n1);
11309 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, (gdouble) n1,
11317 qtdemux_tag_add_uint32 (GstQTDemux * qtdemux, GstTagList * taglist,
11318 const char *tag1, const char *dummy, GNode * node)
11325 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
11327 len = QT_UINT32 (data->data);
11328 type = QT_UINT32 ((guint8 *) data->data + 8);
11329 GST_DEBUG_OBJECT (qtdemux, "have %s tag, type=%d,len=%d", tag1, type, len);
11330 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
11331 if ((type == 0x00000015 || type == 0x0000000f) && len >= 20) {
11332 num = QT_UINT32 ((guint8 *) data->data + 16);
11334 /* do not add num=0 */
11335 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", num);
11336 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, num, NULL);
11343 qtdemux_tag_add_covr (GstQTDemux * qtdemux, GstTagList * taglist,
11344 const char *tag1, const char *dummy, GNode * node)
11351 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
11353 len = QT_UINT32 (data->data);
11354 type = QT_UINT32 ((guint8 *) data->data + 8);
11355 GST_DEBUG_OBJECT (qtdemux, "have covr tag, type=%d,len=%d", type, len);
11356 if ((type == 0x0000000d || type == 0x0000000e) && len > 16) {
11358 gst_tag_image_data_to_image_sample ((guint8 *) data->data + 16,
11359 len - 16, GST_TAG_IMAGE_TYPE_NONE))) {
11360 GST_DEBUG_OBJECT (qtdemux, "adding tag size %d", len - 16);
11361 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, sample, NULL);
11362 gst_sample_unref (sample);
11369 qtdemux_tag_add_date (GstQTDemux * qtdemux, GstTagList * taglist,
11370 const char *tag, const char *dummy, GNode * node)
11377 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
11379 len = QT_UINT32 (data->data);
11380 type = QT_UINT32 ((guint8 *) data->data + 8);
11381 if (type == 0x00000001 && len > 16) {
11382 guint y, m = 1, d = 1;
11385 s = g_strndup ((char *) data->data + 16, len - 16);
11386 GST_DEBUG_OBJECT (qtdemux, "adding date '%s'", s);
11387 ret = sscanf (s, "%u-%u-%u", &y, &m, &d);
11388 if (ret >= 1 && y > 1500 && y < 3000) {
11391 date = g_date_new_dmy (d, m, y);
11392 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, date, NULL);
11393 g_date_free (date);
11395 GST_DEBUG_OBJECT (qtdemux, "could not parse date string '%s'", s);
11403 qtdemux_tag_add_gnre (GstQTDemux * qtdemux, GstTagList * taglist,
11404 const char *tag, const char *dummy, GNode * node)
11408 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
11410 /* re-route to normal string tag if major brand says so
11411 * or no data atom and compatible brand suggests so */
11412 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
11413 (qtdemux_is_brand_3gp (qtdemux, FALSE) && !data)) {
11414 qtdemux_tag_add_str (qtdemux, taglist, tag, dummy, node);
11419 guint len, type, n;
11421 len = QT_UINT32 (data->data);
11422 type = QT_UINT32 ((guint8 *) data->data + 8);
11423 if (type == 0x00000000 && len >= 18) {
11424 n = QT_UINT16 ((guint8 *) data->data + 16);
11426 const gchar *genre;
11428 genre = gst_tag_id3_genre_get (n - 1);
11429 if (genre != NULL) {
11430 GST_DEBUG_OBJECT (qtdemux, "adding %d [%s]", n, genre);
11431 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, genre, NULL);
11439 qtdemux_add_double_tag_from_str (GstQTDemux * demux, GstTagList * taglist,
11440 const gchar * tag, guint8 * data, guint32 datasize)
11445 /* make a copy to have \0 at the end */
11446 datacopy = g_strndup ((gchar *) data, datasize);
11448 /* convert the str to double */
11449 if (sscanf (datacopy, "%lf", &value) == 1) {
11450 GST_DEBUG_OBJECT (demux, "adding tag: %s [%s]", tag, datacopy);
11451 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, value, NULL);
11453 GST_WARNING_OBJECT (demux, "Failed to parse double from string: %s",
11461 qtdemux_tag_add_revdns (GstQTDemux * demux, GstTagList * taglist,
11462 const char *tag, const char *tag_bis, GNode * node)
11471 const gchar *meanstr;
11472 const gchar *namestr;
11474 /* checking the whole ---- atom size for consistency */
11475 if (QT_UINT32 (node->data) <= 4 + 12 + 12 + 16) {
11476 GST_WARNING_OBJECT (demux, "Tag ---- atom is too small, ignoring");
11480 mean = qtdemux_tree_get_child_by_type (node, FOURCC_mean);
11482 GST_WARNING_OBJECT (demux, "No 'mean' atom found");
11486 meansize = QT_UINT32 (mean->data);
11487 if (meansize <= 12) {
11488 GST_WARNING_OBJECT (demux, "Small mean atom, ignoring the whole tag");
11491 meanstr = ((gchar *) mean->data) + 12;
11494 name = qtdemux_tree_get_child_by_type (node, FOURCC_name);
11496 GST_WARNING_OBJECT (demux, "'name' atom not found, ignoring tag");
11500 namesize = QT_UINT32 (name->data);
11501 if (namesize <= 12) {
11502 GST_WARNING_OBJECT (demux, "'name' atom is too small, ignoring tag");
11505 namestr = ((gchar *) name->data) + 12;
11513 * uint24 - data type
11517 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
11519 GST_WARNING_OBJECT (demux, "No data atom in this tag");
11522 datasize = QT_UINT32 (data->data);
11523 if (datasize <= 16) {
11524 GST_WARNING_OBJECT (demux, "Data atom too small");
11527 datatype = QT_UINT32 (((gchar *) data->data) + 8) & 0xFFFFFF;
11529 if ((strncmp (meanstr, "com.apple.iTunes", meansize) == 0) ||
11530 (strncmp (meanstr, "org.hydrogenaudio.replaygain", meansize) == 0)) {
11531 static const struct
11533 const gchar name[28];
11534 const gchar tag[28];
11537 "replaygain_track_gain", GST_TAG_TRACK_GAIN}, {
11538 "replaygain_track_peak", GST_TAG_TRACK_PEAK}, {
11539 "replaygain_album_gain", GST_TAG_ALBUM_GAIN}, {
11540 "replaygain_album_peak", GST_TAG_ALBUM_PEAK}, {
11541 "MusicBrainz Track Id", GST_TAG_MUSICBRAINZ_TRACKID}, {
11542 "MusicBrainz Artist Id", GST_TAG_MUSICBRAINZ_ARTISTID}, {
11543 "MusicBrainz Album Id", GST_TAG_MUSICBRAINZ_ALBUMID}, {
11544 "MusicBrainz Album Artist Id", GST_TAG_MUSICBRAINZ_ALBUMARTISTID}
11548 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
11549 if (!g_ascii_strncasecmp (tags[i].name, namestr, namesize)) {
11550 switch (gst_tag_get_type (tags[i].tag)) {
11551 case G_TYPE_DOUBLE:
11552 qtdemux_add_double_tag_from_str (demux, taglist, tags[i].tag,
11553 ((guint8 *) data->data) + 16, datasize - 16);
11555 case G_TYPE_STRING:
11556 qtdemux_tag_add_str (demux, taglist, tags[i].tag, NULL, node);
11565 if (i == G_N_ELEMENTS (tags))
11575 #ifndef GST_DISABLE_GST_DEBUG
11577 gchar *namestr_dbg;
11578 gchar *meanstr_dbg;
11580 meanstr_dbg = g_strndup (meanstr, meansize);
11581 namestr_dbg = g_strndup (namestr, namesize);
11583 GST_WARNING_OBJECT (demux, "This tag %s:%s type:%u is not mapped, "
11584 "file a bug at bugzilla.gnome.org", meanstr_dbg, namestr_dbg, datatype);
11586 g_free (namestr_dbg);
11587 g_free (meanstr_dbg);
11594 qtdemux_tag_add_id32 (GstQTDemux * demux, GstTagList * taglist, const char *tag,
11595 const char *tag_bis, GNode * node)
11600 GstTagList *id32_taglist = NULL;
11602 GST_LOG_OBJECT (demux, "parsing ID32");
11605 len = GST_READ_UINT32_BE (data);
11607 /* need at least full box and language tag */
11611 buf = gst_buffer_new_allocate (NULL, len - 14, NULL);
11612 gst_buffer_fill (buf, 0, data + 14, len - 14);
11614 id32_taglist = gst_tag_list_from_id3v2_tag (buf);
11615 if (id32_taglist) {
11616 GST_LOG_OBJECT (demux, "parsing ok");
11617 gst_tag_list_insert (taglist, id32_taglist, GST_TAG_MERGE_KEEP);
11618 gst_tag_list_unref (id32_taglist);
11620 GST_LOG_OBJECT (demux, "parsing failed");
11623 gst_buffer_unref (buf);
11626 typedef void (*GstQTDemuxAddTagFunc) (GstQTDemux * demux, GstTagList * taglist,
11627 const char *tag, const char *tag_bis, GNode * node);
11630 FOURCC_pcst -> if media is a podcast -> bool
11631 FOURCC_cpil -> if media is part of a compilation -> bool
11632 FOURCC_pgap -> if media is part of a gapless context -> bool
11633 FOURCC_tven -> the tv episode id e.g. S01E23 -> str
11636 static const struct
11639 const gchar *gst_tag;
11640 const gchar *gst_tag_bis;
11641 const GstQTDemuxAddTagFunc func;
11644 FOURCC__nam, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
11645 FOURCC_titl, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
11646 FOURCC__grp, GST_TAG_GROUPING, NULL, qtdemux_tag_add_str}, {
11647 FOURCC__wrt, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
11648 FOURCC__ART, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
11649 FOURCC_aART, GST_TAG_ALBUM_ARTIST, NULL, qtdemux_tag_add_str}, {
11650 FOURCC_perf, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
11651 FOURCC_auth, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
11652 FOURCC__alb, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
11653 FOURCC_albm, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
11654 FOURCC_cprt, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
11655 FOURCC__cpy, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
11656 FOURCC__cmt, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
11657 FOURCC__des, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
11658 FOURCC_desc, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
11659 FOURCC_dscp, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
11660 FOURCC__lyr, GST_TAG_LYRICS, NULL, qtdemux_tag_add_str}, {
11661 FOURCC__day, GST_TAG_DATE, NULL, qtdemux_tag_add_date}, {
11662 FOURCC_yrrc, GST_TAG_DATE, NULL, qtdemux_tag_add_year}, {
11663 FOURCC__too, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
11664 FOURCC__inf, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
11665 FOURCC_trkn, GST_TAG_TRACK_NUMBER, GST_TAG_TRACK_COUNT, qtdemux_tag_add_num}, {
11666 FOURCC_disk, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
11667 qtdemux_tag_add_num}, {
11668 FOURCC_disc, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
11669 qtdemux_tag_add_num}, {
11670 FOURCC__gen, GST_TAG_GENRE, NULL, qtdemux_tag_add_str}, {
11671 FOURCC_gnre, GST_TAG_GENRE, NULL, qtdemux_tag_add_gnre}, {
11672 FOURCC_tmpo, GST_TAG_BEATS_PER_MINUTE, NULL, qtdemux_tag_add_tmpo}, {
11673 FOURCC_covr, GST_TAG_PREVIEW_IMAGE, NULL, qtdemux_tag_add_covr}, {
11674 FOURCC_sonm, GST_TAG_TITLE_SORTNAME, NULL, qtdemux_tag_add_str}, {
11675 FOURCC_soal, GST_TAG_ALBUM_SORTNAME, NULL, qtdemux_tag_add_str}, {
11676 FOURCC_soar, GST_TAG_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
11677 FOURCC_soaa, GST_TAG_ALBUM_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
11678 FOURCC_soco, GST_TAG_COMPOSER_SORTNAME, NULL, qtdemux_tag_add_str}, {
11679 FOURCC_sosn, GST_TAG_SHOW_SORTNAME, NULL, qtdemux_tag_add_str}, {
11680 FOURCC_tvsh, GST_TAG_SHOW_NAME, NULL, qtdemux_tag_add_str}, {
11681 FOURCC_tvsn, GST_TAG_SHOW_SEASON_NUMBER, NULL, qtdemux_tag_add_uint32}, {
11682 FOURCC_tves, GST_TAG_SHOW_EPISODE_NUMBER, NULL, qtdemux_tag_add_uint32}, {
11683 FOURCC_kywd, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_keywords}, {
11684 FOURCC_keyw, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_str}, {
11685 FOURCC__enc, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
11686 FOURCC_loci, GST_TAG_GEO_LOCATION_NAME, NULL, qtdemux_tag_add_location}, {
11687 FOURCC_clsf, GST_QT_DEMUX_CLASSIFICATION_TAG, NULL,
11688 qtdemux_tag_add_classification}, {
11689 FOURCC__mak, GST_TAG_DEVICE_MANUFACTURER, NULL, qtdemux_tag_add_str}, {
11690 FOURCC__mod, GST_TAG_DEVICE_MODEL, NULL, qtdemux_tag_add_str}, {
11691 FOURCC__swr, GST_TAG_APPLICATION_NAME, NULL, qtdemux_tag_add_str}, {
11693 /* This is a special case, some tags are stored in this
11694 * 'reverse dns naming', according to:
11695 * http://atomicparsley.sourceforge.net/mpeg-4files.html and
11698 FOURCC_____, "", NULL, qtdemux_tag_add_revdns}, {
11699 /* see http://www.mp4ra.org/specs.html for ID32 in meta box */
11700 FOURCC_ID32, "", NULL, qtdemux_tag_add_id32}
11703 struct _GstQtDemuxTagList
11706 GstTagList *taglist;
11708 typedef struct _GstQtDemuxTagList GstQtDemuxTagList;
11711 qtdemux_tag_add_blob (GNode * node, GstQtDemuxTagList * qtdemuxtaglist)
11717 const gchar *style;
11722 GstQTDemux *demux = qtdemuxtaglist->demux;
11723 GstTagList *taglist = qtdemuxtaglist->taglist;
11726 len = QT_UINT32 (data);
11727 buf = gst_buffer_new_and_alloc (len);
11728 gst_buffer_fill (buf, 0, data, len);
11730 /* heuristic to determine style of tag */
11731 if (QT_FOURCC (data + 4) == FOURCC_____ ||
11732 (len > 8 + 12 && QT_FOURCC (data + 12) == FOURCC_data))
11734 else if (demux->major_brand == FOURCC_qt__)
11735 style = "quicktime";
11736 /* fall back to assuming iso/3gp tag style */
11740 /* santize the name for the caps. */
11741 for (i = 0; i < 4; i++) {
11742 guint8 d = data[4 + i];
11743 if (g_ascii_isalnum (d))
11744 ndata[i] = g_ascii_tolower (d);
11749 media_type = g_strdup_printf ("application/x-gst-qt-%c%c%c%c-tag",
11750 ndata[0], ndata[1], ndata[2], ndata[3]);
11751 GST_DEBUG_OBJECT (demux, "media type %s", media_type);
11753 s = gst_structure_new (media_type, "style", G_TYPE_STRING, style, NULL);
11754 sample = gst_sample_new (buf, NULL, NULL, s);
11755 gst_buffer_unref (buf);
11756 g_free (media_type);
11758 GST_DEBUG_OBJECT (demux, "adding private tag; size %d, info %" GST_PTR_FORMAT,
11761 gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND,
11762 GST_QT_DEMUX_PRIVATE_TAG, sample, NULL);
11764 gst_sample_unref (sample);
11768 qtdemux_parse_udta (GstQTDemux * qtdemux, GstTagList * taglist, GNode * udta)
11775 GstQtDemuxTagList demuxtaglist;
11777 demuxtaglist.demux = qtdemux;
11778 demuxtaglist.taglist = taglist;
11780 meta = qtdemux_tree_get_child_by_type (udta, FOURCC_meta);
11781 if (meta != NULL) {
11782 ilst = qtdemux_tree_get_child_by_type (meta, FOURCC_ilst);
11783 if (ilst == NULL) {
11784 GST_LOG_OBJECT (qtdemux, "no ilst");
11789 GST_LOG_OBJECT (qtdemux, "no meta so using udta itself");
11793 while (i < G_N_ELEMENTS (add_funcs)) {
11794 node = qtdemux_tree_get_child_by_type (ilst, add_funcs[i].fourcc);
11798 len = QT_UINT32 (node->data);
11800 GST_DEBUG_OBJECT (qtdemux, "too small tag atom %" GST_FOURCC_FORMAT,
11801 GST_FOURCC_ARGS (add_funcs[i].fourcc));
11803 add_funcs[i].func (qtdemux, taglist, add_funcs[i].gst_tag,
11804 add_funcs[i].gst_tag_bis, node);
11806 g_node_destroy (node);
11812 /* parsed nodes have been removed, pass along remainder as blob */
11813 g_node_children_foreach (ilst, G_TRAVERSE_ALL,
11814 (GNodeForeachFunc) qtdemux_tag_add_blob, &demuxtaglist);
11816 /* parse up XMP_ node if existing */
11817 xmp_ = qtdemux_tree_get_child_by_type (udta, FOURCC_XMP_);
11818 if (xmp_ != NULL) {
11820 GstTagList *xmptaglist;
11822 buf = _gst_buffer_new_wrapped (((guint8 *) xmp_->data) + 8,
11823 QT_UINT32 ((guint8 *) xmp_->data) - 8, NULL);
11824 xmptaglist = gst_tag_list_from_xmp_buffer (buf);
11825 gst_buffer_unref (buf);
11827 qtdemux_handle_xmp_taglist (qtdemux, taglist, xmptaglist);
11829 GST_DEBUG_OBJECT (qtdemux, "No XMP_ node found");
11835 GstStructure *structure; /* helper for sort function */
11837 guint min_req_bitrate;
11838 guint min_req_qt_version;
11842 qtdemux_redirects_sort_func (gconstpointer a, gconstpointer b)
11844 GstQtReference *ref_a = (GstQtReference *) a;
11845 GstQtReference *ref_b = (GstQtReference *) b;
11847 if (ref_b->min_req_qt_version != ref_a->min_req_qt_version)
11848 return ref_b->min_req_qt_version - ref_a->min_req_qt_version;
11850 /* known bitrates go before unknown; higher bitrates go first */
11851 return ref_b->min_req_bitrate - ref_a->min_req_bitrate;
11854 /* sort the redirects and post a message for the application.
11857 qtdemux_process_redirects (GstQTDemux * qtdemux, GList * references)
11859 GstQtReference *best;
11862 GValue list_val = { 0, };
11865 g_assert (references != NULL);
11867 references = g_list_sort (references, qtdemux_redirects_sort_func);
11869 best = (GstQtReference *) references->data;
11871 g_value_init (&list_val, GST_TYPE_LIST);
11873 for (l = references; l != NULL; l = l->next) {
11874 GstQtReference *ref = (GstQtReference *) l->data;
11875 GValue struct_val = { 0, };
11877 ref->structure = gst_structure_new ("redirect",
11878 "new-location", G_TYPE_STRING, ref->location, NULL);
11880 if (ref->min_req_bitrate > 0) {
11881 gst_structure_set (ref->structure, "minimum-bitrate", G_TYPE_INT,
11882 ref->min_req_bitrate, NULL);
11885 g_value_init (&struct_val, GST_TYPE_STRUCTURE);
11886 g_value_set_boxed (&struct_val, ref->structure);
11887 gst_value_list_append_value (&list_val, &struct_val);
11888 g_value_unset (&struct_val);
11889 /* don't free anything here yet, since we need best->structure below */
11892 g_assert (best != NULL);
11893 s = gst_structure_copy (best->structure);
11895 if (g_list_length (references) > 1) {
11896 gst_structure_set_value (s, "locations", &list_val);
11899 g_value_unset (&list_val);
11901 for (l = references; l != NULL; l = l->next) {
11902 GstQtReference *ref = (GstQtReference *) l->data;
11904 gst_structure_free (ref->structure);
11905 g_free (ref->location);
11908 g_list_free (references);
11910 GST_INFO_OBJECT (qtdemux, "posting redirect message: %" GST_PTR_FORMAT, s);
11911 msg = gst_message_new_element (GST_OBJECT_CAST (qtdemux), s);
11912 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
11913 qtdemux->posted_redirect = TRUE;
11916 /* look for redirect nodes, collect all redirect information and
11920 qtdemux_parse_redirects (GstQTDemux * qtdemux)
11922 GNode *rmra, *rmda, *rdrf;
11924 rmra = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_rmra);
11926 GList *redirects = NULL;
11928 rmda = qtdemux_tree_get_child_by_type (rmra, FOURCC_rmda);
11930 GstQtReference ref = { NULL, NULL, 0, 0 };
11931 GNode *rmdr, *rmvc;
11933 if ((rmdr = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmdr))) {
11934 ref.min_req_bitrate = QT_UINT32 ((guint8 *) rmdr->data + 12);
11935 GST_LOG_OBJECT (qtdemux, "data rate atom, required bitrate = %u",
11936 ref.min_req_bitrate);
11939 if ((rmvc = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmvc))) {
11940 guint32 package = QT_FOURCC ((guint8 *) rmvc->data + 12);
11941 guint version = QT_UINT32 ((guint8 *) rmvc->data + 16);
11943 #ifndef GST_DISABLE_GST_DEBUG
11944 guint bitmask = QT_UINT32 ((guint8 *) rmvc->data + 20);
11946 guint check_type = QT_UINT16 ((guint8 *) rmvc->data + 24);
11948 GST_LOG_OBJECT (qtdemux,
11949 "version check atom [%" GST_FOURCC_FORMAT "], version=0x%08x"
11950 ", mask=%08x, check_type=%u", GST_FOURCC_ARGS (package), version,
11951 bitmask, check_type);
11952 if (package == FOURCC_qtim && check_type == 0) {
11953 ref.min_req_qt_version = version;
11957 rdrf = qtdemux_tree_get_child_by_type (rmda, FOURCC_rdrf);
11963 ref_len = QT_UINT32 ((guint8 *) rdrf->data);
11964 if (ref_len > 20) {
11965 ref_type = QT_FOURCC ((guint8 *) rdrf->data + 12);
11966 ref_data = (guint8 *) rdrf->data + 20;
11967 if (ref_type == FOURCC_alis) {
11968 guint record_len, record_version, fn_len;
11970 if (ref_len > 70) {
11971 /* MacOSX alias record, google for alias-layout.txt */
11972 record_len = QT_UINT16 (ref_data + 4);
11973 record_version = QT_UINT16 (ref_data + 4 + 2);
11974 fn_len = QT_UINT8 (ref_data + 50);
11975 if (record_len > 50 && record_version == 2 && fn_len > 0) {
11976 ref.location = g_strndup ((gchar *) ref_data + 51, fn_len);
11979 GST_WARNING_OBJECT (qtdemux, "Invalid rdrf/alis size (%u < 70)",
11982 } else if (ref_type == FOURCC_url_) {
11983 ref.location = g_strndup ((gchar *) ref_data, ref_len - 8);
11985 GST_DEBUG_OBJECT (qtdemux,
11986 "unknown rdrf reference type %" GST_FOURCC_FORMAT,
11987 GST_FOURCC_ARGS (ref_type));
11989 if (ref.location != NULL) {
11990 GST_INFO_OBJECT (qtdemux, "New location: %s", ref.location);
11992 g_list_prepend (redirects, g_memdup (&ref, sizeof (ref)));
11994 GST_WARNING_OBJECT (qtdemux,
11995 "Failed to extract redirect location from rdrf atom");
11998 GST_WARNING_OBJECT (qtdemux, "Invalid rdrf size (%u < 20)", ref_len);
12002 /* look for others */
12003 rmda = qtdemux_tree_get_sibling_by_type (rmda, FOURCC_rmda);
12006 if (redirects != NULL) {
12007 qtdemux_process_redirects (qtdemux, redirects);
12013 static GstTagList *
12014 qtdemux_add_container_format (GstQTDemux * qtdemux, GstTagList * tags)
12018 if (tags == NULL) {
12019 tags = gst_tag_list_new_empty ();
12020 gst_tag_list_set_scope (tags, GST_TAG_SCOPE_GLOBAL);
12023 if (qtdemux->major_brand == FOURCC_mjp2)
12024 fmt = "Motion JPEG 2000";
12025 else if ((qtdemux->major_brand & 0xffff) == FOURCC_3g__)
12027 else if (qtdemux->major_brand == FOURCC_qt__)
12029 else if (qtdemux->fragmented)
12032 fmt = "ISO MP4/M4A";
12034 GST_LOG_OBJECT (qtdemux, "mapped %" GST_FOURCC_FORMAT " to '%s'",
12035 GST_FOURCC_ARGS (qtdemux->major_brand), fmt);
12037 gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_CONTAINER_FORMAT,
12043 /* we have read th complete moov node now.
12044 * This function parses all of the relevant info, creates the traks and
12045 * prepares all data structures for playback
12048 qtdemux_parse_tree (GstQTDemux * qtdemux)
12054 GstClockTime duration;
12056 guint64 creation_time;
12057 GstDateTime *datetime = NULL;
12060 /* make sure we have a usable taglist */
12061 if (!qtdemux->tag_list) {
12062 qtdemux->tag_list = gst_tag_list_new_empty ();
12063 gst_tag_list_set_scope (qtdemux->tag_list, GST_TAG_SCOPE_GLOBAL);
12065 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
12068 mvhd = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvhd);
12069 if (mvhd == NULL) {
12070 GST_LOG_OBJECT (qtdemux, "No mvhd node found, looking for redirects.");
12071 return qtdemux_parse_redirects (qtdemux);
12074 version = QT_UINT8 ((guint8 *) mvhd->data + 8);
12075 if (version == 1) {
12076 creation_time = QT_UINT64 ((guint8 *) mvhd->data + 12);
12077 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 28);
12078 qtdemux->duration = QT_UINT64 ((guint8 *) mvhd->data + 32);
12079 } else if (version == 0) {
12080 creation_time = QT_UINT32 ((guint8 *) mvhd->data + 12);
12081 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 20);
12082 qtdemux->duration = QT_UINT32 ((guint8 *) mvhd->data + 24);
12084 GST_WARNING_OBJECT (qtdemux, "Unhandled mvhd version %d", version);
12088 /* Moving qt creation time (secs since 1904) to unix time */
12089 if (creation_time != 0) {
12090 /* Try to use epoch first as it should be faster and more commonly found */
12091 if (creation_time >= QTDEMUX_SECONDS_FROM_1904_TO_1970) {
12094 creation_time -= QTDEMUX_SECONDS_FROM_1904_TO_1970;
12095 /* some data cleansing sanity */
12096 g_get_current_time (&now);
12097 if (now.tv_sec + 24 * 3600 < creation_time) {
12098 GST_DEBUG_OBJECT (qtdemux, "discarding bogus future creation time");
12100 datetime = gst_date_time_new_from_unix_epoch_utc (creation_time);
12103 GDateTime *base_dt = g_date_time_new_utc (1904, 1, 1, 0, 0, 0);
12104 GDateTime *dt, *dt_local;
12106 dt = g_date_time_add_seconds (base_dt, creation_time);
12107 dt_local = g_date_time_to_local (dt);
12108 datetime = gst_date_time_new_from_g_date_time (dt_local);
12110 g_date_time_unref (base_dt);
12111 g_date_time_unref (dt);
12115 /* Use KEEP as explicit tags should have a higher priority than mvhd tag */
12116 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_KEEP, GST_TAG_DATE_TIME,
12118 gst_date_time_unref (datetime);
12121 GST_INFO_OBJECT (qtdemux, "timescale: %u", qtdemux->timescale);
12122 GST_INFO_OBJECT (qtdemux, "duration: %" G_GUINT64_FORMAT, qtdemux->duration);
12124 /* check for fragmented file and get some (default) data */
12125 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
12128 GstByteReader mehd_data;
12130 /* let track parsing or anyone know weird stuff might happen ... */
12131 qtdemux->fragmented = TRUE;
12133 /* compensate for total duration */
12134 mehd = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_mehd, &mehd_data);
12136 qtdemux_parse_mehd (qtdemux, &mehd_data);
12139 /* set duration in the segment info */
12140 gst_qtdemux_get_duration (qtdemux, &duration);
12142 qtdemux->segment.duration = duration;
12143 /* also do not exceed duration; stop is set that way post seek anyway,
12144 * and segment activation falls back to duration,
12145 * whereas loop only checks stop, so let's align this here as well */
12146 qtdemux->segment.stop = duration;
12149 /* parse all traks */
12150 trak = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_trak);
12152 qtdemux_parse_trak (qtdemux, trak);
12153 /* iterate all siblings */
12154 trak = qtdemux_tree_get_sibling_by_type (trak, FOURCC_trak);
12157 if (!qtdemux->tag_list) {
12158 GST_DEBUG_OBJECT (qtdemux, "new tag list");
12159 qtdemux->tag_list = gst_tag_list_new_empty ();
12160 gst_tag_list_set_scope (qtdemux->tag_list, GST_TAG_SCOPE_GLOBAL);
12162 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
12166 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_udta);
12168 qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
12170 GST_LOG_OBJECT (qtdemux, "No udta node found.");
12173 /* maybe also some tags in meta box */
12174 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_meta);
12176 GST_DEBUG_OBJECT (qtdemux, "Parsing meta box for tags.");
12177 qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
12179 GST_LOG_OBJECT (qtdemux, "No meta node found.");
12182 /* parse any protection system info */
12183 pssh = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_pssh);
12185 GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
12186 qtdemux_parse_pssh (qtdemux, pssh);
12187 pssh = qtdemux_tree_get_sibling_by_type (pssh, FOURCC_pssh);
12190 qtdemux->tag_list = qtdemux_add_container_format (qtdemux, qtdemux->tag_list);
12195 /* taken from ffmpeg */
12197 read_descr_size (guint8 * ptr, guint8 * end, guint8 ** end_out)
12209 len = (len << 7) | (c & 0x7f);
12217 /* this can change the codec originally present in @list */
12219 gst_qtdemux_handle_esds (GstQTDemux * qtdemux, QtDemuxStream * stream,
12220 GNode * esds, GstTagList * list)
12222 int len = QT_UINT32 (esds->data);
12223 guint8 *ptr = esds->data;
12224 guint8 *end = ptr + len;
12226 guint8 *data_ptr = NULL;
12228 guint8 object_type_id = 0;
12229 const char *codec_name = NULL;
12230 GstCaps *caps = NULL;
12232 GST_MEMDUMP_OBJECT (qtdemux, "esds", ptr, len);
12234 GST_DEBUG_OBJECT (qtdemux, "version/flags = %08x", QT_UINT32 (ptr));
12236 while (ptr + 1 < end) {
12237 tag = QT_UINT8 (ptr);
12238 GST_DEBUG_OBJECT (qtdemux, "tag = %02x", tag);
12240 len = read_descr_size (ptr, end, &ptr);
12241 GST_DEBUG_OBJECT (qtdemux, "len = %d", len);
12243 /* Check the stated amount of data is available for reading */
12244 if (len < 0 || ptr + len > end)
12248 case ES_DESCRIPTOR_TAG:
12249 GST_DEBUG_OBJECT (qtdemux, "ID %04x", QT_UINT16 (ptr));
12250 GST_DEBUG_OBJECT (qtdemux, "priority %04x", QT_UINT8 (ptr + 2));
12253 case DECODER_CONFIG_DESC_TAG:{
12254 guint max_bitrate, avg_bitrate;
12256 object_type_id = QT_UINT8 (ptr);
12257 max_bitrate = QT_UINT32 (ptr + 5);
12258 avg_bitrate = QT_UINT32 (ptr + 9);
12259 GST_DEBUG_OBJECT (qtdemux, "object_type_id %02x", object_type_id);
12260 GST_DEBUG_OBJECT (qtdemux, "stream_type %02x", QT_UINT8 (ptr + 1));
12261 GST_DEBUG_OBJECT (qtdemux, "buffer_size_db %02x", QT_UINT24 (ptr + 2));
12262 GST_DEBUG_OBJECT (qtdemux, "max bitrate %u", max_bitrate);
12263 GST_DEBUG_OBJECT (qtdemux, "avg bitrate %u", avg_bitrate);
12264 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
12265 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
12266 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
12268 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
12269 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
12270 avg_bitrate, NULL);
12275 case DECODER_SPECIFIC_INFO_TAG:
12276 GST_MEMDUMP_OBJECT (qtdemux, "data", ptr, len);
12277 if (object_type_id == 0xe0 && len == 0x40) {
12283 GST_DEBUG_OBJECT (qtdemux,
12284 "Have VOBSUB palette. Creating palette event");
12285 /* move to decConfigDescr data and read palette */
12287 for (i = 0; i < 16; i++) {
12288 clut[i] = QT_UINT32 (data);
12292 s = gst_structure_new ("application/x-gst-dvd", "event",
12293 G_TYPE_STRING, "dvd-spu-clut-change",
12294 "clut00", G_TYPE_INT, clut[0], "clut01", G_TYPE_INT, clut[1],
12295 "clut02", G_TYPE_INT, clut[2], "clut03", G_TYPE_INT, clut[3],
12296 "clut04", G_TYPE_INT, clut[4], "clut05", G_TYPE_INT, clut[5],
12297 "clut06", G_TYPE_INT, clut[6], "clut07", G_TYPE_INT, clut[7],
12298 "clut08", G_TYPE_INT, clut[8], "clut09", G_TYPE_INT, clut[9],
12299 "clut10", G_TYPE_INT, clut[10], "clut11", G_TYPE_INT, clut[11],
12300 "clut12", G_TYPE_INT, clut[12], "clut13", G_TYPE_INT, clut[13],
12301 "clut14", G_TYPE_INT, clut[14], "clut15", G_TYPE_INT, clut[15],
12304 /* store event and trigger custom processing */
12305 stream->pending_event =
12306 gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s);
12308 /* Generic codec_data handler puts it on the caps */
12315 case SL_CONFIG_DESC_TAG:
12316 GST_DEBUG_OBJECT (qtdemux, "data %02x", QT_UINT8 (ptr));
12320 GST_DEBUG_OBJECT (qtdemux, "Unknown/unhandled descriptor tag %02x",
12322 GST_MEMDUMP_OBJECT (qtdemux, "descriptor data", ptr, len);
12328 /* object_type_id in the esds atom in mp4a and mp4v tells us which codec is
12329 * in use, and should also be used to override some other parameters for some
12331 switch (object_type_id) {
12332 case 0x20: /* MPEG-4 */
12333 /* 4 bytes for the visual_object_sequence_start_code and 1 byte for the
12334 * profile_and_level_indication */
12335 if (data_ptr != NULL && data_len >= 5 &&
12336 GST_READ_UINT32_BE (data_ptr) == 0x000001b0) {
12337 gst_codec_utils_mpeg4video_caps_set_level_and_profile (stream->caps,
12338 data_ptr + 4, data_len - 4);
12340 break; /* Nothing special needed here */
12341 case 0x21: /* H.264 */
12342 codec_name = "H.264 / AVC";
12343 caps = gst_caps_new_simple ("video/x-h264",
12344 "stream-format", G_TYPE_STRING, "avc",
12345 "alignment", G_TYPE_STRING, "au", NULL);
12347 case 0x40: /* AAC (any) */
12348 case 0x66: /* AAC Main */
12349 case 0x67: /* AAC LC */
12350 case 0x68: /* AAC SSR */
12351 /* Override channels and rate based on the codec_data, as it's often
12353 /* Only do so for basic setup without HE-AAC extension */
12354 if (data_ptr && data_len == 2) {
12355 guint channels, rate;
12357 channels = gst_codec_utils_aac_get_channels (data_ptr, data_len);
12359 stream->n_channels = channels;
12361 rate = gst_codec_utils_aac_get_sample_rate (data_ptr, data_len);
12363 stream->rate = rate;
12366 /* Set level and profile if possible */
12367 if (data_ptr != NULL && data_len >= 2) {
12368 gst_codec_utils_aac_caps_set_level_and_profile (stream->caps,
12369 data_ptr, data_len);
12372 case 0x60: /* MPEG-2, various profiles */
12378 codec_name = "MPEG-2 video";
12379 caps = gst_caps_new_simple ("video/mpeg",
12380 "mpegversion", G_TYPE_INT, 2,
12381 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
12383 case 0x69: /* MPEG-2 BC audio */
12384 case 0x6B: /* MPEG-1 audio */
12385 caps = gst_caps_new_simple ("audio/mpeg",
12386 "mpegversion", G_TYPE_INT, 1, "parsed", G_TYPE_BOOLEAN, TRUE, NULL);
12387 codec_name = "MPEG-1 audio";
12389 case 0x6A: /* MPEG-1 */
12390 codec_name = "MPEG-1 video";
12391 caps = gst_caps_new_simple ("video/mpeg",
12392 "mpegversion", G_TYPE_INT, 1,
12393 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
12395 case 0x6C: /* MJPEG */
12397 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
12399 codec_name = "Motion-JPEG";
12401 case 0x6D: /* PNG */
12403 gst_caps_new_simple ("image/png", "parsed", G_TYPE_BOOLEAN, TRUE,
12405 codec_name = "PNG still images";
12407 case 0x6E: /* JPEG2000 */
12408 codec_name = "JPEG-2000";
12409 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
12411 case 0xA4: /* Dirac */
12412 codec_name = "Dirac";
12413 caps = gst_caps_new_empty_simple ("video/x-dirac");
12415 case 0xA5: /* AC3 */
12416 codec_name = "AC-3 audio";
12417 caps = gst_caps_new_simple ("audio/x-ac3",
12418 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
12420 case 0xA9: /* AC3 */
12421 codec_name = "DTS audio";
12422 caps = gst_caps_new_simple ("audio/x-dts",
12423 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
12425 case 0xE1: /* QCELP */
12426 /* QCELP, the codec_data is a riff tag (little endian) with
12427 * 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). */
12428 caps = gst_caps_new_empty_simple ("audio/qcelp");
12429 codec_name = "QCELP";
12435 /* If we have a replacement caps, then change our caps for this stream */
12437 gst_caps_unref (stream->caps);
12438 stream->caps = caps;
12441 if (codec_name && list)
12442 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
12443 GST_TAG_AUDIO_CODEC, codec_name, NULL);
12445 /* Add the codec_data attribute to caps, if we have it */
12449 buffer = gst_buffer_new_and_alloc (data_len);
12450 gst_buffer_fill (buffer, 0, data_ptr, data_len);
12452 GST_DEBUG_OBJECT (qtdemux, "setting codec_data from esds");
12453 GST_MEMDUMP_OBJECT (qtdemux, "codec_data from esds", data_ptr, data_len);
12455 gst_caps_set_simple (stream->caps, "codec_data", GST_TYPE_BUFFER,
12457 gst_buffer_unref (buffer);
12462 #define _codec(name) \
12464 if (codec_name) { \
12465 *codec_name = g_strdup (name); \
12470 qtdemux_video_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
12471 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
12473 GstCaps *caps = NULL;
12474 GstVideoFormat format = GST_VIDEO_FORMAT_UNKNOWN;
12477 case GST_MAKE_FOURCC ('p', 'n', 'g', ' '):
12478 _codec ("PNG still images");
12479 caps = gst_caps_new_empty_simple ("image/png");
12482 _codec ("JPEG still images");
12484 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
12487 case GST_MAKE_FOURCC ('m', 'j', 'p', 'a'):
12488 case GST_MAKE_FOURCC ('A', 'V', 'D', 'J'):
12489 case GST_MAKE_FOURCC ('M', 'J', 'P', 'G'):
12490 case GST_MAKE_FOURCC ('d', 'm', 'b', '1'):
12491 _codec ("Motion-JPEG");
12493 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
12496 case GST_MAKE_FOURCC ('m', 'j', 'p', 'b'):
12497 _codec ("Motion-JPEG format B");
12498 caps = gst_caps_new_empty_simple ("video/x-mjpeg-b");
12501 _codec ("JPEG-2000");
12502 /* override to what it should be according to spec, avoid palette_data */
12503 stream->bits_per_sample = 24;
12504 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
12507 _codec ("Sorensen video v.3");
12508 caps = gst_caps_new_simple ("video/x-svq",
12509 "svqversion", G_TYPE_INT, 3, NULL);
12511 case GST_MAKE_FOURCC ('s', 'v', 'q', 'i'):
12512 case GST_MAKE_FOURCC ('S', 'V', 'Q', '1'):
12513 _codec ("Sorensen video v.1");
12514 caps = gst_caps_new_simple ("video/x-svq",
12515 "svqversion", G_TYPE_INT, 1, NULL);
12517 case GST_MAKE_FOURCC ('W', 'R', 'A', 'W'):
12518 caps = gst_caps_new_empty_simple ("video/x-raw");
12519 gst_caps_set_simple (caps, "format", G_TYPE_STRING, "RGB8P", NULL);
12520 _codec ("Windows Raw RGB");
12526 bps = QT_UINT16 (stsd_data + 98);
12529 format = GST_VIDEO_FORMAT_RGB15;
12532 format = GST_VIDEO_FORMAT_RGB16;
12535 format = GST_VIDEO_FORMAT_RGB;
12538 format = GST_VIDEO_FORMAT_ARGB;
12546 case GST_MAKE_FOURCC ('y', 'v', '1', '2'):
12547 format = GST_VIDEO_FORMAT_I420;
12549 case GST_MAKE_FOURCC ('y', 'u', 'v', '2'):
12550 case GST_MAKE_FOURCC ('Y', 'u', 'v', '2'):
12551 format = GST_VIDEO_FORMAT_I420;
12554 case GST_MAKE_FOURCC ('2', 'V', 'u', 'y'):
12555 format = GST_VIDEO_FORMAT_UYVY;
12557 case GST_MAKE_FOURCC ('v', '3', '0', '8'):
12558 format = GST_VIDEO_FORMAT_v308;
12560 case GST_MAKE_FOURCC ('v', '2', '1', '6'):
12561 format = GST_VIDEO_FORMAT_v216;
12564 format = GST_VIDEO_FORMAT_v210;
12566 case GST_MAKE_FOURCC ('r', '2', '1', '0'):
12567 format = GST_VIDEO_FORMAT_r210;
12569 /* Packed YUV 4:4:4 10 bit in 32 bits, complex
12570 case GST_MAKE_FOURCC ('v', '4', '1', '0'):
12571 format = GST_VIDEO_FORMAT_v410;
12574 /* Packed YUV 4:4:4:4 8 bit in 32 bits
12575 * but different order than AYUV
12576 case GST_MAKE_FOURCC ('v', '4', '0', '8'):
12577 format = GST_VIDEO_FORMAT_v408;
12580 case GST_MAKE_FOURCC ('m', 'p', 'e', 'g'):
12581 case GST_MAKE_FOURCC ('m', 'p', 'g', '1'):
12582 _codec ("MPEG-1 video");
12583 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
12584 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
12586 case GST_MAKE_FOURCC ('h', 'd', 'v', '1'): /* HDV 720p30 */
12587 case GST_MAKE_FOURCC ('h', 'd', 'v', '2'): /* HDV 1080i60 */
12588 case GST_MAKE_FOURCC ('h', 'd', 'v', '3'): /* HDV 1080i50 */
12589 case GST_MAKE_FOURCC ('h', 'd', 'v', '4'): /* HDV 720p24 */
12590 case GST_MAKE_FOURCC ('h', 'd', 'v', '5'): /* HDV 720p25 */
12591 case GST_MAKE_FOURCC ('h', 'd', 'v', '6'): /* HDV 1080p24 */
12592 case GST_MAKE_FOURCC ('h', 'd', 'v', '7'): /* HDV 1080p25 */
12593 case GST_MAKE_FOURCC ('h', 'd', 'v', '8'): /* HDV 1080p30 */
12594 case GST_MAKE_FOURCC ('h', 'd', 'v', '9'): /* HDV 720p60 */
12595 case GST_MAKE_FOURCC ('h', 'd', 'v', 'a'): /* HDV 720p50 */
12596 case GST_MAKE_FOURCC ('m', 'x', '5', 'n'): /* MPEG2 IMX NTSC 525/60 50mb/s produced by FCP */
12597 case GST_MAKE_FOURCC ('m', 'x', '5', 'p'): /* MPEG2 IMX PAL 625/60 50mb/s produced by FCP */
12598 case GST_MAKE_FOURCC ('m', 'x', '4', 'n'): /* MPEG2 IMX NTSC 525/60 40mb/s produced by FCP */
12599 case GST_MAKE_FOURCC ('m', 'x', '4', 'p'): /* MPEG2 IMX PAL 625/60 40mb/s produced by FCP */
12600 case GST_MAKE_FOURCC ('m', 'x', '3', 'n'): /* MPEG2 IMX NTSC 525/60 30mb/s produced by FCP */
12601 case GST_MAKE_FOURCC ('m', 'x', '3', 'p'): /* MPEG2 IMX PAL 625/50 30mb/s produced by FCP */
12602 case GST_MAKE_FOURCC ('x', 'd', 'v', '1'): /* XDCAM HD 720p30 35Mb/s */
12603 case GST_MAKE_FOURCC ('x', 'd', 'v', '2'): /* XDCAM HD 1080i60 35Mb/s */
12604 case GST_MAKE_FOURCC ('x', 'd', 'v', '3'): /* XDCAM HD 1080i50 35Mb/s */
12605 case GST_MAKE_FOURCC ('x', 'd', 'v', '4'): /* XDCAM HD 720p24 35Mb/s */
12606 case GST_MAKE_FOURCC ('x', 'd', 'v', '5'): /* XDCAM HD 720p25 35Mb/s */
12607 case GST_MAKE_FOURCC ('x', 'd', 'v', '6'): /* XDCAM HD 1080p24 35Mb/s */
12608 case GST_MAKE_FOURCC ('x', 'd', 'v', '7'): /* XDCAM HD 1080p25 35Mb/s */
12609 case GST_MAKE_FOURCC ('x', 'd', 'v', '8'): /* XDCAM HD 1080p30 35Mb/s */
12610 case GST_MAKE_FOURCC ('x', 'd', 'v', '9'): /* XDCAM HD 720p60 35Mb/s */
12611 case GST_MAKE_FOURCC ('x', 'd', 'v', 'a'): /* XDCAM HD 720p50 35Mb/s */
12612 case GST_MAKE_FOURCC ('x', 'd', 'v', 'b'): /* XDCAM EX 1080i60 50Mb/s CBR */
12613 case GST_MAKE_FOURCC ('x', 'd', 'v', 'c'): /* XDCAM EX 1080i50 50Mb/s CBR */
12614 case GST_MAKE_FOURCC ('x', 'd', 'v', 'd'): /* XDCAM HD 1080p24 50Mb/s CBR */
12615 case GST_MAKE_FOURCC ('x', 'd', 'v', 'e'): /* XDCAM HD 1080p25 50Mb/s CBR */
12616 case GST_MAKE_FOURCC ('x', 'd', 'v', 'f'): /* XDCAM HD 1080p30 50Mb/s CBR */
12617 case GST_MAKE_FOURCC ('x', 'd', '5', '1'): /* XDCAM HD422 720p30 50Mb/s CBR */
12618 case GST_MAKE_FOURCC ('x', 'd', '5', '4'): /* XDCAM HD422 720p24 50Mb/s CBR */
12619 case GST_MAKE_FOURCC ('x', 'd', '5', '5'): /* XDCAM HD422 720p25 50Mb/s CBR */
12620 case GST_MAKE_FOURCC ('x', 'd', '5', '9'): /* XDCAM HD422 720p60 50Mb/s CBR */
12621 case GST_MAKE_FOURCC ('x', 'd', '5', 'a'): /* XDCAM HD422 720p50 50Mb/s CBR */
12622 case GST_MAKE_FOURCC ('x', 'd', '5', 'b'): /* XDCAM HD422 1080i50 50Mb/s CBR */
12623 case GST_MAKE_FOURCC ('x', 'd', '5', 'c'): /* XDCAM HD422 1080i50 50Mb/s CBR */
12624 case GST_MAKE_FOURCC ('x', 'd', '5', 'd'): /* XDCAM HD422 1080p24 50Mb/s CBR */
12625 case GST_MAKE_FOURCC ('x', 'd', '5', 'e'): /* XDCAM HD422 1080p25 50Mb/s CBR */
12626 case GST_MAKE_FOURCC ('x', 'd', '5', 'f'): /* XDCAM HD422 1080p30 50Mb/s CBR */
12627 case GST_MAKE_FOURCC ('x', 'd', 'h', 'd'): /* XDCAM HD 540p */
12628 case GST_MAKE_FOURCC ('x', 'd', 'h', '2'): /* XDCAM HD422 540p */
12629 case GST_MAKE_FOURCC ('A', 'V', 'm', 'p'): /* AVID IMX PAL */
12630 case GST_MAKE_FOURCC ('m', 'p', 'g', '2'): /* AVID IMX PAL */
12631 case GST_MAKE_FOURCC ('m', 'p', '2', 'v'): /* AVID IMX PAL */
12632 _codec ("MPEG-2 video");
12633 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 2,
12634 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
12636 case GST_MAKE_FOURCC ('g', 'i', 'f', ' '):
12637 _codec ("GIF still images");
12638 caps = gst_caps_new_empty_simple ("image/gif");
12641 case GST_MAKE_FOURCC ('H', '2', '6', '3'):
12643 case GST_MAKE_FOURCC ('U', '2', '6', '3'):
12645 /* ffmpeg uses the height/width props, don't know why */
12646 caps = gst_caps_new_simple ("video/x-h263",
12647 "variant", G_TYPE_STRING, "itu", NULL);
12651 _codec ("MPEG-4 video");
12652 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
12653 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
12655 case GST_MAKE_FOURCC ('3', 'i', 'v', 'd'):
12656 case GST_MAKE_FOURCC ('3', 'I', 'V', 'D'):
12657 _codec ("Microsoft MPEG-4 4.3"); /* FIXME? */
12658 caps = gst_caps_new_simple ("video/x-msmpeg",
12659 "msmpegversion", G_TYPE_INT, 43, NULL);
12661 case GST_MAKE_FOURCC ('D', 'I', 'V', '3'):
12663 caps = gst_caps_new_simple ("video/x-divx",
12664 "divxversion", G_TYPE_INT, 3, NULL);
12666 case GST_MAKE_FOURCC ('D', 'I', 'V', 'X'):
12667 case GST_MAKE_FOURCC ('d', 'i', 'v', 'x'):
12669 caps = gst_caps_new_simple ("video/x-divx",
12670 "divxversion", G_TYPE_INT, 4, NULL);
12672 case GST_MAKE_FOURCC ('D', 'X', '5', '0'):
12674 caps = gst_caps_new_simple ("video/x-divx",
12675 "divxversion", G_TYPE_INT, 5, NULL);
12678 case GST_MAKE_FOURCC ('F', 'F', 'V', '1'):
12680 caps = gst_caps_new_simple ("video/x-ffv",
12681 "ffvversion", G_TYPE_INT, 1, NULL);
12684 case GST_MAKE_FOURCC ('3', 'I', 'V', '1'):
12685 case GST_MAKE_FOURCC ('3', 'I', 'V', '2'):
12686 case GST_MAKE_FOURCC ('X', 'V', 'I', 'D'):
12687 case GST_MAKE_FOURCC ('x', 'v', 'i', 'd'):
12689 case GST_MAKE_FOURCC ('U', 'M', 'P', '4'):
12690 caps = gst_caps_new_simple ("video/mpeg",
12691 "mpegversion", G_TYPE_INT, 4, NULL);
12695 case GST_MAKE_FOURCC ('c', 'v', 'i', 'd'):
12696 _codec ("Cinepak");
12697 caps = gst_caps_new_empty_simple ("video/x-cinepak");
12699 case GST_MAKE_FOURCC ('q', 'd', 'r', 'w'):
12700 _codec ("Apple QuickDraw");
12701 caps = gst_caps_new_empty_simple ("video/x-qdrw");
12703 case GST_MAKE_FOURCC ('r', 'p', 'z', 'a'):
12704 _codec ("Apple video");
12705 caps = gst_caps_new_empty_simple ("video/x-apple-video");
12709 _codec ("H.264 / AVC");
12710 caps = gst_caps_new_simple ("video/x-h264",
12711 "stream-format", G_TYPE_STRING, "avc",
12712 "alignment", G_TYPE_STRING, "au", NULL);
12715 _codec ("H.264 / AVC");
12716 caps = gst_caps_new_simple ("video/x-h264",
12717 "stream-format", G_TYPE_STRING, "avc3",
12718 "alignment", G_TYPE_STRING, "au", NULL);
12722 _codec ("H.265 / HEVC");
12723 caps = gst_caps_new_simple ("video/x-h265",
12724 "stream-format", G_TYPE_STRING, "hvc1",
12725 "alignment", G_TYPE_STRING, "au", NULL);
12728 _codec ("H.265 / HEVC");
12729 caps = gst_caps_new_simple ("video/x-h265",
12730 "stream-format", G_TYPE_STRING, "hev1",
12731 "alignment", G_TYPE_STRING, "au", NULL);
12734 _codec ("Run-length encoding");
12735 caps = gst_caps_new_simple ("video/x-rle",
12736 "layout", G_TYPE_STRING, "quicktime", NULL);
12739 _codec ("Run-length encoding");
12740 caps = gst_caps_new_simple ("video/x-rle",
12741 "layout", G_TYPE_STRING, "microsoft", NULL);
12743 case GST_MAKE_FOURCC ('I', 'V', '3', '2'):
12744 case GST_MAKE_FOURCC ('i', 'v', '3', '2'):
12745 _codec ("Indeo Video 3");
12746 caps = gst_caps_new_simple ("video/x-indeo",
12747 "indeoversion", G_TYPE_INT, 3, NULL);
12749 case GST_MAKE_FOURCC ('I', 'V', '4', '1'):
12750 case GST_MAKE_FOURCC ('i', 'v', '4', '1'):
12751 _codec ("Intel Video 4");
12752 caps = gst_caps_new_simple ("video/x-indeo",
12753 "indeoversion", G_TYPE_INT, 4, NULL);
12757 case GST_MAKE_FOURCC ('d', 'v', 's', 'd'):
12758 case GST_MAKE_FOURCC ('D', 'V', 'S', 'D'):
12759 case GST_MAKE_FOURCC ('d', 'v', 'c', 's'):
12760 case GST_MAKE_FOURCC ('D', 'V', 'C', 'S'):
12761 case GST_MAKE_FOURCC ('d', 'v', '2', '5'):
12762 case GST_MAKE_FOURCC ('d', 'v', 'p', 'p'):
12763 _codec ("DV Video");
12764 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 25,
12765 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
12767 case FOURCC_dv5n: /* DVCPRO50 NTSC */
12768 case FOURCC_dv5p: /* DVCPRO50 PAL */
12769 _codec ("DVCPro50 Video");
12770 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 50,
12771 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
12773 case GST_MAKE_FOURCC ('d', 'v', 'h', '5'): /* DVCPRO HD 50i produced by FCP */
12774 case GST_MAKE_FOURCC ('d', 'v', 'h', '6'): /* DVCPRO HD 60i produced by FCP */
12775 _codec ("DVCProHD Video");
12776 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 100,
12777 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
12779 case GST_MAKE_FOURCC ('s', 'm', 'c', ' '):
12780 _codec ("Apple Graphics (SMC)");
12781 caps = gst_caps_new_empty_simple ("video/x-smc");
12783 case GST_MAKE_FOURCC ('V', 'P', '3', '1'):
12785 caps = gst_caps_new_empty_simple ("video/x-vp3");
12787 case GST_MAKE_FOURCC ('V', 'P', '6', 'F'):
12788 _codec ("VP6 Flash");
12789 caps = gst_caps_new_empty_simple ("video/x-vp6-flash");
12793 caps = gst_caps_new_empty_simple ("video/x-theora");
12794 /* theora uses one byte of padding in the data stream because it does not
12795 * allow 0 sized packets while theora does */
12796 stream->padding = 1;
12800 caps = gst_caps_new_empty_simple ("video/x-dirac");
12802 case GST_MAKE_FOURCC ('t', 'i', 'f', 'f'):
12803 _codec ("TIFF still images");
12804 caps = gst_caps_new_empty_simple ("image/tiff");
12806 case GST_MAKE_FOURCC ('i', 'c', 'o', 'd'):
12807 _codec ("Apple Intermediate Codec");
12808 caps = gst_caps_from_string ("video/x-apple-intermediate-codec");
12810 case GST_MAKE_FOURCC ('A', 'V', 'd', 'n'):
12811 _codec ("AVID DNxHD");
12812 caps = gst_caps_from_string ("video/x-dnxhd");
12815 _codec ("On2 VP8");
12816 caps = gst_caps_from_string ("video/x-vp8");
12819 _codec ("Apple ProRes LT");
12821 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "lt",
12825 _codec ("Apple ProRes HQ");
12827 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "hq",
12831 _codec ("Apple ProRes");
12833 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
12837 _codec ("Apple ProRes Proxy");
12839 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
12843 _codec ("Apple ProRes 4444");
12845 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
12851 caps = gst_caps_new_simple ("video/x-wmv",
12852 "wmvversion", G_TYPE_INT, 3, "format", G_TYPE_STRING, "WVC1", NULL);
12854 case GST_MAKE_FOURCC ('k', 'p', 'c', 'd'):
12857 char *s, fourstr[5];
12859 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
12860 s = g_strdup_printf ("video/x-gst-fourcc-%s", g_strstrip (fourstr));
12861 caps = gst_caps_new_empty_simple (s);
12867 if (format != GST_VIDEO_FORMAT_UNKNOWN) {
12870 gst_video_info_init (&info);
12871 gst_video_info_set_format (&info, format, stream->width, stream->height);
12873 caps = gst_video_info_to_caps (&info);
12874 *codec_name = gst_pb_utils_get_codec_description (caps);
12876 /* enable clipping for raw video streams */
12877 stream->need_clip = TRUE;
12884 qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
12885 guint32 fourcc, const guint8 * data, int len, gchar ** codec_name)
12888 const GstStructure *s;
12891 GstAudioFormat format = 0;
12894 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
12896 depth = stream->bytes_per_packet * 8;
12899 case GST_MAKE_FOURCC ('N', 'O', 'N', 'E'):
12901 /* 8-bit audio is unsigned */
12903 format = GST_AUDIO_FORMAT_U8;
12904 /* otherwise it's signed and big-endian just like 'twos' */
12906 endian = G_BIG_ENDIAN;
12913 endian = G_LITTLE_ENDIAN;
12916 format = gst_audio_format_build_integer (TRUE, endian, depth, depth);
12918 str = g_strdup_printf ("Raw %d-bit PCM audio", depth);
12922 caps = gst_caps_new_simple ("audio/x-raw",
12923 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
12924 "layout", G_TYPE_STRING, "interleaved", NULL);
12927 case GST_MAKE_FOURCC ('f', 'l', '6', '4'):
12928 _codec ("Raw 64-bit floating-point audio");
12929 caps = gst_caps_new_simple ("audio/x-raw",
12930 "format", G_TYPE_STRING, "F64BE",
12931 "layout", G_TYPE_STRING, "interleaved", NULL);
12933 case GST_MAKE_FOURCC ('f', 'l', '3', '2'):
12934 _codec ("Raw 32-bit floating-point audio");
12935 caps = gst_caps_new_simple ("audio/x-raw",
12936 "format", G_TYPE_STRING, "F32BE",
12937 "layout", G_TYPE_STRING, "interleaved", NULL);
12940 _codec ("Raw 24-bit PCM audio");
12941 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
12943 caps = gst_caps_new_simple ("audio/x-raw",
12944 "format", G_TYPE_STRING, "S24BE",
12945 "layout", G_TYPE_STRING, "interleaved", NULL);
12947 case GST_MAKE_FOURCC ('i', 'n', '3', '2'):
12948 _codec ("Raw 32-bit PCM audio");
12949 caps = gst_caps_new_simple ("audio/x-raw",
12950 "format", G_TYPE_STRING, "S32BE",
12951 "layout", G_TYPE_STRING, "interleaved", NULL);
12954 _codec ("Mu-law audio");
12955 caps = gst_caps_new_empty_simple ("audio/x-mulaw");
12958 _codec ("A-law audio");
12959 caps = gst_caps_new_empty_simple ("audio/x-alaw");
12963 _codec ("Microsoft ADPCM");
12964 /* Microsoft ADPCM-ACM code 2 */
12965 caps = gst_caps_new_simple ("audio/x-adpcm",
12966 "layout", G_TYPE_STRING, "microsoft", NULL);
12970 _codec ("DVI/IMA ADPCM");
12971 caps = gst_caps_new_simple ("audio/x-adpcm",
12972 "layout", G_TYPE_STRING, "dvi", NULL);
12976 _codec ("DVI/Intel IMA ADPCM");
12977 /* FIXME DVI/Intel IMA ADPCM/ACM code 17 */
12978 caps = gst_caps_new_simple ("audio/x-adpcm",
12979 "layout", G_TYPE_STRING, "quicktime", NULL);
12983 /* MPEG layer 3, CBR only (pre QT4.1) */
12985 _codec ("MPEG-1 layer 3");
12986 /* MPEG layer 3, CBR & VBR (QT4.1 and later) */
12987 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 3,
12988 "mpegversion", G_TYPE_INT, 1, NULL);
12991 case GST_MAKE_FOURCC ('e', 'c', '-', '3'):
12992 _codec ("EAC-3 audio");
12993 caps = gst_caps_new_simple ("audio/x-eac3",
12994 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
12995 stream->sampled = TRUE;
12997 case GST_MAKE_FOURCC ('s', 'a', 'c', '3'): // Nero Recode
12999 _codec ("AC-3 audio");
13000 caps = gst_caps_new_simple ("audio/x-ac3",
13001 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
13002 stream->sampled = TRUE;
13004 case GST_MAKE_FOURCC ('d', 't', 's', 'c'):
13005 case GST_MAKE_FOURCC ('D', 'T', 'S', ' '):
13006 _codec ("DTS audio");
13007 caps = gst_caps_new_simple ("audio/x-dts",
13008 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
13009 stream->sampled = TRUE;
13011 case GST_MAKE_FOURCC ('d', 't', 's', 'h'): // DTS-HD
13012 case GST_MAKE_FOURCC ('d', 't', 's', 'l'): // DTS-HD Lossless
13013 _codec ("DTS-HD audio");
13014 caps = gst_caps_new_simple ("audio/x-dts",
13015 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
13016 stream->sampled = TRUE;
13020 caps = gst_caps_new_simple ("audio/x-mace",
13021 "maceversion", G_TYPE_INT, 3, NULL);
13025 caps = gst_caps_new_simple ("audio/x-mace",
13026 "maceversion", G_TYPE_INT, 6, NULL);
13028 case GST_MAKE_FOURCC ('O', 'g', 'g', 'V'):
13030 caps = gst_caps_new_empty_simple ("application/ogg");
13032 case GST_MAKE_FOURCC ('d', 'v', 'c', 'a'):
13033 _codec ("DV audio");
13034 caps = gst_caps_new_empty_simple ("audio/x-dv");
13037 _codec ("MPEG-4 AAC audio");
13038 caps = gst_caps_new_simple ("audio/mpeg",
13039 "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE,
13040 "stream-format", G_TYPE_STRING, "raw", NULL);
13042 case GST_MAKE_FOURCC ('Q', 'D', 'M', 'C'):
13043 _codec ("QDesign Music");
13044 caps = gst_caps_new_empty_simple ("audio/x-qdm");
13047 _codec ("QDesign Music v.2");
13048 /* FIXME: QDesign music version 2 (no constant) */
13049 if (FALSE && data) {
13050 caps = gst_caps_new_simple ("audio/x-qdm2",
13051 "framesize", G_TYPE_INT, QT_UINT32 (data + 52),
13052 "bitrate", G_TYPE_INT, QT_UINT32 (data + 40),
13053 "blocksize", G_TYPE_INT, QT_UINT32 (data + 44), NULL);
13055 caps = gst_caps_new_empty_simple ("audio/x-qdm2");
13059 _codec ("GSM audio");
13060 caps = gst_caps_new_empty_simple ("audio/x-gsm");
13063 _codec ("AMR audio");
13064 caps = gst_caps_new_empty_simple ("audio/AMR");
13067 _codec ("AMR-WB audio");
13068 caps = gst_caps_new_empty_simple ("audio/AMR-WB");
13071 _codec ("Quicktime IMA ADPCM");
13072 caps = gst_caps_new_simple ("audio/x-adpcm",
13073 "layout", G_TYPE_STRING, "quicktime", NULL);
13076 _codec ("Apple lossless audio");
13077 caps = gst_caps_new_empty_simple ("audio/x-alac");
13079 case GST_MAKE_FOURCC ('Q', 'c', 'l', 'p'):
13080 _codec ("QualComm PureVoice");
13081 caps = gst_caps_from_string ("audio/qcelp");
13086 caps = gst_caps_new_empty_simple ("audio/x-wma");
13090 caps = gst_caps_new_empty_simple ("audio/x-opus");
13092 case GST_MAKE_FOURCC ('l', 'p', 'c', 'm'):
13097 GstAudioFormat format;
13100 FLAG_IS_FLOAT = 0x1,
13101 FLAG_IS_BIG_ENDIAN = 0x2,
13102 FLAG_IS_SIGNED = 0x4,
13103 FLAG_IS_PACKED = 0x8,
13104 FLAG_IS_ALIGNED_HIGH = 0x10,
13105 FLAG_IS_NON_INTERLEAVED = 0x20
13107 _codec ("Raw LPCM audio");
13109 if (data && len >= 56) {
13110 depth = QT_UINT32 (data + 40);
13111 flags = QT_UINT32 (data + 44);
13112 width = QT_UINT32 (data + 48) * 8 / stream->n_channels;
13114 if ((flags & FLAG_IS_FLOAT) == 0) {
13119 format = gst_audio_format_build_integer ((flags & FLAG_IS_SIGNED) ?
13120 TRUE : FALSE, (flags & FLAG_IS_BIG_ENDIAN) ?
13121 G_BIG_ENDIAN : G_LITTLE_ENDIAN, width, depth);
13122 caps = gst_caps_new_simple ("audio/x-raw",
13123 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
13124 "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
13125 "non-interleaved" : "interleaved", NULL);
13130 if (flags & FLAG_IS_BIG_ENDIAN)
13131 format = GST_AUDIO_FORMAT_F64BE;
13133 format = GST_AUDIO_FORMAT_F64LE;
13135 if (flags & FLAG_IS_BIG_ENDIAN)
13136 format = GST_AUDIO_FORMAT_F32BE;
13138 format = GST_AUDIO_FORMAT_F32LE;
13140 caps = gst_caps_new_simple ("audio/x-raw",
13141 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
13142 "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
13143 "non-interleaved" : "interleaved", NULL);
13147 case GST_MAKE_FOURCC ('q', 't', 'v', 'r'):
13151 char *s, fourstr[5];
13153 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
13154 s = g_strdup_printf ("audio/x-gst-fourcc-%s", g_strstrip (fourstr));
13155 caps = gst_caps_new_empty_simple (s);
13162 GstCaps *templ_caps =
13163 gst_static_pad_template_get_caps (&gst_qtdemux_audiosrc_template);
13164 GstCaps *intersection = gst_caps_intersect (caps, templ_caps);
13165 gst_caps_unref (caps);
13166 gst_caps_unref (templ_caps);
13167 caps = intersection;
13170 /* enable clipping for raw audio streams */
13171 s = gst_caps_get_structure (caps, 0);
13172 name = gst_structure_get_name (s);
13173 if (g_str_has_prefix (name, "audio/x-raw")) {
13174 stream->need_clip = TRUE;
13175 stream->max_buffer_size = 4096 * stream->bytes_per_frame;
13176 GST_DEBUG ("setting max buffer size to %d", stream->max_buffer_size);
13182 qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
13183 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
13187 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
13191 _codec ("DVD subtitle");
13192 caps = gst_caps_new_empty_simple ("subpicture/x-dvd");
13193 stream->need_process = TRUE;
13196 _codec ("Quicktime timed text");
13199 _codec ("3GPP timed text");
13201 caps = gst_caps_new_simple ("text/x-raw", "format", G_TYPE_STRING,
13203 /* actual text piece needs to be extracted */
13204 stream->need_process = TRUE;
13207 _codec ("XML subtitles");
13208 caps = gst_caps_new_empty_simple ("application/ttml+xml");
13212 char *s, fourstr[5];
13214 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
13215 s = g_strdup_printf ("text/x-gst-fourcc-%s", g_strstrip (fourstr));
13216 caps = gst_caps_new_empty_simple (s);
13225 qtdemux_generic_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
13226 guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
13232 _codec ("MPEG 1 video");
13233 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
13234 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13244 gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux,
13245 const gchar * system_id)
13249 if (!qtdemux->protection_system_ids)
13250 qtdemux->protection_system_ids =
13251 g_ptr_array_new_with_free_func ((GDestroyNotify) g_free);
13252 /* Check whether we already have an entry for this system ID. */
13253 for (i = 0; i < qtdemux->protection_system_ids->len; ++i) {
13254 const gchar *id = g_ptr_array_index (qtdemux->protection_system_ids, i);
13255 if (g_ascii_strcasecmp (system_id, id) == 0) {
13259 GST_DEBUG_OBJECT (qtdemux, "Adding cenc protection system ID %s", system_id);
13260 g_ptr_array_add (qtdemux->protection_system_ids, g_ascii_strdown (system_id,