blob: 815792aa51ec73674ab73e0a7c87366ee20b56bf [file] [log] [blame]
zengliang.li5f31ef42024-05-16 08:27:38 +00001/* GStreamer
2 * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
3 * Copyright (C) <2003> David A. Schleef <ds@schleef.org>
4 * Copyright (C) <2006> Wim Taymans <wim@fluendo.com>
5 * Copyright (C) <2007> Julien Moutte <julien@fluendo.com>
6 * Copyright (C) <2009> Tim-Philipp Müller <tim centricular net>
7 * Copyright (C) <2009> STEricsson <benjamin.gaignard@stericsson.com>
8 * Copyright (C) <2013> Sreerenj Balachandran <sreerenj.balachandran@intel.com>
9 * Copyright (C) <2013> Intel Corporation
10 * Copyright (C) <2014> Centricular Ltd
11 * Copyright (C) <2015> YouView TV Ltd.
12 * Copyright (C) <2016> British Broadcasting Corporation
13 *
14 * This library is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU Library General Public
16 * License as published by the Free Software Foundation; either
17 * version 2 of the License, or (at your option) any later version.
18 *
19 * This library is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * Library General Public License for more details.
23 *
24 * You should have received a copy of the GNU Library General Public
25 * License along with this library; if not, write to the
26 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
27 * Boston, MA 02110-1301, USA.
28 */
29
30/**
31 * SECTION:element-qtdemux
32 * @title: qtdemux
33 *
34 * Demuxes a .mov file into raw or compressed audio and/or video streams.
35 *
36 * This element supports both push and pull-based scheduling, depending on the
37 * capabilities of the upstream elements.
38 *
39 * ## Example launch line
40 * |[
41 * gst-launch-1.0 filesrc location=test.mov ! qtdemux name=demux demux.audio_0 ! queue ! decodebin ! audioconvert ! audioresample ! autoaudiosink demux.video_0 ! queue ! decodebin ! videoconvert ! videoscale ! autovideosink
42 * ]| Play (parse and decode) a .mov file and try to output it to
43 * an automatically detected soundcard and videosink. If the MOV file contains
44 * compressed audio or video data, this will only work if you have the
45 * right decoder elements/plugins installed.
46 *
47 */
48
49#ifdef HAVE_CONFIG_H
50#include "config.h"
51#endif
52
53#include "gst/gst-i18n-plugin.h"
54
55#include <glib/gprintf.h>
56#include <gst/base/base.h>
57#include <gst/tag/tag.h>
58#include <gst/audio/audio.h>
59#include <gst/riff/riff.h>
60#include <gst/pbutils/pbutils.h>
61
62#include "gstisomp4elements.h"
63#include "qtatomparser.h"
64#include "qtdemux_types.h"
65#include "qtdemux_dump.h"
66#include "fourcc.h"
67#include "descriptors.h"
68#include "qtdemux_lang.h"
69#include "qtdemux.h"
70#include "qtpalette.h"
71#include "qtdemux_tags.h"
72#include "qtdemux_tree.h"
73#include "qtdemux-webvtt.h"
74
75#include <stdlib.h>
76#include <string.h>
77
78#include <math.h>
79#include <gst/math-compat.h>
80
81#ifdef HAVE_ZLIB
82# include <zlib.h>
83#endif
84
85/* max. size considered 'sane' for non-mdat atoms */
86#define QTDEMUX_MAX_ATOM_SIZE (32*1024*1024)
87
88/* if the sample index is larger than this, something is likely wrong */
89#define QTDEMUX_MAX_SAMPLE_INDEX_SIZE (200*1024*1024)
90
91/* For converting qt creation times to unix epoch times */
92#define QTDEMUX_SECONDS_PER_DAY (60 * 60 * 24)
93#define QTDEMUX_LEAP_YEARS_FROM_1904_TO_1970 17
94#define QTDEMUX_SECONDS_FROM_1904_TO_1970 (((1970 - 1904) * (guint64) 365 + \
95 QTDEMUX_LEAP_YEARS_FROM_1904_TO_1970) * QTDEMUX_SECONDS_PER_DAY)
96
97#define QTDEMUX_TREE_NODE_FOURCC(n) (QT_FOURCC(((guint8 *) (n)->data) + 4))
98
99#define STREAM_IS_EOS(s) ((s)->time_position == GST_CLOCK_TIME_NONE)
100
101#define ABSDIFF(x, y) ( (x) > (y) ? ((x) - (y)) : ((y) - (x)) )
102
103#define QTDEMUX_STREAM(s) ((QtDemuxStream *)(s))
104#define QTDEMUX_N_STREAMS(demux) ((demux)->active_streams->len)
105#define QTDEMUX_NTH_STREAM(demux,idx) \
106 QTDEMUX_STREAM(g_ptr_array_index((demux)->active_streams,idx))
107#define QTDEMUX_NTH_OLD_STREAM(demux,idx) \
108 QTDEMUX_STREAM(g_ptr_array_index((demux)->old_streams,idx))
109
110#define CUR_STREAM(s) (&((s)->stsd_entries[(s)->cur_stsd_entry_index]))
111
112GST_DEBUG_CATEGORY (qtdemux_debug);
113#define GST_CAT_DEFAULT qtdemux_debug
114
115typedef struct _QtDemuxCencSampleSetInfo QtDemuxCencSampleSetInfo;
116typedef struct _QtDemuxAavdEncryptionInfo QtDemuxAavdEncryptionInfo;
117
118/* Macros for converting to/from timescale */
119#define QTSTREAMTIME_TO_GSTTIME(stream, value) (gst_util_uint64_scale((value), GST_SECOND, (stream)->timescale))
120#define GSTTIME_TO_QTSTREAMTIME(stream, value) (gst_util_uint64_scale((value), (stream)->timescale, GST_SECOND))
121
122#define QTTIME_TO_GSTTIME(qtdemux, value) (gst_util_uint64_scale((value), GST_SECOND, (qtdemux)->timescale))
123#define GSTTIME_TO_QTTIME(qtdemux, value) (gst_util_uint64_scale((value), (qtdemux)->timescale, GST_SECOND))
124
125/* timestamp is the DTS */
126#define QTSAMPLE_DTS(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp))
127/* timestamp + offset + cslg_shift is the outgoing PTS */
128#define QTSAMPLE_PTS(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp + (stream)->cslg_shift + (sample)->pts_offset))
129/* timestamp + offset is the PTS used for internal seek calculations */
130#define QTSAMPLE_PTS_NO_CSLG(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp + (sample)->pts_offset))
131/* timestamp + duration - dts is the duration */
132#define QTSAMPLE_DUR_DTS(stream, sample, dts) (QTSTREAMTIME_TO_GSTTIME ((stream), (sample)->timestamp + (sample)->duration) - (dts))
133
134#define QTSAMPLE_KEYFRAME(stream,sample) ((stream)->all_keyframe || (sample)->keyframe)
135
136#define QTDEMUX_EXPOSE_GET_LOCK(demux) (&((demux)->expose_lock))
137#define QTDEMUX_EXPOSE_LOCK(demux) G_STMT_START { \
138 GST_TRACE("Locking from thread %p", g_thread_self()); \
139 g_mutex_lock (QTDEMUX_EXPOSE_GET_LOCK (demux)); \
140 GST_TRACE("Locked from thread %p", g_thread_self()); \
141 } G_STMT_END
142
143#define QTDEMUX_EXPOSE_UNLOCK(demux) G_STMT_START { \
144 GST_TRACE("Unlocking from thread %p", g_thread_self()); \
145 g_mutex_unlock (QTDEMUX_EXPOSE_GET_LOCK (demux)); \
146 } G_STMT_END
147
148/*
149 * Quicktime has tracks and segments. A track is a continuous piece of
150 * multimedia content. The track is not always played from start to finish but
151 * instead, pieces of the track are 'cut out' and played in sequence. This is
152 * what the segments do.
153 *
154 * Inside the track we have keyframes (K) and delta frames. The track has its
155 * own timing, which starts from 0 and extends to end. The position in the track
156 * is called the media_time.
157 *
158 * The segments now describe the pieces that should be played from this track
159 * and are basically tuples of media_time/duration/rate entries. We can have
160 * multiple segments and they are all played after one another. An example:
161 *
162 * segment 1: media_time: 1 second, duration: 1 second, rate 1
163 * segment 2: media_time: 3 second, duration: 2 second, rate 2
164 *
165 * To correctly play back this track, one must play: 1 second of media starting
166 * from media_time 1 followed by 2 seconds of media starting from media_time 3
167 * at a rate of 2.
168 *
169 * Each of the segments will be played at a specific time, the first segment at
170 * time 0, the second one after the duration of the first one, etc.. Note that
171 * the time in resulting playback is not identical to the media_time of the
172 * track anymore.
173 *
174 * Visually, assuming the track has 4 second of media_time:
175 *
176 * (a) (b) (c) (d)
177 * .-----------------------------------------------------------.
178 * track: | K.....K.........K........K.......K.......K...........K... |
179 * '-----------------------------------------------------------'
180 * 0 1 2 3 4
181 * .------------^ ^ .----------^ ^
182 * / .-------------' / .------------------'
183 * / / .-----' /
184 * .--------------. .--------------.
185 * | segment 1 | | segment 2 |
186 * '--------------' '--------------'
187 *
188 * The challenge here is to cut out the right pieces of the track for each of
189 * the playback segments. This fortunately can easily be done with the SEGMENT
190 * events of GStreamer.
191 *
192 * For playback of segment 1, we need to provide the decoder with the keyframe
193 * (a), in the above figure, but we must instruct it only to output the decoded
194 * data between second 1 and 2. We do this with a SEGMENT event for 1 to 2, time
195 * position set to the time of the segment: 0.
196 *
197 * We then proceed to push data from keyframe (a) to frame (b). The decoder
198 * decodes but clips all before media_time 1.
199 *
200 * After finishing a segment, we push out a new SEGMENT event with the clipping
201 * boundaries of the new data.
202 *
203 * This is a good usecase for the GStreamer accumulated SEGMENT events.
204 */
205
206struct _QtDemuxSegment
207{
208 /* global time and duration, all gst time */
209 GstClockTime time;
210 GstClockTime stop_time;
211 GstClockTime duration;
212 /* media time of trak, all gst time */
213 GstClockTime media_start;
214 GstClockTime media_stop;
215 gdouble rate;
216 /* Media start time in trak timescale units */
217 guint32 trak_media_start;
218};
219
220#define QTSEGMENT_IS_EMPTY(s) ((s)->media_start == GST_CLOCK_TIME_NONE)
221
222/* Used with fragmented MP4 files (mfra atom) */
223struct _QtDemuxRandomAccessEntry
224{
225 GstClockTime ts;
226 guint64 moof_offset;
227};
228
229
230/* Contains properties and cryptographic info for a set of samples from a
231 * track protected using Common Encryption (cenc) */
232struct _QtDemuxCencSampleSetInfo
233{
234 GstStructure *default_properties;
235
236 /* @crypto_info holds one GstStructure per sample */
237 GPtrArray *crypto_info;
238};
239
240struct _QtDemuxAavdEncryptionInfo
241{
242 GstStructure *default_properties;
243};
244
245static const gchar *
246qt_demux_state_string (enum QtDemuxState state)
247{
248 switch (state) {
249 case QTDEMUX_STATE_INITIAL:
250 return "<INITIAL>";
251 case QTDEMUX_STATE_HEADER:
252 return "<HEADER>";
253 case QTDEMUX_STATE_MOVIE:
254 return "<MOVIE>";
255 case QTDEMUX_STATE_BUFFER_MDAT:
256 return "<BUFFER_MDAT>";
257 default:
258 return "<UNKNOWN>";
259 }
260}
261
262static GstFlowReturn qtdemux_add_fragmented_samples (GstQTDemux * qtdemux);
263
264static void gst_qtdemux_check_send_pending_segment (GstQTDemux * demux);
265
266static GstStaticPadTemplate gst_qtdemux_sink_template =
267 GST_STATIC_PAD_TEMPLATE ("sink",
268 GST_PAD_SINK,
269 GST_PAD_ALWAYS,
270 GST_STATIC_CAPS ("video/quicktime; video/mj2; audio/x-m4a; "
271 "application/x-3gp")
272 );
273
274static GstStaticPadTemplate gst_qtdemux_videosrc_template =
275GST_STATIC_PAD_TEMPLATE ("video_%u",
276 GST_PAD_SRC,
277 GST_PAD_SOMETIMES,
278 GST_STATIC_CAPS_ANY);
279
280static GstStaticPadTemplate gst_qtdemux_audiosrc_template =
281GST_STATIC_PAD_TEMPLATE ("audio_%u",
282 GST_PAD_SRC,
283 GST_PAD_SOMETIMES,
284 GST_STATIC_CAPS_ANY);
285
286static GstStaticPadTemplate gst_qtdemux_subsrc_template =
287GST_STATIC_PAD_TEMPLATE ("subtitle_%u",
288 GST_PAD_SRC,
289 GST_PAD_SOMETIMES,
290 GST_STATIC_CAPS_ANY);
291
292#define gst_qtdemux_parent_class parent_class
293G_DEFINE_TYPE (GstQTDemux, gst_qtdemux, GST_TYPE_ELEMENT);
294GST_ELEMENT_REGISTER_DEFINE_WITH_CODE (qtdemux, "qtdemux",
295 GST_RANK_PRIMARY, GST_TYPE_QTDEMUX, isomp4_element_init (plugin));
296
297static void gst_qtdemux_dispose (GObject * object);
298static void gst_qtdemux_finalize (GObject * object);
299
300static guint32
301gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
302 GstClockTime media_time);
303static guint32
304gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
305 QtDemuxStream * str, gint64 media_offset);
306
307#if 0
308static void gst_qtdemux_set_index (GstElement * element, GstIndex * index);
309static GstIndex *gst_qtdemux_get_index (GstElement * element);
310#endif
311static GstStateChangeReturn gst_qtdemux_change_state (GstElement * element,
312 GstStateChange transition);
313static void gst_qtdemux_set_context (GstElement * element,
314 GstContext * context);
315static gboolean qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent);
316static gboolean qtdemux_sink_activate_mode (GstPad * sinkpad,
317 GstObject * parent, GstPadMode mode, gboolean active);
318
319static void gst_qtdemux_loop (GstPad * pad);
320static GstFlowReturn gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent,
321 GstBuffer * inbuf);
322static gboolean gst_qtdemux_handle_sink_event (GstPad * pad, GstObject * parent,
323 GstEvent * event);
324static gboolean gst_qtdemux_handle_sink_query (GstPad * pad, GstObject * parent,
325 GstQuery * query);
326static gboolean gst_qtdemux_setcaps (GstQTDemux * qtdemux, GstCaps * caps);
327static gboolean gst_qtdemux_configure_stream (GstQTDemux * qtdemux,
328 QtDemuxStream * stream);
329static void gst_qtdemux_stream_check_and_change_stsd_index (GstQTDemux * demux,
330 QtDemuxStream * stream);
331static GstFlowReturn gst_qtdemux_process_adapter (GstQTDemux * demux,
332 gboolean force);
333
334static void gst_qtdemux_check_seekability (GstQTDemux * demux);
335
336static gboolean qtdemux_parse_moov (GstQTDemux * qtdemux,
337 const guint8 * buffer, guint length);
338static gboolean qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node,
339 const guint8 * buffer, guint length);
340static gboolean qtdemux_parse_tree (GstQTDemux * qtdemux);
341
342static void gst_qtdemux_handle_esds (GstQTDemux * qtdemux,
343 QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, GNode * esds,
344 GstTagList * list);
345static GstCaps *qtdemux_video_caps (GstQTDemux * qtdemux,
346 QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, guint32 fourcc,
347 const guint8 * stsd_entry_data, gchar ** codec_name);
348static GstCaps *qtdemux_audio_caps (GstQTDemux * qtdemux,
349 QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, guint32 fourcc,
350 const guint8 * data, int len, gchar ** codec_name);
351static GstCaps *qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
352 QtDemuxStreamStsdEntry * entry, guint32 fourcc, const guint8 * data,
353 gchar ** codec_name);
354static GstCaps *qtdemux_generic_caps (GstQTDemux * qtdemux,
355 QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, guint32 fourcc,
356 const guint8 * stsd_entry_data, gchar ** codec_name);
357
358static gboolean qtdemux_parse_samples (GstQTDemux * qtdemux,
359 QtDemuxStream * stream, guint32 n);
360static GstFlowReturn qtdemux_expose_streams (GstQTDemux * qtdemux);
361static QtDemuxStream *gst_qtdemux_stream_ref (QtDemuxStream * stream);
362static void gst_qtdemux_stream_unref (QtDemuxStream * stream);
363static void gst_qtdemux_stream_clear (QtDemuxStream * stream);
364static GstFlowReturn qtdemux_prepare_streams (GstQTDemux * qtdemux);
365static void qtdemux_do_allocation (QtDemuxStream * stream,
366 GstQTDemux * qtdemux);
367static gboolean gst_qtdemux_activate_segment (GstQTDemux * qtdemux,
368 QtDemuxStream * stream, guint32 seg_idx, GstClockTime offset);
369static gboolean gst_qtdemux_stream_update_segment (GstQTDemux * qtdemux,
370 QtDemuxStream * stream, gint seg_idx, GstClockTime offset,
371 GstClockTime * _start, GstClockTime * _stop);
372static void gst_qtdemux_send_gap_for_segment (GstQTDemux * demux,
373 QtDemuxStream * stream, gint segment_index, GstClockTime pos);
374
375static gboolean qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux);
376static void check_update_duration (GstQTDemux * qtdemux, GstClockTime duration);
377
378static gchar *qtdemux_uuid_bytes_to_string (gconstpointer uuid_bytes);
379
380static GstStructure *qtdemux_get_cenc_sample_properties (GstQTDemux * qtdemux,
381 QtDemuxStream * stream, guint sample_index);
382static void gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux,
383 const gchar * id);
384static void qtdemux_gst_structure_free (GstStructure * gststructure);
385static void gst_qtdemux_reset (GstQTDemux * qtdemux, gboolean hard);
386
387static void
388gst_qtdemux_class_init (GstQTDemuxClass * klass)
389{
390 GObjectClass *gobject_class;
391 GstElementClass *gstelement_class;
392
393 gobject_class = (GObjectClass *) klass;
394 gstelement_class = (GstElementClass *) klass;
395
396 parent_class = g_type_class_peek_parent (klass);
397
398 gobject_class->dispose = gst_qtdemux_dispose;
399 gobject_class->finalize = gst_qtdemux_finalize;
400
401 gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_qtdemux_change_state);
402#if 0
403 gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_qtdemux_set_index);
404 gstelement_class->get_index = GST_DEBUG_FUNCPTR (gst_qtdemux_get_index);
405#endif
406 gstelement_class->set_context = GST_DEBUG_FUNCPTR (gst_qtdemux_set_context);
407
408 gst_tag_register_musicbrainz_tags ();
409
410 gst_element_class_add_static_pad_template (gstelement_class,
411 &gst_qtdemux_sink_template);
412 gst_element_class_add_static_pad_template (gstelement_class,
413 &gst_qtdemux_videosrc_template);
414 gst_element_class_add_static_pad_template (gstelement_class,
415 &gst_qtdemux_audiosrc_template);
416 gst_element_class_add_static_pad_template (gstelement_class,
417 &gst_qtdemux_subsrc_template);
418 gst_element_class_set_static_metadata (gstelement_class, "QuickTime demuxer",
419 "Codec/Demuxer",
420 "Demultiplex a QuickTime file into audio and video streams",
421 "David Schleef <ds@schleef.org>, Wim Taymans <wim@fluendo.com>");
422
423 GST_DEBUG_CATEGORY_INIT (qtdemux_debug, "qtdemux", 0, "qtdemux plugin");
424 gst_riff_init ();
425}
426
427static void
428gst_qtdemux_init (GstQTDemux * qtdemux)
429{
430 qtdemux->sinkpad =
431 gst_pad_new_from_static_template (&gst_qtdemux_sink_template, "sink");
432 gst_pad_set_activate_function (qtdemux->sinkpad, qtdemux_sink_activate);
433 gst_pad_set_activatemode_function (qtdemux->sinkpad,
434 qtdemux_sink_activate_mode);
435 gst_pad_set_chain_function (qtdemux->sinkpad, gst_qtdemux_chain);
436 gst_pad_set_event_function (qtdemux->sinkpad, gst_qtdemux_handle_sink_event);
437 gst_pad_set_query_function (qtdemux->sinkpad, gst_qtdemux_handle_sink_query);
438 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), qtdemux->sinkpad);
439
440 qtdemux->adapter = gst_adapter_new ();
441 g_queue_init (&qtdemux->protection_event_queue);
442 qtdemux->flowcombiner = gst_flow_combiner_new ();
443 g_mutex_init (&qtdemux->expose_lock);
444
445 qtdemux->active_streams = g_ptr_array_new_with_free_func
446 ((GDestroyNotify) gst_qtdemux_stream_unref);
447 qtdemux->old_streams = g_ptr_array_new_with_free_func
448 ((GDestroyNotify) gst_qtdemux_stream_unref);
449
450 GST_OBJECT_FLAG_SET (qtdemux, GST_ELEMENT_FLAG_INDEXABLE);
451
452 gst_qtdemux_reset (qtdemux, TRUE);
453}
454
455static void
456gst_qtdemux_finalize (GObject * object)
457{
458 GstQTDemux *qtdemux = GST_QTDEMUX (object);
459
460 g_free (qtdemux->redirect_location);
461
462 G_OBJECT_CLASS (parent_class)->finalize (object);
463}
464
465static void
466gst_qtdemux_dispose (GObject * object)
467{
468 GstQTDemux *qtdemux = GST_QTDEMUX (object);
469
470 if (qtdemux->adapter) {
471 g_object_unref (G_OBJECT (qtdemux->adapter));
472 qtdemux->adapter = NULL;
473 }
474 gst_tag_list_unref (qtdemux->tag_list);
475 gst_flow_combiner_free (qtdemux->flowcombiner);
476 g_queue_foreach (&qtdemux->protection_event_queue, (GFunc) gst_event_unref,
477 NULL);
478 g_queue_clear (&qtdemux->protection_event_queue);
479
480 g_free (qtdemux->cenc_aux_info_sizes);
481 qtdemux->cenc_aux_info_sizes = NULL;
482 g_mutex_clear (&qtdemux->expose_lock);
483
484 g_ptr_array_free (qtdemux->active_streams, TRUE);
485 g_ptr_array_free (qtdemux->old_streams, TRUE);
486
487 G_OBJECT_CLASS (parent_class)->dispose (object);
488}
489
490static void
491gst_qtdemux_post_no_playable_stream_error (GstQTDemux * qtdemux)
492{
493 if (qtdemux->redirect_location) {
494 GST_ELEMENT_ERROR_WITH_DETAILS (qtdemux, STREAM, DEMUX,
495 (_("This file contains no playable streams.")),
496 ("no known streams found, a redirect message has been posted"),
497 ("redirect-location", G_TYPE_STRING, qtdemux->redirect_location, NULL));
498 } else {
499 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
500 (_("This file contains no playable streams.")),
501 ("no known streams found"));
502 }
503}
504
505static GstBuffer *
506_gst_buffer_new_wrapped (gpointer mem, gsize size, GFreeFunc free_func)
507{
508 return gst_buffer_new_wrapped_full (free_func ? 0 : GST_MEMORY_FLAG_READONLY,
509 mem, size, 0, size, mem, free_func);
510}
511
512static GstFlowReturn
513gst_qtdemux_pull_atom (GstQTDemux * qtdemux, guint64 offset, guint64 size,
514 GstBuffer ** buf)
515{
516 GstFlowReturn flow;
517 GstMapInfo map;
518 gsize bsize;
519
520 if (G_UNLIKELY (size == 0)) {
521 GstFlowReturn ret;
522 GstBuffer *tmp = NULL;
523
524 ret = gst_qtdemux_pull_atom (qtdemux, offset, sizeof (guint32), &tmp);
525 if (ret != GST_FLOW_OK)
526 return ret;
527
528 gst_buffer_map (tmp, &map, GST_MAP_READ);
529 size = QT_UINT32 (map.data);
530 GST_DEBUG_OBJECT (qtdemux, "size 0x%08" G_GINT64_MODIFIER "x", size);
531
532 gst_buffer_unmap (tmp, &map);
533 gst_buffer_unref (tmp);
534 }
535
536 /* Sanity check: catch bogus sizes (fuzzed/broken files) */
537 if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
538 if (qtdemux->state != QTDEMUX_STATE_MOVIE && qtdemux->got_moov) {
539 /* we're pulling header but already got most interesting bits,
540 * so never mind the rest (e.g. tags) (that much) */
541 GST_WARNING_OBJECT (qtdemux, "atom has bogus size %" G_GUINT64_FORMAT,
542 size);
543 return GST_FLOW_EOS;
544 } else {
545 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
546 (_("This file is invalid and cannot be played.")),
547 ("atom has bogus size %" G_GUINT64_FORMAT, size));
548 return GST_FLOW_ERROR;
549 }
550 }
551
552 flow = gst_pad_pull_range (qtdemux->sinkpad, offset, size, buf);
553
554 if (G_UNLIKELY (flow != GST_FLOW_OK))
555 return flow;
556
557 bsize = gst_buffer_get_size (*buf);
558 /* Catch short reads - we don't want any partial atoms */
559 if (G_UNLIKELY (bsize < size)) {
560 GST_WARNING_OBJECT (qtdemux,
561 "short read: %" G_GSIZE_FORMAT " < %" G_GUINT64_FORMAT, bsize, size);
562 gst_buffer_unref (*buf);
563 *buf = NULL;
564 return GST_FLOW_EOS;
565 }
566
567 return flow;
568}
569
570#if 1
571static gboolean
572gst_qtdemux_src_convert (GstQTDemux * qtdemux, GstPad * pad,
573 GstFormat src_format, gint64 src_value, GstFormat dest_format,
574 gint64 * dest_value)
575{
576 gboolean res = TRUE;
577 QtDemuxStream *stream = gst_pad_get_element_private (pad);
578 gint32 index;
579
580 if (stream->subtype != FOURCC_vide) {
581 res = FALSE;
582 goto done;
583 }
584
585 switch (src_format) {
586 case GST_FORMAT_TIME:
587 switch (dest_format) {
588 case GST_FORMAT_BYTES:{
589 index = gst_qtdemux_find_index_linear (qtdemux, stream, src_value);
590 if (-1 == index) {
591 res = FALSE;
592 goto done;
593 }
594
595 *dest_value = stream->samples[index].offset;
596
597 GST_DEBUG_OBJECT (qtdemux, "Format Conversion Time->Offset :%"
598 GST_TIME_FORMAT "->%" G_GUINT64_FORMAT,
599 GST_TIME_ARGS (src_value), *dest_value);
600 break;
601 }
602 default:
603 res = FALSE;
604 break;
605 }
606 break;
607 case GST_FORMAT_BYTES:
608 switch (dest_format) {
609 case GST_FORMAT_TIME:{
610 index =
611 gst_qtdemux_find_index_for_given_media_offset_linear (qtdemux,
612 stream, src_value);
613
614 if (-1 == index) {
615 res = FALSE;
616 goto done;
617 }
618
619 *dest_value =
620 QTSTREAMTIME_TO_GSTTIME (stream,
621 stream->samples[index].timestamp);
622 GST_DEBUG_OBJECT (qtdemux,
623 "Format Conversion Offset->Time :%" G_GUINT64_FORMAT "->%"
624 GST_TIME_FORMAT, src_value, GST_TIME_ARGS (*dest_value));
625 break;
626 }
627 default:
628 res = FALSE;
629 break;
630 }
631 break;
632 default:
633 res = FALSE;
634 break;
635 }
636
637done:
638 return res;
639}
640#endif
641
642static gboolean
643gst_qtdemux_get_duration (GstQTDemux * qtdemux, GstClockTime * duration)
644{
645 gboolean res = FALSE;
646
647 *duration = GST_CLOCK_TIME_NONE;
648
649 if (qtdemux->duration != 0 &&
650 qtdemux->duration != G_MAXINT64 && qtdemux->timescale != 0) {
651 *duration = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
652 res = TRUE;
653 } else {
654 *duration = GST_CLOCK_TIME_NONE;
655 }
656
657 return res;
658}
659
660static gboolean
661gst_qtdemux_handle_src_query (GstPad * pad, GstObject * parent,
662 GstQuery * query)
663{
664 gboolean res = FALSE;
665 GstQTDemux *qtdemux = GST_QTDEMUX (parent);
666
667 GST_LOG_OBJECT (pad, "%s query", GST_QUERY_TYPE_NAME (query));
668
669 switch (GST_QUERY_TYPE (query)) {
670 case GST_QUERY_POSITION:{
671 GstFormat fmt;
672
673 gst_query_parse_position (query, &fmt, NULL);
674 if (fmt == GST_FORMAT_TIME
675 && GST_CLOCK_TIME_IS_VALID (qtdemux->segment.position)) {
676 gst_query_set_position (query, GST_FORMAT_TIME,
677 qtdemux->segment.position);
678 res = TRUE;
679 }
680 }
681 break;
682 case GST_QUERY_DURATION:{
683 GstFormat fmt;
684
685 gst_query_parse_duration (query, &fmt, NULL);
686 if (fmt == GST_FORMAT_TIME) {
687 /* First try to query upstream */
688 res = gst_pad_query_default (pad, parent, query);
689 if (!res) {
690 GstClockTime duration;
691 if (gst_qtdemux_get_duration (qtdemux, &duration) && duration > 0) {
692 gst_query_set_duration (query, GST_FORMAT_TIME, duration);
693 res = TRUE;
694 }
695 }
696 }
697 break;
698 }
699 case GST_QUERY_CONVERT:{
700 GstFormat src_fmt, dest_fmt;
701 gint64 src_value, dest_value = 0;
702
703 gst_query_parse_convert (query, &src_fmt, &src_value, &dest_fmt, NULL);
704
705 res = gst_qtdemux_src_convert (qtdemux, pad,
706 src_fmt, src_value, dest_fmt, &dest_value);
707 if (res)
708 gst_query_set_convert (query, src_fmt, src_value, dest_fmt, dest_value);
709
710 break;
711 }
712 case GST_QUERY_FORMATS:
713 gst_query_set_formats (query, 2, GST_FORMAT_TIME, GST_FORMAT_BYTES);
714 res = TRUE;
715 break;
716 case GST_QUERY_SEEKING:{
717 GstFormat fmt;
718 gboolean seekable;
719
720 gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
721
722 if (fmt == GST_FORMAT_BYTES) {
723 /* We always refuse BYTES seeks from downstream */
724 break;
725 }
726
727 /* try upstream first */
728 res = gst_pad_query_default (pad, parent, query);
729
730 if (!res) {
731 gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
732 if (fmt == GST_FORMAT_TIME) {
733 GstClockTime duration;
734
735 gst_qtdemux_get_duration (qtdemux, &duration);
736 seekable = TRUE;
737 if (!qtdemux->pullbased) {
738 GstQuery *q;
739
740 /* we might be able with help from upstream */
741 seekable = FALSE;
742 q = gst_query_new_seeking (GST_FORMAT_BYTES);
743 if (gst_pad_peer_query (qtdemux->sinkpad, q)) {
744 gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL);
745 GST_LOG_OBJECT (qtdemux, "upstream BYTE seekable %d", seekable);
746 }
747 gst_query_unref (q);
748 }
749 gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0, duration);
750 res = TRUE;
751 }
752 }
753 break;
754 }
755 case GST_QUERY_SEGMENT:
756 {
757 GstFormat format;
758 gint64 start, stop;
759
760 format = qtdemux->segment.format;
761
762 start =
763 gst_segment_to_stream_time (&qtdemux->segment, format,
764 qtdemux->segment.start);
765 if ((stop = qtdemux->segment.stop) == -1)
766 stop = qtdemux->segment.duration;
767 else
768 stop = gst_segment_to_stream_time (&qtdemux->segment, format, stop);
769
770 gst_query_set_segment (query, qtdemux->segment.rate, format, start, stop);
771 res = TRUE;
772 break;
773 }
774 default:
775 res = gst_pad_query_default (pad, parent, query);
776 break;
777 }
778
779 return res;
780}
781
782static void
783gst_qtdemux_push_tags (GstQTDemux * qtdemux, QtDemuxStream * stream)
784{
785 if (G_LIKELY (stream->pad)) {
786 GST_DEBUG_OBJECT (qtdemux, "Checking pad %s:%s for tags",
787 GST_DEBUG_PAD_NAME (stream->pad));
788
789 if (!gst_tag_list_is_empty (stream->stream_tags)) {
790 GST_DEBUG_OBJECT (qtdemux, "Sending tags %" GST_PTR_FORMAT,
791 stream->stream_tags);
792 gst_pad_push_event (stream->pad,
793 gst_event_new_tag (gst_tag_list_ref (stream->stream_tags)));
794 }
795
796 if (G_UNLIKELY (stream->send_global_tags)) {
797 GST_DEBUG_OBJECT (qtdemux, "Sending global tags %" GST_PTR_FORMAT,
798 qtdemux->tag_list);
799 gst_pad_push_event (stream->pad,
800 gst_event_new_tag (gst_tag_list_ref (qtdemux->tag_list)));
801 stream->send_global_tags = FALSE;
802 }
803 }
804}
805
806/* push event on all source pads; takes ownership of the event */
807static void
808gst_qtdemux_push_event (GstQTDemux * qtdemux, GstEvent * event)
809{
810 gboolean has_valid_stream = FALSE;
811 GstEventType etype = GST_EVENT_TYPE (event);
812 guint i;
813
814 GST_DEBUG_OBJECT (qtdemux, "pushing %s event on all source pads",
815 GST_EVENT_TYPE_NAME (event));
816
817 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
818 GstPad *pad;
819 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
820 GST_DEBUG_OBJECT (qtdemux, "pushing on track-id %u", stream->track_id);
821
822 if ((pad = stream->pad)) {
823 has_valid_stream = TRUE;
824
825 if (etype == GST_EVENT_EOS) {
826 /* let's not send twice */
827 if (stream->sent_eos)
828 continue;
829 stream->sent_eos = TRUE;
830 }
831
832 gst_pad_push_event (pad, gst_event_ref (event));
833 }
834 }
835
836 gst_event_unref (event);
837
838 /* if it is EOS and there are no pads, post an error */
839 if (!has_valid_stream && etype == GST_EVENT_EOS) {
840 gst_qtdemux_post_no_playable_stream_error (qtdemux);
841 }
842}
843
844typedef struct
845{
846 guint64 media_time;
847} FindData;
848
849static gint
850find_func (QtDemuxSample * s1, gint64 * media_time, gpointer user_data)
851{
852 if ((gint64) s1->timestamp > *media_time)
853 return 1;
854 if ((gint64) s1->timestamp == *media_time)
855 return 0;
856
857 return -1;
858}
859
860/* find the index of the sample that includes the data for @media_time using a
861 * binary search. Only to be called in optimized cases of linear search below.
862 *
863 * Returns the index of the sample with the corresponding *DTS*.
864 */
865static guint32
866gst_qtdemux_find_index (GstQTDemux * qtdemux, QtDemuxStream * str,
867 guint64 media_time)
868{
869 QtDemuxSample *result;
870 guint32 index;
871
872 /* convert media_time to mov format */
873 media_time =
874 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
875
876 result = gst_util_array_binary_search (str->samples, str->stbl_index + 1,
877 sizeof (QtDemuxSample), (GCompareDataFunc) find_func,
878 GST_SEARCH_MODE_BEFORE, &media_time, NULL);
879
880 if (G_LIKELY (result))
881 index = result - str->samples;
882 else
883 index = 0;
884
885 return index;
886}
887
888
889
890/* find the index of the sample that includes the data for @media_offset using a
891 * linear search
892 *
893 * Returns the index of the sample.
894 */
895static guint32
896gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
897 QtDemuxStream * str, gint64 media_offset)
898{
899 QtDemuxSample *result = str->samples;
900 guint32 index = 0;
901
902 if (result == NULL || str->n_samples == 0)
903 return -1;
904
905 if (media_offset == result->offset)
906 return index;
907
908 result++;
909 while (index < str->n_samples - 1) {
910 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
911 goto parse_failed;
912
913 if (media_offset < result->offset)
914 break;
915
916 index++;
917 result++;
918 }
919 return index;
920
921 /* ERRORS */
922parse_failed:
923 {
924 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
925 return -1;
926 }
927}
928
929/* find the index of the sample that includes the data for @media_time using a
930 * linear search, and keeping in mind that not all samples may have been parsed
931 * yet. If possible, it will delegate to binary search.
932 *
933 * Returns the index of the sample.
934 */
935static guint32
936gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
937 GstClockTime media_time)
938{
939 guint32 index = 0;
940 guint64 mov_time;
941 QtDemuxSample *sample;
942
943 /* convert media_time to mov format */
944 mov_time =
945 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
946
947 sample = str->samples;
948 if (mov_time == sample->timestamp + sample->pts_offset)
949 return index;
950
951 /* use faster search if requested time in already parsed range */
952 sample = str->samples + str->stbl_index;
953 if (str->stbl_index >= 0 && mov_time <= sample->timestamp) {
954 index = gst_qtdemux_find_index (qtdemux, str, media_time);
955 sample = str->samples + index;
956 } else {
957 while (index < str->n_samples - 1) {
958 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
959 goto parse_failed;
960
961 sample = str->samples + index + 1;
962 if (mov_time < sample->timestamp) {
963 sample = str->samples + index;
964 break;
965 }
966
967 index++;
968 }
969 }
970
971 /* sample->timestamp is now <= media_time, need to find the corresponding
972 * PTS now by looking backwards */
973 while (index > 0 && sample->timestamp + sample->pts_offset > mov_time) {
974 index--;
975 sample = str->samples + index;
976 }
977
978 return index;
979
980 /* ERRORS */
981parse_failed:
982 {
983 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
984 return -1;
985 }
986}
987
988/* find the index of the keyframe needed to decode the sample at @index
989 * of stream @str, or of a subsequent keyframe (depending on @next)
990 *
991 * Returns the index of the keyframe.
992 */
993static guint32
994gst_qtdemux_find_keyframe (GstQTDemux * qtdemux, QtDemuxStream * str,
995 guint32 index, gboolean next)
996{
997 guint32 new_index = index;
998
999 if (index >= str->n_samples) {
1000 new_index = str->n_samples;
1001 goto beach;
1002 }
1003
1004 /* all keyframes, return index */
1005 if (str->all_keyframe) {
1006 new_index = index;
1007 goto beach;
1008 }
1009
1010 /* else search until we have a keyframe */
1011 while (new_index < str->n_samples) {
1012 if (next && !qtdemux_parse_samples (qtdemux, str, new_index))
1013 goto parse_failed;
1014
1015 if (str->samples[new_index].keyframe)
1016 break;
1017
1018 if (new_index == 0)
1019 break;
1020
1021 if (next)
1022 new_index++;
1023 else
1024 new_index--;
1025 }
1026
1027 if (new_index == str->n_samples) {
1028 GST_DEBUG_OBJECT (qtdemux, "no next keyframe");
1029 new_index = -1;
1030 }
1031
1032beach:
1033 GST_DEBUG_OBJECT (qtdemux, "searching for keyframe index %s index %u "
1034 "gave %u", next ? "after" : "before", index, new_index);
1035
1036 return new_index;
1037
1038 /* ERRORS */
1039parse_failed:
1040 {
1041 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", new_index);
1042 return -1;
1043 }
1044}
1045
1046/* find the segment for @time_position for @stream
1047 *
1048 * Returns the index of the segment containing @time_position.
1049 * Returns the last segment and sets the @eos variable to TRUE
1050 * if the time is beyond the end. @eos may be NULL
1051 */
1052static guint32
1053gst_qtdemux_find_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
1054 GstClockTime time_position)
1055{
1056 gint i;
1057 guint32 seg_idx;
1058
1059 GST_LOG_OBJECT (stream->pad, "finding segment for %" GST_TIME_FORMAT,
1060 GST_TIME_ARGS (time_position));
1061
1062 seg_idx = -1;
1063 for (i = 0; i < stream->n_segments; i++) {
1064 QtDemuxSegment *segment = &stream->segments[i];
1065
1066 GST_LOG_OBJECT (stream->pad,
1067 "looking at segment %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT,
1068 GST_TIME_ARGS (segment->time), GST_TIME_ARGS (segment->stop_time));
1069
1070 /* For the last segment we include stop_time in the last segment */
1071 if (i < stream->n_segments - 1) {
1072 if (segment->time <= time_position && time_position < segment->stop_time) {
1073 GST_LOG_OBJECT (stream->pad, "segment %d matches", i);
1074 seg_idx = i;
1075 break;
1076 }
1077 } else {
1078 /* Last segment always matches */
1079 seg_idx = i;
1080 break;
1081 }
1082 }
1083 return seg_idx;
1084}
1085
1086/* move the stream @str to the sample position @index.
1087 *
1088 * Updates @str->sample_index and marks discontinuity if needed.
1089 */
1090static void
1091gst_qtdemux_move_stream (GstQTDemux * qtdemux, QtDemuxStream * str,
1092 guint32 index)
1093{
1094 /* no change needed */
1095 if (index == str->sample_index)
1096 return;
1097
1098 GST_DEBUG_OBJECT (qtdemux, "moving to sample %u of %u", index,
1099 str->n_samples);
1100
1101 /* position changed, we have a discont */
1102 str->sample_index = index;
1103 str->offset_in_sample = 0;
1104 /* Each time we move in the stream we store the position where we are
1105 * starting from */
1106 str->from_sample = index;
1107 str->discont = TRUE;
1108}
1109
1110static void
1111gst_qtdemux_adjust_seek (GstQTDemux * qtdemux, gint64 desired_time,
1112 gboolean use_sparse, gboolean next, gint64 * key_time, gint64 * key_offset)
1113{
1114 guint64 min_offset;
1115 gint64 min_byte_offset = -1;
1116 guint i;
1117
1118 min_offset = desired_time;
1119
1120 /* for each stream, find the index of the sample in the segment
1121 * and move back to the previous keyframe. */
1122 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
1123 QtDemuxStream *str;
1124 guint32 index, kindex;
1125 guint32 seg_idx;
1126 GstClockTime media_start;
1127 GstClockTime media_time;
1128 GstClockTime seg_time;
1129 QtDemuxSegment *seg;
1130 gboolean empty_segment = FALSE;
1131
1132 str = QTDEMUX_NTH_STREAM (qtdemux, i);
1133
1134 if (CUR_STREAM (str)->sparse && !use_sparse)
1135 continue;
1136
1137 seg_idx = gst_qtdemux_find_segment (qtdemux, str, desired_time);
1138 GST_DEBUG_OBJECT (qtdemux, "align segment %d", seg_idx);
1139
1140 /* get segment and time in the segment */
1141 seg = &str->segments[seg_idx];
1142 seg_time = (desired_time - seg->time) * seg->rate;
1143
1144 while (QTSEGMENT_IS_EMPTY (seg)) {
1145 seg_time = 0;
1146 empty_segment = TRUE;
1147 GST_DEBUG_OBJECT (str->pad, "Segment %d is empty, moving to next one",
1148 seg_idx);
1149 seg_idx++;
1150 if (seg_idx == str->n_segments)
1151 break;
1152 seg = &str->segments[seg_idx];
1153 }
1154
1155 if (seg_idx == str->n_segments) {
1156 /* FIXME track shouldn't have the last segment as empty, but if it
1157 * happens we better handle it */
1158 continue;
1159 }
1160
1161 /* get the media time in the segment */
1162 media_start = seg->media_start + seg_time;
1163
1164 /* get the index of the sample with media time */
1165 index = gst_qtdemux_find_index_linear (qtdemux, str, media_start);
1166 GST_DEBUG_OBJECT (qtdemux, "sample for %" GST_TIME_FORMAT " at %u"
1167 " at offset %" G_GUINT64_FORMAT " (empty segment: %d)",
1168 GST_TIME_ARGS (media_start), index, str->samples[index].offset,
1169 empty_segment);
1170
1171 /* shift to next frame if we are looking for next keyframe */
1172 if (next && QTSAMPLE_PTS_NO_CSLG (str, &str->samples[index]) < media_start
1173 && index < str->stbl_index)
1174 index++;
1175
1176 if (!empty_segment) {
1177 /* find previous keyframe */
1178 kindex = gst_qtdemux_find_keyframe (qtdemux, str, index, next);
1179
1180 /* we will settle for one before if none found after */
1181 if (next && kindex == -1)
1182 kindex = gst_qtdemux_find_keyframe (qtdemux, str, index, FALSE);
1183
1184 /* Update the requested time whenever a keyframe was found, to make it
1185 * accurate and avoid having the first buffer fall outside of the segment
1186 */
1187 if (kindex != -1) {
1188 index = kindex;
1189
1190 /* get timestamp of keyframe */
1191 media_time = QTSAMPLE_PTS_NO_CSLG (str, &str->samples[kindex]);
1192 GST_DEBUG_OBJECT (qtdemux,
1193 "keyframe at %u with time %" GST_TIME_FORMAT " at offset %"
1194 G_GUINT64_FORMAT, kindex, GST_TIME_ARGS (media_time),
1195 str->samples[kindex].offset);
1196
1197 /* keyframes in the segment get a chance to change the
1198 * desired_offset. keyframes out of the segment are
1199 * ignored. */
1200 if (media_time >= seg->media_start) {
1201 GstClockTime seg_time;
1202
1203 /* this keyframe is inside the segment, convert back to
1204 * segment time */
1205 seg_time = (media_time - seg->media_start) + seg->time;
1206 if ((!next && (seg_time < min_offset)) ||
1207 (next && (seg_time > min_offset)))
1208 min_offset = seg_time;
1209 }
1210 }
1211 }
1212
1213 if (min_byte_offset < 0 || str->samples[index].offset < min_byte_offset)
1214 min_byte_offset = str->samples[index].offset;
1215 }
1216
1217 if (key_time)
1218 *key_time = min_offset;
1219 if (key_offset)
1220 *key_offset = min_byte_offset;
1221}
1222
1223static gboolean
1224gst_qtdemux_convert_seek (GstPad * pad, GstFormat * format,
1225 GstSeekType cur_type, gint64 * cur, GstSeekType stop_type, gint64 * stop)
1226{
1227 gboolean res;
1228
1229 g_return_val_if_fail (format != NULL, FALSE);
1230 g_return_val_if_fail (cur != NULL, FALSE);
1231 g_return_val_if_fail (stop != NULL, FALSE);
1232
1233 if (*format == GST_FORMAT_TIME)
1234 return TRUE;
1235
1236 res = TRUE;
1237 if (cur_type != GST_SEEK_TYPE_NONE)
1238 res = gst_pad_query_convert (pad, *format, *cur, GST_FORMAT_TIME, cur);
1239 if (res && stop_type != GST_SEEK_TYPE_NONE)
1240 res = gst_pad_query_convert (pad, *format, *stop, GST_FORMAT_TIME, stop);
1241
1242 if (res)
1243 *format = GST_FORMAT_TIME;
1244
1245 return res;
1246}
1247
1248/* perform seek in push based mode:
1249 find BYTE position to move to based on time and delegate to upstream
1250*/
1251static gboolean
1252gst_qtdemux_do_push_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1253{
1254 gdouble rate;
1255 GstFormat format;
1256 GstSeekFlags flags;
1257 GstSeekType cur_type, stop_type;
1258 gint64 cur, stop, key_cur;
1259 gboolean res;
1260 gint64 byte_cur;
1261 gint64 original_stop;
1262 guint32 seqnum;
1263
1264 GST_DEBUG_OBJECT (qtdemux, "doing push-based seek");
1265
1266 gst_event_parse_seek (event, &rate, &format, &flags,
1267 &cur_type, &cur, &stop_type, &stop);
1268 seqnum = gst_event_get_seqnum (event);
1269
1270 /* Directly send the instant-rate-change event here before taking the
1271 * stream-lock so that it can be applied as soon as possible */
1272 if (flags & GST_SEEK_FLAG_INSTANT_RATE_CHANGE) {
1273 GstEvent *ev;
1274
1275 /* instant rate change only supported if direction does not change. All
1276 * other requirements are already checked before creating the seek event
1277 * but let's double-check here to be sure */
1278 if ((qtdemux->segment.rate > 0 && rate < 0) ||
1279 (qtdemux->segment.rate < 0 && rate > 0) ||
1280 cur_type != GST_SEEK_TYPE_NONE ||
1281 stop_type != GST_SEEK_TYPE_NONE || (flags & GST_SEEK_FLAG_FLUSH)) {
1282 GST_ERROR_OBJECT (qtdemux,
1283 "Instant rate change seeks only supported in the "
1284 "same direction, without flushing and position change");
1285 return FALSE;
1286 }
1287
1288 ev = gst_event_new_instant_rate_change (rate / qtdemux->segment.rate,
1289 (GstSegmentFlags) flags);
1290 gst_event_set_seqnum (ev, seqnum);
1291 gst_qtdemux_push_event (qtdemux, ev);
1292 return TRUE;
1293 }
1294
1295 /* only forward streaming and seeking is possible */
1296 if (rate <= 0)
1297 goto unsupported_seek;
1298
1299 /* convert to TIME if needed and possible */
1300 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1301 stop_type, &stop))
1302 goto no_format;
1303
1304 /* Upstream seek in bytes will have undefined stop, but qtdemux stores
1305 * the original stop position to use when upstream pushes the new segment
1306 * for this seek */
1307 original_stop = stop;
1308 stop = -1;
1309
1310 /* find reasonable corresponding BYTE position,
1311 * also try to mind about keyframes, since we can not go back a bit for them
1312 * later on */
1313 /* determining @next here based on SNAP_BEFORE/SNAP_AFTER should
1314 * mostly just work, but let's not yet boldly go there ... */
1315 gst_qtdemux_adjust_seek (qtdemux, cur, FALSE, FALSE, &key_cur, &byte_cur);
1316
1317 if (byte_cur == -1)
1318 goto abort_seek;
1319
1320 GST_DEBUG_OBJECT (qtdemux, "Pushing BYTE seek rate %g, "
1321 "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, byte_cur,
1322 stop);
1323
1324 GST_OBJECT_LOCK (qtdemux);
1325 qtdemux->seek_offset = byte_cur;
1326 if (!(flags & GST_SEEK_FLAG_KEY_UNIT)) {
1327 qtdemux->push_seek_start = cur;
1328 } else {
1329 qtdemux->push_seek_start = key_cur;
1330 }
1331
1332 if (stop_type == GST_SEEK_TYPE_NONE) {
1333 qtdemux->push_seek_stop = qtdemux->segment.stop;
1334 } else {
1335 qtdemux->push_seek_stop = original_stop;
1336 }
1337 GST_OBJECT_UNLOCK (qtdemux);
1338
1339 qtdemux->segment_seqnum = seqnum;
1340 /* BYTE seek event */
1341 event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type, byte_cur,
1342 stop_type, stop);
1343 gst_event_set_seqnum (event, seqnum);
1344 res = gst_pad_push_event (qtdemux->sinkpad, event);
1345
1346 return res;
1347
1348 /* ERRORS */
1349abort_seek:
1350 {
1351 GST_DEBUG_OBJECT (qtdemux, "could not determine byte position to seek to, "
1352 "seek aborted.");
1353 return FALSE;
1354 }
1355unsupported_seek:
1356 {
1357 GST_DEBUG_OBJECT (qtdemux, "unsupported seek, seek aborted.");
1358 return FALSE;
1359 }
1360no_format:
1361 {
1362 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1363 return FALSE;
1364 }
1365}
1366
1367/* perform the seek.
1368 *
1369 * We set all segment_indexes in the streams to unknown and
1370 * adjust the time_position to the desired position. this is enough
1371 * to trigger a segment switch in the streaming thread to start
1372 * streaming from the desired position.
1373 *
1374 * Keyframe seeking is a little more complicated when dealing with
1375 * segments. Ideally we want to move to the previous keyframe in
1376 * the segment but there might not be a keyframe in the segment. In
1377 * fact, none of the segments could contain a keyframe. We take a
1378 * practical approach: seek to the previous keyframe in the segment,
1379 * if there is none, seek to the beginning of the segment.
1380 *
1381 * Called with STREAM_LOCK
1382 */
1383static gboolean
1384gst_qtdemux_perform_seek (GstQTDemux * qtdemux, GstSegment * segment,
1385 guint32 seqnum, GstSeekFlags flags)
1386{
1387 gint64 desired_offset;
1388 guint i;
1389
1390 desired_offset = segment->position;
1391
1392 GST_DEBUG_OBJECT (qtdemux, "seeking to %" GST_TIME_FORMAT,
1393 GST_TIME_ARGS (desired_offset));
1394
1395 /* may not have enough fragmented info to do this adjustment,
1396 * and we can't scan (and probably should not) at this time with
1397 * possibly flushing upstream */
1398 if ((flags & GST_SEEK_FLAG_KEY_UNIT) && !qtdemux->fragmented) {
1399 gint64 min_offset;
1400 gboolean next, before, after;
1401
1402 before = ! !(flags & GST_SEEK_FLAG_SNAP_BEFORE);
1403 after = ! !(flags & GST_SEEK_FLAG_SNAP_AFTER);
1404 next = after && !before;
1405 if (segment->rate < 0)
1406 next = !next;
1407
1408 gst_qtdemux_adjust_seek (qtdemux, desired_offset, TRUE, next, &min_offset,
1409 NULL);
1410 GST_DEBUG_OBJECT (qtdemux, "keyframe seek, align to %"
1411 GST_TIME_FORMAT, GST_TIME_ARGS (min_offset));
1412 desired_offset = min_offset;
1413 }
1414
1415 /* and set all streams to the final position */
1416 GST_OBJECT_LOCK (qtdemux);
1417 gst_flow_combiner_reset (qtdemux->flowcombiner);
1418 GST_OBJECT_UNLOCK (qtdemux);
1419 qtdemux->segment_seqnum = seqnum;
1420 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
1421 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
1422
1423 stream->time_position = desired_offset;
1424 stream->accumulated_base = 0;
1425 stream->sample_index = -1;
1426 stream->offset_in_sample = 0;
1427 stream->segment_index = -1;
1428 stream->sent_eos = FALSE;
1429 stream->last_keyframe_dts = GST_CLOCK_TIME_NONE;
1430
1431 if (segment->flags & GST_SEEK_FLAG_FLUSH)
1432 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
1433 }
1434 segment->position = desired_offset;
1435 if (segment->rate >= 0) {
1436 segment->start = desired_offset;
1437 /* We need to update time as we update start in that direction */
1438 segment->time = desired_offset;
1439
1440 /* we stop at the end */
1441 if (segment->stop == -1)
1442 segment->stop = segment->duration;
1443 } else {
1444 segment->stop = desired_offset;
1445 }
1446
1447 if (qtdemux->fragmented)
1448 qtdemux->fragmented_seek_pending = TRUE;
1449
1450 return TRUE;
1451}
1452
1453/* do a seek in pull based mode */
1454static gboolean
1455gst_qtdemux_do_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1456{
1457 gdouble rate = 1.0;
1458 GstFormat format;
1459 GstSeekFlags flags;
1460 GstSeekType cur_type, stop_type;
1461 gint64 cur, stop;
1462 gboolean flush, instant_rate_change;
1463 gboolean update;
1464 GstSegment seeksegment;
1465 guint32 seqnum = GST_SEQNUM_INVALID;
1466 GstEvent *flush_event;
1467 gboolean ret;
1468
1469 GST_DEBUG_OBJECT (qtdemux, "doing seek with event");
1470
1471 gst_event_parse_seek (event, &rate, &format, &flags,
1472 &cur_type, &cur, &stop_type, &stop);
1473 seqnum = gst_event_get_seqnum (event);
1474
1475 /* we have to have a format as the segment format. Try to convert
1476 * if not. */
1477 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1478 stop_type, &stop))
1479 goto no_format;
1480
1481 GST_DEBUG_OBJECT (qtdemux, "seek format %s", gst_format_get_name (format));
1482
1483 flush = ! !(flags & GST_SEEK_FLAG_FLUSH);
1484 instant_rate_change = ! !(flags & GST_SEEK_FLAG_INSTANT_RATE_CHANGE);
1485
1486 /* Directly send the instant-rate-change event here before taking the
1487 * stream-lock so that it can be applied as soon as possible */
1488 if (instant_rate_change) {
1489 GstEvent *ev;
1490
1491 /* instant rate change only supported if direction does not change. All
1492 * other requirements are already checked before creating the seek event
1493 * but let's double-check here to be sure */
1494 if ((qtdemux->segment.rate > 0 && rate < 0) ||
1495 (qtdemux->segment.rate < 0 && rate > 0) ||
1496 cur_type != GST_SEEK_TYPE_NONE ||
1497 stop_type != GST_SEEK_TYPE_NONE || flush) {
1498 GST_ERROR_OBJECT (qtdemux,
1499 "Instant rate change seeks only supported in the "
1500 "same direction, without flushing and position change");
1501 return FALSE;
1502 }
1503
1504 ev = gst_event_new_instant_rate_change (rate / qtdemux->segment.rate,
1505 (GstSegmentFlags) flags);
1506 gst_event_set_seqnum (ev, seqnum);
1507 gst_qtdemux_push_event (qtdemux, ev);
1508 return TRUE;
1509 }
1510
1511 /* stop streaming, either by flushing or by pausing the task */
1512 if (flush) {
1513 flush_event = gst_event_new_flush_start ();
1514 if (seqnum != GST_SEQNUM_INVALID)
1515 gst_event_set_seqnum (flush_event, seqnum);
1516 /* unlock upstream pull_range */
1517 gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event));
1518 /* make sure out loop function exits */
1519 gst_qtdemux_push_event (qtdemux, flush_event);
1520 } else {
1521 /* non flushing seek, pause the task */
1522 gst_pad_pause_task (qtdemux->sinkpad);
1523 }
1524
1525 /* wait for streaming to finish */
1526 GST_PAD_STREAM_LOCK (qtdemux->sinkpad);
1527
1528 /* copy segment, we need this because we still need the old
1529 * segment when we close the current segment. */
1530 memcpy (&seeksegment, &qtdemux->segment, sizeof (GstSegment));
1531
1532 /* configure the segment with the seek variables */
1533 GST_DEBUG_OBJECT (qtdemux, "configuring seek");
1534 if (!gst_segment_do_seek (&seeksegment, rate, format, flags,
1535 cur_type, cur, stop_type, stop, &update)) {
1536 ret = FALSE;
1537 GST_ERROR_OBJECT (qtdemux, "inconsistent seek values, doing nothing");
1538 } else {
1539 /* now do the seek */
1540 ret = gst_qtdemux_perform_seek (qtdemux, &seeksegment, seqnum, flags);
1541 }
1542
1543 /* prepare for streaming again */
1544 if (flush) {
1545 flush_event = gst_event_new_flush_stop (TRUE);
1546 if (seqnum != GST_SEQNUM_INVALID)
1547 gst_event_set_seqnum (flush_event, seqnum);
1548
1549 gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event));
1550 gst_qtdemux_push_event (qtdemux, flush_event);
1551 }
1552
1553 /* commit the new segment */
1554 memcpy (&qtdemux->segment, &seeksegment, sizeof (GstSegment));
1555
1556 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
1557 GstMessage *msg = gst_message_new_segment_start (GST_OBJECT_CAST (qtdemux),
1558 qtdemux->segment.format, qtdemux->segment.position);
1559 if (seqnum != GST_SEQNUM_INVALID)
1560 gst_message_set_seqnum (msg, seqnum);
1561 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
1562 }
1563
1564 /* restart streaming, NEWSEGMENT will be sent from the streaming thread. */
1565 gst_pad_start_task (qtdemux->sinkpad, (GstTaskFunction) gst_qtdemux_loop,
1566 qtdemux->sinkpad, NULL);
1567
1568 GST_PAD_STREAM_UNLOCK (qtdemux->sinkpad);
1569
1570 return ret;
1571
1572 /* ERRORS */
1573no_format:
1574 {
1575 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1576 return FALSE;
1577 }
1578}
1579
1580static gboolean
1581qtdemux_ensure_index (GstQTDemux * qtdemux)
1582{
1583 guint i;
1584
1585 GST_DEBUG_OBJECT (qtdemux, "collecting all metadata for all streams");
1586
1587 /* Build complete index */
1588 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
1589 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
1590
1591 if (!qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
1592 GST_LOG_OBJECT (qtdemux,
1593 "Building complete index of track-id %u for seeking failed!",
1594 stream->track_id);
1595 return FALSE;
1596 }
1597 }
1598
1599 return TRUE;
1600}
1601
1602static gboolean
1603gst_qtdemux_handle_src_event (GstPad * pad, GstObject * parent,
1604 GstEvent * event)
1605{
1606 gboolean res = TRUE;
1607 GstQTDemux *qtdemux = GST_QTDEMUX (parent);
1608
1609 switch (GST_EVENT_TYPE (event)) {
1610 case GST_EVENT_RECONFIGURE:
1611 GST_OBJECT_LOCK (qtdemux);
1612 gst_flow_combiner_reset (qtdemux->flowcombiner);
1613 GST_OBJECT_UNLOCK (qtdemux);
1614 res = gst_pad_event_default (pad, parent, event);
1615 break;
1616 case GST_EVENT_SEEK:
1617 {
1618 GstSeekFlags flags = 0;
1619 GstFormat seek_format;
1620 gboolean instant_rate_change;
1621
1622#ifndef GST_DISABLE_GST_DEBUG
1623 GstClockTime ts = gst_util_get_timestamp ();
1624#endif
1625 guint32 seqnum = gst_event_get_seqnum (event);
1626
1627 qtdemux->received_seek = TRUE;
1628
1629 gst_event_parse_seek (event, NULL, &seek_format, &flags, NULL, NULL, NULL,
1630 NULL);
1631 instant_rate_change = ! !(flags & GST_SEEK_FLAG_INSTANT_RATE_CHANGE);
1632
1633 if (seqnum == qtdemux->segment_seqnum) {
1634 GST_LOG_OBJECT (pad,
1635 "Drop duplicated SEEK event seqnum %" G_GUINT32_FORMAT, seqnum);
1636 gst_event_unref (event);
1637 return TRUE;
1638 }
1639
1640 if (qtdemux->upstream_format_is_time && qtdemux->fragmented) {
1641 /* seek should be handled by upstream, we might need to re-download fragments */
1642 GST_DEBUG_OBJECT (qtdemux,
1643 "let upstream handle seek for fragmented playback");
1644 goto upstream;
1645 }
1646
1647 if (seek_format == GST_FORMAT_BYTES) {
1648 GST_DEBUG_OBJECT (pad, "Rejecting seek request in bytes format");
1649 gst_event_unref (event);
1650 return FALSE;
1651 }
1652
1653 gst_event_parse_seek_trickmode_interval (event,
1654 &qtdemux->trickmode_interval);
1655
1656 /* Build complete index for seeking;
1657 * if not a fragmented file at least and we're really doing a seek,
1658 * not just an instant-rate-change */
1659 if (!qtdemux->fragmented && !instant_rate_change) {
1660 if (!qtdemux_ensure_index (qtdemux))
1661 goto index_failed;
1662 }
1663#ifndef GST_DISABLE_GST_DEBUG
1664 ts = gst_util_get_timestamp () - ts;
1665 GST_INFO_OBJECT (qtdemux,
1666 "Time taken to parse index %" GST_TIME_FORMAT, GST_TIME_ARGS (ts));
1667#endif
1668 if (qtdemux->pullbased) {
1669 res = gst_qtdemux_do_seek (qtdemux, pad, event);
1670 } else if (gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (event))) {
1671 GST_DEBUG_OBJECT (qtdemux, "Upstream successfully seeked");
1672 res = TRUE;
1673 } else if (qtdemux->state == QTDEMUX_STATE_MOVIE
1674 && QTDEMUX_N_STREAMS (qtdemux)
1675 && !qtdemux->fragmented) {
1676 res = gst_qtdemux_do_push_seek (qtdemux, pad, event);
1677 } else {
1678 GST_DEBUG_OBJECT (qtdemux,
1679 "ignoring seek in push mode in current state");
1680 res = FALSE;
1681 }
1682 gst_event_unref (event);
1683 }
1684 break;
1685 default:
1686 upstream:
1687 res = gst_pad_event_default (pad, parent, event);
1688 break;
1689 }
1690
1691done:
1692 return res;
1693
1694 /* ERRORS */
1695index_failed:
1696 {
1697 GST_ERROR_OBJECT (qtdemux, "Index failed");
1698 gst_event_unref (event);
1699 res = FALSE;
1700 goto done;
1701 }
1702}
1703
1704/* Find, for each track, the first sample in coding order that has a file offset >= @byte_pos.
1705 *
1706 * If @fw is false, the coding order is explored backwards.
1707 *
1708 * If @set is true, each stream will be moved to its matched sample, or EOS if no matching
1709 * sample is found for that track.
1710 *
1711 * The stream and sample index of the sample with the minimum offset in the direction explored
1712 * (see @fw) is returned in the output parameters @_stream and @_index respectively.
1713 *
1714 * @_time is set to the QTSAMPLE_PTS of the matched sample with the minimum QTSAMPLE_PTS in the
1715 * direction explored, which may not always match the QTSAMPLE_PTS of the sample returned in
1716 * @_stream and @_index. */
1717static void
1718gst_qtdemux_find_sample (GstQTDemux * qtdemux, gint64 byte_pos, gboolean fw,
1719 gboolean set, QtDemuxStream ** _stream, gint * _index, gint64 * _time)
1720{
1721 gint i, index;
1722 gint64 time, min_time;
1723 QtDemuxStream *stream;
1724 gint iter;
1725
1726 min_time = -1;
1727 stream = NULL;
1728 index = -1;
1729
1730 for (iter = 0; iter < QTDEMUX_N_STREAMS (qtdemux); iter++) {
1731 QtDemuxStream *str;
1732 gint inc;
1733 gboolean set_sample;
1734
1735 str = QTDEMUX_NTH_STREAM (qtdemux, iter);
1736 set_sample = !set;
1737
1738 if (fw) {
1739 i = 0;
1740 inc = 1;
1741 } else {
1742 i = str->n_samples - 1;
1743 inc = -1;
1744 }
1745
1746 for (; (i >= 0) && (i < str->n_samples); i += inc) {
1747 if (str->samples[i].size == 0)
1748 continue;
1749
1750 if (fw && (str->samples[i].offset < byte_pos))
1751 continue;
1752
1753 if (!fw && (str->samples[i].offset + str->samples[i].size > byte_pos))
1754 continue;
1755
1756 /* move stream to first available sample */
1757 if (set) {
1758 gst_qtdemux_move_stream (qtdemux, str, i);
1759 set_sample = TRUE;
1760 }
1761
1762 /* avoid index from sparse streams since they might be far away */
1763 if (!CUR_STREAM (str)->sparse) {
1764 /* determine min/max time */
1765 time = QTSAMPLE_PTS (str, &str->samples[i]);
1766 if (min_time == -1 || (!fw && time > min_time) ||
1767 (fw && time < min_time)) {
1768 min_time = time;
1769 }
1770
1771 /* determine stream with leading sample, to get its position */
1772 if (!stream ||
1773 (fw && (str->samples[i].offset < stream->samples[index].offset)) ||
1774 (!fw && (str->samples[i].offset > stream->samples[index].offset))) {
1775 stream = str;
1776 index = i;
1777 }
1778 }
1779 break;
1780 }
1781
1782 /* no sample for this stream, mark eos */
1783 if (!set_sample)
1784 gst_qtdemux_move_stream (qtdemux, str, str->n_samples);
1785 }
1786
1787 if (_time)
1788 *_time = min_time;
1789 if (_stream)
1790 *_stream = stream;
1791 if (_index)
1792 *_index = index;
1793}
1794
1795/* Copied from mpegtsbase code */
1796/* FIXME: replace this function when we add new util function for stream-id creation */
1797static gchar *
1798_get_upstream_id (GstQTDemux * demux)
1799{
1800 gchar *upstream_id = gst_pad_get_stream_id (demux->sinkpad);
1801
1802 if (!upstream_id) {
1803 /* Try to create one from the upstream URI, else use a randome number */
1804 GstQuery *query;
1805 gchar *uri = NULL;
1806
1807 /* Try to generate one from the URI query and
1808 * if it fails take a random number instead */
1809 query = gst_query_new_uri ();
1810 if (gst_element_query (GST_ELEMENT_CAST (demux), query)) {
1811 gst_query_parse_uri (query, &uri);
1812 }
1813
1814 if (uri) {
1815 GChecksum *cs;
1816
1817 /* And then generate an SHA256 sum of the URI */
1818 cs = g_checksum_new (G_CHECKSUM_SHA256);
1819 g_checksum_update (cs, (const guchar *) uri, strlen (uri));
1820 g_free (uri);
1821 upstream_id = g_strdup (g_checksum_get_string (cs));
1822 g_checksum_free (cs);
1823 } else {
1824 /* Just get some random number if the URI query fails */
1825 GST_FIXME_OBJECT (demux, "Creating random stream-id, consider "
1826 "implementing a deterministic way of creating a stream-id");
1827 upstream_id =
1828 g_strdup_printf ("%08x%08x%08x%08x", g_random_int (), g_random_int (),
1829 g_random_int (), g_random_int ());
1830 }
1831
1832 gst_query_unref (query);
1833 }
1834 return upstream_id;
1835}
1836
1837static QtDemuxStream *
1838_create_stream (GstQTDemux * demux, guint32 track_id)
1839{
1840 QtDemuxStream *stream;
1841 gchar *upstream_id;
1842
1843 stream = g_new0 (QtDemuxStream, 1);
1844 stream->demux = demux;
1845 stream->track_id = track_id;
1846 upstream_id = _get_upstream_id (demux);
1847 stream->stream_id = g_strdup_printf ("%s/%03u", upstream_id, track_id);
1848 g_free (upstream_id);
1849 /* new streams always need a discont */
1850 stream->discont = TRUE;
1851 /* we enable clipping for raw audio/video streams */
1852 stream->need_clip = FALSE;
1853 stream->process_func = NULL;
1854 stream->segment_index = -1;
1855 stream->time_position = 0;
1856 stream->sample_index = -1;
1857 stream->offset_in_sample = 0;
1858 stream->new_stream = TRUE;
1859 stream->multiview_mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
1860 stream->multiview_flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
1861 stream->protected = FALSE;
1862 stream->protection_scheme_type = 0;
1863 stream->protection_scheme_version = 0;
1864 stream->protection_scheme_info = NULL;
1865 stream->n_samples_moof = 0;
1866 stream->duration_moof = 0;
1867 stream->duration_last_moof = 0;
1868 stream->alignment = 1;
1869 stream->stream_tags = gst_tag_list_new_empty ();
1870 gst_tag_list_set_scope (stream->stream_tags, GST_TAG_SCOPE_STREAM);
1871 g_queue_init (&stream->protection_scheme_event_queue);
1872 stream->ref_count = 1;
1873 /* consistent default for push based mode */
1874 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
1875 return stream;
1876}
1877
1878static gboolean
1879gst_qtdemux_setcaps (GstQTDemux * demux, GstCaps * caps)
1880{
1881 GstStructure *structure;
1882 const gchar *variant;
1883 const GstCaps *mediacaps = NULL;
1884
1885 GST_DEBUG_OBJECT (demux, "Sink set caps: %" GST_PTR_FORMAT, caps);
1886
1887 structure = gst_caps_get_structure (caps, 0);
1888 variant = gst_structure_get_string (structure, "variant");
1889
1890 if (variant && strcmp (variant, "mse-bytestream") == 0) {
1891 demux->variant = VARIANT_MSE_BYTESTREAM;
1892 }
1893
1894 if (variant && strcmp (variant, "mss-fragmented") == 0) {
1895 QtDemuxStream *stream;
1896 const GValue *value;
1897
1898 demux->fragmented = TRUE;
1899 demux->variant = VARIANT_MSS_FRAGMENTED;
1900
1901 if (QTDEMUX_N_STREAMS (demux) > 1) {
1902 /* can't do this, we can only renegotiate for another mss format */
1903 return FALSE;
1904 }
1905
1906 value = gst_structure_get_value (structure, "media-caps");
1907 /* create stream */
1908 if (value) {
1909 const GValue *timescale_v;
1910
1911 /* TODO update when stream changes during playback */
1912
1913 if (QTDEMUX_N_STREAMS (demux) == 0) {
1914 stream = _create_stream (demux, 1);
1915 g_ptr_array_add (demux->active_streams, stream);
1916 /* mss has no stsd/stsd entry, use id 0 as default */
1917 stream->stsd_entries_length = 1;
1918 stream->stsd_sample_description_id = stream->cur_stsd_entry_index = 0;
1919 stream->stsd_entries = g_new0 (QtDemuxStreamStsdEntry, 1);
1920 } else {
1921 stream = QTDEMUX_NTH_STREAM (demux, 0);
1922 }
1923
1924 timescale_v = gst_structure_get_value (structure, "timescale");
1925 if (timescale_v) {
1926 stream->timescale = g_value_get_uint64 (timescale_v);
1927 } else {
1928 /* default mss timescale */
1929 stream->timescale = 10000000;
1930 }
1931 demux->timescale = stream->timescale;
1932
1933 mediacaps = gst_value_get_caps (value);
1934 if (!CUR_STREAM (stream)->caps
1935 || !gst_caps_is_equal_fixed (mediacaps, CUR_STREAM (stream)->caps)) {
1936 GST_DEBUG_OBJECT (demux, "We have a new caps %" GST_PTR_FORMAT,
1937 mediacaps);
1938 stream->new_caps = TRUE;
1939 }
1940 gst_caps_replace (&CUR_STREAM (stream)->caps, (GstCaps *) mediacaps);
1941 structure = gst_caps_get_structure (mediacaps, 0);
1942 if (g_str_has_prefix (gst_structure_get_name (structure), "video")) {
1943 stream->subtype = FOURCC_vide;
1944
1945 gst_structure_get_int (structure, "width", &CUR_STREAM (stream)->width);
1946 gst_structure_get_int (structure, "height",
1947 &CUR_STREAM (stream)->height);
1948 gst_structure_get_fraction (structure, "framerate",
1949 &CUR_STREAM (stream)->fps_n, &CUR_STREAM (stream)->fps_d);
1950 } else if (g_str_has_prefix (gst_structure_get_name (structure), "audio")) {
1951 gint rate = 0;
1952 stream->subtype = FOURCC_soun;
1953 gst_structure_get_int (structure, "channels",
1954 &CUR_STREAM (stream)->n_channels);
1955 gst_structure_get_int (structure, "rate", &rate);
1956 CUR_STREAM (stream)->rate = rate;
1957 } else if (gst_structure_has_name (structure, "application/x-cenc")) {
1958 if (gst_structure_has_field (structure, "original-media-type")) {
1959 const gchar *media_type =
1960 gst_structure_get_string (structure, "original-media-type");
1961 if (g_str_has_prefix (media_type, "video")) {
1962 stream->subtype = FOURCC_vide;
1963 } else if (g_str_has_prefix (media_type, "audio")) {
1964 stream->subtype = FOURCC_soun;
1965 }
1966 }
1967 }
1968 }
1969 gst_caps_replace (&demux->media_caps, (GstCaps *) mediacaps);
1970 }
1971
1972 return TRUE;
1973}
1974
1975static void
1976gst_qtdemux_reset (GstQTDemux * qtdemux, gboolean hard)
1977{
1978 gint i;
1979
1980 GST_DEBUG_OBJECT (qtdemux, "Resetting demux");
1981 gst_pad_stop_task (qtdemux->sinkpad);
1982
1983 if (hard || qtdemux->upstream_format_is_time) {
1984 qtdemux->state = QTDEMUX_STATE_INITIAL;
1985 qtdemux->neededbytes = 16;
1986 qtdemux->todrop = 0;
1987 qtdemux->pullbased = FALSE;
1988 g_clear_pointer (&qtdemux->redirect_location, g_free);
1989 qtdemux->first_mdat = -1;
1990 qtdemux->header_size = 0;
1991 qtdemux->mdatoffset = -1;
1992 qtdemux->restoredata_offset = -1;
1993 if (qtdemux->mdatbuffer)
1994 gst_buffer_unref (qtdemux->mdatbuffer);
1995 if (qtdemux->restoredata_buffer)
1996 gst_buffer_unref (qtdemux->restoredata_buffer);
1997 qtdemux->mdatbuffer = NULL;
1998 qtdemux->restoredata_buffer = NULL;
1999 qtdemux->mdatleft = 0;
2000 qtdemux->mdatsize = 0;
2001 if (qtdemux->comp_brands)
2002 gst_buffer_unref (qtdemux->comp_brands);
2003 qtdemux->comp_brands = NULL;
2004 qtdemux->last_moov_offset = -1;
2005 if (qtdemux->moov_node_compressed) {
2006 g_node_destroy (qtdemux->moov_node_compressed);
2007 if (qtdemux->moov_node)
2008 g_free (qtdemux->moov_node->data);
2009 }
2010 qtdemux->moov_node_compressed = NULL;
2011 if (qtdemux->moov_node)
2012 g_node_destroy (qtdemux->moov_node);
2013 qtdemux->moov_node = NULL;
2014 if (qtdemux->tag_list)
2015 gst_mini_object_unref (GST_MINI_OBJECT_CAST (qtdemux->tag_list));
2016 qtdemux->tag_list = gst_tag_list_new_empty ();
2017 gst_tag_list_set_scope (qtdemux->tag_list, GST_TAG_SCOPE_GLOBAL);
2018#if 0
2019 if (qtdemux->element_index)
2020 gst_object_unref (qtdemux->element_index);
2021 qtdemux->element_index = NULL;
2022#endif
2023 qtdemux->major_brand = 0;
2024 qtdemux->upstream_format_is_time = FALSE;
2025 qtdemux->upstream_seekable = FALSE;
2026 qtdemux->upstream_size = 0;
2027
2028 qtdemux->fragment_start = -1;
2029 qtdemux->fragment_start_offset = -1;
2030 qtdemux->duration = 0;
2031 qtdemux->moof_offset = 0;
2032 qtdemux->chapters_track_id = 0;
2033 qtdemux->have_group_id = FALSE;
2034 qtdemux->group_id = G_MAXUINT;
2035
2036 g_queue_foreach (&qtdemux->protection_event_queue, (GFunc) gst_event_unref,
2037 NULL);
2038 g_queue_clear (&qtdemux->protection_event_queue);
2039
2040 qtdemux->received_seek = FALSE;
2041 qtdemux->first_moof_already_parsed = FALSE;
2042 }
2043 qtdemux->offset = 0;
2044 gst_adapter_clear (qtdemux->adapter);
2045 gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
2046 qtdemux->need_segment = TRUE;
2047
2048 if (hard) {
2049 qtdemux->segment_seqnum = GST_SEQNUM_INVALID;
2050 qtdemux->trickmode_interval = 0;
2051 g_ptr_array_set_size (qtdemux->active_streams, 0);
2052 g_ptr_array_set_size (qtdemux->old_streams, 0);
2053 qtdemux->n_video_streams = 0;
2054 qtdemux->n_audio_streams = 0;
2055 qtdemux->n_sub_streams = 0;
2056 qtdemux->exposed = FALSE;
2057 qtdemux->fragmented = FALSE;
2058 qtdemux->variant = VARIANT_NONE;
2059 gst_caps_replace (&qtdemux->media_caps, NULL);
2060 qtdemux->timescale = 0;
2061 qtdemux->got_moov = FALSE;
2062 qtdemux->cenc_aux_info_offset = 0;
2063 qtdemux->cenc_aux_info_sizes = NULL;
2064 qtdemux->cenc_aux_sample_count = 0;
2065 if (qtdemux->protection_system_ids) {
2066 g_ptr_array_free (qtdemux->protection_system_ids, TRUE);
2067 qtdemux->protection_system_ids = NULL;
2068 }
2069 qtdemux->streams_aware = GST_OBJECT_PARENT (qtdemux)
2070 && GST_OBJECT_FLAG_IS_SET (GST_OBJECT_PARENT (qtdemux),
2071 GST_BIN_FLAG_STREAMS_AWARE);
2072
2073 if (qtdemux->preferred_protection_system_id) {
2074 g_free (qtdemux->preferred_protection_system_id);
2075 qtdemux->preferred_protection_system_id = NULL;
2076 }
2077 } else if (qtdemux->variant == VARIANT_MSS_FRAGMENTED) {
2078 gst_flow_combiner_reset (qtdemux->flowcombiner);
2079 g_ptr_array_foreach (qtdemux->active_streams,
2080 (GFunc) gst_qtdemux_stream_clear, NULL);
2081 } else {
2082 gst_flow_combiner_reset (qtdemux->flowcombiner);
2083 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
2084 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
2085 stream->sent_eos = FALSE;
2086 stream->time_position = 0;
2087 stream->accumulated_base = 0;
2088 stream->last_keyframe_dts = GST_CLOCK_TIME_NONE;
2089 }
2090 }
2091}
2092
2093
2094/* Maps the @segment to the qt edts internal segments and pushes
2095 * the corresponding segment event.
2096 *
2097 * If it ends up being at a empty segment, a gap will be pushed and the next
2098 * edts segment will be activated in sequence.
2099 *
2100 * To be used in push-mode only */
2101static void
2102gst_qtdemux_map_and_push_segments (GstQTDemux * qtdemux, GstSegment * segment)
2103{
2104 gint i, iter;
2105
2106 for (iter = 0; iter < QTDEMUX_N_STREAMS (qtdemux); iter++) {
2107 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, iter);
2108
2109 stream->time_position = segment->start;
2110
2111 /* in push mode we should be guaranteed that we will have empty segments
2112 * at the beginning and then one segment after, other scenarios are not
2113 * supported and are discarded when parsing the edts */
2114 for (i = 0; i < stream->n_segments; i++) {
2115 if (stream->segments[i].stop_time > segment->start) {
2116 /* push the empty segment and move to the next one */
2117 gst_qtdemux_activate_segment (qtdemux, stream, i,
2118 stream->time_position);
2119 if (QTSEGMENT_IS_EMPTY (&stream->segments[i])) {
2120 gst_qtdemux_send_gap_for_segment (qtdemux, stream, i,
2121 stream->time_position);
2122
2123 /* accumulate previous segments */
2124 if (GST_CLOCK_TIME_IS_VALID (stream->segment.stop))
2125 stream->accumulated_base +=
2126 (stream->segment.stop -
2127 stream->segment.start) / ABS (stream->segment.rate);
2128 continue;
2129 }
2130
2131 g_assert (i == stream->n_segments - 1);
2132 }
2133 }
2134 }
2135}
2136
2137static void
2138gst_qtdemux_stream_concat (GstQTDemux * qtdemux, GPtrArray * dest,
2139 GPtrArray * src)
2140{
2141 guint i;
2142 guint len;
2143
2144 len = src->len;
2145
2146 if (len == 0)
2147 return;
2148
2149 for (i = 0; i < len; i++) {
2150 QtDemuxStream *stream = g_ptr_array_index (src, i);
2151
2152#ifndef GST_DISABLE_GST_DEBUG
2153 GST_DEBUG_OBJECT (qtdemux, "Move stream %p (stream-id %s) to %p",
2154 stream, GST_STR_NULL (stream->stream_id), dest);
2155#endif
2156 g_ptr_array_add (dest, gst_qtdemux_stream_ref (stream));
2157 }
2158
2159 g_ptr_array_set_size (src, 0);
2160}
2161
2162static gboolean
2163gst_qtdemux_handle_sink_event (GstPad * sinkpad, GstObject * parent,
2164 GstEvent * event)
2165{
2166 GstQTDemux *demux = GST_QTDEMUX (parent);
2167 gboolean res = TRUE;
2168
2169 GST_LOG_OBJECT (demux, "handling %s event", GST_EVENT_TYPE_NAME (event));
2170
2171 switch (GST_EVENT_TYPE (event)) {
2172 case GST_EVENT_SEGMENT:
2173 {
2174 gint64 offset = 0;
2175 QtDemuxStream *stream;
2176 gint idx;
2177 GstSegment segment;
2178
2179 /* some debug output */
2180 gst_event_copy_segment (event, &segment);
2181 GST_DEBUG_OBJECT (demux, "received newsegment %" GST_SEGMENT_FORMAT,
2182 &segment);
2183
2184 if (segment.format == GST_FORMAT_TIME) {
2185 demux->upstream_format_is_time = TRUE;
2186 demux->segment_seqnum = gst_event_get_seqnum (event);
2187 } else {
2188 GST_DEBUG_OBJECT (demux, "Not storing upstream newsegment, "
2189 "not in time format");
2190
2191 /* chain will send initial newsegment after pads have been added */
2192 if (demux->state != QTDEMUX_STATE_MOVIE || !QTDEMUX_N_STREAMS (demux)) {
2193 GST_DEBUG_OBJECT (demux, "still starting, eating event");
2194 goto exit;
2195 }
2196 }
2197
2198 /* check if this matches a time seek we received previously
2199 * FIXME for backwards compatibility reasons we use the
2200 * seek_offset here to compare. In the future we might want to
2201 * change this to use the seqnum as it uniquely should identify
2202 * the segment that corresponds to the seek. */
2203 GST_DEBUG_OBJECT (demux, "Stored seek offset: %" G_GINT64_FORMAT
2204 ", received segment offset %" G_GINT64_FORMAT,
2205 demux->seek_offset, segment.start);
2206 if (segment.format == GST_FORMAT_BYTES
2207 && demux->seek_offset == segment.start) {
2208 GST_OBJECT_LOCK (demux);
2209 offset = segment.start;
2210
2211 segment.format = GST_FORMAT_TIME;
2212 segment.start = demux->push_seek_start;
2213 segment.stop = demux->push_seek_stop;
2214 GST_DEBUG_OBJECT (demux, "Replaced segment with stored seek "
2215 "segment %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT,
2216 GST_TIME_ARGS (segment.start), GST_TIME_ARGS (segment.stop));
2217 GST_OBJECT_UNLOCK (demux);
2218 }
2219
2220 /* we only expect a BYTE segment, e.g. following a seek */
2221 if (segment.format == GST_FORMAT_BYTES) {
2222 if (GST_CLOCK_TIME_IS_VALID (segment.start)) {
2223 offset = segment.start;
2224
2225 gst_qtdemux_find_sample (demux, segment.start, TRUE, FALSE, NULL,
2226 NULL, (gint64 *) & segment.start);
2227 if ((gint64) segment.start < 0)
2228 segment.start = 0;
2229 }
2230 if (GST_CLOCK_TIME_IS_VALID (segment.stop)) {
2231 gst_qtdemux_find_sample (demux, segment.stop, FALSE, FALSE, NULL,
2232 NULL, (gint64 *) & segment.stop);
2233 /* keyframe seeking should already arrange for start >= stop,
2234 * but make sure in other rare cases */
2235 segment.stop = MAX (segment.stop, segment.start);
2236 }
2237 } else if (segment.format == GST_FORMAT_TIME) {
2238 /* push all data on the adapter before starting this
2239 * new segment */
2240 gst_qtdemux_process_adapter (demux, TRUE);
2241 } else {
2242 GST_DEBUG_OBJECT (demux, "unsupported segment format, ignoring");
2243 goto exit;
2244 }
2245
2246 /* We shouldn't modify upstream driven TIME FORMAT segment */
2247 if (!demux->upstream_format_is_time) {
2248 /* accept upstream's notion of segment and distribute along */
2249 segment.format = GST_FORMAT_TIME;
2250 segment.position = segment.time = segment.start;
2251 segment.duration = demux->segment.duration;
2252 segment.base = gst_segment_to_running_time (&demux->segment,
2253 GST_FORMAT_TIME, demux->segment.position);
2254 }
2255
2256 gst_segment_copy_into (&segment, &demux->segment);
2257 GST_DEBUG_OBJECT (demux, "Pushing newseg %" GST_SEGMENT_FORMAT, &segment);
2258
2259 /* map segment to internal qt segments and push on each stream */
2260 if (QTDEMUX_N_STREAMS (demux)) {
2261 demux->need_segment = TRUE;
2262 gst_qtdemux_check_send_pending_segment (demux);
2263 }
2264
2265 /* clear leftover in current segment, if any */
2266 gst_adapter_clear (demux->adapter);
2267
2268 /* set up streaming thread */
2269 demux->offset = offset;
2270 if (demux->upstream_format_is_time) {
2271 GST_DEBUG_OBJECT (demux, "Upstream is driving in time format, "
2272 "set values to restart reading from a new atom");
2273 demux->neededbytes = 16;
2274 demux->todrop = 0;
2275 } else {
2276 gst_qtdemux_find_sample (demux, offset, TRUE, TRUE, &stream, &idx,
2277 NULL);
2278 if (stream) {
2279 demux->todrop = stream->samples[idx].offset - offset;
2280 demux->neededbytes = demux->todrop + stream->samples[idx].size;
2281 } else {
2282 /* set up for EOS */
2283 demux->neededbytes = -1;
2284 demux->todrop = 0;
2285 }
2286 }
2287 exit:
2288 gst_event_unref (event);
2289 res = TRUE;
2290 goto drop;
2291 }
2292 case GST_EVENT_FLUSH_START:
2293 {
2294 if (gst_event_get_seqnum (event) == demux->offset_seek_seqnum) {
2295 gst_event_unref (event);
2296 goto drop;
2297 }
2298 QTDEMUX_EXPOSE_LOCK (demux);
2299 res = gst_pad_event_default (demux->sinkpad, parent, event);
2300 QTDEMUX_EXPOSE_UNLOCK (demux);
2301 goto drop;
2302 }
2303 case GST_EVENT_FLUSH_STOP:
2304 {
2305 guint64 dur;
2306
2307 dur = demux->segment.duration;
2308 gst_qtdemux_reset (demux, FALSE);
2309 demux->segment.duration = dur;
2310
2311 if (gst_event_get_seqnum (event) == demux->offset_seek_seqnum) {
2312 gst_event_unref (event);
2313 goto drop;
2314 }
2315 break;
2316 }
2317 case GST_EVENT_EOS:
2318 /* If we are in push mode, and get an EOS before we've seen any streams,
2319 * then error out - we have nowhere to send the EOS */
2320 if (!demux->pullbased) {
2321 gint i;
2322 gboolean has_valid_stream = FALSE;
2323 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
2324 if (QTDEMUX_NTH_STREAM (demux, i)->pad != NULL) {
2325 has_valid_stream = TRUE;
2326 break;
2327 }
2328 }
2329 if (!has_valid_stream)
2330 gst_qtdemux_post_no_playable_stream_error (demux);
2331 else {
2332 GST_DEBUG_OBJECT (demux, "Data still available after EOS: %u",
2333 (guint) gst_adapter_available (demux->adapter));
2334 if (gst_qtdemux_process_adapter (demux, TRUE) != GST_FLOW_OK) {
2335 res = FALSE;
2336 }
2337 }
2338 }
2339 break;
2340 case GST_EVENT_CAPS:{
2341 GstCaps *caps = NULL;
2342
2343 gst_event_parse_caps (event, &caps);
2344 gst_qtdemux_setcaps (demux, caps);
2345 res = TRUE;
2346 gst_event_unref (event);
2347 goto drop;
2348 }
2349 case GST_EVENT_PROTECTION:
2350 {
2351 const gchar *system_id = NULL;
2352
2353 gst_event_parse_protection (event, &system_id, NULL, NULL);
2354 GST_DEBUG_OBJECT (demux, "Received protection event for system ID %s",
2355 system_id);
2356 gst_qtdemux_append_protection_system_id (demux, system_id);
2357 /* save the event for later, for source pads that have not been created */
2358 g_queue_push_tail (&demux->protection_event_queue, gst_event_ref (event));
2359 /* send it to all pads that already exist */
2360 gst_qtdemux_push_event (demux, event);
2361 res = TRUE;
2362 goto drop;
2363 }
2364 case GST_EVENT_STREAM_START:
2365 {
2366 res = TRUE;
2367 gst_event_unref (event);
2368
2369 /* Drain all the buffers */
2370 gst_qtdemux_process_adapter (demux, TRUE);
2371 gst_qtdemux_reset (demux, FALSE);
2372 /* We expect new moov box after new stream-start event */
2373 if (demux->exposed) {
2374 gst_qtdemux_stream_concat (demux,
2375 demux->old_streams, demux->active_streams);
2376 }
2377
2378 goto drop;
2379 }
2380 default:
2381 break;
2382 }
2383
2384 res = gst_pad_event_default (demux->sinkpad, parent, event) & res;
2385
2386drop:
2387 return res;
2388}
2389
2390static gboolean
2391gst_qtdemux_handle_sink_query (GstPad * pad, GstObject * parent,
2392 GstQuery * query)
2393{
2394 GstQTDemux *demux = GST_QTDEMUX (parent);
2395 gboolean res = FALSE;
2396
2397 switch (GST_QUERY_TYPE (query)) {
2398 case GST_QUERY_BITRATE:
2399 {
2400 GstClockTime duration;
2401
2402 /* populate demux->upstream_size if not done yet */
2403 gst_qtdemux_check_seekability (demux);
2404
2405 if (demux->upstream_size != -1
2406 && gst_qtdemux_get_duration (demux, &duration)) {
2407 guint bitrate =
2408 gst_util_uint64_scale (8 * demux->upstream_size, GST_SECOND,
2409 duration);
2410
2411 GST_LOG_OBJECT (demux, "bitrate query byte length: %" G_GUINT64_FORMAT
2412 " duration %" GST_TIME_FORMAT " resulting a bitrate of %u",
2413 demux->upstream_size, GST_TIME_ARGS (duration), bitrate);
2414
2415 /* TODO: better results based on ranges/index tables */
2416 gst_query_set_bitrate (query, bitrate);
2417 res = TRUE;
2418 }
2419 break;
2420 }
2421 default:
2422 res = gst_pad_query_default (pad, (GstObject *) demux, query);
2423 break;
2424 }
2425
2426 return res;
2427}
2428
2429
2430#if 0
2431static void
2432gst_qtdemux_set_index (GstElement * element, GstIndex * index)
2433{
2434 GstQTDemux *demux = GST_QTDEMUX (element);
2435
2436 GST_OBJECT_LOCK (demux);
2437 if (demux->element_index)
2438 gst_object_unref (demux->element_index);
2439 if (index) {
2440 demux->element_index = gst_object_ref (index);
2441 } else {
2442 demux->element_index = NULL;
2443 }
2444 GST_OBJECT_UNLOCK (demux);
2445 /* object lock might be taken again */
2446 if (index)
2447 gst_index_get_writer_id (index, GST_OBJECT (element), &demux->index_id);
2448 GST_DEBUG_OBJECT (demux, "Set index %" GST_PTR_FORMAT "for writer id %d",
2449 demux->element_index, demux->index_id);
2450}
2451
2452static GstIndex *
2453gst_qtdemux_get_index (GstElement * element)
2454{
2455 GstIndex *result = NULL;
2456 GstQTDemux *demux = GST_QTDEMUX (element);
2457
2458 GST_OBJECT_LOCK (demux);
2459 if (demux->element_index)
2460 result = gst_object_ref (demux->element_index);
2461 GST_OBJECT_UNLOCK (demux);
2462
2463 GST_DEBUG_OBJECT (demux, "Returning index %" GST_PTR_FORMAT, result);
2464
2465 return result;
2466}
2467#endif
2468
2469static void
2470gst_qtdemux_stbl_free (QtDemuxStream * stream)
2471{
2472 g_free ((gpointer) stream->stco.data);
2473 stream->stco.data = NULL;
2474 g_free ((gpointer) stream->stsz.data);
2475 stream->stsz.data = NULL;
2476 g_free ((gpointer) stream->stsc.data);
2477 stream->stsc.data = NULL;
2478 g_free ((gpointer) stream->stts.data);
2479 stream->stts.data = NULL;
2480 g_free ((gpointer) stream->stss.data);
2481 stream->stss.data = NULL;
2482 g_free ((gpointer) stream->stps.data);
2483 stream->stps.data = NULL;
2484 g_free ((gpointer) stream->ctts.data);
2485 stream->ctts.data = NULL;
2486}
2487
2488static void
2489gst_qtdemux_stream_flush_segments_data (QtDemuxStream * stream)
2490{
2491 g_free (stream->segments);
2492 stream->segments = NULL;
2493 stream->segment_index = -1;
2494 stream->accumulated_base = 0;
2495}
2496
2497static void
2498gst_qtdemux_stream_flush_samples_data (QtDemuxStream * stream)
2499{
2500 g_free (stream->samples);
2501 stream->samples = NULL;
2502 gst_qtdemux_stbl_free (stream);
2503
2504 /* fragments */
2505 g_free (stream->ra_entries);
2506 stream->ra_entries = NULL;
2507 stream->n_ra_entries = 0;
2508
2509 stream->sample_index = -1;
2510 stream->stbl_index = -1;
2511 stream->n_samples = 0;
2512 stream->time_position = 0;
2513
2514 stream->n_samples_moof = 0;
2515 stream->duration_moof = 0;
2516 stream->duration_last_moof = 0;
2517}
2518
2519static void
2520gst_qtdemux_stream_clear (QtDemuxStream * stream)
2521{
2522 gint i;
2523 if (stream->allocator)
2524 gst_object_unref (stream->allocator);
2525 while (stream->buffers) {
2526 gst_buffer_unref (GST_BUFFER_CAST (stream->buffers->data));
2527 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
2528 }
2529 for (i = 0; i < stream->stsd_entries_length; i++) {
2530 QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[i];
2531 if (entry->rgb8_palette) {
2532 gst_memory_unref (entry->rgb8_palette);
2533 entry->rgb8_palette = NULL;
2534 }
2535 entry->sparse = FALSE;
2536 }
2537
2538 if (stream->stream_tags)
2539 gst_tag_list_unref (stream->stream_tags);
2540
2541 stream->stream_tags = gst_tag_list_new_empty ();
2542 gst_tag_list_set_scope (stream->stream_tags, GST_TAG_SCOPE_STREAM);
2543 g_free (stream->redirect_uri);
2544 stream->redirect_uri = NULL;
2545 stream->sent_eos = FALSE;
2546 stream->protected = FALSE;
2547 if (stream->protection_scheme_info) {
2548 if (stream->protection_scheme_type == FOURCC_cenc
2549 || stream->protection_scheme_type == FOURCC_cbcs) {
2550 QtDemuxCencSampleSetInfo *info =
2551 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
2552 if (info->default_properties)
2553 gst_structure_free (info->default_properties);
2554 if (info->crypto_info)
2555 g_ptr_array_free (info->crypto_info, TRUE);
2556 }
2557 if (stream->protection_scheme_type == FOURCC_aavd) {
2558 QtDemuxAavdEncryptionInfo *info =
2559 (QtDemuxAavdEncryptionInfo *) stream->protection_scheme_info;
2560 if (info->default_properties)
2561 gst_structure_free (info->default_properties);
2562 }
2563 g_free (stream->protection_scheme_info);
2564 stream->protection_scheme_info = NULL;
2565 }
2566 stream->protection_scheme_type = 0;
2567 stream->protection_scheme_version = 0;
2568 g_queue_foreach (&stream->protection_scheme_event_queue,
2569 (GFunc) gst_event_unref, NULL);
2570 g_queue_clear (&stream->protection_scheme_event_queue);
2571 gst_qtdemux_stream_flush_segments_data (stream);
2572 gst_qtdemux_stream_flush_samples_data (stream);
2573}
2574
2575static void
2576gst_qtdemux_stream_reset (QtDemuxStream * stream)
2577{
2578 gint i;
2579 gst_qtdemux_stream_clear (stream);
2580 for (i = 0; i < stream->stsd_entries_length; i++) {
2581 QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[i];
2582 if (entry->caps) {
2583 gst_caps_unref (entry->caps);
2584 entry->caps = NULL;
2585 }
2586 }
2587 g_free (stream->stsd_entries);
2588 stream->stsd_entries = NULL;
2589 stream->stsd_entries_length = 0;
2590}
2591
2592static QtDemuxStream *
2593gst_qtdemux_stream_ref (QtDemuxStream * stream)
2594{
2595 g_atomic_int_add (&stream->ref_count, 1);
2596
2597 return stream;
2598}
2599
2600static void
2601gst_qtdemux_stream_unref (QtDemuxStream * stream)
2602{
2603 if (g_atomic_int_dec_and_test (&stream->ref_count)) {
2604 gst_qtdemux_stream_reset (stream);
2605 gst_tag_list_unref (stream->stream_tags);
2606 if (stream->pad) {
2607 GstQTDemux *demux = stream->demux;
2608 gst_element_remove_pad (GST_ELEMENT_CAST (demux), stream->pad);
2609 GST_OBJECT_LOCK (demux);
2610 gst_flow_combiner_remove_pad (demux->flowcombiner, stream->pad);
2611 GST_OBJECT_UNLOCK (demux);
2612 }
2613 g_free (stream->stream_id);
2614 g_free (stream);
2615 }
2616}
2617
2618static GstStateChangeReturn
2619gst_qtdemux_change_state (GstElement * element, GstStateChange transition)
2620{
2621 GstQTDemux *qtdemux = GST_QTDEMUX (element);
2622 GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
2623
2624 switch (transition) {
2625 case GST_STATE_CHANGE_READY_TO_PAUSED:
2626 gst_qtdemux_reset (qtdemux, TRUE);
2627 break;
2628 default:
2629 break;
2630 }
2631
2632 result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
2633
2634 switch (transition) {
2635 case GST_STATE_CHANGE_PAUSED_TO_READY:{
2636 gst_qtdemux_reset (qtdemux, TRUE);
2637 break;
2638 }
2639 default:
2640 break;
2641 }
2642
2643 return result;
2644}
2645
2646static void
2647gst_qtdemux_set_context (GstElement * element, GstContext * context)
2648{
2649 GstQTDemux *qtdemux = GST_QTDEMUX (element);
2650
2651 g_return_if_fail (GST_IS_CONTEXT (context));
2652
2653 if (gst_context_has_context_type (context,
2654 "drm-preferred-decryption-system-id")) {
2655 const GstStructure *s;
2656
2657 s = gst_context_get_structure (context);
2658 g_free (qtdemux->preferred_protection_system_id);
2659 qtdemux->preferred_protection_system_id =
2660 g_strdup (gst_structure_get_string (s, "decryption-system-id"));
2661 GST_DEBUG_OBJECT (element, "set preferred decryption system to %s",
2662 qtdemux->preferred_protection_system_id);
2663 }
2664
2665 GST_ELEMENT_CLASS (parent_class)->set_context (element, context);
2666}
2667
2668static void
2669qtdemux_parse_ftyp (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2670{
2671 /* counts as header data */
2672 qtdemux->header_size += length;
2673
2674 /* only consider at least a sufficiently complete ftyp atom */
2675 if (length >= 20) {
2676 GstBuffer *buf;
2677
2678 qtdemux->major_brand = QT_FOURCC (buffer + 8);
2679 GST_DEBUG_OBJECT (qtdemux, "major brand: %" GST_FOURCC_FORMAT,
2680 GST_FOURCC_ARGS (qtdemux->major_brand));
2681 if (qtdemux->comp_brands)
2682 gst_buffer_unref (qtdemux->comp_brands);
2683 buf = qtdemux->comp_brands = gst_buffer_new_and_alloc (length - 16);
2684 gst_buffer_fill (buf, 0, buffer + 16, length - 16);
2685 }
2686}
2687
2688static void
2689qtdemux_update_default_sample_cenc_settings (GstQTDemux * qtdemux,
2690 QtDemuxCencSampleSetInfo * info, guint32 is_encrypted,
2691 guint32 protection_scheme_type, guint8 iv_size, const guint8 * kid,
2692 guint crypt_byte_block, guint skip_byte_block, guint8 constant_iv_size,
2693 const guint8 * constant_iv)
2694{
2695 GstBuffer *kid_buf = gst_buffer_new_allocate (NULL, 16, NULL);
2696 gst_buffer_fill (kid_buf, 0, kid, 16);
2697 if (info->default_properties)
2698 gst_structure_free (info->default_properties);
2699 info->default_properties =
2700 gst_structure_new ("application/x-cenc",
2701 "iv_size", G_TYPE_UINT, iv_size,
2702 "encrypted", G_TYPE_BOOLEAN, (is_encrypted == 1),
2703 "kid", GST_TYPE_BUFFER, kid_buf, NULL);
2704 GST_DEBUG_OBJECT (qtdemux, "default sample properties: "
2705 "is_encrypted=%u, iv_size=%u", is_encrypted, iv_size);
2706 gst_buffer_unref (kid_buf);
2707 if (protection_scheme_type == FOURCC_cbcs) {
2708 if (crypt_byte_block != 0 || skip_byte_block != 0) {
2709 gst_structure_set (info->default_properties, "crypt_byte_block",
2710 G_TYPE_UINT, crypt_byte_block, "skip_byte_block", G_TYPE_UINT,
2711 skip_byte_block, NULL);
2712 }
2713 if (constant_iv != NULL) {
2714 GstBuffer *constant_iv_buf =
2715 gst_buffer_new_allocate (NULL, constant_iv_size, NULL);
2716 gst_buffer_fill (constant_iv_buf, 0, constant_iv, constant_iv_size);
2717 gst_structure_set (info->default_properties, "constant_iv_size",
2718 G_TYPE_UINT, constant_iv_size, "iv", GST_TYPE_BUFFER, constant_iv_buf,
2719 NULL);
2720 gst_buffer_unref (constant_iv_buf);
2721 }
2722 gst_structure_set (info->default_properties, "cipher-mode",
2723 G_TYPE_STRING, "cbcs", NULL);
2724 } else {
2725 gst_structure_set (info->default_properties, "cipher-mode",
2726 G_TYPE_STRING, "cenc", NULL);
2727 }
2728}
2729
2730static gboolean
2731qtdemux_update_default_piff_encryption_settings (GstQTDemux * qtdemux,
2732 QtDemuxCencSampleSetInfo * info, GstByteReader * br)
2733{
2734 guint32 algorithm_id = 0;
2735 const guint8 *kid;
2736 gboolean is_encrypted = TRUE;
2737 guint8 iv_size = 8;
2738
2739 if (!gst_byte_reader_get_uint24_le (br, &algorithm_id)) {
2740 GST_ERROR_OBJECT (qtdemux, "Error getting box's algorithm ID field");
2741 return FALSE;
2742 }
2743
2744 algorithm_id >>= 8;
2745 if (algorithm_id == 0) {
2746 is_encrypted = FALSE;
2747 } else if (algorithm_id == 1) {
2748 GST_DEBUG_OBJECT (qtdemux, "AES 128-bits CTR encrypted stream");
2749 } else if (algorithm_id == 2) {
2750 GST_DEBUG_OBJECT (qtdemux, "AES 128-bits CBC encrypted stream");
2751 }
2752
2753 if (!gst_byte_reader_get_uint8 (br, &iv_size))
2754 return FALSE;
2755
2756 if (!gst_byte_reader_get_data (br, 16, &kid))
2757 return FALSE;
2758
2759 qtdemux_update_default_sample_cenc_settings (qtdemux, info,
2760 is_encrypted, FOURCC_cenc, iv_size, kid, 0, 0, 0, NULL);
2761 gst_structure_set (info->default_properties, "piff_algorithm_id",
2762 G_TYPE_UINT, algorithm_id, NULL);
2763 return TRUE;
2764}
2765
2766
2767static void
2768qtdemux_parse_piff (GstQTDemux * qtdemux, const guint8 * buffer, gint length,
2769 guint offset)
2770{
2771 GstByteReader br;
2772 guint8 version;
2773 guint32 flags = 0;
2774 guint i;
2775 guint iv_size = 8;
2776 QtDemuxStream *stream;
2777 GstStructure *structure;
2778 QtDemuxCencSampleSetInfo *ss_info = NULL;
2779 const gchar *system_id;
2780 gboolean uses_sub_sample_encryption = FALSE;
2781 guint32 sample_count;
2782
2783 if (QTDEMUX_N_STREAMS (qtdemux) == 0)
2784 return;
2785
2786 stream = QTDEMUX_NTH_STREAM (qtdemux, 0);
2787
2788 structure = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
2789 if (!gst_structure_has_name (structure, "application/x-cenc")) {
2790 GST_WARNING_OBJECT (qtdemux,
2791 "Attempting PIFF box parsing on an unencrypted stream.");
2792 return;
2793 }
2794
2795 if (!gst_structure_get (structure, GST_PROTECTION_SYSTEM_ID_CAPS_FIELD,
2796 G_TYPE_STRING, &system_id, NULL)) {
2797 GST_WARNING_OBJECT (qtdemux, "%s field not present in caps",
2798 GST_PROTECTION_SYSTEM_ID_CAPS_FIELD);
2799 return;
2800 }
2801
2802 gst_qtdemux_append_protection_system_id (qtdemux, system_id);
2803
2804 stream->protected = TRUE;
2805 stream->protection_scheme_type = FOURCC_cenc;
2806
2807 if (!stream->protection_scheme_info)
2808 stream->protection_scheme_info = g_new0 (QtDemuxCencSampleSetInfo, 1);
2809
2810 ss_info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
2811 if (!ss_info->default_properties) {
2812 ss_info->default_properties =
2813 gst_structure_new ("application/x-cenc",
2814 "iv_size", G_TYPE_UINT, iv_size, "encrypted", G_TYPE_BOOLEAN, TRUE,
2815 NULL);
2816
2817 }
2818
2819 if (ss_info->crypto_info) {
2820 GST_LOG_OBJECT (qtdemux, "unreffing existing crypto_info");
2821 g_ptr_array_free (ss_info->crypto_info, TRUE);
2822 ss_info->crypto_info = NULL;
2823 }
2824
2825 /* skip UUID */
2826 gst_byte_reader_init (&br, buffer + offset + 16, length - offset - 16);
2827
2828 if (!gst_byte_reader_get_uint8 (&br, &version)) {
2829 GST_ERROR_OBJECT (qtdemux, "Error getting box's version field");
2830 return;
2831 }
2832
2833 if (!gst_byte_reader_get_uint24_be (&br, &flags)) {
2834 GST_ERROR_OBJECT (qtdemux, "Error getting box's flags field");
2835 return;
2836 }
2837
2838 if ((flags & 0x000001)) {
2839 if (!qtdemux_update_default_piff_encryption_settings (qtdemux, ss_info,
2840 &br))
2841 return;
2842 } else if ((flags & 0x000002)) {
2843 uses_sub_sample_encryption = TRUE;
2844 }
2845
2846 if (!gst_structure_get_uint (ss_info->default_properties, "iv_size",
2847 &iv_size)) {
2848 GST_ERROR_OBJECT (qtdemux, "Error getting encryption IV size field");
2849 return;
2850 }
2851
2852 if (!gst_byte_reader_get_uint32_be (&br, &sample_count)) {
2853 GST_ERROR_OBJECT (qtdemux, "Error getting box's sample count field");
2854 return;
2855 }
2856
2857 ss_info->crypto_info =
2858 g_ptr_array_new_full (sample_count,
2859 (GDestroyNotify) qtdemux_gst_structure_free);
2860
2861 for (i = 0; i < sample_count; ++i) {
2862 GstStructure *properties;
2863 guint8 *data;
2864 GstBuffer *buf;
2865
2866 properties = qtdemux_get_cenc_sample_properties (qtdemux, stream, i);
2867 if (properties == NULL) {
2868 GST_ERROR_OBJECT (qtdemux, "failed to get properties for sample %u", i);
2869 qtdemux->cenc_aux_sample_count = i;
2870 return;
2871 }
2872
2873 if (!gst_byte_reader_dup_data (&br, iv_size, &data)) {
2874 GST_ERROR_OBJECT (qtdemux, "IV data not present for sample %u", i);
2875 gst_structure_free (properties);
2876 qtdemux->cenc_aux_sample_count = i;
2877 return;
2878 }
2879 buf = gst_buffer_new_wrapped (data, iv_size);
2880 gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL);
2881 gst_buffer_unref (buf);
2882
2883 if (uses_sub_sample_encryption) {
2884 guint16 n_subsamples;
2885 const GValue *kid_buf_value;
2886
2887 if (!gst_byte_reader_get_uint16_be (&br, &n_subsamples)
2888 || n_subsamples == 0) {
2889 GST_ERROR_OBJECT (qtdemux,
2890 "failed to get subsample count for sample %u", i);
2891 gst_structure_free (properties);
2892 qtdemux->cenc_aux_sample_count = i;
2893 return;
2894 }
2895 GST_LOG_OBJECT (qtdemux, "subsample count: %u", n_subsamples);
2896 if (!gst_byte_reader_dup_data (&br, n_subsamples * 6, &data)) {
2897 GST_ERROR_OBJECT (qtdemux, "failed to get subsample data for sample %u",
2898 i);
2899 gst_structure_free (properties);
2900 qtdemux->cenc_aux_sample_count = i;
2901 return;
2902 }
2903 buf = gst_buffer_new_wrapped (data, n_subsamples * 6);
2904
2905 kid_buf_value =
2906 gst_structure_get_value (ss_info->default_properties, "kid");
2907
2908 gst_structure_set (properties,
2909 "subsample_count", G_TYPE_UINT, n_subsamples,
2910 "subsamples", GST_TYPE_BUFFER, buf, NULL);
2911 gst_structure_set_value (properties, "kid", kid_buf_value);
2912 gst_buffer_unref (buf);
2913 } else {
2914 gst_structure_set (properties, "subsample_count", G_TYPE_UINT, 0, NULL);
2915 }
2916
2917 g_ptr_array_add (ss_info->crypto_info, properties);
2918 }
2919
2920 qtdemux->cenc_aux_sample_count = sample_count;
2921}
2922
2923static void
2924qtdemux_parse_uuid (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2925{
2926 static const guint8 xmp_uuid[] = { 0xBE, 0x7A, 0xCF, 0xCB,
2927 0x97, 0xA9, 0x42, 0xE8,
2928 0x9C, 0x71, 0x99, 0x94,
2929 0x91, 0xE3, 0xAF, 0xAC
2930 };
2931 static const guint8 playready_uuid[] = {
2932 0xd0, 0x8a, 0x4f, 0x18, 0x10, 0xf3, 0x4a, 0x82,
2933 0xb6, 0xc8, 0x32, 0xd8, 0xab, 0xa1, 0x83, 0xd3
2934 };
2935
2936 static const guint8 piff_sample_encryption_uuid[] = {
2937 0xa2, 0x39, 0x4f, 0x52, 0x5a, 0x9b, 0x4f, 0x14,
2938 0xa2, 0x44, 0x6c, 0x42, 0x7c, 0x64, 0x8d, 0xf4
2939 };
2940
2941 guint offset;
2942
2943 /* counts as header data */
2944 qtdemux->header_size += length;
2945
2946 offset = (QT_UINT32 (buffer) == 0) ? 16 : 8;
2947
2948 if (length <= offset + 16) {
2949 GST_DEBUG_OBJECT (qtdemux, "uuid atom is too short, skipping");
2950 return;
2951 }
2952
2953 if (memcmp (buffer + offset, xmp_uuid, 16) == 0) {
2954 GstBuffer *buf;
2955 GstTagList *taglist;
2956
2957 buf = _gst_buffer_new_wrapped ((guint8 *) buffer + offset + 16,
2958 length - offset - 16, NULL);
2959 taglist = gst_tag_list_from_xmp_buffer (buf);
2960 gst_buffer_unref (buf);
2961
2962 /* make sure we have a usable taglist */
2963 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
2964
2965 qtdemux_handle_xmp_taglist (qtdemux, qtdemux->tag_list, taglist);
2966
2967 } else if (memcmp (buffer + offset, playready_uuid, 16) == 0) {
2968 int len;
2969 const gunichar2 *s_utf16;
2970 char *contents;
2971
2972 len = GST_READ_UINT16_LE (buffer + offset + 0x30);
2973 s_utf16 = (const gunichar2 *) (buffer + offset + 0x32);
2974 contents = g_utf16_to_utf8 (s_utf16, len / 2, NULL, NULL, NULL);
2975 GST_ERROR_OBJECT (qtdemux, "contents: %s", contents);
2976
2977 g_free (contents);
2978
2979 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT,
2980 (_("Cannot play stream because it is encrypted with PlayReady DRM.")),
2981 (NULL));
2982 } else if (memcmp (buffer + offset, piff_sample_encryption_uuid, 16) == 0) {
2983 qtdemux_parse_piff (qtdemux, buffer, length, offset);
2984 } else {
2985 GST_DEBUG_OBJECT (qtdemux, "Ignoring unknown uuid: %08x-%08x-%08x-%08x",
2986 GST_READ_UINT32_LE (buffer + offset),
2987 GST_READ_UINT32_LE (buffer + offset + 4),
2988 GST_READ_UINT32_LE (buffer + offset + 8),
2989 GST_READ_UINT32_LE (buffer + offset + 12));
2990 }
2991}
2992
2993static void
2994qtdemux_parse_sidx (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2995{
2996 GstSidxParser sidx_parser;
2997 GstIsoffParserResult res;
2998 guint consumed;
2999
3000 gst_isoff_qt_sidx_parser_init (&sidx_parser);
3001
3002 res =
3003 gst_isoff_qt_sidx_parser_add_data (&sidx_parser, buffer, length,
3004 &consumed);
3005 GST_DEBUG_OBJECT (qtdemux, "sidx parse result: %d", res);
3006 if (res == GST_ISOFF_QT_PARSER_DONE) {
3007 check_update_duration (qtdemux, sidx_parser.cumulative_pts);
3008 }
3009 gst_isoff_qt_sidx_parser_clear (&sidx_parser);
3010}
3011
3012/* caller verifies at least 8 bytes in buf */
3013static void
3014extract_initial_length_and_fourcc (const guint8 * data, guint size,
3015 guint64 * plength, guint32 * pfourcc)
3016{
3017 guint64 length;
3018 guint32 fourcc;
3019
3020 length = QT_UINT32 (data);
3021 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
3022 fourcc = QT_FOURCC (data + 4);
3023 GST_DEBUG ("atom type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
3024
3025 if (length == 0) {
3026 length = G_MAXUINT64;
3027 } else if (length == 1 && size >= 16) {
3028 /* this means we have an extended size, which is the 64 bit value of
3029 * the next 8 bytes */
3030 length = QT_UINT64 (data + 8);
3031 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
3032 }
3033
3034 if (plength)
3035 *plength = length;
3036 if (pfourcc)
3037 *pfourcc = fourcc;
3038}
3039
3040static gboolean
3041qtdemux_parse_mehd (GstQTDemux * qtdemux, GstByteReader * br)
3042{
3043 guint32 version = 0;
3044 GstClockTime duration = 0;
3045
3046 if (!gst_byte_reader_get_uint32_be (br, &version))
3047 goto failed;
3048
3049 version >>= 24;
3050 if (version == 1) {
3051 if (!gst_byte_reader_get_uint64_be (br, &duration))
3052 goto failed;
3053 } else {
3054 guint32 dur = 0;
3055
3056 if (!gst_byte_reader_get_uint32_be (br, &dur))
3057 goto failed;
3058 duration = dur;
3059 }
3060
3061 GST_INFO_OBJECT (qtdemux, "mehd duration: %" G_GUINT64_FORMAT, duration);
3062 qtdemux->duration = duration;
3063
3064 return TRUE;
3065
3066failed:
3067 {
3068 GST_DEBUG_OBJECT (qtdemux, "parsing mehd failed");
3069 return FALSE;
3070 }
3071}
3072
3073static gboolean
3074qtdemux_parse_trex (GstQTDemux * qtdemux, QtDemuxStream * stream,
3075 guint32 * ds_duration, guint32 * ds_size, guint32 * ds_flags)
3076{
3077 if (!stream->parsed_trex && qtdemux->moov_node) {
3078 GNode *mvex, *trex;
3079 GstByteReader trex_data;
3080
3081 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
3082 if (mvex) {
3083 trex = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_trex,
3084 &trex_data);
3085 while (trex) {
3086 guint32 id = 0, sdi = 0, dur = 0, size = 0, flags = 0;
3087
3088 /* skip version/flags */
3089 if (!gst_byte_reader_skip (&trex_data, 4))
3090 goto next;
3091 if (!gst_byte_reader_get_uint32_be (&trex_data, &id))
3092 goto next;
3093 if (id != stream->track_id)
3094 goto next;
3095 if (!gst_byte_reader_get_uint32_be (&trex_data, &sdi))
3096 goto next;
3097 if (!gst_byte_reader_get_uint32_be (&trex_data, &dur))
3098 goto next;
3099 if (!gst_byte_reader_get_uint32_be (&trex_data, &size))
3100 goto next;
3101 if (!gst_byte_reader_get_uint32_be (&trex_data, &flags))
3102 goto next;
3103
3104 GST_DEBUG_OBJECT (qtdemux, "fragment defaults for stream %d; "
3105 "duration %d, size %d, flags 0x%x", stream->track_id,
3106 dur, size, flags);
3107
3108 stream->parsed_trex = TRUE;
3109 stream->def_sample_description_index = sdi;
3110 stream->def_sample_duration = dur;
3111 stream->def_sample_size = size;
3112 stream->def_sample_flags = flags;
3113
3114 next:
3115 /* iterate all siblings */
3116 trex = qtdemux_tree_get_sibling_by_type_full (trex, FOURCC_trex,
3117 &trex_data);
3118 }
3119 }
3120 }
3121
3122 *ds_duration = stream->def_sample_duration;
3123 *ds_size = stream->def_sample_size;
3124 *ds_flags = stream->def_sample_flags;
3125
3126 /* even then, above values are better than random ... */
3127 if (G_UNLIKELY (!stream->parsed_trex)) {
3128 GST_WARNING_OBJECT (qtdemux,
3129 "failed to find fragment defaults for stream %d", stream->track_id);
3130 return FALSE;
3131 }
3132
3133 return TRUE;
3134}
3135
3136/* This method should be called whenever a more accurate duration might
3137 * have been found. It will update all relevant variables if/where needed
3138 */
3139static void
3140check_update_duration (GstQTDemux * qtdemux, GstClockTime duration)
3141{
3142 guint i;
3143 guint64 movdur;
3144 GstClockTime prevdur;
3145
3146 movdur = GSTTIME_TO_QTTIME (qtdemux, duration);
3147
3148 if (movdur > qtdemux->duration) {
3149 prevdur = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
3150 GST_DEBUG_OBJECT (qtdemux,
3151 "Updating total duration to %" GST_TIME_FORMAT " was %" GST_TIME_FORMAT,
3152 GST_TIME_ARGS (duration), GST_TIME_ARGS (prevdur));
3153 qtdemux->duration = movdur;
3154 GST_DEBUG_OBJECT (qtdemux,
3155 "qtdemux->segment.duration: %" GST_TIME_FORMAT " .stop: %"
3156 GST_TIME_FORMAT, GST_TIME_ARGS (qtdemux->segment.duration),
3157 GST_TIME_ARGS (qtdemux->segment.stop));
3158 if (qtdemux->segment.duration == prevdur) {
3159 /* If the current segment has duration/stop identical to previous duration
3160 * update them also (because they were set at that point in time with
3161 * the wrong duration */
3162 /* We convert the value *from* the timescale version to avoid rounding errors */
3163 GstClockTime fixeddur = QTTIME_TO_GSTTIME (qtdemux, movdur);
3164 GST_DEBUG_OBJECT (qtdemux, "Updated segment.duration and segment.stop");
3165 qtdemux->segment.duration = fixeddur;
3166 qtdemux->segment.stop = fixeddur;
3167 }
3168 }
3169
3170 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
3171 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
3172
3173 movdur = GSTTIME_TO_QTSTREAMTIME (stream, duration);
3174 if (movdur > stream->duration) {
3175 GST_DEBUG_OBJECT (qtdemux,
3176 "Updating stream #%d duration to %" GST_TIME_FORMAT, i,
3177 GST_TIME_ARGS (duration));
3178 stream->duration = movdur;
3179 /* internal duration tracking state has been updated above, so */
3180 /* preserve an open-ended dummy segment rather than repeatedly updating
3181 * it and spamming downstream accordingly with segment events */
3182 /* also mangle the edit list end time when fragmented with a single edit
3183 * list that may only cover any non-fragmented data */
3184 if ((stream->dummy_segment ||
3185 (qtdemux->fragmented && stream->n_segments == 1)) &&
3186 GST_CLOCK_TIME_IS_VALID (stream->segments[0].duration)) {
3187 /* Update all dummy values to new duration */
3188 stream->segments[0].stop_time = duration;
3189 stream->segments[0].duration = duration;
3190 stream->segments[0].media_stop = duration;
3191
3192 /* let downstream know we possibly have a new stop time */
3193 if (stream->segment_index != -1) {
3194 GstClockTime pos;
3195
3196 if (qtdemux->segment.rate >= 0) {
3197 pos = stream->segment.start;
3198 } else {
3199 pos = stream->segment.stop;
3200 }
3201
3202 gst_qtdemux_stream_update_segment (qtdemux, stream,
3203 stream->segment_index, pos, NULL, NULL);
3204 }
3205 }
3206 }
3207 }
3208}
3209
3210static gboolean
3211qtdemux_parse_trun (GstQTDemux * qtdemux, GstByteReader * trun,
3212 QtDemuxStream * stream, guint32 d_sample_duration, guint32 d_sample_size,
3213 guint32 d_sample_flags, gint64 moof_offset, gint64 moof_length,
3214 gint64 * base_offset, gint64 * running_offset, gint64 decode_ts,
3215 gboolean has_tfdt)
3216{
3217 GstClockTime gst_ts = GST_CLOCK_TIME_NONE;
3218 guint64 timestamp;
3219 gint32 data_offset = 0;
3220 guint8 version;
3221 guint32 flags = 0, first_flags = 0, samples_count = 0;
3222 gint i;
3223 guint8 *data;
3224 guint entry_size, dur_offset, size_offset, flags_offset = 0, ct_offset = 0;
3225 QtDemuxSample *sample;
3226 gboolean ismv = FALSE;
3227 gint64 initial_offset;
3228 gint32 min_ct = 0;
3229
3230 GST_LOG_OBJECT (qtdemux, "parsing trun track-id %d; "
3231 "default dur %d, size %d, flags 0x%x, base offset %" G_GINT64_FORMAT ", "
3232 "decode ts %" G_GINT64_FORMAT, stream->track_id, d_sample_duration,
3233 d_sample_size, d_sample_flags, *base_offset, decode_ts);
3234
3235 if (stream->pending_seek && moof_offset < stream->pending_seek->moof_offset) {
3236 GST_INFO_OBJECT (stream->pad, "skipping trun before seek target fragment");
3237 return TRUE;
3238 }
3239
3240 /* presence of stss or not can't really tell us much,
3241 * and flags and so on tend to be marginally reliable in these files */
3242 if (stream->subtype == FOURCC_soun) {
3243 GST_DEBUG_OBJECT (qtdemux,
3244 "sound track in fragmented file; marking all keyframes");
3245 stream->all_keyframe = TRUE;
3246 }
3247
3248 if (!gst_byte_reader_get_uint8 (trun, &version) ||
3249 !gst_byte_reader_get_uint24_be (trun, &flags))
3250 goto fail;
3251
3252 if (!gst_byte_reader_get_uint32_be (trun, &samples_count))
3253 goto fail;
3254
3255 if (flags & TR_DATA_OFFSET) {
3256 /* note this is really signed */
3257 if (!gst_byte_reader_get_int32_be (trun, &data_offset))
3258 goto fail;
3259 GST_LOG_OBJECT (qtdemux, "trun data offset %d", data_offset);
3260 /* default base offset = first byte of moof */
3261 if (*base_offset == -1) {
3262 GST_LOG_OBJECT (qtdemux, "base_offset at moof");
3263 *base_offset = moof_offset;
3264 }
3265 *running_offset = *base_offset + data_offset;
3266 } else {
3267 /* if no offset at all, that would mean data starts at moof start,
3268 * which is a bit wrong and is ismv crappy way, so compensate
3269 * assuming data is in mdat following moof */
3270 if (*base_offset == -1) {
3271 *base_offset = moof_offset + moof_length + 8;
3272 GST_LOG_OBJECT (qtdemux, "base_offset assumed in mdat after moof");
3273 ismv = TRUE;
3274 }
3275 if (*running_offset == -1)
3276 *running_offset = *base_offset;
3277 }
3278
3279 GST_LOG_OBJECT (qtdemux, "running offset now %" G_GINT64_FORMAT,
3280 *running_offset);
3281 GST_LOG_OBJECT (qtdemux, "trun offset %d, flags 0x%x, entries %d",
3282 data_offset, flags, samples_count);
3283
3284 if (flags & TR_FIRST_SAMPLE_FLAGS) {
3285 if (G_UNLIKELY (flags & TR_SAMPLE_FLAGS)) {
3286 GST_DEBUG_OBJECT (qtdemux,
3287 "invalid flags; SAMPLE and FIRST_SAMPLE present, discarding latter");
3288 flags ^= TR_FIRST_SAMPLE_FLAGS;
3289 } else {
3290 if (!gst_byte_reader_get_uint32_be (trun, &first_flags))
3291 goto fail;
3292 GST_LOG_OBJECT (qtdemux, "first flags: 0x%x", first_flags);
3293 }
3294 }
3295
3296 /* FIXME ? spec says other bits should also be checked to determine
3297 * entry size (and prefix size for that matter) */
3298 entry_size = 0;
3299 dur_offset = size_offset = 0;
3300 if (flags & TR_SAMPLE_DURATION) {
3301 GST_LOG_OBJECT (qtdemux, "entry duration present");
3302 dur_offset = entry_size;
3303 entry_size += 4;
3304 }
3305 if (flags & TR_SAMPLE_SIZE) {
3306 GST_LOG_OBJECT (qtdemux, "entry size present");
3307 size_offset = entry_size;
3308 entry_size += 4;
3309 }
3310 if (flags & TR_SAMPLE_FLAGS) {
3311 GST_LOG_OBJECT (qtdemux, "entry flags present");
3312 flags_offset = entry_size;
3313 entry_size += 4;
3314 }
3315 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
3316 GST_LOG_OBJECT (qtdemux, "entry ct offset present");
3317 ct_offset = entry_size;
3318 entry_size += 4;
3319 }
3320
3321 if (!qt_atom_parser_has_chunks (trun, samples_count, entry_size))
3322 goto fail;
3323 data = (guint8 *) gst_byte_reader_peek_data_unchecked (trun);
3324
3325 if (stream->n_samples + samples_count >=
3326 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample))
3327 goto index_too_big;
3328
3329 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
3330 stream->n_samples + samples_count, (guint) sizeof (QtDemuxSample),
3331 (stream->n_samples + samples_count) *
3332 sizeof (QtDemuxSample) / (1024.0 * 1024.0));
3333
3334 /* create a new array of samples if it's the first sample parsed */
3335 if (stream->n_samples == 0) {
3336 g_assert (stream->samples == NULL);
3337 stream->samples = g_try_new0 (QtDemuxSample, samples_count);
3338 /* or try to reallocate it with space enough to insert the new samples */
3339 } else
3340 stream->samples = g_try_renew (QtDemuxSample, stream->samples,
3341 stream->n_samples + samples_count);
3342 if (stream->samples == NULL)
3343 goto out_of_memory;
3344
3345 if (qtdemux->fragment_start != -1) {
3346 timestamp = GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->fragment_start);
3347 qtdemux->fragment_start = -1;
3348 } else {
3349 if (stream->n_samples == 0) {
3350 if (decode_ts > 0) {
3351 timestamp = decode_ts;
3352 } else if (stream->pending_seek != NULL) {
3353 /* if we don't have a timestamp from a tfdt box, we'll use the one
3354 * from the mfra seek table */
3355 GST_INFO_OBJECT (stream->pad, "pending seek ts = %" GST_TIME_FORMAT,
3356 GST_TIME_ARGS (stream->pending_seek->ts));
3357
3358 /* FIXME: this is not fully correct, the timestamp refers to the random
3359 * access sample refered to in the tfra entry, which may not necessarily
3360 * be the first sample in the tfrag/trun (but hopefully/usually is) */
3361 timestamp = GSTTIME_TO_QTSTREAMTIME (stream, stream->pending_seek->ts);
3362 } else {
3363 timestamp = 0;
3364 }
3365
3366 gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
3367 GST_INFO_OBJECT (stream->pad, "first sample ts %" GST_TIME_FORMAT,
3368 GST_TIME_ARGS (gst_ts));
3369 } else {
3370 /* subsequent fragments extend stream */
3371 timestamp =
3372 stream->samples[stream->n_samples - 1].timestamp +
3373 stream->samples[stream->n_samples - 1].duration;
3374
3375 /* If this is a GST_FORMAT_BYTES stream and there's a significant
3376 * difference (1 sec.) between decode_ts and timestamp, prefer the
3377 * former */
3378 if (has_tfdt && !qtdemux->upstream_format_is_time
3379 && ABSDIFF (decode_ts, timestamp) >
3380 MAX (stream->duration_last_moof / 2,
3381 GSTTIME_TO_QTSTREAMTIME (stream, GST_SECOND))) {
3382 GST_INFO_OBJECT (qtdemux,
3383 "decode_ts (%" GST_TIME_FORMAT ") and timestamp (%" GST_TIME_FORMAT
3384 ") are significantly different (more than %" GST_TIME_FORMAT
3385 "), using decode_ts",
3386 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, decode_ts)),
3387 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, timestamp)),
3388 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream,
3389 MAX (stream->duration_last_moof / 2,
3390 GSTTIME_TO_QTSTREAMTIME (stream, GST_SECOND)))));
3391 timestamp = decode_ts;
3392 }
3393
3394 gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
3395 GST_INFO_OBJECT (qtdemux, "first sample ts %" GST_TIME_FORMAT
3396 " (extends previous samples)", GST_TIME_ARGS (gst_ts));
3397 }
3398 }
3399
3400 initial_offset = *running_offset;
3401
3402 sample = stream->samples + stream->n_samples;
3403 for (i = 0; i < samples_count; i++) {
3404 guint32 dur, size, sflags;
3405 gint32 ct;
3406
3407 /* first read sample data */
3408 if (flags & TR_SAMPLE_DURATION) {
3409 dur = QT_UINT32 (data + dur_offset);
3410 } else {
3411 dur = d_sample_duration;
3412 }
3413 if (flags & TR_SAMPLE_SIZE) {
3414 size = QT_UINT32 (data + size_offset);
3415 } else {
3416 size = d_sample_size;
3417 }
3418 if (flags & TR_FIRST_SAMPLE_FLAGS) {
3419 if (i == 0) {
3420 sflags = first_flags;
3421 } else {
3422 sflags = d_sample_flags;
3423 }
3424 } else if (flags & TR_SAMPLE_FLAGS) {
3425 sflags = QT_UINT32 (data + flags_offset);
3426 } else {
3427 sflags = d_sample_flags;
3428 }
3429
3430 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
3431 /* Read offsets as signed numbers regardless of trun version as very
3432 * high offsets are unlikely and there are files out there that use
3433 * version=0 truns with negative offsets */
3434 ct = QT_UINT32 (data + ct_offset);
3435
3436 /* FIXME: Set offset to 0 for "no decode samples". This needs
3437 * to be handled in a codec specific manner ideally. */
3438 if (ct == G_MININT32)
3439 ct = 0;
3440 } else {
3441 ct = 0;
3442 }
3443 data += entry_size;
3444
3445 /* fill the sample information */
3446 sample->offset = *running_offset;
3447 sample->pts_offset = ct;
3448 sample->size = size;
3449 sample->timestamp = timestamp;
3450 sample->duration = dur;
3451 /* sample-is-difference-sample */
3452 /* ismv seems to use 0x40 for keyframe, 0xc0 for non-keyframe,
3453 * now idea how it relates to bitfield other than massive LE/BE confusion */
3454 sample->keyframe = ismv ? ((sflags & 0xff) == 0x40) : !(sflags & 0x10000);
3455 *running_offset += size;
3456 timestamp += dur;
3457 stream->duration_moof += dur;
3458 sample++;
3459
3460 if (ct < min_ct)
3461 min_ct = ct;
3462 }
3463
3464 /* Shift PTS/DTS to allow for negative composition offsets while keeping
3465 * A/V sync in place. This is similar to the code handling ctts/cslg in the
3466 * non-fragmented case.
3467 */
3468 if (min_ct < 0)
3469 stream->cslg_shift = -min_ct;
3470 else
3471 stream->cslg_shift = 0;
3472
3473 GST_DEBUG_OBJECT (qtdemux, "Using clsg_shift %" G_GUINT64_FORMAT,
3474 stream->cslg_shift);
3475
3476 /* Update total duration if needed */
3477 check_update_duration (qtdemux, QTSTREAMTIME_TO_GSTTIME (stream, timestamp));
3478
3479 /* Pre-emptively figure out size of mdat based on trun information.
3480 * If the [mdat] atom is effectively read, it will be replaced by the actual
3481 * size, else we will still be able to use this when dealing with gap'ed
3482 * input */
3483 qtdemux->mdatleft = *running_offset - initial_offset;
3484 qtdemux->mdatoffset = initial_offset;
3485 qtdemux->mdatsize = qtdemux->mdatleft;
3486
3487 stream->n_samples += samples_count;
3488 stream->n_samples_moof += samples_count;
3489
3490 if (stream->pending_seek != NULL)
3491 stream->pending_seek = NULL;
3492
3493 return TRUE;
3494
3495fail:
3496 {
3497 GST_WARNING_OBJECT (qtdemux, "failed to parse trun");
3498 return FALSE;
3499 }
3500out_of_memory:
3501 {
3502 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
3503 stream->n_samples);
3504 return FALSE;
3505 }
3506index_too_big:
3507 {
3508 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
3509 "be larger than %uMB (broken file?)", stream->n_samples,
3510 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
3511 return FALSE;
3512 }
3513}
3514
3515/* find stream with @id */
3516static inline QtDemuxStream *
3517qtdemux_find_stream (GstQTDemux * qtdemux, guint32 id)
3518{
3519 QtDemuxStream *stream;
3520 gint i;
3521
3522 /* check */
3523 if (G_UNLIKELY (!id)) {
3524 GST_DEBUG_OBJECT (qtdemux, "invalid track id 0");
3525 return NULL;
3526 }
3527
3528 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
3529 stream = QTDEMUX_NTH_STREAM (qtdemux, i);
3530 if (stream->track_id == id)
3531 return stream;
3532 }
3533 if (qtdemux->variant == VARIANT_MSS_FRAGMENTED) {
3534 /* mss should have only 1 stream anyway */
3535 return QTDEMUX_NTH_STREAM (qtdemux, 0);
3536 }
3537
3538 return NULL;
3539}
3540
3541static gboolean
3542qtdemux_parse_mfhd (GstQTDemux * qtdemux, GstByteReader * mfhd,
3543 guint32 * fragment_number)
3544{
3545 if (!gst_byte_reader_skip (mfhd, 4))
3546 goto fail;
3547 if (!gst_byte_reader_get_uint32_be (mfhd, fragment_number))
3548 goto fail;
3549 return TRUE;
3550fail:
3551 {
3552 GST_WARNING_OBJECT (qtdemux, "Failed to parse mfhd atom");
3553 return FALSE;
3554 }
3555}
3556
3557static gboolean
3558qtdemux_parse_tfhd (GstQTDemux * qtdemux, GstByteReader * tfhd,
3559 QtDemuxStream ** stream, guint32 * default_sample_duration,
3560 guint32 * default_sample_size, guint32 * default_sample_flags,
3561 gint64 * base_offset)
3562{
3563 guint32 flags = 0;
3564 guint32 track_id = 0;
3565
3566 if (!gst_byte_reader_skip (tfhd, 1) ||
3567 !gst_byte_reader_get_uint24_be (tfhd, &flags))
3568 goto invalid_track;
3569
3570 if (!gst_byte_reader_get_uint32_be (tfhd, &track_id))
3571 goto invalid_track;
3572
3573 *stream = qtdemux_find_stream (qtdemux, track_id);
3574 if (G_UNLIKELY (!*stream))
3575 goto unknown_stream;
3576
3577 if (flags & TF_DEFAULT_BASE_IS_MOOF)
3578 *base_offset = qtdemux->moof_offset;
3579
3580 if (flags & TF_BASE_DATA_OFFSET)
3581 if (!gst_byte_reader_get_uint64_be (tfhd, (guint64 *) base_offset))
3582 goto invalid_track;
3583
3584 /* obtain stream defaults */
3585 if (qtdemux_parse_trex (qtdemux, *stream,
3586 default_sample_duration, default_sample_size, default_sample_flags)) {
3587
3588 /* Default sample description index is only valid if trex parsing succeeded */
3589 (*stream)->stsd_sample_description_id =
3590 (*stream)->def_sample_description_index - 1;
3591 }
3592
3593 if (flags & TF_SAMPLE_DESCRIPTION_INDEX) {
3594 guint32 sample_description_index;
3595 if (!gst_byte_reader_get_uint32_be (tfhd, &sample_description_index))
3596 goto invalid_track;
3597 (*stream)->stsd_sample_description_id = sample_description_index - 1;
3598 }
3599
3600 if (qtdemux->variant == VARIANT_MSS_FRAGMENTED) {
3601 /* mss has no stsd entry */
3602 (*stream)->stsd_sample_description_id = 0;
3603 }
3604
3605 if (flags & TF_DEFAULT_SAMPLE_DURATION)
3606 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_duration))
3607 goto invalid_track;
3608
3609 if (flags & TF_DEFAULT_SAMPLE_SIZE)
3610 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_size))
3611 goto invalid_track;
3612
3613 if (flags & TF_DEFAULT_SAMPLE_FLAGS)
3614 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_flags))
3615 goto invalid_track;
3616
3617 return TRUE;
3618
3619invalid_track:
3620 {
3621 GST_WARNING_OBJECT (qtdemux, "invalid track fragment header");
3622 return FALSE;
3623 }
3624unknown_stream:
3625 {
3626 GST_DEBUG_OBJECT (qtdemux, "unknown stream (%u) in tfhd", track_id);
3627 return TRUE;
3628 }
3629}
3630
3631static gboolean
3632qtdemux_parse_tfdt (GstQTDemux * qtdemux, GstByteReader * br,
3633 guint64 * decode_time)
3634{
3635 guint32 version = 0;
3636
3637 if (!gst_byte_reader_get_uint32_be (br, &version))
3638 return FALSE;
3639
3640 version >>= 24;
3641 if (version == 1) {
3642 if (!gst_byte_reader_get_uint64_be (br, decode_time))
3643 goto failed;
3644 } else {
3645 guint32 dec_time = 0;
3646 if (!gst_byte_reader_get_uint32_be (br, &dec_time))
3647 goto failed;
3648 *decode_time = dec_time;
3649 }
3650
3651 GST_INFO_OBJECT (qtdemux, "Track fragment decode time: %" G_GUINT64_FORMAT,
3652 *decode_time);
3653
3654 return TRUE;
3655
3656failed:
3657 {
3658 GST_DEBUG_OBJECT (qtdemux, "parsing tfdt failed");
3659 return FALSE;
3660 }
3661}
3662
3663/* Returns a pointer to a GstStructure containing the properties of
3664 * the stream sample identified by @sample_index. The caller must unref
3665 * the returned object after use. Returns NULL if unsuccessful. */
3666static GstStructure *
3667qtdemux_get_cenc_sample_properties (GstQTDemux * qtdemux,
3668 QtDemuxStream * stream, guint sample_index)
3669{
3670 QtDemuxCencSampleSetInfo *info = NULL;
3671
3672 g_return_val_if_fail (stream != NULL, NULL);
3673 g_return_val_if_fail (stream->protected, NULL);
3674 g_return_val_if_fail (stream->protection_scheme_info != NULL, NULL);
3675
3676 info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
3677
3678 /* Currently, cenc properties for groups of samples are not supported, so
3679 * simply return a copy of the default sample properties */
3680 return gst_structure_copy (info->default_properties);
3681}
3682
3683/* Parses the sizes of sample auxiliary information contained within a stream,
3684 * as given in a saiz box. Returns array of sample_count guint8 size values,
3685 * or NULL on failure */
3686static guint8 *
3687qtdemux_parse_saiz (GstQTDemux * qtdemux, QtDemuxStream * stream,
3688 GstByteReader * br, guint32 * sample_count)
3689{
3690 guint32 flags = 0;
3691 guint8 *info_sizes;
3692 guint8 default_info_size;
3693
3694 g_return_val_if_fail (qtdemux != NULL, NULL);
3695 g_return_val_if_fail (stream != NULL, NULL);
3696 g_return_val_if_fail (br != NULL, NULL);
3697 g_return_val_if_fail (sample_count != NULL, NULL);
3698
3699 if (!gst_byte_reader_get_uint32_be (br, &flags))
3700 return NULL;
3701
3702 if (flags & 0x1) {
3703 /* aux_info_type and aux_info_type_parameter are ignored */
3704 if (!gst_byte_reader_skip (br, 8))
3705 return NULL;
3706 }
3707
3708 if (!gst_byte_reader_get_uint8 (br, &default_info_size))
3709 return NULL;
3710 GST_DEBUG_OBJECT (qtdemux, "default_info_size: %u", default_info_size);
3711
3712 if (!gst_byte_reader_get_uint32_be (br, sample_count))
3713 return NULL;
3714 GST_DEBUG_OBJECT (qtdemux, "sample_count: %u", *sample_count);
3715
3716
3717 if (default_info_size == 0) {
3718 if (!gst_byte_reader_dup_data (br, *sample_count, &info_sizes)) {
3719 return NULL;
3720 }
3721 } else {
3722 info_sizes = g_new (guint8, *sample_count);
3723 memset (info_sizes, default_info_size, *sample_count);
3724 }
3725
3726 return info_sizes;
3727}
3728
3729/* Parses the offset of sample auxiliary information contained within a stream,
3730 * as given in a saio box. Returns TRUE if successful; FALSE otherwise. */
3731static gboolean
3732qtdemux_parse_saio (GstQTDemux * qtdemux, QtDemuxStream * stream,
3733 GstByteReader * br, guint32 * info_type, guint32 * info_type_parameter,
3734 guint64 * offset)
3735{
3736 guint8 version = 0;
3737 guint32 flags = 0;
3738 guint32 aux_info_type = 0;
3739 guint32 aux_info_type_parameter = 0;
3740 guint32 entry_count;
3741 guint32 off_32;
3742 guint64 off_64;
3743 const guint8 *aux_info_type_data = NULL;
3744
3745 g_return_val_if_fail (qtdemux != NULL, FALSE);
3746 g_return_val_if_fail (stream != NULL, FALSE);
3747 g_return_val_if_fail (br != NULL, FALSE);
3748 g_return_val_if_fail (offset != NULL, FALSE);
3749
3750 if (!gst_byte_reader_get_uint8 (br, &version))
3751 return FALSE;
3752
3753 if (!gst_byte_reader_get_uint24_be (br, &flags))
3754 return FALSE;
3755
3756 if (flags & 0x1) {
3757
3758 if (!gst_byte_reader_get_data (br, 4, &aux_info_type_data))
3759 return FALSE;
3760 aux_info_type = QT_FOURCC (aux_info_type_data);
3761
3762 if (!gst_byte_reader_get_uint32_be (br, &aux_info_type_parameter))
3763 return FALSE;
3764 } else if (stream->protected) {
3765 aux_info_type = stream->protection_scheme_type;
3766 } else {
3767 aux_info_type = CUR_STREAM (stream)->fourcc;
3768 }
3769
3770 if (info_type)
3771 *info_type = aux_info_type;
3772 if (info_type_parameter)
3773 *info_type_parameter = aux_info_type_parameter;
3774
3775 GST_DEBUG_OBJECT (qtdemux, "aux_info_type: '%" GST_FOURCC_FORMAT "', "
3776 "aux_info_type_parameter: %#06x",
3777 GST_FOURCC_ARGS (aux_info_type), aux_info_type_parameter);
3778
3779 if (!gst_byte_reader_get_uint32_be (br, &entry_count))
3780 return FALSE;
3781
3782 if (entry_count != 1) {
3783 GST_ERROR_OBJECT (qtdemux, "multiple offsets are not supported");
3784 return FALSE;
3785 }
3786
3787 if (version == 0) {
3788 if (!gst_byte_reader_get_uint32_be (br, &off_32))
3789 return FALSE;
3790 *offset = (guint64) off_32;
3791 } else {
3792 if (!gst_byte_reader_get_uint64_be (br, &off_64))
3793 return FALSE;
3794 *offset = off_64;
3795 }
3796
3797 GST_DEBUG_OBJECT (qtdemux, "offset: %" G_GUINT64_FORMAT, *offset);
3798 return TRUE;
3799}
3800
3801static void
3802qtdemux_gst_structure_free (GstStructure * gststructure)
3803{
3804 if (gststructure) {
3805 gst_structure_free (gststructure);
3806 }
3807}
3808
3809/* Parses auxiliary information relating to samples protected using
3810 * Common Encryption (cenc); the format of this information
3811 * is defined in ISO/IEC 23001-7. Returns TRUE if successful; FALSE
3812 * otherwise. */
3813static gboolean
3814qtdemux_parse_cenc_aux_info (GstQTDemux * qtdemux, QtDemuxStream * stream,
3815 GstByteReader * br, guint8 * info_sizes, guint32 sample_count)
3816{
3817 QtDemuxCencSampleSetInfo *ss_info = NULL;
3818 guint8 size;
3819 gint i;
3820 GPtrArray *old_crypto_info = NULL;
3821 guint old_entries = 0;
3822
3823 g_return_val_if_fail (qtdemux != NULL, FALSE);
3824 g_return_val_if_fail (stream != NULL, FALSE);
3825 g_return_val_if_fail (br != NULL, FALSE);
3826 g_return_val_if_fail (stream->protected, FALSE);
3827 g_return_val_if_fail (stream->protection_scheme_info != NULL, FALSE);
3828
3829 ss_info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
3830
3831 if (ss_info->crypto_info) {
3832 old_crypto_info = ss_info->crypto_info;
3833 /* Count number of non-null entries remaining at the tail end */
3834 for (i = old_crypto_info->len - 1; i >= 0; i--) {
3835 if (g_ptr_array_index (old_crypto_info, i) == NULL)
3836 break;
3837 old_entries++;
3838 }
3839 }
3840
3841 ss_info->crypto_info =
3842 g_ptr_array_new_full (sample_count + old_entries,
3843 (GDestroyNotify) qtdemux_gst_structure_free);
3844
3845 /* We preserve old entries because we parse the next moof in advance
3846 * of consuming all samples from the previous moof, and otherwise
3847 * we'd discard the corresponding crypto info for the samples
3848 * from the previous fragment. */
3849 if (old_entries) {
3850 GST_DEBUG_OBJECT (qtdemux, "Preserving %d old crypto info entries",
3851 old_entries);
3852 for (i = old_crypto_info->len - old_entries; i < old_crypto_info->len; i++) {
3853 g_ptr_array_add (ss_info->crypto_info, g_ptr_array_index (old_crypto_info,
3854 i));
3855 g_ptr_array_index (old_crypto_info, i) = NULL;
3856 }
3857 }
3858
3859 if (old_crypto_info) {
3860 /* Everything now belongs to the new array */
3861 g_ptr_array_free (old_crypto_info, TRUE);
3862 }
3863
3864 for (i = 0; i < sample_count; ++i) {
3865 GstStructure *properties;
3866 guint16 n_subsamples = 0;
3867 guint8 *data;
3868 guint iv_size;
3869 GstBuffer *buf;
3870 gboolean could_read_iv;
3871
3872 properties = qtdemux_get_cenc_sample_properties (qtdemux, stream, i);
3873 if (properties == NULL) {
3874 GST_ERROR_OBJECT (qtdemux, "failed to get properties for sample %u", i);
3875 return FALSE;
3876 }
3877 if (!gst_structure_get_uint (properties, "iv_size", &iv_size)) {
3878 GST_ERROR_OBJECT (qtdemux, "failed to get iv_size for sample %u", i);
3879 gst_structure_free (properties);
3880 return FALSE;
3881 }
3882 could_read_iv =
3883 iv_size > 0 ? gst_byte_reader_dup_data (br, iv_size, &data) : FALSE;
3884 if (could_read_iv) {
3885 buf = gst_buffer_new_wrapped (data, iv_size);
3886 gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL);
3887 gst_buffer_unref (buf);
3888 } else if (stream->protection_scheme_type == FOURCC_cbcs) {
3889 const GValue *constant_iv_size_value =
3890 gst_structure_get_value (properties, "constant_iv_size");
3891 const GValue *constant_iv_value =
3892 gst_structure_get_value (properties, "iv");
3893 if (constant_iv_size_value == NULL || constant_iv_value == NULL) {
3894 GST_ERROR_OBJECT (qtdemux, "failed to get constant_iv");
3895 gst_structure_free (properties);
3896 return FALSE;
3897 }
3898 gst_structure_set_value (properties, "iv_size", constant_iv_size_value);
3899 gst_structure_remove_field (properties, "constant_iv_size");
3900 } else if (stream->protection_scheme_type == FOURCC_cenc) {
3901 GST_ERROR_OBJECT (qtdemux, "failed to get IV for sample %u", i);
3902 gst_structure_free (properties);
3903 return FALSE;
3904 }
3905 size = info_sizes[i];
3906 if (size > iv_size) {
3907 if (!gst_byte_reader_get_uint16_be (br, &n_subsamples)
3908 || !(n_subsamples > 0)) {
3909 gst_structure_free (properties);
3910 GST_ERROR_OBJECT (qtdemux,
3911 "failed to get subsample count for sample %u", i);
3912 return FALSE;
3913 }
3914 GST_LOG_OBJECT (qtdemux, "subsample count: %u", n_subsamples);
3915 if (!gst_byte_reader_dup_data (br, n_subsamples * 6, &data)) {
3916 GST_ERROR_OBJECT (qtdemux, "failed to get subsample data for sample %u",
3917 i);
3918 gst_structure_free (properties);
3919 return FALSE;
3920 }
3921 buf = gst_buffer_new_wrapped (data, n_subsamples * 6);
3922 if (!buf) {
3923 gst_structure_free (properties);
3924 return FALSE;
3925 }
3926 gst_structure_set (properties,
3927 "subsample_count", G_TYPE_UINT, n_subsamples,
3928 "subsamples", GST_TYPE_BUFFER, buf, NULL);
3929 gst_buffer_unref (buf);
3930 } else {
3931 gst_structure_set (properties, "subsample_count", G_TYPE_UINT, 0, NULL);
3932 }
3933 g_ptr_array_add (ss_info->crypto_info, properties);
3934 }
3935 return TRUE;
3936}
3937
3938/* Converts a UUID in raw byte form to a string representation, as defined in
3939 * RFC 4122. The caller takes ownership of the returned string and is
3940 * responsible for freeing it after use. */
3941static gchar *
3942qtdemux_uuid_bytes_to_string (gconstpointer uuid_bytes)
3943{
3944 const guint8 *uuid = (const guint8 *) uuid_bytes;
3945
3946 return g_strdup_printf ("%02x%02x%02x%02x-%02x%02x-%02x%02x-"
3947 "%02x%02x-%02x%02x%02x%02x%02x%02x",
3948 uuid[0], uuid[1], uuid[2], uuid[3],
3949 uuid[4], uuid[5], uuid[6], uuid[7],
3950 uuid[8], uuid[9], uuid[10], uuid[11],
3951 uuid[12], uuid[13], uuid[14], uuid[15]);
3952}
3953
3954/* Parses a Protection System Specific Header box (pssh), as defined in the
3955 * Common Encryption (cenc) standard (ISO/IEC 23001-7), which contains
3956 * information needed by a specific content protection system in order to
3957 * decrypt cenc-protected tracks. Returns TRUE if successful; FALSE
3958 * otherwise. */
3959static gboolean
3960qtdemux_parse_pssh (GstQTDemux * qtdemux, GNode * node)
3961{
3962 gchar *sysid_string;
3963 guint32 pssh_size = QT_UINT32 (node->data);
3964 GstBuffer *pssh = NULL;
3965 GstEvent *event = NULL;
3966 guint32 parent_box_type;
3967 gint i;
3968
3969 if (G_UNLIKELY (pssh_size < 32U)) {
3970 GST_ERROR_OBJECT (qtdemux, "invalid box size");
3971 return FALSE;
3972 }
3973
3974 sysid_string =
3975 qtdemux_uuid_bytes_to_string ((const guint8 *) node->data + 12);
3976
3977 gst_qtdemux_append_protection_system_id (qtdemux, sysid_string);
3978
3979 pssh = gst_buffer_new_memdup (node->data, pssh_size);
3980 GST_LOG_OBJECT (qtdemux, "cenc pssh size: %" G_GSIZE_FORMAT,
3981 gst_buffer_get_size (pssh));
3982
3983 parent_box_type = QT_FOURCC ((const guint8 *) node->parent->data + 4);
3984
3985 /* Push an event containing the pssh box onto the queues of all streams. */
3986 event = gst_event_new_protection (sysid_string, pssh,
3987 (parent_box_type == FOURCC_moov) ? "isobmff/moov" : "isobmff/moof");
3988 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
3989 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
3990 GST_TRACE_OBJECT (qtdemux,
3991 "adding protection event for stream %s and system %s",
3992 stream->stream_id, sysid_string);
3993 g_queue_push_tail (&stream->protection_scheme_event_queue,
3994 gst_event_ref (event));
3995 }
3996 g_free (sysid_string);
3997 gst_event_unref (event);
3998 gst_buffer_unref (pssh);
3999 return TRUE;
4000}
4001
4002static gboolean
4003qtdemux_parse_moof (GstQTDemux * qtdemux, const guint8 * buffer, guint length,
4004 guint64 moof_offset, QtDemuxStream * stream)
4005{
4006 GNode *moof_node, *traf_node, *tfhd_node, *trun_node, *tfdt_node, *mfhd_node;
4007 GNode *uuid_node;
4008 GstByteReader mfhd_data, trun_data, tfhd_data, tfdt_data;
4009 GNode *saiz_node, *saio_node, *pssh_node;
4010 GstByteReader saiz_data, saio_data;
4011 guint32 ds_size = 0, ds_duration = 0, ds_flags = 0;
4012 gint64 base_offset, running_offset;
4013 guint32 frag_num;
4014 GstClockTime min_dts = GST_CLOCK_TIME_NONE;
4015
4016 /* NOTE @stream ignored */
4017
4018 moof_node = g_node_new ((guint8 *) buffer);
4019 qtdemux_parse_node (qtdemux, moof_node, buffer, length);
4020 qtdemux_node_dump (qtdemux, moof_node);
4021
4022 /* Get fragment number from mfhd and check it's valid */
4023 mfhd_node =
4024 qtdemux_tree_get_child_by_type_full (moof_node, FOURCC_mfhd, &mfhd_data);
4025 if (mfhd_node == NULL)
4026 goto missing_mfhd;
4027 if (!qtdemux_parse_mfhd (qtdemux, &mfhd_data, &frag_num))
4028 goto fail;
4029 GST_DEBUG_OBJECT (qtdemux, "Fragment #%d", frag_num);
4030
4031 /* unknown base_offset to start with */
4032 base_offset = running_offset = -1;
4033 traf_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_traf);
4034 while (traf_node) {
4035 guint64 decode_time = 0;
4036
4037 /* Fragment Header node */
4038 tfhd_node =
4039 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfhd,
4040 &tfhd_data);
4041 if (!tfhd_node)
4042 goto missing_tfhd;
4043 if (!qtdemux_parse_tfhd (qtdemux, &tfhd_data, &stream, &ds_duration,
4044 &ds_size, &ds_flags, &base_offset))
4045 goto missing_tfhd;
4046
4047 /* The following code assumes at most a single set of sample auxiliary
4048 * data in the fragment (consisting of a saiz box and a corresponding saio
4049 * box); in theory, however, there could be multiple sets of sample
4050 * auxiliary data in a fragment. */
4051 saiz_node =
4052 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saiz,
4053 &saiz_data);
4054 if (saiz_node) {
4055 guint32 info_type = 0;
4056 guint64 offset = 0;
4057 guint32 info_type_parameter = 0;
4058
4059 g_free (qtdemux->cenc_aux_info_sizes);
4060
4061 qtdemux->cenc_aux_info_sizes =
4062 qtdemux_parse_saiz (qtdemux, stream, &saiz_data,
4063 &qtdemux->cenc_aux_sample_count);
4064 if (qtdemux->cenc_aux_info_sizes == NULL) {
4065 GST_ERROR_OBJECT (qtdemux, "failed to parse saiz box");
4066 goto fail;
4067 }
4068 saio_node =
4069 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saio,
4070 &saio_data);
4071 if (!saio_node) {
4072 GST_ERROR_OBJECT (qtdemux, "saiz box without a corresponding saio box");
4073 g_free (qtdemux->cenc_aux_info_sizes);
4074 qtdemux->cenc_aux_info_sizes = NULL;
4075 goto fail;
4076 }
4077
4078 if (G_UNLIKELY (!qtdemux_parse_saio (qtdemux, stream, &saio_data,
4079 &info_type, &info_type_parameter, &offset))) {
4080 GST_ERROR_OBJECT (qtdemux, "failed to parse saio box");
4081 g_free (qtdemux->cenc_aux_info_sizes);
4082 qtdemux->cenc_aux_info_sizes = NULL;
4083 goto fail;
4084 }
4085 if (base_offset > -1 && base_offset > qtdemux->moof_offset)
4086 offset += (guint64) (base_offset - qtdemux->moof_offset);
4087 if ((info_type == FOURCC_cenc || info_type == FOURCC_cbcs)
4088 && info_type_parameter == 0U) {
4089 GstByteReader br;
4090 if (offset > length) {
4091 GST_DEBUG_OBJECT (qtdemux, "cenc auxiliary info stored out of moof");
4092 qtdemux->cenc_aux_info_offset = offset;
4093 } else {
4094 gst_byte_reader_init (&br, buffer + offset, length - offset);
4095 if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
4096 qtdemux->cenc_aux_info_sizes,
4097 qtdemux->cenc_aux_sample_count)) {
4098 GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
4099 g_free (qtdemux->cenc_aux_info_sizes);
4100 qtdemux->cenc_aux_info_sizes = NULL;
4101 goto fail;
4102 }
4103 }
4104 }
4105 }
4106
4107 tfdt_node =
4108 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfdt,
4109 &tfdt_data);
4110 if (tfdt_node) {
4111 /* We'll use decode_time to interpolate timestamps
4112 * in case the input timestamps are missing */
4113 qtdemux_parse_tfdt (qtdemux, &tfdt_data, &decode_time);
4114
4115 GST_DEBUG_OBJECT (qtdemux, "decode time %" G_GINT64_FORMAT
4116 " (%" GST_TIME_FORMAT ")", decode_time,
4117 GST_TIME_ARGS (stream ? QTSTREAMTIME_TO_GSTTIME (stream,
4118 decode_time) : GST_CLOCK_TIME_NONE));
4119
4120 /* Discard the fragment buffer timestamp info to avoid using it.
4121 * Rely on tfdt instead as it is more accurate than the timestamp
4122 * that is fetched from a manifest/playlist and is usually
4123 * less accurate. */
4124 qtdemux->fragment_start = -1;
4125 }
4126
4127 if (G_UNLIKELY (!stream)) {
4128 /* we lost track of offset, we'll need to regain it,
4129 * but can delay complaining until later or avoid doing so altogether */
4130 base_offset = -2;
4131 goto next;
4132 }
4133 if (G_UNLIKELY (base_offset < -1))
4134 goto lost_offset;
4135
4136 min_dts = MIN (min_dts, QTSTREAMTIME_TO_GSTTIME (stream, decode_time));
4137
4138 if (!qtdemux->pullbased) {
4139 /* Sample tables can grow enough to be problematic if the system memory
4140 * is very low (e.g. embedded devices) and the videos very long
4141 * (~8 MiB/hour for 25-30 fps video + typical AAC audio frames).
4142 * Fortunately, we can easily discard them for each new fragment when
4143 * we know qtdemux will not receive seeks outside of the current fragment.
4144 * adaptivedemux honors this assumption.
4145 * This optimization is also useful for applications that use qtdemux as
4146 * a push-based simple demuxer, like Media Source Extensions. */
4147 gst_qtdemux_stream_flush_samples_data (stream);
4148 }
4149
4150 /* initialise moof sample data */
4151 stream->n_samples_moof = 0;
4152 stream->duration_last_moof = stream->duration_moof;
4153 stream->duration_moof = 0;
4154
4155 /* Track Run node */
4156 trun_node =
4157 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_trun,
4158 &trun_data);
4159 while (trun_node) {
4160 qtdemux_parse_trun (qtdemux, &trun_data, stream,
4161 ds_duration, ds_size, ds_flags, moof_offset, length, &base_offset,
4162 &running_offset, decode_time, (tfdt_node != NULL));
4163 /* iterate all siblings */
4164 trun_node = qtdemux_tree_get_sibling_by_type_full (trun_node, FOURCC_trun,
4165 &trun_data);
4166 /* don't use tfdt for subsequent trun as it only refers to the first */
4167 tfdt_node = NULL;
4168 }
4169
4170 uuid_node = qtdemux_tree_get_child_by_type (traf_node, FOURCC_uuid);
4171 if (uuid_node) {
4172 guint8 *uuid_buffer = (guint8 *) uuid_node->data;
4173 guint32 box_length = QT_UINT32 (uuid_buffer);
4174
4175 qtdemux_parse_uuid (qtdemux, uuid_buffer, box_length);
4176 }
4177
4178 /* if no new base_offset provided for next traf,
4179 * base is end of current traf */
4180 base_offset = running_offset;
4181 running_offset = -1;
4182
4183 if (stream->n_samples_moof && stream->duration_moof)
4184 stream->new_caps = TRUE;
4185
4186 next:
4187 /* iterate all siblings */
4188 traf_node = qtdemux_tree_get_sibling_by_type (traf_node, FOURCC_traf);
4189 }
4190
4191 /* parse any protection system info */
4192 pssh_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_pssh);
4193 while (pssh_node) {
4194 GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
4195 qtdemux_parse_pssh (qtdemux, pssh_node);
4196 pssh_node = qtdemux_tree_get_sibling_by_type (pssh_node, FOURCC_pssh);
4197 }
4198
4199 if (!qtdemux->upstream_format_is_time
4200 && qtdemux->variant != VARIANT_MSE_BYTESTREAM
4201 && !qtdemux->first_moof_already_parsed
4202 && !qtdemux->received_seek && GST_CLOCK_TIME_IS_VALID (min_dts)
4203 && min_dts != 0) {
4204 /* Unless the user has explicitly requested another seek, perform an
4205 * internal seek to the time specified in the tfdt.
4206 *
4207 * This way if the user opens a file where the first tfdt is 1 hour
4208 * into the presentation, they will not have to wait 1 hour for run
4209 * time to catch up and actual playback to start. */
4210 gint i;
4211
4212 GST_DEBUG_OBJECT (qtdemux, "First fragment has a non-zero tfdt, "
4213 "performing an internal seek to %" GST_TIME_FORMAT,
4214 GST_TIME_ARGS (min_dts));
4215
4216 qtdemux->segment.start = min_dts;
4217 qtdemux->segment.time = qtdemux->segment.position = min_dts;
4218
4219 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
4220 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
4221 stream->time_position = min_dts;
4222 }
4223
4224 /* Before this code was run a segment was already sent when the moov was
4225 * parsed... which is OK -- some apps (mostly tests) expect a segment to
4226 * be emitted after a moov, and we can emit a second segment anyway for
4227 * special cases like this. */
4228 qtdemux->need_segment = TRUE;
4229 }
4230
4231 qtdemux->first_moof_already_parsed = TRUE;
4232
4233 g_node_destroy (moof_node);
4234 return TRUE;
4235
4236missing_tfhd:
4237 {
4238 GST_DEBUG_OBJECT (qtdemux, "missing tfhd box");
4239 goto fail;
4240 }
4241missing_mfhd:
4242 {
4243 GST_DEBUG_OBJECT (qtdemux, "Missing mfhd box");
4244 goto fail;
4245 }
4246lost_offset:
4247 {
4248 GST_DEBUG_OBJECT (qtdemux, "lost offset");
4249 goto fail;
4250 }
4251fail:
4252 {
4253 g_node_destroy (moof_node);
4254 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4255 (_("This file is corrupt and cannot be played.")), (NULL));
4256 return FALSE;
4257 }
4258}
4259
4260#if 0
4261/* might be used if some day we actually use mfra & co
4262 * for random access to fragments,
4263 * but that will require quite some modifications and much less relying
4264 * on a sample array */
4265#endif
4266
4267static gboolean
4268qtdemux_parse_tfra (GstQTDemux * qtdemux, GNode * tfra_node)
4269{
4270 QtDemuxStream *stream;
4271 guint32 ver_flags, track_id, len, num_entries, i;
4272 guint value_size, traf_size, trun_size, sample_size;
4273 guint64 time = 0, moof_offset = 0;
4274#if 0
4275 GstBuffer *buf = NULL;
4276 GstFlowReturn ret;
4277#endif
4278 GstByteReader tfra;
4279
4280 gst_byte_reader_init (&tfra, tfra_node->data, QT_UINT32 (tfra_node->data));
4281
4282 if (!gst_byte_reader_skip (&tfra, 8))
4283 return FALSE;
4284
4285 if (!gst_byte_reader_get_uint32_be (&tfra, &ver_flags))
4286 return FALSE;
4287
4288 if (!gst_byte_reader_get_uint32_be (&tfra, &track_id)
4289 || !gst_byte_reader_get_uint32_be (&tfra, &len)
4290 || !gst_byte_reader_get_uint32_be (&tfra, &num_entries))
4291 return FALSE;
4292
4293 GST_DEBUG_OBJECT (qtdemux, "parsing tfra box for track id %u", track_id);
4294
4295 stream = qtdemux_find_stream (qtdemux, track_id);
4296 if (stream == NULL)
4297 goto unknown_trackid;
4298
4299 value_size = ((ver_flags >> 24) == 1) ? sizeof (guint64) : sizeof (guint32);
4300 sample_size = (len & 3) + 1;
4301 trun_size = ((len & 12) >> 2) + 1;
4302 traf_size = ((len & 48) >> 4) + 1;
4303
4304 GST_DEBUG_OBJECT (qtdemux, "%u entries, sizes: value %u, traf %u, trun %u, "
4305 "sample %u", num_entries, value_size, traf_size, trun_size, sample_size);
4306
4307 if (num_entries == 0)
4308 goto no_samples;
4309
4310 if (!qt_atom_parser_has_chunks (&tfra, num_entries,
4311 value_size + value_size + traf_size + trun_size + sample_size))
4312 goto corrupt_file;
4313
4314 g_free (stream->ra_entries);
4315 stream->ra_entries = g_new (QtDemuxRandomAccessEntry, num_entries);
4316 stream->n_ra_entries = num_entries;
4317
4318 for (i = 0; i < num_entries; i++) {
4319 qt_atom_parser_get_offset (&tfra, value_size, &time);
4320 qt_atom_parser_get_offset (&tfra, value_size, &moof_offset);
4321 qt_atom_parser_get_uint_with_size_unchecked (&tfra, traf_size);
4322 qt_atom_parser_get_uint_with_size_unchecked (&tfra, trun_size);
4323 qt_atom_parser_get_uint_with_size_unchecked (&tfra, sample_size);
4324
4325 time = QTSTREAMTIME_TO_GSTTIME (stream, time);
4326
4327 GST_LOG_OBJECT (qtdemux, "fragment time: %" GST_TIME_FORMAT ", "
4328 " moof_offset: %" G_GUINT64_FORMAT, GST_TIME_ARGS (time), moof_offset);
4329
4330 stream->ra_entries[i].ts = time;
4331 stream->ra_entries[i].moof_offset = moof_offset;
4332
4333 /* don't want to go through the entire file and read all moofs at startup */
4334#if 0
4335 ret = gst_qtdemux_pull_atom (qtdemux, moof_offset, 0, &buf);
4336 if (ret != GST_FLOW_OK)
4337 goto corrupt_file;
4338 qtdemux_parse_moof (qtdemux, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf),
4339 moof_offset, stream);
4340 gst_buffer_unref (buf);
4341#endif
4342 }
4343
4344 check_update_duration (qtdemux, time);
4345
4346 return TRUE;
4347
4348/* ERRORS */
4349unknown_trackid:
4350 {
4351 GST_WARNING_OBJECT (qtdemux, "Couldn't find stream for track %u", track_id);
4352 return FALSE;
4353 }
4354corrupt_file:
4355 {
4356 GST_WARNING_OBJECT (qtdemux, "broken traf box, ignoring");
4357 return FALSE;
4358 }
4359no_samples:
4360 {
4361 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
4362 return FALSE;
4363 }
4364}
4365
4366static gboolean
4367qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux)
4368{
4369 GstMapInfo mfro_map = GST_MAP_INFO_INIT;
4370 GstMapInfo mfra_map = GST_MAP_INFO_INIT;
4371 GstBuffer *mfro = NULL, *mfra = NULL;
4372 GstFlowReturn flow;
4373 gboolean ret = FALSE;
4374 GNode *mfra_node, *tfra_node;
4375 guint64 mfra_offset = 0;
4376 guint32 fourcc, mfra_size;
4377 gint64 len;
4378
4379 /* query upstream size in bytes */
4380 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &len))
4381 goto size_query_failed;
4382
4383 /* mfro box should be at the very end of the file */
4384 flow = gst_qtdemux_pull_atom (qtdemux, len - 16, 16, &mfro);
4385 if (flow != GST_FLOW_OK)
4386 goto exit;
4387
4388 gst_buffer_map (mfro, &mfro_map, GST_MAP_READ);
4389
4390 fourcc = QT_FOURCC (mfro_map.data + 4);
4391 if (fourcc != FOURCC_mfro)
4392 goto exit;
4393
4394 GST_INFO_OBJECT (qtdemux, "Found mfro box");
4395 if (mfro_map.size < 16)
4396 goto invalid_mfro_size;
4397
4398 mfra_size = QT_UINT32 (mfro_map.data + 12);
4399 if (mfra_size >= len)
4400 goto invalid_mfra_size;
4401
4402 mfra_offset = len - mfra_size;
4403
4404 GST_INFO_OBJECT (qtdemux, "mfra offset: %" G_GUINT64_FORMAT ", size %u",
4405 mfra_offset, mfra_size);
4406
4407 /* now get and parse mfra box */
4408 flow = gst_qtdemux_pull_atom (qtdemux, mfra_offset, mfra_size, &mfra);
4409 if (flow != GST_FLOW_OK)
4410 goto broken_file;
4411
4412 gst_buffer_map (mfra, &mfra_map, GST_MAP_READ);
4413
4414 mfra_node = g_node_new ((guint8 *) mfra_map.data);
4415 qtdemux_parse_node (qtdemux, mfra_node, mfra_map.data, mfra_map.size);
4416
4417 tfra_node = qtdemux_tree_get_child_by_type (mfra_node, FOURCC_tfra);
4418
4419 while (tfra_node) {
4420 qtdemux_parse_tfra (qtdemux, tfra_node);
4421 /* iterate all siblings */
4422 tfra_node = qtdemux_tree_get_sibling_by_type (tfra_node, FOURCC_tfra);
4423 }
4424 g_node_destroy (mfra_node);
4425
4426 GST_INFO_OBJECT (qtdemux, "parsed movie fragment random access box (mfra)");
4427 ret = TRUE;
4428
4429exit:
4430
4431 if (mfro) {
4432 if (mfro_map.memory != NULL)
4433 gst_buffer_unmap (mfro, &mfro_map);
4434 gst_buffer_unref (mfro);
4435 }
4436 if (mfra) {
4437 if (mfra_map.memory != NULL)
4438 gst_buffer_unmap (mfra, &mfra_map);
4439 gst_buffer_unref (mfra);
4440 }
4441 return ret;
4442
4443/* ERRORS */
4444size_query_failed:
4445 {
4446 GST_WARNING_OBJECT (qtdemux, "could not query upstream size");
4447 goto exit;
4448 }
4449invalid_mfro_size:
4450 {
4451 GST_WARNING_OBJECT (qtdemux, "mfro size is too small");
4452 goto exit;
4453 }
4454invalid_mfra_size:
4455 {
4456 GST_WARNING_OBJECT (qtdemux, "mfra_size in mfro box is invalid");
4457 goto exit;
4458 }
4459broken_file:
4460 {
4461 GST_WARNING_OBJECT (qtdemux, "bogus mfra offset or size, broken file");
4462 goto exit;
4463 }
4464}
4465
4466static guint64
4467add_offset (guint64 offset, guint64 advance)
4468{
4469 /* Avoid 64-bit overflow by clamping */
4470 if (offset > G_MAXUINT64 - advance)
4471 return G_MAXUINT64;
4472 return offset + advance;
4473}
4474
4475static GstFlowReturn
4476gst_qtdemux_loop_state_header (GstQTDemux * qtdemux)
4477{
4478 guint64 length = 0;
4479 guint32 fourcc = 0;
4480 GstBuffer *buf = NULL;
4481 GstFlowReturn ret = GST_FLOW_OK;
4482 guint64 cur_offset = qtdemux->offset;
4483 GstMapInfo map;
4484
4485 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, 16, &buf);
4486 if (G_UNLIKELY (ret != GST_FLOW_OK))
4487 goto beach;
4488 gst_buffer_map (buf, &map, GST_MAP_READ);
4489 if (G_LIKELY (map.size >= 8))
4490 extract_initial_length_and_fourcc (map.data, map.size, &length, &fourcc);
4491 gst_buffer_unmap (buf, &map);
4492 gst_buffer_unref (buf);
4493
4494 /* maybe we already got most we needed, so only consider this eof */
4495 if (G_UNLIKELY (length == 0)) {
4496 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
4497 (_("Invalid atom size.")),
4498 ("Header atom '%" GST_FOURCC_FORMAT "' has empty length",
4499 GST_FOURCC_ARGS (fourcc)));
4500 ret = GST_FLOW_EOS;
4501 goto beach;
4502 }
4503
4504 switch (fourcc) {
4505 case FOURCC_moof:
4506 /* record for later parsing when needed */
4507 if (!qtdemux->moof_offset) {
4508 qtdemux->moof_offset = qtdemux->offset;
4509 }
4510 if (qtdemux_pull_mfro_mfra (qtdemux)) {
4511 /* FIXME */
4512 } else {
4513 qtdemux->offset += length; /* skip moof and keep going */
4514 }
4515 if (qtdemux->got_moov) {
4516 GST_INFO_OBJECT (qtdemux, "moof header, got moov, done with headers");
4517 ret = GST_FLOW_EOS;
4518 goto beach;
4519 }
4520 break;
4521 case FOURCC_mdat:
4522 case FOURCC_free:
4523 case FOURCC_skip:
4524 case FOURCC_wide:
4525 case FOURCC_PICT:
4526 case FOURCC_pnot:
4527 {
4528 GST_LOG_OBJECT (qtdemux,
4529 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
4530 GST_FOURCC_ARGS (fourcc), cur_offset);
4531 qtdemux->offset = add_offset (qtdemux->offset, length);
4532 break;
4533 }
4534 case FOURCC_moov:
4535 {
4536 GstBuffer *moov = NULL;
4537
4538 if (qtdemux->got_moov) {
4539 GST_DEBUG_OBJECT (qtdemux, "Skipping moov atom as we have one already");
4540 qtdemux->offset = add_offset (qtdemux->offset, length);
4541 goto beach;
4542 }
4543
4544 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, length, &moov);
4545 if (ret != GST_FLOW_OK)
4546 goto beach;
4547 gst_buffer_map (moov, &map, GST_MAP_READ);
4548
4549 if (length != map.size) {
4550 /* Some files have a 'moov' atom at the end of the file which contains
4551 * a terminal 'free' atom where the body of the atom is missing.
4552 * Check for, and permit, this special case.
4553 */
4554 if (map.size >= 8) {
4555 guint8 *final_data = map.data + (map.size - 8);
4556 guint32 final_length = QT_UINT32 (final_data);
4557 guint32 final_fourcc = QT_FOURCC (final_data + 4);
4558
4559 if (final_fourcc == FOURCC_free
4560 && map.size + final_length - 8 == length) {
4561 /* Ok, we've found that special case. Allocate a new buffer with
4562 * that free atom actually present. */
4563 GstBuffer *newmoov = gst_buffer_new_and_alloc (length);
4564 gst_buffer_fill (newmoov, 0, map.data, map.size);
4565 gst_buffer_memset (newmoov, map.size, 0, final_length - 8);
4566 gst_buffer_unmap (moov, &map);
4567 gst_buffer_unref (moov);
4568 moov = newmoov;
4569 gst_buffer_map (moov, &map, GST_MAP_READ);
4570 }
4571 }
4572 }
4573
4574 if (length != map.size) {
4575 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4576 (_("This file is incomplete and cannot be played.")),
4577 ("We got less than expected (received %" G_GSIZE_FORMAT
4578 ", wanted %u, offset %" G_GUINT64_FORMAT ")", map.size,
4579 (guint) length, cur_offset));
4580 gst_buffer_unmap (moov, &map);
4581 gst_buffer_unref (moov);
4582 ret = GST_FLOW_ERROR;
4583 goto beach;
4584 }
4585 qtdemux->offset += length;
4586
4587 qtdemux_parse_moov (qtdemux, map.data, length);
4588 qtdemux_node_dump (qtdemux, qtdemux->moov_node);
4589
4590 qtdemux_parse_tree (qtdemux);
4591 if (qtdemux->moov_node_compressed) {
4592 g_node_destroy (qtdemux->moov_node_compressed);
4593 g_free (qtdemux->moov_node->data);
4594 }
4595 qtdemux->moov_node_compressed = NULL;
4596 g_node_destroy (qtdemux->moov_node);
4597 qtdemux->moov_node = NULL;
4598 gst_buffer_unmap (moov, &map);
4599 gst_buffer_unref (moov);
4600 qtdemux->got_moov = TRUE;
4601
4602 break;
4603 }
4604 case FOURCC_ftyp:
4605 {
4606 GstBuffer *ftyp = NULL;
4607
4608 /* extract major brand; might come in handy for ISO vs QT issues */
4609 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &ftyp);
4610 if (ret != GST_FLOW_OK)
4611 goto beach;
4612 qtdemux->offset += length;
4613 gst_buffer_map (ftyp, &map, GST_MAP_READ);
4614 qtdemux_parse_ftyp (qtdemux, map.data, map.size);
4615 gst_buffer_unmap (ftyp, &map);
4616 gst_buffer_unref (ftyp);
4617 break;
4618 }
4619 case FOURCC_uuid:
4620 {
4621 GstBuffer *uuid = NULL;
4622
4623 /* uuid are extension atoms */
4624 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &uuid);
4625 if (ret != GST_FLOW_OK)
4626 goto beach;
4627 qtdemux->offset += length;
4628 gst_buffer_map (uuid, &map, GST_MAP_READ);
4629 qtdemux_parse_uuid (qtdemux, map.data, map.size);
4630 gst_buffer_unmap (uuid, &map);
4631 gst_buffer_unref (uuid);
4632 break;
4633 }
4634 case FOURCC_sidx:
4635 {
4636 GstBuffer *sidx = NULL;
4637 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &sidx);
4638 if (ret != GST_FLOW_OK)
4639 goto beach;
4640 qtdemux->offset += length;
4641 gst_buffer_map (sidx, &map, GST_MAP_READ);
4642 qtdemux_parse_sidx (qtdemux, map.data, map.size);
4643 gst_buffer_unmap (sidx, &map);
4644 gst_buffer_unref (sidx);
4645 break;
4646 }
4647 default:
4648 {
4649 GstBuffer *unknown = NULL;
4650
4651 GST_LOG_OBJECT (qtdemux,
4652 "unknown %08x '%" GST_FOURCC_FORMAT "' of size %" G_GUINT64_FORMAT
4653 " at %" G_GUINT64_FORMAT, fourcc, GST_FOURCC_ARGS (fourcc), length,
4654 cur_offset);
4655 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &unknown);
4656 if (ret != GST_FLOW_OK)
4657 goto beach;
4658 gst_buffer_map (unknown, &map, GST_MAP_READ);
4659 GST_MEMDUMP ("Unknown tag", map.data, map.size);
4660 gst_buffer_unmap (unknown, &map);
4661 gst_buffer_unref (unknown);
4662 qtdemux->offset += length;
4663 break;
4664 }
4665 }
4666
4667beach:
4668 if (ret == GST_FLOW_EOS && (qtdemux->got_moov || qtdemux->media_caps)) {
4669 /* digested all data, show what we have */
4670 qtdemux_prepare_streams (qtdemux);
4671 QTDEMUX_EXPOSE_LOCK (qtdemux);
4672 ret = qtdemux_expose_streams (qtdemux);
4673 QTDEMUX_EXPOSE_UNLOCK (qtdemux);
4674
4675 qtdemux->state = QTDEMUX_STATE_MOVIE;
4676 GST_DEBUG_OBJECT (qtdemux, "switching state to STATE_MOVIE (%d)",
4677 qtdemux->state);
4678 return ret;
4679 }
4680 return ret;
4681}
4682
4683/* Seeks to the previous keyframe of the indexed stream and
4684 * aligns other streams with respect to the keyframe timestamp
4685 * of indexed stream. Only called in case of Reverse Playback
4686 */
4687static GstFlowReturn
4688gst_qtdemux_seek_to_previous_keyframe (GstQTDemux * qtdemux)
4689{
4690 guint32 seg_idx = 0, k_index = 0;
4691 guint32 ref_seg_idx, ref_k_index;
4692 GstClockTime k_pos = 0, last_stop = 0;
4693 QtDemuxSegment *seg = NULL;
4694 QtDemuxStream *ref_str = NULL;
4695 guint64 seg_media_start_mov; /* segment media start time in mov format */
4696 guint64 target_ts;
4697 gint i;
4698
4699 /* Now we choose an arbitrary stream, get the previous keyframe timestamp
4700 * and finally align all the other streams on that timestamp with their
4701 * respective keyframes */
4702 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
4703 QtDemuxStream *str = QTDEMUX_NTH_STREAM (qtdemux, i);
4704
4705 /* No candidate yet, take the first stream */
4706 if (!ref_str) {
4707 ref_str = str;
4708 continue;
4709 }
4710
4711 /* So that stream has a segment, we prefer video streams */
4712 if (str->subtype == FOURCC_vide) {
4713 ref_str = str;
4714 break;
4715 }
4716 }
4717
4718 if (G_UNLIKELY (!ref_str)) {
4719 GST_DEBUG_OBJECT (qtdemux, "couldn't find any stream");
4720 goto eos;
4721 }
4722
4723 if (G_UNLIKELY (!ref_str->from_sample)) {
4724 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of the file");
4725 goto eos;
4726 }
4727
4728 /* So that stream has been playing from from_sample to to_sample. We will
4729 * get the timestamp of the previous sample and search for a keyframe before
4730 * that. For audio streams we do an arbitrary jump in the past (10 samples) */
4731 if (ref_str->subtype == FOURCC_vide) {
4732 k_index = gst_qtdemux_find_keyframe (qtdemux, ref_str,
4733 ref_str->from_sample - 1, FALSE);
4734 } else {
4735 if (ref_str->from_sample >= 10)
4736 k_index = ref_str->from_sample - 10;
4737 else
4738 k_index = 0;
4739 }
4740
4741 target_ts =
4742 ref_str->samples[k_index].timestamp +
4743 ref_str->samples[k_index].pts_offset;
4744
4745 /* get current segment for that stream */
4746 seg = &ref_str->segments[ref_str->segment_index];
4747 /* Use segment start in original timescale for comparisons */
4748 seg_media_start_mov = seg->trak_media_start;
4749
4750 GST_LOG_OBJECT (qtdemux, "keyframe index %u ts %" G_GUINT64_FORMAT
4751 " seg start %" G_GUINT64_FORMAT " %" GST_TIME_FORMAT,
4752 k_index, target_ts, seg_media_start_mov,
4753 GST_TIME_ARGS (seg->media_start));
4754
4755 /* Crawl back through segments to find the one containing this I frame */
4756 while (target_ts < seg_media_start_mov) {
4757 GST_DEBUG_OBJECT (qtdemux,
4758 "keyframe position (sample %u) is out of segment %u " " target %"
4759 G_GUINT64_FORMAT " seg start %" G_GUINT64_FORMAT, k_index,
4760 ref_str->segment_index, target_ts, seg_media_start_mov);
4761
4762 if (G_UNLIKELY (!ref_str->segment_index)) {
4763 /* Reached first segment, let's consider it's EOS */
4764 goto eos;
4765 }
4766 ref_str->segment_index--;
4767 seg = &ref_str->segments[ref_str->segment_index];
4768 /* Use segment start in original timescale for comparisons */
4769 seg_media_start_mov = seg->trak_media_start;
4770 }
4771 /* Calculate time position of the keyframe and where we should stop */
4772 k_pos =
4773 QTSTREAMTIME_TO_GSTTIME (ref_str,
4774 target_ts - seg->trak_media_start) + seg->time;
4775 last_stop =
4776 QTSTREAMTIME_TO_GSTTIME (ref_str,
4777 ref_str->samples[ref_str->from_sample].timestamp -
4778 seg->trak_media_start) + seg->time;
4779
4780 GST_DEBUG_OBJECT (qtdemux, "preferred stream played from sample %u, "
4781 "now going to sample %u (pts %" GST_TIME_FORMAT ")", ref_str->from_sample,
4782 k_index, GST_TIME_ARGS (k_pos));
4783
4784 /* Set last_stop with the keyframe timestamp we pushed of that stream */
4785 qtdemux->segment.position = last_stop;
4786 GST_DEBUG_OBJECT (qtdemux, "last_stop now is %" GST_TIME_FORMAT,
4787 GST_TIME_ARGS (last_stop));
4788
4789 if (G_UNLIKELY (last_stop < qtdemux->segment.start)) {
4790 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of segment");
4791 goto eos;
4792 }
4793
4794 ref_seg_idx = ref_str->segment_index;
4795 ref_k_index = k_index;
4796
4797 /* Align them all on this */
4798 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
4799 guint32 index = 0;
4800 GstClockTime seg_time = 0;
4801 QtDemuxStream *str = QTDEMUX_NTH_STREAM (qtdemux, i);
4802
4803 /* aligning reference stream again might lead to backing up to yet another
4804 * keyframe (due to timestamp rounding issues),
4805 * potentially putting more load on downstream; so let's try to avoid */
4806 if (str == ref_str) {
4807 seg_idx = ref_seg_idx;
4808 seg = &str->segments[seg_idx];
4809 k_index = ref_k_index;
4810 GST_DEBUG_OBJECT (qtdemux, "reference track-id %u segment %d, "
4811 "sample at index %d", str->track_id, ref_str->segment_index, k_index);
4812 } else {
4813 seg_idx = gst_qtdemux_find_segment (qtdemux, str, k_pos);
4814 GST_DEBUG_OBJECT (qtdemux,
4815 "track-id %u align segment %d for keyframe pos %" GST_TIME_FORMAT,
4816 str->track_id, seg_idx, GST_TIME_ARGS (k_pos));
4817
4818 /* get segment and time in the segment */
4819 seg = &str->segments[seg_idx];
4820 seg_time = k_pos - seg->time;
4821
4822 /* get the media time in the segment.
4823 * No adjustment for empty "filler" segments */
4824 if (seg->media_start != GST_CLOCK_TIME_NONE)
4825 seg_time += seg->media_start;
4826
4827 /* get the index of the sample with media time */
4828 index = gst_qtdemux_find_index_linear (qtdemux, str, seg_time);
4829 GST_DEBUG_OBJECT (qtdemux,
4830 "track-id %u sample for %" GST_TIME_FORMAT " at %u", str->track_id,
4831 GST_TIME_ARGS (seg_time), index);
4832
4833 /* find previous keyframe */
4834 k_index = gst_qtdemux_find_keyframe (qtdemux, str, index, FALSE);
4835 }
4836
4837 /* Remember until where we want to go */
4838 str->to_sample = str->from_sample - 1;
4839 /* Define our time position */
4840 target_ts =
4841 str->samples[k_index].timestamp + str->samples[k_index].pts_offset;
4842 str->time_position = QTSTREAMTIME_TO_GSTTIME (str, target_ts) + seg->time;
4843 if (seg->media_start != GST_CLOCK_TIME_NONE)
4844 str->time_position -= seg->media_start;
4845
4846 /* Now seek back in time */
4847 gst_qtdemux_move_stream (qtdemux, str, k_index);
4848 GST_DEBUG_OBJECT (qtdemux, "track-id %u keyframe at %u, time position %"
4849 GST_TIME_FORMAT " playing from sample %u to %u", str->track_id, k_index,
4850 GST_TIME_ARGS (str->time_position), str->from_sample, str->to_sample);
4851 }
4852
4853 return GST_FLOW_OK;
4854
4855eos:
4856 return GST_FLOW_EOS;
4857}
4858
4859/*
4860 * Gets the current qt segment start, stop and position for the
4861 * given time offset. This is used in update_segment()
4862 */
4863static void
4864gst_qtdemux_stream_segment_get_boundaries (GstQTDemux * qtdemux,
4865 QtDemuxStream * stream, GstClockTime offset,
4866 GstClockTime * _start, GstClockTime * _stop, GstClockTime * _time)
4867{
4868 GstClockTime seg_time;
4869 GstClockTime start, stop, time;
4870 QtDemuxSegment *segment;
4871
4872 segment = &stream->segments[stream->segment_index];
4873
4874 /* get time in this segment */
4875 seg_time = (offset - segment->time) * segment->rate;
4876
4877 GST_LOG_OBJECT (stream->pad, "seg_time %" GST_TIME_FORMAT,
4878 GST_TIME_ARGS (seg_time));
4879
4880 if (G_UNLIKELY (seg_time > segment->duration)) {
4881 GST_LOG_OBJECT (stream->pad,
4882 "seg_time > segment->duration %" GST_TIME_FORMAT,
4883 GST_TIME_ARGS (segment->duration));
4884 seg_time = segment->duration;
4885 }
4886
4887 /* qtdemux->segment.stop is in outside-time-realm, whereas
4888 * segment->media_stop is in track-time-realm.
4889 *
4890 * In order to compare the two, we need to bring segment.stop
4891 * into the track-time-realm
4892 *
4893 * FIXME - does this comment still hold? Don't see any conversion here */
4894
4895 stop = qtdemux->segment.stop;
4896 if (stop == GST_CLOCK_TIME_NONE)
4897 stop = qtdemux->segment.duration;
4898 if (stop == GST_CLOCK_TIME_NONE)
4899 stop = segment->media_stop;
4900 else
4901 stop =
4902 MIN (segment->media_stop, stop - segment->time + segment->media_start);
4903
4904 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
4905 start = segment->time + seg_time;
4906 time = offset;
4907 stop = start - seg_time + segment->duration;
4908 } else if (qtdemux->segment.rate >= 0) {
4909 start = MIN (segment->media_start + seg_time, stop);
4910 time = offset;
4911 } else {
4912 if (segment->media_start >= qtdemux->segment.start) {
4913 time = segment->time;
4914 } else {
4915 time = segment->time + (qtdemux->segment.start - segment->media_start);
4916 }
4917
4918 start = MAX (segment->media_start, qtdemux->segment.start);
4919 stop = MIN (segment->media_start + seg_time, stop);
4920 }
4921
4922 *_start = start;
4923 *_stop = stop;
4924 *_time = time;
4925}
4926
4927/*
4928 * Updates the qt segment used for the stream and pushes a new segment event
4929 * downstream on this stream's pad.
4930 */
4931static gboolean
4932gst_qtdemux_stream_update_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
4933 gint seg_idx, GstClockTime offset, GstClockTime * _start,
4934 GstClockTime * _stop)
4935{
4936 QtDemuxSegment *segment;
4937 GstClockTime start = 0, stop = GST_CLOCK_TIME_NONE, time = 0;
4938 gdouble rate;
4939 GstEvent *event;
4940
4941 /* update the current segment */
4942 stream->segment_index = seg_idx;
4943
4944 /* get the segment */
4945 segment = &stream->segments[seg_idx];
4946
4947 if (G_UNLIKELY (offset < segment->time)) {
4948 GST_WARNING_OBJECT (stream->pad, "offset < segment->time %" GST_TIME_FORMAT,
4949 GST_TIME_ARGS (segment->time));
4950 return FALSE;
4951 }
4952
4953 /* segment lies beyond total indicated duration */
4954 if (G_UNLIKELY (qtdemux->segment.duration != GST_CLOCK_TIME_NONE &&
4955 segment->time > qtdemux->segment.duration)) {
4956 GST_WARNING_OBJECT (stream->pad, "file duration %" GST_TIME_FORMAT
4957 " < segment->time %" GST_TIME_FORMAT,
4958 GST_TIME_ARGS (qtdemux->segment.duration),
4959 GST_TIME_ARGS (segment->time));
4960 return FALSE;
4961 }
4962
4963 gst_qtdemux_stream_segment_get_boundaries (qtdemux, stream, offset,
4964 &start, &stop, &time);
4965
4966 GST_DEBUG_OBJECT (stream->pad, "new segment %d from %" GST_TIME_FORMAT
4967 " to %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT, seg_idx,
4968 GST_TIME_ARGS (start), GST_TIME_ARGS (stop), GST_TIME_ARGS (time));
4969
4970 /* combine global rate with that of the segment */
4971 rate = segment->rate * qtdemux->segment.rate;
4972
4973 /* Copy flags from main segment */
4974 stream->segment.flags = qtdemux->segment.flags;
4975
4976 /* update the segment values used for clipping */
4977 stream->segment.offset = qtdemux->segment.offset;
4978 stream->segment.base = qtdemux->segment.base + stream->accumulated_base;
4979 stream->segment.applied_rate = qtdemux->segment.applied_rate;
4980 stream->segment.rate = rate;
4981 stream->segment.start = start + QTSTREAMTIME_TO_GSTTIME (stream,
4982 stream->cslg_shift);
4983 if (stop != -1)
4984 stream->segment.stop = stop + QTSTREAMTIME_TO_GSTTIME (stream,
4985 stream->cslg_shift);
4986 else
4987 stream->segment.stop = stop;
4988 stream->segment.time = time;
4989 stream->segment.position = stream->segment.start;
4990
4991 GST_DEBUG_OBJECT (stream->pad, "New segment: %" GST_SEGMENT_FORMAT,
4992 &stream->segment);
4993
4994 /* now prepare and send the segment */
4995 if (stream->pad) {
4996 event = gst_event_new_segment (&stream->segment);
4997 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID) {
4998 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
4999 }
5000 gst_pad_push_event (stream->pad, event);
5001 /* assume we can send more data now */
5002 GST_PAD_LAST_FLOW_RETURN (stream->pad) = GST_FLOW_OK;
5003 /* clear to send tags on this pad now */
5004 gst_qtdemux_push_tags (qtdemux, stream);
5005 }
5006
5007 if (_start)
5008 *_start = start;
5009 if (_stop)
5010 *_stop = stop;
5011
5012 return TRUE;
5013}
5014
5015/* activate the given segment number @seg_idx of @stream at time @offset.
5016 * @offset is an absolute global position over all the segments.
5017 *
5018 * This will push out a NEWSEGMENT event with the right values and
5019 * position the stream index to the first decodable sample before
5020 * @offset.
5021 */
5022static gboolean
5023gst_qtdemux_activate_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
5024 guint32 seg_idx, GstClockTime offset)
5025{
5026 QtDemuxSegment *segment;
5027 guint32 index, kf_index;
5028 GstClockTime start = 0, stop = GST_CLOCK_TIME_NONE;
5029
5030 GST_LOG_OBJECT (stream->pad, "activate segment %d, offset %" GST_TIME_FORMAT,
5031 seg_idx, GST_TIME_ARGS (offset));
5032
5033 if (!gst_qtdemux_stream_update_segment (qtdemux, stream, seg_idx, offset,
5034 &start, &stop))
5035 return FALSE;
5036
5037 segment = &stream->segments[stream->segment_index];
5038
5039 /* in the fragmented case, we pick a fragment that starts before our
5040 * desired position and rely on downstream to wait for a keyframe
5041 * (FIXME: doesn't seem to work so well with ismv and wmv, as no parser; the
5042 * tfra entries tells us which trun/sample the key unit is in, but we don't
5043 * make use of this additional information at the moment) */
5044 if (qtdemux->fragmented && !qtdemux->fragmented_seek_pending) {
5045 stream->to_sample = G_MAXUINT32;
5046 return TRUE;
5047 } else {
5048 /* well, it will be taken care of below */
5049 qtdemux->fragmented_seek_pending = FALSE;
5050 /* FIXME ideally the do_fragmented_seek can be done right here,
5051 * rather than at loop level
5052 * (which might even allow handling edit lists in a fragmented file) */
5053 }
5054
5055 /* We don't need to look for a sample in push-based */
5056 if (!qtdemux->pullbased)
5057 return TRUE;
5058
5059 /* and move to the keyframe before the indicated media time of the
5060 * segment */
5061 if (G_LIKELY (!QTSEGMENT_IS_EMPTY (segment))) {
5062 if (qtdemux->segment.rate >= 0) {
5063 index = gst_qtdemux_find_index_linear (qtdemux, stream, start);
5064 stream->to_sample = G_MAXUINT32;
5065 GST_DEBUG_OBJECT (stream->pad,
5066 "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
5067 GST_TIME_FORMAT, GST_TIME_ARGS (start), index,
5068 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
5069 } else {
5070 index = gst_qtdemux_find_index_linear (qtdemux, stream, stop);
5071 stream->to_sample = index;
5072 GST_DEBUG_OBJECT (stream->pad,
5073 "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
5074 GST_TIME_FORMAT, GST_TIME_ARGS (stop), index,
5075 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
5076 }
5077 } else {
5078 GST_DEBUG_OBJECT (stream->pad, "No need to look for keyframe, "
5079 "this is an empty segment");
5080 return TRUE;
5081 }
5082
5083 /* gst_qtdemux_parse_sample () called from gst_qtdemux_find_index_linear ()
5084 * encountered an error and printed a message so we return appropriately */
5085 if (index == -1)
5086 return FALSE;
5087
5088 /* we're at the right spot */
5089 if (index == stream->sample_index) {
5090 GST_DEBUG_OBJECT (stream->pad, "we are at the right index");
5091 return TRUE;
5092 }
5093
5094 /* find keyframe of the target index */
5095 kf_index = gst_qtdemux_find_keyframe (qtdemux, stream, index, FALSE);
5096
5097 /* go back two frames to provide lead-in for non-raw audio decoders */
5098 if (stream->subtype == FOURCC_soun && !stream->need_clip) {
5099 guint32 lead_in = 2;
5100 guint32 old_index = kf_index;
5101 GstStructure *s = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
5102
5103 if (gst_structure_has_name (s, "audio/mpeg")) {
5104 gint mpegversion;
5105 if (gst_structure_get_int (s, "mpegversion", &mpegversion)
5106 && mpegversion == 1) {
5107 /* mp3 could need up to 30 frames of lead-in per mpegaudioparse */
5108 lead_in = 30;
5109 }
5110 }
5111
5112 kf_index = MAX (kf_index, lead_in) - lead_in;
5113 if (qtdemux_parse_samples (qtdemux, stream, kf_index)) {
5114 GST_DEBUG_OBJECT (stream->pad,
5115 "Moving backwards %u frames to ensure sufficient sound lead-in",
5116 old_index - kf_index);
5117 } else {
5118 kf_index = old_index;
5119 }
5120 }
5121
5122 /* if we move forwards, we don't have to go back to the previous
5123 * keyframe since we already sent that. We can also just jump to
5124 * the keyframe right before the target index if there is one. */
5125 if (index > stream->sample_index) {
5126 /* moving forwards check if we move past a keyframe */
5127 if (kf_index > stream->sample_index) {
5128 GST_DEBUG_OBJECT (stream->pad,
5129 "moving forwards to keyframe at %u "
5130 "(pts %" GST_TIME_FORMAT " dts %" GST_TIME_FORMAT " )",
5131 kf_index,
5132 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[kf_index])),
5133 GST_TIME_ARGS (QTSAMPLE_DTS (stream, &stream->samples[kf_index])));
5134 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
5135 } else {
5136 GST_DEBUG_OBJECT (stream->pad,
5137 "moving forwards, keyframe at %u "
5138 "(pts %" GST_TIME_FORMAT " dts %" GST_TIME_FORMAT " ) already sent",
5139 kf_index,
5140 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[kf_index])),
5141 GST_TIME_ARGS (QTSAMPLE_DTS (stream, &stream->samples[kf_index])));
5142 }
5143 } else {
5144 GST_DEBUG_OBJECT (stream->pad,
5145 "moving backwards to %sframe at %u "
5146 "(pts %" GST_TIME_FORMAT " dts %" GST_TIME_FORMAT " )",
5147 (stream->subtype == FOURCC_soun) ? "audio " : "key", kf_index,
5148 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[kf_index])),
5149 GST_TIME_ARGS (QTSAMPLE_DTS (stream, &stream->samples[kf_index])));
5150 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
5151 }
5152
5153 return TRUE;
5154}
5155
5156/* prepare to get the current sample of @stream, getting essential values.
5157 *
5158 * This function will also prepare and send the segment when needed.
5159 *
5160 * Return FALSE if the stream is EOS.
5161 *
5162 * PULL-BASED
5163 */
5164static gboolean
5165gst_qtdemux_prepare_current_sample (GstQTDemux * qtdemux,
5166 QtDemuxStream * stream, gboolean * empty, guint64 * offset, guint * size,
5167 GstClockTime * dts, GstClockTime * pts, GstClockTime * duration,
5168 gboolean * keyframe)
5169{
5170 QtDemuxSample *sample;
5171 GstClockTime time_position;
5172 guint32 seg_idx;
5173
5174 g_return_val_if_fail (stream != NULL, FALSE);
5175
5176 time_position = stream->time_position;
5177 if (G_UNLIKELY (time_position == GST_CLOCK_TIME_NONE))
5178 goto eos;
5179
5180 seg_idx = stream->segment_index;
5181 if (G_UNLIKELY (seg_idx == -1)) {
5182 /* find segment corresponding to time_position if we are looking
5183 * for a segment. */
5184 seg_idx = gst_qtdemux_find_segment (qtdemux, stream, time_position);
5185 }
5186
5187 /* different segment, activate it, sample_index will be set. */
5188 if (G_UNLIKELY (stream->segment_index != seg_idx))
5189 gst_qtdemux_activate_segment (qtdemux, stream, seg_idx, time_position);
5190
5191 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (&stream->
5192 segments[stream->segment_index]))) {
5193 QtDemuxSegment *seg = &stream->segments[stream->segment_index];
5194
5195 GST_LOG_OBJECT (qtdemux, "Empty segment activated,"
5196 " prepare empty sample");
5197
5198 *empty = TRUE;
5199 *pts = *dts = time_position;
5200 *duration = seg->duration - (time_position - seg->time);
5201
5202 return TRUE;
5203 }
5204
5205 *empty = FALSE;
5206
5207 if (stream->sample_index == -1)
5208 stream->sample_index = 0;
5209
5210 GST_LOG_OBJECT (qtdemux, "segment active, index = %u of %u",
5211 stream->sample_index, stream->n_samples);
5212
5213 if (G_UNLIKELY (stream->sample_index >= stream->n_samples)) {
5214 if (!qtdemux->fragmented)
5215 goto eos;
5216
5217 GST_INFO_OBJECT (qtdemux, "out of samples, trying to add more");
5218 do {
5219 GstFlowReturn flow;
5220
5221 GST_OBJECT_LOCK (qtdemux);
5222 flow = qtdemux_add_fragmented_samples (qtdemux);
5223 GST_OBJECT_UNLOCK (qtdemux);
5224
5225 if (flow != GST_FLOW_OK)
5226 goto eos;
5227 }
5228 while (stream->sample_index >= stream->n_samples);
5229 }
5230
5231 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
5232 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
5233 stream->sample_index);
5234 return FALSE;
5235 }
5236
5237 /* now get the info for the sample we're at */
5238 sample = &stream->samples[stream->sample_index];
5239
5240 *dts = QTSAMPLE_DTS (stream, sample);
5241 *pts = QTSAMPLE_PTS (stream, sample);
5242 *offset = sample->offset;
5243 *size = sample->size;
5244 *duration = QTSAMPLE_DUR_DTS (stream, sample, *dts);
5245 *keyframe = QTSAMPLE_KEYFRAME (stream, sample);
5246
5247 return TRUE;
5248
5249 /* special cases */
5250eos:
5251 {
5252 stream->time_position = GST_CLOCK_TIME_NONE;
5253 return FALSE;
5254 }
5255}
5256
5257/* move to the next sample in @stream.
5258 *
5259 * Moves to the next segment when needed.
5260 */
5261static void
5262gst_qtdemux_advance_sample (GstQTDemux * qtdemux, QtDemuxStream * stream)
5263{
5264 QtDemuxSample *sample;
5265 QtDemuxSegment *segment;
5266
5267 /* get current segment */
5268 segment = &stream->segments[stream->segment_index];
5269
5270 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
5271 GST_DEBUG_OBJECT (qtdemux, "Empty segment, no samples to advance");
5272 goto next_segment;
5273 }
5274
5275 if (G_UNLIKELY (stream->sample_index >= stream->to_sample)) {
5276 /* Mark the stream as EOS */
5277 GST_DEBUG_OBJECT (qtdemux,
5278 "reached max allowed sample %u, mark EOS", stream->to_sample);
5279 stream->time_position = GST_CLOCK_TIME_NONE;
5280 return;
5281 }
5282
5283 /* move to next sample */
5284 stream->sample_index++;
5285 stream->offset_in_sample = 0;
5286
5287 GST_TRACE_OBJECT (qtdemux, "advance to sample %u/%u", stream->sample_index,
5288 stream->n_samples);
5289
5290 /* reached the last sample, we need the next segment */
5291 if (G_UNLIKELY (stream->sample_index >= stream->n_samples))
5292 goto next_segment;
5293
5294 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
5295 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
5296 stream->sample_index);
5297 return;
5298 }
5299
5300 /* get next sample */
5301 sample = &stream->samples[stream->sample_index];
5302
5303 GST_TRACE_OBJECT (qtdemux, "sample dts %" GST_TIME_FORMAT " media_stop: %"
5304 GST_TIME_FORMAT, GST_TIME_ARGS (QTSAMPLE_DTS (stream, sample)),
5305 GST_TIME_ARGS (segment->media_stop));
5306
5307 /* see if we are past the segment */
zengliang.li1ab157f2024-05-16 12:12:48 +00005308 if (G_UNLIKELY (QTSAMPLE_PTS (stream, sample) >= segment->media_stop))
zengliang.li5f31ef42024-05-16 08:27:38 +00005309 goto next_segment;
5310
zengliang.li1ab157f2024-05-16 12:12:48 +00005311 if (QTSAMPLE_PTS (stream, sample) >= segment->media_start) {
zengliang.li5f31ef42024-05-16 08:27:38 +00005312 /* inside the segment, update time_position, looks very familiar to
5313 * GStreamer segments, doesn't it? */
5314 stream->time_position =
zengliang.li1ab157f2024-05-16 12:12:48 +00005315 QTSAMPLE_PTS (stream, sample) - segment->media_start + segment->time;
zengliang.li5f31ef42024-05-16 08:27:38 +00005316 } else {
5317 /* not yet in segment, time does not yet increment. This means
5318 * that we are still prerolling keyframes to the decoder so it can
5319 * decode the first sample of the segment. */
5320 stream->time_position = segment->time;
5321 }
5322 return;
5323
5324 /* move to the next segment */
5325next_segment:
5326 {
5327 GST_DEBUG_OBJECT (qtdemux, "segment %d ended ", stream->segment_index);
5328
5329 if (stream->segment_index == stream->n_segments - 1) {
5330 /* are we at the end of the last segment, we're EOS */
5331 stream->time_position = GST_CLOCK_TIME_NONE;
5332 } else {
5333 /* else we're only at the end of the current segment */
5334 stream->time_position = segment->stop_time;
5335 }
5336 /* make sure we select a new segment */
5337
5338 /* accumulate previous segments */
5339 if (GST_CLOCK_TIME_IS_VALID (stream->segment.stop))
5340 stream->accumulated_base +=
5341 (stream->segment.stop -
5342 stream->segment.start) / ABS (stream->segment.rate);
5343
5344 stream->segment_index = -1;
5345 }
5346}
5347
5348static void
5349gst_qtdemux_sync_streams (GstQTDemux * demux)
5350{
5351 gint i;
5352
5353 if (QTDEMUX_N_STREAMS (demux) <= 1)
5354 return;
5355
5356 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
5357 QtDemuxStream *stream;
5358 GstClockTime end_time;
5359
5360 stream = QTDEMUX_NTH_STREAM (demux, i);
5361
5362 if (!stream->pad)
5363 continue;
5364
5365 /* TODO advance time on subtitle streams here, if any some day */
5366
5367 /* some clips/trailers may have unbalanced streams at the end,
5368 * so send EOS on shorter stream to prevent stalling others */
5369
5370 /* do not mess with EOS if SEGMENT seeking */
5371 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT)
5372 continue;
5373
5374 if (demux->pullbased) {
5375 /* loop mode is sample time based */
5376 if (!STREAM_IS_EOS (stream))
5377 continue;
5378 } else {
5379 /* push mode is byte position based */
5380 if (stream->n_samples &&
5381 stream->samples[stream->n_samples - 1].offset >= demux->offset)
5382 continue;
5383 }
5384
5385 if (stream->sent_eos)
5386 continue;
5387
5388 /* only act if some gap */
5389 end_time = stream->segments[stream->n_segments - 1].stop_time;
5390 GST_LOG_OBJECT (demux, "current position: %" GST_TIME_FORMAT
5391 ", stream end: %" GST_TIME_FORMAT,
5392 GST_TIME_ARGS (demux->segment.position), GST_TIME_ARGS (end_time));
5393 if (GST_CLOCK_TIME_IS_VALID (end_time)
5394 && (end_time + 2 * GST_SECOND < demux->segment.position)) {
5395 GstEvent *event;
5396
5397 GST_DEBUG_OBJECT (demux, "sending EOS for stream %s",
5398 GST_PAD_NAME (stream->pad));
5399 stream->sent_eos = TRUE;
5400 event = gst_event_new_eos ();
5401 if (demux->segment_seqnum != GST_SEQNUM_INVALID)
5402 gst_event_set_seqnum (event, demux->segment_seqnum);
5403 gst_pad_push_event (stream->pad, event);
5404 }
5405 }
5406}
5407
5408/* EOS and NOT_LINKED need to be combined. This means that we return:
5409 *
5410 * GST_FLOW_NOT_LINKED: when all pads NOT_LINKED.
5411 * GST_FLOW_EOS: when all pads EOS or NOT_LINKED.
5412 */
5413static GstFlowReturn
5414gst_qtdemux_combine_flows (GstQTDemux * demux, QtDemuxStream * stream,
5415 GstFlowReturn ret)
5416{
5417 GST_LOG_OBJECT (demux, "flow return: %s", gst_flow_get_name (ret));
5418
5419 if (stream->pad)
5420 ret = gst_flow_combiner_update_pad_flow (demux->flowcombiner, stream->pad,
5421 ret);
5422 else
5423 ret = gst_flow_combiner_update_flow (demux->flowcombiner, ret);
5424
5425 GST_LOG_OBJECT (demux, "combined flow return: %s", gst_flow_get_name (ret));
5426 return ret;
5427}
5428
5429/* the input buffer metadata must be writable. Returns NULL when the buffer is
5430 * completely clipped
5431 *
5432 * Should be used only with raw buffers */
5433static GstBuffer *
5434gst_qtdemux_clip_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
5435 GstBuffer * buf)
5436{
5437 guint64 start, stop, cstart, cstop, diff;
5438 GstClockTime pts, duration;
5439 gsize size, osize;
5440 gint num_rate, denom_rate;
5441 gint frame_size;
5442 gboolean clip_data;
5443 guint offset;
5444
5445 osize = size = gst_buffer_get_size (buf);
5446 offset = 0;
5447
5448 /* depending on the type, setup the clip parameters */
5449 if (stream->subtype == FOURCC_soun) {
5450 frame_size = CUR_STREAM (stream)->bytes_per_frame;
5451 num_rate = GST_SECOND;
5452 denom_rate = (gint) CUR_STREAM (stream)->rate;
5453 clip_data = TRUE;
5454 } else if (stream->subtype == FOURCC_vide) {
5455 frame_size = size;
5456 num_rate = CUR_STREAM (stream)->fps_n;
5457 denom_rate = CUR_STREAM (stream)->fps_d;
5458 clip_data = FALSE;
5459 } else
5460 goto wrong_type;
5461
5462 if (frame_size <= 0)
5463 goto bad_frame_size;
5464
5465 /* we can only clip if we have a valid pts */
5466 pts = GST_BUFFER_PTS (buf);
5467 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (pts)))
5468 goto no_pts;
5469
5470 duration = GST_BUFFER_DURATION (buf);
5471
5472 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (duration))) {
5473 duration =
5474 gst_util_uint64_scale_int (size / frame_size, num_rate, denom_rate);
5475 }
5476
5477 start = pts;
5478 stop = start + duration;
5479
5480 if (G_UNLIKELY (!gst_segment_clip (&stream->segment,
5481 GST_FORMAT_TIME, start, stop, &cstart, &cstop)))
5482 goto clipped;
5483
5484 /* see if some clipping happened */
5485 diff = cstart - start;
5486 if (diff > 0) {
5487 pts += diff;
5488 duration -= diff;
5489
5490 if (clip_data) {
5491 /* bring clipped time to samples and to bytes */
5492 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
5493 diff *= frame_size;
5494
5495 GST_DEBUG_OBJECT (qtdemux,
5496 "clipping start to %" GST_TIME_FORMAT " %"
5497 G_GUINT64_FORMAT " bytes", GST_TIME_ARGS (cstart), diff);
5498
5499 offset = diff;
5500 size -= diff;
5501 }
5502 }
5503 diff = stop - cstop;
5504 if (diff > 0) {
5505 duration -= diff;
5506
5507 if (clip_data) {
5508 /* bring clipped time to samples and then to bytes */
5509 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
5510 diff *= frame_size;
5511 GST_DEBUG_OBJECT (qtdemux,
5512 "clipping stop to %" GST_TIME_FORMAT " %" G_GUINT64_FORMAT
5513 " bytes", GST_TIME_ARGS (cstop), diff);
5514 size -= diff;
5515 }
5516 }
5517
5518 if (offset != 0 || size != osize)
5519 gst_buffer_resize (buf, offset, size);
5520
5521 GST_BUFFER_DTS (buf) = GST_CLOCK_TIME_NONE;
5522 GST_BUFFER_PTS (buf) = pts;
5523 GST_BUFFER_DURATION (buf) = duration;
5524
5525 return buf;
5526
5527 /* dropped buffer */
5528wrong_type:
5529 {
5530 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
5531 return buf;
5532 }
5533bad_frame_size:
5534 {
5535 GST_DEBUG_OBJECT (qtdemux, "bad frame size");
5536 return buf;
5537 }
5538no_pts:
5539 {
5540 GST_DEBUG_OBJECT (qtdemux, "no pts on buffer");
5541 return buf;
5542 }
5543clipped:
5544 {
5545 GST_DEBUG_OBJECT (qtdemux, "clipped buffer");
5546 gst_buffer_unref (buf);
5547 return NULL;
5548 }
5549}
5550
5551static GstBuffer *
5552gst_qtdemux_align_buffer (GstQTDemux * demux,
5553 GstBuffer * buffer, gsize alignment)
5554{
5555 GstMapInfo map;
5556
5557 gst_buffer_map (buffer, &map, GST_MAP_READ);
5558
5559 if (map.size < sizeof (guintptr)) {
5560 gst_buffer_unmap (buffer, &map);
5561 return buffer;
5562 }
5563
5564 if (((guintptr) map.data) & (alignment - 1)) {
5565 GstBuffer *new_buffer;
5566 GstAllocationParams params = { 0, alignment - 1, 0, 0, };
5567
5568 new_buffer = gst_buffer_new_allocate (NULL,
5569 gst_buffer_get_size (buffer), &params);
5570
5571 /* Copy data "by hand", so ensure alignment is kept: */
5572 gst_buffer_fill (new_buffer, 0, map.data, map.size);
5573
5574 gst_buffer_copy_into (new_buffer, buffer, GST_BUFFER_COPY_METADATA, 0, -1);
5575 GST_DEBUG_OBJECT (demux,
5576 "We want output aligned on %" G_GSIZE_FORMAT ", reallocated",
5577 alignment);
5578
5579 gst_buffer_unmap (buffer, &map);
5580 gst_buffer_unref (buffer);
5581
5582 return new_buffer;
5583 }
5584
5585 gst_buffer_unmap (buffer, &map);
5586 return buffer;
5587}
5588
5589static guint8 *
5590convert_to_s334_1a (const guint8 * ccpair, guint8 ccpair_size, guint field,
5591 gsize * res)
5592{
5593 guint8 *storage;
5594 gsize i;
5595
5596 /* We are converting from pairs to triplets */
5597 *res = ccpair_size / 2 * 3;
5598 storage = g_malloc (*res);
5599 for (i = 0; i * 2 < ccpair_size; i += 1) {
5600 /* FIXME: Use line offset 0 as we simply can't know here */
5601 if (field == 1)
5602 storage[i * 3] = 0x80 | 0x00;
5603 else
5604 storage[i * 3] = 0x00 | 0x00;
5605 storage[i * 3 + 1] = ccpair[i * 2];
5606 storage[i * 3 + 2] = ccpair[i * 2 + 1];
5607 }
5608
5609 return storage;
5610}
5611
5612static guint8 *
5613extract_cc_from_data (QtDemuxStream * stream, const guint8 * data, gsize size,
5614 gsize * cclen)
5615{
5616 guint8 *res = NULL;
5617 guint32 atom_length, fourcc;
5618 QtDemuxStreamStsdEntry *stsd_entry;
5619
5620 GST_MEMDUMP ("caption atom", data, size);
5621
5622 /* There might be multiple atoms */
5623
5624 *cclen = 0;
5625 if (size < 8)
5626 goto invalid_cdat;
5627 atom_length = QT_UINT32 (data);
5628 fourcc = QT_FOURCC (data + 4);
5629 if (G_UNLIKELY (atom_length > size || atom_length == 8))
5630 goto invalid_cdat;
5631
5632 GST_DEBUG_OBJECT (stream->pad, "here");
5633
5634 /* Check if we have something compatible */
5635 stsd_entry = CUR_STREAM (stream);
5636 switch (stsd_entry->fourcc) {
5637 case FOURCC_c608:{
5638 guint8 *cdat = NULL, *cdt2 = NULL;
5639 gsize cdat_size = 0, cdt2_size = 0;
5640 /* Should be cdat or cdt2 */
5641 if (fourcc != FOURCC_cdat && fourcc != FOURCC_cdt2) {
5642 GST_WARNING_OBJECT (stream->pad,
5643 "Unknown data atom (%" GST_FOURCC_FORMAT ") for CEA608",
5644 GST_FOURCC_ARGS (fourcc));
5645 goto invalid_cdat;
5646 }
5647
5648 /* Convert to S334-1 Annex A byte triplet */
5649 if (fourcc == FOURCC_cdat)
5650 cdat = convert_to_s334_1a (data + 8, atom_length - 8, 1, &cdat_size);
5651 else
5652 cdt2 = convert_to_s334_1a (data + 8, atom_length - 8, 2, &cdt2_size);
5653 GST_DEBUG_OBJECT (stream->pad, "size:%" G_GSIZE_FORMAT " atom_length:%u",
5654 size, atom_length);
5655
5656 /* Check for another atom ? */
5657 if (size > atom_length + 8) {
5658 guint32 new_atom_length = QT_UINT32 (data + atom_length);
5659 if (size >= atom_length + new_atom_length) {
5660 fourcc = QT_FOURCC (data + atom_length + 4);
5661 if (fourcc == FOURCC_cdat) {
5662 if (cdat == NULL)
5663 cdat =
5664 convert_to_s334_1a (data + atom_length + 8,
5665 new_atom_length - 8, 1, &cdat_size);
5666 else
5667 GST_WARNING_OBJECT (stream->pad,
5668 "Got multiple [cdat] atoms in a c608 sample. This is unsupported for now. Please file a bug");
5669 } else {
5670 if (cdt2 == NULL)
5671 cdt2 =
5672 convert_to_s334_1a (data + atom_length + 8,
5673 new_atom_length - 8, 2, &cdt2_size);
5674 else
5675 GST_WARNING_OBJECT (stream->pad,
5676 "Got multiple [cdt2] atoms in a c608 sample. This is unsupported for now. Please file a bug");
5677 }
5678 }
5679 }
5680
5681 *cclen = cdat_size + cdt2_size;
5682 res = g_malloc (*cclen);
5683 if (cdat_size)
5684 memcpy (res, cdat, cdat_size);
5685 if (cdt2_size)
5686 memcpy (res + cdat_size, cdt2, cdt2_size);
5687 g_free (cdat);
5688 g_free (cdt2);
5689 }
5690 break;
5691 case FOURCC_c708:
5692 if (fourcc != FOURCC_ccdp) {
5693 GST_WARNING_OBJECT (stream->pad,
5694 "Unknown data atom (%" GST_FOURCC_FORMAT ") for CEA708",
5695 GST_FOURCC_ARGS (fourcc));
5696 goto invalid_cdat;
5697 }
5698 *cclen = atom_length - 8;
5699 res = g_memdup2 (data + 8, *cclen);
5700 break;
5701 default:
5702 /* Keep this here in case other closed caption formats are added */
5703 g_assert_not_reached ();
5704 break;
5705 }
5706
5707 GST_MEMDUMP ("Output", res, *cclen);
5708 return res;
5709
5710 /* Errors */
5711invalid_cdat:
5712 GST_WARNING ("[cdat] atom is too small or invalid");
5713 return NULL;
5714}
5715
5716/* Handle Closed Caption sample buffers.
5717 * The input buffer metadata must be writable,
5718 * but time/duration etc not yet set and need not be preserved */
5719static GstBuffer *
5720gst_qtdemux_process_buffer_clcp (GstQTDemux * qtdemux, QtDemuxStream * stream,
5721 GstBuffer * buf)
5722{
5723 GstBuffer *outbuf = NULL;
5724 GstMapInfo map;
5725 guint8 *cc;
5726 gsize cclen = 0;
5727
5728 gst_buffer_map (buf, &map, GST_MAP_READ);
5729
5730 /* empty buffer is sent to terminate previous subtitle */
5731 if (map.size <= 2) {
5732 gst_buffer_unmap (buf, &map);
5733 gst_buffer_unref (buf);
5734 return NULL;
5735 }
5736
5737 /* For closed caption, we need to extract the information from the
5738 * [cdat],[cdt2] or [ccdp] atom */
5739 cc = extract_cc_from_data (stream, map.data, map.size, &cclen);
5740 gst_buffer_unmap (buf, &map);
5741 if (cc) {
5742 outbuf = _gst_buffer_new_wrapped (cc, cclen, g_free);
5743 gst_buffer_copy_into (outbuf, buf, GST_BUFFER_COPY_METADATA, 0, -1);
5744 } else {
5745 /* Conversion failed or there's nothing */
5746 }
5747 gst_buffer_unref (buf);
5748
5749 return outbuf;
5750}
5751
5752/* DVD subpicture specific sample handling.
5753 * the input buffer metadata must be writable,
5754 * but time/duration etc not yet set and need not be preserved */
5755static GstBuffer *
5756gst_qtdemux_process_buffer_dvd (GstQTDemux * qtdemux, QtDemuxStream * stream,
5757 GstBuffer * buf)
5758{
5759 /* send a one time dvd clut event */
5760 if (stream->pending_event && stream->pad)
5761 gst_pad_push_event (stream->pad, stream->pending_event);
5762 stream->pending_event = NULL;
5763
5764 /* empty buffer is sent to terminate previous subtitle */
5765 if (gst_buffer_get_size (buf) <= 2) {
5766 gst_buffer_unref (buf);
5767 return NULL;
5768 }
5769
5770 /* That's all the processing needed for subpictures */
5771 return buf;
5772}
5773
5774/* Timed text formats
5775 * the input buffer metadata must be writable,
5776 * but time/duration etc not yet set and need not be preserved */
5777static GstBuffer *
5778gst_qtdemux_process_buffer_text (GstQTDemux * qtdemux, QtDemuxStream * stream,
5779 GstBuffer * buf)
5780{
5781 GstBuffer *outbuf = NULL;
5782 GstMapInfo map;
5783 guint nsize = 0;
5784 gchar *str;
5785
5786 /* not many cases for now */
5787 if (G_UNLIKELY (stream->subtype != FOURCC_text &&
5788 stream->subtype != FOURCC_sbtl)) {
5789 return buf;
5790 }
5791
5792 gst_buffer_map (buf, &map, GST_MAP_READ);
5793
5794 /* empty buffer is sent to terminate previous subtitle */
5795 if (map.size <= 2) {
5796 gst_buffer_unmap (buf, &map);
5797 gst_buffer_unref (buf);
5798 return NULL;
5799 }
5800
5801 nsize = GST_READ_UINT16_BE (map.data);
5802 nsize = MIN (nsize, map.size - 2);
5803
5804 GST_LOG_OBJECT (qtdemux, "3GPP timed text subtitle: %d/%" G_GSIZE_FORMAT "",
5805 nsize, map.size);
5806
5807 /* takes care of UTF-8 validation or UTF-16 recognition,
5808 * no other encoding expected */
5809 str = gst_tag_freeform_string_to_utf8 ((gchar *) map.data + 2, nsize, NULL);
5810 gst_buffer_unmap (buf, &map);
5811
5812 if (str) {
5813 outbuf = _gst_buffer_new_wrapped (str, strlen (str), g_free);
5814 gst_buffer_copy_into (outbuf, buf, GST_BUFFER_COPY_METADATA, 0, -1);
5815 } else {
5816 /* this should not really happen unless the subtitle is corrupted */
5817 }
5818 gst_buffer_unref (buf);
5819
5820 /* FIXME ? convert optional subsequent style info to markup */
5821
5822 return outbuf;
5823}
5824
5825/* WebVTT sample handling according to 14496-30 */
5826static GstBuffer *
5827gst_qtdemux_process_buffer_wvtt (GstQTDemux * qtdemux, QtDemuxStream * stream,
5828 GstBuffer * buf)
5829{
5830 GstBuffer *outbuf = NULL;
5831 GstMapInfo map;
5832
5833 if (!gst_buffer_map (buf, &map, GST_MAP_READ)) {
5834 g_assert_not_reached (); /* The buffer must be mappable */
5835 }
5836
5837 if (qtdemux_webvtt_is_empty (qtdemux, map.data, map.size)) {
5838 GstEvent *gap = NULL;
5839 /* Push a gap event */
5840 stream->segment.position = GST_BUFFER_PTS (buf);
5841 gap =
5842 gst_event_new_gap (stream->segment.position, GST_BUFFER_DURATION (buf));
5843 gst_pad_push_event (stream->pad, gap);
5844
5845 if (GST_BUFFER_DURATION_IS_VALID (buf))
5846 stream->segment.position += GST_BUFFER_DURATION (buf);
5847 } else {
5848 outbuf =
5849 qtdemux_webvtt_decode (qtdemux, GST_BUFFER_PTS (buf),
5850 GST_BUFFER_DURATION (buf), map.data, map.size);
5851 gst_buffer_copy_into (outbuf, buf, GST_BUFFER_COPY_METADATA, 0, -1);
5852 }
5853
5854 gst_buffer_unmap (buf, &map);
5855 gst_buffer_unref (buf);
5856
5857 return outbuf;
5858}
5859
5860static GstFlowReturn
5861gst_qtdemux_push_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
5862 GstBuffer * buf)
5863{
5864 GstFlowReturn ret = GST_FLOW_OK;
5865 GstClockTime pts, duration;
5866
5867 if (stream->need_clip)
5868 buf = gst_qtdemux_clip_buffer (qtdemux, stream, buf);
5869
5870 if (G_UNLIKELY (buf == NULL))
5871 goto exit;
5872
5873 if (G_UNLIKELY (stream->discont)) {
5874 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
5875 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
5876 stream->discont = FALSE;
5877 } else {
5878 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
5879 }
5880
5881 GST_LOG_OBJECT (qtdemux,
5882 "Pushing buffer with dts %" GST_TIME_FORMAT ", pts %" GST_TIME_FORMAT
5883 ", duration %" GST_TIME_FORMAT " on pad %s",
5884 GST_TIME_ARGS (GST_BUFFER_DTS (buf)),
5885 GST_TIME_ARGS (GST_BUFFER_PTS (buf)),
5886 GST_TIME_ARGS (GST_BUFFER_DURATION (buf)), GST_PAD_NAME (stream->pad));
5887
5888 if (stream->protected && stream->protection_scheme_type == FOURCC_aavd) {
5889 GstStructure *crypto_info;
5890 QtDemuxAavdEncryptionInfo *info =
5891 (QtDemuxAavdEncryptionInfo *) stream->protection_scheme_info;
5892
5893 crypto_info = gst_structure_copy (info->default_properties);
5894 if (!crypto_info || !gst_buffer_add_protection_meta (buf, crypto_info))
5895 GST_ERROR_OBJECT (qtdemux, "failed to attach aavd metadata to buffer");
5896 }
5897
5898 if (stream->protected && (stream->protection_scheme_type == FOURCC_cenc
5899 || stream->protection_scheme_type == FOURCC_cbcs)) {
5900 GstStructure *crypto_info;
5901 QtDemuxCencSampleSetInfo *info =
5902 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
5903 gint index;
5904 GstEvent *event;
5905
5906 while ((event = g_queue_pop_head (&stream->protection_scheme_event_queue))) {
5907 GST_TRACE_OBJECT (stream->pad, "pushing protection event: %"
5908 GST_PTR_FORMAT, event);
5909 gst_pad_push_event (stream->pad, event);
5910 }
5911
5912 if (info->crypto_info == NULL) {
5913 if (stream->protection_scheme_type == FOURCC_cbcs) {
5914 crypto_info = qtdemux_get_cenc_sample_properties (qtdemux, stream, 0);
5915 if (!crypto_info || !gst_buffer_add_protection_meta (buf, crypto_info)) {
5916 GST_ERROR_OBJECT (qtdemux,
5917 "failed to attach cbcs metadata to buffer");
5918 qtdemux_gst_structure_free (crypto_info);
5919 } else {
5920 GST_TRACE_OBJECT (qtdemux, "added cbcs protection metadata");
5921 }
5922 } else {
5923 GST_DEBUG_OBJECT (qtdemux,
5924 "cenc metadata hasn't been parsed yet, pushing buffer as if it wasn't encrypted");
5925 }
5926 } else {
5927 /* The end of the crypto_info array matches our n_samples position,
5928 * so count backward from there */
5929 index = stream->sample_index - stream->n_samples + info->crypto_info->len;
5930 if (G_LIKELY (index >= 0 && index < info->crypto_info->len)) {
5931 /* steal structure from array */
5932 crypto_info = g_ptr_array_index (info->crypto_info, index);
5933 g_ptr_array_index (info->crypto_info, index) = NULL;
5934 GST_LOG_OBJECT (qtdemux, "attaching cenc metadata [%u/%u]", index,
5935 info->crypto_info->len);
5936 if (!crypto_info || !gst_buffer_add_protection_meta (buf, crypto_info))
5937 GST_ERROR_OBJECT (qtdemux,
5938 "failed to attach cenc metadata to buffer");
5939 } else {
5940 GST_INFO_OBJECT (qtdemux, "No crypto info with index %d and sample %d",
5941 index, stream->sample_index);
5942 }
5943 }
5944 }
5945
5946 if (stream->alignment > 1)
5947 buf = gst_qtdemux_align_buffer (qtdemux, buf, stream->alignment);
5948
5949 pts = GST_BUFFER_PTS (buf);
5950 duration = GST_BUFFER_DURATION (buf);
5951
5952 ret = gst_pad_push (stream->pad, buf);
5953
5954 if (GST_CLOCK_TIME_IS_VALID (pts) && GST_CLOCK_TIME_IS_VALID (duration)) {
5955 /* mark position in stream, we'll need this to know when to send GAP event */
5956 stream->segment.position = pts + duration;
5957 }
5958
5959exit:
5960
5961 return ret;
5962}
5963
5964static GstFlowReturn
5965gst_qtdemux_split_and_push_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
5966 GstBuffer * buf)
5967{
5968 GstFlowReturn ret = GST_FLOW_OK;
5969
5970 if (stream->subtype == FOURCC_clcp
5971 && CUR_STREAM (stream)->fourcc == FOURCC_c608 && stream->need_split) {
5972 GstMapInfo map;
5973 guint n_output_buffers, n_field1 = 0, n_field2 = 0;
5974 guint n_triplets, i;
5975 guint field1_off = 0, field2_off = 0;
5976
5977 /* We have to split CEA608 buffers so that each outgoing buffer contains
5978 * one byte pair per field according to the framerate of the video track.
5979 *
5980 * If there is only a single byte pair per field we don't have to do
5981 * anything
5982 */
5983
5984 gst_buffer_map (buf, &map, GST_MAP_READ);
5985
5986 n_triplets = map.size / 3;
5987 for (i = 0; i < n_triplets; i++) {
5988 if (map.data[3 * i] & 0x80)
5989 n_field1++;
5990 else
5991 n_field2++;
5992 }
5993
5994 g_assert (n_field1 || n_field2);
5995
5996 /* If there's more than 1 frame we have to split, otherwise we can just
5997 * pass through */
5998 if (n_field1 > 1 || n_field2 > 1) {
5999 n_output_buffers =
6000 gst_util_uint64_scale (GST_BUFFER_DURATION (buf),
6001 CUR_STREAM (stream)->fps_n, GST_SECOND * CUR_STREAM (stream)->fps_d);
6002
6003 for (i = 0; i < n_output_buffers; i++) {
6004 GstBuffer *outbuf =
6005 gst_buffer_new_and_alloc ((n_field1 ? 3 : 0) + (n_field2 ? 3 : 0));
6006 GstMapInfo outmap;
6007 guint8 *outptr;
6008
6009 gst_buffer_map (outbuf, &outmap, GST_MAP_WRITE);
6010 outptr = outmap.data;
6011
6012 if (n_field1) {
6013 gboolean found = FALSE;
6014
6015 while (map.data + field1_off < map.data + map.size) {
6016 if (map.data[field1_off] & 0x80) {
6017 memcpy (outptr, &map.data[field1_off], 3);
6018 field1_off += 3;
6019 found = TRUE;
6020 break;
6021 }
6022 field1_off += 3;
6023 }
6024
6025 if (!found) {
6026 const guint8 empty[] = { 0x80, 0x80, 0x80 };
6027
6028 memcpy (outptr, empty, 3);
6029 }
6030
6031 outptr += 3;
6032 }
6033
6034 if (n_field2) {
6035 gboolean found = FALSE;
6036
6037 while (map.data + field2_off < map.data + map.size) {
6038 if ((map.data[field2_off] & 0x80) == 0) {
6039 memcpy (outptr, &map.data[field2_off], 3);
6040 field2_off += 3;
6041 found = TRUE;
6042 break;
6043 }
6044 field2_off += 3;
6045 }
6046
6047 if (!found) {
6048 const guint8 empty[] = { 0x00, 0x80, 0x80 };
6049
6050 memcpy (outptr, empty, 3);
6051 }
6052
6053 outptr += 3;
6054 }
6055
6056 gst_buffer_unmap (outbuf, &outmap);
6057
6058 GST_BUFFER_PTS (outbuf) =
6059 GST_BUFFER_PTS (buf) + gst_util_uint64_scale (i,
6060 GST_SECOND * CUR_STREAM (stream)->fps_d,
6061 CUR_STREAM (stream)->fps_n);
6062 GST_BUFFER_DURATION (outbuf) =
6063 gst_util_uint64_scale (GST_SECOND, CUR_STREAM (stream)->fps_d,
6064 CUR_STREAM (stream)->fps_n);
6065 GST_BUFFER_OFFSET (outbuf) = -1;
6066 GST_BUFFER_OFFSET_END (outbuf) = -1;
6067
6068 ret = gst_qtdemux_push_buffer (qtdemux, stream, outbuf);
6069
6070 if (ret != GST_FLOW_OK && ret != GST_FLOW_NOT_LINKED)
6071 break;
6072 }
6073 gst_buffer_unmap (buf, &map);
6074 gst_buffer_unref (buf);
6075 } else {
6076 gst_buffer_unmap (buf, &map);
6077 ret = gst_qtdemux_push_buffer (qtdemux, stream, buf);
6078 }
6079 } else {
6080 ret = gst_qtdemux_push_buffer (qtdemux, stream, buf);
6081 }
6082
6083 return ret;
6084}
6085
6086/* Sets a buffer's attributes properly and pushes it downstream.
6087 * Also checks for additional actions and custom processing that may
6088 * need to be done first.
6089 */
6090static GstFlowReturn
6091gst_qtdemux_decorate_and_push_buffer (GstQTDemux * qtdemux,
6092 QtDemuxStream * stream, GstBuffer * buf,
6093 GstClockTime dts, GstClockTime pts, GstClockTime duration,
6094 gboolean keyframe, GstClockTime position, guint64 byte_position)
6095{
6096 GstFlowReturn ret = GST_FLOW_OK;
6097
6098 /* offset the timestamps according to the edit list */
6099
6100 if (G_UNLIKELY (CUR_STREAM (stream)->fourcc == FOURCC_rtsp)) {
6101 gchar *url;
6102 GstMapInfo map;
6103
6104 gst_buffer_map (buf, &map, GST_MAP_READ);
6105 url = g_strndup ((gchar *) map.data, map.size);
6106 gst_buffer_unmap (buf, &map);
6107 if (url != NULL && strlen (url) != 0) {
6108 /* we have RTSP redirect now */
6109 g_free (qtdemux->redirect_location);
6110 qtdemux->redirect_location = g_strdup (url);
6111 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
6112 gst_message_new_element (GST_OBJECT_CAST (qtdemux),
6113 gst_structure_new ("redirect",
6114 "new-location", G_TYPE_STRING, url, NULL)));
6115 } else {
6116 GST_WARNING_OBJECT (qtdemux, "Redirect URI of stream is empty, not "
6117 "posting");
6118 }
6119 g_free (url);
6120 }
6121
6122 /* position reporting */
zengliang.li4681ee42024-05-16 12:25:30 +00006123 if (qtdemux->segment.rate >= 0 && GST_CLOCK_TIME_IS_VALID(position)) {
zengliang.li5f31ef42024-05-16 08:27:38 +00006124 qtdemux->segment.position = position;
6125 gst_qtdemux_sync_streams (qtdemux);
6126 }
6127
6128 if (G_UNLIKELY (!stream->pad)) {
6129 GST_DEBUG_OBJECT (qtdemux, "No output pad for stream, ignoring");
6130 gst_buffer_unref (buf);
6131 goto exit;
6132 }
6133
6134 /* send out pending buffers */
6135 while (stream->buffers) {
6136 GstBuffer *buffer = (GstBuffer *) stream->buffers->data;
6137
6138 if (G_UNLIKELY (stream->discont)) {
6139 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
6140 GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
6141 stream->discont = FALSE;
6142 } else {
6143 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
6144 }
6145
6146 if (stream->alignment > 1)
6147 buffer = gst_qtdemux_align_buffer (qtdemux, buffer, stream->alignment);
6148 gst_pad_push (stream->pad, buffer);
6149
6150 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
6151 }
6152
6153 /* we're going to modify the metadata */
6154 buf = gst_buffer_make_writable (buf);
6155
6156 GST_BUFFER_DTS (buf) = dts;
6157 GST_BUFFER_PTS (buf) = pts;
6158 GST_BUFFER_DURATION (buf) = duration;
6159 GST_BUFFER_OFFSET (buf) = -1;
6160 GST_BUFFER_OFFSET_END (buf) = -1;
6161
6162 if (G_UNLIKELY (stream->process_func))
6163 buf = stream->process_func (qtdemux, stream, buf);
6164
6165 if (!buf) {
6166 goto exit;
6167 }
6168
6169 if (!keyframe) {
6170 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
6171 stream->on_keyframe = FALSE;
6172 } else {
6173 stream->on_keyframe = TRUE;
6174 }
6175
6176 if (G_UNLIKELY (CUR_STREAM (stream)->rgb8_palette))
6177 gst_buffer_append_memory (buf,
6178 gst_memory_ref (CUR_STREAM (stream)->rgb8_palette));
6179
6180 if (G_UNLIKELY (CUR_STREAM (stream)->padding)) {
6181 gst_buffer_resize (buf, CUR_STREAM (stream)->padding, -1);
6182 }
6183#if 0
6184 if (G_UNLIKELY (qtdemux->element_index)) {
6185 GstClockTime stream_time;
6186
6187 stream_time =
6188 gst_segment_to_stream_time (&stream->segment, GST_FORMAT_TIME,
6189 timestamp);
6190 if (GST_CLOCK_TIME_IS_VALID (stream_time)) {
6191 GST_LOG_OBJECT (qtdemux,
6192 "adding association %" GST_TIME_FORMAT "-> %"
6193 G_GUINT64_FORMAT, GST_TIME_ARGS (stream_time), byte_position);
6194 gst_index_add_association (qtdemux->element_index,
6195 qtdemux->index_id,
6196 keyframe ? GST_ASSOCIATION_FLAG_KEY_UNIT :
6197 GST_ASSOCIATION_FLAG_DELTA_UNIT, GST_FORMAT_TIME, stream_time,
6198 GST_FORMAT_BYTES, byte_position, NULL);
6199 }
6200 }
6201#endif
6202
6203 ret = gst_qtdemux_split_and_push_buffer (qtdemux, stream, buf);
6204
6205exit:
6206 return ret;
6207}
6208
6209static const QtDemuxRandomAccessEntry *
6210gst_qtdemux_stream_seek_fragment (GstQTDemux * qtdemux, QtDemuxStream * stream,
6211 GstClockTime pos, gboolean after)
6212{
6213 QtDemuxRandomAccessEntry *entries = stream->ra_entries;
6214 guint n_entries = stream->n_ra_entries;
6215 guint i;
6216
6217 /* we assume the table is sorted */
6218 for (i = 0; i < n_entries; ++i) {
6219 if (entries[i].ts > pos)
6220 break;
6221 }
6222
6223 /* FIXME: maybe save first moof_offset somewhere instead, but for now it's
6224 * probably okay to assume that the index lists the very first fragment */
6225 if (i == 0)
6226 return &entries[0];
6227
6228 if (after)
6229 return &entries[i];
6230 else
6231 return &entries[i - 1];
6232}
6233
6234static gboolean
6235gst_qtdemux_do_fragmented_seek (GstQTDemux * qtdemux)
6236{
6237 const QtDemuxRandomAccessEntry *best_entry = NULL;
6238 gint i;
6239
6240 GST_OBJECT_LOCK (qtdemux);
6241
6242 g_assert (QTDEMUX_N_STREAMS (qtdemux) > 0);
6243
6244 /* first see if we can determine where to go to using mfra,
6245 * before we start clearing things */
6246 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
6247 const QtDemuxRandomAccessEntry *entry;
6248 QtDemuxStream *stream;
6249 gboolean is_audio_or_video;
6250
6251 stream = QTDEMUX_NTH_STREAM (qtdemux, i);
6252
6253 if (stream->ra_entries == NULL)
6254 continue;
6255
6256 if (stream->subtype == FOURCC_vide || stream->subtype == FOURCC_soun)
6257 is_audio_or_video = TRUE;
6258 else
6259 is_audio_or_video = FALSE;
6260
6261 entry =
6262 gst_qtdemux_stream_seek_fragment (qtdemux, stream,
6263 stream->time_position, !is_audio_or_video);
6264
6265 GST_INFO_OBJECT (stream->pad, "%" GST_TIME_FORMAT " at offset "
6266 "%" G_GUINT64_FORMAT, GST_TIME_ARGS (entry->ts), entry->moof_offset);
6267
6268 stream->pending_seek = entry;
6269
6270 /* decide position to jump to just based on audio/video tracks, not subs */
6271 if (!is_audio_or_video)
6272 continue;
6273
6274 if (best_entry == NULL || entry->moof_offset < best_entry->moof_offset)
6275 best_entry = entry;
6276 }
6277
6278 /* no luck, will handle seek otherwise */
6279 if (best_entry == NULL) {
6280 GST_OBJECT_UNLOCK (qtdemux);
6281 return FALSE;
6282 }
6283
6284 /* ok, now we can prepare for processing as of located moof */
6285 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
6286 QtDemuxStream *stream;
6287
6288 stream = QTDEMUX_NTH_STREAM (qtdemux, i);
6289
6290 g_free (stream->samples);
6291 stream->samples = NULL;
6292 stream->n_samples = 0;
6293 stream->stbl_index = -1; /* no samples have yet been parsed */
6294 stream->sample_index = -1;
6295
6296 if (stream->protection_scheme_info) {
6297 /* Clear out any old cenc crypto info entries as we'll move to a new moof */
6298 if (stream->protection_scheme_type == FOURCC_cenc
6299 || stream->protection_scheme_type == FOURCC_cbcs) {
6300 QtDemuxCencSampleSetInfo *info =
6301 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
6302 if (info->crypto_info) {
6303 g_ptr_array_free (info->crypto_info, TRUE);
6304 info->crypto_info = NULL;
6305 }
6306 }
6307 }
6308 }
6309
6310 GST_INFO_OBJECT (qtdemux, "seek to %" GST_TIME_FORMAT ", best fragment "
6311 "moof offset: %" G_GUINT64_FORMAT ", ts %" GST_TIME_FORMAT,
6312 GST_TIME_ARGS (QTDEMUX_NTH_STREAM (qtdemux, 0)->time_position),
6313 best_entry->moof_offset, GST_TIME_ARGS (best_entry->ts));
6314
6315 qtdemux->moof_offset = best_entry->moof_offset;
6316
6317 qtdemux_add_fragmented_samples (qtdemux);
6318
6319 GST_OBJECT_UNLOCK (qtdemux);
6320 return TRUE;
6321}
6322
6323static GstFlowReturn
6324gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux)
6325{
6326 GstFlowReturn ret = GST_FLOW_OK;
6327 GstBuffer *buf = NULL;
6328 QtDemuxStream *stream, *target_stream = NULL;
6329 GstClockTime min_time;
6330 guint64 offset = 0;
6331 GstClockTime dts = GST_CLOCK_TIME_NONE;
6332 GstClockTime pts = GST_CLOCK_TIME_NONE;
6333 GstClockTime duration = 0;
6334 gboolean keyframe = FALSE;
6335 guint sample_size = 0;
6336 guint num_samples = 1;
6337 gboolean empty = 0;
6338 guint size;
6339 gint i;
6340
6341 if (qtdemux->fragmented_seek_pending) {
6342 GST_INFO_OBJECT (qtdemux, "pending fragmented seek");
6343 if (gst_qtdemux_do_fragmented_seek (qtdemux)) {
6344 GST_INFO_OBJECT (qtdemux, "fragmented seek done!");
6345 qtdemux->fragmented_seek_pending = FALSE;
6346 } else {
6347 GST_INFO_OBJECT (qtdemux, "fragmented seek still pending");
6348 }
6349 }
6350
6351 /* Figure out the next stream sample to output, min_time is expressed in
6352 * global time and runs over the edit list segments. */
6353 min_time = G_MAXUINT64;
6354 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
6355 GstClockTime position;
6356
6357 stream = QTDEMUX_NTH_STREAM (qtdemux, i);
6358 position = stream->time_position;
6359
6360 /* position of -1 is EOS */
zengliang.li8c9c4092024-05-16 11:35:51 +00006361 if ((position != GST_CLOCK_TIME_NONE && position < min_time) ||
6362 || (stream->discont)) {
zengliang.li5f31ef42024-05-16 08:27:38 +00006363 min_time = position;
6364 target_stream = stream;
6365 }
6366 }
6367 /* all are EOS */
6368 if (G_UNLIKELY (target_stream == NULL)) {
6369 GST_DEBUG_OBJECT (qtdemux, "all streams are EOS");
6370 goto eos;
6371 }
6372
6373 /* check for segment end */
6374 if (G_UNLIKELY (qtdemux->segment.stop != -1
6375 && qtdemux->segment.rate >= 0
6376 && qtdemux->segment.stop <= min_time && target_stream->on_keyframe)) {
6377 GST_DEBUG_OBJECT (qtdemux, "we reached the end of our segment.");
6378 target_stream->time_position = GST_CLOCK_TIME_NONE;
6379 goto eos_stream;
6380 }
6381
6382 /* gap events for subtitle streams */
6383 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
6384 stream = QTDEMUX_NTH_STREAM (qtdemux, i);
6385 if (stream->pad) {
6386 GstClockTime gap_threshold;
6387
6388 /* Only send gap events on non-subtitle streams if lagging way behind. */
6389 if (stream->subtype == FOURCC_subp
6390 || stream->subtype == FOURCC_text || stream->subtype == FOURCC_sbtl ||
6391 stream->subtype == FOURCC_wvtt)
6392 gap_threshold = 1 * GST_SECOND;
6393 else
6394 gap_threshold = 3 * GST_SECOND;
6395
6396 /* send gap events until the stream catches up */
6397 /* gaps can only be sent after segment is activated (segment.stop is no longer -1) */
6398 while (GST_CLOCK_TIME_IS_VALID (stream->segment.stop) &&
6399 GST_CLOCK_TIME_IS_VALID (stream->segment.position) &&
6400 stream->segment.position < (G_MAXUINT64 - gap_threshold) &&
6401 stream->segment.position + gap_threshold < min_time) {
6402 GstEvent *gap =
6403 gst_event_new_gap (stream->segment.position, gap_threshold);
6404 gst_pad_push_event (stream->pad, gap);
6405 stream->segment.position += gap_threshold;
6406 }
6407 }
6408 }
6409
6410 stream = target_stream;
6411 /* fetch info for the current sample of this stream */
6412 if (G_UNLIKELY (!gst_qtdemux_prepare_current_sample (qtdemux, stream, &empty,
6413 &offset, &sample_size, &dts, &pts, &duration, &keyframe)))
6414 goto eos_stream;
6415
6416 gst_qtdemux_stream_check_and_change_stsd_index (qtdemux, stream);
6417 if (stream->new_caps) {
6418 gst_qtdemux_configure_stream (qtdemux, stream);
6419 qtdemux_do_allocation (stream, qtdemux);
6420 }
6421
6422 /* If we're doing a keyframe-only trickmode, only push keyframes on video streams */
6423 if (G_UNLIKELY (qtdemux->segment.
6424 flags & GST_SEGMENT_FLAG_TRICKMODE_KEY_UNITS)) {
6425 if (stream->subtype == FOURCC_vide) {
6426 if (!keyframe) {
6427 GST_LOG_OBJECT (qtdemux, "Skipping non-keyframe on track-id %u",
6428 stream->track_id);
6429 goto next;
6430 } else if (qtdemux->trickmode_interval > 0) {
6431 GstClockTimeDiff interval;
6432
6433 if (qtdemux->segment.rate > 0)
6434 interval = stream->time_position - stream->last_keyframe_dts;
6435 else
6436 interval = stream->last_keyframe_dts - stream->time_position;
6437
6438 if (GST_CLOCK_TIME_IS_VALID (stream->last_keyframe_dts)
6439 && interval < qtdemux->trickmode_interval) {
6440 GST_LOG_OBJECT (qtdemux,
6441 "Skipping keyframe within interval on track-id %u",
6442 stream->track_id);
6443 goto next;
6444 } else {
6445 stream->last_keyframe_dts = stream->time_position;
6446 }
6447 }
6448 }
6449 }
6450
6451 GST_DEBUG_OBJECT (qtdemux,
6452 "pushing from track-id %u, empty %d offset %" G_GUINT64_FORMAT
6453 ", size %d, dts=%" GST_TIME_FORMAT ", pts=%" GST_TIME_FORMAT
6454 ", duration %" GST_TIME_FORMAT, stream->track_id, empty, offset,
6455 sample_size, GST_TIME_ARGS (dts), GST_TIME_ARGS (pts),
6456 GST_TIME_ARGS (duration));
6457
6458 if (G_UNLIKELY (empty)) {
6459 /* empty segment, push a gap if there's a second or more
6460 * difference and move to the next one */
6461 if ((pts + duration - stream->segment.position) >= GST_SECOND)
6462 gst_pad_push_event (stream->pad, gst_event_new_gap (pts, duration));
6463 stream->segment.position = pts + duration;
6464 goto next;
6465 }
6466
6467 /* hmm, empty sample, skip and move to next sample */
6468 if (G_UNLIKELY (sample_size <= 0))
6469 goto next;
6470
6471 /* last pushed sample was out of boundary, goto next sample */
6472 if (G_UNLIKELY (GST_PAD_LAST_FLOW_RETURN (stream->pad) == GST_FLOW_EOS))
6473 goto next;
6474
6475 if (stream->max_buffer_size != 0 && sample_size > stream->max_buffer_size) {
6476 GST_DEBUG_OBJECT (qtdemux,
6477 "size %d larger than stream max_buffer_size %d, trimming",
6478 sample_size, stream->max_buffer_size);
6479 size =
6480 MIN (sample_size - stream->offset_in_sample, stream->max_buffer_size);
6481 } else if (stream->min_buffer_size != 0 && stream->offset_in_sample == 0
6482 && sample_size < stream->min_buffer_size) {
6483 guint start_sample_index = stream->sample_index;
6484 guint accumulated_size = sample_size;
6485 guint64 expected_next_offset = offset + sample_size;
6486
6487 GST_DEBUG_OBJECT (qtdemux,
6488 "size %d smaller than stream min_buffer_size %d, combining with the next",
6489 sample_size, stream->min_buffer_size);
6490
6491 while (stream->sample_index < stream->to_sample
6492 && stream->sample_index + 1 < stream->n_samples) {
6493 const QtDemuxSample *next_sample;
6494
6495 /* Increment temporarily */
6496 stream->sample_index++;
6497
6498 /* Failed to parse sample so let's go back to the previous one that was
6499 * still successful */
6500 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
6501 stream->sample_index--;
6502 break;
6503 }
6504
6505 next_sample = &stream->samples[stream->sample_index];
6506
6507 /* Not contiguous with the previous sample so let's go back to the
6508 * previous one that was still successful */
6509 if (next_sample->offset != expected_next_offset) {
6510 stream->sample_index--;
6511 break;
6512 }
6513
6514 accumulated_size += next_sample->size;
6515 expected_next_offset += next_sample->size;
6516 if (accumulated_size >= stream->min_buffer_size)
6517 break;
6518 }
6519
6520 num_samples = stream->sample_index + 1 - start_sample_index;
6521 stream->sample_index = start_sample_index;
6522 GST_DEBUG_OBJECT (qtdemux, "Pulling %u samples of size %u at once",
6523 num_samples, accumulated_size);
6524 size = accumulated_size;
6525 } else {
6526 size = sample_size;
6527 }
6528
6529 if (qtdemux->cenc_aux_info_offset > 0) {
6530 GstMapInfo map;
6531 GstByteReader br;
6532 GstBuffer *aux_info = NULL;
6533
6534 /* pull the data stored before the sample */
6535 ret =
6536 gst_qtdemux_pull_atom (qtdemux, qtdemux->offset,
6537 offset + stream->offset_in_sample - qtdemux->offset, &aux_info);
6538 if (G_UNLIKELY (ret != GST_FLOW_OK))
6539 goto beach;
6540 gst_buffer_map (aux_info, &map, GST_MAP_READ);
6541 GST_DEBUG_OBJECT (qtdemux, "parsing cenc auxiliary info");
6542 gst_byte_reader_init (&br, map.data + 8, map.size);
6543 if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
6544 qtdemux->cenc_aux_info_sizes, qtdemux->cenc_aux_sample_count)) {
6545 GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
6546 gst_buffer_unmap (aux_info, &map);
6547 gst_buffer_unref (aux_info);
6548 ret = GST_FLOW_ERROR;
6549 goto beach;
6550 }
6551 gst_buffer_unmap (aux_info, &map);
6552 gst_buffer_unref (aux_info);
6553 }
6554
6555 GST_LOG_OBJECT (qtdemux, "reading %d bytes @ %" G_GUINT64_FORMAT, size,
6556 offset);
6557
6558 if (stream->use_allocator) {
6559 /* if we have a per-stream allocator, use it */
6560 buf = gst_buffer_new_allocate (stream->allocator, size, &stream->params);
6561 }
6562
6563 ret = gst_qtdemux_pull_atom (qtdemux, offset + stream->offset_in_sample,
6564 size, &buf);
6565 if (G_UNLIKELY (ret != GST_FLOW_OK))
6566 goto beach;
6567
6568 /* Update for both splitting and combining of samples */
6569 if (size != sample_size) {
6570 pts += gst_util_uint64_scale_int (GST_SECOND,
6571 stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame,
6572 stream->timescale);
6573 dts +=
6574 gst_util_uint64_scale_int (GST_SECOND,
6575 stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame,
6576 stream->timescale);
6577 duration =
6578 gst_util_uint64_scale_int (GST_SECOND,
6579 size / CUR_STREAM (stream)->bytes_per_frame, stream->timescale);
6580 }
6581
6582 ret = gst_qtdemux_decorate_and_push_buffer (qtdemux, stream, buf,
6583 dts, pts, duration, keyframe, min_time, offset);
6584
6585 if (size < sample_size) {
6586 QtDemuxSample *sample = &stream->samples[stream->sample_index];
6587 QtDemuxSegment *segment = &stream->segments[stream->segment_index];
6588
6589 GstClockTime time_position = QTSTREAMTIME_TO_GSTTIME (stream,
6590 sample->timestamp +
6591 stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame);
6592 if (time_position >= segment->media_start) {
6593 /* inside the segment, update time_position, looks very familiar to
6594 * GStreamer segments, doesn't it? */
6595 stream->time_position = (time_position - segment->media_start) +
6596 segment->time;
6597 } else {
6598 /* not yet in segment, time does not yet increment. This means
6599 * that we are still prerolling keyframes to the decoder so it can
6600 * decode the first sample of the segment. */
6601 stream->time_position = segment->time;
6602 }
6603 } else if (size > sample_size) {
6604 /* Increase to the last sample we already pulled so that advancing
6605 * below brings us to the next sample we need to pull */
6606 stream->sample_index += num_samples - 1;
6607 }
6608
6609 /* combine flows */
6610 GST_OBJECT_LOCK (qtdemux);
6611 ret = gst_qtdemux_combine_flows (qtdemux, stream, ret);
6612 GST_OBJECT_UNLOCK (qtdemux);
6613 /* ignore unlinked, we will not push on the pad anymore and we will EOS when
6614 * we have no more data for the pad to push */
6615 if (ret == GST_FLOW_EOS)
6616 ret = GST_FLOW_OK;
6617
6618 stream->offset_in_sample += size;
6619 if (stream->offset_in_sample >= sample_size) {
6620 gst_qtdemux_advance_sample (qtdemux, stream);
6621 }
6622 goto beach;
6623
6624next:
6625 gst_qtdemux_advance_sample (qtdemux, stream);
6626
6627beach:
6628 return ret;
6629
6630 /* special cases */
6631eos:
6632 {
6633 GST_DEBUG_OBJECT (qtdemux, "No samples left for any streams - EOS");
6634 ret = GST_FLOW_EOS;
6635 goto beach;
6636 }
6637eos_stream:
6638 {
6639 GST_DEBUG_OBJECT (qtdemux, "No samples left for stream");
6640 /* EOS will be raised if all are EOS */
6641 ret = GST_FLOW_OK;
6642 goto beach;
6643 }
6644}
6645
6646static void
6647gst_qtdemux_loop (GstPad * pad)
6648{
6649 GstQTDemux *qtdemux;
6650 guint64 cur_offset;
6651 GstFlowReturn ret;
6652
6653 qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
6654
6655 cur_offset = qtdemux->offset;
6656 GST_LOG_OBJECT (qtdemux, "loop at position %" G_GUINT64_FORMAT ", state %s",
6657 cur_offset, qt_demux_state_string (qtdemux->state));
6658
6659 switch (qtdemux->state) {
6660 case QTDEMUX_STATE_INITIAL:
6661 case QTDEMUX_STATE_HEADER:
6662 ret = gst_qtdemux_loop_state_header (qtdemux);
6663 break;
6664 case QTDEMUX_STATE_MOVIE:
6665 ret = gst_qtdemux_loop_state_movie (qtdemux);
6666 if (qtdemux->segment.rate < 0 && ret == GST_FLOW_EOS) {
6667 ret = gst_qtdemux_seek_to_previous_keyframe (qtdemux);
6668 }
6669 break;
6670 default:
6671 /* ouch */
6672 goto invalid_state;
6673 }
6674
6675 /* if something went wrong, pause */
6676 if (ret != GST_FLOW_OK)
6677 goto pause;
6678
6679done:
6680 gst_object_unref (qtdemux);
6681 return;
6682
6683 /* ERRORS */
6684invalid_state:
6685 {
6686 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
6687 (NULL), ("streaming stopped, invalid state"));
6688 gst_pad_pause_task (pad);
6689 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
6690 goto done;
6691 }
6692pause:
6693 {
6694 const gchar *reason = gst_flow_get_name (ret);
6695
6696 GST_LOG_OBJECT (qtdemux, "pausing task, reason %s", reason);
6697
6698 gst_pad_pause_task (pad);
6699
6700 /* fatal errors need special actions */
6701 /* check EOS */
6702 if (ret == GST_FLOW_EOS) {
6703 if (QTDEMUX_N_STREAMS (qtdemux) == 0) {
6704 /* we have no streams, post an error */
6705 gst_qtdemux_post_no_playable_stream_error (qtdemux);
6706 }
6707 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
6708 gint64 stop;
6709
6710 if ((stop = qtdemux->segment.stop) == -1)
6711 stop = qtdemux->segment.duration;
6712
6713 if (qtdemux->segment.rate >= 0) {
6714 GstMessage *message;
6715 GstEvent *event;
6716
6717 GST_LOG_OBJECT (qtdemux, "Sending segment done, at end of segment");
6718 message = gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
6719 GST_FORMAT_TIME, stop);
6720 event = gst_event_new_segment_done (GST_FORMAT_TIME, stop);
6721 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID) {
6722 gst_message_set_seqnum (message, qtdemux->segment_seqnum);
6723 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
6724 }
6725 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), message);
6726 gst_qtdemux_push_event (qtdemux, event);
6727 } else {
6728 GstMessage *message;
6729 GstEvent *event;
6730
6731 /* For Reverse Playback */
6732 GST_LOG_OBJECT (qtdemux, "Sending segment done, at start of segment");
6733 message = gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
6734 GST_FORMAT_TIME, qtdemux->segment.start);
6735 event = gst_event_new_segment_done (GST_FORMAT_TIME,
6736 qtdemux->segment.start);
6737 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID) {
6738 gst_message_set_seqnum (message, qtdemux->segment_seqnum);
6739 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
6740 }
6741 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), message);
6742 gst_qtdemux_push_event (qtdemux, event);
6743 }
6744 } else {
6745 GstEvent *event;
6746
6747 GST_LOG_OBJECT (qtdemux, "Sending EOS at end of segment");
6748 event = gst_event_new_eos ();
6749 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID)
6750 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
6751 gst_qtdemux_push_event (qtdemux, event);
6752 }
6753 } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
6754 GST_ELEMENT_FLOW_ERROR (qtdemux, ret);
6755 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
6756 }
6757 goto done;
6758 }
6759}
6760
6761/*
6762 * has_next_entry
6763 *
6764 * Returns if there are samples to be played.
6765 */
6766static gboolean
6767has_next_entry (GstQTDemux * demux)
6768{
6769 QtDemuxStream *stream;
6770 gint i;
6771
6772 GST_DEBUG_OBJECT (demux, "Checking if there are samples not played yet");
6773
6774 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
6775 stream = QTDEMUX_NTH_STREAM (demux, i);
6776
6777 if (stream->sample_index == -1) {
6778 stream->sample_index = 0;
6779 stream->offset_in_sample = 0;
6780 }
6781
6782 if (stream->sample_index >= stream->n_samples) {
6783 GST_LOG_OBJECT (demux, "track-id %u samples exhausted", stream->track_id);
6784 continue;
6785 }
6786 GST_DEBUG_OBJECT (demux, "Found a sample");
6787 return TRUE;
6788 }
6789
6790 GST_DEBUG_OBJECT (demux, "There wasn't any next sample");
6791 return FALSE;
6792}
6793
6794/*
6795 * next_entry_size
6796 *
6797 * Returns the size of the first entry at the current offset.
6798 * If -1, there are none (which means EOS or empty file).
6799 */
6800static guint64
6801next_entry_size (GstQTDemux * demux)
6802{
6803 QtDemuxStream *stream, *target_stream = NULL;
6804 guint64 smalloffs = (guint64) - 1;
6805 QtDemuxSample *sample;
6806 gint i;
6807
6808 GST_LOG_OBJECT (demux, "Finding entry at offset %" G_GUINT64_FORMAT,
6809 demux->offset);
6810
6811 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
6812 stream = QTDEMUX_NTH_STREAM (demux, i);
6813
6814 if (stream->sample_index == -1) {
6815 stream->sample_index = 0;
6816 stream->offset_in_sample = 0;
6817 }
6818
6819 if (stream->sample_index >= stream->n_samples) {
6820 GST_LOG_OBJECT (demux, "track-id %u samples exhausted", stream->track_id);
6821 continue;
6822 }
6823
6824 if (!qtdemux_parse_samples (demux, stream, stream->sample_index)) {
6825 GST_LOG_OBJECT (demux, "Parsing of index %u from stbl atom failed!",
6826 stream->sample_index);
6827 return -1;
6828 }
6829
6830 sample = &stream->samples[stream->sample_index];
6831
6832 GST_LOG_OBJECT (demux,
6833 "Checking track-id %u (sample_index:%d / offset:%" G_GUINT64_FORMAT
6834 " / size:%" G_GUINT32_FORMAT ")", stream->track_id,
6835 stream->sample_index, sample->offset, sample->size);
6836
6837 if (((smalloffs == -1)
6838 || (sample->offset < smalloffs)) && (sample->size)) {
6839 smalloffs = sample->offset;
6840 target_stream = stream;
6841 }
6842 }
6843
6844 if (!target_stream)
6845 return -1;
6846
6847 GST_LOG_OBJECT (demux,
6848 "track-id %u offset %" G_GUINT64_FORMAT " demux->offset :%"
6849 G_GUINT64_FORMAT, target_stream->track_id, smalloffs, demux->offset);
6850
6851 stream = target_stream;
6852 sample = &stream->samples[stream->sample_index];
6853
6854 if (sample->offset >= demux->offset) {
6855 demux->todrop = sample->offset - demux->offset;
6856 return sample->size + demux->todrop;
6857 }
6858
6859 GST_DEBUG_OBJECT (demux,
6860 "There wasn't any entry at offset %" G_GUINT64_FORMAT, demux->offset);
6861 return -1;
6862}
6863
6864static void
6865gst_qtdemux_post_progress (GstQTDemux * demux, gint num, gint denom)
6866{
6867 gint perc = (gint) ((gdouble) num * 100.0 / (gdouble) denom);
6868
6869 gst_element_post_message (GST_ELEMENT_CAST (demux),
6870 gst_message_new_element (GST_OBJECT_CAST (demux),
6871 gst_structure_new ("progress", "percent", G_TYPE_INT, perc, NULL)));
6872}
6873
6874static gboolean
6875qtdemux_seek_offset (GstQTDemux * demux, guint64 offset)
6876{
6877 GstEvent *event;
6878 gboolean res = 0;
6879
6880 GST_DEBUG_OBJECT (demux, "Seeking to %" G_GUINT64_FORMAT, offset);
6881
6882 event =
6883 gst_event_new_seek (1.0, GST_FORMAT_BYTES,
6884 GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset,
6885 GST_SEEK_TYPE_NONE, -1);
6886
6887 /* store seqnum to drop flush events, they don't need to reach downstream */
6888 demux->offset_seek_seqnum = gst_event_get_seqnum (event);
6889 res = gst_pad_push_event (demux->sinkpad, event);
6890 demux->offset_seek_seqnum = GST_SEQNUM_INVALID;
6891
6892 return res;
6893}
6894
6895/* check for seekable upstream, above and beyond a mere query */
6896static void
6897gst_qtdemux_check_seekability (GstQTDemux * demux)
6898{
6899 GstQuery *query;
6900 gboolean seekable = FALSE;
6901 gint64 start = -1, stop = -1;
6902
6903 if (demux->upstream_size)
6904 return;
6905
6906 if (demux->upstream_format_is_time)
6907 return;
6908
6909 query = gst_query_new_seeking (GST_FORMAT_BYTES);
6910 if (!gst_pad_peer_query (demux->sinkpad, query)) {
6911 GST_DEBUG_OBJECT (demux, "seeking query failed");
6912 goto done;
6913 }
6914
6915 gst_query_parse_seeking (query, NULL, &seekable, &start, &stop);
6916
6917 /* try harder to query upstream size if we didn't get it the first time */
6918 if (seekable && stop == -1) {
6919 GST_DEBUG_OBJECT (demux, "doing duration query to fix up unset stop");
6920 gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &stop);
6921 }
6922
6923 /* if upstream doesn't know the size, it's likely that it's not seekable in
6924 * practice even if it technically may be seekable */
6925 if (seekable && (start != 0 || stop <= start)) {
6926 GST_DEBUG_OBJECT (demux, "seekable but unknown start/stop -> disable");
6927 seekable = FALSE;
6928 }
6929
6930done:
6931 gst_query_unref (query);
6932
6933 GST_DEBUG_OBJECT (demux, "seekable: %d (%" G_GUINT64_FORMAT " - %"
6934 G_GUINT64_FORMAT ")", seekable, start, stop);
6935 demux->upstream_seekable = seekable;
6936 demux->upstream_size = seekable ? stop : -1;
6937}
6938
6939static void
6940gst_qtdemux_drop_data (GstQTDemux * demux, gint bytes)
6941{
6942 g_return_if_fail (bytes <= demux->todrop);
6943
6944 GST_LOG_OBJECT (demux, "Dropping %d bytes", bytes);
6945 gst_adapter_flush (demux->adapter, bytes);
6946 demux->neededbytes -= bytes;
6947 demux->offset += bytes;
6948 demux->todrop -= bytes;
6949}
6950
6951/* PUSH-MODE only: Send a segment, if not done already. */
6952static void
6953gst_qtdemux_check_send_pending_segment (GstQTDemux * demux)
6954{
6955 if (G_UNLIKELY (demux->need_segment)) {
6956 gint i;
6957
6958 if (!demux->upstream_format_is_time) {
6959 gst_qtdemux_map_and_push_segments (demux, &demux->segment);
6960 } else {
6961 GstEvent *segment_event;
6962 segment_event = gst_event_new_segment (&demux->segment);
6963 if (demux->segment_seqnum != GST_SEQNUM_INVALID)
6964 gst_event_set_seqnum (segment_event, demux->segment_seqnum);
6965 gst_qtdemux_push_event (demux, segment_event);
6966 }
6967
6968 demux->need_segment = FALSE;
6969
6970 /* clear to send tags on all streams */
6971 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
6972 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (demux, i);
6973 gst_qtdemux_push_tags (demux, stream);
6974 if (CUR_STREAM (stream)->sparse) {
6975 GST_INFO_OBJECT (demux, "Sending gap event on stream %d", i);
6976 gst_pad_push_event (stream->pad,
6977 gst_event_new_gap (stream->segment.position, GST_CLOCK_TIME_NONE));
6978 }
6979 }
6980 }
6981}
6982
6983/* Used for push mode only. */
6984static void
6985gst_qtdemux_send_gap_for_segment (GstQTDemux * demux,
6986 QtDemuxStream * stream, gint segment_index, GstClockTime pos)
6987{
6988 GstClockTime ts, dur;
6989
6990 ts = pos;
6991 dur =
6992 stream->segments[segment_index].duration - (pos -
6993 stream->segments[segment_index].time);
6994 stream->time_position += dur;
6995
6996 /* Only gaps with a duration of at least one second are propagated.
6997 * Same workaround as in pull mode.
6998 * (See 2e45926a96ec5298c6ef29bf912e5e6a06dc3e0e) */
6999 if (dur >= GST_SECOND) {
7000 GstEvent *gap;
7001 gap = gst_event_new_gap (ts, dur);
7002
7003 GST_DEBUG_OBJECT (stream->pad, "Pushing gap for empty "
7004 "segment: %" GST_PTR_FORMAT, gap);
7005 gst_pad_push_event (stream->pad, gap);
7006 }
7007}
7008
7009static GstFlowReturn
7010gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent, GstBuffer * inbuf)
7011{
7012 GstQTDemux *demux;
7013
7014 demux = GST_QTDEMUX (parent);
7015
7016 GST_DEBUG_OBJECT (demux,
7017 "Received buffer pts:%" GST_TIME_FORMAT " dts:%" GST_TIME_FORMAT
7018 " offset:%" G_GUINT64_FORMAT " size:%" G_GSIZE_FORMAT " demux offset:%"
7019 G_GUINT64_FORMAT, GST_TIME_ARGS (GST_BUFFER_PTS (inbuf)),
7020 GST_TIME_ARGS (GST_BUFFER_DTS (inbuf)), GST_BUFFER_OFFSET (inbuf),
7021 gst_buffer_get_size (inbuf), demux->offset);
7022
7023 if (GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_DISCONT)) {
7024 gboolean is_gap_input = FALSE;
7025 gint i;
7026
7027 GST_DEBUG_OBJECT (demux, "Got DISCONT, marking all streams as DISCONT");
7028
7029 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
7030 QTDEMUX_NTH_STREAM (demux, i)->discont = TRUE;
7031 }
7032
7033 /* Check if we can land back on our feet in the case where upstream is
7034 * handling the seeking/pushing of samples with gaps in between (like
7035 * in the case of trick-mode DASH for example) */
7036 if (demux->upstream_format_is_time
7037 && GST_BUFFER_OFFSET (inbuf) != GST_BUFFER_OFFSET_NONE) {
7038 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
7039 guint32 res;
7040 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (demux, i);
7041 GST_LOG_OBJECT (demux,
7042 "track-id #%u , checking if offset %" G_GUINT64_FORMAT
7043 " is a sample start", stream->track_id, GST_BUFFER_OFFSET (inbuf));
7044 res =
7045 gst_qtdemux_find_index_for_given_media_offset_linear (demux,
7046 stream, GST_BUFFER_OFFSET (inbuf));
7047 if (res != -1) {
7048 QtDemuxSample *sample = &stream->samples[res];
7049 GST_LOG_OBJECT (demux,
7050 "Checking if sample %d from track-id %u is valid (offset:%"
7051 G_GUINT64_FORMAT " size:%" G_GUINT32_FORMAT ")", res,
7052 stream->track_id, sample->offset, sample->size);
7053 if (sample->offset == GST_BUFFER_OFFSET (inbuf)) {
7054 GST_LOG_OBJECT (demux,
7055 "new buffer corresponds to a valid sample : %" G_GUINT32_FORMAT,
7056 res);
7057 is_gap_input = TRUE;
7058 /* We can go back to standard playback mode */
7059 demux->state = QTDEMUX_STATE_MOVIE;
7060 /* Remember which sample this stream is at */
7061 stream->sample_index = res;
7062 /* Finally update all push-based values to the expected values */
7063 demux->neededbytes = stream->samples[res].size;
7064 demux->offset = GST_BUFFER_OFFSET (inbuf);
7065 demux->mdatleft =
7066 demux->mdatsize - demux->offset + demux->mdatoffset;
7067 demux->todrop = 0;
7068 }
7069 }
7070 }
7071 if (!is_gap_input) {
7072 GST_DEBUG_OBJECT (demux, "Resetting, actual DISCONT");
7073 /* Reset state if it's a real discont */
7074 demux->neededbytes = 16;
7075 demux->state = QTDEMUX_STATE_INITIAL;
7076 demux->offset = GST_BUFFER_OFFSET (inbuf);
7077 gst_adapter_clear (demux->adapter);
7078 }
7079 }
7080 /* Reverse fragmented playback, need to flush all we have before
7081 * consuming a new fragment.
7082 * The samples array have the timestamps calculated by accumulating the
7083 * durations but this won't work for reverse playback of fragments as
7084 * the timestamps of a subsequent fragment should be smaller than the
7085 * previously received one. */
7086 if (!is_gap_input && demux->fragmented && demux->segment.rate < 0) {
7087 gst_qtdemux_process_adapter (demux, TRUE);
7088 g_ptr_array_foreach (demux->active_streams,
7089 (GFunc) gst_qtdemux_stream_flush_samples_data, NULL);
7090 }
7091 }
7092
7093 gst_adapter_push (demux->adapter, inbuf);
7094
7095 GST_DEBUG_OBJECT (demux,
7096 "pushing in inbuf %p, neededbytes:%u, available:%" G_GSIZE_FORMAT, inbuf,
7097 demux->neededbytes, gst_adapter_available (demux->adapter));
7098
7099 return gst_qtdemux_process_adapter (demux, FALSE);
7100}
7101
7102static GstFlowReturn
7103gst_qtdemux_process_adapter (GstQTDemux * demux, gboolean force)
7104{
7105 GstFlowReturn ret = GST_FLOW_OK;
7106
7107 /* we never really mean to buffer that much */
7108 if (demux->neededbytes == -1) {
7109 goto eos;
7110 }
7111
7112 while (((gst_adapter_available (demux->adapter)) >= demux->neededbytes) &&
7113 (ret == GST_FLOW_OK || (ret == GST_FLOW_NOT_LINKED && force))) {
7114
7115#ifndef GST_DISABLE_GST_DEBUG
7116 {
7117 guint64 discont_offset, distance_from_discont;
7118
7119 discont_offset = gst_adapter_offset_at_discont (demux->adapter);
7120 distance_from_discont =
7121 gst_adapter_distance_from_discont (demux->adapter);
7122
7123 GST_DEBUG_OBJECT (demux,
7124 "state:%s , demux->neededbytes:%d, demux->offset:%" G_GUINT64_FORMAT
7125 " adapter offset :%" G_GUINT64_FORMAT " (+ %" G_GUINT64_FORMAT
7126 " bytes)", qt_demux_state_string (demux->state), demux->neededbytes,
7127 demux->offset, discont_offset, distance_from_discont);
7128 }
7129#endif
7130
7131 switch (demux->state) {
7132 case QTDEMUX_STATE_INITIAL:{
7133 const guint8 *data;
7134 guint32 fourcc;
7135 guint64 size;
7136
7137 gst_qtdemux_check_seekability (demux);
7138
7139 data = gst_adapter_map (demux->adapter, demux->neededbytes);
7140
7141 /* get fourcc/length, set neededbytes */
7142 extract_initial_length_and_fourcc ((guint8 *) data, demux->neededbytes,
7143 &size, &fourcc);
7144 gst_adapter_unmap (demux->adapter);
7145 data = NULL;
7146 GST_DEBUG_OBJECT (demux, "Peeking found [%" GST_FOURCC_FORMAT "] "
7147 "size: %" G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), size);
7148 if (size == 0) {
7149 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
7150 (_("This file is invalid and cannot be played.")),
7151 ("initial atom '%" GST_FOURCC_FORMAT "' has empty length",
7152 GST_FOURCC_ARGS (fourcc)));
7153 ret = GST_FLOW_ERROR;
7154 break;
7155 }
7156 if (fourcc == FOURCC_mdat) {
7157 gint next_entry = next_entry_size (demux);
7158 if (QTDEMUX_N_STREAMS (demux) > 0 && (next_entry != -1
7159 || !demux->fragmented)) {
7160 /* we have the headers, start playback */
7161 demux->state = QTDEMUX_STATE_MOVIE;
7162 demux->neededbytes = next_entry;
7163 demux->mdatleft = size;
7164 demux->mdatsize = demux->mdatleft;
7165 } else {
7166 /* no headers yet, try to get them */
7167 guint bs;
7168 gboolean res;
7169 guint64 old, target;
7170
7171 buffer_data:
7172 old = demux->offset;
7173 target = old + size;
7174
7175 /* try to jump over the atom with a seek */
7176 /* only bother if it seems worth doing so,
7177 * and avoids possible upstream/server problems */
7178 if (demux->upstream_seekable &&
7179 demux->upstream_size > 4 * (1 << 20)) {
7180 res = qtdemux_seek_offset (demux, target);
7181 } else {
7182 GST_DEBUG_OBJECT (demux, "skipping seek");
7183 res = FALSE;
7184 }
7185
7186 if (res) {
7187 GST_DEBUG_OBJECT (demux, "seek success");
7188 /* remember the offset fo the first mdat so we can seek back to it
7189 * after we have the headers */
7190 if (fourcc == FOURCC_mdat && demux->first_mdat == -1) {
7191 demux->first_mdat = old;
7192 GST_DEBUG_OBJECT (demux, "first mdat at %" G_GUINT64_FORMAT,
7193 demux->first_mdat);
7194 }
7195 /* seek worked, continue reading */
7196 demux->offset = target;
7197 demux->neededbytes = 16;
7198 demux->state = QTDEMUX_STATE_INITIAL;
7199 } else {
7200 /* seek failed, need to buffer */
7201 demux->offset = old;
7202 GST_DEBUG_OBJECT (demux, "seek failed/skipped");
7203 /* there may be multiple mdat (or alike) buffers */
7204 /* sanity check */
7205 if (demux->mdatbuffer)
7206 bs = gst_buffer_get_size (demux->mdatbuffer);
7207 else
7208 bs = 0;
7209 if (size + bs > 10 * (1 << 20))
7210 goto no_moov;
7211 demux->state = QTDEMUX_STATE_BUFFER_MDAT;
7212 demux->neededbytes = size;
7213 if (!demux->mdatbuffer)
7214 demux->mdatoffset = demux->offset;
7215 }
7216 }
7217 } else if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
7218 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
7219 (_("This file is invalid and cannot be played.")),
7220 ("atom %" GST_FOURCC_FORMAT " has bogus size %" G_GUINT64_FORMAT,
7221 GST_FOURCC_ARGS (fourcc), size));
7222 ret = GST_FLOW_ERROR;
7223 break;
7224 } else {
7225 /* this means we already started buffering and still no moov header,
7226 * let's continue buffering everything till we get moov */
7227 if (demux->mdatbuffer && !(fourcc == FOURCC_moov
7228 || fourcc == FOURCC_moof))
7229 goto buffer_data;
7230 demux->neededbytes = size;
7231 demux->state = QTDEMUX_STATE_HEADER;
7232 }
7233 break;
7234 }
7235 case QTDEMUX_STATE_HEADER:{
7236 const guint8 *data;
7237 guint32 fourcc;
7238
7239 GST_DEBUG_OBJECT (demux, "In header");
7240
7241 data = gst_adapter_map (demux->adapter, demux->neededbytes);
7242
7243 /* parse the header */
7244 extract_initial_length_and_fourcc (data, demux->neededbytes, NULL,
7245 &fourcc);
7246 if (fourcc == FOURCC_moov) {
7247 /* in usual fragmented setup we could try to scan for more
7248 * and end up at the the moov (after mdat) again */
7249 if (demux->got_moov && QTDEMUX_N_STREAMS (demux) > 0 &&
7250 (!demux->fragmented
7251 || demux->last_moov_offset == demux->offset)) {
7252 GST_DEBUG_OBJECT (demux,
7253 "Skipping moov atom as we have (this) one already");
7254 } else {
7255 GST_DEBUG_OBJECT (demux, "Parsing [moov]");
7256
7257 if (demux->got_moov && demux->fragmented) {
7258 GST_DEBUG_OBJECT (demux,
7259 "Got a second moov, clean up data from old one");
7260 if (demux->moov_node_compressed) {
7261 g_node_destroy (demux->moov_node_compressed);
7262 if (demux->moov_node)
7263 g_free (demux->moov_node->data);
7264 }
7265 demux->moov_node_compressed = NULL;
7266 if (demux->moov_node)
7267 g_node_destroy (demux->moov_node);
7268 demux->moov_node = NULL;
7269 }
7270
7271 demux->last_moov_offset = demux->offset;
7272
7273 /* Update streams with new moov */
7274 gst_qtdemux_stream_concat (demux,
7275 demux->old_streams, demux->active_streams);
7276
7277 qtdemux_parse_moov (demux, data, demux->neededbytes);
7278 qtdemux_node_dump (demux, demux->moov_node);
7279 qtdemux_parse_tree (demux);
7280 qtdemux_prepare_streams (demux);
7281 QTDEMUX_EXPOSE_LOCK (demux);
7282 qtdemux_expose_streams (demux);
7283 QTDEMUX_EXPOSE_UNLOCK (demux);
7284
7285 demux->got_moov = TRUE;
7286
7287 gst_qtdemux_check_send_pending_segment (demux);
7288
7289 if (demux->moov_node_compressed) {
7290 g_node_destroy (demux->moov_node_compressed);
7291 g_free (demux->moov_node->data);
7292 }
7293 demux->moov_node_compressed = NULL;
7294 g_node_destroy (demux->moov_node);
7295 demux->moov_node = NULL;
7296 GST_DEBUG_OBJECT (demux, "Finished parsing the header");
7297 }
7298 } else if (fourcc == FOURCC_moof) {
7299 if ((demux->got_moov || demux->media_caps) && demux->fragmented) {
7300 guint64 dist = 0;
7301 GstClockTime prev_pts;
7302 guint64 prev_offset;
7303 guint64 adapter_discont_offset, adapter_discont_dist;
7304
7305 GST_DEBUG_OBJECT (demux, "Parsing [moof]");
7306
7307 /*
7308 * The timestamp of the moof buffer is relevant as some scenarios
7309 * won't have the initial timestamp in the atoms. Whenever a new
7310 * buffer has started, we get that buffer's PTS and use it as a base
7311 * timestamp for the trun entries.
7312 *
7313 * To keep track of the current buffer timestamp and starting point
7314 * we use gst_adapter_prev_pts that gives us the PTS and the distance
7315 * from the beginning of the buffer, with the distance and demux->offset
7316 * we know if it is still the same buffer or not.
7317 */
7318 prev_pts = gst_adapter_prev_pts (demux->adapter, &dist);
7319 prev_offset = demux->offset - dist;
7320 if (demux->fragment_start_offset == -1
7321 || prev_offset > demux->fragment_start_offset) {
7322 demux->fragment_start_offset = prev_offset;
7323 demux->fragment_start = prev_pts;
7324 GST_DEBUG_OBJECT (demux,
7325 "New fragment start found at: %" G_GUINT64_FORMAT " : %"
7326 GST_TIME_FORMAT, demux->fragment_start_offset,
7327 GST_TIME_ARGS (demux->fragment_start));
7328 }
7329
7330 /* We can't use prev_offset() here because this would require
7331 * upstream to set consistent and correct offsets on all buffers
7332 * since the discont. Nothing ever did that in the past and we
7333 * would break backwards compatibility here then.
7334 * Instead take the offset we had at the last discont and count
7335 * the bytes from there. This works with old code as there would
7336 * be no discont between moov and moof, and also works with
7337 * adaptivedemux which correctly sets offset and will set the
7338 * DISCONT flag accordingly when needed.
7339 *
7340 * We also only do this for upstream TIME segments as otherwise
7341 * there are potential backwards compatibility problems with
7342 * seeking in PUSH mode and upstream providing inconsistent
7343 * timestamps. */
7344 adapter_discont_offset =
7345 gst_adapter_offset_at_discont (demux->adapter);
7346 adapter_discont_dist =
7347 gst_adapter_distance_from_discont (demux->adapter);
7348
7349 GST_DEBUG_OBJECT (demux,
7350 "demux offset %" G_GUINT64_FORMAT " adapter offset %"
7351 G_GUINT64_FORMAT " (+ %" G_GUINT64_FORMAT " bytes)",
7352 demux->offset, adapter_discont_offset, adapter_discont_dist);
7353
7354 if (demux->upstream_format_is_time) {
7355 demux->moof_offset = adapter_discont_offset;
7356 if (demux->moof_offset != GST_BUFFER_OFFSET_NONE)
7357 demux->moof_offset += adapter_discont_dist;
7358 if (demux->moof_offset == GST_BUFFER_OFFSET_NONE)
7359 demux->moof_offset = demux->offset;
7360 } else {
7361 demux->moof_offset = demux->offset;
7362 }
7363
7364 if (!qtdemux_parse_moof (demux, data, demux->neededbytes,
7365 demux->moof_offset, NULL)) {
7366 gst_adapter_unmap (demux->adapter);
7367 ret = GST_FLOW_ERROR;
7368 goto done;
7369 }
7370
7371 /* in MSS we need to expose the pads after the first moof as we won't get a moov */
7372 if (demux->variant == VARIANT_MSS_FRAGMENTED && !demux->exposed) {
7373 QTDEMUX_EXPOSE_LOCK (demux);
7374 qtdemux_expose_streams (demux);
7375 QTDEMUX_EXPOSE_UNLOCK (demux);
7376 }
7377
7378 gst_qtdemux_check_send_pending_segment (demux);
7379 } else {
7380 GST_DEBUG_OBJECT (demux, "Discarding [moof]");
7381 }
7382 } else if (fourcc == FOURCC_ftyp) {
7383 GST_DEBUG_OBJECT (demux, "Parsing [ftyp]");
7384 qtdemux_parse_ftyp (demux, data, demux->neededbytes);
7385 } else if (fourcc == FOURCC_uuid) {
7386 GST_DEBUG_OBJECT (demux, "Parsing [uuid]");
7387 qtdemux_parse_uuid (demux, data, demux->neededbytes);
7388 } else if (fourcc == FOURCC_sidx) {
7389 GST_DEBUG_OBJECT (demux, "Parsing [sidx]");
7390 qtdemux_parse_sidx (demux, data, demux->neededbytes);
7391 } else {
7392 switch (fourcc) {
7393 case FOURCC_styp:
7394 /* [styp] is like a [ftyp], but in fragment header. We ignore it for now
7395 * FALLTHROUGH */
7396 case FOURCC_skip:
7397 case FOURCC_free:
7398 /* [free] and [skip] are padding atoms */
7399 GST_DEBUG_OBJECT (demux,
7400 "Skipping fourcc while parsing header : %" GST_FOURCC_FORMAT,
7401 GST_FOURCC_ARGS (fourcc));
7402 break;
7403 default:
7404 GST_WARNING_OBJECT (demux,
7405 "Unknown fourcc while parsing header : %" GST_FOURCC_FORMAT,
7406 GST_FOURCC_ARGS (fourcc));
7407 /* Let's jump that one and go back to initial state */
7408 break;
7409 }
7410 }
7411 gst_adapter_unmap (demux->adapter);
7412 data = NULL;
7413
7414 if (demux->mdatbuffer && QTDEMUX_N_STREAMS (demux)) {
7415 gsize remaining_data_size = 0;
7416
7417 /* the mdat was before the header */
7418 GST_DEBUG_OBJECT (demux, "We have n_streams:%d and mdatbuffer:%p",
7419 QTDEMUX_N_STREAMS (demux), demux->mdatbuffer);
7420 /* restore our adapter/offset view of things with upstream;
7421 * put preceding buffered data ahead of current moov data.
7422 * This should also handle evil mdat, moov, mdat cases and alike */
7423 gst_adapter_flush (demux->adapter, demux->neededbytes);
7424
7425 /* Store any remaining data after the mdat for later usage */
7426 remaining_data_size = gst_adapter_available (demux->adapter);
7427 if (remaining_data_size > 0) {
7428 g_assert (demux->restoredata_buffer == NULL);
7429 demux->restoredata_buffer =
7430 gst_adapter_take_buffer (demux->adapter, remaining_data_size);
7431 demux->restoredata_offset = demux->offset + demux->neededbytes;
7432 GST_DEBUG_OBJECT (demux,
7433 "Stored %" G_GSIZE_FORMAT " post mdat bytes at offset %"
7434 G_GUINT64_FORMAT, remaining_data_size,
7435 demux->restoredata_offset);
7436 }
7437
7438 gst_adapter_push (demux->adapter, demux->mdatbuffer);
7439 demux->mdatbuffer = NULL;
7440 demux->offset = demux->mdatoffset;
7441 demux->neededbytes = next_entry_size (demux);
7442 demux->state = QTDEMUX_STATE_MOVIE;
7443 demux->mdatleft = gst_adapter_available (demux->adapter);
7444 demux->mdatsize = demux->mdatleft;
7445 } else {
7446 GST_DEBUG_OBJECT (demux, "Carrying on normally");
7447 gst_adapter_flush (demux->adapter, demux->neededbytes);
7448
7449 /* only go back to the mdat if there are samples to play */
7450 if (demux->got_moov && demux->first_mdat != -1
7451 && has_next_entry (demux)) {
7452 gboolean res;
7453
7454 /* we need to seek back */
7455 res = qtdemux_seek_offset (demux, demux->first_mdat);
7456 if (res) {
7457 demux->offset = demux->first_mdat;
7458 } else {
7459 GST_DEBUG_OBJECT (demux, "Seek back failed");
7460 }
7461 } else {
7462 demux->offset += demux->neededbytes;
7463 }
7464 demux->neededbytes = 16;
7465 demux->state = QTDEMUX_STATE_INITIAL;
7466 }
7467
7468 break;
7469 }
7470 case QTDEMUX_STATE_BUFFER_MDAT:{
7471 GstBuffer *buf;
7472 guint8 fourcc[4];
7473
7474 GST_DEBUG_OBJECT (demux, "Got our buffer at offset %" G_GUINT64_FORMAT,
7475 demux->offset);
7476 buf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
7477 gst_buffer_extract (buf, 0, fourcc, 4);
7478 GST_DEBUG_OBJECT (demux, "mdatbuffer starts with %" GST_FOURCC_FORMAT,
7479 GST_FOURCC_ARGS (QT_FOURCC (fourcc)));
7480 if (demux->mdatbuffer)
7481 demux->mdatbuffer = gst_buffer_append (demux->mdatbuffer, buf);
7482 else
7483 demux->mdatbuffer = buf;
7484 demux->offset += demux->neededbytes;
7485 demux->neededbytes = 16;
7486 demux->state = QTDEMUX_STATE_INITIAL;
7487 gst_qtdemux_post_progress (demux, 1, 1);
7488
7489 break;
7490 }
7491 case QTDEMUX_STATE_MOVIE:{
7492 QtDemuxStream *stream = NULL;
7493 QtDemuxSample *sample;
7494 GstClockTime dts, pts, duration;
7495 gboolean keyframe;
7496 gint i;
7497
7498 GST_DEBUG_OBJECT (demux,
7499 "BEGIN // in MOVIE for offset %" G_GUINT64_FORMAT, demux->offset);
7500
7501 if (demux->fragmented) {
7502 GST_DEBUG_OBJECT (demux, "mdat remaining %" G_GUINT64_FORMAT,
7503 demux->mdatleft);
7504 if (G_LIKELY (demux->todrop < demux->mdatleft)) {
7505 /* if needed data starts within this atom,
7506 * then it should not exceed this atom */
7507 if (G_UNLIKELY (demux->neededbytes > demux->mdatleft)) {
7508 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
7509 (_("This file is invalid and cannot be played.")),
7510 ("sample data crosses atom boundary"));
7511 ret = GST_FLOW_ERROR;
7512 break;
7513 }
7514 demux->mdatleft -= demux->neededbytes;
7515 } else {
7516 GST_DEBUG_OBJECT (demux, "data atom emptied; resuming atom scan");
7517 /* so we are dropping more than left in this atom */
7518 gst_qtdemux_drop_data (demux, demux->mdatleft);
7519 demux->mdatleft = 0;
7520
7521 /* need to resume atom parsing so we do not miss any other pieces */
7522 demux->state = QTDEMUX_STATE_INITIAL;
7523 demux->neededbytes = 16;
7524
7525 /* check if there was any stored post mdat data from previous buffers */
7526 if (demux->restoredata_buffer) {
7527 g_assert (gst_adapter_available (demux->adapter) == 0);
7528
7529 gst_adapter_push (demux->adapter, demux->restoredata_buffer);
7530 demux->restoredata_buffer = NULL;
7531 demux->offset = demux->restoredata_offset;
7532 }
7533
7534 break;
7535 }
7536 }
7537
7538 if (demux->todrop) {
7539 if (demux->cenc_aux_info_offset > 0) {
7540 GstByteReader br;
7541 const guint8 *data;
7542
7543 GST_DEBUG_OBJECT (demux, "parsing cenc auxiliary info");
7544 data = gst_adapter_map (demux->adapter, demux->todrop);
7545 gst_byte_reader_init (&br, data + 8, demux->todrop);
7546 if (!qtdemux_parse_cenc_aux_info (demux,
7547 QTDEMUX_NTH_STREAM (demux, 0), &br,
7548 demux->cenc_aux_info_sizes, demux->cenc_aux_sample_count)) {
7549 GST_ERROR_OBJECT (demux, "failed to parse cenc auxiliary info");
7550 ret = GST_FLOW_ERROR;
7551 gst_adapter_unmap (demux->adapter);
7552 g_free (demux->cenc_aux_info_sizes);
7553 demux->cenc_aux_info_sizes = NULL;
7554 goto done;
7555 }
7556 demux->cenc_aux_info_offset = 0;
7557 g_free (demux->cenc_aux_info_sizes);
7558 demux->cenc_aux_info_sizes = NULL;
7559 gst_adapter_unmap (demux->adapter);
7560 }
7561 gst_qtdemux_drop_data (demux, demux->todrop);
7562 }
7563
7564 /* first buffer? */
7565 /* initial newsegment sent here after having added pads,
7566 * possible others in sink_event */
7567 gst_qtdemux_check_send_pending_segment (demux);
7568
7569 /* Figure out which stream this packet belongs to */
7570 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
7571 stream = QTDEMUX_NTH_STREAM (demux, i);
7572 if (stream->sample_index >= stream->n_samples) {
7573 /* reset to be checked below G_UNLIKELY (stream == NULL) */
7574 stream = NULL;
7575 continue;
7576 }
7577 GST_LOG_OBJECT (demux,
7578 "Checking track-id %u (sample_index:%d / offset:%"
7579 G_GUINT64_FORMAT " / size:%d)", stream->track_id,
7580 stream->sample_index,
7581 stream->samples[stream->sample_index].offset,
7582 stream->samples[stream->sample_index].size);
7583
7584 if (stream->samples[stream->sample_index].offset == demux->offset)
7585 break;
7586 }
7587
7588 if (G_UNLIKELY (stream == NULL))
7589 goto unknown_stream;
7590
7591 gst_qtdemux_stream_check_and_change_stsd_index (demux, stream);
7592
7593 if (stream->new_caps) {
7594 gst_qtdemux_configure_stream (demux, stream);
7595 }
7596
7597 /* Put data in a buffer, set timestamps, caps, ... */
7598 sample = &stream->samples[stream->sample_index];
7599
7600 if (G_LIKELY (!(STREAM_IS_EOS (stream)))) {
7601 GST_DEBUG_OBJECT (demux, "stream : %" GST_FOURCC_FORMAT,
7602 GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
7603
7604 dts = QTSAMPLE_DTS (stream, sample);
7605 pts = QTSAMPLE_PTS (stream, sample);
7606 duration = QTSAMPLE_DUR_DTS (stream, sample, dts);
7607 keyframe = QTSAMPLE_KEYFRAME (stream, sample);
7608
7609 /* check for segment end */
zengliang.li4681ee42024-05-16 12:25:30 +00007610 if (G_UNLIKELY (demux->segment.stop != -1 && GST_CLOCK_TIME_IS_VALID(dts)
zengliang.li5f31ef42024-05-16 08:27:38 +00007611 && demux->segment.stop <= pts && stream->on_keyframe)
7612 && !(demux->upstream_format_is_time && demux->segment.rate < 0)) {
7613 GST_DEBUG_OBJECT (demux, "we reached the end of our segment.");
7614 stream->time_position = GST_CLOCK_TIME_NONE; /* this means EOS */
7615
7616 /* skip this data, stream is EOS */
7617 gst_adapter_flush (demux->adapter, demux->neededbytes);
7618 demux->offset += demux->neededbytes;
7619
7620 /* check if all streams are eos */
7621 ret = GST_FLOW_EOS;
7622 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
7623 if (!STREAM_IS_EOS (QTDEMUX_NTH_STREAM (demux, i))) {
7624 ret = GST_FLOW_OK;
7625 break;
7626 }
7627 }
7628 } else {
7629 GstBuffer *outbuf;
7630
7631 outbuf =
7632 gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
7633
7634 /* FIXME: should either be an assert or a plain check */
7635 g_return_val_if_fail (outbuf != NULL, GST_FLOW_ERROR);
7636
7637 ret = gst_qtdemux_decorate_and_push_buffer (demux, stream, outbuf,
7638 dts, pts, duration, keyframe, dts, demux->offset);
7639 }
7640
7641 /* combine flows */
7642 GST_OBJECT_LOCK (demux);
7643 ret = gst_qtdemux_combine_flows (demux, stream, ret);
7644 GST_OBJECT_UNLOCK (demux);
7645 } else {
7646 /* skip this data, stream is EOS */
7647 gst_adapter_flush (demux->adapter, demux->neededbytes);
7648 }
7649
7650 stream->sample_index++;
7651 stream->offset_in_sample = 0;
7652
7653 /* update current offset and figure out size of next buffer */
7654 GST_LOG_OBJECT (demux, "increasing offset %" G_GUINT64_FORMAT " by %u",
7655 demux->offset, demux->neededbytes);
7656 demux->offset += demux->neededbytes;
7657 GST_LOG_OBJECT (demux, "offset is now %" G_GUINT64_FORMAT,
7658 demux->offset);
7659
7660
7661 if (ret == GST_FLOW_EOS) {
7662 GST_DEBUG_OBJECT (demux, "All streams are EOS, signal upstream");
7663 demux->neededbytes = -1;
7664 goto eos;
7665 }
7666
7667 if ((demux->neededbytes = next_entry_size (demux)) == -1) {
7668 if (demux->fragmented) {
7669 GST_DEBUG_OBJECT (demux, "(temporarily) out of fragmented samples");
7670 /* there may be more to follow, only finish this atom */
7671 demux->todrop = demux->mdatleft;
7672 demux->neededbytes = demux->todrop;
7673 break;
7674 }
7675 goto eos;
7676 }
7677 if (ret != GST_FLOW_OK && ret != GST_FLOW_NOT_LINKED) {
7678 goto non_ok_unlinked_flow;
7679 }
7680 break;
7681 }
7682 default:
7683 goto invalid_state;
7684 }
7685 }
7686
7687 /* when buffering movie data, at least show user something is happening */
7688 if (ret == GST_FLOW_OK && demux->state == QTDEMUX_STATE_BUFFER_MDAT &&
7689 gst_adapter_available (demux->adapter) <= demux->neededbytes) {
7690 gst_qtdemux_post_progress (demux, gst_adapter_available (demux->adapter),
7691 demux->neededbytes);
7692 }
7693done:
7694
7695 return ret;
7696
7697 /* ERRORS */
7698non_ok_unlinked_flow:
7699 {
7700 GST_DEBUG_OBJECT (demux, "Stopping, combined return flow %s",
7701 gst_flow_get_name (ret));
7702 return ret;
7703 }
7704unknown_stream:
7705 {
7706 GST_ELEMENT_ERROR (demux, STREAM, FAILED, (NULL), ("unknown stream found"));
7707 ret = GST_FLOW_ERROR;
7708 goto done;
7709 }
7710eos:
7711 {
7712 GST_DEBUG_OBJECT (demux, "no next entry, EOS");
7713 ret = GST_FLOW_EOS;
7714 goto done;
7715 }
7716invalid_state:
7717 {
7718 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
7719 (NULL), ("qtdemuxer invalid state %d", demux->state));
7720 ret = GST_FLOW_ERROR;
7721 goto done;
7722 }
7723no_moov:
7724 {
7725 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
7726 (NULL), ("no 'moov' atom within the first 10 MB"));
7727 ret = GST_FLOW_ERROR;
7728 goto done;
7729 }
7730}
7731
7732static gboolean
7733qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent)
7734{
7735 GstQuery *query;
7736 gboolean pull_mode;
7737
7738 query = gst_query_new_scheduling ();
7739
7740 if (!gst_pad_peer_query (sinkpad, query)) {
7741 gst_query_unref (query);
7742 goto activate_push;
7743 }
7744
7745 pull_mode = gst_query_has_scheduling_mode_with_flags (query,
7746 GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
7747 gst_query_unref (query);
7748
7749 if (!pull_mode)
7750 goto activate_push;
7751
7752 GST_DEBUG_OBJECT (sinkpad, "activating pull");
7753 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
7754
7755activate_push:
7756 {
7757 GST_DEBUG_OBJECT (sinkpad, "activating push");
7758 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
7759 }
7760}
7761
7762static gboolean
7763qtdemux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
7764 GstPadMode mode, gboolean active)
7765{
7766 gboolean res;
7767 GstQTDemux *demux = GST_QTDEMUX (parent);
7768
7769 switch (mode) {
7770 case GST_PAD_MODE_PUSH:
7771 demux->pullbased = FALSE;
7772 res = TRUE;
7773 break;
7774 case GST_PAD_MODE_PULL:
7775 if (active) {
7776 demux->pullbased = TRUE;
7777 res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_qtdemux_loop,
7778 sinkpad, NULL);
7779 } else {
7780 res = gst_pad_stop_task (sinkpad);
7781 }
7782 break;
7783 default:
7784 res = FALSE;
7785 break;
7786 }
7787 return res;
7788}
7789
7790#ifdef HAVE_ZLIB
7791static void *
7792qtdemux_inflate (void *z_buffer, guint z_length, guint * length)
7793{
7794 guint8 *buffer;
7795 z_stream z;
7796 int ret;
7797
7798 memset (&z, 0, sizeof (z));
7799 z.zalloc = NULL;
7800 z.zfree = NULL;
7801 z.opaque = NULL;
7802
7803 if ((ret = inflateInit (&z)) != Z_OK) {
7804 GST_ERROR ("inflateInit() returned %d", ret);
7805 return NULL;
7806 }
7807
7808 z.next_in = z_buffer;
7809 z.avail_in = z_length;
7810
7811 buffer = (guint8 *) g_malloc (*length);
7812 z.avail_out = *length;
7813 z.next_out = (Bytef *) buffer;
7814 do {
7815 ret = inflate (&z, Z_NO_FLUSH);
7816 if (ret == Z_STREAM_END) {
7817 break;
7818 } else if (ret != Z_OK) {
7819 GST_WARNING ("inflate() returned %d", ret);
7820 break;
7821 }
7822
7823 if (*length > G_MAXUINT - 4096 || *length > QTDEMUX_MAX_SAMPLE_INDEX_SIZE) {
7824 GST_WARNING ("too big decompressed data");
7825 ret = Z_MEM_ERROR;
7826 break;
7827 }
7828
7829 *length += 4096;
7830 buffer = (guint8 *) g_realloc (buffer, *length);
7831 z.next_out = (Bytef *) (buffer + z.total_out);
7832 z.avail_out += *length - z.total_out;
7833 } while (z.avail_in > 0);
7834
7835 if (ret != Z_STREAM_END) {
7836 g_free (buffer);
7837 buffer = NULL;
7838 *length = 0;
7839 } else {
7840 *length = z.total_out;
7841 }
7842
7843 inflateEnd (&z);
7844
7845 return buffer;
7846}
7847#endif /* HAVE_ZLIB */
7848
7849static gboolean
7850qtdemux_parse_moov (GstQTDemux * qtdemux, const guint8 * buffer, guint length)
7851{
7852 GNode *cmov;
7853
7854 qtdemux->moov_node = g_node_new ((guint8 *) buffer);
7855
7856 /* counts as header data */
7857 qtdemux->header_size += length;
7858
7859 GST_DEBUG_OBJECT (qtdemux, "parsing 'moov' atom");
7860 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buffer, length);
7861
7862 cmov = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_cmov);
7863 if (cmov) {
7864 guint32 method;
7865 GNode *dcom;
7866 GNode *cmvd;
7867 guint32 dcom_len;
7868
7869 dcom = qtdemux_tree_get_child_by_type (cmov, FOURCC_dcom);
7870 cmvd = qtdemux_tree_get_child_by_type (cmov, FOURCC_cmvd);
7871 if (dcom == NULL || cmvd == NULL)
7872 goto invalid_compression;
7873
7874 dcom_len = QT_UINT32 (dcom->data);
7875 if (dcom_len < 12)
7876 goto invalid_compression;
7877
7878 method = QT_FOURCC ((guint8 *) dcom->data + 8);
7879 switch (method) {
7880#ifdef HAVE_ZLIB
7881 case FOURCC_zlib:{
7882 guint uncompressed_length;
7883 guint compressed_length;
7884 guint8 *buf;
7885 guint32 cmvd_len;
7886
7887 cmvd_len = QT_UINT32 ((guint8 *) cmvd->data);
7888 if (cmvd_len < 12)
7889 goto invalid_compression;
7890
7891 uncompressed_length = QT_UINT32 ((guint8 *) cmvd->data + 8);
7892 compressed_length = cmvd_len - 12;
7893 GST_LOG ("length = %u", uncompressed_length);
7894
7895 buf =
7896 (guint8 *) qtdemux_inflate ((guint8 *) cmvd->data + 12,
7897 compressed_length, &uncompressed_length);
7898
7899 if (buf) {
7900 qtdemux->moov_node_compressed = qtdemux->moov_node;
7901 qtdemux->moov_node = g_node_new (buf);
7902
7903 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buf,
7904 uncompressed_length);
7905 }
7906 break;
7907 }
7908#endif /* HAVE_ZLIB */
7909 default:
7910 GST_WARNING_OBJECT (qtdemux, "unknown or unhandled header compression "
7911 "type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (method));
7912 break;
7913 }
7914 }
7915 return TRUE;
7916
7917 /* ERRORS */
7918invalid_compression:
7919 {
7920 GST_ERROR_OBJECT (qtdemux, "invalid compressed header");
7921 return FALSE;
7922 }
7923}
7924
7925static gboolean
7926qtdemux_parse_container (GstQTDemux * qtdemux, GNode * node, const guint8 * buf,
7927 const guint8 * end)
7928{
7929 while (G_UNLIKELY (buf < end)) {
7930 GNode *child;
7931 guint32 len;
7932
7933 if (G_UNLIKELY (buf + 4 > end)) {
7934 GST_LOG_OBJECT (qtdemux, "buffer overrun");
7935 break;
7936 }
7937 len = QT_UINT32 (buf);
7938 if (G_UNLIKELY (len == 0)) {
7939 GST_LOG_OBJECT (qtdemux, "empty container");
7940 break;
7941 }
7942 if (G_UNLIKELY (len < 8)) {
7943 GST_WARNING_OBJECT (qtdemux, "length too short (%d < 8)", len);
7944 break;
7945 }
7946 if (G_UNLIKELY (len > (end - buf))) {
7947 GST_WARNING_OBJECT (qtdemux, "length too long (%d > %d)", len,
7948 (gint) (end - buf));
7949 break;
7950 }
7951
7952 child = g_node_new ((guint8 *) buf);
7953 g_node_append (node, child);
7954 GST_LOG_OBJECT (qtdemux, "adding new node of len %d", len);
7955 qtdemux_parse_node (qtdemux, child, buf, len);
7956
7957 buf += len;
7958 }
7959 return TRUE;
7960}
7961
7962static gboolean
7963qtdemux_parse_theora_extension (GstQTDemux * qtdemux, QtDemuxStream * stream,
7964 GNode * xdxt)
7965{
7966 int len = QT_UINT32 (xdxt->data);
7967 guint8 *buf = xdxt->data;
7968 guint8 *end = buf + len;
7969 GstBuffer *buffer;
7970
7971 /* skip size and type */
7972 buf += 8;
7973 end -= 8;
7974
7975 while (buf < end) {
7976 gint size;
7977 guint32 type;
7978
7979 size = QT_UINT32 (buf);
7980 type = QT_FOURCC (buf + 4);
7981
7982 GST_LOG_OBJECT (qtdemux, "%p %p", buf, end);
7983
7984 if (buf + size > end || size <= 0)
7985 break;
7986
7987 buf += 8;
7988 size -= 8;
7989
7990 GST_WARNING_OBJECT (qtdemux, "have cookie %" GST_FOURCC_FORMAT,
7991 GST_FOURCC_ARGS (type));
7992
7993 switch (type) {
7994 case FOURCC_tCtH:
7995 buffer = gst_buffer_new_and_alloc (size);
7996 gst_buffer_fill (buffer, 0, buf, size);
7997 stream->buffers = g_slist_append (stream->buffers, buffer);
7998 GST_LOG_OBJECT (qtdemux, "parsing theora header");
7999 break;
8000 case FOURCC_tCt_:
8001 buffer = gst_buffer_new_and_alloc (size);
8002 gst_buffer_fill (buffer, 0, buf, size);
8003 stream->buffers = g_slist_append (stream->buffers, buffer);
8004 GST_LOG_OBJECT (qtdemux, "parsing theora comment");
8005 break;
8006 case FOURCC_tCtC:
8007 buffer = gst_buffer_new_and_alloc (size);
8008 gst_buffer_fill (buffer, 0, buf, size);
8009 stream->buffers = g_slist_append (stream->buffers, buffer);
8010 GST_LOG_OBJECT (qtdemux, "parsing theora codebook");
8011 break;
8012 default:
8013 GST_WARNING_OBJECT (qtdemux,
8014 "unknown theora cookie %" GST_FOURCC_FORMAT,
8015 GST_FOURCC_ARGS (type));
8016 break;
8017 }
8018 buf += size;
8019 }
8020 return TRUE;
8021}
8022
8023static gboolean
8024qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node, const guint8 * buffer,
8025 guint length)
8026{
8027 guint32 fourcc = 0;
8028 guint32 node_length = 0;
8029 const QtNodeType *type;
8030 const guint8 *end;
8031
8032 GST_LOG_OBJECT (qtdemux, "qtdemux_parse buffer %p length %u", buffer, length);
8033
8034 if (G_UNLIKELY (length < 8))
8035 goto not_enough_data;
8036
8037 node_length = QT_UINT32 (buffer);
8038 fourcc = QT_FOURCC (buffer + 4);
8039
8040 /* ignore empty nodes */
8041 if (G_UNLIKELY (fourcc == 0 || node_length == 8))
8042 return TRUE;
8043
8044 type = qtdemux_type_get (fourcc);
8045
8046 end = buffer + length;
8047
8048 GST_LOG_OBJECT (qtdemux,
8049 "parsing '%" GST_FOURCC_FORMAT "', length=%u, name '%s'",
8050 GST_FOURCC_ARGS (fourcc), node_length, type->name);
8051
8052 if (node_length > length)
8053 goto broken_atom_size;
8054
8055 if (type->flags & QT_FLAG_CONTAINER) {
8056 qtdemux_parse_container (qtdemux, node, buffer + 8, end);
8057 } else {
8058 switch (fourcc) {
8059 case FOURCC_stsd:
8060 {
8061 if (node_length < 20) {
8062 GST_LOG_OBJECT (qtdemux, "skipping small stsd box");
8063 break;
8064 }
8065 GST_DEBUG_OBJECT (qtdemux,
8066 "parsing stsd (sample table, sample description) atom");
8067 /* Skip over 8 byte atom hdr + 1 byte version, 3 bytes flags, 4 byte num_entries */
8068 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
8069 break;
8070 }
8071 case FOURCC_mp4a:
8072 case FOURCC_alac:
8073 case FOURCC_fLaC:
8074 case FOURCC_aavd:
8075 {
8076 guint32 version;
8077 guint32 offset;
8078 guint min_size;
8079
8080 /* also read alac (or whatever) in stead of mp4a in the following,
8081 * since a similar layout is used in other cases as well */
8082 if (fourcc == FOURCC_mp4a)
8083 min_size = 20;
8084 else if (fourcc == FOURCC_fLaC)
8085 min_size = 86;
8086 else
8087 min_size = 40;
8088
8089 /* There are two things we might encounter here: a true mp4a atom, and
8090 an mp4a entry in an stsd atom. The latter is what we're interested
8091 in, and it looks like an atom, but isn't really one. The true mp4a
8092 atom is short, so we detect it based on length here. */
8093 if (length < min_size) {
8094 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
8095 GST_FOURCC_ARGS (fourcc));
8096 break;
8097 }
8098
8099 /* 'version' here is the sound sample description version. Types 0 and
8100 1 are documented in the QTFF reference, but type 2 is not: it's
8101 described in Apple header files instead (struct SoundDescriptionV2
8102 in Movies.h) */
8103 version = QT_UINT16 (buffer + 16);
8104
8105 GST_DEBUG_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT " version 0x%08x",
8106 GST_FOURCC_ARGS (fourcc), version);
8107
8108 /* parse any esds descriptors */
8109 switch (version) {
8110 case 0:
8111 offset = 0x24;
8112 break;
8113 case 1:
8114 offset = 0x34;
8115 break;
8116 case 2:
8117 offset = 0x48;
8118 break;
8119 default:
8120 GST_WARNING_OBJECT (qtdemux,
8121 "unhandled %" GST_FOURCC_FORMAT " version 0x%08x",
8122 GST_FOURCC_ARGS (fourcc), version);
8123 offset = 0;
8124 break;
8125 }
8126 if (offset)
8127 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
8128 break;
8129 }
8130 case FOURCC_mp4v:
8131 case FOURCC_MP4V:
8132 case FOURCC_fmp4:
8133 case FOURCC_FMP4:
8134 case FOURCC_apcs:
8135 case FOURCC_apch:
8136 case FOURCC_apcn:
8137 case FOURCC_apco:
8138 case FOURCC_ap4h:
8139 case FOURCC_xvid:
8140 case FOURCC_XVID:
8141 case FOURCC_H264:
8142 case FOURCC_avc1:
8143 case FOURCC_avc3:
8144 case FOURCC_H265:
8145 case FOURCC_hvc1:
8146 case FOURCC_hev1:
8147 case FOURCC_dvh1:
8148 case FOURCC_dvhe:
8149 case FOURCC_mjp2:
8150 case FOURCC_encv:
8151 {
8152 guint32 version;
8153 guint32 str_len;
8154
8155 /* codec_data is contained inside these atoms, which all have
8156 * the same format. */
8157 /* video sample description size is 86 bytes without extension.
8158 * node_length have to be bigger than 86 bytes because video sample
8159 * description can include extensions such as esds, fiel, glbl, etc. */
8160 if (node_length < 86) {
8161 GST_WARNING_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT
8162 " sample description length too short (%u < 86)",
8163 GST_FOURCC_ARGS (fourcc), node_length);
8164 break;
8165 }
8166
8167 GST_DEBUG_OBJECT (qtdemux, "parsing in %" GST_FOURCC_FORMAT,
8168 GST_FOURCC_ARGS (fourcc));
8169
8170 /* version (2 bytes) : this is set to 0, unless a compressor has changed
8171 * its data format.
8172 * revision level (2 bytes) : must be set to 0. */
8173 version = QT_UINT32 (buffer + 16);
8174 GST_DEBUG_OBJECT (qtdemux, "version %08x", version);
8175
8176 /* compressor name : PASCAL string and informative purposes
8177 * first byte : the number of bytes to be displayed.
8178 * it has to be less than 32 because it is reserved
8179 * space of 32 bytes total including itself. */
8180 str_len = QT_UINT8 (buffer + 50);
8181 if (str_len < 32)
8182 GST_DEBUG_OBJECT (qtdemux, "compressorname = %.*s", str_len,
8183 (char *) buffer + 51);
8184 else
8185 GST_WARNING_OBJECT (qtdemux,
8186 "compressorname length too big (%u > 31)", str_len);
8187
8188 GST_MEMDUMP_OBJECT (qtdemux, "video sample description", buffer,
8189 end - buffer);
8190 qtdemux_parse_container (qtdemux, node, buffer + 86, end);
8191 break;
8192 }
8193 case FOURCC_meta:
8194 {
8195 GST_DEBUG_OBJECT (qtdemux, "parsing meta atom");
8196
8197 /* You are reading this correctly. QTFF specifies that the
8198 * metadata atom is a short atom, whereas ISO BMFF specifies
8199 * it's a full atom. But since so many people are doing things
8200 * differently, we actually peek into the atom to see which
8201 * variant it is */
8202 if (length < 16) {
8203 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
8204 GST_FOURCC_ARGS (fourcc));
8205 break;
8206 }
8207 if (QT_FOURCC (buffer + 12) == FOURCC_hdlr) {
8208 /* Variant 1: What QTFF specifies. 'meta' is a short header which
8209 * starts with a 'hdlr' atom */
8210 qtdemux_parse_container (qtdemux, node, buffer + 8, end);
8211 } else if (QT_UINT32 (buffer + 8) == 0x00000000) {
8212 /* Variant 2: What ISO BMFF specifies. 'meta' is a _full_ atom
8213 * with version/flags both set to zero */
8214 qtdemux_parse_container (qtdemux, node, buffer + 12, end);
8215 } else
8216 GST_WARNING_OBJECT (qtdemux, "Unknown 'meta' atom format");
8217 break;
8218 }
8219 case FOURCC_mp4s:
8220 {
8221 GST_MEMDUMP_OBJECT (qtdemux, "mp4s", buffer, end - buffer);
8222 /* Skip 8 byte header, plus 8 byte version + flags + entry_count */
8223 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
8224 break;
8225 }
8226 case FOURCC_XiTh:
8227 {
8228 guint32 version;
8229 guint32 offset;
8230
8231 if (length < 16) {
8232 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
8233 GST_FOURCC_ARGS (fourcc));
8234 break;
8235 }
8236
8237 version = QT_UINT32 (buffer + 12);
8238 GST_DEBUG_OBJECT (qtdemux, "parsing XiTh atom version 0x%08x", version);
8239
8240 switch (version) {
8241 case 0x00000001:
8242 offset = 0x62;
8243 break;
8244 default:
8245 GST_DEBUG_OBJECT (qtdemux, "unknown version 0x%08x", version);
8246 offset = 0;
8247 break;
8248 }
8249 if (offset) {
8250 if (length < offset) {
8251 GST_WARNING_OBJECT (qtdemux,
8252 "skipping too small %" GST_FOURCC_FORMAT " box",
8253 GST_FOURCC_ARGS (fourcc));
8254 break;
8255 }
8256 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
8257 }
8258 break;
8259 }
8260 case FOURCC_in24:
8261 {
8262 qtdemux_parse_container (qtdemux, node, buffer + 0x34, end);
8263 break;
8264 }
8265 case FOURCC_uuid:
8266 {
8267 qtdemux_parse_uuid (qtdemux, buffer, end - buffer);
8268 break;
8269 }
8270 case FOURCC_enca:
8271 {
8272 qtdemux_parse_container (qtdemux, node, buffer + 36, end);
8273 break;
8274 }
8275 default:
8276 if (!strcmp (type->name, "unknown"))
8277 GST_MEMDUMP ("Unknown tag", buffer + 4, end - buffer - 4);
8278 break;
8279 }
8280 }
8281 GST_LOG_OBJECT (qtdemux, "parsed '%" GST_FOURCC_FORMAT "'",
8282 GST_FOURCC_ARGS (fourcc));
8283 return TRUE;
8284
8285/* ERRORS */
8286not_enough_data:
8287 {
8288 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8289 (_("This file is corrupt and cannot be played.")),
8290 ("Not enough data for an atom header, got only %u bytes", length));
8291 return FALSE;
8292 }
8293broken_atom_size:
8294 {
8295 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8296 (_("This file is corrupt and cannot be played.")),
8297 ("Atom '%" GST_FOURCC_FORMAT "' has size of %u bytes, but we have only "
8298 "%u bytes available.", GST_FOURCC_ARGS (fourcc), node_length,
8299 length));
8300 return FALSE;
8301 }
8302}
8303
8304static void
8305qtdemux_do_allocation (QtDemuxStream * stream, GstQTDemux * qtdemux)
8306{
8307/* FIXME: This can only reliably work if demuxers have a
8308 * separate streaming thread per srcpad. This should be
8309 * done in a demuxer base class, which integrates parts
8310 * of multiqueue
8311 *
8312 * https://bugzilla.gnome.org/show_bug.cgi?id=701856
8313 */
8314#if 0
8315 GstQuery *query;
8316
8317 query = gst_query_new_allocation (stream->caps, FALSE);
8318
8319 if (!gst_pad_peer_query (stream->pad, query)) {
8320 /* not a problem, just debug a little */
8321 GST_DEBUG_OBJECT (qtdemux, "peer ALLOCATION query failed");
8322 }
8323
8324 if (stream->allocator)
8325 gst_object_unref (stream->allocator);
8326
8327 if (gst_query_get_n_allocation_params (query) > 0) {
8328 /* try the allocator */
8329 gst_query_parse_nth_allocation_param (query, 0, &stream->allocator,
8330 &stream->params);
8331 stream->use_allocator = TRUE;
8332 } else {
8333 stream->allocator = NULL;
8334 gst_allocation_params_init (&stream->params);
8335 stream->use_allocator = FALSE;
8336 }
8337 gst_query_unref (query);
8338#endif
8339}
8340
8341static gboolean
8342pad_query (const GValue * item, GValue * value, gpointer user_data)
8343{
8344 GstPad *pad = g_value_get_object (item);
8345 GstQuery *query = user_data;
8346 gboolean res;
8347
8348 res = gst_pad_peer_query (pad, query);
8349
8350 if (res) {
8351 g_value_set_boolean (value, TRUE);
8352 return FALSE;
8353 }
8354
8355 GST_INFO_OBJECT (pad, "pad peer query failed");
8356 return TRUE;
8357}
8358
8359static gboolean
8360gst_qtdemux_run_query (GstElement * element, GstQuery * query,
8361 GstPadDirection direction)
8362{
8363 GstIterator *it;
8364 GstIteratorFoldFunction func = pad_query;
8365 GValue res = { 0, };
8366
8367 g_value_init (&res, G_TYPE_BOOLEAN);
8368 g_value_set_boolean (&res, FALSE);
8369
8370 /* Ask neighbor */
8371 if (direction == GST_PAD_SRC)
8372 it = gst_element_iterate_src_pads (element);
8373 else
8374 it = gst_element_iterate_sink_pads (element);
8375
8376 while (gst_iterator_fold (it, func, &res, query) == GST_ITERATOR_RESYNC)
8377 gst_iterator_resync (it);
8378
8379 gst_iterator_free (it);
8380
8381 return g_value_get_boolean (&res);
8382}
8383
8384static void
8385gst_qtdemux_request_protection_context (GstQTDemux * qtdemux,
8386 QtDemuxStream * stream)
8387{
8388 GstQuery *query;
8389 GstContext *ctxt;
8390 GstElement *element = GST_ELEMENT (qtdemux);
8391 GstStructure *st;
8392 gchar **filtered_sys_ids;
8393 GValue event_list = G_VALUE_INIT;
8394 GList *walk;
8395
8396 /* 1. Check if we already have the context. */
8397 if (qtdemux->preferred_protection_system_id != NULL) {
8398 GST_LOG_OBJECT (element,
8399 "already have the protection context, no need to request it again");
8400 return;
8401 }
8402
8403 g_ptr_array_add (qtdemux->protection_system_ids, NULL);
8404 filtered_sys_ids = gst_protection_filter_systems_by_available_decryptors (
8405 (const gchar **) qtdemux->protection_system_ids->pdata);
8406
8407 g_ptr_array_remove_index (qtdemux->protection_system_ids,
8408 qtdemux->protection_system_ids->len - 1);
8409 GST_TRACE_OBJECT (qtdemux, "detected %u protection systems, we have "
8410 "decryptors for %u of them, running context request",
8411 qtdemux->protection_system_ids->len,
8412 filtered_sys_ids ? g_strv_length (filtered_sys_ids) : 0);
8413
8414
8415 if (stream->protection_scheme_event_queue.length) {
8416 GST_TRACE_OBJECT (qtdemux, "using stream event queue, length %u",
8417 stream->protection_scheme_event_queue.length);
8418 walk = stream->protection_scheme_event_queue.tail;
8419 } else {
8420 GST_TRACE_OBJECT (qtdemux, "using demuxer event queue, length %u",
8421 qtdemux->protection_event_queue.length);
8422 walk = qtdemux->protection_event_queue.tail;
8423 }
8424
8425 g_value_init (&event_list, GST_TYPE_LIST);
8426 for (; walk; walk = g_list_previous (walk)) {
8427 GValue *event_value = g_new0 (GValue, 1);
8428 g_value_init (event_value, GST_TYPE_EVENT);
8429 g_value_set_boxed (event_value, walk->data);
8430 gst_value_list_append_and_take_value (&event_list, event_value);
8431 }
8432
8433 /* 2a) Query downstream with GST_QUERY_CONTEXT for the context and
8434 * check if downstream already has a context of the specific type
8435 * 2b) Query upstream as above.
8436 */
8437 query = gst_query_new_context ("drm-preferred-decryption-system-id");
8438 st = gst_query_writable_structure (query);
8439 gst_structure_set (st, "track-id", G_TYPE_UINT, stream->track_id,
8440 "available-stream-encryption-systems", G_TYPE_STRV, filtered_sys_ids,
8441 NULL);
8442 gst_structure_set_value (st, "stream-encryption-events", &event_list);
8443 if (gst_qtdemux_run_query (element, query, GST_PAD_SRC)) {
8444 gst_query_parse_context (query, &ctxt);
8445 GST_INFO_OBJECT (element, "found context (%p) in downstream query", ctxt);
8446 gst_element_set_context (element, ctxt);
8447 } else if (gst_qtdemux_run_query (element, query, GST_PAD_SINK)) {
8448 gst_query_parse_context (query, &ctxt);
8449 GST_INFO_OBJECT (element, "found context (%p) in upstream query", ctxt);
8450 gst_element_set_context (element, ctxt);
8451 } else {
8452 /* 3) Post a GST_MESSAGE_NEED_CONTEXT message on the bus with
8453 * the required context type and afterwards check if a
8454 * usable context was set now as in 1). The message could
8455 * be handled by the parent bins of the element and the
8456 * application.
8457 */
8458 GstMessage *msg;
8459
8460 GST_INFO_OBJECT (element, "posting need context message");
8461 msg = gst_message_new_need_context (GST_OBJECT_CAST (element),
8462 "drm-preferred-decryption-system-id");
8463 st = (GstStructure *) gst_message_get_structure (msg);
8464 gst_structure_set (st, "track-id", G_TYPE_UINT, stream->track_id,
8465 "available-stream-encryption-systems", G_TYPE_STRV, filtered_sys_ids,
8466 NULL);
8467
8468 gst_structure_set_value (st, "stream-encryption-events", &event_list);
8469 gst_element_post_message (element, msg);
8470 }
8471
8472 g_strfreev (filtered_sys_ids);
8473 g_value_unset (&event_list);
8474 gst_query_unref (query);
8475}
8476
8477static gboolean
8478gst_qtdemux_configure_protected_caps (GstQTDemux * qtdemux,
8479 QtDemuxStream * stream)
8480{
8481 GstStructure *s;
8482 const gchar *selected_system = NULL;
8483
8484 g_return_val_if_fail (qtdemux != NULL, FALSE);
8485 g_return_val_if_fail (stream != NULL, FALSE);
8486 g_return_val_if_fail (gst_caps_get_size (CUR_STREAM (stream)->caps) == 1,
8487 FALSE);
8488
8489 if (stream->protection_scheme_type == FOURCC_aavd) {
8490 s = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
8491 if (!gst_structure_has_name (s, "application/x-aavd")) {
8492 gst_structure_set (s,
8493 "original-media-type", G_TYPE_STRING, gst_structure_get_name (s),
8494 NULL);
8495 gst_structure_set_name (s, "application/x-aavd");
8496 }
8497 return TRUE;
8498 }
8499
8500 if (stream->protection_scheme_type != FOURCC_cenc
8501 && stream->protection_scheme_type != FOURCC_cbcs) {
8502 GST_ERROR_OBJECT (qtdemux,
8503 "unsupported protection scheme: %" GST_FOURCC_FORMAT,
8504 GST_FOURCC_ARGS (stream->protection_scheme_type));
8505 return FALSE;
8506 }
8507
8508 s = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
8509 if (!gst_structure_has_name (s, "application/x-cenc")) {
8510 gst_structure_set (s,
8511 "original-media-type", G_TYPE_STRING, gst_structure_get_name (s), NULL);
8512 gst_structure_set (s, "cipher-mode", G_TYPE_STRING,
8513 (stream->protection_scheme_type == FOURCC_cbcs) ? "cbcs" : "cenc",
8514 NULL);
8515 gst_structure_set_name (s, "application/x-cenc");
8516 }
8517
8518 if (qtdemux->protection_system_ids == NULL) {
8519 GST_DEBUG_OBJECT (qtdemux, "stream is protected using cenc, but no "
8520 "cenc protection system information has been found, not setting a "
8521 "protection system UUID");
8522 return TRUE;
8523 }
8524
8525 gst_qtdemux_request_protection_context (qtdemux, stream);
8526 if (qtdemux->preferred_protection_system_id != NULL) {
8527 const gchar *preferred_system_array[] =
8528 { qtdemux->preferred_protection_system_id, NULL };
8529
8530 selected_system = gst_protection_select_system (preferred_system_array);
8531
8532 if (selected_system) {
8533 GST_TRACE_OBJECT (qtdemux, "selected preferred system %s",
8534 qtdemux->preferred_protection_system_id);
8535 } else {
8536 GST_WARNING_OBJECT (qtdemux, "could not select preferred system %s "
8537 "because there is no available decryptor",
8538 qtdemux->preferred_protection_system_id);
8539 }
8540 }
8541
8542 if (!selected_system) {
8543 g_ptr_array_add (qtdemux->protection_system_ids, NULL);
8544 selected_system = gst_protection_select_system ((const gchar **)
8545 qtdemux->protection_system_ids->pdata);
8546 g_ptr_array_remove_index (qtdemux->protection_system_ids,
8547 qtdemux->protection_system_ids->len - 1);
8548 }
8549
8550 if (!selected_system) {
8551 GST_ERROR_OBJECT (qtdemux, "stream is protected, but no "
8552 "suitable decryptor element has been found");
8553 return FALSE;
8554 }
8555
8556 GST_DEBUG_OBJECT (qtdemux, "selected protection system is %s",
8557 selected_system);
8558
8559 gst_structure_set (s,
8560 GST_PROTECTION_SYSTEM_ID_CAPS_FIELD, G_TYPE_STRING, selected_system,
8561 NULL);
8562
8563 return TRUE;
8564}
8565
8566static gboolean
8567gst_qtdemux_guess_framerate (GstQTDemux * qtdemux, QtDemuxStream * stream)
8568{
8569 /* fps is calculated base on the duration of the average framerate since
8570 * qt does not have a fixed framerate. */
8571 gboolean fps_available = TRUE;
8572 guint32 first_duration = 0;
8573
8574 if (stream->n_samples > 0)
8575 first_duration = stream->samples[0].duration;
8576
8577 if ((stream->n_samples == 1 && first_duration == 0)
8578 || (qtdemux->fragmented && stream->n_samples_moof == 1)) {
8579 /* still frame */
8580 CUR_STREAM (stream)->fps_n = 0;
8581 CUR_STREAM (stream)->fps_d = 1;
8582 } else {
8583 if (stream->duration == 0 || stream->n_samples < 2) {
8584 CUR_STREAM (stream)->fps_n = stream->timescale;
8585 CUR_STREAM (stream)->fps_d = 1;
8586 fps_available = FALSE;
8587 } else {
8588 GstClockTime avg_duration;
8589 guint64 duration;
8590 guint32 n_samples;
8591
8592 /* duration and n_samples can be updated for fragmented format
8593 * so, framerate of fragmented format is calculated using data in a moof */
8594 if (qtdemux->fragmented && stream->n_samples_moof > 0
8595 && stream->duration_moof > 0) {
8596 n_samples = stream->n_samples_moof;
8597 duration = stream->duration_moof;
8598 } else {
8599 n_samples = stream->n_samples;
8600 duration = stream->duration;
8601 }
8602
8603 /* Calculate a framerate, ignoring the first sample which is sometimes truncated */
8604 /* stream->duration is guint64, timescale, n_samples are guint32 */
8605 avg_duration =
8606 gst_util_uint64_scale_round (duration -
8607 first_duration, GST_SECOND,
8608 (guint64) (stream->timescale) * (n_samples - 1));
8609
8610 GST_LOG_OBJECT (qtdemux,
8611 "Calculating avg sample duration based on stream (or moof) duration %"
8612 G_GUINT64_FORMAT
8613 " minus first sample %u, leaving %d samples gives %"
8614 GST_TIME_FORMAT, duration, first_duration,
8615 n_samples - 1, GST_TIME_ARGS (avg_duration));
8616
8617 fps_available =
8618 gst_video_guess_framerate (avg_duration,
8619 &CUR_STREAM (stream)->fps_n, &CUR_STREAM (stream)->fps_d);
8620
8621 GST_DEBUG_OBJECT (qtdemux,
8622 "Calculating framerate, timescale %u gave fps_n %d fps_d %d",
8623 stream->timescale, CUR_STREAM (stream)->fps_n,
8624 CUR_STREAM (stream)->fps_d);
8625 }
8626 }
8627
8628 return fps_available;
8629}
8630
8631static gboolean
8632gst_qtdemux_configure_stream (GstQTDemux * qtdemux, QtDemuxStream * stream)
8633{
8634 if (stream->subtype == FOURCC_vide) {
8635 gboolean fps_available = gst_qtdemux_guess_framerate (qtdemux, stream);
8636
8637 if (CUR_STREAM (stream)->caps) {
8638 CUR_STREAM (stream)->caps =
8639 gst_caps_make_writable (CUR_STREAM (stream)->caps);
8640
8641 if (CUR_STREAM (stream)->width && CUR_STREAM (stream)->height)
8642 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8643 "width", G_TYPE_INT, CUR_STREAM (stream)->width,
8644 "height", G_TYPE_INT, CUR_STREAM (stream)->height, NULL);
8645
8646 /* set framerate if calculated framerate is reliable */
8647 if (fps_available) {
8648 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8649 "framerate", GST_TYPE_FRACTION, CUR_STREAM (stream)->fps_n,
8650 CUR_STREAM (stream)->fps_d, NULL);
8651 }
8652
8653 /* calculate pixel-aspect-ratio using display width and height */
8654 GST_DEBUG_OBJECT (qtdemux,
8655 "video size %dx%d, target display size %dx%d",
8656 CUR_STREAM (stream)->width, CUR_STREAM (stream)->height,
8657 stream->display_width, stream->display_height);
8658 /* qt file might have pasp atom */
8659 if (CUR_STREAM (stream)->par_w > 0 && CUR_STREAM (stream)->par_h > 0) {
8660 GST_DEBUG_OBJECT (qtdemux, "par %d:%d", CUR_STREAM (stream)->par_w,
8661 CUR_STREAM (stream)->par_h);
8662 gst_caps_set_simple (CUR_STREAM (stream)->caps, "pixel-aspect-ratio",
8663 GST_TYPE_FRACTION, CUR_STREAM (stream)->par_w,
8664 CUR_STREAM (stream)->par_h, NULL);
8665 } else if (stream->display_width > 0 && stream->display_height > 0
8666 && CUR_STREAM (stream)->width > 0
8667 && CUR_STREAM (stream)->height > 0) {
8668 gint n, d;
8669
8670 /* calculate the pixel aspect ratio using the display and pixel w/h */
8671 n = stream->display_width * CUR_STREAM (stream)->height;
8672 d = stream->display_height * CUR_STREAM (stream)->width;
8673 if (n == d)
8674 n = d = 1;
8675 GST_DEBUG_OBJECT (qtdemux, "setting PAR to %d/%d", n, d);
8676 CUR_STREAM (stream)->par_w = n;
8677 CUR_STREAM (stream)->par_h = d;
8678 gst_caps_set_simple (CUR_STREAM (stream)->caps, "pixel-aspect-ratio",
8679 GST_TYPE_FRACTION, CUR_STREAM (stream)->par_w,
8680 CUR_STREAM (stream)->par_h, NULL);
8681 }
8682
8683 if (CUR_STREAM (stream)->interlace_mode > 0) {
8684 if (CUR_STREAM (stream)->interlace_mode == 1) {
8685 gst_caps_set_simple (CUR_STREAM (stream)->caps, "interlace-mode",
8686 G_TYPE_STRING, "progressive", NULL);
8687 } else if (CUR_STREAM (stream)->interlace_mode == 2) {
8688 gst_caps_set_simple (CUR_STREAM (stream)->caps, "interlace-mode",
8689 G_TYPE_STRING, "interleaved", NULL);
8690 if (CUR_STREAM (stream)->field_order == 9) {
8691 gst_caps_set_simple (CUR_STREAM (stream)->caps, "field-order",
8692 G_TYPE_STRING, "top-field-first", NULL);
8693 } else if (CUR_STREAM (stream)->field_order == 14) {
8694 gst_caps_set_simple (CUR_STREAM (stream)->caps, "field-order",
8695 G_TYPE_STRING, "bottom-field-first", NULL);
8696 }
8697 }
8698 }
8699
8700 /* Create incomplete colorimetry here if needed */
8701 if (CUR_STREAM (stream)->colorimetry.range ||
8702 CUR_STREAM (stream)->colorimetry.matrix ||
8703 CUR_STREAM (stream)->colorimetry.transfer
8704 || CUR_STREAM (stream)->colorimetry.primaries) {
8705 gchar *colorimetry =
8706 gst_video_colorimetry_to_string (&CUR_STREAM (stream)->colorimetry);
8707 gst_caps_set_simple (CUR_STREAM (stream)->caps, "colorimetry",
8708 G_TYPE_STRING, colorimetry, NULL);
8709 g_free (colorimetry);
8710 }
8711
8712 if (stream->multiview_mode != GST_VIDEO_MULTIVIEW_MODE_NONE) {
8713 guint par_w = 1, par_h = 1;
8714
8715 if (CUR_STREAM (stream)->par_w > 0 && CUR_STREAM (stream)->par_h > 0) {
8716 par_w = CUR_STREAM (stream)->par_w;
8717 par_h = CUR_STREAM (stream)->par_h;
8718 }
8719
8720 if (gst_video_multiview_guess_half_aspect (stream->multiview_mode,
8721 CUR_STREAM (stream)->width, CUR_STREAM (stream)->height, par_w,
8722 par_h)) {
8723 stream->multiview_flags |= GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT;
8724 }
8725
8726 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8727 "multiview-mode", G_TYPE_STRING,
8728 gst_video_multiview_mode_to_caps_string (stream->multiview_mode),
8729 "multiview-flags", GST_TYPE_VIDEO_MULTIVIEW_FLAGSET,
8730 stream->multiview_flags, GST_FLAG_SET_MASK_EXACT, NULL);
8731 }
8732 }
8733 }
8734
8735 else if (stream->subtype == FOURCC_soun) {
8736 if (CUR_STREAM (stream)->caps) {
8737 CUR_STREAM (stream)->caps =
8738 gst_caps_make_writable (CUR_STREAM (stream)->caps);
8739 if (CUR_STREAM (stream)->rate > 0)
8740 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8741 "rate", G_TYPE_INT, (int) CUR_STREAM (stream)->rate, NULL);
8742 if (CUR_STREAM (stream)->n_channels > 0)
8743 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8744 "channels", G_TYPE_INT, CUR_STREAM (stream)->n_channels, NULL);
8745 if (CUR_STREAM (stream)->n_channels > 2) {
8746 /* FIXME: Need to parse the 'chan' atom to get channel layouts
8747 * correctly; this is just the minimum we can do - assume
8748 * we don't actually have any channel positions. */
8749 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8750 "channel-mask", GST_TYPE_BITMASK, G_GUINT64_CONSTANT (0), NULL);
8751 }
8752 }
8753 }
8754
8755 else if (stream->subtype == FOURCC_clcp && CUR_STREAM (stream)->caps) {
8756 const GstStructure *s;
8757 QtDemuxStream *fps_stream = NULL;
8758 gboolean fps_available = FALSE;
8759
8760 /* CEA608 closed caption tracks are a bit special in that each sample
8761 * can contain CCs for multiple frames, and CCs can be omitted and have to
8762 * be inferred from the duration of the sample then.
8763 *
8764 * As such we take the framerate from the (first) video track here for
8765 * CEA608 as there must be one CC byte pair for every video frame
8766 * according to the spec.
8767 *
8768 * For CEA708 all is fine and there is one sample per frame.
8769 */
8770
8771 s = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
8772 if (gst_structure_has_name (s, "closedcaption/x-cea-608")) {
8773 gint i;
8774
8775 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
8776 QtDemuxStream *tmp = QTDEMUX_NTH_STREAM (qtdemux, i);
8777
8778 if (tmp->subtype == FOURCC_vide) {
8779 fps_stream = tmp;
8780 break;
8781 }
8782 }
8783
8784 if (fps_stream) {
8785 fps_available = gst_qtdemux_guess_framerate (qtdemux, fps_stream);
8786 CUR_STREAM (stream)->fps_n = CUR_STREAM (fps_stream)->fps_n;
8787 CUR_STREAM (stream)->fps_d = CUR_STREAM (fps_stream)->fps_d;
8788 }
8789 } else {
8790 fps_available = gst_qtdemux_guess_framerate (qtdemux, stream);
8791 fps_stream = stream;
8792 }
8793
8794 CUR_STREAM (stream)->caps =
8795 gst_caps_make_writable (CUR_STREAM (stream)->caps);
8796
8797 /* set framerate if calculated framerate is reliable */
8798 if (fps_available) {
8799 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8800 "framerate", GST_TYPE_FRACTION, CUR_STREAM (stream)->fps_n,
8801 CUR_STREAM (stream)->fps_d, NULL);
8802 }
8803 }
8804
8805 if (stream->pad) {
8806 GstCaps *prev_caps = NULL;
8807
8808 GST_PAD_ELEMENT_PRIVATE (stream->pad) = stream;
8809 gst_pad_set_event_function (stream->pad, gst_qtdemux_handle_src_event);
8810 gst_pad_set_query_function (stream->pad, gst_qtdemux_handle_src_query);
8811 gst_pad_set_active (stream->pad, TRUE);
8812
8813 gst_pad_use_fixed_caps (stream->pad);
8814
8815 if (stream->protected) {
8816 if (!gst_qtdemux_configure_protected_caps (qtdemux, stream)) {
8817 GST_ERROR_OBJECT (qtdemux,
8818 "Failed to configure protected stream caps.");
8819 return FALSE;
8820 }
8821 }
8822
8823 GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT,
8824 CUR_STREAM (stream)->caps);
8825 if (stream->new_stream) {
8826 GstEvent *event;
8827 GstStreamFlags stream_flags = GST_STREAM_FLAG_NONE;
8828
8829 event =
8830 gst_pad_get_sticky_event (qtdemux->sinkpad, GST_EVENT_STREAM_START,
8831 0);
8832 if (event) {
8833 gst_event_parse_stream_flags (event, &stream_flags);
8834 if (gst_event_parse_group_id (event, &qtdemux->group_id))
8835 qtdemux->have_group_id = TRUE;
8836 else
8837 qtdemux->have_group_id = FALSE;
8838 gst_event_unref (event);
8839 } else if (!qtdemux->have_group_id) {
8840 qtdemux->have_group_id = TRUE;
8841 qtdemux->group_id = gst_util_group_id_next ();
8842 }
8843
8844 stream->new_stream = FALSE;
8845 event = gst_event_new_stream_start (stream->stream_id);
8846 if (qtdemux->have_group_id)
8847 gst_event_set_group_id (event, qtdemux->group_id);
8848 if (stream->disabled)
8849 stream_flags |= GST_STREAM_FLAG_UNSELECT;
8850 if (CUR_STREAM (stream)->sparse) {
8851 stream_flags |= GST_STREAM_FLAG_SPARSE;
8852 } else {
8853 stream_flags &= ~GST_STREAM_FLAG_SPARSE;
8854 }
8855 gst_event_set_stream_flags (event, stream_flags);
8856 gst_pad_push_event (stream->pad, event);
8857 }
8858
8859 prev_caps = gst_pad_get_current_caps (stream->pad);
8860
8861 if (CUR_STREAM (stream)->caps) {
8862 if (!prev_caps
8863 || !gst_caps_is_equal_fixed (prev_caps, CUR_STREAM (stream)->caps)) {
8864 GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT,
8865 CUR_STREAM (stream)->caps);
8866 gst_pad_set_caps (stream->pad, CUR_STREAM (stream)->caps);
8867 } else {
8868 GST_DEBUG_OBJECT (qtdemux, "ignore duplicated caps");
8869 }
8870 } else {
8871 GST_WARNING_OBJECT (qtdemux, "stream without caps");
8872 }
8873
8874 if (prev_caps)
8875 gst_caps_unref (prev_caps);
8876 stream->new_caps = FALSE;
8877 }
8878 return TRUE;
8879}
8880
8881static void
8882gst_qtdemux_stream_check_and_change_stsd_index (GstQTDemux * demux,
8883 QtDemuxStream * stream)
8884{
8885 if (stream->cur_stsd_entry_index == stream->stsd_sample_description_id)
8886 return;
8887
8888 GST_DEBUG_OBJECT (stream->pad, "Changing stsd index from '%u' to '%u'",
8889 stream->cur_stsd_entry_index, stream->stsd_sample_description_id);
8890 if (G_UNLIKELY (stream->stsd_sample_description_id >=
8891 stream->stsd_entries_length)) {
8892 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
8893 (_("This file is invalid and cannot be played.")),
8894 ("New sample description id is out of bounds (%d >= %d)",
8895 stream->stsd_sample_description_id, stream->stsd_entries_length));
8896 } else {
8897 stream->cur_stsd_entry_index = stream->stsd_sample_description_id;
8898 stream->new_caps = TRUE;
8899 }
8900}
8901
8902static gboolean
8903gst_qtdemux_add_stream (GstQTDemux * qtdemux,
8904 QtDemuxStream * stream, GstTagList * list)
8905{
8906 gboolean ret = TRUE;
8907
8908 if (stream->subtype == FOURCC_vide) {
8909 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
8910
8911 stream->pad =
8912 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
8913 g_free (name);
8914
8915 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8916 gst_object_unref (stream->pad);
8917 stream->pad = NULL;
8918 ret = FALSE;
8919 goto done;
8920 }
8921
8922 qtdemux->n_video_streams++;
8923 } else if (stream->subtype == FOURCC_soun) {
8924 gchar *name = g_strdup_printf ("audio_%u", qtdemux->n_audio_streams);
8925
8926 stream->pad =
8927 gst_pad_new_from_static_template (&gst_qtdemux_audiosrc_template, name);
8928 g_free (name);
8929 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8930 gst_object_unref (stream->pad);
8931 stream->pad = NULL;
8932 ret = FALSE;
8933 goto done;
8934 }
8935 qtdemux->n_audio_streams++;
8936 } else if (stream->subtype == FOURCC_strm) {
8937 GST_DEBUG_OBJECT (qtdemux, "stream type, not creating pad");
8938 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
8939 || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt
8940 || stream->subtype == FOURCC_clcp || stream->subtype == FOURCC_wvtt) {
8941 gchar *name = g_strdup_printf ("subtitle_%u", qtdemux->n_sub_streams);
8942
8943 stream->pad =
8944 gst_pad_new_from_static_template (&gst_qtdemux_subsrc_template, name);
8945 g_free (name);
8946 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8947 gst_object_unref (stream->pad);
8948 stream->pad = NULL;
8949 ret = FALSE;
8950 goto done;
8951 }
8952 qtdemux->n_sub_streams++;
8953 } else if (CUR_STREAM (stream)->caps) {
8954 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
8955
8956 stream->pad =
8957 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
8958 g_free (name);
8959 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8960 gst_object_unref (stream->pad);
8961 stream->pad = NULL;
8962 ret = FALSE;
8963 goto done;
8964 }
8965 qtdemux->n_video_streams++;
8966 } else {
8967 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
8968 goto done;
8969 }
8970
8971 if (stream->pad) {
8972 GList *l;
8973
8974 GST_DEBUG_OBJECT (qtdemux, "adding pad %s %p to qtdemux %p",
8975 GST_OBJECT_NAME (stream->pad), stream->pad, qtdemux);
8976 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
8977 GST_OBJECT_LOCK (qtdemux);
8978 gst_flow_combiner_add_pad (qtdemux->flowcombiner, stream->pad);
8979 GST_OBJECT_UNLOCK (qtdemux);
8980
8981 if (stream->stream_tags)
8982 gst_tag_list_unref (stream->stream_tags);
8983 stream->stream_tags = list;
8984 list = NULL;
8985 /* global tags go on each pad anyway */
8986 stream->send_global_tags = TRUE;
8987 /* send upstream GST_EVENT_PROTECTION events that were received before
8988 this source pad was created */
8989 for (l = qtdemux->protection_event_queue.head; l != NULL; l = l->next)
8990 gst_pad_push_event (stream->pad, gst_event_ref (l->data));
8991 }
8992done:
8993 if (list)
8994 gst_tag_list_unref (list);
8995 return ret;
8996}
8997
8998/* find next atom with @fourcc starting at @offset */
8999static GstFlowReturn
9000qtdemux_find_atom (GstQTDemux * qtdemux, guint64 * offset,
9001 guint64 * length, guint32 fourcc)
9002{
9003 GstFlowReturn ret;
9004 guint32 lfourcc;
9005 GstBuffer *buf;
9006
9007 GST_LOG_OBJECT (qtdemux, "finding fourcc %" GST_FOURCC_FORMAT " at offset %"
9008 G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), *offset);
9009
9010 while (TRUE) {
9011 GstMapInfo map;
9012
9013 buf = NULL;
9014 ret = gst_pad_pull_range (qtdemux->sinkpad, *offset, 16, &buf);
9015 if (G_UNLIKELY (ret != GST_FLOW_OK))
9016 goto locate_failed;
9017 if (G_UNLIKELY (gst_buffer_get_size (buf) != 16)) {
9018 /* likely EOF */
9019 ret = GST_FLOW_EOS;
9020 gst_buffer_unref (buf);
9021 goto locate_failed;
9022 }
9023 gst_buffer_map (buf, &map, GST_MAP_READ);
9024 extract_initial_length_and_fourcc (map.data, 16, length, &lfourcc);
9025 gst_buffer_unmap (buf, &map);
9026 gst_buffer_unref (buf);
9027
9028 if (G_UNLIKELY (*length == 0)) {
9029 GST_DEBUG_OBJECT (qtdemux, "invalid length 0");
9030 ret = GST_FLOW_ERROR;
9031 goto locate_failed;
9032 }
9033
9034 if (lfourcc == fourcc) {
9035 GST_DEBUG_OBJECT (qtdemux, "found '%" GST_FOURCC_FORMAT " at offset %"
9036 G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), *offset);
9037 break;
9038 } else {
9039 GST_LOG_OBJECT (qtdemux,
9040 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
9041 GST_FOURCC_ARGS (lfourcc), *offset);
9042 if (*offset == G_MAXUINT64)
9043 goto locate_failed;
9044 *offset += *length;
9045 }
9046 }
9047
9048 return GST_FLOW_OK;
9049
9050locate_failed:
9051 {
9052 /* might simply have had last one */
9053 GST_DEBUG_OBJECT (qtdemux, "fourcc not found");
9054 return ret;
9055 }
9056}
9057
9058/* should only do something in pull mode */
9059/* call with OBJECT lock */
9060static GstFlowReturn
9061qtdemux_add_fragmented_samples (GstQTDemux * qtdemux)
9062{
9063 guint64 length, offset;
9064 GstBuffer *buf = NULL;
9065 GstFlowReturn ret = GST_FLOW_OK;
9066 GstFlowReturn res = GST_FLOW_OK;
9067 GstMapInfo map;
9068
9069 offset = qtdemux->moof_offset;
9070 GST_DEBUG_OBJECT (qtdemux, "next moof at offset %" G_GUINT64_FORMAT, offset);
9071
9072 if (!offset) {
9073 GST_DEBUG_OBJECT (qtdemux, "no next moof");
9074 return GST_FLOW_EOS;
9075 }
9076
9077 /* best not do pull etc with lock held */
9078 GST_OBJECT_UNLOCK (qtdemux);
9079
9080 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
9081 if (ret != GST_FLOW_OK)
9082 goto flow_failed;
9083
9084 ret = gst_qtdemux_pull_atom (qtdemux, offset, length, &buf);
9085 if (G_UNLIKELY (ret != GST_FLOW_OK))
9086 goto flow_failed;
9087 gst_buffer_map (buf, &map, GST_MAP_READ);
9088 if (!qtdemux_parse_moof (qtdemux, map.data, map.size, offset, NULL)) {
9089 gst_buffer_unmap (buf, &map);
9090 gst_buffer_unref (buf);
9091 buf = NULL;
9092 goto parse_failed;
9093 }
9094
9095 gst_buffer_unmap (buf, &map);
9096 gst_buffer_unref (buf);
9097 buf = NULL;
9098
9099 offset += length;
9100 /* look for next moof */
9101 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
9102 if (G_UNLIKELY (ret != GST_FLOW_OK))
9103 goto flow_failed;
9104
9105exit:
9106 GST_OBJECT_LOCK (qtdemux);
9107
9108 qtdemux->moof_offset = offset;
9109
9110 return res;
9111
9112parse_failed:
9113 {
9114 GST_DEBUG_OBJECT (qtdemux, "failed to parse moof");
9115 offset = 0;
9116 res = GST_FLOW_ERROR;
9117 goto exit;
9118 }
9119flow_failed:
9120 {
9121 /* maybe upstream temporarily flushing */
9122 if (ret != GST_FLOW_FLUSHING) {
9123 GST_DEBUG_OBJECT (qtdemux, "no next moof");
9124 offset = 0;
9125 } else {
9126 GST_DEBUG_OBJECT (qtdemux, "upstream WRONG_STATE");
9127 /* resume at current position next time */
9128 }
9129 res = ret;
9130 goto exit;
9131 }
9132}
9133
9134static void
9135qtdemux_merge_sample_table (GstQTDemux * qtdemux, QtDemuxStream * stream)
9136{
9137 guint i;
9138 guint32 num_chunks;
9139 gint32 stts_duration;
9140 GstByteWriter stsc, stts, stsz;
9141
9142 /* Each sample has a different size, which we don't support for merging */
9143 if (stream->sample_size == 0) {
9144 GST_DEBUG_OBJECT (qtdemux,
9145 "Not all samples have the same size, not merging");
9146 return;
9147 }
9148
9149 /* The stream has a ctts table, we don't support that */
9150 if (stream->ctts_present) {
9151 GST_DEBUG_OBJECT (qtdemux, "Have ctts, not merging");
9152 return;
9153 }
9154
9155 /* If there's a sync sample table also ignore this stream */
9156 if (stream->stps_present || stream->stss_present) {
9157 GST_DEBUG_OBJECT (qtdemux, "Have stss/stps, not merging");
9158 return;
9159 }
9160
9161 /* If chunks are considered samples already ignore this stream */
9162 if (stream->chunks_are_samples) {
9163 GST_DEBUG_OBJECT (qtdemux, "Chunks are samples, not merging");
9164 return;
9165 }
9166
9167 /* Require that all samples have the same duration */
9168 if (stream->n_sample_times > 1) {
9169 GST_DEBUG_OBJECT (qtdemux, "Not all samples have the same duration");
9170 return;
9171 }
9172
9173 /* Parse the stts to get the sample duration and number of samples */
9174 gst_byte_reader_skip_unchecked (&stream->stts, 4);
9175 stts_duration = gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
9176
9177 /* Parse the number of chunks from the stco manually because the
9178 * reader is already behind that */
9179 num_chunks = GST_READ_UINT32_BE (stream->stco.data + 4);
9180
9181 GST_DEBUG_OBJECT (qtdemux, "sample_duration %d, num_chunks %u", stts_duration,
9182 num_chunks);
9183
9184 /* Now parse stsc, convert chunks into single samples and generate a
9185 * new stsc, stts and stsz from this information */
9186 gst_byte_writer_init (&stsc);
9187 gst_byte_writer_init (&stts);
9188 gst_byte_writer_init (&stsz);
9189
9190 /* Note: we skip fourccs, size, version, flags and other fields of the new
9191 * atoms as the byte readers with them are already behind that position
9192 * anyway and only update the values of those inside the stream directly.
9193 */
9194 stream->n_sample_times = 0;
9195 stream->n_samples = 0;
9196 for (i = 0; i < stream->n_samples_per_chunk; i++) {
9197 guint j;
9198 guint32 first_chunk, last_chunk, samples_per_chunk, sample_description_id;
9199
9200 first_chunk = gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9201 samples_per_chunk = gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9202 sample_description_id =
9203 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9204
9205 if (i == stream->n_samples_per_chunk - 1) {
9206 /* +1 because first_chunk is 1-based */
9207 last_chunk = num_chunks + 1;
9208 } else {
9209 last_chunk = gst_byte_reader_peek_uint32_be_unchecked (&stream->stsc);
9210 }
9211
9212 GST_DEBUG_OBJECT (qtdemux,
9213 "Merging first_chunk: %u, last_chunk: %u, samples_per_chunk: %u, sample_description_id: %u",
9214 first_chunk, last_chunk, samples_per_chunk, sample_description_id);
9215
9216 gst_byte_writer_put_uint32_be (&stsc, first_chunk);
9217 /* One sample in this chunk */
9218 gst_byte_writer_put_uint32_be (&stsc, 1);
9219 gst_byte_writer_put_uint32_be (&stsc, sample_description_id);
9220
9221 /* For each chunk write a stts and stsz entry now */
9222 gst_byte_writer_put_uint32_be (&stts, last_chunk - first_chunk);
9223 gst_byte_writer_put_uint32_be (&stts, stts_duration * samples_per_chunk);
9224 for (j = first_chunk; j < last_chunk; j++) {
9225 gst_byte_writer_put_uint32_be (&stsz,
9226 stream->sample_size * samples_per_chunk);
9227 }
9228
9229 stream->n_sample_times += 1;
9230 stream->n_samples += last_chunk - first_chunk;
9231 }
9232
9233 g_assert_cmpint (stream->n_samples, ==, num_chunks);
9234
9235 GST_DEBUG_OBJECT (qtdemux, "Have %u samples and %u sample times",
9236 stream->n_samples, stream->n_sample_times);
9237
9238 /* We don't have a fixed sample size anymore */
9239 stream->sample_size = 0;
9240
9241 /* Free old data for the atoms */
9242 g_free ((gpointer) stream->stsz.data);
9243 stream->stsz.data = NULL;
9244 g_free ((gpointer) stream->stsc.data);
9245 stream->stsc.data = NULL;
9246 g_free ((gpointer) stream->stts.data);
9247 stream->stts.data = NULL;
9248
9249 /* Store new data and replace byte readers */
9250 stream->stsz.size = gst_byte_writer_get_size (&stsz);
9251 stream->stsz.data = gst_byte_writer_reset_and_get_data (&stsz);
9252 gst_byte_reader_init (&stream->stsz, stream->stsz.data, stream->stsz.size);
9253 stream->stts.size = gst_byte_writer_get_size (&stts);
9254 stream->stts.data = gst_byte_writer_reset_and_get_data (&stts);
9255 gst_byte_reader_init (&stream->stts, stream->stts.data, stream->stts.size);
9256 stream->stsc.size = gst_byte_writer_get_size (&stsc);
9257 stream->stsc.data = gst_byte_writer_reset_and_get_data (&stsc);
9258 gst_byte_reader_init (&stream->stsc, stream->stsc.data, stream->stsc.size);
9259}
9260
9261/* initialise bytereaders for stbl sub-atoms */
9262static gboolean
9263qtdemux_stbl_init (GstQTDemux * qtdemux, QtDemuxStream * stream, GNode * stbl)
9264{
9265 stream->stbl_index = -1; /* no samples have yet been parsed */
9266 stream->sample_index = -1;
9267
9268 /* time-to-sample atom */
9269 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stts, &stream->stts))
9270 goto corrupt_file;
9271
9272 /* copy atom data into a new buffer for later use */
9273 stream->stts.data = g_memdup2 (stream->stts.data, stream->stts.size);
9274
9275 /* skip version + flags */
9276 if (!gst_byte_reader_skip (&stream->stts, 1 + 3) ||
9277 !gst_byte_reader_get_uint32_be (&stream->stts, &stream->n_sample_times))
9278 goto corrupt_file;
9279 GST_LOG_OBJECT (qtdemux, "%u timestamp blocks", stream->n_sample_times);
9280
9281 /* make sure there's enough data */
9282 if (!qt_atom_parser_has_chunks (&stream->stts, stream->n_sample_times, 8)) {
9283 stream->n_sample_times = gst_byte_reader_get_remaining (&stream->stts) / 8;
9284 GST_LOG_OBJECT (qtdemux, "overriding to %u timestamp blocks",
9285 stream->n_sample_times);
9286 if (!stream->n_sample_times)
9287 goto corrupt_file;
9288 }
9289
9290 /* sync sample atom */
9291 stream->stps_present = FALSE;
9292 if ((stream->stss_present =
9293 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stss,
9294 &stream->stss) ? TRUE : FALSE) == TRUE) {
9295 /* copy atom data into a new buffer for later use */
9296 stream->stss.data = g_memdup2 (stream->stss.data, stream->stss.size);
9297
9298 /* skip version + flags */
9299 if (!gst_byte_reader_skip (&stream->stss, 1 + 3) ||
9300 !gst_byte_reader_get_uint32_be (&stream->stss, &stream->n_sample_syncs))
9301 goto corrupt_file;
9302
9303 if (stream->n_sample_syncs) {
9304 /* make sure there's enough data */
9305 if (!qt_atom_parser_has_chunks (&stream->stss, stream->n_sample_syncs, 4))
9306 goto corrupt_file;
9307 }
9308
9309 /* partial sync sample atom */
9310 if ((stream->stps_present =
9311 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stps,
9312 &stream->stps) ? TRUE : FALSE) == TRUE) {
9313 /* copy atom data into a new buffer for later use */
9314 stream->stps.data = g_memdup2 (stream->stps.data, stream->stps.size);
9315
9316 /* skip version + flags */
9317 if (!gst_byte_reader_skip (&stream->stps, 1 + 3) ||
9318 !gst_byte_reader_get_uint32_be (&stream->stps,
9319 &stream->n_sample_partial_syncs))
9320 goto corrupt_file;
9321
9322 /* if there are no entries, the stss table contains the real
9323 * sync samples */
9324 if (stream->n_sample_partial_syncs) {
9325 /* make sure there's enough data */
9326 if (!qt_atom_parser_has_chunks (&stream->stps,
9327 stream->n_sample_partial_syncs, 4))
9328 goto corrupt_file;
9329 }
9330 }
9331 }
9332
9333 /* sample size */
9334 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsz, &stream->stsz))
9335 goto no_samples;
9336
9337 /* copy atom data into a new buffer for later use */
9338 stream->stsz.data = g_memdup2 (stream->stsz.data, stream->stsz.size);
9339
9340 /* skip version + flags */
9341 if (!gst_byte_reader_skip (&stream->stsz, 1 + 3) ||
9342 !gst_byte_reader_get_uint32_be (&stream->stsz, &stream->sample_size))
9343 goto corrupt_file;
9344
9345 if (!gst_byte_reader_get_uint32_be (&stream->stsz, &stream->n_samples))
9346 goto corrupt_file;
9347
9348 if (!stream->n_samples)
9349 goto no_samples;
9350
9351 /* sample-to-chunk atom */
9352 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsc, &stream->stsc))
9353 goto corrupt_file;
9354
9355 /* copy atom data into a new buffer for later use */
9356 stream->stsc.data = g_memdup2 (stream->stsc.data, stream->stsc.size);
9357
9358 /* skip version + flags */
9359 if (!gst_byte_reader_skip (&stream->stsc, 1 + 3) ||
9360 !gst_byte_reader_get_uint32_be (&stream->stsc,
9361 &stream->n_samples_per_chunk))
9362 goto corrupt_file;
9363
9364 GST_DEBUG_OBJECT (qtdemux, "n_samples_per_chunk %u",
9365 stream->n_samples_per_chunk);
9366
9367 /* make sure there's enough data */
9368 if (!qt_atom_parser_has_chunks (&stream->stsc, stream->n_samples_per_chunk,
9369 12))
9370 goto corrupt_file;
9371
9372
9373 /* chunk offset */
9374 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stco, &stream->stco))
9375 stream->co_size = sizeof (guint32);
9376 else if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_co64,
9377 &stream->stco))
9378 stream->co_size = sizeof (guint64);
9379 else
9380 goto corrupt_file;
9381
9382 /* copy atom data into a new buffer for later use */
9383 stream->stco.data = g_memdup2 (stream->stco.data, stream->stco.size);
9384
9385 /* skip version + flags */
9386 if (!gst_byte_reader_skip (&stream->stco, 1 + 3))
9387 goto corrupt_file;
9388
9389 /* chunks_are_samples == TRUE means treat chunks as samples */
9390 stream->chunks_are_samples = stream->sample_size
9391 && !CUR_STREAM (stream)->sampled;
9392 if (stream->chunks_are_samples) {
9393 /* treat chunks as samples */
9394 if (!gst_byte_reader_get_uint32_be (&stream->stco, &stream->n_samples))
9395 goto corrupt_file;
9396 } else {
9397 /* skip number of entries */
9398 if (!gst_byte_reader_skip (&stream->stco, 4))
9399 goto corrupt_file;
9400
9401 /* make sure there are enough data in the stsz atom */
9402 if (!stream->sample_size) {
9403 /* different sizes for each sample */
9404 if (!qt_atom_parser_has_chunks (&stream->stsz, stream->n_samples, 4))
9405 goto corrupt_file;
9406 }
9407 }
9408
9409 /* composition time-to-sample */
9410 if ((stream->ctts_present =
9411 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_ctts,
9412 &stream->ctts) ? TRUE : FALSE) == TRUE) {
9413 GstByteReader cslg = GST_BYTE_READER_INIT (NULL, 0);
9414 guint8 ctts_version;
9415 gboolean checked_ctts = FALSE;
9416
9417 /* copy atom data into a new buffer for later use */
9418 stream->ctts.data = g_memdup2 (stream->ctts.data, stream->ctts.size);
9419
9420 /* version 1 has signed offsets */
9421 if (!gst_byte_reader_get_uint8 (&stream->ctts, &ctts_version))
9422 goto corrupt_file;
9423
9424 /* flags */
9425 if (!gst_byte_reader_skip (&stream->ctts, 3)
9426 || !gst_byte_reader_get_uint32_be (&stream->ctts,
9427 &stream->n_composition_times))
9428 goto corrupt_file;
9429
9430 /* make sure there's enough data */
9431 if (!qt_atom_parser_has_chunks (&stream->ctts, stream->n_composition_times,
9432 4 + 4))
9433 goto corrupt_file;
9434
9435 /* This is optional, if missing we iterate the ctts */
9436 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_cslg, &cslg)) {
9437 guint8 cslg_version;
9438
9439 /* cslg version 1 has 64 bit fields */
9440 if (!gst_byte_reader_get_uint8 (&cslg, &cslg_version))
9441 goto corrupt_file;
9442
9443 /* skip flags */
9444 if (!gst_byte_reader_skip (&cslg, 3))
9445 goto corrupt_file;
9446
9447 if (cslg_version == 0) {
9448 gint32 composition_to_dts_shift;
9449
9450 if (!gst_byte_reader_get_int32_be (&cslg, &composition_to_dts_shift))
9451 goto corrupt_file;
9452
9453 stream->cslg_shift = MAX (0, composition_to_dts_shift);
9454 } else {
9455 gint64 composition_to_dts_shift;
9456
9457 if (!gst_byte_reader_get_int64_be (&cslg, &composition_to_dts_shift))
9458 goto corrupt_file;
9459
9460 stream->cslg_shift = MAX (0, composition_to_dts_shift);
9461 }
9462 } else {
9463 gint32 cslg_least = 0;
9464 guint num_entries, pos;
9465 gint i;
9466
9467 pos = gst_byte_reader_get_pos (&stream->ctts);
9468 num_entries = stream->n_composition_times;
9469
9470 checked_ctts = TRUE;
9471
9472 stream->cslg_shift = 0;
9473
9474 for (i = 0; i < num_entries; i++) {
9475 gint32 offset;
9476
9477 gst_byte_reader_skip_unchecked (&stream->ctts, 4);
9478 offset = gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
9479 /* HACK: if sample_offset is larger than 2 * duration, ignore the box.
9480 * slightly inaccurate PTS could be more usable than corrupted one */
9481 if (G_UNLIKELY ((ctts_version == 0 || offset != G_MININT32)
zengliang.li055f1112024-05-16 12:50:57 +00009482 && ABS (offset) * 2 > stream->duration)) {
zengliang.li5f31ef42024-05-16 08:27:38 +00009483 GST_WARNING_OBJECT (qtdemux,
9484 "Ignore corrupted ctts, sample_offset %" G_GINT32_FORMAT
9485 " larger than duration %" G_GUINT64_FORMAT, offset,
9486 stream->duration);
9487
9488 stream->cslg_shift = 0;
9489 stream->ctts_present = FALSE;
9490 goto done;
9491 }
9492
9493 /* Don't consider "no decode samples" with offset G_MININT32
9494 * for the DTS/PTS shift */
9495 if (offset != G_MININT32 && offset < cslg_least)
9496 cslg_least = offset;
9497 }
9498
9499 if (cslg_least < 0)
9500 stream->cslg_shift = -cslg_least;
9501 else
9502 stream->cslg_shift = 0;
9503
9504 /* reset the reader so we can generate sample table */
9505 gst_byte_reader_set_pos (&stream->ctts, pos);
9506 }
9507
9508 /* Check if ctts values are looking reasonable if that didn't happen above */
9509 if (!checked_ctts) {
9510 guint num_entries, pos;
9511 gint i;
9512
9513 pos = gst_byte_reader_get_pos (&stream->ctts);
9514 num_entries = stream->n_composition_times;
9515
9516 for (i = 0; i < num_entries; i++) {
9517 gint32 offset;
9518
9519 gst_byte_reader_skip_unchecked (&stream->ctts, 4);
9520 offset = gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
9521 /* HACK: if sample_offset is larger than 2 * duration, ignore the box.
9522 * slightly inaccurate PTS could be more usable than corrupted one */
9523 if (G_UNLIKELY ((ctts_version == 0 || offset != G_MININT32)
9524 && ABS (offset) / 2 > stream->duration)) {
9525 GST_WARNING_OBJECT (qtdemux,
9526 "Ignore corrupted ctts, sample_offset %" G_GINT32_FORMAT
9527 " larger than duration %" G_GUINT64_FORMAT, offset,
9528 stream->duration);
9529
9530 stream->cslg_shift = 0;
9531 stream->ctts_present = FALSE;
9532 goto done;
9533 }
9534 }
9535
9536 /* reset the reader so we can generate sample table */
9537 gst_byte_reader_set_pos (&stream->ctts, pos);
9538 }
9539 } else {
9540 /* Ensure the cslg_shift value is consistent so we can use it
9541 * unconditionally to produce TS and Segment */
9542 stream->cslg_shift = 0;
9543 }
9544
9545 GST_DEBUG_OBJECT (qtdemux, "Using clsg_shift %" G_GUINT64_FORMAT,
9546 stream->cslg_shift);
9547
9548 /* For raw audio streams especially we might want to merge the samples
9549 * to not output one audio sample per buffer. We're doing this here
9550 * before allocating the sample tables so that from this point onwards
9551 * the number of container samples are static */
9552 if (stream->min_buffer_size > 0) {
9553 qtdemux_merge_sample_table (qtdemux, stream);
9554 }
9555
9556done:
9557 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
9558 stream->n_samples, (guint) sizeof (QtDemuxSample),
9559 stream->n_samples * sizeof (QtDemuxSample) / (1024.0 * 1024.0));
9560
9561 if (stream->n_samples >=
9562 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample)) {
9563 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
9564 "be larger than %uMB (broken file?)", stream->n_samples,
9565 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
9566 return FALSE;
9567 }
9568
9569 g_assert (stream->samples == NULL);
9570 stream->samples = g_try_new0 (QtDemuxSample, stream->n_samples);
9571 if (!stream->samples) {
9572 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
9573 stream->n_samples);
9574 return FALSE;
9575 }
9576
9577 return TRUE;
9578
9579corrupt_file:
9580 {
9581 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
9582 (_("This file is corrupt and cannot be played.")), (NULL));
9583 return FALSE;
9584 }
9585no_samples:
9586 {
9587 gst_qtdemux_stbl_free (stream);
9588 if (!qtdemux->fragmented) {
9589 /* not quite good */
9590 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
9591 return FALSE;
9592 } else {
9593 /* may pick up samples elsewhere */
9594 return TRUE;
9595 }
9596 }
9597}
9598
9599/* collect samples from the next sample to be parsed up to sample @n for @stream
9600 * by reading the info from @stbl
9601 *
9602 * This code can be executed from both the streaming thread and the seeking
9603 * thread so it takes the object lock to protect itself
9604 */
9605static gboolean
9606qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream, guint32 n)
9607{
9608 gint i, j, k;
9609 QtDemuxSample *samples, *first, *cur, *last;
9610 guint32 n_samples_per_chunk;
9611 guint32 n_samples;
9612
9613 GST_LOG_OBJECT (qtdemux, "parsing samples for stream fourcc %"
9614 GST_FOURCC_FORMAT ", pad %s",
9615 GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc),
9616 stream->pad ? GST_PAD_NAME (stream->pad) : "(NULL)");
9617
9618 n_samples = stream->n_samples;
9619
9620 if (n >= n_samples)
9621 goto out_of_samples;
9622
9623 GST_OBJECT_LOCK (qtdemux);
9624 if (n <= stream->stbl_index)
9625 goto already_parsed;
9626
9627 GST_DEBUG_OBJECT (qtdemux, "parsing up to sample %u", n);
9628
9629 if (!stream->stsz.data) {
9630 /* so we already parsed and passed all the moov samples;
9631 * onto fragmented ones */
9632 g_assert (qtdemux->fragmented);
9633 goto done;
9634 }
9635
9636 /* pointer to the sample table */
9637 samples = stream->samples;
9638
9639 /* starts from -1, moves to the next sample index to parse */
9640 stream->stbl_index++;
9641
9642 /* keep track of the first and last sample to fill */
9643 first = &samples[stream->stbl_index];
9644 last = &samples[n];
9645
9646 if (!stream->chunks_are_samples) {
9647 /* set the sample sizes */
9648 if (stream->sample_size == 0) {
9649 /* different sizes for each sample */
9650 for (cur = first; cur <= last; cur++) {
9651 cur->size = gst_byte_reader_get_uint32_be_unchecked (&stream->stsz);
9652 GST_LOG_OBJECT (qtdemux, "sample %d has size %u",
9653 (guint) (cur - samples), cur->size);
9654 }
9655 } else {
9656 /* samples have the same size */
9657 GST_LOG_OBJECT (qtdemux, "all samples have size %u", stream->sample_size);
9658 for (cur = first; cur <= last; cur++)
9659 cur->size = stream->sample_size;
9660 }
9661 }
9662
9663 n_samples_per_chunk = stream->n_samples_per_chunk;
9664 cur = first;
9665
9666 for (i = stream->stsc_index; i < n_samples_per_chunk; i++) {
9667 guint32 last_chunk;
9668
9669 if (stream->stsc_chunk_index >= stream->last_chunk
9670 || stream->stsc_chunk_index < stream->first_chunk) {
9671 stream->first_chunk =
9672 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9673 stream->samples_per_chunk =
9674 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9675 /* starts from 1 */
9676 stream->stsd_sample_description_id =
9677 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc) - 1;
9678
9679 /* chunk numbers are counted from 1 it seems */
9680 if (G_UNLIKELY (stream->first_chunk == 0))
9681 goto corrupt_file;
9682
9683 --stream->first_chunk;
9684
9685 /* the last chunk of each entry is calculated by taking the first chunk
9686 * of the next entry; except if there is no next, where we fake it with
9687 * INT_MAX */
9688 if (G_UNLIKELY (i == (stream->n_samples_per_chunk - 1))) {
9689 stream->last_chunk = G_MAXUINT32;
9690 } else {
9691 stream->last_chunk =
9692 gst_byte_reader_peek_uint32_be_unchecked (&stream->stsc);
9693 if (G_UNLIKELY (stream->last_chunk == 0))
9694 goto corrupt_file;
9695
9696 --stream->last_chunk;
9697 }
9698
9699 GST_LOG_OBJECT (qtdemux,
9700 "entry %d has first_chunk %d, last_chunk %d, samples_per_chunk %d"
9701 "sample desc ID: %d", i, stream->first_chunk, stream->last_chunk,
9702 stream->samples_per_chunk, stream->stsd_sample_description_id);
9703
9704 if (G_UNLIKELY (stream->last_chunk < stream->first_chunk))
9705 goto corrupt_file;
9706
9707 if (stream->last_chunk != G_MAXUINT32) {
9708 if (!qt_atom_parser_peek_sub (&stream->stco,
9709 stream->first_chunk * stream->co_size,
9710 (stream->last_chunk - stream->first_chunk) * stream->co_size,
9711 &stream->co_chunk))
9712 goto corrupt_file;
9713
9714 } else {
9715 stream->co_chunk = stream->stco;
9716 if (!gst_byte_reader_skip (&stream->co_chunk,
9717 stream->first_chunk * stream->co_size))
9718 goto corrupt_file;
9719 }
9720
9721 stream->stsc_chunk_index = stream->first_chunk;
9722 }
9723
9724 last_chunk = stream->last_chunk;
9725
9726 if (stream->chunks_are_samples) {
9727 cur = &samples[stream->stsc_chunk_index];
9728
9729 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
9730 if (j > n) {
9731 /* save state */
9732 stream->stsc_chunk_index = j;
9733 goto done;
9734 }
9735
9736 cur->offset =
9737 qt_atom_parser_get_offset_unchecked (&stream->co_chunk,
9738 stream->co_size);
9739
9740 GST_LOG_OBJECT (qtdemux, "Created entry %d with offset "
9741 "%" G_GUINT64_FORMAT, j, cur->offset);
9742
9743 if (CUR_STREAM (stream)->samples_per_frame > 0 &&
9744 CUR_STREAM (stream)->bytes_per_frame > 0) {
9745 cur->size =
9746 (stream->samples_per_chunk * CUR_STREAM (stream)->n_channels) /
9747 CUR_STREAM (stream)->samples_per_frame *
9748 CUR_STREAM (stream)->bytes_per_frame;
9749 } else {
9750 cur->size = stream->samples_per_chunk;
9751 }
9752
9753 GST_DEBUG_OBJECT (qtdemux,
9754 "keyframe sample %d: timestamp %" GST_TIME_FORMAT ", size %u",
9755 j, GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream,
9756 stream->stco_sample_index)), cur->size);
9757
9758 cur->timestamp = stream->stco_sample_index;
9759 cur->duration = stream->samples_per_chunk;
9760 cur->keyframe = TRUE;
9761 cur++;
9762
9763 stream->stco_sample_index += stream->samples_per_chunk;
9764 }
9765 stream->stsc_chunk_index = j;
9766 } else {
9767 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
9768 guint32 samples_per_chunk;
9769 guint64 chunk_offset;
9770
9771 if (!stream->stsc_sample_index
9772 && !qt_atom_parser_get_offset (&stream->co_chunk, stream->co_size,
9773 &stream->chunk_offset))
9774 goto corrupt_file;
9775
9776 samples_per_chunk = stream->samples_per_chunk;
9777 chunk_offset = stream->chunk_offset;
9778
9779 for (k = stream->stsc_sample_index; k < samples_per_chunk; k++) {
9780 GST_LOG_OBJECT (qtdemux, "creating entry %d with offset %"
9781 G_GUINT64_FORMAT " and size %d",
9782 (guint) (cur - samples), chunk_offset, cur->size);
9783
9784 cur->offset = chunk_offset;
9785 chunk_offset += cur->size;
9786 cur++;
9787
9788 if (G_UNLIKELY (cur > last)) {
9789 /* save state */
9790 stream->stsc_sample_index = k + 1;
9791 stream->chunk_offset = chunk_offset;
9792 stream->stsc_chunk_index = j;
9793 goto done2;
9794 }
9795 }
9796 stream->stsc_sample_index = 0;
9797 }
9798 stream->stsc_chunk_index = j;
9799 }
9800 stream->stsc_index++;
9801 }
9802
9803 if (stream->chunks_are_samples)
9804 goto ctts;
9805done2:
9806 {
9807 guint32 n_sample_times;
9808
9809 n_sample_times = stream->n_sample_times;
9810 cur = first;
9811
9812 for (i = stream->stts_index; i < n_sample_times; i++) {
9813 guint32 stts_samples;
9814 gint32 stts_duration;
9815 gint64 stts_time;
9816
9817 if (stream->stts_sample_index >= stream->stts_samples
9818 || !stream->stts_sample_index) {
9819
9820 stream->stts_samples =
9821 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
9822 stream->stts_duration =
9823 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
9824
9825 GST_LOG_OBJECT (qtdemux, "block %d, %u timestamps, duration %u",
9826 i, stream->stts_samples, stream->stts_duration);
9827
9828 stream->stts_sample_index = 0;
9829 }
9830
9831 stts_samples = stream->stts_samples;
9832 stts_duration = stream->stts_duration;
9833 stts_time = stream->stts_time;
9834
9835 for (j = stream->stts_sample_index; j < stts_samples; j++) {
9836 GST_DEBUG_OBJECT (qtdemux,
9837 "sample %d: index %d, timestamp %" GST_TIME_FORMAT,
9838 (guint) (cur - samples), j,
9839 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stts_time)));
9840
9841 cur->timestamp = stts_time;
9842 cur->duration = stts_duration;
9843
9844 /* avoid 32-bit wrap-around,
9845 * but still mind possible 'negative' duration */
9846 stts_time += (gint64) stts_duration;
9847 cur++;
9848
9849 if (G_UNLIKELY (cur > last)) {
9850 /* save values */
9851 stream->stts_time = stts_time;
9852 stream->stts_sample_index = j + 1;
9853 if (stream->stts_sample_index >= stream->stts_samples)
9854 stream->stts_index++;
9855 goto done3;
9856 }
9857 }
9858 stream->stts_sample_index = 0;
9859 stream->stts_time = stts_time;
9860 stream->stts_index++;
9861 }
9862 /* fill up empty timestamps with the last timestamp, this can happen when
9863 * the last samples do not decode and so we don't have timestamps for them.
9864 * We however look at the last timestamp to estimate the track length so we
9865 * need something in here. */
9866 for (; cur < last; cur++) {
9867 GST_DEBUG_OBJECT (qtdemux,
9868 "fill sample %d: timestamp %" GST_TIME_FORMAT,
9869 (guint) (cur - samples),
9870 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stream->stts_time)));
9871 cur->timestamp = stream->stts_time;
9872 cur->duration = -1;
9873 }
9874 }
9875done3:
9876 {
9877 /* sample sync, can be NULL */
9878 if (stream->stss_present == TRUE) {
9879 guint32 n_sample_syncs;
9880
9881 n_sample_syncs = stream->n_sample_syncs;
9882
9883 if (!n_sample_syncs) {
9884 GST_DEBUG_OBJECT (qtdemux, "all samples are keyframes");
9885 stream->all_keyframe = TRUE;
9886 } else {
9887 for (i = stream->stss_index; i < n_sample_syncs; i++) {
9888 /* note that the first sample is index 1, not 0 */
9889 guint32 index;
9890
9891 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stss);
9892
9893 if (G_LIKELY (index > 0 && index <= n_samples)) {
9894 index -= 1;
9895 samples[index].keyframe = TRUE;
9896 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
9897 /* and exit if we have enough samples */
9898 if (G_UNLIKELY (index >= n)) {
9899 i++;
9900 break;
9901 }
9902 }
9903 }
9904 /* save state */
9905 stream->stss_index = i;
9906 }
9907
9908 /* stps marks partial sync frames like open GOP I-Frames */
9909 if (stream->stps_present == TRUE) {
9910 guint32 n_sample_partial_syncs;
9911
9912 n_sample_partial_syncs = stream->n_sample_partial_syncs;
9913
9914 /* if there are no entries, the stss table contains the real
9915 * sync samples */
9916 if (n_sample_partial_syncs) {
9917 for (i = stream->stps_index; i < n_sample_partial_syncs; i++) {
9918 /* note that the first sample is index 1, not 0 */
9919 guint32 index;
9920
9921 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stps);
9922
9923 if (G_LIKELY (index > 0 && index <= n_samples)) {
9924 index -= 1;
9925 samples[index].keyframe = TRUE;
9926 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
9927 /* and exit if we have enough samples */
9928 if (G_UNLIKELY (index >= n)) {
9929 i++;
9930 break;
9931 }
9932 }
9933 }
9934 /* save state */
9935 stream->stps_index = i;
9936 }
9937 }
9938 } else {
9939 /* no stss, all samples are keyframes */
9940 stream->all_keyframe = TRUE;
9941 GST_DEBUG_OBJECT (qtdemux, "setting all keyframes");
9942 }
9943 }
9944
9945ctts:
9946 /* composition time to sample */
9947 if (stream->ctts_present == TRUE) {
9948 guint32 n_composition_times;
9949 guint32 ctts_count;
9950 gint32 ctts_soffset;
9951
9952 /* Fill in the pts_offsets */
9953 cur = first;
9954 n_composition_times = stream->n_composition_times;
9955
9956 for (i = stream->ctts_index; i < n_composition_times; i++) {
9957 if (stream->ctts_sample_index >= stream->ctts_count
9958 || !stream->ctts_sample_index) {
9959 stream->ctts_count =
9960 gst_byte_reader_get_uint32_be_unchecked (&stream->ctts);
9961 stream->ctts_soffset =
9962 gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
9963 stream->ctts_sample_index = 0;
9964 }
9965
9966 ctts_count = stream->ctts_count;
9967 ctts_soffset = stream->ctts_soffset;
9968
9969 /* FIXME: Set offset to 0 for "no decode samples". This needs
9970 * to be handled in a codec specific manner ideally. */
9971 if (ctts_soffset == G_MININT32)
9972 ctts_soffset = 0;
9973
9974 for (j = stream->ctts_sample_index; j < ctts_count; j++) {
zengliang.li4681ee42024-05-16 12:25:30 +00009975 if (stream->elst_media_time != G_MAXUINT64 && FOURCC_vide == stream->subtype)
9976 {
9977 cur->pts_offset = ctts_soffset - stream->elst_media_time;
9978 GST_DEBUG_OBJECT (qtdemux, "elst_media_time: %lld, new pts_offset: %lld", stream->elst_media_time, cur->pts_offset);
9979 } else {
9980 cur->pts_offset = ctts_soffset;
9981 }
zengliang.li5f31ef42024-05-16 08:27:38 +00009982 cur++;
9983
9984 if (G_UNLIKELY (cur > last)) {
9985 /* save state */
9986 stream->ctts_sample_index = j + 1;
9987 goto done;
9988 }
9989 }
9990 stream->ctts_sample_index = 0;
9991 stream->ctts_index++;
9992 }
9993 }
9994done:
9995 stream->stbl_index = n;
9996 /* if index has been completely parsed, free data that is no-longer needed */
9997 if (n + 1 == stream->n_samples) {
9998 gst_qtdemux_stbl_free (stream);
9999 GST_DEBUG_OBJECT (qtdemux, "parsed all available samples;");
10000 if (qtdemux->pullbased) {
10001 GST_DEBUG_OBJECT (qtdemux, "checking for more samples");
10002 while (n + 1 == stream->n_samples)
10003 if (qtdemux_add_fragmented_samples (qtdemux) != GST_FLOW_OK)
10004 break;
10005 }
10006 }
10007 GST_OBJECT_UNLOCK (qtdemux);
10008
10009 return TRUE;
10010
10011 /* SUCCESS */
10012already_parsed:
10013 {
10014 GST_LOG_OBJECT (qtdemux,
10015 "Tried to parse up to sample %u but this sample has already been parsed",
10016 n);
10017 /* if fragmented, there may be more */
10018 if (qtdemux->fragmented && n == stream->stbl_index)
10019 goto done;
10020 GST_OBJECT_UNLOCK (qtdemux);
10021 return TRUE;
10022 }
10023 /* ERRORS */
10024out_of_samples:
10025 {
10026 GST_LOG_OBJECT (qtdemux,
10027 "Tried to parse up to sample %u but there are only %u samples", n + 1,
10028 stream->n_samples);
10029 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
10030 (_("This file is corrupt and cannot be played.")), (NULL));
10031 return FALSE;
10032 }
10033corrupt_file:
10034 {
10035 GST_OBJECT_UNLOCK (qtdemux);
10036 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
10037 (_("This file is corrupt and cannot be played.")), (NULL));
10038 return FALSE;
10039 }
10040}
10041
10042/* collect all segment info for @stream.
10043 */
10044static gboolean
10045qtdemux_parse_segments (GstQTDemux * qtdemux, QtDemuxStream * stream,
10046 GNode * trak)
10047{
10048 GNode *edts;
10049 /* accept edts if they contain gaps at start and there is only
10050 * one media segment */
10051 gboolean allow_pushbased_edts = TRUE;
10052 gint media_segments_count = 0;
10053
10054 /* parse and prepare segment info from the edit list */
10055 GST_DEBUG_OBJECT (qtdemux, "looking for edit list container");
10056 stream->n_segments = 0;
10057 stream->segments = NULL;
zengliang.li4681ee42024-05-16 12:25:30 +000010058 stream->elst_media_time = G_MAXUINT64;
zengliang.li5f31ef42024-05-16 08:27:38 +000010059 if ((edts = qtdemux_tree_get_child_by_type (trak, FOURCC_edts))) {
10060 GNode *elst;
10061 guint n_segments;
10062 guint segment_number, entry_size;
10063 guint64 time;
10064 GstClockTime stime;
10065 const guint8 *buffer;
10066 guint8 version;
10067 guint32 size;
10068
10069 GST_DEBUG_OBJECT (qtdemux, "looking for edit list");
10070 if (!(elst = qtdemux_tree_get_child_by_type (edts, FOURCC_elst)))
10071 goto done;
10072
10073 buffer = elst->data;
10074
10075 size = QT_UINT32 (buffer);
10076 /* version, flags, n_segments */
10077 if (size < 16) {
10078 GST_WARNING_OBJECT (qtdemux, "Invalid edit list");
10079 goto done;
10080 }
10081 version = QT_UINT8 (buffer + 8);
10082 entry_size = (version == 1) ? 20 : 12;
10083
10084 n_segments = QT_UINT32 (buffer + 12);
10085
10086 if (n_segments > 100000 || size < 16 + n_segments * entry_size) {
10087 GST_WARNING_OBJECT (qtdemux, "Invalid edit list");
10088 goto done;
10089 }
10090
10091 /* we might allocate a bit too much, at least allocate 1 segment */
10092 stream->segments = g_new (QtDemuxSegment, MAX (n_segments, 1));
10093
10094 /* segments always start from 0 */
10095 time = 0;
10096 stime = 0;
10097 buffer += 16;
10098 for (segment_number = 0; segment_number < n_segments; segment_number++) {
10099 guint64 duration;
10100 guint64 media_time;
10101 gboolean empty_edit = FALSE;
10102 QtDemuxSegment *segment;
10103 guint32 rate_int;
10104 GstClockTime media_start = GST_CLOCK_TIME_NONE;
10105
10106 if (version == 1) {
10107 media_time = QT_UINT64 (buffer + 8);
10108 duration = QT_UINT64 (buffer);
10109 if (media_time == G_MAXUINT64)
10110 empty_edit = TRUE;
10111 } else {
10112 media_time = QT_UINT32 (buffer + 4);
10113 duration = QT_UINT32 (buffer);
10114 if (media_time == G_MAXUINT32)
10115 empty_edit = TRUE;
10116 }
10117
10118 if (!empty_edit)
zengliang.li4681ee42024-05-16 12:25:30 +000010119 {
10120 stream->elst_media_time = MIN(media_time, stream->elst_media_time);
zengliang.li5f31ef42024-05-16 08:27:38 +000010121 media_start = QTSTREAMTIME_TO_GSTTIME (stream, media_time);
zengliang.li4681ee42024-05-16 12:25:30 +000010122 }
zengliang.li5f31ef42024-05-16 08:27:38 +000010123
10124 segment = &stream->segments[segment_number];
10125
10126 /* time and duration expressed in global timescale */
10127 segment->time = stime;
10128 if (duration != 0 || empty_edit) {
10129 /* edge case: empty edits with duration=zero are treated here.
10130 * (files should not have these anyway). */
10131
10132 /* add non scaled values so we don't cause roundoff errors */
10133 time += duration;
10134 stime = QTTIME_TO_GSTTIME (qtdemux, time);
10135 segment->duration = stime - segment->time;
10136 } else {
10137 /* zero duration does not imply media_start == media_stop
10138 * but, only specify media_start. The edit ends with the track. */
10139 stime = segment->duration = GST_CLOCK_TIME_NONE;
10140 /* Don't allow more edits after this one. */
10141 n_segments = segment_number + 1;
10142 }
10143 segment->stop_time = stime;
10144
10145 segment->trak_media_start = media_time;
10146 /* media_time expressed in stream timescale */
10147 if (!empty_edit) {
10148 segment->media_start = media_start;
10149 segment->media_stop = GST_CLOCK_TIME_IS_VALID (segment->duration)
10150 ? segment->media_start + segment->duration : GST_CLOCK_TIME_NONE;
10151 media_segments_count++;
10152 } else {
10153 segment->media_start = GST_CLOCK_TIME_NONE;
10154 segment->media_stop = GST_CLOCK_TIME_NONE;
10155 }
10156 rate_int = QT_UINT32 (buffer + ((version == 1) ? 16 : 8));
10157
10158 if (rate_int <= 1) {
10159 /* 0 is not allowed, some programs write 1 instead of the floating point
10160 * value */
10161 GST_WARNING_OBJECT (qtdemux, "found suspicious rate %" G_GUINT32_FORMAT,
10162 rate_int);
10163 segment->rate = 1;
10164 } else {
10165 segment->rate = rate_int / 65536.0;
10166 }
10167
10168 GST_DEBUG_OBJECT (qtdemux, "created segment %d time %" GST_TIME_FORMAT
10169 ", duration %" GST_TIME_FORMAT ", media_start %" GST_TIME_FORMAT
10170 " (%" G_GUINT64_FORMAT ") , media_stop %" GST_TIME_FORMAT
10171 " stop_time %" GST_TIME_FORMAT " rate %g, (%d) timescale %u",
10172 segment_number, GST_TIME_ARGS (segment->time),
10173 GST_TIME_ARGS (segment->duration),
10174 GST_TIME_ARGS (segment->media_start), media_time,
10175 GST_TIME_ARGS (segment->media_stop),
10176 GST_TIME_ARGS (segment->stop_time), segment->rate, rate_int,
10177 stream->timescale);
10178 if (segment->stop_time > qtdemux->segment.stop &&
10179 !qtdemux->upstream_format_is_time) {
10180 GST_WARNING_OBJECT (qtdemux, "Segment %d "
10181 " extends to %" GST_TIME_FORMAT
10182 " past the end of the declared movie duration %" GST_TIME_FORMAT
10183 " movie segment will be extended", segment_number,
10184 GST_TIME_ARGS (segment->stop_time),
10185 GST_TIME_ARGS (qtdemux->segment.stop));
10186 qtdemux->segment.stop = qtdemux->segment.duration = segment->stop_time;
10187 }
10188
10189 buffer += entry_size;
10190 }
10191 GST_DEBUG_OBJECT (qtdemux, "found %d segments", n_segments);
10192 stream->n_segments = n_segments;
10193 if (media_segments_count != 1)
10194 allow_pushbased_edts = FALSE;
10195 }
10196done:
10197
10198 /* push based does not handle segments, so act accordingly here,
10199 * and warn if applicable */
10200 if (!qtdemux->pullbased && !allow_pushbased_edts) {
10201 GST_WARNING_OBJECT (qtdemux, "streaming; discarding edit list segments");
10202 /* remove and use default one below, we stream like it anyway */
10203 g_free (stream->segments);
10204 stream->segments = NULL;
10205 stream->n_segments = 0;
10206 }
10207
10208 /* no segments, create one to play the complete trak */
10209 if (stream->n_segments == 0) {
10210 GstClockTime stream_duration =
10211 QTSTREAMTIME_TO_GSTTIME (stream, stream->duration);
10212
10213 if (stream->segments == NULL)
10214 stream->segments = g_new (QtDemuxSegment, 1);
10215
10216 /* represent unknown our way */
10217 if (stream_duration == 0)
10218 stream_duration = GST_CLOCK_TIME_NONE;
10219
10220 stream->segments[0].time = 0;
10221 stream->segments[0].stop_time = stream_duration;
10222 stream->segments[0].duration = stream_duration;
10223 stream->segments[0].media_start = 0;
10224 stream->segments[0].media_stop = stream_duration;
10225 stream->segments[0].rate = 1.0;
10226 stream->segments[0].trak_media_start = 0;
10227
10228 GST_DEBUG_OBJECT (qtdemux, "created dummy segment %" GST_TIME_FORMAT,
10229 GST_TIME_ARGS (stream_duration));
10230 stream->n_segments = 1;
10231 stream->dummy_segment = TRUE;
10232 }
10233 GST_DEBUG_OBJECT (qtdemux, "using %d segments", stream->n_segments);
10234
10235 return TRUE;
10236}
10237
10238/*
10239 * Parses the stsd atom of a svq3 trak looking for
10240 * the SMI and gama atoms.
10241 */
10242static void
10243qtdemux_parse_svq3_stsd_data (GstQTDemux * qtdemux,
10244 const guint8 * stsd_entry_data, const guint8 ** gamma, GstBuffer ** seqh)
10245{
10246 const guint8 *_gamma = NULL;
10247 GstBuffer *_seqh = NULL;
10248 const guint8 *stsd_data = stsd_entry_data;
10249 guint32 length = QT_UINT32 (stsd_data);
10250 guint16 version;
10251
10252 if (length < 32) {
10253 GST_WARNING_OBJECT (qtdemux, "stsd too short");
10254 goto end;
10255 }
10256
10257 stsd_data += 16;
10258 length -= 16;
10259 version = QT_UINT16 (stsd_data);
10260 if (version == 3) {
10261 if (length >= 70) {
10262 length -= 70;
10263 stsd_data += 70;
10264 while (length > 8) {
10265 guint32 fourcc, size;
10266 const guint8 *data;
10267 size = QT_UINT32 (stsd_data);
10268 fourcc = QT_FOURCC (stsd_data + 4);
10269 data = stsd_data + 8;
10270
10271 if (size == 0) {
10272 GST_WARNING_OBJECT (qtdemux, "Atom of size 0 found, aborting "
10273 "svq3 atom parsing");
10274 goto end;
10275 }
10276
10277 switch (fourcc) {
10278 case FOURCC_gama:{
10279 if (size == 12) {
10280 _gamma = data;
10281 } else {
10282 GST_WARNING_OBJECT (qtdemux, "Unexpected size %" G_GUINT32_FORMAT
10283 " for gama atom, expected 12", size);
10284 }
10285 break;
10286 }
10287 case FOURCC_SMI_:{
10288 if (size > 16 && QT_FOURCC (data) == FOURCC_SEQH) {
10289 guint32 seqh_size;
10290 if (_seqh != NULL) {
10291 GST_WARNING_OBJECT (qtdemux, "Unexpected second SEQH SMI atom "
10292 " found, ignoring");
10293 } else {
10294 seqh_size = QT_UINT32 (data + 4);
10295 if (seqh_size > 0) {
10296 _seqh = gst_buffer_new_and_alloc (seqh_size);
10297 gst_buffer_fill (_seqh, 0, data + 8, seqh_size);
10298 }
10299 }
10300 }
10301 break;
10302 }
10303 default:{
10304 GST_WARNING_OBJECT (qtdemux, "Unhandled atom %" GST_FOURCC_FORMAT
10305 " in SVQ3 entry in stsd atom", GST_FOURCC_ARGS (fourcc));
10306 }
10307 }
10308
10309 if (size <= length) {
10310 length -= size;
10311 stsd_data += size;
10312 }
10313 }
10314 } else {
10315 GST_WARNING_OBJECT (qtdemux, "SVQ3 entry too short in stsd atom");
10316 }
10317 } else {
10318 GST_WARNING_OBJECT (qtdemux, "Unexpected version for SVQ3 entry %"
10319 G_GUINT16_FORMAT, version);
10320 goto end;
10321 }
10322
10323end:
10324 if (gamma) {
10325 *gamma = _gamma;
10326 }
10327 if (seqh) {
10328 *seqh = _seqh;
10329 } else if (_seqh) {
10330 gst_buffer_unref (_seqh);
10331 }
10332}
10333
10334static gchar *
10335qtdemux_get_rtsp_uri_from_hndl (GstQTDemux * qtdemux, GNode * minf)
10336{
10337 GNode *dinf;
10338 GstByteReader dref;
10339 gchar *uri = NULL;
10340
10341 /*
10342 * Get 'dinf', to get its child 'dref', that might contain a 'hndl'
10343 * atom that might contain a 'data' atom with the rtsp uri.
10344 * This case was reported in bug #597497, some info about
10345 * the hndl atom can be found in TN1195
10346 */
10347 dinf = qtdemux_tree_get_child_by_type (minf, FOURCC_dinf);
10348 GST_DEBUG_OBJECT (qtdemux, "Trying to obtain rtsp URI for stream trak");
10349
10350 if (dinf) {
10351 guint32 dref_num_entries = 0;
10352 if (qtdemux_tree_get_child_by_type_full (dinf, FOURCC_dref, &dref) &&
10353 gst_byte_reader_skip (&dref, 4) &&
10354 gst_byte_reader_get_uint32_be (&dref, &dref_num_entries)) {
10355 gint i;
10356
10357 /* search dref entries for hndl atom */
10358 for (i = 0; i < dref_num_entries; i++) {
10359 guint32 size = 0, type;
10360 guint8 string_len = 0;
10361 if (gst_byte_reader_get_uint32_be (&dref, &size) &&
10362 qt_atom_parser_get_fourcc (&dref, &type)) {
10363 if (type == FOURCC_hndl) {
10364 GST_DEBUG_OBJECT (qtdemux, "Found hndl atom");
10365
10366 /* skip data reference handle bytes and the
10367 * following pascal string and some extra 4
10368 * bytes I have no idea what are */
10369 if (!gst_byte_reader_skip (&dref, 4) ||
10370 !gst_byte_reader_get_uint8 (&dref, &string_len) ||
10371 !gst_byte_reader_skip (&dref, string_len + 4)) {
10372 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl atom");
10373 break;
10374 }
10375
10376 /* iterate over the atoms to find the data atom */
10377 while (gst_byte_reader_get_remaining (&dref) >= 8) {
10378 guint32 atom_size;
10379 guint32 atom_type;
10380
10381 if (gst_byte_reader_get_uint32_be (&dref, &atom_size) &&
10382 qt_atom_parser_get_fourcc (&dref, &atom_type)) {
10383 if (atom_type == FOURCC_data) {
10384 const guint8 *uri_aux = NULL;
10385
10386 /* found the data atom that might contain the rtsp uri */
10387 GST_DEBUG_OBJECT (qtdemux, "Found data atom inside "
10388 "hndl atom, interpreting it as an URI");
10389 if (gst_byte_reader_peek_data (&dref, atom_size - 8,
10390 &uri_aux)) {
10391 if (g_strstr_len ((gchar *) uri_aux, 7, "rtsp://") != NULL)
10392 uri = g_strndup ((gchar *) uri_aux, atom_size - 8);
10393 else
10394 GST_WARNING_OBJECT (qtdemux, "Data atom in hndl atom "
10395 "didn't contain a rtsp address");
10396 } else {
10397 GST_WARNING_OBJECT (qtdemux, "Failed to get the data "
10398 "atom contents");
10399 }
10400 break;
10401 }
10402 /* skipping to the next entry */
10403 if (!gst_byte_reader_skip (&dref, atom_size - 8))
10404 break;
10405 } else {
10406 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl child "
10407 "atom header");
10408 break;
10409 }
10410 }
10411 break;
10412 }
10413 /* skip to the next entry */
10414 if (!gst_byte_reader_skip (&dref, size - 8))
10415 break;
10416 } else {
10417 GST_WARNING_OBJECT (qtdemux, "Error parsing dref atom");
10418 }
10419 }
10420 GST_DEBUG_OBJECT (qtdemux, "Finished parsing dref atom");
10421 }
10422 }
10423 return uri;
10424}
10425
10426#define AMR_NB_ALL_MODES 0x81ff
10427#define AMR_WB_ALL_MODES 0x83ff
10428static guint
10429qtdemux_parse_amr_bitrate (GstBuffer * buf, gboolean wb)
10430{
10431 /* The 'damr' atom is of the form:
10432 *
10433 * | vendor | decoder_ver | mode_set | mode_change_period | frames/sample |
10434 * 32 b 8 b 16 b 8 b 8 b
10435 *
10436 * The highest set bit of the first 7 (AMR-NB) or 8 (AMR-WB) bits of mode_set
10437 * represents the highest mode used in the stream (and thus the maximum
10438 * bitrate), with a couple of special cases as seen below.
10439 */
10440
10441 /* Map of frame type ID -> bitrate */
10442 static const guint nb_bitrates[] = {
10443 4750, 5150, 5900, 6700, 7400, 7950, 10200, 12200
10444 };
10445 static const guint wb_bitrates[] = {
10446 6600, 8850, 12650, 14250, 15850, 18250, 19850, 23050, 23850
10447 };
10448 GstMapInfo map;
10449 gsize max_mode;
10450 guint16 mode_set;
10451
10452 gst_buffer_map (buf, &map, GST_MAP_READ);
10453
10454 if (map.size != 0x11) {
10455 GST_DEBUG ("Atom should have size 0x11, not %" G_GSIZE_FORMAT, map.size);
10456 goto bad_data;
10457 }
10458
10459 if (QT_FOURCC (map.data + 4) != FOURCC_damr) {
10460 GST_DEBUG ("Unknown atom in %" GST_FOURCC_FORMAT,
10461 GST_FOURCC_ARGS (QT_UINT32 (map.data + 4)));
10462 goto bad_data;
10463 }
10464
10465 mode_set = QT_UINT16 (map.data + 13);
10466
10467 if (mode_set == (wb ? AMR_WB_ALL_MODES : AMR_NB_ALL_MODES))
10468 max_mode = 7 + (wb ? 1 : 0);
10469 else
10470 /* AMR-NB modes fo from 0-7, and AMR-WB modes go from 0-8 */
10471 max_mode = g_bit_nth_msf ((gulong) mode_set & (wb ? 0x1ff : 0xff), -1);
10472
10473 if (max_mode == -1) {
10474 GST_DEBUG ("No mode indication was found (mode set) = %x",
10475 (guint) mode_set);
10476 goto bad_data;
10477 }
10478
10479 gst_buffer_unmap (buf, &map);
10480 return wb ? wb_bitrates[max_mode] : nb_bitrates[max_mode];
10481
10482bad_data:
10483 gst_buffer_unmap (buf, &map);
10484 return 0;
10485}
10486
10487static gboolean
10488qtdemux_parse_transformation_matrix (GstQTDemux * qtdemux,
10489 GstByteReader * reader, guint32 * matrix, const gchar * atom)
10490{
10491 /*
10492 * 9 values of 32 bits (fixed point 16.16, except 2 5 and 8 that are 2.30)
10493 * [0 1 2]
10494 * [3 4 5]
10495 * [6 7 8]
10496 */
10497
10498 if (gst_byte_reader_get_remaining (reader) < 36)
10499 return FALSE;
10500
10501 matrix[0] = gst_byte_reader_get_uint32_be_unchecked (reader);
10502 matrix[1] = gst_byte_reader_get_uint32_be_unchecked (reader);
10503 matrix[2] = gst_byte_reader_get_uint32_be_unchecked (reader);
10504 matrix[3] = gst_byte_reader_get_uint32_be_unchecked (reader);
10505 matrix[4] = gst_byte_reader_get_uint32_be_unchecked (reader);
10506 matrix[5] = gst_byte_reader_get_uint32_be_unchecked (reader);
10507 matrix[6] = gst_byte_reader_get_uint32_be_unchecked (reader);
10508 matrix[7] = gst_byte_reader_get_uint32_be_unchecked (reader);
10509 matrix[8] = gst_byte_reader_get_uint32_be_unchecked (reader);
10510
10511 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix from atom %s", atom);
10512 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[0] >> 16,
10513 matrix[0] & 0xFFFF, matrix[1] >> 16, matrix[1] & 0xFF, matrix[2] >> 16,
10514 matrix[2] & 0xFF);
10515 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[3] >> 16,
10516 matrix[3] & 0xFFFF, matrix[4] >> 16, matrix[4] & 0xFF, matrix[5] >> 16,
10517 matrix[5] & 0xFF);
10518 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[6] >> 16,
10519 matrix[6] & 0xFFFF, matrix[7] >> 16, matrix[7] & 0xFF, matrix[8] >> 16,
10520 matrix[8] & 0xFF);
10521
10522 return TRUE;
10523}
10524
10525static void
10526qtdemux_inspect_transformation_matrix (GstQTDemux * qtdemux,
10527 QtDemuxStream * stream, guint32 * matrix, GstTagList ** taglist)
10528{
10529
10530/* [a b c]
10531 * [d e f]
10532 * [g h i]
10533 *
10534 * This macro will only compare value abdegh, it expects cfi to have already
10535 * been checked
10536 */
10537#define QTCHECK_MATRIX(m,a,b,d,e) ((m)[0] == (a << 16) && (m)[1] == (b << 16) && \
10538 (m)[3] == (d << 16) && (m)[4] == (e << 16))
10539
10540 /* only handle the cases where the last column has standard values */
10541 if (matrix[2] == 0 && matrix[5] == 0 && matrix[8] == 1 << 30) {
10542 const gchar *rotation_tag = NULL;
10543
10544 /* no rotation needed */
10545 if (QTCHECK_MATRIX (matrix, 1, 0, 0, 1)) {
10546 /* NOP */
10547 } else if (QTCHECK_MATRIX (matrix, 0, 1, G_MAXUINT16, 0)) {
10548 rotation_tag = "rotate-90";
10549 } else if (QTCHECK_MATRIX (matrix, G_MAXUINT16, 0, 0, G_MAXUINT16)) {
10550 rotation_tag = "rotate-180";
10551 } else if (QTCHECK_MATRIX (matrix, 0, G_MAXUINT16, 1, 0)) {
10552 rotation_tag = "rotate-270";
10553 } else {
10554 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
10555 }
10556
10557 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix rotation %s",
10558 GST_STR_NULL (rotation_tag));
10559 if (rotation_tag != NULL) {
10560 if (*taglist == NULL)
10561 *taglist = gst_tag_list_new_empty ();
10562 gst_tag_list_add (*taglist, GST_TAG_MERGE_REPLACE,
10563 GST_TAG_IMAGE_ORIENTATION, rotation_tag, NULL);
10564 }
10565 } else {
10566 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
10567 }
10568}
10569
10570static gboolean
10571qtdemux_parse_protection_aavd (GstQTDemux * qtdemux,
10572 QtDemuxStream * stream, GNode * container, guint32 * original_fmt)
10573{
10574 GNode *adrm;
10575 guint32 adrm_size;
10576 GstBuffer *adrm_buf = NULL;
10577 QtDemuxAavdEncryptionInfo *info;
10578
10579 adrm = qtdemux_tree_get_child_by_type (container, FOURCC_adrm);
10580 if (G_UNLIKELY (!adrm)) {
10581 GST_ERROR_OBJECT (qtdemux, "aavd box does not contain mandatory adrm box");
10582 return FALSE;
10583 }
10584 adrm_size = QT_UINT32 (adrm->data);
10585 adrm_buf = gst_buffer_new_memdup (adrm->data, adrm_size);
10586
10587 stream->protection_scheme_type = FOURCC_aavd;
10588
10589 if (!stream->protection_scheme_info)
10590 stream->protection_scheme_info = g_new0 (QtDemuxAavdEncryptionInfo, 1);
10591
10592 info = (QtDemuxAavdEncryptionInfo *) stream->protection_scheme_info;
10593
10594 if (info->default_properties)
10595 gst_structure_free (info->default_properties);
10596 info->default_properties = gst_structure_new ("application/x-aavd",
10597 "encrypted", G_TYPE_BOOLEAN, TRUE,
10598 "adrm", GST_TYPE_BUFFER, adrm_buf, NULL);
10599 gst_buffer_unref (adrm_buf);
10600
10601 *original_fmt = FOURCC_mp4a;
10602 return TRUE;
10603}
10604
10605/* Parses the boxes defined in ISO/IEC 14496-12 that enable support for
10606 * protected streams (sinf, frma, schm and schi); if the protection scheme is
10607 * Common Encryption (cenc), the function will also parse the tenc box (defined
10608 * in ISO/IEC 23001-7). @container points to the node that contains these boxes
10609 * (typically an enc[v|a|t|s] sample entry); the function will set
10610 * @original_fmt to the fourcc of the original unencrypted stream format.
10611 * Returns TRUE if successful; FALSE otherwise. */
10612static gboolean
10613qtdemux_parse_protection_scheme_info (GstQTDemux * qtdemux,
10614 QtDemuxStream * stream, GNode * container, guint32 * original_fmt)
10615{
10616 GNode *sinf;
10617 GNode *frma;
10618 GNode *schm;
10619 GNode *schi;
10620 QtDemuxCencSampleSetInfo *info;
10621 GNode *tenc;
10622 const guint8 *tenc_data;
10623
10624 g_return_val_if_fail (qtdemux != NULL, FALSE);
10625 g_return_val_if_fail (stream != NULL, FALSE);
10626 g_return_val_if_fail (container != NULL, FALSE);
10627 g_return_val_if_fail (original_fmt != NULL, FALSE);
10628
10629 sinf = qtdemux_tree_get_child_by_type (container, FOURCC_sinf);
10630 if (G_UNLIKELY (!sinf)) {
10631 if (stream->protection_scheme_type == FOURCC_cenc
10632 || stream->protection_scheme_type == FOURCC_cbcs) {
10633 GST_ERROR_OBJECT (qtdemux, "sinf box does not contain schi box, which is "
10634 "mandatory for Common Encryption");
10635 return FALSE;
10636 }
10637 return TRUE;
10638 }
10639
10640 frma = qtdemux_tree_get_child_by_type (sinf, FOURCC_frma);
10641 if (G_UNLIKELY (!frma)) {
10642 GST_ERROR_OBJECT (qtdemux, "sinf box does not contain mandatory frma box");
10643 return FALSE;
10644 }
10645
10646 *original_fmt = QT_FOURCC ((const guint8 *) frma->data + 8);
10647 GST_DEBUG_OBJECT (qtdemux, "original stream format: '%" GST_FOURCC_FORMAT "'",
10648 GST_FOURCC_ARGS (*original_fmt));
10649
10650 schm = qtdemux_tree_get_child_by_type (sinf, FOURCC_schm);
10651 if (!schm) {
10652 GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schm box");
10653 return FALSE;
10654 }
10655 stream->protection_scheme_type = QT_FOURCC ((const guint8 *) schm->data + 12);
10656 stream->protection_scheme_version =
10657 QT_UINT32 ((const guint8 *) schm->data + 16);
10658
10659 GST_DEBUG_OBJECT (qtdemux,
10660 "protection_scheme_type: %" GST_FOURCC_FORMAT ", "
10661 "protection_scheme_version: %#010x",
10662 GST_FOURCC_ARGS (stream->protection_scheme_type),
10663 stream->protection_scheme_version);
10664
10665 schi = qtdemux_tree_get_child_by_type (sinf, FOURCC_schi);
10666 if (!schi) {
10667 GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schi box");
10668 return FALSE;
10669 }
10670 if (stream->protection_scheme_type != FOURCC_cenc &&
10671 stream->protection_scheme_type != FOURCC_piff &&
10672 stream->protection_scheme_type != FOURCC_cbcs) {
10673 GST_ERROR_OBJECT (qtdemux,
10674 "Invalid protection_scheme_type: %" GST_FOURCC_FORMAT,
10675 GST_FOURCC_ARGS (stream->protection_scheme_type));
10676 return FALSE;
10677 }
10678
10679 if (G_UNLIKELY (!stream->protection_scheme_info))
10680 stream->protection_scheme_info =
10681 g_malloc0 (sizeof (QtDemuxCencSampleSetInfo));
10682
10683 info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
10684
10685 if (stream->protection_scheme_type == FOURCC_cenc
10686 || stream->protection_scheme_type == FOURCC_cbcs) {
10687 guint8 is_encrypted;
10688 guint8 iv_size;
10689 guint8 constant_iv_size = 0;
10690 const guint8 *default_kid;
10691 guint8 crypt_byte_block = 0;
10692 guint8 skip_byte_block = 0;
10693 const guint8 *constant_iv = NULL;
10694
10695 tenc = qtdemux_tree_get_child_by_type (schi, FOURCC_tenc);
10696 if (!tenc) {
10697 GST_ERROR_OBJECT (qtdemux, "schi box does not contain tenc box, "
10698 "which is mandatory for Common Encryption");
10699 return FALSE;
10700 }
10701 tenc_data = (const guint8 *) tenc->data + 12;
10702 is_encrypted = QT_UINT8 (tenc_data + 2);
10703 iv_size = QT_UINT8 (tenc_data + 3);
10704 default_kid = (tenc_data + 4);
10705 if (stream->protection_scheme_type == FOURCC_cbcs) {
10706 guint8 possible_pattern_info;
10707 if (iv_size == 0) {
10708 constant_iv_size = QT_UINT8 (tenc_data + 20);
10709 if (constant_iv_size != 8 && constant_iv_size != 16) {
10710 GST_ERROR_OBJECT (qtdemux,
10711 "constant IV size should be 8 or 16, not %hhu", constant_iv_size);
10712 return FALSE;
10713 }
10714 constant_iv = (tenc_data + 21);
10715 }
10716 possible_pattern_info = QT_UINT8 (tenc_data + 1);
10717 crypt_byte_block = (possible_pattern_info >> 4) & 0x0f;
10718 skip_byte_block = possible_pattern_info & 0x0f;
10719 }
10720 qtdemux_update_default_sample_cenc_settings (qtdemux, info,
10721 is_encrypted, stream->protection_scheme_type, iv_size, default_kid,
10722 crypt_byte_block, skip_byte_block, constant_iv_size, constant_iv);
10723 } else if (stream->protection_scheme_type == FOURCC_piff) {
10724 GstByteReader br;
10725 static const guint8 piff_track_encryption_uuid[] = {
10726 0x89, 0x74, 0xdb, 0xce, 0x7b, 0xe7, 0x4c, 0x51,
10727 0x84, 0xf9, 0x71, 0x48, 0xf9, 0x88, 0x25, 0x54
10728 };
10729
10730 tenc = qtdemux_tree_get_child_by_type (schi, FOURCC_uuid);
10731 if (!tenc) {
10732 GST_ERROR_OBJECT (qtdemux, "schi box does not contain tenc box, "
10733 "which is mandatory for Common Encryption");
10734 return FALSE;
10735 }
10736
10737 tenc_data = (const guint8 *) tenc->data + 8;
10738 if (memcmp (tenc_data, piff_track_encryption_uuid, 16) != 0) {
10739 gchar *box_uuid = qtdemux_uuid_bytes_to_string (tenc_data);
10740 GST_ERROR_OBJECT (qtdemux,
10741 "Unsupported track encryption box with uuid: %s", box_uuid);
10742 g_free (box_uuid);
10743 return FALSE;
10744 }
10745 tenc_data = (const guint8 *) tenc->data + 16 + 12;
10746 gst_byte_reader_init (&br, tenc_data, 20);
10747 if (!qtdemux_update_default_piff_encryption_settings (qtdemux, info, &br)) {
10748 GST_ERROR_OBJECT (qtdemux, "PIFF track box parsing error");
10749 return FALSE;
10750 }
10751 stream->protection_scheme_type = FOURCC_cenc;
10752 }
10753
10754 return TRUE;
10755}
10756
10757static gint
10758qtdemux_track_id_compare_func (QtDemuxStream ** stream1,
10759 QtDemuxStream ** stream2)
10760{
10761 return (gint) (*stream1)->track_id - (gint) (*stream2)->track_id;
10762}
10763
10764static gboolean
10765qtdemux_parse_stereo_svmi_atom (GstQTDemux * qtdemux, QtDemuxStream * stream,
10766 GNode * stbl)
10767{
10768 GNode *svmi;
10769
10770 /*parse svmi header if existing */
10771 svmi = qtdemux_tree_get_child_by_type (stbl, FOURCC_svmi);
10772 if (svmi) {
10773 guint32 len = QT_UINT32 ((guint8 *) svmi->data);
10774 guint32 version = QT_UINT32 ((guint8 *) svmi->data + 8);
10775 if (!version) {
10776 GstVideoMultiviewMode mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
10777 GstVideoMultiviewFlags flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
10778 guint8 frame_type, frame_layout;
10779 guint32 stereo_mono_change_count;
10780
10781 if (len < 18)
10782 return FALSE;
10783
10784 /* MPEG-A stereo video */
10785 if (qtdemux->major_brand == FOURCC_ss02)
10786 flags |= GST_VIDEO_MULTIVIEW_FLAGS_MIXED_MONO;
10787
10788 frame_type = QT_UINT8 ((guint8 *) svmi->data + 12);
10789 frame_layout = QT_UINT8 ((guint8 *) svmi->data + 13) & 0x01;
10790 stereo_mono_change_count = QT_UINT32 ((guint8 *) svmi->data + 14);
10791
10792 switch (frame_type) {
10793 case 0:
10794 mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
10795 break;
10796 case 1:
10797 mode = GST_VIDEO_MULTIVIEW_MODE_ROW_INTERLEAVED;
10798 break;
10799 case 2:
10800 mode = GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME;
10801 break;
10802 case 3:
10803 /* mode 3 is primary/secondary view sequence, ie
10804 * left/right views in separate tracks. See section 7.2
10805 * of ISO/IEC 23000-11:2009 */
10806 /* In the future this might be supported using related
10807 * streams, like an enhancement track - if files like this
10808 * ever exist */
10809 GST_FIXME_OBJECT (qtdemux,
10810 "Implement stereo video in separate streams");
10811 }
10812
10813 if ((frame_layout & 0x1) == 0)
10814 flags |= GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
10815
10816 GST_LOG_OBJECT (qtdemux,
10817 "StereoVideo: composition type: %u, is_left_first: %u",
10818 frame_type, frame_layout);
10819
10820 if (stereo_mono_change_count > 1) {
10821 GST_FIXME_OBJECT (qtdemux,
10822 "Mixed-mono flags are not yet supported in qtdemux.");
10823 }
10824
10825 stream->multiview_mode = mode;
10826 stream->multiview_flags = flags;
10827 }
10828 }
10829
10830 return TRUE;
10831}
10832
10833/* parse the traks.
10834 * With each track we associate a new QtDemuxStream that contains all the info
10835 * about the trak.
10836 * traks that do not decode to something (like strm traks) will not have a pad.
10837 */
10838static gboolean
10839qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
10840{
10841 GstByteReader tkhd;
10842 int offset;
10843 GNode *mdia;
10844 GNode *mdhd;
10845 GNode *hdlr;
10846 GNode *minf;
10847 GNode *stbl;
10848 GNode *stsd;
10849 GNode *mp4a;
10850 GNode *mp4v;
10851 GNode *esds;
10852 GNode *tref;
10853 GNode *udta;
10854
10855 QtDemuxStream *stream = NULL;
10856 const guint8 *stsd_data;
10857 const guint8 *stsd_entry_data;
10858 guint remaining_stsd_len;
10859 guint stsd_entry_count;
10860 guint stsd_index;
10861 guint16 lang_code; /* quicktime lang code or packed iso code */
10862 guint32 version;
10863 guint32 tkhd_flags = 0;
10864 guint8 tkhd_version = 0;
10865 guint32 w = 0, h = 0;
10866 guint value_size, stsd_len, len;
10867 guint32 track_id;
10868 guint32 dummy;
10869
10870 GST_DEBUG_OBJECT (qtdemux, "parse_trak");
10871
10872 if (!qtdemux_tree_get_child_by_type_full (trak, FOURCC_tkhd, &tkhd)
10873 || !gst_byte_reader_get_uint8 (&tkhd, &tkhd_version)
10874 || !gst_byte_reader_get_uint24_be (&tkhd, &tkhd_flags))
10875 goto corrupt_file;
10876
10877 /* pick between 64 or 32 bits */
10878 value_size = tkhd_version == 1 ? 8 : 4;
10879 if (!gst_byte_reader_skip (&tkhd, value_size * 2) ||
10880 !gst_byte_reader_get_uint32_be (&tkhd, &track_id))
10881 goto corrupt_file;
10882
10883 /* Check if current moov has duplicated track_id */
10884 if (qtdemux_find_stream (qtdemux, track_id))
10885 goto existing_stream;
10886
10887 stream = _create_stream (qtdemux, track_id);
10888 stream->stream_tags = gst_tag_list_make_writable (stream->stream_tags);
10889
10890 /* need defaults for fragments */
10891 qtdemux_parse_trex (qtdemux, stream, &dummy, &dummy, &dummy);
10892
10893 if ((tkhd_flags & 1) == 0)
10894 stream->disabled = TRUE;
10895
10896 GST_LOG_OBJECT (qtdemux, "track[tkhd] version/flags/id: 0x%02x/%06x/%u",
10897 tkhd_version, tkhd_flags, stream->track_id);
10898
10899 if (!(mdia = qtdemux_tree_get_child_by_type (trak, FOURCC_mdia)))
10900 goto corrupt_file;
10901
10902 if (!(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mdhd))) {
10903 /* be nice for some crooked mjp2 files that use mhdr for mdhd */
10904 if (qtdemux->major_brand != FOURCC_mjp2 ||
10905 !(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mhdr)))
10906 goto corrupt_file;
10907 }
10908
10909 len = QT_UINT32 ((guint8 *) mdhd->data);
10910 version = QT_UINT32 ((guint8 *) mdhd->data + 8);
10911 GST_LOG_OBJECT (qtdemux, "track version/flags: %08x", version);
10912 if (version == 0x01000000) {
10913 if (len < 42)
10914 goto corrupt_file;
10915 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 28);
10916 stream->duration = QT_UINT64 ((guint8 *) mdhd->data + 32);
10917 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 40);
10918 } else {
10919 if (len < 30)
10920 goto corrupt_file;
10921 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 20);
10922 stream->duration = QT_UINT32 ((guint8 *) mdhd->data + 24);
10923 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 28);
10924 }
10925
10926 if (lang_code < 0x400) {
10927 qtdemux_lang_map_qt_code_to_iso (stream->lang_id, lang_code);
10928 } else if (lang_code == 0x7fff) {
10929 stream->lang_id[0] = 0; /* unspecified */
10930 } else {
10931 stream->lang_id[0] = 0x60 + ((lang_code >> 10) & 0x1F);
10932 stream->lang_id[1] = 0x60 + ((lang_code >> 5) & 0x1F);
10933 stream->lang_id[2] = 0x60 + (lang_code & 0x1F);
10934 stream->lang_id[3] = 0;
10935 }
10936
10937 GST_LOG_OBJECT (qtdemux, "track timescale: %" G_GUINT32_FORMAT,
10938 stream->timescale);
10939 GST_LOG_OBJECT (qtdemux, "track duration: %" G_GUINT64_FORMAT,
10940 stream->duration);
10941 GST_LOG_OBJECT (qtdemux, "track language code/id: 0x%04x/%s",
10942 lang_code, stream->lang_id);
10943
10944 if (G_UNLIKELY (stream->timescale == 0 || qtdemux->timescale == 0))
10945 goto corrupt_file;
10946
10947 if ((tref = qtdemux_tree_get_child_by_type (trak, FOURCC_tref))) {
10948 /* chapters track reference */
10949 GNode *chap = qtdemux_tree_get_child_by_type (tref, FOURCC_chap);
10950 if (chap) {
10951 gsize length = GST_READ_UINT32_BE (chap->data);
10952 if (qtdemux->chapters_track_id)
10953 GST_FIXME_OBJECT (qtdemux, "Multiple CHAP tracks");
10954
10955 if (length >= 12) {
10956 qtdemux->chapters_track_id =
10957 GST_READ_UINT32_BE ((gint8 *) chap->data + 8);
10958 }
10959 }
10960 }
10961
10962 /* fragmented files may have bogus duration in moov */
10963 if (!qtdemux->fragmented &&
10964 qtdemux->duration != G_MAXINT64 && stream->duration != G_MAXINT32) {
10965 guint64 tdur1, tdur2;
10966
10967 /* don't overflow */
10968 tdur1 = stream->timescale * (guint64) qtdemux->duration;
10969 tdur2 = qtdemux->timescale * (guint64) stream->duration;
10970
10971 /* HACK:
10972 * some of those trailers, nowadays, have prologue images that are
10973 * themselves video tracks as well. I haven't really found a way to
10974 * identify those yet, except for just looking at their duration. */
10975 if (tdur1 != 0 && (tdur2 * 10 / tdur1) < 2) {
10976 GST_WARNING_OBJECT (qtdemux,
10977 "Track shorter than 20%% (%" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT
10978 " vs. %" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT ") of the stream "
10979 "found, assuming preview image or something; skipping track",
10980 stream->duration, stream->timescale, qtdemux->duration,
10981 qtdemux->timescale);
10982 gst_qtdemux_stream_unref (stream);
10983 return TRUE;
10984 }
10985 }
10986
10987 if (!(hdlr = qtdemux_tree_get_child_by_type (mdia, FOURCC_hdlr)))
10988 goto corrupt_file;
10989
10990 GST_LOG_OBJECT (qtdemux, "track type: %" GST_FOURCC_FORMAT,
10991 GST_FOURCC_ARGS (QT_FOURCC ((guint8 *) hdlr->data + 12)));
10992
10993 len = QT_UINT32 ((guint8 *) hdlr->data);
10994 if (len >= 20)
10995 stream->subtype = QT_FOURCC ((guint8 *) hdlr->data + 16);
10996 GST_LOG_OBJECT (qtdemux, "track subtype: %" GST_FOURCC_FORMAT,
10997 GST_FOURCC_ARGS (stream->subtype));
10998
10999 if (!(minf = qtdemux_tree_get_child_by_type (mdia, FOURCC_minf)))
11000 goto corrupt_file;
11001
11002 if (!(stbl = qtdemux_tree_get_child_by_type (minf, FOURCC_stbl)))
11003 goto corrupt_file;
11004
11005 /* Parse out svmi (and later st3d/sv3d) atoms */
11006 if (!qtdemux_parse_stereo_svmi_atom (qtdemux, stream, stbl))
11007 goto corrupt_file;
11008
11009 /* parse rest of tkhd */
11010 if (stream->subtype == FOURCC_vide) {
11011 guint32 matrix[9];
11012
11013 /* version 1 uses some 64-bit ints */
11014 if (!gst_byte_reader_skip (&tkhd, 20 + value_size))
11015 goto corrupt_file;
11016
11017 if (!qtdemux_parse_transformation_matrix (qtdemux, &tkhd, matrix, "tkhd"))
11018 goto corrupt_file;
11019
11020 if (!gst_byte_reader_get_uint32_be (&tkhd, &w)
11021 || !gst_byte_reader_get_uint32_be (&tkhd, &h))
11022 goto corrupt_file;
11023
11024 qtdemux_inspect_transformation_matrix (qtdemux, stream, matrix,
11025 &stream->stream_tags);
11026 }
11027
11028 /* parse stsd */
11029 if (!(stsd = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsd)))
11030 goto corrupt_file;
11031 stsd_data = (const guint8 *) stsd->data;
11032
11033 /* stsd should at least have one entry */
11034 stsd_len = QT_UINT32 (stsd_data);
11035 if (stsd_len < 24) {
11036 /* .. but skip stream with empty stsd produced by some Vivotek cameras */
11037 if (stream->subtype == FOURCC_vivo) {
11038 gst_qtdemux_stream_unref (stream);
11039 return TRUE;
11040 } else {
11041 goto corrupt_file;
11042 }
11043 }
11044
11045 stream->stsd_entries_length = stsd_entry_count = QT_UINT32 (stsd_data + 12);
11046 /* each stsd entry must contain at least 8 bytes */
11047 if (stream->stsd_entries_length == 0
11048 || stream->stsd_entries_length > stsd_len / 8) {
11049 stream->stsd_entries_length = 0;
11050 goto corrupt_file;
11051 }
11052 stream->stsd_entries = g_new0 (QtDemuxStreamStsdEntry, stsd_entry_count);
11053 GST_LOG_OBJECT (qtdemux, "stsd len: %d", stsd_len);
11054 GST_LOG_OBJECT (qtdemux, "stsd entry count: %u", stsd_entry_count);
11055
11056 stsd_entry_data = stsd_data + 16;
11057 remaining_stsd_len = stsd_len - 16;
11058 for (stsd_index = 0; stsd_index < stsd_entry_count; stsd_index++) {
11059 guint32 fourcc;
11060 gchar *codec = NULL;
11061 QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[stsd_index];
11062
11063 /* and that entry should fit within stsd */
11064 len = QT_UINT32 (stsd_entry_data);
11065 if (len > remaining_stsd_len)
11066 goto corrupt_file;
11067
11068 entry->fourcc = fourcc = QT_FOURCC (stsd_entry_data + 4);
11069 GST_LOG_OBJECT (qtdemux, "stsd type: %" GST_FOURCC_FORMAT,
11070 GST_FOURCC_ARGS (entry->fourcc));
11071 GST_LOG_OBJECT (qtdemux, "stsd type len: %d", len);
11072
11073 if ((fourcc == FOURCC_drms) || (fourcc == FOURCC_drmi))
11074 goto error_encrypted;
11075
11076 if (fourcc == FOURCC_aavd) {
11077 if (stream->subtype != FOURCC_soun) {
11078 GST_ERROR_OBJECT (qtdemux,
11079 "Unexpeced stsd type 'aavd' outside 'soun' track");
11080 } else {
11081 /* encrypted audio with sound sample description v0 */
11082 GNode *enc = qtdemux_tree_get_child_by_type (stsd, fourcc);
11083 stream->protected = TRUE;
11084 if (!qtdemux_parse_protection_aavd (qtdemux, stream, enc, &fourcc))
11085 GST_ERROR_OBJECT (qtdemux, "Failed to parse protection scheme info");
11086 }
11087 }
11088
11089 if (fourcc == FOURCC_encv || fourcc == FOURCC_enca) {
11090 /* FIXME this looks wrong, there might be multiple children
11091 * with the same type */
11092 GNode *enc = qtdemux_tree_get_child_by_type (stsd, fourcc);
11093 stream->protected = TRUE;
11094 if (!qtdemux_parse_protection_scheme_info (qtdemux, stream, enc, &fourcc))
11095 GST_ERROR_OBJECT (qtdemux, "Failed to parse protection scheme info");
11096 }
11097
11098 if (stream->subtype == FOURCC_vide) {
11099 GNode *colr;
11100 GNode *fiel;
11101 GNode *pasp;
11102 gboolean gray;
11103 gint depth, palette_size, palette_count;
11104 guint32 *palette_data = NULL;
11105
11106 entry->sampled = TRUE;
11107
11108 stream->display_width = w >> 16;
11109 stream->display_height = h >> 16;
11110
11111 offset = 16;
11112 if (len < 86) /* TODO verify */
11113 goto corrupt_file;
11114
11115 entry->width = QT_UINT16 (stsd_entry_data + offset + 16);
11116 entry->height = QT_UINT16 (stsd_entry_data + offset + 18);
11117 entry->fps_n = 0; /* this is filled in later */
11118 entry->fps_d = 0; /* this is filled in later */
11119 entry->bits_per_sample = QT_UINT16 (stsd_entry_data + offset + 66);
11120 entry->color_table_id = QT_UINT16 (stsd_entry_data + offset + 68);
11121
11122 /* if color_table_id is 0, ctab atom must follow; however some files
11123 * produced by TMPEGEnc have color_table_id = 0 and no ctab atom, so
11124 * if color table is not present we'll correct the value */
11125 if (entry->color_table_id == 0 &&
11126 (len < 90
11127 || QT_FOURCC (stsd_entry_data + offset + 70) != FOURCC_ctab)) {
11128 entry->color_table_id = -1;
11129 }
11130
11131 GST_LOG_OBJECT (qtdemux, "width %d, height %d, bps %d, color table id %d",
11132 entry->width, entry->height, entry->bits_per_sample,
11133 entry->color_table_id);
11134
11135 depth = entry->bits_per_sample;
11136
11137 /* more than 32 bits means grayscale */
11138 gray = (depth > 32);
11139 /* low 32 bits specify the depth */
11140 depth &= 0x1F;
11141
11142 /* different number of palette entries is determined by depth. */
11143 palette_count = 0;
11144 if ((depth == 1) || (depth == 2) || (depth == 4) || (depth == 8))
11145 palette_count = (1 << depth);
11146 palette_size = palette_count * 4;
11147
11148 if (entry->color_table_id) {
11149 switch (palette_count) {
11150 case 0:
11151 break;
11152 case 2:
11153 palette_data = g_memdup2 (ff_qt_default_palette_2, palette_size);
11154 break;
11155 case 4:
11156 palette_data = g_memdup2 (ff_qt_default_palette_4, palette_size);
11157 break;
11158 case 16:
11159 if (gray)
11160 palette_data =
11161 g_memdup2 (ff_qt_grayscale_palette_16, palette_size);
11162 else
11163 palette_data = g_memdup2 (ff_qt_default_palette_16, palette_size);
11164 break;
11165 case 256:
11166 if (gray)
11167 palette_data =
11168 g_memdup2 (ff_qt_grayscale_palette_256, palette_size);
11169 else
11170 palette_data =
11171 g_memdup2 (ff_qt_default_palette_256, palette_size);
11172 break;
11173 default:
11174 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
11175 (_("The video in this file might not play correctly.")),
11176 ("unsupported palette depth %d", depth));
11177 break;
11178 }
11179 } else {
11180 guint i, j, start, end;
11181
11182 if (len < 94)
11183 goto corrupt_file;
11184
11185 /* read table */
11186 start = QT_UINT32 (stsd_entry_data + offset + 70);
11187 palette_count = QT_UINT16 (stsd_entry_data + offset + 74);
11188 end = QT_UINT16 (stsd_entry_data + offset + 76);
11189
11190 GST_LOG_OBJECT (qtdemux, "start %d, end %d, palette_count %d",
11191 start, end, palette_count);
11192
11193 if (end > 255)
11194 end = 255;
11195 if (start > end)
11196 start = end;
11197
11198 if (len < 94 + (end - start) * 8)
11199 goto corrupt_file;
11200
11201 /* palette is always the same size */
11202 palette_data = g_malloc0 (256 * 4);
11203 palette_size = 256 * 4;
11204
11205 for (j = 0, i = start; i <= end; j++, i++) {
11206 guint32 a, r, g, b;
11207
11208 a = QT_UINT16 (stsd_entry_data + offset + 78 + (j * 8));
11209 r = QT_UINT16 (stsd_entry_data + offset + 80 + (j * 8));
11210 g = QT_UINT16 (stsd_entry_data + offset + 82 + (j * 8));
11211 b = QT_UINT16 (stsd_entry_data + offset + 84 + (j * 8));
11212
11213 palette_data[i] = ((a & 0xff00) << 16) | ((r & 0xff00) << 8) |
11214 (g & 0xff00) | (b >> 8);
11215 }
11216 }
11217
11218 if (entry->caps)
11219 gst_caps_unref (entry->caps);
11220
11221 entry->caps =
11222 qtdemux_video_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
11223 &codec);
11224 if (G_UNLIKELY (!entry->caps)) {
11225 g_free (palette_data);
11226 goto unknown_stream;
11227 }
11228
11229 if (codec) {
11230 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11231 GST_TAG_VIDEO_CODEC, codec, NULL);
11232 g_free (codec);
11233 codec = NULL;
11234 }
11235
11236 if (palette_data) {
11237 GstStructure *s;
11238
11239 if (entry->rgb8_palette)
11240 gst_memory_unref (entry->rgb8_palette);
11241 entry->rgb8_palette = gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY,
11242 palette_data, palette_size, 0, palette_size, palette_data, g_free);
11243
11244 s = gst_caps_get_structure (entry->caps, 0);
11245
11246 /* non-raw video has a palette_data property. raw video has the palette as
11247 * an extra plane that we append to the output buffers before we push
11248 * them*/
11249 if (!gst_structure_has_name (s, "video/x-raw")) {
11250 GstBuffer *palette;
11251
11252 palette = gst_buffer_new ();
11253 gst_buffer_append_memory (palette, entry->rgb8_palette);
11254 entry->rgb8_palette = NULL;
11255
11256 gst_caps_set_simple (entry->caps, "palette_data",
11257 GST_TYPE_BUFFER, palette, NULL);
11258 gst_buffer_unref (palette);
11259 }
11260 } else if (palette_count != 0) {
11261 GST_ELEMENT_WARNING (qtdemux, STREAM, NOT_IMPLEMENTED,
11262 (NULL), ("Unsupported palette depth %d", depth));
11263 }
11264
11265 GST_LOG_OBJECT (qtdemux, "frame count: %u",
11266 QT_UINT16 (stsd_entry_data + offset + 32));
11267
11268 esds = NULL;
11269 pasp = NULL;
11270 colr = NULL;
11271 fiel = NULL;
11272 /* pick 'the' stsd child */
11273 mp4v = qtdemux_tree_get_child_by_index (stsd, stsd_index);
11274 // We should skip parsing the stsd for non-protected streams if
11275 // the entry doesn't match the fourcc, since they don't change
11276 // format. However, for protected streams we can have partial
11277 // encryption, where parts of the stream are encrypted and parts
11278 // not. For both parts of such streams, we should ensure the
11279 // esds overrides are parsed for both from the stsd.
11280 if (QTDEMUX_TREE_NODE_FOURCC (mp4v) != fourcc) {
11281 if (stream->protected && QTDEMUX_TREE_NODE_FOURCC (mp4v) != FOURCC_encv)
11282 mp4v = NULL;
11283 else if (!stream->protected)
11284 mp4v = NULL;
11285 }
11286
11287 if (mp4v) {
11288 esds = qtdemux_tree_get_child_by_type (mp4v, FOURCC_esds);
11289 pasp = qtdemux_tree_get_child_by_type (mp4v, FOURCC_pasp);
11290 colr = qtdemux_tree_get_child_by_type (mp4v, FOURCC_colr);
11291 fiel = qtdemux_tree_get_child_by_type (mp4v, FOURCC_fiel);
11292 }
11293
11294 if (pasp) {
11295 const guint8 *pasp_data = (const guint8 *) pasp->data;
11296 guint len = QT_UINT32 (pasp_data);
11297
11298 if (len == 16) {
11299 CUR_STREAM (stream)->par_w = QT_UINT32 (pasp_data + 8);
11300 CUR_STREAM (stream)->par_h = QT_UINT32 (pasp_data + 12);
11301 } else {
11302 CUR_STREAM (stream)->par_w = 0;
11303 CUR_STREAM (stream)->par_h = 0;
11304 }
11305 } else {
11306 CUR_STREAM (stream)->par_w = 0;
11307 CUR_STREAM (stream)->par_h = 0;
11308 }
11309
11310 if (fiel) {
11311 const guint8 *fiel_data = (const guint8 *) fiel->data;
11312 guint len = QT_UINT32 (fiel_data);
11313
11314 if (len == 10) {
11315 CUR_STREAM (stream)->interlace_mode = GST_READ_UINT8 (fiel_data + 8);
11316 CUR_STREAM (stream)->field_order = GST_READ_UINT8 (fiel_data + 9);
11317 }
11318 }
11319
11320 if (colr) {
11321 const guint8 *colr_data = (const guint8 *) colr->data;
11322 guint len = QT_UINT32 (colr_data);
11323
11324 if (len == 19 || len == 18) {
11325 guint32 color_type = GST_READ_UINT32_LE (colr_data + 8);
11326
11327 if (color_type == FOURCC_nclx || color_type == FOURCC_nclc) {
11328 guint16 primaries = GST_READ_UINT16_BE (colr_data + 12);
11329 guint16 transfer_function = GST_READ_UINT16_BE (colr_data + 14);
11330 guint16 matrix = GST_READ_UINT16_BE (colr_data + 16);
11331 gboolean full_range = len == 19 ? colr_data[17] >> 7 : FALSE;
11332
11333 CUR_STREAM (stream)->colorimetry.primaries =
11334 gst_video_color_primaries_from_iso (primaries);
11335 CUR_STREAM (stream)->colorimetry.transfer =
11336 gst_video_transfer_function_from_iso (transfer_function);
11337 CUR_STREAM (stream)->colorimetry.matrix =
11338 gst_video_color_matrix_from_iso (matrix);
11339 CUR_STREAM (stream)->colorimetry.range =
11340 full_range ? GST_VIDEO_COLOR_RANGE_0_255 :
11341 GST_VIDEO_COLOR_RANGE_16_235;
11342 } else {
11343 GST_DEBUG_OBJECT (qtdemux, "Unsupported color type");
11344 }
11345 } else {
11346 GST_WARNING_OBJECT (qtdemux, "Invalid colr atom size");
11347 }
11348 }
11349
11350 if (esds) {
11351 gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
11352 stream->stream_tags);
11353 } else {
11354 switch (fourcc) {
11355 case FOURCC_H264:
11356 case FOURCC_avc1:
11357 case FOURCC_avc3:
11358 {
11359 guint len = QT_UINT32 (stsd_entry_data);
11360 len = len <= 0x56 ? 0 : len - 0x56;
11361 const guint8 *avc_data = stsd_entry_data + 0x56;
11362
11363 /* find avcC */
11364 while (len >= 0x8) {
11365 guint size;
11366
11367 if (QT_UINT32 (avc_data) <= 0x8)
11368 size = 0;
11369 else if (QT_UINT32 (avc_data) <= len)
11370 size = QT_UINT32 (avc_data) - 0x8;
11371 else
11372 size = len - 0x8;
11373
11374 if (size < 1)
11375 /* No real data, so break out */
11376 break;
11377
11378 switch (QT_FOURCC (avc_data + 0x4)) {
11379 case FOURCC_avcC:
11380 {
11381 /* parse, if found */
11382 GstBuffer *buf;
11383
11384 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
11385
11386 /* First 4 bytes are the length of the atom, the next 4 bytes
11387 * are the fourcc, the next 1 byte is the version, and the
11388 * subsequent bytes are profile_tier_level structure like data. */
11389 gst_codec_utils_h264_caps_set_level_and_profile (entry->caps,
11390 avc_data + 8 + 1, size - 1);
11391 buf = gst_buffer_new_and_alloc (size);
11392 gst_buffer_fill (buf, 0, avc_data + 0x8, size);
11393 gst_caps_set_simple (entry->caps,
11394 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11395 gst_buffer_unref (buf);
11396
11397 break;
11398 }
11399 case FOURCC_strf:
11400 {
11401 GstBuffer *buf;
11402
11403 GST_DEBUG_OBJECT (qtdemux, "found strf codec_data in stsd");
11404
11405 /* First 4 bytes are the length of the atom, the next 4 bytes
11406 * are the fourcc, next 40 bytes are BITMAPINFOHEADER,
11407 * next 1 byte is the version, and the
11408 * subsequent bytes are sequence parameter set like data. */
11409
11410 size -= 40; /* we'll be skipping BITMAPINFOHEADER */
11411 if (size > 1) {
11412 gst_codec_utils_h264_caps_set_level_and_profile
11413 (entry->caps, avc_data + 8 + 40 + 1, size - 1);
11414
11415 buf = gst_buffer_new_and_alloc (size);
11416 gst_buffer_fill (buf, 0, avc_data + 8 + 40, size);
11417 gst_caps_set_simple (entry->caps,
11418 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11419 gst_buffer_unref (buf);
11420 }
11421 break;
11422 }
11423 case FOURCC_btrt:
11424 {
11425 guint avg_bitrate, max_bitrate;
11426
11427 /* bufferSizeDB, maxBitrate and avgBitrate - 4 bytes each */
11428 if (size < 12)
11429 break;
11430
11431 max_bitrate = QT_UINT32 (avc_data + 0xc);
11432 avg_bitrate = QT_UINT32 (avc_data + 0x10);
11433
11434 if (!max_bitrate && !avg_bitrate)
11435 break;
11436
11437 /* Some muxers seem to swap the average and maximum bitrates
11438 * (I'm looking at you, YouTube), so we swap for sanity. */
11439 if (max_bitrate > 0 && max_bitrate < avg_bitrate) {
11440 guint temp = avg_bitrate;
11441
11442 avg_bitrate = max_bitrate;
11443 max_bitrate = temp;
11444 }
11445
11446 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
11447 gst_tag_list_add (stream->stream_tags,
11448 GST_TAG_MERGE_REPLACE, GST_TAG_MAXIMUM_BITRATE,
11449 max_bitrate, NULL);
11450 }
11451 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
11452 gst_tag_list_add (stream->stream_tags,
11453 GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE, avg_bitrate,
11454 NULL);
11455 }
11456
11457 break;
11458 }
11459
11460 default:
11461 break;
11462 }
11463
11464 len -= size + 8;
11465 avc_data += size + 8;
11466 }
11467
11468 break;
11469 }
11470 case FOURCC_H265:
11471 case FOURCC_hvc1:
11472 case FOURCC_hev1:
11473 case FOURCC_dvh1:
11474 case FOURCC_dvhe:
11475 {
11476 guint len = QT_UINT32 (stsd_entry_data);
11477 len = len <= 0x56 ? 0 : len - 0x56;
11478 const guint8 *hevc_data = stsd_entry_data + 0x56;
11479
11480 /* find hevc */
11481 while (len >= 0x8) {
11482 guint size;
11483
11484 if (QT_UINT32 (hevc_data) <= 0x8)
11485 size = 0;
11486 else if (QT_UINT32 (hevc_data) <= len)
11487 size = QT_UINT32 (hevc_data) - 0x8;
11488 else
11489 size = len - 0x8;
11490
11491 if (size < 1)
11492 /* No real data, so break out */
11493 break;
11494
11495 switch (QT_FOURCC (hevc_data + 0x4)) {
11496 case FOURCC_hvcC:
11497 {
11498 /* parse, if found */
11499 GstBuffer *buf;
11500
11501 GST_DEBUG_OBJECT (qtdemux, "found hvcC codec_data in stsd");
11502
11503 /* First 4 bytes are the length of the atom, the next 4 bytes
11504 * are the fourcc, the next 1 byte is the version, and the
11505 * subsequent bytes are sequence parameter set like data. */
11506 gst_codec_utils_h265_caps_set_level_tier_and_profile
11507 (entry->caps, hevc_data + 8 + 1, size - 1);
11508
11509 buf = gst_buffer_new_and_alloc (size);
11510 gst_buffer_fill (buf, 0, hevc_data + 0x8, size);
11511 gst_caps_set_simple (entry->caps,
11512 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11513 gst_buffer_unref (buf);
11514 break;
11515 }
11516 default:
11517 break;
11518 }
11519 len -= size + 8;
11520 hevc_data += size + 8;
11521 }
11522 break;
11523 }
11524 case FOURCC_mp4v:
11525 case FOURCC_MP4V:
11526 case FOURCC_fmp4:
11527 case FOURCC_FMP4:
11528 case FOURCC_xvid:
11529 case FOURCC_XVID:
11530 {
11531 GNode *glbl;
11532
11533 GST_DEBUG_OBJECT (qtdemux, "found %" GST_FOURCC_FORMAT,
11534 GST_FOURCC_ARGS (fourcc));
11535
11536 /* codec data might be in glbl extension atom */
11537 glbl = mp4v ?
11538 qtdemux_tree_get_child_by_type (mp4v, FOURCC_glbl) : NULL;
11539 if (glbl) {
11540 guint8 *data;
11541 GstBuffer *buf;
11542 guint len;
11543
11544 GST_DEBUG_OBJECT (qtdemux, "found glbl data in stsd");
11545 data = glbl->data;
11546 len = QT_UINT32 (data);
11547 if (len > 0x8) {
11548 len -= 0x8;
11549 buf = gst_buffer_new_and_alloc (len);
11550 gst_buffer_fill (buf, 0, data + 8, len);
11551 gst_caps_set_simple (entry->caps,
11552 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11553 gst_buffer_unref (buf);
11554 }
11555 }
11556 break;
11557 }
11558 case FOURCC_mjp2:
11559 {
11560 /* see annex I of the jpeg2000 spec */
11561 GNode *jp2h, *ihdr, *colr, *mjp2, *field, *prefix, *cmap, *cdef;
11562 const guint8 *data;
11563 const gchar *colorspace = NULL;
11564 gint ncomp = 0;
11565 guint32 ncomp_map = 0;
11566 gint32 *comp_map = NULL;
11567 guint32 nchan_def = 0;
11568 gint32 *chan_def = NULL;
11569
11570 GST_DEBUG_OBJECT (qtdemux, "found mjp2");
11571 /* some required atoms */
11572 mjp2 = qtdemux_tree_get_child_by_index (stsd, stsd_index);
11573 if (!mjp2)
11574 break;
11575 jp2h = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2h);
11576 if (!jp2h)
11577 break;
11578
11579 /* number of components; redundant with info in codestream, but useful
11580 to a muxer */
11581 ihdr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_ihdr);
11582 if (!ihdr || QT_UINT32 (ihdr->data) != 22)
11583 break;
11584 ncomp = QT_UINT16 (((guint8 *) ihdr->data) + 16);
11585
11586 colr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_colr);
11587 if (!colr)
11588 break;
11589 GST_DEBUG_OBJECT (qtdemux, "found colr");
11590 /* extract colour space info */
11591 if (QT_UINT8 ((guint8 *) colr->data + 8) == 1) {
11592 switch (QT_UINT32 ((guint8 *) colr->data + 11)) {
11593 case 16:
11594 colorspace = "sRGB";
11595 break;
11596 case 17:
11597 colorspace = "GRAY";
11598 break;
11599 case 18:
11600 colorspace = "sYUV";
11601 break;
11602 default:
11603 colorspace = NULL;
11604 break;
11605 }
11606 }
11607 if (!colorspace)
11608 /* colr is required, and only values 16, 17, and 18 are specified,
11609 so error if we have no colorspace */
11610 break;
11611
11612 /* extract component mapping */
11613 cmap = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cmap);
11614 if (cmap) {
11615 guint32 cmap_len = 0;
11616 int i;
11617 cmap_len = QT_UINT32 (cmap->data);
11618 if (cmap_len >= 8) {
11619 /* normal box, subtract off header */
11620 cmap_len -= 8;
11621 /* cmap: { u16 cmp; u8 mtyp; u8 pcol; }* */
11622 if (cmap_len % 4 == 0) {
11623 ncomp_map = (cmap_len / 4);
11624 comp_map = g_new0 (gint32, ncomp_map);
11625 for (i = 0; i < ncomp_map; i++) {
11626 guint16 cmp;
11627 guint8 mtyp, pcol;
11628 cmp = QT_UINT16 (((guint8 *) cmap->data) + 8 + i * 4);
11629 mtyp = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 2);
11630 pcol = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 3);
11631 comp_map[i] = (mtyp << 24) | (pcol << 16) | cmp;
11632 }
11633 }
11634 }
11635 }
11636 /* extract channel definitions */
11637 cdef = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cdef);
11638 if (cdef) {
11639 guint32 cdef_len = 0;
11640 int i;
11641 cdef_len = QT_UINT32 (cdef->data);
11642 if (cdef_len >= 10) {
11643 /* normal box, subtract off header and len */
11644 cdef_len -= 10;
11645 /* cdef: u16 n; { u16 cn; u16 typ; u16 asoc; }* */
11646 if (cdef_len % 6 == 0) {
11647 nchan_def = (cdef_len / 6);
11648 chan_def = g_new0 (gint32, nchan_def);
11649 for (i = 0; i < nchan_def; i++)
11650 chan_def[i] = -1;
11651 for (i = 0; i < nchan_def; i++) {
11652 guint16 cn, typ, asoc;
11653 cn = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6);
11654 typ = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 2);
11655 asoc = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 4);
11656 if (cn < nchan_def) {
11657 switch (typ) {
11658 case 0:
11659 chan_def[cn] = asoc;
11660 break;
11661 case 1:
11662 chan_def[cn] = 0; /* alpha */
11663 break;
11664 default:
11665 chan_def[cn] = -typ;
11666 }
11667 }
11668 }
11669 }
11670 }
11671 }
11672
11673 gst_caps_set_simple (entry->caps,
11674 "num-components", G_TYPE_INT, ncomp, NULL);
11675 gst_caps_set_simple (entry->caps,
11676 "colorspace", G_TYPE_STRING, colorspace, NULL);
11677
11678 if (comp_map) {
11679 GValue arr = { 0, };
11680 GValue elt = { 0, };
11681 int i;
11682 g_value_init (&arr, GST_TYPE_ARRAY);
11683 g_value_init (&elt, G_TYPE_INT);
11684 for (i = 0; i < ncomp_map; i++) {
11685 g_value_set_int (&elt, comp_map[i]);
11686 gst_value_array_append_value (&arr, &elt);
11687 }
11688 gst_structure_set_value (gst_caps_get_structure (entry->caps, 0),
11689 "component-map", &arr);
11690 g_value_unset (&elt);
11691 g_value_unset (&arr);
11692 g_free (comp_map);
11693 }
11694
11695 if (chan_def) {
11696 GValue arr = { 0, };
11697 GValue elt = { 0, };
11698 int i;
11699 g_value_init (&arr, GST_TYPE_ARRAY);
11700 g_value_init (&elt, G_TYPE_INT);
11701 for (i = 0; i < nchan_def; i++) {
11702 g_value_set_int (&elt, chan_def[i]);
11703 gst_value_array_append_value (&arr, &elt);
11704 }
11705 gst_structure_set_value (gst_caps_get_structure (entry->caps, 0),
11706 "channel-definitions", &arr);
11707 g_value_unset (&elt);
11708 g_value_unset (&arr);
11709 g_free (chan_def);
11710 }
11711
11712 /* some optional atoms */
11713 field = qtdemux_tree_get_child_by_type (mjp2, FOURCC_fiel);
11714 prefix = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2x);
11715
11716 /* indicate possible fields in caps */
11717 if (field) {
11718 data = (guint8 *) field->data + 8;
11719 if (*data != 1)
11720 gst_caps_set_simple (entry->caps, "fields", G_TYPE_INT,
11721 (gint) * data, NULL);
11722 }
11723 /* add codec_data if provided */
11724 if (prefix) {
11725 GstBuffer *buf;
11726 guint len;
11727
11728 GST_DEBUG_OBJECT (qtdemux, "found prefix data in stsd");
11729 data = prefix->data;
11730 len = QT_UINT32 (data);
11731 if (len > 0x8) {
11732 len -= 0x8;
11733 buf = gst_buffer_new_and_alloc (len);
11734 gst_buffer_fill (buf, 0, data + 8, len);
11735 gst_caps_set_simple (entry->caps,
11736 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11737 gst_buffer_unref (buf);
11738 }
11739 }
11740 break;
11741 }
11742 case FOURCC_SVQ3:
11743 case FOURCC_VP31:
11744 {
11745 GstBuffer *buf;
11746 GstBuffer *seqh = NULL;
11747 const guint8 *gamma_data = NULL;
11748 guint len = QT_UINT32 (stsd_data); /* FIXME review - why put the whole stsd in codec data? */
11749
11750 qtdemux_parse_svq3_stsd_data (qtdemux, stsd_entry_data, &gamma_data,
11751 &seqh);
11752 if (gamma_data) {
11753 gst_caps_set_simple (entry->caps, "applied-gamma", G_TYPE_DOUBLE,
11754 QT_FP32 (gamma_data), NULL);
11755 }
11756 if (seqh) {
11757 /* sorry for the bad name, but we don't know what this is, other
11758 * than its own fourcc */
11759 gst_caps_set_simple (entry->caps, "seqh", GST_TYPE_BUFFER, seqh,
11760 NULL);
11761 gst_buffer_unref (seqh);
11762 }
11763
11764 GST_DEBUG_OBJECT (qtdemux, "found codec_data in stsd");
11765 buf = gst_buffer_new_and_alloc (len);
11766 gst_buffer_fill (buf, 0, stsd_data, len);
11767 gst_caps_set_simple (entry->caps,
11768 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11769 gst_buffer_unref (buf);
11770 break;
11771 }
11772 case FOURCC_jpeg:
11773 {
11774 /* https://developer.apple.com/standards/qtff-2001.pdf,
11775 * page 92, "Video Sample Description", under table 3.1 */
11776 GstByteReader br;
11777
11778 const gint compressor_offset =
11779 16 + 4 + 4 * 3 + 2 * 2 + 2 * 4 + 4 + 2;
11780 const gint min_size = compressor_offset + 32 + 2 + 2;
11781 GNode *jpeg;
11782 guint32 len;
11783 guint16 color_table_id = 0;
11784 gboolean ok;
11785
11786 GST_DEBUG_OBJECT (qtdemux, "found jpeg");
11787
11788 /* recover information on interlaced/progressive */
11789 jpeg = qtdemux_tree_get_child_by_type (stsd, FOURCC_jpeg);
11790 if (!jpeg)
11791 break;
11792
11793 len = QT_UINT32 (jpeg->data);
11794 GST_DEBUG_OBJECT (qtdemux, "Found jpeg: len %u, need %d", len,
11795 min_size);
11796 if (len >= min_size) {
11797 gst_byte_reader_init (&br, jpeg->data, len);
11798
11799 gst_byte_reader_skip (&br, compressor_offset + 32 + 2);
11800 gst_byte_reader_get_uint16_le (&br, &color_table_id);
11801 if (color_table_id != 0) {
11802 /* the spec says there can be concatenated chunks in the data, and we want
11803 * to find one called field. Walk through them. */
11804 gint offset = min_size;
11805 while (offset + 8 < len) {
11806 guint32 size = 0, tag;
11807 ok = gst_byte_reader_get_uint32_le (&br, &size);
11808 ok &= gst_byte_reader_get_uint32_le (&br, &tag);
11809 if (!ok || size < 8) {
11810 GST_WARNING_OBJECT (qtdemux,
11811 "Failed to walk optional chunk list");
11812 break;
11813 }
11814 GST_DEBUG_OBJECT (qtdemux,
11815 "Found optional %4.4s chunk, size %u",
11816 (const char *) &tag, size);
11817 if (tag == FOURCC_fiel) {
11818 guint8 n_fields = 0, ordering = 0;
11819 gst_byte_reader_get_uint8 (&br, &n_fields);
11820 gst_byte_reader_get_uint8 (&br, &ordering);
11821 if (n_fields == 1 || n_fields == 2) {
11822 GST_DEBUG_OBJECT (qtdemux,
11823 "Found fiel tag with %u fields, ordering %u",
11824 n_fields, ordering);
11825 if (n_fields == 2)
11826 gst_caps_set_simple (CUR_STREAM (stream)->caps,
11827 "interlace-mode", G_TYPE_STRING, "interleaved",
11828 NULL);
11829 } else {
11830 GST_WARNING_OBJECT (qtdemux,
11831 "Found fiel tag with invalid fields (%u)", n_fields);
11832 }
11833 }
11834 offset += size;
11835 }
11836 } else {
11837 GST_DEBUG_OBJECT (qtdemux,
11838 "Color table ID is 0, not trying to get interlacedness");
11839 }
11840 } else {
11841 GST_WARNING_OBJECT (qtdemux,
11842 "Length of jpeg chunk is too small, not trying to get interlacedness");
11843 }
11844
11845 break;
11846 }
11847 case FOURCC_rle_:
11848 case FOURCC_WRLE:
11849 {
11850 gst_caps_set_simple (entry->caps,
11851 "depth", G_TYPE_INT, QT_UINT16 (stsd_entry_data + offset + 66),
11852 NULL);
11853 break;
11854 }
11855 case FOURCC_XiTh:
11856 {
11857 GNode *xith, *xdxt;
11858
11859 GST_DEBUG_OBJECT (qtdemux, "found XiTh");
11860 xith = qtdemux_tree_get_child_by_index (stsd, stsd_index);
11861 if (!xith)
11862 break;
11863
11864 xdxt = qtdemux_tree_get_child_by_type (xith, FOURCC_XdxT);
11865 if (!xdxt)
11866 break;
11867
11868 GST_DEBUG_OBJECT (qtdemux, "found XdxT node");
11869 /* collect the headers and store them in a stream list so that we can
11870 * send them out first */
11871 qtdemux_parse_theora_extension (qtdemux, stream, xdxt);
11872 break;
11873 }
11874 case FOURCC_ovc1:
11875 {
11876 GNode *ovc1;
11877 guint8 *ovc1_data;
11878 guint ovc1_len;
11879 GstBuffer *buf;
11880
11881 GST_DEBUG_OBJECT (qtdemux, "parse ovc1 header");
11882 ovc1 = qtdemux_tree_get_child_by_index (stsd, stsd_index);
11883 if (!ovc1)
11884 break;
11885 ovc1_data = ovc1->data;
11886 ovc1_len = QT_UINT32 (ovc1_data);
11887 if (ovc1_len <= 198) {
11888 GST_WARNING_OBJECT (qtdemux, "Too small ovc1 header, skipping");
11889 break;
11890 }
11891 buf = gst_buffer_new_and_alloc (ovc1_len - 198);
11892 gst_buffer_fill (buf, 0, ovc1_data + 198, ovc1_len - 198);
11893 gst_caps_set_simple (entry->caps,
11894 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11895 gst_buffer_unref (buf);
11896 break;
11897 }
11898 case FOURCC_vc_1:
11899 {
11900 guint len = QT_UINT32 (stsd_entry_data);
11901 len = len <= 0x56 ? 0 : len - 0x56;
11902 const guint8 *vc1_data = stsd_entry_data + 0x56;
11903
11904 /* find dvc1 */
11905 while (len >= 8) {
11906 guint size;
11907
11908 if (QT_UINT32 (vc1_data) <= 8)
11909 size = 0;
11910 else if (QT_UINT32 (vc1_data) <= len)
11911 size = QT_UINT32 (vc1_data) - 8;
11912 else
11913 size = len - 8;
11914
11915 if (size < 1)
11916 /* No real data, so break out */
11917 break;
11918
11919 switch (QT_FOURCC (vc1_data + 0x4)) {
11920 case GST_MAKE_FOURCC ('d', 'v', 'c', '1'):
11921 {
11922 GstBuffer *buf;
11923
11924 GST_DEBUG_OBJECT (qtdemux, "found dvc1 codec_data in stsd");
11925 buf = gst_buffer_new_and_alloc (size);
11926 gst_buffer_fill (buf, 0, vc1_data + 8, size);
11927 gst_caps_set_simple (entry->caps,
11928 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11929 gst_buffer_unref (buf);
11930 break;
11931 }
11932 default:
11933 break;
11934 }
11935 len -= size + 8;
11936 vc1_data += size + 8;
11937 }
11938 break;
11939 }
11940 case FOURCC_av01:
11941 {
11942 guint len = QT_UINT32 (stsd_entry_data);
11943 len = len <= 0x56 ? 0 : len - 0x56;
11944 const guint8 *av1_data = stsd_entry_data + 0x56;
11945
11946 /* find av1C */
11947 while (len >= 0x8) {
11948 guint size;
11949
11950 if (QT_UINT32 (av1_data) <= 0x8)
11951 size = 0;
11952 else if (QT_UINT32 (av1_data) <= len)
11953 size = QT_UINT32 (av1_data) - 0x8;
11954 else
11955 size = len - 0x8;
11956
11957 if (size < 1)
11958 /* No real data, so break out */
11959 break;
11960
11961 switch (QT_FOURCC (av1_data + 0x4)) {
11962 case FOURCC_av1C:
11963 {
11964 /* parse, if found */
11965 GstBuffer *buf;
11966
11967 GST_DEBUG_OBJECT (qtdemux,
11968 "found av1C codec_data in stsd of size %d", size);
11969
11970 /* not enough data, just ignore and hope for the best */
11971 if (size < 4)
11972 break;
11973
11974 /* Content is:
11975 * 4 bytes: atom length
11976 * 4 bytes: fourcc
11977 *
11978 * version 1 (marker=1):
11979 *
11980 * unsigned int (1) marker = 1;
11981 * unsigned int (7) version = 1;
11982 * unsigned int (3) seq_profile;
11983 * unsigned int (5) seq_level_idx_0;
11984 * unsigned int (1) seq_tier_0;
11985 * unsigned int (1) high_bitdepth;
11986 * unsigned int (1) twelve_bit;
11987 * unsigned int (1) monochrome;
11988 * unsigned int (1) chroma_subsampling_x;
11989 * unsigned int (1) chroma_subsampling_y;
11990 * unsigned int (2) chroma_sample_position;
11991 * unsigned int (3) reserved = 0;
11992 *
11993 * unsigned int (1) initial_presentation_delay_present;
11994 * if (initial_presentation_delay_present) {
11995 * unsigned int (4) initial_presentation_delay_minus_one;
11996 * } else {
11997 * unsigned int (4) reserved = 0;
11998 * }
11999 *
12000 * unsigned int (8) configOBUs[];
12001 *
12002 * rest: OBUs.
12003 */
12004
12005 switch (av1_data[8]) {
12006 case 0x81:{
12007 guint8 pres_delay_field;
12008
12009 /* We let profile and the other parts be figured out by
12010 * av1parse and only include the presentation delay here
12011 * if present */
12012 /* We skip initial_presentation_delay* for now */
12013 pres_delay_field = *(av1_data + 11);
12014 if (pres_delay_field & (1 << 5)) {
12015 gst_caps_set_simple (entry->caps,
12016 "presentation-delay", G_TYPE_INT,
12017 (gint) (pres_delay_field & 0x0F) + 1, NULL);
12018 }
12019
12020 buf = gst_buffer_new_and_alloc (size);
12021 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_HEADER);
12022 gst_buffer_fill (buf, 0, av1_data + 8, size);
12023 gst_caps_set_simple (entry->caps,
12024 "codec_data", GST_TYPE_BUFFER, buf, NULL);
12025 gst_buffer_unref (buf);
12026 break;
12027 }
12028 default:
12029 GST_WARNING ("Unknown version 0x%02x of av1C box",
12030 av1_data[8]);
12031 break;
12032 }
12033
12034 break;
12035 }
12036 default:
12037 break;
12038 }
12039
12040 len -= size + 8;
12041 av1_data += size + 8;
12042 }
12043
12044 break;
12045 }
12046
12047 /* TODO: Need to parse vpcC for VP8 codec too.
12048 * Note that VPCodecConfigurationBox (vpcC) is defined for
12049 * vp08, vp09, and vp10 fourcc. */
12050 case FOURCC_vp09:
12051 {
12052 guint len = QT_UINT32 (stsd_entry_data);
12053 len = len <= 0x56 ? 0 : len - 0x56;
12054 const guint8 *vpcc_data = stsd_entry_data + 0x56;
12055
12056 /* find vpcC */
12057 while (len >= 0x8) {
12058 guint size;
12059
12060 if (QT_UINT32 (vpcc_data) <= 0x8)
12061 size = 0;
12062 else if (QT_UINT32 (vpcc_data) <= len)
12063 size = QT_UINT32 (vpcc_data) - 0x8;
12064 else
12065 size = len - 0x8;
12066
12067 if (size < 1)
12068 /* No real data, so break out */
12069 break;
12070
12071 switch (QT_FOURCC (vpcc_data + 0x4)) {
12072 case FOURCC_vpcC:
12073 {
12074 const gchar *profile_str = NULL;
12075 const gchar *chroma_format_str = NULL;
12076 guint8 profile;
12077 guint8 bitdepth;
12078 guint8 chroma_format;
12079 GstVideoColorimetry cinfo;
12080
12081 /* parse, if found */
12082 GST_DEBUG_OBJECT (qtdemux,
12083 "found vp codec_data in stsd of size %d", size);
12084
12085 /* the meaning of "size" is length of the atom body, excluding
12086 * atom length and fourcc fields */
12087 if (size < 12)
12088 break;
12089
12090 /* Content is:
12091 * 4 bytes: atom length
12092 * 4 bytes: fourcc
12093 * 1 byte: version
12094 * 3 bytes: flags
12095 * 1 byte: profile
12096 * 1 byte: level
12097 * 4 bits: bitDepth
12098 * 3 bits: chromaSubsampling
12099 * 1 bit: videoFullRangeFlag
12100 * 1 byte: colourPrimaries
12101 * 1 byte: transferCharacteristics
12102 * 1 byte: matrixCoefficients
12103 * 2 bytes: codecInitializationDataSize (should be zero for vp8 and vp9)
12104 * rest: codecInitializationData (not used for vp8 and vp9)
12105 */
12106
12107 if (vpcc_data[8] != 1) {
12108 GST_WARNING_OBJECT (qtdemux,
12109 "unknown vpcC version %d", vpcc_data[8]);
12110 break;
12111 }
12112
12113 profile = vpcc_data[12];
12114 switch (profile) {
12115 case 0:
12116 profile_str = "0";
12117 break;
12118 case 1:
12119 profile_str = "1";
12120 break;
12121 case 2:
12122 profile_str = "2";
12123 break;
12124 case 3:
12125 profile_str = "3";
12126 break;
12127 default:
12128 break;
12129 }
12130
12131 if (profile_str) {
12132 gst_caps_set_simple (entry->caps,
12133 "profile", G_TYPE_STRING, profile_str, NULL);
12134 }
12135
12136 /* skip level, the VP9 spec v0.6 defines only one level atm,
12137 * but webm spec define various ones. Add level to caps
12138 * if we really need it then */
12139
12140 bitdepth = (vpcc_data[14] & 0xf0) >> 4;
12141 if (bitdepth == 8 || bitdepth == 10 || bitdepth == 12) {
12142 gst_caps_set_simple (entry->caps,
12143 "bit-depth-luma", G_TYPE_UINT, bitdepth,
12144 "bit-depth-chroma", G_TYPE_UINT, bitdepth, NULL);
12145 }
12146
12147 chroma_format = (vpcc_data[14] & 0xe) >> 1;
12148 switch (chroma_format) {
12149 case 0:
12150 case 1:
12151 chroma_format_str = "4:2:0";
12152 break;
12153 case 2:
12154 chroma_format_str = "4:2:2";
12155 break;
12156 case 3:
12157 chroma_format_str = "4:4:4";
12158 break;
12159 default:
12160 break;
12161 }
12162
12163 if (chroma_format_str) {
12164 gst_caps_set_simple (entry->caps,
12165 "chroma-format", G_TYPE_STRING, chroma_format_str,
12166 NULL);
12167 }
12168
12169 if ((vpcc_data[14] & 0x1) != 0)
12170 cinfo.range = GST_VIDEO_COLOR_RANGE_0_255;
12171 else
12172 cinfo.range = GST_VIDEO_COLOR_RANGE_16_235;
12173 cinfo.primaries =
12174 gst_video_color_primaries_from_iso (vpcc_data[15]);
12175 cinfo.transfer =
12176 gst_video_transfer_function_from_iso (vpcc_data[16]);
12177 cinfo.matrix =
12178 gst_video_color_matrix_from_iso (vpcc_data[17]);
12179
12180 if (cinfo.primaries != GST_VIDEO_COLOR_PRIMARIES_UNKNOWN &&
12181 cinfo.transfer != GST_VIDEO_TRANSFER_UNKNOWN &&
12182 cinfo.matrix != GST_VIDEO_COLOR_MATRIX_UNKNOWN) {
12183 /* set this only if all values are known, otherwise this
12184 * might overwrite valid ones parsed from other color box */
12185 CUR_STREAM (stream)->colorimetry = cinfo;
12186 }
12187 break;
12188 }
12189 default:
12190 break;
12191 }
12192
12193 len -= size + 8;
12194 vpcc_data += size + 8;
12195 }
12196
12197 break;
12198 }
12199 default:
12200 break;
12201 }
12202 }
12203
12204 GST_INFO_OBJECT (qtdemux,
12205 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
12206 GST_FOURCC_ARGS (fourcc), entry->caps);
12207
12208 } else if (stream->subtype == FOURCC_soun) {
12209 GNode *wave;
12210 guint version, samplesize;
12211 guint16 compression_id;
12212 gboolean amrwb = FALSE;
12213
12214 offset = 16;
12215 /* sample description entry (16) + sound sample description v0 (20) */
12216 if (len < 36)
12217 goto corrupt_file;
12218
12219 version = QT_UINT32 (stsd_entry_data + offset);
12220 entry->n_channels = QT_UINT16 (stsd_entry_data + offset + 8);
12221 samplesize = QT_UINT16 (stsd_entry_data + offset + 10);
12222 compression_id = QT_UINT16 (stsd_entry_data + offset + 12);
12223 entry->rate = QT_FP32 (stsd_entry_data + offset + 16);
12224
12225 GST_LOG_OBJECT (qtdemux, "version/rev: %08x", version);
12226 GST_LOG_OBJECT (qtdemux, "vendor: %08x",
12227 QT_UINT32 (stsd_entry_data + offset + 4));
12228 GST_LOG_OBJECT (qtdemux, "n_channels: %d", entry->n_channels);
12229 GST_LOG_OBJECT (qtdemux, "sample_size: %d", samplesize);
12230 GST_LOG_OBJECT (qtdemux, "compression_id: %d", compression_id);
12231 GST_LOG_OBJECT (qtdemux, "packet size: %d",
12232 QT_UINT16 (stsd_entry_data + offset + 14));
12233 GST_LOG_OBJECT (qtdemux, "sample rate: %g", entry->rate);
12234
12235 if (compression_id == 0xfffe)
12236 entry->sampled = TRUE;
12237
12238 /* first assume uncompressed audio */
12239 entry->bytes_per_sample = samplesize / 8;
12240 entry->samples_per_frame = entry->n_channels;
12241 entry->bytes_per_frame = entry->n_channels * entry->bytes_per_sample;
12242 entry->samples_per_packet = entry->samples_per_frame;
12243 entry->bytes_per_packet = entry->bytes_per_sample;
12244
12245 offset = 36;
12246
12247 if (version == 0x00010000) {
12248 /* sample description entry (16) + sound sample description v1 (20+16) */
12249 if (len < 52)
12250 goto corrupt_file;
12251
12252 /* take information from here over the normal sample description */
12253 entry->samples_per_packet = QT_UINT32 (stsd_entry_data + offset);
12254 entry->bytes_per_packet = QT_UINT32 (stsd_entry_data + offset + 4);
12255 entry->bytes_per_frame = QT_UINT32 (stsd_entry_data + offset + 8);
12256 entry->bytes_per_sample = QT_UINT32 (stsd_entry_data + offset + 12);
12257
12258 GST_LOG_OBJECT (qtdemux, "Sound sample description Version 1");
12259 GST_LOG_OBJECT (qtdemux, "samples/packet: %d",
12260 entry->samples_per_packet);
12261 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
12262 entry->bytes_per_packet);
12263 GST_LOG_OBJECT (qtdemux, "bytes/frame: %d",
12264 entry->bytes_per_frame);
12265 GST_LOG_OBJECT (qtdemux, "bytes/sample: %d",
12266 entry->bytes_per_sample);
12267
12268 if (!entry->sampled && entry->bytes_per_packet) {
12269 entry->samples_per_frame = (entry->bytes_per_frame /
12270 entry->bytes_per_packet) * entry->samples_per_packet;
12271 GST_LOG_OBJECT (qtdemux, "samples/frame: %d",
12272 entry->samples_per_frame);
12273 }
12274 } else if (version == 0x00020000) {
12275 /* sample description entry (16) + sound sample description v2 (56) */
12276 if (len < 72)
12277 goto corrupt_file;
12278
12279 /* take information from here over the normal sample description */
12280 entry->rate = GST_READ_DOUBLE_BE (stsd_entry_data + offset + 4);
12281 entry->n_channels = QT_UINT32 (stsd_entry_data + offset + 12);
12282 entry->samples_per_frame = entry->n_channels;
12283 entry->bytes_per_sample = QT_UINT32 (stsd_entry_data + offset + 20) / 8;
12284 entry->bytes_per_packet = QT_UINT32 (stsd_entry_data + offset + 28);
12285 entry->samples_per_packet = QT_UINT32 (stsd_entry_data + offset + 32);
12286 entry->bytes_per_frame = entry->bytes_per_sample * entry->n_channels;
12287
12288 GST_LOG_OBJECT (qtdemux, "Sound sample description Version 2");
12289 GST_LOG_OBJECT (qtdemux, "sample rate: %g", entry->rate);
12290 GST_LOG_OBJECT (qtdemux, "n_channels: %d", entry->n_channels);
12291 GST_LOG_OBJECT (qtdemux, "bits/channel: %d",
12292 entry->bytes_per_sample * 8);
12293 GST_LOG_OBJECT (qtdemux, "format flags: %X",
12294 QT_UINT32 (stsd_entry_data + offset + 24));
12295 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
12296 entry->bytes_per_packet);
12297 GST_LOG_OBJECT (qtdemux, "LPCM frames/packet: %d",
12298 entry->samples_per_packet);
12299 } else if (version != 0x00000) {
12300 GST_WARNING_OBJECT (qtdemux, "unknown audio STSD version %08x",
12301 version);
12302 }
12303
12304 switch (fourcc) {
12305 /* Yes, these have to be hard-coded */
12306 case FOURCC_MAC6:
12307 {
12308 entry->samples_per_packet = 6;
12309 entry->bytes_per_packet = 1;
12310 entry->bytes_per_frame = 1 * entry->n_channels;
12311 entry->bytes_per_sample = 1;
12312 entry->samples_per_frame = 6 * entry->n_channels;
12313 break;
12314 }
12315 case FOURCC_MAC3:
12316 {
12317 entry->samples_per_packet = 3;
12318 entry->bytes_per_packet = 1;
12319 entry->bytes_per_frame = 1 * entry->n_channels;
12320 entry->bytes_per_sample = 1;
12321 entry->samples_per_frame = 3 * entry->n_channels;
12322 break;
12323 }
12324 case FOURCC_ima4:
12325 {
12326 entry->samples_per_packet = 64;
12327 entry->bytes_per_packet = 34;
12328 entry->bytes_per_frame = 34 * entry->n_channels;
12329 entry->bytes_per_sample = 2;
12330 entry->samples_per_frame = 64 * entry->n_channels;
12331 break;
12332 }
12333 case FOURCC_ulaw:
12334 case FOURCC_alaw:
12335 {
12336 entry->samples_per_packet = 1;
12337 entry->bytes_per_packet = 1;
12338 entry->bytes_per_frame = 1 * entry->n_channels;
12339 entry->bytes_per_sample = 1;
12340 entry->samples_per_frame = 1 * entry->n_channels;
12341 break;
12342 }
12343 case FOURCC_agsm:
12344 {
12345 entry->samples_per_packet = 160;
12346 entry->bytes_per_packet = 33;
12347 entry->bytes_per_frame = 33 * entry->n_channels;
12348 entry->bytes_per_sample = 2;
12349 entry->samples_per_frame = 160 * entry->n_channels;
12350 break;
12351 }
12352 /* fix up any invalid header information from above */
12353 case FOURCC_twos:
12354 case FOURCC_sowt:
12355 case FOURCC_raw_:
12356 case FOURCC_lpcm:
12357 /* Sometimes these are set to 0 in the sound sample descriptions so
12358 * let's try to infer useful values from the other information we
12359 * have available */
12360 if (entry->bytes_per_sample == 0)
12361 entry->bytes_per_sample =
12362 entry->bytes_per_frame / entry->n_channels;
12363 if (entry->bytes_per_sample == 0)
12364 entry->bytes_per_sample = samplesize / 8;
12365
12366 if (entry->bytes_per_frame == 0)
12367 entry->bytes_per_frame =
12368 entry->bytes_per_sample * entry->n_channels;
12369
12370 if (entry->bytes_per_packet == 0)
12371 entry->bytes_per_packet = entry->bytes_per_sample;
12372
12373 if (entry->samples_per_frame == 0)
12374 entry->samples_per_frame = entry->n_channels;
12375
12376 if (entry->samples_per_packet == 0)
12377 entry->samples_per_packet = entry->samples_per_frame;
12378
12379 break;
12380 case FOURCC_in24:
12381 case FOURCC_in32:
12382 case FOURCC_fl32:
12383 case FOURCC_fl64:
12384 case FOURCC_s16l:{
12385 switch (fourcc) {
12386 case FOURCC_in24:
12387 entry->bytes_per_sample = 3;
12388 break;
12389 case FOURCC_in32:
12390 case FOURCC_fl32:
12391 entry->bytes_per_sample = 4;
12392 break;
12393 case FOURCC_fl64:
12394 entry->bytes_per_sample = 8;
12395 break;
12396 case FOURCC_s16l:
12397 entry->bytes_per_sample = 2;
12398 break;
12399 default:
12400 g_assert_not_reached ();
12401 break;
12402 }
12403 entry->samples_per_frame = entry->n_channels;
12404 entry->bytes_per_frame = entry->n_channels * entry->bytes_per_sample;
12405 entry->samples_per_packet = entry->samples_per_frame;
12406 entry->bytes_per_packet = entry->bytes_per_sample;
12407 break;
12408 }
12409 default:
12410 break;
12411 }
12412
12413 if (entry->caps)
12414 gst_caps_unref (entry->caps);
12415
12416 entry->caps = qtdemux_audio_caps (qtdemux, stream, entry, fourcc,
12417 stsd_entry_data + 32, len - 16, &codec);
12418
12419 switch (fourcc) {
12420 case FOURCC_in24:
12421 case FOURCC_in32:
12422 case FOURCC_fl32:
12423 case FOURCC_fl64:
12424 {
12425 GNode *enda;
12426 GNode *fmt;
12427
12428 fmt = qtdemux_tree_get_child_by_type (stsd, fourcc);
12429
12430 enda = qtdemux_tree_get_child_by_type (fmt, FOURCC_enda);
12431 if (!enda) {
12432 wave = qtdemux_tree_get_child_by_type (fmt, FOURCC_wave);
12433 if (wave)
12434 enda = qtdemux_tree_get_child_by_type (wave, FOURCC_enda);
12435 }
12436 if (enda) {
12437 int enda_value = QT_UINT16 ((guint8 *) enda->data + 8);
12438 const gchar *format_str;
12439
12440 switch (fourcc) {
12441 case FOURCC_in24:
12442 format_str = (enda_value) ? "S24LE" : "S24BE";
12443 break;
12444 case FOURCC_in32:
12445 format_str = (enda_value) ? "S32LE" : "S32BE";
12446 break;
12447 case FOURCC_fl32:
12448 format_str = (enda_value) ? "F32LE" : "F32BE";
12449 break;
12450 case FOURCC_fl64:
12451 format_str = (enda_value) ? "F64LE" : "F64BE";
12452 break;
12453 default:
12454 g_assert_not_reached ();
12455 break;
12456 }
12457 gst_caps_set_simple (entry->caps,
12458 "format", G_TYPE_STRING, format_str, NULL);
12459 }
12460 break;
12461 }
12462 case FOURCC_owma:
12463 {
12464 const guint8 *owma_data;
12465 const gchar *codec_name = NULL;
12466 guint owma_len;
12467 GstBuffer *buf;
12468 gint version = 1;
12469 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
12470 /* FIXME this should also be gst_riff_strf_auds,
12471 * but the latter one is actually missing bits-per-sample :( */
12472 typedef struct
12473 {
12474 gint16 wFormatTag;
12475 gint16 nChannels;
12476 gint32 nSamplesPerSec;
12477 gint32 nAvgBytesPerSec;
12478 gint16 nBlockAlign;
12479 gint16 wBitsPerSample;
12480 gint16 cbSize;
12481 } WAVEFORMATEX;
12482 WAVEFORMATEX *wfex;
12483
12484 GST_DEBUG_OBJECT (qtdemux, "parse owma");
12485 owma_data = stsd_entry_data;
12486 owma_len = QT_UINT32 (owma_data);
12487 if (owma_len <= 54) {
12488 GST_WARNING_OBJECT (qtdemux, "Too small owma header, skipping");
12489 break;
12490 }
12491 wfex = (WAVEFORMATEX *) (owma_data + 36);
12492 buf = gst_buffer_new_and_alloc (owma_len - 54);
12493 gst_buffer_fill (buf, 0, owma_data + 54, owma_len - 54);
12494 if (wfex->wFormatTag == 0x0161) {
12495 codec_name = "Windows Media Audio";
12496 version = 2;
12497 } else if (wfex->wFormatTag == 0x0162) {
12498 codec_name = "Windows Media Audio 9 Pro";
12499 version = 3;
12500 } else if (wfex->wFormatTag == 0x0163) {
12501 codec_name = "Windows Media Audio 9 Lossless";
12502 /* is that correct? gstffmpegcodecmap.c is missing it, but
12503 * fluendo codec seems to support it */
12504 version = 4;
12505 }
12506
12507 gst_caps_set_simple (entry->caps,
12508 "codec_data", GST_TYPE_BUFFER, buf,
12509 "wmaversion", G_TYPE_INT, version,
12510 "block_align", G_TYPE_INT,
12511 GST_READ_UINT16_LE (&wfex->nBlockAlign), "bitrate", G_TYPE_INT,
12512 GST_READ_UINT32_LE (&wfex->nAvgBytesPerSec), "width", G_TYPE_INT,
12513 GST_READ_UINT16_LE (&wfex->wBitsPerSample), "depth", G_TYPE_INT,
12514 GST_READ_UINT16_LE (&wfex->wBitsPerSample), NULL);
12515 gst_buffer_unref (buf);
12516
12517 if (codec_name) {
12518 g_free (codec);
12519 codec = g_strdup (codec_name);
12520 }
12521 break;
12522 }
12523 case FOURCC_wma_:
12524 {
12525 guint len = QT_UINT32 (stsd_entry_data);
12526 len = len <= offset ? 0 : len - offset;
12527 const guint8 *wfex_data = stsd_entry_data + offset;
12528 const gchar *codec_name = NULL;
12529 gint version = 1;
12530 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
12531 /* FIXME this should also be gst_riff_strf_auds,
12532 * but the latter one is actually missing bits-per-sample :( */
12533 typedef struct
12534 {
12535 gint16 wFormatTag;
12536 gint16 nChannels;
12537 gint32 nSamplesPerSec;
12538 gint32 nAvgBytesPerSec;
12539 gint16 nBlockAlign;
12540 gint16 wBitsPerSample;
12541 gint16 cbSize;
12542 } WAVEFORMATEX;
12543 WAVEFORMATEX wfex;
12544
12545 /* FIXME: unify with similar wavformatex parsing code above */
12546 GST_DEBUG_OBJECT (qtdemux, "parse wma, looking for wfex");
12547
12548 /* find wfex */
12549 while (len >= 8) {
12550 guint size;
12551
12552 if (QT_UINT32 (wfex_data) <= 0x8)
12553 size = 0;
12554 else if (QT_UINT32 (wfex_data) <= len)
12555 size = QT_UINT32 (wfex_data) - 8;
12556 else
12557 size = len - 8;
12558
12559 if (size < 1)
12560 /* No real data, so break out */
12561 break;
12562
12563 switch (QT_FOURCC (wfex_data + 4)) {
12564 case GST_MAKE_FOURCC ('w', 'f', 'e', 'x'):
12565 {
12566 GST_DEBUG_OBJECT (qtdemux, "found wfex in stsd");
12567
12568 if (size < 8 + 18)
12569 break;
12570
12571 wfex.wFormatTag = GST_READ_UINT16_LE (wfex_data + 8 + 0);
12572 wfex.nChannels = GST_READ_UINT16_LE (wfex_data + 8 + 2);
12573 wfex.nSamplesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 4);
12574 wfex.nAvgBytesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 8);
12575 wfex.nBlockAlign = GST_READ_UINT16_LE (wfex_data + 8 + 12);
12576 wfex.wBitsPerSample = GST_READ_UINT16_LE (wfex_data + 8 + 14);
12577 wfex.cbSize = GST_READ_UINT16_LE (wfex_data + 8 + 16);
12578
12579 GST_LOG_OBJECT (qtdemux, "Found wfex box in stsd:");
12580 GST_LOG_OBJECT (qtdemux, "FormatTag = 0x%04x, Channels = %u, "
12581 "SamplesPerSec = %u, AvgBytesPerSec = %u, BlockAlign = %u, "
12582 "BitsPerSample = %u, Size = %u", wfex.wFormatTag,
12583 wfex.nChannels, wfex.nSamplesPerSec, wfex.nAvgBytesPerSec,
12584 wfex.nBlockAlign, wfex.wBitsPerSample, wfex.cbSize);
12585
12586 if (wfex.wFormatTag == 0x0161) {
12587 codec_name = "Windows Media Audio";
12588 version = 2;
12589 } else if (wfex.wFormatTag == 0x0162) {
12590 codec_name = "Windows Media Audio 9 Pro";
12591 version = 3;
12592 } else if (wfex.wFormatTag == 0x0163) {
12593 codec_name = "Windows Media Audio 9 Lossless";
12594 /* is that correct? gstffmpegcodecmap.c is missing it, but
12595 * fluendo codec seems to support it */
12596 version = 4;
12597 }
12598
12599 gst_caps_set_simple (entry->caps,
12600 "wmaversion", G_TYPE_INT, version,
12601 "block_align", G_TYPE_INT, wfex.nBlockAlign,
12602 "bitrate", G_TYPE_INT, wfex.nAvgBytesPerSec,
12603 "width", G_TYPE_INT, wfex.wBitsPerSample,
12604 "depth", G_TYPE_INT, wfex.wBitsPerSample, NULL);
12605
12606 if (size > wfex.cbSize) {
12607 GstBuffer *buf;
12608
12609 buf = gst_buffer_new_and_alloc (size - wfex.cbSize);
12610 gst_buffer_fill (buf, 0, wfex_data + 8 + wfex.cbSize,
12611 size - wfex.cbSize);
12612 gst_caps_set_simple (entry->caps,
12613 "codec_data", GST_TYPE_BUFFER, buf, NULL);
12614 gst_buffer_unref (buf);
12615 } else {
12616 GST_WARNING_OBJECT (qtdemux, "no codec data");
12617 }
12618
12619 if (codec_name) {
12620 g_free (codec);
12621 codec = g_strdup (codec_name);
12622 }
12623 break;
12624 }
12625 default:
12626 break;
12627 }
12628 len -= size + 8;
12629 wfex_data += size + 8;
12630 }
12631 break;
12632 }
12633 case FOURCC_opus:
12634 {
12635 const guint8 *dops_data;
12636 guint8 *channel_mapping = NULL;
12637 guint32 rate;
12638 guint8 channels;
12639 guint8 channel_mapping_family;
12640 guint8 stream_count;
12641 guint8 coupled_count;
12642 guint8 i;
12643
12644 version = GST_READ_UINT16_BE (stsd_entry_data + 16);
12645 if (version == 1)
12646 dops_data = stsd_entry_data + 51;
12647 else
12648 dops_data = stsd_entry_data + 35;
12649
12650 channels = GST_READ_UINT8 (dops_data + 10);
12651 rate = GST_READ_UINT32_LE (dops_data + 13);
12652 channel_mapping_family = GST_READ_UINT8 (dops_data + 19);
12653 stream_count = GST_READ_UINT8 (dops_data + 20);
12654 coupled_count = GST_READ_UINT8 (dops_data + 21);
12655
12656 if (channels > 0) {
12657 channel_mapping = g_malloc (channels * sizeof (guint8));
12658 for (i = 0; i < channels; i++)
12659 channel_mapping[i] = GST_READ_UINT8 (dops_data + i + 22);
12660 }
12661
12662 entry->caps = gst_codec_utils_opus_create_caps (rate, channels,
12663 channel_mapping_family, stream_count, coupled_count,
12664 channel_mapping);
12665 g_free (channel_mapping);
12666 break;
12667 }
12668 default:
12669 break;
12670 }
12671
12672 if (codec) {
12673 GstStructure *s;
12674 gint bitrate = 0;
12675
12676 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12677 GST_TAG_AUDIO_CODEC, codec, NULL);
12678 g_free (codec);
12679 codec = NULL;
12680
12681 /* some bitrate info may have ended up in caps */
12682 s = gst_caps_get_structure (entry->caps, 0);
12683 gst_structure_get_int (s, "bitrate", &bitrate);
12684 if (bitrate > 0)
12685 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12686 GST_TAG_BITRATE, bitrate, NULL);
12687 }
12688
12689 esds = NULL;
12690 mp4a = qtdemux_tree_get_child_by_index (stsd, stsd_index);
12691 if (QTDEMUX_TREE_NODE_FOURCC (mp4a) != fourcc) {
12692 if (stream->protected) {
12693 if (QTDEMUX_TREE_NODE_FOURCC (mp4a) == FOURCC_aavd) {
12694 esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
12695 }
12696 if (QTDEMUX_TREE_NODE_FOURCC (mp4a) != FOURCC_enca) {
12697 mp4a = NULL;
12698 }
12699 } else {
12700 mp4a = NULL;
12701 }
12702 }
12703
12704 wave = NULL;
12705 if (mp4a) {
12706 wave = qtdemux_tree_get_child_by_type (mp4a, FOURCC_wave);
12707 if (wave)
12708 esds = qtdemux_tree_get_child_by_type (wave, FOURCC_esds);
12709 if (!esds)
12710 esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
12711 }
12712
12713
12714 /* If the fourcc's bottom 16 bits gives 'sm', then the top
12715 16 bits is a byte-swapped wave-style codec identifier,
12716 and we can find a WAVE header internally to a 'wave' atom here.
12717 This can more clearly be thought of as 'ms' as the top 16 bits, and a
12718 codec id as the bottom 16 bits - but byte-swapped to store in QT (which
12719 is big-endian).
12720 */
12721 if ((fourcc & 0xffff) == (('s' << 8) | 'm')) {
12722 if (len < offset + 20) {
12723 GST_WARNING_OBJECT (qtdemux, "No wave atom in MS-style audio");
12724 } else {
12725 guint32 datalen = QT_UINT32 (stsd_entry_data + offset + 16);
12726 const guint8 *data = stsd_entry_data + offset + 16;
12727 GNode *wavenode;
12728 GNode *waveheadernode;
12729
12730 wavenode = g_node_new ((guint8 *) data);
12731 if (qtdemux_parse_node (qtdemux, wavenode, data, datalen)) {
12732 const guint8 *waveheader;
12733 guint32 headerlen;
12734
12735 waveheadernode = qtdemux_tree_get_child_by_type (wavenode, fourcc);
12736 if (waveheadernode) {
12737 waveheader = (const guint8 *) waveheadernode->data;
12738 headerlen = QT_UINT32 (waveheader);
12739
12740 if (headerlen > 8) {
12741 gst_riff_strf_auds *header = NULL;
12742 GstBuffer *headerbuf;
12743 GstBuffer *extra;
12744
12745 waveheader += 8;
12746 headerlen -= 8;
12747
12748 headerbuf = gst_buffer_new_and_alloc (headerlen);
12749 gst_buffer_fill (headerbuf, 0, waveheader, headerlen);
12750
12751 if (gst_riff_parse_strf_auds (GST_ELEMENT_CAST (qtdemux),
12752 headerbuf, &header, &extra)) {
12753 gst_caps_unref (entry->caps);
12754 /* FIXME: Need to do something with the channel reorder map */
12755 entry->caps =
12756 gst_riff_create_audio_caps (header->format, NULL, header,
12757 extra, NULL, NULL, NULL);
12758
12759 if (extra)
12760 gst_buffer_unref (extra);
12761 g_free (header);
12762 }
12763 }
12764 } else
12765 GST_DEBUG ("Didn't find waveheadernode for this codec");
12766 }
12767 g_node_destroy (wavenode);
12768 }
12769 } else if (esds) {
12770 gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
12771 stream->stream_tags);
12772 } else {
12773 switch (fourcc) {
12774#if 0
12775 /* FIXME: what is in the chunk? */
12776 case FOURCC_QDMC:
12777 {
12778 gint len = QT_UINT32 (stsd_data);
12779
12780 /* seems to be always = 116 = 0x74 */
12781 break;
12782 }
12783#endif
12784 case FOURCC_QDM2:
12785 {
12786 gint len = QT_UINT32 (stsd_entry_data);
12787
12788 if (len > 0x3C) {
12789 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x3C);
12790
12791 gst_buffer_fill (buf, 0, stsd_entry_data + 0x3C, len - 0x3C);
12792 gst_caps_set_simple (entry->caps,
12793 "codec_data", GST_TYPE_BUFFER, buf, NULL);
12794 gst_buffer_unref (buf);
12795 }
12796 gst_caps_set_simple (entry->caps,
12797 "samplesize", G_TYPE_INT, samplesize, NULL);
12798 break;
12799 }
12800 case FOURCC_alac:
12801 {
12802 GNode *alac, *wave = NULL;
12803
12804 /* apparently, m4a has this atom appended directly in the stsd entry,
12805 * while mov has it in a wave atom */
12806 alac = qtdemux_tree_get_child_by_type (stsd, FOURCC_alac);
12807 if (alac) {
12808 /* alac now refers to stsd entry atom */
12809 wave = qtdemux_tree_get_child_by_type (alac, FOURCC_wave);
12810 if (wave)
12811 alac = qtdemux_tree_get_child_by_type (wave, FOURCC_alac);
12812 else
12813 alac = qtdemux_tree_get_child_by_type (alac, FOURCC_alac);
12814 }
12815 if (alac) {
12816 const guint8 *alac_data = alac->data;
12817 gint len = QT_UINT32 (alac->data);
12818 GstBuffer *buf;
12819
12820 if (len < 36) {
12821 GST_DEBUG_OBJECT (qtdemux,
12822 "discarding alac atom with unexpected len %d", len);
12823 } else {
12824 /* codec-data contains alac atom size and prefix,
12825 * ffmpeg likes it that way, not quite gst-ish though ...*/
12826 buf = gst_buffer_new_and_alloc (len);
12827 gst_buffer_fill (buf, 0, alac->data, len);
12828 gst_caps_set_simple (entry->caps,
12829 "codec_data", GST_TYPE_BUFFER, buf, NULL);
12830 gst_buffer_unref (buf);
12831
12832 entry->bytes_per_frame = QT_UINT32 (alac_data + 12);
12833 entry->n_channels = QT_UINT8 (alac_data + 21);
12834 entry->rate = QT_UINT32 (alac_data + 32);
12835 samplesize = QT_UINT8 (alac_data + 16 + 1);
12836 }
12837 }
12838 gst_caps_set_simple (entry->caps,
12839 "samplesize", G_TYPE_INT, samplesize, NULL);
12840 break;
12841 }
12842 case FOURCC_fLaC:
12843 {
12844 /* The codingname of the sample entry is 'fLaC' */
12845 GNode *flac = qtdemux_tree_get_child_by_type (stsd, FOURCC_fLaC);
12846
12847 if (flac) {
12848 /* The 'dfLa' box is added to the sample entry to convey
12849 initializing information for the decoder. */
12850 const GNode *dfla =
12851 qtdemux_tree_get_child_by_type (flac, FOURCC_dfLa);
12852
12853 if (dfla) {
12854 const guint32 len = QT_UINT32 (dfla->data);
12855
12856 /* Must contain at least dfLa box header (12),
12857 * METADATA_BLOCK_HEADER (4), METADATA_BLOCK_STREAMINFO (34) */
12858 if (len < 50) {
12859 GST_DEBUG_OBJECT (qtdemux,
12860 "discarding dfla atom with unexpected len %d", len);
12861 } else {
12862 /* skip dfLa header to get the METADATA_BLOCKs */
12863 const guint8 *metadata_blocks = (guint8 *) dfla->data + 12;
12864 const guint32 metadata_blocks_len = len - 12;
12865
12866 gchar *stream_marker = g_strdup ("fLaC");
12867 GstBuffer *block = gst_buffer_new_wrapped (stream_marker,
12868 strlen (stream_marker));
12869
12870 guint32 index = 0;
12871 guint32 remainder = 0;
12872 guint32 block_size = 0;
12873 gboolean is_last = FALSE;
12874
12875 GValue array = G_VALUE_INIT;
12876 GValue value = G_VALUE_INIT;
12877
12878 g_value_init (&array, GST_TYPE_ARRAY);
12879 g_value_init (&value, GST_TYPE_BUFFER);
12880
12881 gst_value_set_buffer (&value, block);
12882 gst_value_array_append_value (&array, &value);
12883 g_value_reset (&value);
12884
12885 gst_buffer_unref (block);
12886
12887 /* check there's at least one METADATA_BLOCK_HEADER's worth
12888 * of data, and we haven't already finished parsing */
12889 while (!is_last && ((index + 3) < metadata_blocks_len)) {
12890 remainder = metadata_blocks_len - index;
12891
12892 /* add the METADATA_BLOCK_HEADER size to the signalled size */
12893 block_size = 4 +
12894 (metadata_blocks[index + 1] << 16) +
12895 (metadata_blocks[index + 2] << 8) +
12896 metadata_blocks[index + 3];
12897
12898 /* be careful not to read off end of box */
12899 if (block_size > remainder) {
12900 break;
12901 }
12902
12903 is_last = metadata_blocks[index] >> 7;
12904
12905 block = gst_buffer_new_and_alloc (block_size);
12906
12907 gst_buffer_fill (block, 0, &metadata_blocks[index],
12908 block_size);
12909
12910 gst_value_set_buffer (&value, block);
12911 gst_value_array_append_value (&array, &value);
12912 g_value_reset (&value);
12913
12914 gst_buffer_unref (block);
12915
12916 index += block_size;
12917 }
12918
12919 /* only append the metadata if we successfully read all of it */
12920 if (is_last) {
12921 gst_structure_set_value (gst_caps_get_structure (CUR_STREAM
12922 (stream)->caps, 0), "streamheader", &array);
12923 } else {
12924 GST_WARNING_OBJECT (qtdemux,
12925 "discarding all METADATA_BLOCKs due to invalid "
12926 "block_size %d at idx %d, rem %d", block_size, index,
12927 remainder);
12928 }
12929
12930 g_value_unset (&value);
12931 g_value_unset (&array);
12932
12933 /* The sample rate obtained from the stsd may not be accurate
12934 * since it cannot represent rates greater than 65535Hz, so
12935 * override that value with the sample rate from the
12936 * METADATA_BLOCK_STREAMINFO block */
12937 CUR_STREAM (stream)->rate =
12938 (QT_UINT32 (metadata_blocks + 14) >> 12) & 0xFFFFF;
12939 }
12940 }
12941 }
12942 break;
12943 }
12944 case FOURCC_sawb:
12945 /* Fallthrough! */
12946 amrwb = TRUE;
12947 case FOURCC_samr:
12948 {
12949 gint len = QT_UINT32 (stsd_entry_data);
12950
12951 if (len > 0x24) {
12952 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x24);
12953 guint bitrate;
12954
12955 gst_buffer_fill (buf, 0, stsd_entry_data + 0x24, len - 0x24);
12956
12957 /* If we have enough data, let's try to get the 'damr' atom. See
12958 * the 3GPP container spec (26.244) for more details. */
12959 if ((len - 0x34) > 8 &&
12960 (bitrate = qtdemux_parse_amr_bitrate (buf, amrwb))) {
12961 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12962 GST_TAG_MAXIMUM_BITRATE, bitrate, NULL);
12963 }
12964
12965 gst_caps_set_simple (entry->caps,
12966 "codec_data", GST_TYPE_BUFFER, buf, NULL);
12967 gst_buffer_unref (buf);
12968 }
12969 break;
12970 }
12971 case FOURCC_mp4a:
12972 {
12973 /* mp4a atom withtout ESDS; Attempt to build codec data from atom */
12974 gint len = QT_UINT32 (stsd_entry_data);
12975 guint16 sound_version = 0;
12976 /* FIXME: Can this be determined somehow? There doesn't seem to be
12977 * anything in mp4a atom that specifis compression */
12978 gint profile = 2;
12979 guint16 channels = entry->n_channels;
12980 guint32 time_scale = (guint32) entry->rate;
12981 gint sample_rate_index = -1;
12982
12983 if (len >= 34) {
12984 sound_version = QT_UINT16 (stsd_entry_data + 16);
12985
12986 if (sound_version == 1) {
12987 channels = QT_UINT16 (stsd_entry_data + 24);
12988 time_scale = QT_UINT32 (stsd_entry_data + 30);
12989 } else {
12990 GST_FIXME_OBJECT (qtdemux, "Unhandled mp4a atom version %d",
12991 sound_version);
12992 }
12993 } else {
12994 GST_DEBUG_OBJECT (qtdemux, "Too small stsd entry data len %d",
12995 len);
12996 }
12997
12998 sample_rate_index =
12999 gst_codec_utils_aac_get_index_from_sample_rate (time_scale);
13000 if (sample_rate_index >= 0 && channels > 0) {
13001 guint8 codec_data[2];
13002 GstBuffer *buf;
13003
13004 /* build AAC codec data */
13005 codec_data[0] = profile << 3;
13006 codec_data[0] |= ((sample_rate_index >> 1) & 0x7);
13007 codec_data[1] = (sample_rate_index & 0x01) << 7;
13008 codec_data[1] |= (channels & 0xF) << 3;
13009
13010 buf = gst_buffer_new_and_alloc (2);
13011 gst_buffer_fill (buf, 0, codec_data, 2);
13012 gst_caps_set_simple (entry->caps,
13013 "codec_data", GST_TYPE_BUFFER, buf, NULL);
13014 gst_buffer_unref (buf);
13015 }
13016 break;
13017 }
13018 case FOURCC_lpcm:
13019 case FOURCC_in24:
13020 case FOURCC_in32:
13021 case FOURCC_fl32:
13022 case FOURCC_fl64:
13023 case FOURCC_s16l:
13024 /* Fully handled elsewhere */
13025 break;
13026 default:
13027 GST_INFO_OBJECT (qtdemux,
13028 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
13029 break;
13030 }
13031 }
13032 GST_INFO_OBJECT (qtdemux,
13033 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
13034 GST_FOURCC_ARGS (fourcc), entry->caps);
13035
13036 } else if (stream->subtype == FOURCC_strm) {
13037 if (fourcc == FOURCC_rtsp) {
13038 stream->redirect_uri = qtdemux_get_rtsp_uri_from_hndl (qtdemux, minf);
13039 } else {
13040 GST_INFO_OBJECT (qtdemux, "unhandled stream type %" GST_FOURCC_FORMAT,
13041 GST_FOURCC_ARGS (fourcc));
13042 goto unknown_stream;
13043 }
13044 entry->sampled = TRUE;
13045 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
13046 || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt
13047 || stream->subtype == FOURCC_clcp || stream->subtype == FOURCC_wvtt) {
13048
13049 entry->sampled = TRUE;
13050 entry->sparse = TRUE;
13051
13052 entry->caps =
13053 qtdemux_sub_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
13054 &codec);
13055 if (codec) {
13056 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
13057 GST_TAG_SUBTITLE_CODEC, codec, NULL);
13058 g_free (codec);
13059 codec = NULL;
13060 }
13061
13062 /* hunt for sort-of codec data */
13063 switch (fourcc) {
13064 case FOURCC_mp4s:
13065 {
13066 GNode *mp4s = NULL;
13067 GNode *esds = NULL;
13068
13069 /* look for palette in a stsd->mp4s->esds sub-atom */
13070 mp4s = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4s);
13071 if (mp4s)
13072 esds = qtdemux_tree_get_child_by_type (mp4s, FOURCC_esds);
13073 if (esds == NULL) {
13074 /* Invalid STSD */
13075 GST_LOG_OBJECT (qtdemux, "Skipping invalid stsd: no esds child");
13076 break;
13077 }
13078
13079 gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
13080 stream->stream_tags);
13081 break;
13082 }
13083 default:
13084 GST_INFO_OBJECT (qtdemux,
13085 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
13086 break;
13087 }
13088 GST_INFO_OBJECT (qtdemux,
13089 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
13090 GST_FOURCC_ARGS (fourcc), entry->caps);
13091 } else {
13092 /* everything in 1 sample */
13093 entry->sampled = TRUE;
13094
13095 entry->caps =
13096 qtdemux_generic_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
13097 &codec);
13098
13099 if (entry->caps == NULL)
13100 goto unknown_stream;
13101
13102 if (codec) {
13103 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
13104 GST_TAG_SUBTITLE_CODEC, codec, NULL);
13105 g_free (codec);
13106 codec = NULL;
13107 }
13108 }
13109
13110 /* promote to sampled format */
13111 if (entry->fourcc == FOURCC_samr) {
13112 /* force mono 8000 Hz for AMR */
13113 entry->sampled = TRUE;
13114 entry->n_channels = 1;
13115 entry->rate = 8000;
13116 } else if (entry->fourcc == FOURCC_sawb) {
13117 /* force mono 16000 Hz for AMR-WB */
13118 entry->sampled = TRUE;
13119 entry->n_channels = 1;
13120 entry->rate = 16000;
13121 } else if (entry->fourcc == FOURCC_mp4a) {
13122 entry->sampled = TRUE;
13123 }
13124
13125
13126 stsd_entry_data += len;
13127 remaining_stsd_len -= len;
13128
13129 }
13130
13131 /* collect sample information */
13132 if (!qtdemux_stbl_init (qtdemux, stream, stbl))
13133 goto samples_failed;
13134
13135 if (qtdemux->fragmented) {
13136 guint64 offset;
13137
13138 /* need all moov samples as basis; probably not many if any at all */
13139 /* prevent moof parsing taking of at this time */
13140 offset = qtdemux->moof_offset;
13141 qtdemux->moof_offset = 0;
13142 if (stream->n_samples &&
13143 !qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
13144 qtdemux->moof_offset = offset;
13145 goto samples_failed;
13146 }
13147 qtdemux->moof_offset = offset;
13148 /* movie duration more reliable in this case (e.g. mehd) */
13149 if (qtdemux->segment.duration &&
13150 GST_CLOCK_TIME_IS_VALID (qtdemux->segment.duration))
13151 stream->duration =
13152 GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->segment.duration);
13153 }
13154
13155 /* configure segments */
13156 if (!qtdemux_parse_segments (qtdemux, stream, trak))
13157 goto segments_failed;
13158
13159 /* add some language tag, if useful */
13160 if (stream->lang_id[0] != '\0' && strcmp (stream->lang_id, "unk") &&
13161 strcmp (stream->lang_id, "und")) {
13162 const gchar *lang_code;
13163
13164 /* convert ISO 639-2 code to ISO 639-1 */
13165 lang_code = gst_tag_get_language_code (stream->lang_id);
13166 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
13167 GST_TAG_LANGUAGE_CODE, (lang_code) ? lang_code : stream->lang_id, NULL);
13168 }
13169
13170 /* Check for UDTA tags */
13171 if ((udta = qtdemux_tree_get_child_by_type (trak, FOURCC_udta))) {
13172 qtdemux_parse_udta (qtdemux, stream->stream_tags, udta);
13173 }
13174
13175 /* Insert and sort new stream in track-id order.
13176 * This will help in comparing old/new streams during stream update check */
13177 g_ptr_array_add (qtdemux->active_streams, stream);
13178 g_ptr_array_sort (qtdemux->active_streams,
13179 (GCompareFunc) qtdemux_track_id_compare_func);
13180 GST_DEBUG_OBJECT (qtdemux, "n_streams is now %d",
13181 QTDEMUX_N_STREAMS (qtdemux));
13182
13183 return TRUE;
13184
13185/* ERRORS */
13186corrupt_file:
13187 {
13188 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
13189 (_("This file is corrupt and cannot be played.")), (NULL));
13190 if (stream)
13191 gst_qtdemux_stream_unref (stream);
13192 return FALSE;
13193 }
13194error_encrypted:
13195 {
13196 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT, (NULL), (NULL));
13197 gst_qtdemux_stream_unref (stream);
13198 return FALSE;
13199 }
13200samples_failed:
13201segments_failed:
13202 {
13203 /* we posted an error already */
13204 /* free stbl sub-atoms */
13205 gst_qtdemux_stbl_free (stream);
13206 gst_qtdemux_stream_unref (stream);
13207 return FALSE;
13208 }
13209existing_stream:
13210 {
13211 GST_INFO_OBJECT (qtdemux, "stream with track id %i already exists",
13212 track_id);
13213 return TRUE;
13214 }
13215unknown_stream:
13216 {
13217 GST_INFO_OBJECT (qtdemux, "unknown subtype %" GST_FOURCC_FORMAT,
13218 GST_FOURCC_ARGS (stream->subtype));
13219 gst_qtdemux_stream_unref (stream);
13220 return TRUE;
13221 }
13222}
13223
13224/* If we can estimate the overall bitrate, and don't have information about the
13225 * stream bitrate for exactly one stream, this guesses the stream bitrate as
13226 * the overall bitrate minus the sum of the bitrates of all other streams. This
13227 * should be useful for the common case where we have one audio and one video
13228 * stream and can estimate the bitrate of one, but not the other. */
13229static void
13230gst_qtdemux_guess_bitrate (GstQTDemux * qtdemux)
13231{
13232 QtDemuxStream *stream = NULL;
13233 gint64 size, sys_bitrate, sum_bitrate = 0;
13234 GstClockTime duration;
13235 guint bitrate;
13236 gint i;
13237
13238 if (qtdemux->fragmented)
13239 return;
13240
13241 GST_DEBUG_OBJECT (qtdemux, "Looking for streams with unknown bitrate");
13242
13243 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &size)
13244 || size <= 0) {
13245 GST_DEBUG_OBJECT (qtdemux,
13246 "Size in bytes of the stream not known - bailing");
13247 return;
13248 }
13249
13250 /* Subtract the header size */
13251 GST_DEBUG_OBJECT (qtdemux, "Total size %" G_GINT64_FORMAT ", header size %u",
13252 size, qtdemux->header_size);
13253
13254 if (size < qtdemux->header_size)
13255 return;
13256
13257 size = size - qtdemux->header_size;
13258
13259 if (!gst_qtdemux_get_duration (qtdemux, &duration)) {
13260 GST_DEBUG_OBJECT (qtdemux, "Stream duration not known - bailing");
13261 return;
13262 }
13263
13264 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13265 QtDemuxStream *str = QTDEMUX_NTH_STREAM (qtdemux, i);
13266 switch (str->subtype) {
13267 case FOURCC_soun:
13268 case FOURCC_vide:
13269 GST_DEBUG_OBJECT (qtdemux, "checking bitrate for %" GST_PTR_FORMAT,
13270 CUR_STREAM (str)->caps);
13271 /* retrieve bitrate, prefer avg then max */
13272 bitrate = 0;
13273 if (str->stream_tags) {
13274 if (gst_tag_list_get_uint (str->stream_tags,
13275 GST_TAG_MAXIMUM_BITRATE, &bitrate))
13276 GST_DEBUG_OBJECT (qtdemux, "max-bitrate: %u", bitrate);
13277 if (gst_tag_list_get_uint (str->stream_tags,
13278 GST_TAG_NOMINAL_BITRATE, &bitrate))
13279 GST_DEBUG_OBJECT (qtdemux, "nominal-bitrate: %u", bitrate);
13280 if (gst_tag_list_get_uint (str->stream_tags,
13281 GST_TAG_BITRATE, &bitrate))
13282 GST_DEBUG_OBJECT (qtdemux, "bitrate: %u", bitrate);
13283 }
13284 if (bitrate)
13285 sum_bitrate += bitrate;
13286 else {
13287 if (stream) {
13288 GST_DEBUG_OBJECT (qtdemux,
13289 ">1 stream with unknown bitrate - bailing");
13290 return;
13291 } else
13292 stream = str;
13293 }
13294
13295 default:
13296 /* For other subtypes, we assume no significant impact on bitrate */
13297 break;
13298 }
13299 }
13300
13301 if (!stream) {
13302 GST_DEBUG_OBJECT (qtdemux, "All stream bitrates are known");
13303 return;
13304 }
13305
13306 sys_bitrate = gst_util_uint64_scale (size, GST_SECOND * 8, duration);
13307
13308 if (sys_bitrate < sum_bitrate) {
13309 /* This can happen, since sum_bitrate might be derived from maximum
13310 * bitrates and not average bitrates */
13311 GST_DEBUG_OBJECT (qtdemux,
13312 "System bitrate less than sum bitrate - bailing");
13313 return;
13314 }
13315
13316 bitrate = sys_bitrate - sum_bitrate;
13317 GST_DEBUG_OBJECT (qtdemux, "System bitrate = %" G_GINT64_FORMAT
13318 ", Stream bitrate = %u", sys_bitrate, bitrate);
13319
13320 if (!stream->stream_tags)
13321 stream->stream_tags = gst_tag_list_new_empty ();
13322 else
13323 stream->stream_tags = gst_tag_list_make_writable (stream->stream_tags);
13324
13325 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
13326 GST_TAG_BITRATE, bitrate, NULL);
13327}
13328
13329static GstFlowReturn
13330qtdemux_prepare_streams (GstQTDemux * qtdemux)
13331{
13332 GstFlowReturn ret = GST_FLOW_OK;
13333 gint i;
13334
13335 GST_DEBUG_OBJECT (qtdemux, "prepare %u streams", QTDEMUX_N_STREAMS (qtdemux));
13336
13337 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13338 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
13339 guint32 sample_num = 0;
13340
13341 GST_DEBUG_OBJECT (qtdemux, "track-id %u, fourcc %" GST_FOURCC_FORMAT,
13342 stream->track_id, GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
13343
13344 if (qtdemux->fragmented && qtdemux->pullbased) {
13345 /* need all moov samples first */
13346 GST_OBJECT_LOCK (qtdemux);
13347 while (stream->n_samples == 0)
13348 if ((ret = qtdemux_add_fragmented_samples (qtdemux)) != GST_FLOW_OK)
13349 break;
13350 GST_OBJECT_UNLOCK (qtdemux);
13351 } else {
13352 /* discard any stray moof */
13353 qtdemux->moof_offset = 0;
13354 }
13355
13356 /* prepare braking */
13357 if (ret != GST_FLOW_ERROR)
13358 ret = GST_FLOW_OK;
13359
13360 /* in pull mode, we should have parsed some sample info by now;
13361 * and quite some code will not handle no samples.
13362 * in push mode, we'll just have to deal with it */
13363 if (G_UNLIKELY (qtdemux->pullbased && !stream->n_samples)) {
13364 GST_DEBUG_OBJECT (qtdemux, "no samples for stream; discarding");
13365 g_ptr_array_remove_index (qtdemux->active_streams, i);
13366 i--;
13367 continue;
13368 } else if (stream->track_id == qtdemux->chapters_track_id &&
13369 (stream->subtype == FOURCC_text || stream->subtype == FOURCC_sbtl)) {
13370 /* TODO - parse chapters track and expose it as GstToc; For now just ignore it
13371 so that it doesn't look like a subtitle track */
13372 g_ptr_array_remove_index (qtdemux->active_streams, i);
13373 i--;
13374 continue;
13375 }
13376
13377 /* parse the initial sample for use in setting the frame rate cap */
13378 while (sample_num == 0 && sample_num < stream->n_samples) {
13379 if (!qtdemux_parse_samples (qtdemux, stream, sample_num))
13380 break;
13381 ++sample_num;
13382 }
13383 }
13384
13385 return ret;
13386}
13387
13388static gboolean
13389_stream_equal_func (const QtDemuxStream * stream, const gchar * stream_id)
13390{
13391 return g_strcmp0 (stream->stream_id, stream_id) == 0;
13392}
13393
13394static gboolean
13395qtdemux_is_streams_update (GstQTDemux * qtdemux)
13396{
13397 gint i;
13398
13399 /* Different length, updated */
13400 if (QTDEMUX_N_STREAMS (qtdemux) != qtdemux->old_streams->len)
13401 return TRUE;
13402
13403 /* streams in list are sorted in track-id order */
13404 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13405 /* Different stream-id, updated */
13406 if (g_strcmp0 (QTDEMUX_NTH_STREAM (qtdemux, i)->stream_id,
13407 QTDEMUX_NTH_OLD_STREAM (qtdemux, i)->stream_id))
13408 return TRUE;
13409 }
13410
13411 return FALSE;
13412}
13413
13414static gboolean
13415qtdemux_reuse_and_configure_stream (GstQTDemux * qtdemux,
13416 QtDemuxStream * oldstream, QtDemuxStream * newstream)
13417{
13418 /* Connect old stream's srcpad to new stream */
13419 newstream->pad = oldstream->pad;
13420 oldstream->pad = NULL;
13421
13422 /* unset new_stream to prevent stream-start event, unless we are EOS in which
13423 * case we need to force one through */
13424 newstream->new_stream = newstream->pad != NULL
13425 && GST_PAD_IS_EOS (newstream->pad);
13426
13427 return gst_qtdemux_configure_stream (qtdemux, newstream);
13428}
13429
13430static gboolean
13431qtdemux_update_streams (GstQTDemux * qtdemux)
13432{
13433 gint i;
13434 g_assert (qtdemux->streams_aware);
13435
13436 /* At below, figure out which stream in active_streams has identical stream-id
13437 * with that of in old_streams. If there is matching stream-id,
13438 * corresponding newstream will not be exposed again,
13439 * but demux will reuse srcpad of matched old stream
13440 *
13441 * active_streams : newly created streams from the latest moov
13442 * old_streams : existing streams (belong to previous moov)
13443 */
13444
13445 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13446 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
13447 QtDemuxStream *oldstream = NULL;
13448 guint target;
13449
13450 GST_DEBUG_OBJECT (qtdemux, "track-id %u, fourcc %" GST_FOURCC_FORMAT,
13451 stream->track_id, GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
13452
13453 if (g_ptr_array_find_with_equal_func (qtdemux->old_streams,
13454 stream->stream_id, (GEqualFunc) _stream_equal_func, &target)) {
13455 oldstream = QTDEMUX_NTH_OLD_STREAM (qtdemux, target);
13456
13457 /* null pad stream cannot be reused */
13458 if (oldstream->pad == NULL)
13459 oldstream = NULL;
13460 }
13461
13462 if (oldstream) {
13463 GST_DEBUG_OBJECT (qtdemux, "Reuse track-id %d", oldstream->track_id);
13464
13465 if (!qtdemux_reuse_and_configure_stream (qtdemux, oldstream, stream))
13466 return FALSE;
13467
13468 /* we don't need to preserve order of old streams */
13469 g_ptr_array_remove_fast (qtdemux->old_streams, oldstream);
13470 } else {
13471 GstTagList *list;
13472
13473 /* now we have all info and can expose */
13474 list = stream->stream_tags;
13475 stream->stream_tags = NULL;
13476 if (!gst_qtdemux_add_stream (qtdemux, stream, list))
13477 return FALSE;
13478 }
13479 }
13480
13481 return TRUE;
13482}
13483
13484/* Must be called with expose lock */
13485static GstFlowReturn
13486qtdemux_expose_streams (GstQTDemux * qtdemux)
13487{
13488 gint i;
13489
13490 GST_DEBUG_OBJECT (qtdemux, "exposing streams");
13491
13492 if (!qtdemux_is_streams_update (qtdemux)) {
13493 GST_DEBUG_OBJECT (qtdemux, "Reuse all streams");
13494 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13495 QtDemuxStream *new_stream = QTDEMUX_NTH_STREAM (qtdemux, i);
13496 QtDemuxStream *old_stream = QTDEMUX_NTH_OLD_STREAM (qtdemux, i);
13497 if (!qtdemux_reuse_and_configure_stream (qtdemux, old_stream, new_stream))
13498 return GST_FLOW_ERROR;
13499 }
13500
13501 g_ptr_array_set_size (qtdemux->old_streams, 0);
13502 qtdemux->need_segment = TRUE;
13503
13504 return GST_FLOW_OK;
13505 }
13506
13507 if (qtdemux->streams_aware) {
13508 if (!qtdemux_update_streams (qtdemux))
13509 return GST_FLOW_ERROR;
13510 } else {
13511 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13512 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
13513 GstTagList *list;
13514
13515 /* now we have all info and can expose */
13516 list = stream->stream_tags;
13517 stream->stream_tags = NULL;
13518 if (!gst_qtdemux_add_stream (qtdemux, stream, list))
13519 return GST_FLOW_ERROR;
13520
13521 }
13522 }
13523
13524 gst_qtdemux_guess_bitrate (qtdemux);
13525
13526 gst_element_no_more_pads (GST_ELEMENT_CAST (qtdemux));
13527
13528 /* If we have still old_streams, it's no more used stream */
13529 for (i = 0; i < qtdemux->old_streams->len; i++) {
13530 QtDemuxStream *stream = QTDEMUX_NTH_OLD_STREAM (qtdemux, i);
13531
13532 if (stream->pad) {
13533 GstEvent *event;
13534
13535 event = gst_event_new_eos ();
13536 if (qtdemux->segment_seqnum)
13537 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
13538
13539 gst_pad_push_event (stream->pad, event);
13540 }
13541 }
13542
13543 g_ptr_array_set_size (qtdemux->old_streams, 0);
13544
13545 /* check if we should post a redirect in case there is a single trak
13546 * and it is a redirecting trak */
13547 if (QTDEMUX_N_STREAMS (qtdemux) == 1 &&
13548 QTDEMUX_NTH_STREAM (qtdemux, 0)->redirect_uri != NULL) {
13549 GstMessage *m;
13550
13551 GST_INFO_OBJECT (qtdemux, "Issuing a redirect due to a single track with "
13552 "an external content");
13553 m = gst_message_new_element (GST_OBJECT_CAST (qtdemux),
13554 gst_structure_new ("redirect",
13555 "new-location", G_TYPE_STRING,
13556 QTDEMUX_NTH_STREAM (qtdemux, 0)->redirect_uri, NULL));
13557 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), m);
13558 g_free (qtdemux->redirect_location);
13559 qtdemux->redirect_location =
13560 g_strdup (QTDEMUX_NTH_STREAM (qtdemux, 0)->redirect_uri);
13561 }
13562
13563 g_ptr_array_foreach (qtdemux->active_streams,
13564 (GFunc) qtdemux_do_allocation, qtdemux);
13565
13566 qtdemux->need_segment = TRUE;
13567
13568 qtdemux->exposed = TRUE;
13569 return GST_FLOW_OK;
13570}
13571
13572typedef struct
13573{
13574 GstStructure *structure; /* helper for sort function */
13575 gchar *location;
13576 guint min_req_bitrate;
13577 guint min_req_qt_version;
13578} GstQtReference;
13579
13580static gint
13581qtdemux_redirects_sort_func (gconstpointer a, gconstpointer b)
13582{
13583 GstQtReference *ref_a = (GstQtReference *) a;
13584 GstQtReference *ref_b = (GstQtReference *) b;
13585
13586 if (ref_b->min_req_qt_version != ref_a->min_req_qt_version)
13587 return ref_b->min_req_qt_version - ref_a->min_req_qt_version;
13588
13589 /* known bitrates go before unknown; higher bitrates go first */
13590 return ref_b->min_req_bitrate - ref_a->min_req_bitrate;
13591}
13592
13593/* sort the redirects and post a message for the application.
13594 */
13595static void
13596qtdemux_process_redirects (GstQTDemux * qtdemux, GList * references)
13597{
13598 GstQtReference *best;
13599 GstStructure *s;
13600 GstMessage *msg;
13601 GValue list_val = { 0, };
13602 GList *l;
13603
13604 g_assert (references != NULL);
13605
13606 references = g_list_sort (references, qtdemux_redirects_sort_func);
13607
13608 best = (GstQtReference *) references->data;
13609
13610 g_value_init (&list_val, GST_TYPE_LIST);
13611
13612 for (l = references; l != NULL; l = l->next) {
13613 GstQtReference *ref = (GstQtReference *) l->data;
13614 GValue struct_val = { 0, };
13615
13616 ref->structure = gst_structure_new ("redirect",
13617 "new-location", G_TYPE_STRING, ref->location, NULL);
13618
13619 if (ref->min_req_bitrate > 0) {
13620 gst_structure_set (ref->structure, "minimum-bitrate", G_TYPE_INT,
13621 ref->min_req_bitrate, NULL);
13622 }
13623
13624 g_value_init (&struct_val, GST_TYPE_STRUCTURE);
13625 g_value_set_boxed (&struct_val, ref->structure);
13626 gst_value_list_append_value (&list_val, &struct_val);
13627 g_value_unset (&struct_val);
13628 /* don't free anything here yet, since we need best->structure below */
13629 }
13630
13631 g_assert (best != NULL);
13632 s = gst_structure_copy (best->structure);
13633
13634 if (g_list_length (references) > 1) {
13635 gst_structure_set_value (s, "locations", &list_val);
13636 }
13637
13638 g_value_unset (&list_val);
13639
13640 for (l = references; l != NULL; l = l->next) {
13641 GstQtReference *ref = (GstQtReference *) l->data;
13642
13643 gst_structure_free (ref->structure);
13644 g_free (ref->location);
13645 g_free (ref);
13646 }
13647 g_list_free (references);
13648
13649 GST_INFO_OBJECT (qtdemux, "posting redirect message: %" GST_PTR_FORMAT, s);
13650 g_free (qtdemux->redirect_location);
13651 qtdemux->redirect_location =
13652 g_strdup (gst_structure_get_string (s, "new-location"));
13653 msg = gst_message_new_element (GST_OBJECT_CAST (qtdemux), s);
13654 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
13655}
13656
13657/* look for redirect nodes, collect all redirect information and
13658 * process it.
13659 */
13660static gboolean
13661qtdemux_parse_redirects (GstQTDemux * qtdemux)
13662{
13663 GNode *rmra, *rmda, *rdrf;
13664
13665 rmra = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_rmra);
13666 if (rmra) {
13667 GList *redirects = NULL;
13668
13669 rmda = qtdemux_tree_get_child_by_type (rmra, FOURCC_rmda);
13670 while (rmda) {
13671 GstQtReference ref = { NULL, NULL, 0, 0 };
13672 GNode *rmdr, *rmvc;
13673
13674 if ((rmdr = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmdr))) {
13675 ref.min_req_bitrate = QT_UINT32 ((guint8 *) rmdr->data + 12);
13676 GST_LOG_OBJECT (qtdemux, "data rate atom, required bitrate = %u",
13677 ref.min_req_bitrate);
13678 }
13679
13680 if ((rmvc = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmvc))) {
13681 guint32 package = QT_FOURCC ((guint8 *) rmvc->data + 12);
13682 guint version = QT_UINT32 ((guint8 *) rmvc->data + 16);
13683
13684#ifndef GST_DISABLE_GST_DEBUG
13685 guint bitmask = QT_UINT32 ((guint8 *) rmvc->data + 20);
13686#endif
13687 guint check_type = QT_UINT16 ((guint8 *) rmvc->data + 24);
13688
13689 GST_LOG_OBJECT (qtdemux,
13690 "version check atom [%" GST_FOURCC_FORMAT "], version=0x%08x"
13691 ", mask=%08x, check_type=%u", GST_FOURCC_ARGS (package), version,
13692 bitmask, check_type);
13693 if (package == FOURCC_qtim && check_type == 0) {
13694 ref.min_req_qt_version = version;
13695 }
13696 }
13697
13698 rdrf = qtdemux_tree_get_child_by_type (rmda, FOURCC_rdrf);
13699 if (rdrf) {
13700 guint32 ref_type;
13701 guint8 *ref_data;
13702 guint ref_len;
13703
13704 ref_len = QT_UINT32 ((guint8 *) rdrf->data);
13705 if (ref_len > 20) {
13706 ref_type = QT_FOURCC ((guint8 *) rdrf->data + 12);
13707 ref_data = (guint8 *) rdrf->data + 20;
13708 if (ref_type == FOURCC_alis) {
13709 guint record_len, record_version, fn_len;
13710
13711 if (ref_len > 70) {
13712 /* MacOSX alias record, google for alias-layout.txt */
13713 record_len = QT_UINT16 (ref_data + 4);
13714 record_version = QT_UINT16 (ref_data + 4 + 2);
13715 fn_len = QT_UINT8 (ref_data + 50);
13716 if (record_len > 50 && record_version == 2 && fn_len > 0) {
13717 ref.location = g_strndup ((gchar *) ref_data + 51, fn_len);
13718 }
13719 } else {
13720 GST_WARNING_OBJECT (qtdemux, "Invalid rdrf/alis size (%u < 70)",
13721 ref_len);
13722 }
13723 } else if (ref_type == FOURCC_url_) {
13724 ref.location = g_strndup ((gchar *) ref_data, ref_len - 8);
13725 } else {
13726 GST_DEBUG_OBJECT (qtdemux,
13727 "unknown rdrf reference type %" GST_FOURCC_FORMAT,
13728 GST_FOURCC_ARGS (ref_type));
13729 }
13730 if (ref.location != NULL) {
13731 GST_INFO_OBJECT (qtdemux, "New location: %s", ref.location);
13732 redirects =
13733 g_list_prepend (redirects, g_memdup2 (&ref, sizeof (ref)));
13734 } else {
13735 GST_WARNING_OBJECT (qtdemux,
13736 "Failed to extract redirect location from rdrf atom");
13737 }
13738 } else {
13739 GST_WARNING_OBJECT (qtdemux, "Invalid rdrf size (%u < 20)", ref_len);
13740 }
13741 }
13742
13743 /* look for others */
13744 rmda = qtdemux_tree_get_sibling_by_type (rmda, FOURCC_rmda);
13745 }
13746
13747 if (redirects != NULL) {
13748 qtdemux_process_redirects (qtdemux, redirects);
13749 }
13750 }
13751 return TRUE;
13752}
13753
13754static GstTagList *
13755qtdemux_add_container_format (GstQTDemux * qtdemux, GstTagList * tags)
13756{
13757 const gchar *fmt;
13758
13759 if (tags == NULL) {
13760 tags = gst_tag_list_new_empty ();
13761 gst_tag_list_set_scope (tags, GST_TAG_SCOPE_GLOBAL);
13762 }
13763
13764 if (qtdemux->major_brand == FOURCC_mjp2)
13765 fmt = "Motion JPEG 2000";
13766 else if ((qtdemux->major_brand & 0xffff) == FOURCC_3g__)
13767 fmt = "3GP";
13768 else if (qtdemux->major_brand == FOURCC_qt__)
13769 fmt = "Quicktime";
13770 else if (qtdemux->fragmented)
13771 fmt = "ISO fMP4";
13772 else
13773 fmt = "ISO MP4/M4A";
13774
13775 GST_LOG_OBJECT (qtdemux, "mapped %" GST_FOURCC_FORMAT " to '%s'",
13776 GST_FOURCC_ARGS (qtdemux->major_brand), fmt);
13777
13778 gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_CONTAINER_FORMAT,
13779 fmt, NULL);
13780
13781 return tags;
13782}
13783
13784/* we have read the complete moov node now.
13785 * This function parses all of the relevant info, creates the traks and
13786 * prepares all data structures for playback
13787 */
13788static gboolean
13789qtdemux_parse_tree (GstQTDemux * qtdemux)
13790{
13791 GNode *mvhd;
13792 GNode *trak;
13793 GNode *udta;
13794 GNode *mvex;
13795 GNode *pssh;
13796 guint64 creation_time;
13797 GstDateTime *datetime = NULL;
13798 gint version;
13799
13800 /* make sure we have a usable taglist */
13801 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
13802
13803 mvhd = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvhd);
13804 if (mvhd == NULL) {
13805 GST_LOG_OBJECT (qtdemux, "No mvhd node found, looking for redirects.");
13806 return qtdemux_parse_redirects (qtdemux);
13807 }
13808
13809 version = QT_UINT8 ((guint8 *) mvhd->data + 8);
13810 if (version == 1) {
13811 creation_time = QT_UINT64 ((guint8 *) mvhd->data + 12);
13812 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 28);
13813 qtdemux->duration = QT_UINT64 ((guint8 *) mvhd->data + 32);
13814 } else if (version == 0) {
13815 creation_time = QT_UINT32 ((guint8 *) mvhd->data + 12);
13816 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 20);
13817 qtdemux->duration = QT_UINT32 ((guint8 *) mvhd->data + 24);
13818 } else {
13819 GST_WARNING_OBJECT (qtdemux, "Unhandled mvhd version %d", version);
13820 return FALSE;
13821 }
13822
13823 /* Moving qt creation time (secs since 1904) to unix time */
13824 if (creation_time != 0) {
13825 /* Try to use epoch first as it should be faster and more commonly found */
13826 if (creation_time >= QTDEMUX_SECONDS_FROM_1904_TO_1970) {
13827 gint64 now_s;
13828
13829 creation_time -= QTDEMUX_SECONDS_FROM_1904_TO_1970;
13830 /* some data cleansing sanity */
13831 now_s = g_get_real_time () / G_USEC_PER_SEC;
13832 if (now_s + 24 * 3600 < creation_time) {
13833 GST_DEBUG_OBJECT (qtdemux, "discarding bogus future creation time");
13834 } else {
13835 datetime = gst_date_time_new_from_unix_epoch_utc (creation_time);
13836 }
13837 } else {
13838 GDateTime *base_dt = g_date_time_new_utc (1904, 1, 1, 0, 0, 0);
13839 GDateTime *dt, *dt_local;
13840
13841 dt = g_date_time_add_seconds (base_dt, creation_time);
13842 dt_local = g_date_time_to_local (dt);
13843 datetime = gst_date_time_new_from_g_date_time (dt_local);
13844
13845 g_date_time_unref (base_dt);
13846 g_date_time_unref (dt);
13847 }
13848 }
13849 if (datetime) {
13850 /* Use KEEP as explicit tags should have a higher priority than mvhd tag */
13851 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_KEEP, GST_TAG_DATE_TIME,
13852 datetime, NULL);
13853 gst_date_time_unref (datetime);
13854 }
13855
13856 GST_INFO_OBJECT (qtdemux, "timescale: %u", qtdemux->timescale);
13857 GST_INFO_OBJECT (qtdemux, "duration: %" G_GUINT64_FORMAT, qtdemux->duration);
13858
13859 /* check for fragmented file and get some (default) data */
13860 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
13861 if (mvex) {
13862 GNode *mehd;
13863 GstByteReader mehd_data;
13864
13865 /* let track parsing or anyone know weird stuff might happen ... */
13866 qtdemux->fragmented = TRUE;
13867
13868 /* compensate for total duration */
13869 mehd = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_mehd, &mehd_data);
13870 if (mehd)
13871 qtdemux_parse_mehd (qtdemux, &mehd_data);
13872 }
13873
13874 /* Update the movie segment duration, unless it was directly given to us
13875 * by upstream. Otherwise let it as is, as we don't want to mangle the
13876 * duration provided by upstream that may come e.g. from a MPD file. */
13877 if (!qtdemux->upstream_format_is_time) {
13878 GstClockTime duration;
13879 /* set duration in the segment info */
13880 gst_qtdemux_get_duration (qtdemux, &duration);
13881 qtdemux->segment.duration = duration;
13882 /* also do not exceed duration; stop is set that way post seek anyway,
13883 * and segment activation falls back to duration,
13884 * whereas loop only checks stop, so let's align this here as well */
13885 qtdemux->segment.stop = duration;
13886 }
13887
13888 /* parse all traks */
13889 trak = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_trak);
13890 while (trak) {
13891 qtdemux_parse_trak (qtdemux, trak);
13892 /* iterate all siblings */
13893 trak = qtdemux_tree_get_sibling_by_type (trak, FOURCC_trak);
13894 }
13895
13896 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
13897
13898 /* find tags */
13899 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_udta);
13900 if (udta) {
13901 qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
13902 } else {
13903 GST_LOG_OBJECT (qtdemux, "No udta node found.");
13904 }
13905
13906 /* maybe also some tags in meta box */
13907 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_meta);
13908 if (udta) {
13909 GST_DEBUG_OBJECT (qtdemux, "Parsing meta box for tags.");
13910 qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
13911 } else {
13912 GST_LOG_OBJECT (qtdemux, "No meta node found.");
13913 }
13914
13915 /* parse any protection system info */
13916 pssh = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_pssh);
13917 while (pssh) {
13918 GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
13919 qtdemux_parse_pssh (qtdemux, pssh);
13920 pssh = qtdemux_tree_get_sibling_by_type (pssh, FOURCC_pssh);
13921 }
13922
13923 qtdemux->tag_list = qtdemux_add_container_format (qtdemux, qtdemux->tag_list);
13924
13925 return TRUE;
13926}
13927
13928/* taken from ffmpeg */
13929static int
13930read_descr_size (guint8 * ptr, guint8 * end, guint8 ** end_out)
13931{
13932 int count = 4;
13933 int len = 0;
13934
13935 while (count--) {
13936 int c;
13937
13938 if (ptr >= end)
13939 return -1;
13940
13941 c = *ptr++;
13942 len = (len << 7) | (c & 0x7f);
13943 if (!(c & 0x80))
13944 break;
13945 }
13946 *end_out = ptr;
13947 return len;
13948}
13949
13950static GList *
13951parse_xiph_stream_headers (GstQTDemux * qtdemux, gpointer codec_data,
13952 gsize codec_data_size)
13953{
13954 GList *list = NULL;
13955 guint8 *p = codec_data;
13956 gint i, offset, num_packets;
13957 guint *length, last;
13958
13959 GST_MEMDUMP_OBJECT (qtdemux, "xiph codec data", codec_data, codec_data_size);
13960
13961 if (codec_data == NULL || codec_data_size == 0)
13962 goto error;
13963
13964 /* start of the stream and vorbis audio or theora video, need to
13965 * send the codec_priv data as first three packets */
13966 num_packets = p[0] + 1;
13967 GST_DEBUG_OBJECT (qtdemux,
13968 "%u stream headers, total length=%" G_GSIZE_FORMAT " bytes",
13969 (guint) num_packets, codec_data_size);
13970
13971 /* Let's put some limits, Don't think there even is a xiph codec
13972 * with more than 3-4 headers */
13973 if (G_UNLIKELY (num_packets > 16)) {
13974 GST_WARNING_OBJECT (qtdemux,
13975 "Unlikely number of xiph headers, most likely not valid");
13976 goto error;
13977 }
13978
13979 length = g_alloca (num_packets * sizeof (guint));
13980 last = 0;
13981 offset = 1;
13982
13983 /* first packets, read length values */
13984 for (i = 0; i < num_packets - 1; i++) {
13985 length[i] = 0;
13986 while (offset < codec_data_size) {
13987 length[i] += p[offset];
13988 if (p[offset++] != 0xff)
13989 break;
13990 }
13991 last += length[i];
13992 }
13993 if (offset + last > codec_data_size)
13994 goto error;
13995
13996 /* last packet is the remaining size */
13997 length[i] = codec_data_size - offset - last;
13998
13999 for (i = 0; i < num_packets; i++) {
14000 GstBuffer *hdr;
14001
14002 GST_DEBUG_OBJECT (qtdemux, "buffer %d: %u bytes", i, (guint) length[i]);
14003
14004 if (offset + length[i] > codec_data_size)
14005 goto error;
14006
14007 hdr = gst_buffer_new_memdup (p + offset, length[i]);
14008 list = g_list_append (list, hdr);
14009
14010 offset += length[i];
14011 }
14012
14013 return list;
14014
14015 /* ERRORS */
14016error:
14017 {
14018 if (list != NULL)
14019 g_list_free_full (list, (GDestroyNotify) gst_buffer_unref);
14020 return NULL;
14021 }
14022
14023}
14024
14025/* this can change the codec originally present in @list */
14026static void
14027gst_qtdemux_handle_esds (GstQTDemux * qtdemux, QtDemuxStream * stream,
14028 QtDemuxStreamStsdEntry * entry, GNode * esds, GstTagList * list)
14029{
14030 int len = QT_UINT32 (esds->data);
14031 guint8 *ptr = esds->data;
14032 guint8 *end = ptr + len;
14033 int tag;
14034 guint8 *data_ptr = NULL;
14035 int data_len = 0;
14036 guint8 object_type_id = 0;
14037 guint8 stream_type = 0;
14038 const char *codec_name = NULL;
14039 GstCaps *caps = NULL;
14040
14041 GST_MEMDUMP_OBJECT (qtdemux, "esds", ptr, len);
14042 ptr += 8;
14043 GST_DEBUG_OBJECT (qtdemux, "version/flags = %08x", QT_UINT32 (ptr));
14044 ptr += 4;
14045 while (ptr + 1 < end) {
14046 tag = QT_UINT8 (ptr);
14047 GST_DEBUG_OBJECT (qtdemux, "tag = %02x", tag);
14048 ptr++;
14049 len = read_descr_size (ptr, end, &ptr);
14050 GST_DEBUG_OBJECT (qtdemux, "len = %d", len);
14051
14052 /* Check the stated amount of data is available for reading */
14053 if (len < 0 || ptr + len > end)
14054 break;
14055
14056 switch (tag) {
14057 case ES_DESCRIPTOR_TAG:
14058 GST_DEBUG_OBJECT (qtdemux, "ID 0x%04x", QT_UINT16 (ptr));
14059 GST_DEBUG_OBJECT (qtdemux, "priority 0x%04x", QT_UINT8 (ptr + 2));
14060 ptr += 3;
14061 break;
14062 case DECODER_CONFIG_DESC_TAG:{
14063 guint max_bitrate, avg_bitrate;
14064
14065 object_type_id = QT_UINT8 (ptr);
14066 stream_type = QT_UINT8 (ptr + 1) >> 2;
14067 max_bitrate = QT_UINT32 (ptr + 5);
14068 avg_bitrate = QT_UINT32 (ptr + 9);
14069 GST_DEBUG_OBJECT (qtdemux, "object_type_id %02x", object_type_id);
14070 GST_DEBUG_OBJECT (qtdemux, "stream_type %02x", stream_type);
14071 GST_DEBUG_OBJECT (qtdemux, "buffer_size_db %02x", QT_UINT24 (ptr + 2));
14072 GST_DEBUG_OBJECT (qtdemux, "max bitrate %u", max_bitrate);
14073 GST_DEBUG_OBJECT (qtdemux, "avg bitrate %u", avg_bitrate);
14074 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
14075 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
14076 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
14077 }
14078 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
14079 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
14080 avg_bitrate, NULL);
14081 }
14082 ptr += 13;
14083 break;
14084 }
14085 case DECODER_SPECIFIC_INFO_TAG:
14086 GST_MEMDUMP_OBJECT (qtdemux, "data", ptr, len);
14087 if (object_type_id == 0xe0 && len == 0x40) {
14088 guint8 *data;
14089 GstStructure *s;
14090 guint32 clut[16];
14091 gint i;
14092
14093 GST_DEBUG_OBJECT (qtdemux,
14094 "Have VOBSUB palette. Creating palette event");
14095 /* move to decConfigDescr data and read palette */
14096 data = ptr;
14097 for (i = 0; i < 16; i++) {
14098 clut[i] = QT_UINT32 (data);
14099 data += 4;
14100 }
14101
14102 s = gst_structure_new ("application/x-gst-dvd", "event",
14103 G_TYPE_STRING, "dvd-spu-clut-change",
14104 "clut00", G_TYPE_INT, clut[0], "clut01", G_TYPE_INT, clut[1],
14105 "clut02", G_TYPE_INT, clut[2], "clut03", G_TYPE_INT, clut[3],
14106 "clut04", G_TYPE_INT, clut[4], "clut05", G_TYPE_INT, clut[5],
14107 "clut06", G_TYPE_INT, clut[6], "clut07", G_TYPE_INT, clut[7],
14108 "clut08", G_TYPE_INT, clut[8], "clut09", G_TYPE_INT, clut[9],
14109 "clut10", G_TYPE_INT, clut[10], "clut11", G_TYPE_INT, clut[11],
14110 "clut12", G_TYPE_INT, clut[12], "clut13", G_TYPE_INT, clut[13],
14111 "clut14", G_TYPE_INT, clut[14], "clut15", G_TYPE_INT, clut[15],
14112 NULL);
14113
14114 /* store event and trigger custom processing */
14115 stream->pending_event =
14116 gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s);
14117 } else {
14118 /* Generic codec_data handler puts it on the caps */
14119 data_ptr = ptr;
14120 data_len = len;
14121 }
14122
14123 ptr += len;
14124 break;
14125 case SL_CONFIG_DESC_TAG:
14126 GST_DEBUG_OBJECT (qtdemux, "data %02x", QT_UINT8 (ptr));
14127 ptr += 1;
14128 break;
14129 default:
14130 GST_DEBUG_OBJECT (qtdemux, "Unknown/unhandled descriptor tag %02x",
14131 tag);
14132 GST_MEMDUMP_OBJECT (qtdemux, "descriptor data", ptr, len);
14133 ptr += len;
14134 break;
14135 }
14136 }
14137
14138 /* object_type_id in the esds atom in mp4a and mp4v tells us which codec is
14139 * in use, and should also be used to override some other parameters for some
14140 * codecs. */
14141 switch (object_type_id) {
14142 case 0x20: /* MPEG-4 */
14143 /* 4 bytes for the visual_object_sequence_start_code and 1 byte for the
14144 * profile_and_level_indication */
14145 if (data_ptr != NULL && data_len >= 5 &&
14146 GST_READ_UINT32_BE (data_ptr) == 0x000001b0) {
14147 gst_codec_utils_mpeg4video_caps_set_level_and_profile (entry->caps,
14148 data_ptr + 4, data_len - 4);
14149 }
14150 break; /* Nothing special needed here */
14151 case 0x21: /* H.264 */
14152 codec_name = "H.264 / AVC";
14153 caps = gst_caps_new_simple ("video/x-h264",
14154 "stream-format", G_TYPE_STRING, "avc",
14155 "alignment", G_TYPE_STRING, "au", NULL);
14156 break;
14157 case 0x40: /* AAC (any) */
14158 case 0x66: /* AAC Main */
14159 case 0x67: /* AAC LC */
14160 case 0x68: /* AAC SSR */
14161 /* Override channels and rate based on the codec_data, as it's often
14162 * wrong. */
14163 /* Only do so for basic setup without HE-AAC extension */
14164 if (data_ptr && data_len == 2) {
14165 guint channels, rate;
14166
14167 channels = gst_codec_utils_aac_get_channels (data_ptr, data_len);
14168 if (channels > 0)
14169 entry->n_channels = channels;
14170
14171 rate = gst_codec_utils_aac_get_sample_rate (data_ptr, data_len);
14172 if (rate > 0)
14173 entry->rate = rate;
14174 }
14175
14176 /* Set level and profile if possible */
14177 if (data_ptr != NULL && data_len >= 2) {
14178 gst_codec_utils_aac_caps_set_level_and_profile (entry->caps,
14179 data_ptr, data_len);
14180 } else {
14181 const gchar *profile_str = NULL;
14182 GstBuffer *buffer;
14183 GstMapInfo map;
14184 guint8 *codec_data;
14185 gint rate_idx, profile;
14186
14187 /* No codec_data, let's invent something.
14188 * FIXME: This is wrong for SBR! */
14189
14190 GST_WARNING_OBJECT (qtdemux, "No codec_data for AAC available");
14191
14192 buffer = gst_buffer_new_and_alloc (2);
14193 gst_buffer_map (buffer, &map, GST_MAP_WRITE);
14194 codec_data = map.data;
14195
14196 rate_idx =
14197 gst_codec_utils_aac_get_index_from_sample_rate (CUR_STREAM
14198 (stream)->rate);
14199
14200 switch (object_type_id) {
14201 case 0x66:
14202 profile_str = "main";
14203 profile = 0;
14204 break;
14205 case 0x67:
14206 profile_str = "lc";
14207 profile = 1;
14208 break;
14209 case 0x68:
14210 profile_str = "ssr";
14211 profile = 2;
14212 break;
14213 default:
14214 profile = 3;
14215 break;
14216 }
14217
14218 codec_data[0] = ((profile + 1) << 3) | ((rate_idx & 0xE) >> 1);
14219 codec_data[1] =
14220 ((rate_idx & 0x1) << 7) | (CUR_STREAM (stream)->n_channels << 3);
14221
14222 gst_buffer_unmap (buffer, &map);
14223 gst_caps_set_simple (CUR_STREAM (stream)->caps, "codec_data",
14224 GST_TYPE_BUFFER, buffer, NULL);
14225 gst_buffer_unref (buffer);
14226
14227 if (profile_str) {
14228 gst_caps_set_simple (CUR_STREAM (stream)->caps, "profile",
14229 G_TYPE_STRING, profile_str, NULL);
14230 }
14231 }
14232 break;
14233 case 0x60: /* MPEG-2, various profiles */
14234 case 0x61:
14235 case 0x62:
14236 case 0x63:
14237 case 0x64:
14238 case 0x65:
14239 codec_name = "MPEG-2 video";
14240 caps = gst_caps_new_simple ("video/mpeg",
14241 "mpegversion", G_TYPE_INT, 2,
14242 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14243 break;
14244 case 0x69: /* MPEG-2 BC audio */
14245 case 0x6B: /* MPEG-1 audio */
14246 caps = gst_caps_new_simple ("audio/mpeg",
14247 "mpegversion", G_TYPE_INT, 1, NULL);
14248 codec_name = "MPEG-1 audio";
14249 break;
14250 case 0x6A: /* MPEG-1 */
14251 codec_name = "MPEG-1 video";
14252 caps = gst_caps_new_simple ("video/mpeg",
14253 "mpegversion", G_TYPE_INT, 1,
14254 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14255 break;
14256 case 0x6C: /* MJPEG */
14257 caps =
14258 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
14259 NULL);
14260 codec_name = "Motion-JPEG";
14261 break;
14262 case 0x6D: /* PNG */
14263 caps =
14264 gst_caps_new_simple ("image/png", "parsed", G_TYPE_BOOLEAN, TRUE,
14265 NULL);
14266 codec_name = "PNG still images";
14267 break;
14268 case 0x6E: /* JPEG2000 */
14269 codec_name = "JPEG-2000";
14270 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
14271 break;
14272 case 0xA4: /* Dirac */
14273 codec_name = "Dirac";
14274 caps = gst_caps_new_empty_simple ("video/x-dirac");
14275 break;
14276 case 0xA5: /* AC3 */
14277 codec_name = "AC-3 audio";
14278 caps = gst_caps_new_simple ("audio/x-ac3",
14279 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14280 break;
14281 case 0xA9: /* AC3 */
14282 codec_name = "DTS audio";
14283 caps = gst_caps_new_simple ("audio/x-dts",
14284 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14285 break;
14286 case 0xDD:
14287 if (stream_type == 0x05 && data_ptr) {
14288 GList *headers =
14289 parse_xiph_stream_headers (qtdemux, data_ptr, data_len);
14290 if (headers) {
14291 GList *tmp;
14292 GValue arr_val = G_VALUE_INIT;
14293 GValue buf_val = G_VALUE_INIT;
14294 GstStructure *s;
14295
14296 /* Let's assume it's vorbis if it's an audio stream of type 0xdd and we have codec data that extracts properly */
14297 codec_name = "Vorbis";
14298 caps = gst_caps_new_empty_simple ("audio/x-vorbis");
14299 g_value_init (&arr_val, GST_TYPE_ARRAY);
14300 g_value_init (&buf_val, GST_TYPE_BUFFER);
14301 for (tmp = headers; tmp; tmp = tmp->next) {
14302 g_value_set_boxed (&buf_val, (GstBuffer *) tmp->data);
14303 gst_value_array_append_value (&arr_val, &buf_val);
14304 }
14305 s = gst_caps_get_structure (caps, 0);
14306 gst_structure_take_value (s, "streamheader", &arr_val);
14307 g_value_unset (&buf_val);
14308 g_list_free (headers);
14309
14310 data_ptr = NULL;
14311 data_len = 0;
14312 }
14313 }
14314 break;
14315 case 0xE1: /* QCELP */
14316 /* QCELP, the codec_data is a riff tag (little endian) with
14317 * 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). */
14318 caps = gst_caps_new_empty_simple ("audio/qcelp");
14319 codec_name = "QCELP";
14320 break;
14321 default:
14322 break;
14323 }
14324
14325 /* If we have a replacement caps, then change our caps for this stream */
14326 if (caps) {
14327 gst_caps_unref (entry->caps);
14328 entry->caps = caps;
14329 }
14330
14331 if (codec_name && list)
14332 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
14333 GST_TAG_AUDIO_CODEC, codec_name, NULL);
14334
14335 /* Add the codec_data attribute to caps, if we have it */
14336 if (data_ptr) {
14337 GstBuffer *buffer;
14338
14339 buffer = gst_buffer_new_and_alloc (data_len);
14340 gst_buffer_fill (buffer, 0, data_ptr, data_len);
14341
14342 GST_DEBUG_OBJECT (qtdemux, "setting codec_data from esds");
14343 GST_MEMDUMP_OBJECT (qtdemux, "codec_data from esds", data_ptr, data_len);
14344
14345 gst_caps_set_simple (entry->caps, "codec_data", GST_TYPE_BUFFER,
14346 buffer, NULL);
14347 gst_buffer_unref (buffer);
14348 }
14349
14350}
14351
14352static inline GstCaps *
14353_get_unknown_codec_name (const gchar * type, guint32 fourcc)
14354{
14355 GstCaps *caps;
14356 guint i;
14357 char *s, fourstr[5];
14358
14359 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
14360 for (i = 0; i < 4; i++) {
14361 if (!g_ascii_isalnum (fourstr[i]))
14362 fourstr[i] = '_';
14363 }
14364 s = g_strdup_printf ("%s/x-gst-fourcc-%s", type, g_strstrip (fourstr));
14365 caps = gst_caps_new_empty_simple (s);
14366 g_free (s);
14367 return caps;
14368}
14369
14370#define _codec(name) \
14371 do { \
14372 if (codec_name) { \
14373 *codec_name = g_strdup (name); \
14374 } \
14375 } while (0)
14376
14377static GstCaps *
14378qtdemux_video_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
14379 QtDemuxStreamStsdEntry * entry, guint32 fourcc,
14380 const guint8 * stsd_entry_data, gchar ** codec_name)
14381{
14382 GstCaps *caps = NULL;
14383 GstVideoFormat format = GST_VIDEO_FORMAT_UNKNOWN;
14384
14385 switch (fourcc) {
14386 case FOURCC_png:
14387 _codec ("PNG still images");
14388 caps = gst_caps_new_empty_simple ("image/png");
14389 break;
14390 case FOURCC_jpeg:
14391 _codec ("JPEG still images");
14392 caps =
14393 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
14394 NULL);
14395 break;
14396 case GST_MAKE_FOURCC ('m', 'j', 'p', 'a'):
14397 case GST_MAKE_FOURCC ('A', 'V', 'D', 'J'):
14398 case GST_MAKE_FOURCC ('M', 'J', 'P', 'G'):
14399 case GST_MAKE_FOURCC ('d', 'm', 'b', '1'):
14400 _codec ("Motion-JPEG");
14401 caps =
14402 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
14403 NULL);
14404 break;
14405 case GST_MAKE_FOURCC ('m', 'j', 'p', 'b'):
14406 _codec ("Motion-JPEG format B");
14407 caps = gst_caps_new_empty_simple ("video/x-mjpeg-b");
14408 break;
14409 case FOURCC_mjp2:
14410 _codec ("JPEG-2000");
14411 /* override to what it should be according to spec, avoid palette_data */
14412 entry->bits_per_sample = 24;
14413 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
14414 break;
14415 case FOURCC_SVQ3:
14416 _codec ("Sorensen video v.3");
14417 caps = gst_caps_new_simple ("video/x-svq",
14418 "svqversion", G_TYPE_INT, 3, NULL);
14419 break;
14420 case GST_MAKE_FOURCC ('s', 'v', 'q', 'i'):
14421 case GST_MAKE_FOURCC ('S', 'V', 'Q', '1'):
14422 _codec ("Sorensen video v.1");
14423 caps = gst_caps_new_simple ("video/x-svq",
14424 "svqversion", G_TYPE_INT, 1, NULL);
14425 break;
14426 case GST_MAKE_FOURCC ('W', 'R', 'A', 'W'):
14427 caps = gst_caps_new_empty_simple ("video/x-raw");
14428 gst_caps_set_simple (caps, "format", G_TYPE_STRING, "RGB8P", NULL);
14429 _codec ("Windows Raw RGB");
14430 stream->alignment = 32;
14431 break;
14432 case FOURCC_raw_:
14433 {
14434 guint16 bps;
14435
14436 bps = QT_UINT16 (stsd_entry_data + 82);
14437 switch (bps) {
14438 case 15:
14439 format = GST_VIDEO_FORMAT_RGB15;
14440 break;
14441 case 16:
14442 format = GST_VIDEO_FORMAT_RGB16;
14443 break;
14444 case 24:
14445 format = GST_VIDEO_FORMAT_RGB;
14446 break;
14447 case 32:
14448 format = GST_VIDEO_FORMAT_ARGB;
14449 break;
14450 default:
14451 /* unknown */
14452 break;
14453 }
14454 break;
14455 }
14456 case GST_MAKE_FOURCC ('y', 'v', '1', '2'):
14457 format = GST_VIDEO_FORMAT_I420;
14458 break;
14459 case GST_MAKE_FOURCC ('y', 'u', 'v', '2'):
14460 case GST_MAKE_FOURCC ('Y', 'u', 'v', '2'):
14461 format = GST_VIDEO_FORMAT_I420;
14462 break;
14463 case FOURCC_2vuy:
14464 case GST_MAKE_FOURCC ('2', 'V', 'u', 'y'):
14465 format = GST_VIDEO_FORMAT_UYVY;
14466 break;
14467 case GST_MAKE_FOURCC ('v', '3', '0', '8'):
14468 format = GST_VIDEO_FORMAT_v308;
14469 break;
14470 case GST_MAKE_FOURCC ('v', '2', '1', '6'):
14471 format = GST_VIDEO_FORMAT_v216;
14472 break;
14473 case FOURCC_v210:
14474 format = GST_VIDEO_FORMAT_v210;
14475 break;
14476 case GST_MAKE_FOURCC ('r', '2', '1', '0'):
14477 format = GST_VIDEO_FORMAT_r210;
14478 break;
14479 /* Packed YUV 4:4:4 10 bit in 32 bits, complex
14480 case GST_MAKE_FOURCC ('v', '4', '1', '0'):
14481 format = GST_VIDEO_FORMAT_v410;
14482 break;
14483 */
14484 /* Packed YUV 4:4:4:4 8 bit in 32 bits
14485 * but different order than AYUV
14486 case GST_MAKE_FOURCC ('v', '4', '0', '8'):
14487 format = GST_VIDEO_FORMAT_v408;
14488 break;
14489 */
14490 case GST_MAKE_FOURCC ('m', 'p', 'e', 'g'):
14491 case GST_MAKE_FOURCC ('m', 'p', 'g', '1'):
14492 _codec ("MPEG-1 video");
14493 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
14494 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14495 break;
14496 case GST_MAKE_FOURCC ('h', 'd', 'v', '1'): /* HDV 720p30 */
14497 case GST_MAKE_FOURCC ('h', 'd', 'v', '2'): /* HDV 1080i60 */
14498 case GST_MAKE_FOURCC ('h', 'd', 'v', '3'): /* HDV 1080i50 */
14499 case GST_MAKE_FOURCC ('h', 'd', 'v', '4'): /* HDV 720p24 */
14500 case GST_MAKE_FOURCC ('h', 'd', 'v', '5'): /* HDV 720p25 */
14501 case GST_MAKE_FOURCC ('h', 'd', 'v', '6'): /* HDV 1080p24 */
14502 case GST_MAKE_FOURCC ('h', 'd', 'v', '7'): /* HDV 1080p25 */
14503 case GST_MAKE_FOURCC ('h', 'd', 'v', '8'): /* HDV 1080p30 */
14504 case GST_MAKE_FOURCC ('h', 'd', 'v', '9'): /* HDV 720p60 */
14505 case GST_MAKE_FOURCC ('h', 'd', 'v', 'a'): /* HDV 720p50 */
14506 case GST_MAKE_FOURCC ('m', 'x', '5', 'n'): /* MPEG2 IMX NTSC 525/60 50mb/s produced by FCP */
14507 case GST_MAKE_FOURCC ('m', 'x', '5', 'p'): /* MPEG2 IMX PAL 625/60 50mb/s produced by FCP */
14508 case GST_MAKE_FOURCC ('m', 'x', '4', 'n'): /* MPEG2 IMX NTSC 525/60 40mb/s produced by FCP */
14509 case GST_MAKE_FOURCC ('m', 'x', '4', 'p'): /* MPEG2 IMX PAL 625/60 40mb/s produced by FCP */
14510 case GST_MAKE_FOURCC ('m', 'x', '3', 'n'): /* MPEG2 IMX NTSC 525/60 30mb/s produced by FCP */
14511 case GST_MAKE_FOURCC ('m', 'x', '3', 'p'): /* MPEG2 IMX PAL 625/50 30mb/s produced by FCP */
14512 case GST_MAKE_FOURCC ('x', 'd', 'v', '1'): /* XDCAM HD 720p30 35Mb/s */
14513 case GST_MAKE_FOURCC ('x', 'd', 'v', '2'): /* XDCAM HD 1080i60 35Mb/s */
14514 case GST_MAKE_FOURCC ('x', 'd', 'v', '3'): /* XDCAM HD 1080i50 35Mb/s */
14515 case GST_MAKE_FOURCC ('x', 'd', 'v', '4'): /* XDCAM HD 720p24 35Mb/s */
14516 case GST_MAKE_FOURCC ('x', 'd', 'v', '5'): /* XDCAM HD 720p25 35Mb/s */
14517 case GST_MAKE_FOURCC ('x', 'd', 'v', '6'): /* XDCAM HD 1080p24 35Mb/s */
14518 case GST_MAKE_FOURCC ('x', 'd', 'v', '7'): /* XDCAM HD 1080p25 35Mb/s */
14519 case GST_MAKE_FOURCC ('x', 'd', 'v', '8'): /* XDCAM HD 1080p30 35Mb/s */
14520 case GST_MAKE_FOURCC ('x', 'd', 'v', '9'): /* XDCAM HD 720p60 35Mb/s */
14521 case GST_MAKE_FOURCC ('x', 'd', 'v', 'a'): /* XDCAM HD 720p50 35Mb/s */
14522 case GST_MAKE_FOURCC ('x', 'd', 'v', 'b'): /* XDCAM EX 1080i60 50Mb/s CBR */
14523 case GST_MAKE_FOURCC ('x', 'd', 'v', 'c'): /* XDCAM EX 1080i50 50Mb/s CBR */
14524 case GST_MAKE_FOURCC ('x', 'd', 'v', 'd'): /* XDCAM HD 1080p24 50Mb/s CBR */
14525 case GST_MAKE_FOURCC ('x', 'd', 'v', 'e'): /* XDCAM HD 1080p25 50Mb/s CBR */
14526 case GST_MAKE_FOURCC ('x', 'd', 'v', 'f'): /* XDCAM HD 1080p30 50Mb/s CBR */
14527 case GST_MAKE_FOURCC ('x', 'd', '5', '1'): /* XDCAM HD422 720p30 50Mb/s CBR */
14528 case GST_MAKE_FOURCC ('x', 'd', '5', '4'): /* XDCAM HD422 720p24 50Mb/s CBR */
14529 case GST_MAKE_FOURCC ('x', 'd', '5', '5'): /* XDCAM HD422 720p25 50Mb/s CBR */
14530 case GST_MAKE_FOURCC ('x', 'd', '5', '9'): /* XDCAM HD422 720p60 50Mb/s CBR */
14531 case GST_MAKE_FOURCC ('x', 'd', '5', 'a'): /* XDCAM HD422 720p50 50Mb/s CBR */
14532 case GST_MAKE_FOURCC ('x', 'd', '5', 'b'): /* XDCAM HD422 1080i50 50Mb/s CBR */
14533 case GST_MAKE_FOURCC ('x', 'd', '5', 'c'): /* XDCAM HD422 1080i50 50Mb/s CBR */
14534 case GST_MAKE_FOURCC ('x', 'd', '5', 'd'): /* XDCAM HD422 1080p24 50Mb/s CBR */
14535 case GST_MAKE_FOURCC ('x', 'd', '5', 'e'): /* XDCAM HD422 1080p25 50Mb/s CBR */
14536 case GST_MAKE_FOURCC ('x', 'd', '5', 'f'): /* XDCAM HD422 1080p30 50Mb/s CBR */
14537 case GST_MAKE_FOURCC ('x', 'd', 'h', 'd'): /* XDCAM HD 540p */
14538 case GST_MAKE_FOURCC ('x', 'd', 'h', '2'): /* XDCAM HD422 540p */
14539 case GST_MAKE_FOURCC ('A', 'V', 'm', 'p'): /* AVID IMX PAL */
14540 case GST_MAKE_FOURCC ('m', 'p', 'g', '2'): /* AVID IMX PAL */
14541 case GST_MAKE_FOURCC ('m', 'p', '2', 'v'): /* AVID IMX PAL */
14542 case GST_MAKE_FOURCC ('m', '2', 'v', '1'):
14543 _codec ("MPEG-2 video");
14544 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 2,
14545 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14546 break;
14547 case GST_MAKE_FOURCC ('g', 'i', 'f', ' '):
14548 _codec ("GIF still images");
14549 caps = gst_caps_new_empty_simple ("image/gif");
14550 break;
14551 case FOURCC_h263:
14552 case GST_MAKE_FOURCC ('H', '2', '6', '3'):
14553 case FOURCC_s263:
14554 case GST_MAKE_FOURCC ('U', '2', '6', '3'):
14555 _codec ("H.263");
14556 /* ffmpeg uses the height/width props, don't know why */
14557 caps = gst_caps_new_simple ("video/x-h263",
14558 "variant", G_TYPE_STRING, "itu", NULL);
14559 break;
14560 case FOURCC_mp4v:
14561 case FOURCC_MP4V:
14562 _codec ("MPEG-4 video");
14563 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
14564 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14565 break;
14566 case GST_MAKE_FOURCC ('3', 'i', 'v', 'd'):
14567 case GST_MAKE_FOURCC ('3', 'I', 'V', 'D'):
14568 _codec ("Microsoft MPEG-4 4.3"); /* FIXME? */
14569 caps = gst_caps_new_simple ("video/x-msmpeg",
14570 "msmpegversion", G_TYPE_INT, 43, NULL);
14571 break;
14572 case GST_MAKE_FOURCC ('D', 'I', 'V', '3'):
14573 _codec ("DivX 3");
14574 caps = gst_caps_new_simple ("video/x-divx",
14575 "divxversion", G_TYPE_INT, 3, NULL);
14576 break;
14577 case GST_MAKE_FOURCC ('D', 'I', 'V', 'X'):
14578 case GST_MAKE_FOURCC ('d', 'i', 'v', 'x'):
14579 _codec ("DivX 4");
14580 caps = gst_caps_new_simple ("video/x-divx",
14581 "divxversion", G_TYPE_INT, 4, NULL);
14582 break;
14583 case GST_MAKE_FOURCC ('D', 'X', '5', '0'):
14584 _codec ("DivX 5");
14585 caps = gst_caps_new_simple ("video/x-divx",
14586 "divxversion", G_TYPE_INT, 5, NULL);
14587 break;
14588
14589 case GST_MAKE_FOURCC ('F', 'F', 'V', '1'):
14590 _codec ("FFV1");
14591 caps = gst_caps_new_simple ("video/x-ffv",
14592 "ffvversion", G_TYPE_INT, 1, NULL);
14593 break;
14594
14595 case GST_MAKE_FOURCC ('3', 'I', 'V', '1'):
14596 case GST_MAKE_FOURCC ('3', 'I', 'V', '2'):
14597 case FOURCC_XVID:
14598 case FOURCC_xvid:
14599 case FOURCC_FMP4:
14600 case FOURCC_fmp4:
14601 case GST_MAKE_FOURCC ('U', 'M', 'P', '4'):
14602 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
14603 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14604 _codec ("MPEG-4");
14605 break;
14606
14607 case GST_MAKE_FOURCC ('c', 'v', 'i', 'd'):
14608 _codec ("Cinepak");
14609 caps = gst_caps_new_empty_simple ("video/x-cinepak");
14610 break;
14611 case GST_MAKE_FOURCC ('q', 'd', 'r', 'w'):
14612 _codec ("Apple QuickDraw");
14613 caps = gst_caps_new_empty_simple ("video/x-qdrw");
14614 break;
14615 case GST_MAKE_FOURCC ('r', 'p', 'z', 'a'):
14616 _codec ("Apple video");
14617 caps = gst_caps_new_empty_simple ("video/x-apple-video");
14618 break;
14619 case FOURCC_H264:
14620 case FOURCC_avc1:
14621 case FOURCC_dva1:
14622 _codec ("H.264 / AVC");
14623 caps = gst_caps_new_simple ("video/x-h264",
14624 "stream-format", G_TYPE_STRING, "avc",
14625 "alignment", G_TYPE_STRING, "au", NULL);
14626 break;
14627 case FOURCC_avc3:
14628 case FOURCC_dvav:
14629 _codec ("H.264 / AVC");
14630 caps = gst_caps_new_simple ("video/x-h264",
14631 "stream-format", G_TYPE_STRING, "avc3",
14632 "alignment", G_TYPE_STRING, "au", NULL);
14633 break;
14634 case FOURCC_H265:
14635 case FOURCC_hvc1:
14636 case FOURCC_dvh1:
14637 _codec ("H.265 / HEVC");
14638 caps = gst_caps_new_simple ("video/x-h265",
14639 "stream-format", G_TYPE_STRING, "hvc1",
14640 "alignment", G_TYPE_STRING, "au", NULL);
14641 break;
14642 case FOURCC_hev1:
14643 case FOURCC_dvhe:
14644 _codec ("H.265 / HEVC");
14645 caps = gst_caps_new_simple ("video/x-h265",
14646 "stream-format", G_TYPE_STRING, "hev1",
14647 "alignment", G_TYPE_STRING, "au", NULL);
14648 break;
14649 case FOURCC_rle_:
14650 _codec ("Run-length encoding");
14651 caps = gst_caps_new_simple ("video/x-rle",
14652 "layout", G_TYPE_STRING, "quicktime", NULL);
14653 break;
14654 case FOURCC_WRLE:
14655 _codec ("Run-length encoding");
14656 caps = gst_caps_new_simple ("video/x-rle",
14657 "layout", G_TYPE_STRING, "microsoft", NULL);
14658 break;
14659 case GST_MAKE_FOURCC ('I', 'V', '3', '2'):
14660 case GST_MAKE_FOURCC ('i', 'v', '3', '2'):
14661 _codec ("Indeo Video 3");
14662 caps = gst_caps_new_simple ("video/x-indeo",
14663 "indeoversion", G_TYPE_INT, 3, NULL);
14664 break;
14665 case GST_MAKE_FOURCC ('I', 'V', '4', '1'):
14666 case GST_MAKE_FOURCC ('i', 'v', '4', '1'):
14667 _codec ("Intel Video 4");
14668 caps = gst_caps_new_simple ("video/x-indeo",
14669 "indeoversion", G_TYPE_INT, 4, NULL);
14670 break;
14671 case FOURCC_dvcp:
14672 case FOURCC_dvc_:
14673 case GST_MAKE_FOURCC ('d', 'v', 's', 'd'):
14674 case GST_MAKE_FOURCC ('D', 'V', 'S', 'D'):
14675 case GST_MAKE_FOURCC ('d', 'v', 'c', 's'):
14676 case GST_MAKE_FOURCC ('D', 'V', 'C', 'S'):
14677 case GST_MAKE_FOURCC ('d', 'v', '2', '5'):
14678 case GST_MAKE_FOURCC ('d', 'v', 'p', 'p'):
14679 _codec ("DV Video");
14680 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 25,
14681 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14682 break;
14683 case FOURCC_dv5n: /* DVCPRO50 NTSC */
14684 case FOURCC_dv5p: /* DVCPRO50 PAL */
14685 _codec ("DVCPro50 Video");
14686 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 50,
14687 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14688 break;
14689 case GST_MAKE_FOURCC ('d', 'v', 'h', '5'): /* DVCPRO HD 50i produced by FCP */
14690 case GST_MAKE_FOURCC ('d', 'v', 'h', '6'): /* DVCPRO HD 60i produced by FCP */
14691 _codec ("DVCProHD Video");
14692 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 100,
14693 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14694 break;
14695 case GST_MAKE_FOURCC ('s', 'm', 'c', ' '):
14696 _codec ("Apple Graphics (SMC)");
14697 caps = gst_caps_new_empty_simple ("video/x-smc");
14698 break;
14699 case GST_MAKE_FOURCC ('V', 'P', '3', '1'):
14700 _codec ("VP3");
14701 caps = gst_caps_new_empty_simple ("video/x-vp3");
14702 break;
14703 case GST_MAKE_FOURCC ('V', 'P', '6', 'F'):
14704 _codec ("VP6 Flash");
14705 caps = gst_caps_new_empty_simple ("video/x-vp6-flash");
14706 break;
14707 case FOURCC_XiTh:
14708 _codec ("Theora");
14709 caps = gst_caps_new_empty_simple ("video/x-theora");
14710 /* theora uses one byte of padding in the data stream because it does not
14711 * allow 0 sized packets while theora does */
14712 entry->padding = 1;
14713 break;
14714 case FOURCC_drac:
14715 _codec ("Dirac");
14716 caps = gst_caps_new_empty_simple ("video/x-dirac");
14717 break;
14718 case GST_MAKE_FOURCC ('t', 'i', 'f', 'f'):
14719 _codec ("TIFF still images");
14720 caps = gst_caps_new_empty_simple ("image/tiff");
14721 break;
14722 case GST_MAKE_FOURCC ('i', 'c', 'o', 'd'):
14723 _codec ("Apple Intermediate Codec");
14724 caps = gst_caps_from_string ("video/x-apple-intermediate-codec");
14725 break;
14726 case GST_MAKE_FOURCC ('A', 'V', 'd', 'n'):
14727 _codec ("AVID DNxHD");
14728 caps = gst_caps_from_string ("video/x-dnxhd");
14729 break;
14730 case FOURCC_VP80:
14731 case FOURCC_vp08:
14732 _codec ("On2 VP8");
14733 caps = gst_caps_from_string ("video/x-vp8");
14734 break;
14735 case FOURCC_vp09:
14736 _codec ("Google VP9");
14737 caps = gst_caps_from_string ("video/x-vp9");
14738 break;
14739 case FOURCC_apcs:
14740 _codec ("Apple ProRes LT");
14741 caps =
14742 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "lt",
14743 NULL);
14744 break;
14745 case FOURCC_apch:
14746 _codec ("Apple ProRes HQ");
14747 caps =
14748 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "hq",
14749 NULL);
14750 break;
14751 case FOURCC_apcn:
14752 _codec ("Apple ProRes");
14753 caps =
14754 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14755 "standard", NULL);
14756 break;
14757 case FOURCC_apco:
14758 _codec ("Apple ProRes Proxy");
14759 caps =
14760 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14761 "proxy", NULL);
14762 break;
14763 case FOURCC_ap4h:
14764 _codec ("Apple ProRes 4444");
14765 caps =
14766 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14767 "4444", NULL);
14768
14769 /* 24 bits per sample = an alpha channel is coded but image is always opaque */
14770 if (entry->bits_per_sample > 0) {
14771 gst_caps_set_simple (caps, "depth", G_TYPE_INT, entry->bits_per_sample,
14772 NULL);
14773 }
14774 break;
14775 case FOURCC_ap4x:
14776 _codec ("Apple ProRes 4444 XQ");
14777 caps =
14778 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14779 "4444xq", NULL);
14780
14781 /* 24 bits per sample = an alpha channel is coded but image is always opaque */
14782 if (entry->bits_per_sample > 0) {
14783 gst_caps_set_simple (caps, "depth", G_TYPE_INT, entry->bits_per_sample,
14784 NULL);
14785 }
14786 break;
14787 case FOURCC_cfhd:
14788 _codec ("GoPro CineForm");
14789 caps = gst_caps_from_string ("video/x-cineform");
14790 break;
14791 case FOURCC_vc_1:
14792 case FOURCC_ovc1:
14793 _codec ("VC-1");
14794 caps = gst_caps_new_simple ("video/x-wmv",
14795 "wmvversion", G_TYPE_INT, 3, "format", G_TYPE_STRING, "WVC1", NULL);
14796 break;
14797 case FOURCC_av01:
14798 _codec ("AV1");
14799 caps = gst_caps_new_simple ("video/x-av1",
14800 "stream-format", G_TYPE_STRING, "obu-stream",
14801 "alignment", G_TYPE_STRING, "tu", NULL);
14802 break;
14803 case GST_MAKE_FOURCC ('k', 'p', 'c', 'd'):
14804 default:
14805 {
14806 caps = _get_unknown_codec_name ("video", fourcc);
14807 break;
14808 }
14809 }
14810
14811 if (format != GST_VIDEO_FORMAT_UNKNOWN) {
14812 GstVideoInfo info;
14813
14814 gst_video_info_init (&info);
14815 gst_video_info_set_format (&info, format, entry->width, entry->height);
14816
14817 caps = gst_video_info_to_caps (&info);
14818 *codec_name = gst_pb_utils_get_codec_description (caps);
14819
14820 /* enable clipping for raw video streams */
14821 stream->need_clip = TRUE;
14822 stream->alignment = 32;
14823 }
14824
14825 return caps;
14826}
14827
14828static guint
14829round_up_pow2 (guint n)
14830{
14831 n = n - 1;
14832 n = n | (n >> 1);
14833 n = n | (n >> 2);
14834 n = n | (n >> 4);
14835 n = n | (n >> 8);
14836 n = n | (n >> 16);
14837 return n + 1;
14838}
14839
14840static GstCaps *
14841qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
14842 QtDemuxStreamStsdEntry * entry, guint32 fourcc, const guint8 * data,
14843 int len, gchar ** codec_name)
14844{
14845 GstCaps *caps;
14846 const GstStructure *s;
14847 const gchar *name;
14848 gint endian = 0;
14849 GstAudioFormat format = 0;
14850 gint depth;
14851
14852 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
14853
14854 depth = entry->bytes_per_packet * 8;
14855
14856 switch (fourcc) {
14857 case GST_MAKE_FOURCC ('N', 'O', 'N', 'E'):
14858 case FOURCC_raw_:
14859 /* 8-bit audio is unsigned */
14860 if (depth == 8)
14861 format = GST_AUDIO_FORMAT_U8;
14862 /* otherwise it's signed and big-endian just like 'twos' */
14863 case FOURCC_twos:
14864 endian = G_BIG_ENDIAN;
14865 /* fall-through */
14866 case FOURCC_sowt:
14867 {
14868 gchar *str;
14869
14870 if (!endian)
14871 endian = G_LITTLE_ENDIAN;
14872
14873 if (!format)
14874 format = gst_audio_format_build_integer (TRUE, endian, depth, depth);
14875
14876 str = g_strdup_printf ("Raw %d-bit PCM audio", depth);
14877 _codec (str);
14878 g_free (str);
14879
14880 caps = gst_caps_new_simple ("audio/x-raw",
14881 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
14882 "layout", G_TYPE_STRING, "interleaved", NULL);
14883 stream->alignment = GST_ROUND_UP_8 (depth);
14884 stream->alignment = round_up_pow2 (stream->alignment);
14885 break;
14886 }
14887 case FOURCC_fl64:
14888 _codec ("Raw 64-bit floating-point audio");
14889 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
14890 * endian later */
14891 caps = gst_caps_new_simple ("audio/x-raw",
14892 "format", G_TYPE_STRING, "F64BE",
14893 "layout", G_TYPE_STRING, "interleaved", NULL);
14894 stream->alignment = 8;
14895 break;
14896 case FOURCC_fl32:
14897 _codec ("Raw 32-bit floating-point audio");
14898 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
14899 * endian later */
14900 caps = gst_caps_new_simple ("audio/x-raw",
14901 "format", G_TYPE_STRING, "F32BE",
14902 "layout", G_TYPE_STRING, "interleaved", NULL);
14903 stream->alignment = 4;
14904 break;
14905 case FOURCC_in24:
14906 _codec ("Raw 24-bit PCM audio");
14907 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
14908 * endian later */
14909 caps = gst_caps_new_simple ("audio/x-raw",
14910 "format", G_TYPE_STRING, "S24BE",
14911 "layout", G_TYPE_STRING, "interleaved", NULL);
14912 stream->alignment = 4;
14913 break;
14914 case FOURCC_in32:
14915 _codec ("Raw 32-bit PCM audio");
14916 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
14917 * endian later */
14918 caps = gst_caps_new_simple ("audio/x-raw",
14919 "format", G_TYPE_STRING, "S32BE",
14920 "layout", G_TYPE_STRING, "interleaved", NULL);
14921 stream->alignment = 4;
14922 break;
14923 case FOURCC_s16l:
14924 _codec ("Raw 16-bit PCM audio");
14925 caps = gst_caps_new_simple ("audio/x-raw",
14926 "format", G_TYPE_STRING, "S16LE",
14927 "layout", G_TYPE_STRING, "interleaved", NULL);
14928 stream->alignment = 2;
14929 break;
14930 case FOURCC_ulaw:
14931 _codec ("Mu-law audio");
14932 caps = gst_caps_new_empty_simple ("audio/x-mulaw");
14933 break;
14934 case FOURCC_alaw:
14935 _codec ("A-law audio");
14936 caps = gst_caps_new_empty_simple ("audio/x-alaw");
14937 break;
14938 case 0x0200736d:
14939 case 0x6d730002:
14940 _codec ("Microsoft ADPCM");
14941 /* Microsoft ADPCM-ACM code 2 */
14942 caps = gst_caps_new_simple ("audio/x-adpcm",
14943 "layout", G_TYPE_STRING, "microsoft", NULL);
14944 break;
14945 case 0x1100736d:
14946 case 0x6d730011:
14947 _codec ("DVI/IMA ADPCM");
14948 caps = gst_caps_new_simple ("audio/x-adpcm",
14949 "layout", G_TYPE_STRING, "dvi", NULL);
14950 break;
14951 case 0x1700736d:
14952 case 0x6d730017:
14953 _codec ("DVI/Intel IMA ADPCM");
14954 /* FIXME DVI/Intel IMA ADPCM/ACM code 17 */
14955 caps = gst_caps_new_simple ("audio/x-adpcm",
14956 "layout", G_TYPE_STRING, "quicktime", NULL);
14957 break;
14958 case 0x5500736d:
14959 case 0x6d730055:
14960 /* MPEG layer 3, CBR only (pre QT4.1) */
14961 case FOURCC__mp3:
14962 case FOURCC_mp3_:
14963 _codec ("MPEG-1 layer 3");
14964 /* MPEG layer 3, CBR & VBR (QT4.1 and later) */
14965 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 3,
14966 "mpegversion", G_TYPE_INT, 1, NULL);
14967 break;
14968 case GST_MAKE_FOURCC ('.', 'm', 'p', '2'):
14969 _codec ("MPEG-1 layer 2");
14970 /* MPEG layer 2 */
14971 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 2,
14972 "mpegversion", G_TYPE_INT, 1, NULL);
14973 break;
14974 case 0x20736d:
14975 case GST_MAKE_FOURCC ('e', 'c', '-', '3'):
14976 _codec ("EAC-3 audio");
14977 caps = gst_caps_new_simple ("audio/x-eac3",
14978 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14979 entry->sampled = TRUE;
14980 break;
14981 case GST_MAKE_FOURCC ('s', 'a', 'c', '3'): // Nero Recode
14982 case FOURCC_ac_3:
14983 _codec ("AC-3 audio");
14984 caps = gst_caps_new_simple ("audio/x-ac3",
14985 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14986 entry->sampled = TRUE;
14987 break;
14988 case GST_MAKE_FOURCC ('d', 't', 's', 'c'):
14989 case GST_MAKE_FOURCC ('D', 'T', 'S', ' '):
14990 _codec ("DTS audio");
14991 caps = gst_caps_new_simple ("audio/x-dts",
14992 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14993 entry->sampled = TRUE;
14994 break;
14995 case GST_MAKE_FOURCC ('d', 't', 's', 'h'): // DTS-HD
14996 case GST_MAKE_FOURCC ('d', 't', 's', 'l'): // DTS-HD Lossless
14997 _codec ("DTS-HD audio");
14998 caps = gst_caps_new_simple ("audio/x-dts",
14999 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
15000 entry->sampled = TRUE;
15001 break;
zengliang.li469a5ca2024-05-16 12:03:55 +000015002 case GST_MAKE_FOURCC ('d', 't', 's', 'e'): // DTS Low Bit Rate (LBR)
15003 _codec ("DTS LBR audio");
15004 caps = gst_caps_new_simple ("audio/x-dts",
15005 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
15006 entry->sampled = TRUE;
15007 break;
zengliang.li5f31ef42024-05-16 08:27:38 +000015008 case FOURCC_MAC3:
15009 _codec ("MACE-3");
15010 caps = gst_caps_new_simple ("audio/x-mace",
15011 "maceversion", G_TYPE_INT, 3, NULL);
15012 break;
15013 case FOURCC_MAC6:
15014 _codec ("MACE-6");
15015 caps = gst_caps_new_simple ("audio/x-mace",
15016 "maceversion", G_TYPE_INT, 6, NULL);
15017 break;
15018 case GST_MAKE_FOURCC ('O', 'g', 'g', 'V'):
15019 /* ogg/vorbis */
15020 caps = gst_caps_new_empty_simple ("application/ogg");
15021 break;
15022 case GST_MAKE_FOURCC ('d', 'v', 'c', 'a'):
15023 _codec ("DV audio");
15024 caps = gst_caps_new_empty_simple ("audio/x-dv");
15025 break;
15026 case FOURCC_mp4a:
15027 _codec ("MPEG-4 AAC audio");
15028 caps = gst_caps_new_simple ("audio/mpeg",
15029 "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE,
15030 "stream-format", G_TYPE_STRING, "raw", NULL);
15031 break;
15032 case GST_MAKE_FOURCC ('Q', 'D', 'M', 'C'):
15033 _codec ("QDesign Music");
15034 caps = gst_caps_new_empty_simple ("audio/x-qdm");
15035 break;
15036 case FOURCC_QDM2:
15037 _codec ("QDesign Music v.2");
15038 /* FIXME: QDesign music version 2 (no constant) */
15039 if (FALSE && data) {
15040 caps = gst_caps_new_simple ("audio/x-qdm2",
15041 "framesize", G_TYPE_INT, QT_UINT32 (data + 52),
15042 "bitrate", G_TYPE_INT, QT_UINT32 (data + 40),
15043 "blocksize", G_TYPE_INT, QT_UINT32 (data + 44), NULL);
15044 } else {
15045 caps = gst_caps_new_empty_simple ("audio/x-qdm2");
15046 }
15047 break;
15048 case FOURCC_agsm:
15049 _codec ("GSM audio");
15050 caps = gst_caps_new_empty_simple ("audio/x-gsm");
15051 break;
15052 case FOURCC_samr:
15053 _codec ("AMR audio");
15054 caps = gst_caps_new_empty_simple ("audio/AMR");
15055 break;
15056 case FOURCC_sawb:
15057 _codec ("AMR-WB audio");
15058 caps = gst_caps_new_empty_simple ("audio/AMR-WB");
15059 break;
15060 case FOURCC_ima4:
15061 _codec ("Quicktime IMA ADPCM");
15062 caps = gst_caps_new_simple ("audio/x-adpcm",
15063 "layout", G_TYPE_STRING, "quicktime", NULL);
15064 break;
15065 case FOURCC_alac:
15066 _codec ("Apple lossless audio");
15067 caps = gst_caps_new_empty_simple ("audio/x-alac");
15068 break;
15069 case FOURCC_fLaC:
15070 _codec ("Free Lossless Audio Codec");
15071 caps = gst_caps_new_simple ("audio/x-flac",
15072 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
15073 break;
15074 case GST_MAKE_FOURCC ('Q', 'c', 'l', 'p'):
15075 _codec ("QualComm PureVoice");
15076 caps = gst_caps_from_string ("audio/qcelp");
15077 break;
15078 case FOURCC_wma_:
15079 case FOURCC_owma:
15080 _codec ("WMA");
15081 caps = gst_caps_new_empty_simple ("audio/x-wma");
15082 break;
15083 case FOURCC_opus:
15084 _codec ("Opus");
15085 caps = gst_caps_new_empty_simple ("audio/x-opus");
15086 break;
15087 case FOURCC_lpcm:
15088 {
15089 guint32 flags = 0;
15090 guint32 depth = 0;
15091 guint32 width = 0;
15092 GstAudioFormat format;
15093 enum
15094 {
15095 FLAG_IS_FLOAT = 0x1,
15096 FLAG_IS_BIG_ENDIAN = 0x2,
15097 FLAG_IS_SIGNED = 0x4,
15098 FLAG_IS_PACKED = 0x8,
15099 FLAG_IS_ALIGNED_HIGH = 0x10,
15100 FLAG_IS_NON_INTERLEAVED = 0x20
15101 };
15102 _codec ("Raw LPCM audio");
15103
15104 if (data && len >= 36) {
15105 depth = QT_UINT32 (data + 24);
15106 flags = QT_UINT32 (data + 28);
15107 width = QT_UINT32 (data + 32) * 8 / entry->n_channels;
15108 }
15109 if ((flags & FLAG_IS_FLOAT) == 0) {
15110 if (depth == 0)
15111 depth = 16;
15112 if (width == 0)
15113 width = 16;
15114 if ((flags & FLAG_IS_ALIGNED_HIGH))
15115 depth = width;
15116
15117 format = gst_audio_format_build_integer ((flags & FLAG_IS_SIGNED) ?
15118 TRUE : FALSE, (flags & FLAG_IS_BIG_ENDIAN) ?
15119 G_BIG_ENDIAN : G_LITTLE_ENDIAN, width, depth);
15120 caps = gst_caps_new_simple ("audio/x-raw",
15121 "format", G_TYPE_STRING,
15122 format !=
15123 GST_AUDIO_FORMAT_UNKNOWN ? gst_audio_format_to_string (format) :
15124 "UNKNOWN", "layout", G_TYPE_STRING,
15125 (flags & FLAG_IS_NON_INTERLEAVED) ? "non-interleaved" :
15126 "interleaved", NULL);
15127 stream->alignment = GST_ROUND_UP_8 (depth);
15128 stream->alignment = round_up_pow2 (stream->alignment);
15129 } else {
15130 if (width == 0)
15131 width = 32;
15132 if (width == 64) {
15133 if (flags & FLAG_IS_BIG_ENDIAN)
15134 format = GST_AUDIO_FORMAT_F64BE;
15135 else
15136 format = GST_AUDIO_FORMAT_F64LE;
15137 } else {
15138 if (flags & FLAG_IS_BIG_ENDIAN)
15139 format = GST_AUDIO_FORMAT_F32BE;
15140 else
15141 format = GST_AUDIO_FORMAT_F32LE;
15142 }
15143 caps = gst_caps_new_simple ("audio/x-raw",
15144 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
15145 "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
15146 "non-interleaved" : "interleaved", NULL);
15147 stream->alignment = width / 8;
15148 }
15149 break;
15150 }
15151 case GST_MAKE_FOURCC ('a', 'c', '-', '4'):
15152 {
15153 _codec ("AC4");
15154 caps = gst_caps_new_empty_simple ("audio/x-ac4");
15155 break;
15156 }
15157 case GST_MAKE_FOURCC ('q', 't', 'v', 'r'):
15158 /* ? */
15159 default:
15160 {
15161 caps = _get_unknown_codec_name ("audio", fourcc);
15162 break;
15163 }
15164 }
15165
15166 if (caps) {
15167 GstCaps *templ_caps =
15168 gst_static_pad_template_get_caps (&gst_qtdemux_audiosrc_template);
15169 GstCaps *intersection = gst_caps_intersect (caps, templ_caps);
15170 gst_caps_unref (caps);
15171 gst_caps_unref (templ_caps);
15172 caps = intersection;
15173 }
15174
15175 /* enable clipping for raw audio streams */
15176 s = gst_caps_get_structure (caps, 0);
15177 name = gst_structure_get_name (s);
15178 if (g_str_has_prefix (name, "audio/x-raw")) {
15179 stream->need_clip = TRUE;
15180 stream->min_buffer_size = 1024 * entry->bytes_per_frame;
15181 stream->max_buffer_size = 4096 * entry->bytes_per_frame;
15182 GST_DEBUG ("setting min/max buffer sizes to %d/%d", stream->min_buffer_size,
15183 stream->max_buffer_size);
15184 }
15185 return caps;
15186}
15187
15188static GstCaps *
15189qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
15190 QtDemuxStreamStsdEntry * entry, guint32 fourcc,
15191 const guint8 * stsd_entry_data, gchar ** codec_name)
15192{
15193 GstCaps *caps;
15194
15195 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
15196
15197 switch (fourcc) {
15198 case FOURCC_mp4s:
15199 _codec ("DVD subtitle");
15200 caps = gst_caps_new_empty_simple ("subpicture/x-dvd");
15201 stream->process_func = gst_qtdemux_process_buffer_dvd;
15202 break;
15203 case FOURCC_text:
15204 _codec ("Quicktime timed text");
15205 goto text;
15206 case FOURCC_tx3g:
15207 _codec ("3GPP timed text");
15208 text:
15209 caps = gst_caps_new_simple ("text/x-raw", "format", G_TYPE_STRING,
15210 "utf8", NULL);
15211 /* actual text piece needs to be extracted */
15212 stream->process_func = gst_qtdemux_process_buffer_text;
15213 break;
15214 case FOURCC_stpp:
15215 _codec ("XML subtitles");
15216 caps = gst_caps_new_empty_simple ("application/ttml+xml");
15217 break;
15218 case FOURCC_wvtt:
15219 {
15220 GstBuffer *buffer;
15221 const gchar *buf = "WEBVTT\n\n";
15222
15223 _codec ("WebVTT subtitles");
15224 caps = gst_caps_new_empty_simple ("application/x-subtitle-vtt");
15225 stream->process_func = gst_qtdemux_process_buffer_wvtt;
15226
15227 /* FIXME: Parse the vttC atom and get the entire WEBVTT header */
15228 buffer = gst_buffer_new_and_alloc (8);
15229 gst_buffer_fill (buffer, 0, buf, 8);
15230 stream->buffers = g_slist_append (stream->buffers, buffer);
15231
15232 break;
15233 }
15234 case FOURCC_c608:
15235 _codec ("CEA 608 Closed Caption");
15236 caps =
15237 gst_caps_new_simple ("closedcaption/x-cea-608", "format",
15238 G_TYPE_STRING, "s334-1a", NULL);
15239 stream->process_func = gst_qtdemux_process_buffer_clcp;
15240 stream->need_split = TRUE;
15241 break;
15242 case FOURCC_c708:
15243 _codec ("CEA 708 Closed Caption");
15244 caps =
15245 gst_caps_new_simple ("closedcaption/x-cea-708", "format",
15246 G_TYPE_STRING, "cdp", NULL);
15247 stream->process_func = gst_qtdemux_process_buffer_clcp;
15248 break;
15249
15250 default:
15251 {
15252 caps = _get_unknown_codec_name ("text", fourcc);
15253 break;
15254 }
15255 }
15256 return caps;
15257}
15258
15259static GstCaps *
15260qtdemux_generic_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
15261 QtDemuxStreamStsdEntry * entry, guint32 fourcc,
15262 const guint8 * stsd_entry_data, gchar ** codec_name)
15263{
15264 GstCaps *caps;
15265
15266 switch (fourcc) {
15267 case FOURCC_m1v:
15268 _codec ("MPEG 1 video");
15269 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
15270 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
15271 break;
15272 default:
15273 caps = NULL;
15274 break;
15275 }
15276 return caps;
15277}
15278
15279static void
15280gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux,
15281 const gchar * system_id)
15282{
15283 gint i;
15284
15285 if (!qtdemux->protection_system_ids)
15286 qtdemux->protection_system_ids =
15287 g_ptr_array_new_with_free_func ((GDestroyNotify) g_free);
15288 /* Check whether we already have an entry for this system ID. */
15289 for (i = 0; i < qtdemux->protection_system_ids->len; ++i) {
15290 const gchar *id = g_ptr_array_index (qtdemux->protection_system_ids, i);
15291 if (g_ascii_strcasecmp (system_id, id) == 0) {
15292 return;
15293 }
15294 }
15295 GST_DEBUG_OBJECT (qtdemux, "Adding cenc protection system ID %s", system_id);
15296 g_ptr_array_add (qtdemux->protection_system_ids, g_ascii_strdown (system_id,
15297 -1));
15298}