1 /* 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 #ifdef OHOS_OPT_PERFORMANCE
86 // ohos.opt.performance.0005
87 // add trace
88 #include "gst_trace.h"
89 #endif
90 /* max. size considered 'sane' for non-mdat atoms */
91 #define QTDEMUX_MAX_ATOM_SIZE (32*1024*1024)
92
93 /* if the sample index is larger than this, something is likely wrong */
94 #define QTDEMUX_MAX_SAMPLE_INDEX_SIZE (200*1024*1024)
95
96 /* For converting qt creation times to unix epoch times */
97 #define QTDEMUX_SECONDS_PER_DAY (60 * 60 * 24)
98 #define QTDEMUX_LEAP_YEARS_FROM_1904_TO_1970 17
99 #define QTDEMUX_SECONDS_FROM_1904_TO_1970 (((1970 - 1904) * (guint64) 365 + \
100 QTDEMUX_LEAP_YEARS_FROM_1904_TO_1970) * QTDEMUX_SECONDS_PER_DAY)
101
102 #define QTDEMUX_TREE_NODE_FOURCC(n) (QT_FOURCC(((guint8 *) (n)->data) + 4))
103
104 #define STREAM_IS_EOS(s) ((s)->time_position == GST_CLOCK_TIME_NONE)
105
106 #define ABSDIFF(x, y) ( (x) > (y) ? ((x) - (y)) : ((y) - (x)) )
107
108 #define QTDEMUX_STREAM(s) ((QtDemuxStream *)(s))
109 #define QTDEMUX_N_STREAMS(demux) ((demux)->active_streams->len)
110 #define QTDEMUX_NTH_STREAM(demux,idx) \
111 QTDEMUX_STREAM(g_ptr_array_index((demux)->active_streams,idx))
112 #define QTDEMUX_NTH_OLD_STREAM(demux,idx) \
113 QTDEMUX_STREAM(g_ptr_array_index((demux)->old_streams,idx))
114
115 #define CUR_STREAM(s) (&((s)->stsd_entries[(s)->cur_stsd_entry_index]))
116
117 GST_DEBUG_CATEGORY (qtdemux_debug);
118 #define GST_CAT_DEFAULT qtdemux_debug
119
120 typedef struct _QtDemuxCencSampleSetInfo QtDemuxCencSampleSetInfo;
121 typedef struct _QtDemuxAavdEncryptionInfo QtDemuxAavdEncryptionInfo;
122
123 /* Macros for converting to/from timescale */
124 #define QTSTREAMTIME_TO_GSTTIME(stream, value) (gst_util_uint64_scale((value), GST_SECOND, (stream)->timescale))
125 #define GSTTIME_TO_QTSTREAMTIME(stream, value) (gst_util_uint64_scale((value), (stream)->timescale, GST_SECOND))
126
127 #define QTTIME_TO_GSTTIME(qtdemux, value) (gst_util_uint64_scale((value), GST_SECOND, (qtdemux)->timescale))
128 #define GSTTIME_TO_QTTIME(qtdemux, value) (gst_util_uint64_scale((value), (qtdemux)->timescale, GST_SECOND))
129
130 /* timestamp is the DTS */
131 #define QTSAMPLE_DTS(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp))
132 /* timestamp + offset + cslg_shift is the outgoing PTS */
133 #define QTSAMPLE_PTS(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp + (stream)->cslg_shift + (sample)->pts_offset))
134 /* timestamp + offset is the PTS used for internal seek calculations */
135 #define QTSAMPLE_PTS_NO_CSLG(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp + (sample)->pts_offset))
136 /* timestamp + duration - dts is the duration */
137 #define QTSAMPLE_DUR_DTS(stream, sample, dts) (QTSTREAMTIME_TO_GSTTIME ((stream), (sample)->timestamp + (sample)->duration) - (dts))
138
139 #define QTSAMPLE_KEYFRAME(stream,sample) ((stream)->all_keyframe || (sample)->keyframe)
140
141 #define QTDEMUX_EXPOSE_GET_LOCK(demux) (&((demux)->expose_lock))
142 #define QTDEMUX_EXPOSE_LOCK(demux) G_STMT_START { \
143 GST_TRACE("Locking from thread %p", g_thread_self()); \
144 g_mutex_lock (QTDEMUX_EXPOSE_GET_LOCK (demux)); \
145 GST_TRACE("Locked from thread %p", g_thread_self()); \
146 } G_STMT_END
147
148 #define QTDEMUX_EXPOSE_UNLOCK(demux) G_STMT_START { \
149 GST_TRACE("Unlocking from thread %p", g_thread_self()); \
150 g_mutex_unlock (QTDEMUX_EXPOSE_GET_LOCK (demux)); \
151 } G_STMT_END
152
153 /*
154 * Quicktime has tracks and segments. A track is a continuous piece of
155 * multimedia content. The track is not always played from start to finish but
156 * instead, pieces of the track are 'cut out' and played in sequence. This is
157 * what the segments do.
158 *
159 * Inside the track we have keyframes (K) and delta frames. The track has its
160 * own timing, which starts from 0 and extends to end. The position in the track
161 * is called the media_time.
162 *
163 * The segments now describe the pieces that should be played from this track
164 * and are basically tuples of media_time/duration/rate entries. We can have
165 * multiple segments and they are all played after one another. An example:
166 *
167 * segment 1: media_time: 1 second, duration: 1 second, rate 1
168 * segment 2: media_time: 3 second, duration: 2 second, rate 2
169 *
170 * To correctly play back this track, one must play: 1 second of media starting
171 * from media_time 1 followed by 2 seconds of media starting from media_time 3
172 * at a rate of 2.
173 *
174 * Each of the segments will be played at a specific time, the first segment at
175 * time 0, the second one after the duration of the first one, etc.. Note that
176 * the time in resulting playback is not identical to the media_time of the
177 * track anymore.
178 *
179 * Visually, assuming the track has 4 second of media_time:
180 *
181 * (a) (b) (c) (d)
182 * .-----------------------------------------------------------.
183 * track: | K.....K.........K........K.......K.......K...........K... |
184 * '-----------------------------------------------------------'
185 * 0 1 2 3 4
186 * .------------^ ^ .----------^ ^
187 * / .-------------' / .------------------'
188 * / / .-----' /
189 * .--------------. .--------------.
190 * | segment 1 | | segment 2 |
191 * '--------------' '--------------'
192 *
193 * The challenge here is to cut out the right pieces of the track for each of
194 * the playback segments. This fortunately can easily be done with the SEGMENT
195 * events of GStreamer.
196 *
197 * For playback of segment 1, we need to provide the decoder with the keyframe
198 * (a), in the above figure, but we must instruct it only to output the decoded
199 * data between second 1 and 2. We do this with a SEGMENT event for 1 to 2, time
200 * position set to the time of the segment: 0.
201 *
202 * We then proceed to push data from keyframe (a) to frame (b). The decoder
203 * decodes but clips all before media_time 1.
204 *
205 * After finishing a segment, we push out a new SEGMENT event with the clipping
206 * boundaries of the new data.
207 *
208 * This is a good usecase for the GStreamer accumulated SEGMENT events.
209 */
210
211 struct _QtDemuxSegment
212 {
213 /* global time and duration, all gst time */
214 GstClockTime time;
215 GstClockTime stop_time;
216 GstClockTime duration;
217 /* media time of trak, all gst time */
218 GstClockTime media_start;
219 GstClockTime media_stop;
220 gdouble rate;
221 /* Media start time in trak timescale units */
222 guint32 trak_media_start;
223 };
224
225 #define QTSEGMENT_IS_EMPTY(s) ((s)->media_start == GST_CLOCK_TIME_NONE)
226
227 /* Used with fragmented MP4 files (mfra atom) */
228 struct _QtDemuxRandomAccessEntry
229 {
230 GstClockTime ts;
231 guint64 moof_offset;
232 };
233
234
235 /* Contains properties and cryptographic info for a set of samples from a
236 * track protected using Common Encryption (cenc) */
237 struct _QtDemuxCencSampleSetInfo
238 {
239 GstStructure *default_properties;
240
241 /* @crypto_info holds one GstStructure per sample */
242 GPtrArray *crypto_info;
243 };
244
245 struct _QtDemuxAavdEncryptionInfo
246 {
247 GstStructure *default_properties;
248 };
249
250 static const gchar *
qt_demux_state_string(enum QtDemuxState state)251 qt_demux_state_string (enum QtDemuxState state)
252 {
253 switch (state) {
254 case QTDEMUX_STATE_INITIAL:
255 return "<INITIAL>";
256 case QTDEMUX_STATE_HEADER:
257 return "<HEADER>";
258 case QTDEMUX_STATE_MOVIE:
259 return "<MOVIE>";
260 case QTDEMUX_STATE_BUFFER_MDAT:
261 return "<BUFFER_MDAT>";
262 default:
263 return "<UNKNOWN>";
264 }
265 }
266
267 static GstFlowReturn qtdemux_add_fragmented_samples (GstQTDemux * qtdemux);
268
269 static void gst_qtdemux_check_send_pending_segment (GstQTDemux * demux);
270
271 static GstStaticPadTemplate gst_qtdemux_sink_template =
272 GST_STATIC_PAD_TEMPLATE ("sink",
273 GST_PAD_SINK,
274 GST_PAD_ALWAYS,
275 GST_STATIC_CAPS ("video/quicktime; video/mj2; audio/x-m4a; "
276 "application/x-3gp")
277 );
278
279 static GstStaticPadTemplate gst_qtdemux_videosrc_template =
280 GST_STATIC_PAD_TEMPLATE ("video_%u",
281 GST_PAD_SRC,
282 GST_PAD_SOMETIMES,
283 GST_STATIC_CAPS_ANY);
284
285 static GstStaticPadTemplate gst_qtdemux_audiosrc_template =
286 GST_STATIC_PAD_TEMPLATE ("audio_%u",
287 GST_PAD_SRC,
288 GST_PAD_SOMETIMES,
289 GST_STATIC_CAPS_ANY);
290
291 static GstStaticPadTemplate gst_qtdemux_subsrc_template =
292 GST_STATIC_PAD_TEMPLATE ("subtitle_%u",
293 GST_PAD_SRC,
294 GST_PAD_SOMETIMES,
295 GST_STATIC_CAPS_ANY);
296
297 #define gst_qtdemux_parent_class parent_class
298 G_DEFINE_TYPE (GstQTDemux, gst_qtdemux, GST_TYPE_ELEMENT);
299 GST_ELEMENT_REGISTER_DEFINE_WITH_CODE (qtdemux, "qtdemux",
300 GST_RANK_PRIMARY, GST_TYPE_QTDEMUX, isomp4_element_init (plugin));
301
302 static void gst_qtdemux_dispose (GObject * object);
303 static void gst_qtdemux_finalize (GObject * object);
304
305 static guint32
306 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
307 GstClockTime media_time);
308 static guint32
309 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
310 QtDemuxStream * str, gint64 media_offset);
311
312 #if 0
313 static void gst_qtdemux_set_index (GstElement * element, GstIndex * index);
314 static GstIndex *gst_qtdemux_get_index (GstElement * element);
315 #endif
316 static GstStateChangeReturn gst_qtdemux_change_state (GstElement * element,
317 GstStateChange transition);
318 static void gst_qtdemux_set_context (GstElement * element,
319 GstContext * context);
320 static gboolean qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent);
321 static gboolean qtdemux_sink_activate_mode (GstPad * sinkpad,
322 GstObject * parent, GstPadMode mode, gboolean active);
323
324 static void gst_qtdemux_loop (GstPad * pad);
325 static GstFlowReturn gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent,
326 GstBuffer * inbuf);
327 static gboolean gst_qtdemux_handle_sink_event (GstPad * pad, GstObject * parent,
328 GstEvent * event);
329 static gboolean gst_qtdemux_handle_sink_query (GstPad * pad, GstObject * parent,
330 GstQuery * query);
331 static gboolean gst_qtdemux_setcaps (GstQTDemux * qtdemux, GstCaps * caps);
332 static gboolean gst_qtdemux_configure_stream (GstQTDemux * qtdemux,
333 QtDemuxStream * stream);
334 static void gst_qtdemux_stream_check_and_change_stsd_index (GstQTDemux * demux,
335 QtDemuxStream * stream);
336 static GstFlowReturn gst_qtdemux_process_adapter (GstQTDemux * demux,
337 gboolean force);
338
339 static void gst_qtdemux_check_seekability (GstQTDemux * demux);
340
341 static gboolean qtdemux_parse_moov (GstQTDemux * qtdemux,
342 const guint8 * buffer, guint length);
343 static gboolean qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node,
344 const guint8 * buffer, guint length);
345 static gboolean qtdemux_parse_tree (GstQTDemux * qtdemux);
346
347 static void gst_qtdemux_handle_esds (GstQTDemux * qtdemux,
348 QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, GNode * esds,
349 GstTagList * list);
350 static GstCaps *qtdemux_video_caps (GstQTDemux * qtdemux,
351 QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, guint32 fourcc,
352 const guint8 * stsd_entry_data, gchar ** codec_name);
353 static GstCaps *qtdemux_audio_caps (GstQTDemux * qtdemux,
354 QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, guint32 fourcc,
355 const guint8 * data, int len, gchar ** codec_name);
356 static GstCaps *qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
357 QtDemuxStreamStsdEntry * entry, guint32 fourcc, const guint8 * data,
358 gchar ** codec_name);
359 static GstCaps *qtdemux_generic_caps (GstQTDemux * qtdemux,
360 QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, guint32 fourcc,
361 const guint8 * stsd_entry_data, gchar ** codec_name);
362
363 static gboolean qtdemux_parse_samples (GstQTDemux * qtdemux,
364 QtDemuxStream * stream, guint32 n);
365 static GstFlowReturn qtdemux_expose_streams (GstQTDemux * qtdemux);
366 static QtDemuxStream *gst_qtdemux_stream_ref (QtDemuxStream * stream);
367 static void gst_qtdemux_stream_unref (QtDemuxStream * stream);
368 static void gst_qtdemux_stream_clear (QtDemuxStream * stream);
369 static GstFlowReturn qtdemux_prepare_streams (GstQTDemux * qtdemux);
370 static void qtdemux_do_allocation (QtDemuxStream * stream,
371 GstQTDemux * qtdemux);
372 static gboolean gst_qtdemux_activate_segment (GstQTDemux * qtdemux,
373 QtDemuxStream * stream, guint32 seg_idx, GstClockTime offset);
374 static gboolean gst_qtdemux_stream_update_segment (GstQTDemux * qtdemux,
375 QtDemuxStream * stream, gint seg_idx, GstClockTime offset,
376 GstClockTime * _start, GstClockTime * _stop);
377 static void gst_qtdemux_send_gap_for_segment (GstQTDemux * demux,
378 QtDemuxStream * stream, gint segment_index, GstClockTime pos);
379
380 static gboolean qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux);
381 static void check_update_duration (GstQTDemux * qtdemux, GstClockTime duration);
382
383 static gchar *qtdemux_uuid_bytes_to_string (gconstpointer uuid_bytes);
384
385 static GstStructure *qtdemux_get_cenc_sample_properties (GstQTDemux * qtdemux,
386 QtDemuxStream * stream, guint sample_index);
387 static void gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux,
388 const gchar * id);
389 static void qtdemux_gst_structure_free (GstStructure * gststructure);
390 static void gst_qtdemux_reset (GstQTDemux * qtdemux, gboolean hard);
391
392 static void
gst_qtdemux_class_init(GstQTDemuxClass * klass)393 gst_qtdemux_class_init (GstQTDemuxClass * klass)
394 {
395 GObjectClass *gobject_class;
396 GstElementClass *gstelement_class;
397
398 gobject_class = (GObjectClass *) klass;
399 gstelement_class = (GstElementClass *) klass;
400
401 parent_class = g_type_class_peek_parent (klass);
402
403 gobject_class->dispose = gst_qtdemux_dispose;
404 gobject_class->finalize = gst_qtdemux_finalize;
405
406 gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_qtdemux_change_state);
407 #if 0
408 gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_qtdemux_set_index);
409 gstelement_class->get_index = GST_DEBUG_FUNCPTR (gst_qtdemux_get_index);
410 #endif
411 gstelement_class->set_context = GST_DEBUG_FUNCPTR (gst_qtdemux_set_context);
412
413 gst_tag_register_musicbrainz_tags ();
414
415 gst_element_class_add_static_pad_template (gstelement_class,
416 &gst_qtdemux_sink_template);
417 gst_element_class_add_static_pad_template (gstelement_class,
418 &gst_qtdemux_videosrc_template);
419 gst_element_class_add_static_pad_template (gstelement_class,
420 &gst_qtdemux_audiosrc_template);
421 gst_element_class_add_static_pad_template (gstelement_class,
422 &gst_qtdemux_subsrc_template);
423 gst_element_class_set_static_metadata (gstelement_class, "QuickTime demuxer",
424 "Codec/Demuxer",
425 "Demultiplex a QuickTime file into audio and video streams",
426 "David Schleef <ds@schleef.org>, Wim Taymans <wim@fluendo.com>");
427
428 GST_DEBUG_CATEGORY_INIT (qtdemux_debug, "qtdemux", 0, "qtdemux plugin");
429 gst_riff_init ();
430 }
431
432 static void
gst_qtdemux_init(GstQTDemux * qtdemux)433 gst_qtdemux_init (GstQTDemux * qtdemux)
434 {
435 qtdemux->sinkpad =
436 gst_pad_new_from_static_template (&gst_qtdemux_sink_template, "sink");
437 gst_pad_set_activate_function (qtdemux->sinkpad, qtdemux_sink_activate);
438 gst_pad_set_activatemode_function (qtdemux->sinkpad,
439 qtdemux_sink_activate_mode);
440 gst_pad_set_chain_function (qtdemux->sinkpad, gst_qtdemux_chain);
441 gst_pad_set_event_function (qtdemux->sinkpad, gst_qtdemux_handle_sink_event);
442 gst_pad_set_query_function (qtdemux->sinkpad, gst_qtdemux_handle_sink_query);
443 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), qtdemux->sinkpad);
444
445 qtdemux->adapter = gst_adapter_new ();
446 g_queue_init (&qtdemux->protection_event_queue);
447 qtdemux->flowcombiner = gst_flow_combiner_new ();
448 g_mutex_init (&qtdemux->expose_lock);
449
450 qtdemux->active_streams = g_ptr_array_new_with_free_func
451 ((GDestroyNotify) gst_qtdemux_stream_unref);
452 qtdemux->old_streams = g_ptr_array_new_with_free_func
453 ((GDestroyNotify) gst_qtdemux_stream_unref);
454
455 GST_OBJECT_FLAG_SET (qtdemux, GST_ELEMENT_FLAG_INDEXABLE);
456
457 gst_qtdemux_reset (qtdemux, TRUE);
458 }
459
460 static void
gst_qtdemux_finalize(GObject * object)461 gst_qtdemux_finalize (GObject * object)
462 {
463 GstQTDemux *qtdemux = GST_QTDEMUX (object);
464
465 g_free (qtdemux->redirect_location);
466
467 G_OBJECT_CLASS (parent_class)->finalize (object);
468 }
469
470 static void
gst_qtdemux_dispose(GObject * object)471 gst_qtdemux_dispose (GObject * object)
472 {
473 GstQTDemux *qtdemux = GST_QTDEMUX (object);
474
475 if (qtdemux->adapter) {
476 g_object_unref (G_OBJECT (qtdemux->adapter));
477 qtdemux->adapter = NULL;
478 }
479 gst_tag_list_unref (qtdemux->tag_list);
480 gst_flow_combiner_free (qtdemux->flowcombiner);
481 g_queue_foreach (&qtdemux->protection_event_queue, (GFunc) gst_event_unref,
482 NULL);
483 g_queue_clear (&qtdemux->protection_event_queue);
484
485 g_free (qtdemux->cenc_aux_info_sizes);
486 qtdemux->cenc_aux_info_sizes = NULL;
487 g_mutex_clear (&qtdemux->expose_lock);
488
489 g_ptr_array_free (qtdemux->active_streams, TRUE);
490 g_ptr_array_free (qtdemux->old_streams, TRUE);
491
492 G_OBJECT_CLASS (parent_class)->dispose (object);
493 }
494
495 static void
gst_qtdemux_post_no_playable_stream_error(GstQTDemux * qtdemux)496 gst_qtdemux_post_no_playable_stream_error (GstQTDemux * qtdemux)
497 {
498 if (qtdemux->redirect_location) {
499 GST_ELEMENT_ERROR_WITH_DETAILS (qtdemux, STREAM, DEMUX,
500 (_("This file contains no playable streams.")),
501 ("no known streams found, a redirect message has been posted"),
502 ("redirect-location", G_TYPE_STRING, qtdemux->redirect_location, NULL));
503 } else {
504 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
505 (_("This file contains no playable streams.")),
506 ("no known streams found"));
507 }
508 }
509
510 static GstBuffer *
_gst_buffer_new_wrapped(gpointer mem,gsize size,GFreeFunc free_func)511 _gst_buffer_new_wrapped (gpointer mem, gsize size, GFreeFunc free_func)
512 {
513 return gst_buffer_new_wrapped_full (free_func ? 0 : GST_MEMORY_FLAG_READONLY,
514 mem, size, 0, size, mem, free_func);
515 }
516
517 static GstFlowReturn
gst_qtdemux_pull_atom(GstQTDemux * qtdemux,guint64 offset,guint64 size,GstBuffer ** buf)518 gst_qtdemux_pull_atom (GstQTDemux * qtdemux, guint64 offset, guint64 size,
519 GstBuffer ** buf)
520 {
521 GstFlowReturn flow;
522 GstMapInfo map;
523 gsize bsize;
524
525 if (G_UNLIKELY (size == 0)) {
526 GstFlowReturn ret;
527 GstBuffer *tmp = NULL;
528
529 ret = gst_qtdemux_pull_atom (qtdemux, offset, sizeof (guint32), &tmp);
530 if (ret != GST_FLOW_OK)
531 return ret;
532
533 gst_buffer_map (tmp, &map, GST_MAP_READ);
534 size = QT_UINT32 (map.data);
535 GST_DEBUG_OBJECT (qtdemux, "size 0x%08" G_GINT64_MODIFIER "x", size);
536
537 gst_buffer_unmap (tmp, &map);
538 gst_buffer_unref (tmp);
539 }
540
541 /* Sanity check: catch bogus sizes (fuzzed/broken files) */
542 if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
543 if (qtdemux->state != QTDEMUX_STATE_MOVIE && qtdemux->got_moov) {
544 /* we're pulling header but already got most interesting bits,
545 * so never mind the rest (e.g. tags) (that much) */
546 GST_WARNING_OBJECT (qtdemux, "atom has bogus size %" G_GUINT64_FORMAT,
547 size);
548 return GST_FLOW_EOS;
549 } else {
550 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
551 (_("This file is invalid and cannot be played.")),
552 ("atom has bogus size %" G_GUINT64_FORMAT, size));
553 return GST_FLOW_ERROR;
554 }
555 }
556
557 flow = gst_pad_pull_range (qtdemux->sinkpad, offset, size, buf);
558
559 if (G_UNLIKELY (flow != GST_FLOW_OK))
560 return flow;
561
562 bsize = gst_buffer_get_size (*buf);
563 /* Catch short reads - we don't want any partial atoms */
564 if (G_UNLIKELY (bsize < size)) {
565 GST_WARNING_OBJECT (qtdemux,
566 "short read: %" G_GSIZE_FORMAT " < %" G_GUINT64_FORMAT, bsize, size);
567 gst_buffer_unref (*buf);
568 *buf = NULL;
569 return GST_FLOW_EOS;
570 }
571
572 return flow;
573 }
574
575 #if 1
576 static gboolean
gst_qtdemux_src_convert(GstQTDemux * qtdemux,GstPad * pad,GstFormat src_format,gint64 src_value,GstFormat dest_format,gint64 * dest_value)577 gst_qtdemux_src_convert (GstQTDemux * qtdemux, GstPad * pad,
578 GstFormat src_format, gint64 src_value, GstFormat dest_format,
579 gint64 * dest_value)
580 {
581 gboolean res = TRUE;
582 QtDemuxStream *stream = gst_pad_get_element_private (pad);
583 gint32 index;
584
585 if (stream->subtype != FOURCC_vide) {
586 res = FALSE;
587 goto done;
588 }
589
590 switch (src_format) {
591 case GST_FORMAT_TIME:
592 switch (dest_format) {
593 case GST_FORMAT_BYTES:{
594 index = gst_qtdemux_find_index_linear (qtdemux, stream, src_value);
595 if (-1 == index) {
596 res = FALSE;
597 goto done;
598 }
599
600 *dest_value = stream->samples[index].offset;
601
602 GST_DEBUG_OBJECT (qtdemux, "Format Conversion Time->Offset :%"
603 GST_TIME_FORMAT "->%" G_GUINT64_FORMAT,
604 GST_TIME_ARGS (src_value), *dest_value);
605 break;
606 }
607 default:
608 res = FALSE;
609 break;
610 }
611 break;
612 case GST_FORMAT_BYTES:
613 switch (dest_format) {
614 case GST_FORMAT_TIME:{
615 index =
616 gst_qtdemux_find_index_for_given_media_offset_linear (qtdemux,
617 stream, src_value);
618
619 if (-1 == index) {
620 res = FALSE;
621 goto done;
622 }
623
624 *dest_value =
625 QTSTREAMTIME_TO_GSTTIME (stream,
626 stream->samples[index].timestamp);
627 GST_DEBUG_OBJECT (qtdemux,
628 "Format Conversion Offset->Time :%" G_GUINT64_FORMAT "->%"
629 GST_TIME_FORMAT, src_value, GST_TIME_ARGS (*dest_value));
630 break;
631 }
632 default:
633 res = FALSE;
634 break;
635 }
636 break;
637 default:
638 res = FALSE;
639 break;
640 }
641
642 done:
643 return res;
644 }
645 #endif
646
647 static gboolean
gst_qtdemux_get_duration(GstQTDemux * qtdemux,GstClockTime * duration)648 gst_qtdemux_get_duration (GstQTDemux * qtdemux, GstClockTime * duration)
649 {
650 gboolean res = FALSE;
651
652 *duration = GST_CLOCK_TIME_NONE;
653
654 if (qtdemux->duration != 0 &&
655 qtdemux->duration != G_MAXINT64 && qtdemux->timescale != 0) {
656 *duration = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
657 res = TRUE;
658 } else {
659 *duration = GST_CLOCK_TIME_NONE;
660 }
661
662 return res;
663 }
664
665 static gboolean
gst_qtdemux_handle_src_query(GstPad * pad,GstObject * parent,GstQuery * query)666 gst_qtdemux_handle_src_query (GstPad * pad, GstObject * parent,
667 GstQuery * query)
668 {
669 gboolean res = FALSE;
670 GstQTDemux *qtdemux = GST_QTDEMUX (parent);
671
672 GST_LOG_OBJECT (pad, "%s query", GST_QUERY_TYPE_NAME (query));
673
674 switch (GST_QUERY_TYPE (query)) {
675 case GST_QUERY_POSITION:{
676 GstFormat fmt;
677
678 gst_query_parse_position (query, &fmt, NULL);
679 if (fmt == GST_FORMAT_TIME
680 && GST_CLOCK_TIME_IS_VALID (qtdemux->segment.position)) {
681 gst_query_set_position (query, GST_FORMAT_TIME,
682 qtdemux->segment.position);
683 res = TRUE;
684 }
685 }
686 break;
687 case GST_QUERY_DURATION:{
688 GstFormat fmt;
689
690 gst_query_parse_duration (query, &fmt, NULL);
691 if (fmt == GST_FORMAT_TIME) {
692 /* First try to query upstream */
693 res = gst_pad_query_default (pad, parent, query);
694 if (!res) {
695 GstClockTime duration;
696 if (gst_qtdemux_get_duration (qtdemux, &duration) && duration > 0) {
697 gst_query_set_duration (query, GST_FORMAT_TIME, duration);
698 res = TRUE;
699 }
700 }
701 }
702 break;
703 }
704 case GST_QUERY_CONVERT:{
705 GstFormat src_fmt, dest_fmt;
706 gint64 src_value, dest_value = 0;
707
708 gst_query_parse_convert (query, &src_fmt, &src_value, &dest_fmt, NULL);
709
710 res = gst_qtdemux_src_convert (qtdemux, pad,
711 src_fmt, src_value, dest_fmt, &dest_value);
712 if (res)
713 gst_query_set_convert (query, src_fmt, src_value, dest_fmt, dest_value);
714
715 break;
716 }
717 case GST_QUERY_FORMATS:
718 gst_query_set_formats (query, 2, GST_FORMAT_TIME, GST_FORMAT_BYTES);
719 res = TRUE;
720 break;
721 case GST_QUERY_SEEKING:{
722 GstFormat fmt;
723 gboolean seekable;
724
725 gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
726
727 if (fmt == GST_FORMAT_BYTES) {
728 /* We always refuse BYTES seeks from downstream */
729 break;
730 }
731
732 /* try upstream first */
733 res = gst_pad_query_default (pad, parent, query);
734
735 if (!res) {
736 gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
737 if (fmt == GST_FORMAT_TIME) {
738 GstClockTime duration;
739
740 gst_qtdemux_get_duration (qtdemux, &duration);
741 seekable = TRUE;
742 if (!qtdemux->pullbased) {
743 GstQuery *q;
744
745 /* we might be able with help from upstream */
746 seekable = FALSE;
747 q = gst_query_new_seeking (GST_FORMAT_BYTES);
748 if (gst_pad_peer_query (qtdemux->sinkpad, q)) {
749 gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL);
750 GST_LOG_OBJECT (qtdemux, "upstream BYTE seekable %d", seekable);
751 }
752 gst_query_unref (q);
753 }
754 gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0, duration);
755 res = TRUE;
756 }
757 }
758 break;
759 }
760 case GST_QUERY_SEGMENT:
761 {
762 GstFormat format;
763 gint64 start, stop;
764
765 format = qtdemux->segment.format;
766
767 start =
768 gst_segment_to_stream_time (&qtdemux->segment, format,
769 qtdemux->segment.start);
770 if ((stop = qtdemux->segment.stop) == -1)
771 stop = qtdemux->segment.duration;
772 else
773 stop = gst_segment_to_stream_time (&qtdemux->segment, format, stop);
774
775 gst_query_set_segment (query, qtdemux->segment.rate, format, start, stop);
776 res = TRUE;
777 break;
778 }
779 default:
780 res = gst_pad_query_default (pad, parent, query);
781 break;
782 }
783
784 return res;
785 }
786
787 static void
gst_qtdemux_push_tags(GstQTDemux * qtdemux,QtDemuxStream * stream)788 gst_qtdemux_push_tags (GstQTDemux * qtdemux, QtDemuxStream * stream)
789 {
790 if (G_LIKELY (stream->pad)) {
791 GST_DEBUG_OBJECT (qtdemux, "Checking pad %s:%s for tags",
792 GST_DEBUG_PAD_NAME (stream->pad));
793
794 if (!gst_tag_list_is_empty (stream->stream_tags)) {
795 GST_DEBUG_OBJECT (qtdemux, "Sending tags %" GST_PTR_FORMAT,
796 stream->stream_tags);
797 gst_pad_push_event (stream->pad,
798 gst_event_new_tag (gst_tag_list_ref (stream->stream_tags)));
799 }
800
801 if (G_UNLIKELY (stream->send_global_tags)) {
802 GST_DEBUG_OBJECT (qtdemux, "Sending global tags %" GST_PTR_FORMAT,
803 qtdemux->tag_list);
804 gst_pad_push_event (stream->pad,
805 gst_event_new_tag (gst_tag_list_ref (qtdemux->tag_list)));
806 stream->send_global_tags = FALSE;
807 }
808 }
809 }
810
811 /* push event on all source pads; takes ownership of the event */
812 static void
gst_qtdemux_push_event(GstQTDemux * qtdemux,GstEvent * event)813 gst_qtdemux_push_event (GstQTDemux * qtdemux, GstEvent * event)
814 {
815 gboolean has_valid_stream = FALSE;
816 GstEventType etype = GST_EVENT_TYPE (event);
817 guint i;
818
819 GST_DEBUG_OBJECT (qtdemux, "pushing %s event on all source pads",
820 GST_EVENT_TYPE_NAME (event));
821
822 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
823 GstPad *pad;
824 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
825 GST_DEBUG_OBJECT (qtdemux, "pushing on track-id %u", stream->track_id);
826
827 if ((pad = stream->pad)) {
828 has_valid_stream = TRUE;
829
830 if (etype == GST_EVENT_EOS) {
831 /* let's not send twice */
832 if (stream->sent_eos)
833 continue;
834 stream->sent_eos = TRUE;
835 }
836
837 gst_pad_push_event (pad, gst_event_ref (event));
838 }
839 }
840
841 gst_event_unref (event);
842
843 /* if it is EOS and there are no pads, post an error */
844 if (!has_valid_stream && etype == GST_EVENT_EOS) {
845 gst_qtdemux_post_no_playable_stream_error (qtdemux);
846 }
847 }
848
849 typedef struct
850 {
851 guint64 media_time;
852 } FindData;
853
854 static gint
find_func(QtDemuxSample * s1,gint64 * media_time,gpointer user_data)855 find_func (QtDemuxSample * s1, gint64 * media_time, gpointer user_data)
856 {
857 if ((gint64) s1->timestamp > *media_time)
858 return 1;
859 if ((gint64) s1->timestamp == *media_time)
860 return 0;
861
862 return -1;
863 }
864
865 /* find the index of the sample that includes the data for @media_time using a
866 * binary search. Only to be called in optimized cases of linear search below.
867 *
868 * Returns the index of the sample with the corresponding *DTS*.
869 */
870 static guint32
gst_qtdemux_find_index(GstQTDemux * qtdemux,QtDemuxStream * str,guint64 media_time)871 gst_qtdemux_find_index (GstQTDemux * qtdemux, QtDemuxStream * str,
872 guint64 media_time)
873 {
874 QtDemuxSample *result;
875 guint32 index;
876
877 /* convert media_time to mov format */
878 media_time =
879 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
880
881 result = gst_util_array_binary_search (str->samples, str->stbl_index + 1,
882 sizeof (QtDemuxSample), (GCompareDataFunc) find_func,
883 GST_SEARCH_MODE_BEFORE, &media_time, NULL);
884
885 if (G_LIKELY (result))
886 index = result - str->samples;
887 else
888 index = 0;
889
890 return index;
891 }
892
893
894
895 /* find the index of the sample that includes the data for @media_offset using a
896 * linear search
897 *
898 * Returns the index of the sample.
899 */
900 static guint32
gst_qtdemux_find_index_for_given_media_offset_linear(GstQTDemux * qtdemux,QtDemuxStream * str,gint64 media_offset)901 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
902 QtDemuxStream * str, gint64 media_offset)
903 {
904 QtDemuxSample *result = str->samples;
905 guint32 index = 0;
906
907 if (result == NULL || str->n_samples == 0)
908 return -1;
909
910 if (media_offset == result->offset)
911 return index;
912
913 result++;
914 while (index < str->n_samples - 1) {
915 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
916 goto parse_failed;
917
918 if (media_offset < result->offset)
919 break;
920
921 index++;
922 result++;
923 }
924 return index;
925
926 /* ERRORS */
927 parse_failed:
928 {
929 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
930 return -1;
931 }
932 }
933
934 /* find the index of the sample that includes the data for @media_time using a
935 * linear search, and keeping in mind that not all samples may have been parsed
936 * yet. If possible, it will delegate to binary search.
937 *
938 * Returns the index of the sample.
939 */
940 static guint32
gst_qtdemux_find_index_linear(GstQTDemux * qtdemux,QtDemuxStream * str,GstClockTime media_time)941 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
942 GstClockTime media_time)
943 {
944 guint32 index = 0;
945 guint64 mov_time;
946 QtDemuxSample *sample;
947
948 /* convert media_time to mov format */
949 mov_time =
950 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
951
952 sample = str->samples;
953 if (mov_time == sample->timestamp + sample->pts_offset)
954 return index;
955
956 /* use faster search if requested time in already parsed range */
957 sample = str->samples + str->stbl_index;
958 if (str->stbl_index >= 0 && mov_time <= sample->timestamp) {
959 index = gst_qtdemux_find_index (qtdemux, str, media_time);
960 sample = str->samples + index;
961 } else {
962 while (index < str->n_samples - 1) {
963 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
964 goto parse_failed;
965
966 sample = str->samples + index + 1;
967 if (mov_time < sample->timestamp) {
968 sample = str->samples + index;
969 break;
970 }
971
972 index++;
973 }
974 }
975
976 /* sample->timestamp is now <= media_time, need to find the corresponding
977 * PTS now by looking backwards */
978 while (index > 0 && sample->timestamp + sample->pts_offset > mov_time) {
979 index--;
980 sample = str->samples + index;
981 }
982
983 return index;
984
985 /* ERRORS */
986 parse_failed:
987 {
988 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
989 return -1;
990 }
991 }
992
993 /* find the index of the keyframe needed to decode the sample at @index
994 * of stream @str, or of a subsequent keyframe (depending on @next)
995 *
996 * Returns the index of the keyframe.
997 */
998 static guint32
gst_qtdemux_find_keyframe(GstQTDemux * qtdemux,QtDemuxStream * str,guint32 index,gboolean next)999 gst_qtdemux_find_keyframe (GstQTDemux * qtdemux, QtDemuxStream * str,
1000 guint32 index, gboolean next)
1001 {
1002 guint32 new_index = index;
1003
1004 if (index >= str->n_samples) {
1005 new_index = str->n_samples;
1006 goto beach;
1007 }
1008
1009 /* all keyframes, return index */
1010 if (str->all_keyframe) {
1011 new_index = index;
1012 goto beach;
1013 }
1014
1015 /* else search until we have a keyframe */
1016 while (new_index < str->n_samples) {
1017 if (next && !qtdemux_parse_samples (qtdemux, str, new_index))
1018 goto parse_failed;
1019
1020 if (str->samples[new_index].keyframe)
1021 break;
1022
1023 if (new_index == 0)
1024 break;
1025
1026 if (next)
1027 new_index++;
1028 else
1029 new_index--;
1030 }
1031
1032 if (new_index == str->n_samples) {
1033 GST_DEBUG_OBJECT (qtdemux, "no next keyframe");
1034 new_index = -1;
1035 }
1036
1037 beach:
1038 GST_DEBUG_OBJECT (qtdemux, "searching for keyframe index %s index %u "
1039 "gave %u", next ? "after" : "before", index, new_index);
1040
1041 return new_index;
1042
1043 /* ERRORS */
1044 parse_failed:
1045 {
1046 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", new_index);
1047 return -1;
1048 }
1049 }
1050
1051 /* find the segment for @time_position for @stream
1052 *
1053 * Returns the index of the segment containing @time_position.
1054 * Returns the last segment and sets the @eos variable to TRUE
1055 * if the time is beyond the end. @eos may be NULL
1056 */
1057 static guint32
gst_qtdemux_find_segment(GstQTDemux * qtdemux,QtDemuxStream * stream,GstClockTime time_position)1058 gst_qtdemux_find_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
1059 GstClockTime time_position)
1060 {
1061 gint i;
1062 guint32 seg_idx;
1063
1064 GST_LOG_OBJECT (stream->pad, "finding segment for %" GST_TIME_FORMAT,
1065 GST_TIME_ARGS (time_position));
1066
1067 seg_idx = -1;
1068 for (i = 0; i < stream->n_segments; i++) {
1069 QtDemuxSegment *segment = &stream->segments[i];
1070
1071 GST_LOG_OBJECT (stream->pad,
1072 "looking at segment %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT,
1073 GST_TIME_ARGS (segment->time), GST_TIME_ARGS (segment->stop_time));
1074
1075 /* For the last segment we include stop_time in the last segment */
1076 if (i < stream->n_segments - 1) {
1077 if (segment->time <= time_position && time_position < segment->stop_time) {
1078 GST_LOG_OBJECT (stream->pad, "segment %d matches", i);
1079 seg_idx = i;
1080 break;
1081 }
1082 } else {
1083 /* Last segment always matches */
1084 seg_idx = i;
1085 break;
1086 }
1087 }
1088 return seg_idx;
1089 }
1090
1091 /* move the stream @str to the sample position @index.
1092 *
1093 * Updates @str->sample_index and marks discontinuity if needed.
1094 */
1095 static void
gst_qtdemux_move_stream(GstQTDemux * qtdemux,QtDemuxStream * str,guint32 index)1096 gst_qtdemux_move_stream (GstQTDemux * qtdemux, QtDemuxStream * str,
1097 guint32 index)
1098 {
1099 /* no change needed */
1100 if (index == str->sample_index)
1101 return;
1102
1103 GST_DEBUG_OBJECT (qtdemux, "moving to sample %u of %u", index,
1104 str->n_samples);
1105
1106 /* position changed, we have a discont */
1107 str->sample_index = index;
1108 str->offset_in_sample = 0;
1109 /* Each time we move in the stream we store the position where we are
1110 * starting from */
1111 str->from_sample = index;
1112 str->discont = TRUE;
1113 }
1114
1115 #ifdef OHOS_OPT_COMPAT
1116 /* ohos.opt.compat.0055 */
gst_qtdemux_get_all_tracks_minimum_duration(GstQTDemux * qtdemux)1117 static gint64 gst_qtdemux_get_all_tracks_minimum_duration(GstQTDemux * qtdemux)
1118 {
1119 guint64 min_duration = G_MAXUINT64;
1120 for (guint i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
1121 QtDemuxStream *str = QTDEMUX_NTH_STREAM (qtdemux, i);
1122 if (str->duration < min_duration) {
1123 min_duration = str->duration;
1124 }
1125 }
1126 return min_duration;
1127 }
1128 #endif
1129
1130 static void
gst_qtdemux_adjust_seek(GstQTDemux * qtdemux,gint64 desired_time,gboolean use_sparse,gboolean next,gint64 * key_time,gint64 * key_offset)1131 gst_qtdemux_adjust_seek (GstQTDemux * qtdemux, gint64 desired_time,
1132 gboolean use_sparse, gboolean next, gint64 * key_time, gint64 * key_offset)
1133 {
1134 guint64 min_offset;
1135 #ifdef OHOS_OPT_COMPAT
1136 /* ohos.opt.compat.0055 */
1137 guint64 max_time = 0;
1138 guint64 min_duration = gst_qtdemux_get_all_tracks_minimum_duration(qtdemux);
1139 #endif
1140 gint64 min_byte_offset = -1;
1141 guint i;
1142
1143 min_offset = desired_time;
1144
1145 /* for each stream, find the index of the sample in the segment
1146 * and move back to the previous keyframe. */
1147 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
1148 QtDemuxStream *str;
1149 guint32 index, kindex;
1150 guint32 seg_idx;
1151 GstClockTime media_start;
1152 GstClockTime media_time;
1153 GstClockTime seg_time;
1154 QtDemuxSegment *seg;
1155 gboolean empty_segment = FALSE;
1156
1157 str = QTDEMUX_NTH_STREAM (qtdemux, i);
1158
1159 if (CUR_STREAM (str)->sparse && !use_sparse)
1160 continue;
1161
1162 seg_idx = gst_qtdemux_find_segment (qtdemux, str, desired_time);
1163 GST_DEBUG_OBJECT (qtdemux, "align segment %d", seg_idx);
1164
1165 /* get segment and time in the segment */
1166 seg = &str->segments[seg_idx];
1167 seg_time = (desired_time - seg->time) * seg->rate;
1168
1169 while (QTSEGMENT_IS_EMPTY (seg)) {
1170 seg_time = 0;
1171 empty_segment = TRUE;
1172 GST_DEBUG_OBJECT (str->pad, "Segment %d is empty, moving to next one",
1173 seg_idx);
1174 seg_idx++;
1175 if (seg_idx == str->n_segments)
1176 break;
1177 seg = &str->segments[seg_idx];
1178 }
1179
1180 if (seg_idx == str->n_segments) {
1181 /* FIXME track shouldn't have the last segment as empty, but if it
1182 * happens we better handle it */
1183 continue;
1184 }
1185
1186 /* get the media time in the segment */
1187 media_start = seg->media_start + seg_time;
1188
1189 /* get the index of the sample with media time */
1190 index = gst_qtdemux_find_index_linear (qtdemux, str, media_start);
1191 GST_DEBUG_OBJECT (qtdemux, "sample for %" GST_TIME_FORMAT " at %u"
1192 " at offset %" G_GUINT64_FORMAT " (empty segment: %d)",
1193 GST_TIME_ARGS (media_start), index, str->samples[index].offset,
1194 empty_segment);
1195
1196 /* shift to next frame if we are looking for next keyframe */
1197 if (next && QTSAMPLE_PTS_NO_CSLG (str, &str->samples[index]) < media_start
1198 && index < str->stbl_index)
1199 index++;
1200
1201 if (!empty_segment) {
1202 /* find previous keyframe */
1203 kindex = gst_qtdemux_find_keyframe (qtdemux, str, index, next);
1204
1205 /* we will settle for one before if none found after */
1206 if (next && kindex == -1)
1207 kindex = gst_qtdemux_find_keyframe (qtdemux, str, index, FALSE);
1208
1209 /* Update the requested time whenever a keyframe was found, to make it
1210 * accurate and avoid having the first buffer fall outside of the segment
1211 */
1212 if (kindex != -1) {
1213 index = kindex;
1214
1215 /* get timestamp of keyframe */
1216 media_time = QTSAMPLE_PTS_NO_CSLG (str, &str->samples[kindex]);
1217 GST_DEBUG_OBJECT (qtdemux,
1218 "keyframe at %u with time %" GST_TIME_FORMAT " at offset %"
1219 G_GUINT64_FORMAT, kindex, GST_TIME_ARGS (media_time),
1220 str->samples[kindex].offset);
1221 #ifdef OHOS_OPT_COMPAT
1222 /**
1223 * ohos.opt.compat.0055
1224 * when video stream and audio stream are different duration(edge. video duration is 01:50,
1225 * audio duration is 0:35), it will lead seek done offset has a huge gap with seek offset.
1226 * Thus, return a timestamp closest to the seek offset.
1227 */
1228 GST_DEBUG_OBJECT (qtdemux,
1229 "min_duration %" GST_TIME_FORMAT " desired_time %" GST_TIME_FORMAT " next %d max_time %" GST_TIME_FORMAT "",
1230 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME(str, min_duration)),
1231 GST_TIME_ARGS (desired_time), next, GST_TIME_ARGS (max_time));
1232 /**
1233 * diffent: compared with the original logic, forward seek may miss video key frames
1234 * forward seek, find all tracks the biggest key frames time
1235 */
1236 if ((min_duration < desired_time) && (!next && (max_time > media_time))) {
1237 continue;
1238 }
1239 max_time = media_time;
1240 #endif
1241 /* keyframes in the segment get a chance to change the
1242 * desired_offset. keyframes out of the segment are
1243 * ignored. */
1244 if (media_time >= seg->media_start) {
1245 GstClockTime seg_time;
1246
1247 /* this keyframe is inside the segment, convert back to
1248 * segment time */
1249 seg_time = (media_time - seg->media_start) + seg->time;
1250 if ((!next && (seg_time < min_offset)) ||
1251 (next && (seg_time > min_offset)))
1252 min_offset = seg_time;
1253 }
1254 }
1255 }
1256
1257 if (min_byte_offset < 0 || str->samples[index].offset < min_byte_offset)
1258 min_byte_offset = str->samples[index].offset;
1259 }
1260
1261 if (key_time)
1262 *key_time = min_offset;
1263 if (key_offset)
1264 *key_offset = min_byte_offset;
1265 }
1266
1267 static gboolean
gst_qtdemux_convert_seek(GstPad * pad,GstFormat * format,GstSeekType cur_type,gint64 * cur,GstSeekType stop_type,gint64 * stop)1268 gst_qtdemux_convert_seek (GstPad * pad, GstFormat * format,
1269 GstSeekType cur_type, gint64 * cur, GstSeekType stop_type, gint64 * stop)
1270 {
1271 gboolean res;
1272
1273 g_return_val_if_fail (format != NULL, FALSE);
1274 g_return_val_if_fail (cur != NULL, FALSE);
1275 g_return_val_if_fail (stop != NULL, FALSE);
1276
1277 if (*format == GST_FORMAT_TIME)
1278 return TRUE;
1279
1280 res = TRUE;
1281 if (cur_type != GST_SEEK_TYPE_NONE)
1282 res = gst_pad_query_convert (pad, *format, *cur, GST_FORMAT_TIME, cur);
1283 if (res && stop_type != GST_SEEK_TYPE_NONE)
1284 res = gst_pad_query_convert (pad, *format, *stop, GST_FORMAT_TIME, stop);
1285
1286 if (res)
1287 *format = GST_FORMAT_TIME;
1288
1289 return res;
1290 }
1291
1292 /* perform seek in push based mode:
1293 find BYTE position to move to based on time and delegate to upstream
1294 */
1295 static gboolean
gst_qtdemux_do_push_seek(GstQTDemux * qtdemux,GstPad * pad,GstEvent * event)1296 gst_qtdemux_do_push_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1297 {
1298 gdouble rate;
1299 GstFormat format;
1300 GstSeekFlags flags;
1301 GstSeekType cur_type, stop_type;
1302 gint64 cur, stop, key_cur;
1303 gboolean res;
1304 gint64 byte_cur;
1305 gint64 original_stop;
1306 guint32 seqnum;
1307
1308 GST_DEBUG_OBJECT (qtdemux, "doing push-based seek");
1309
1310 gst_event_parse_seek (event, &rate, &format, &flags,
1311 &cur_type, &cur, &stop_type, &stop);
1312 seqnum = gst_event_get_seqnum (event);
1313
1314 /* Directly send the instant-rate-change event here before taking the
1315 * stream-lock so that it can be applied as soon as possible */
1316 if (flags & GST_SEEK_FLAG_INSTANT_RATE_CHANGE) {
1317 GstEvent *ev;
1318
1319 /* instant rate change only supported if direction does not change. All
1320 * other requirements are already checked before creating the seek event
1321 * but let's double-check here to be sure */
1322 if ((qtdemux->segment.rate > 0 && rate < 0) ||
1323 (qtdemux->segment.rate < 0 && rate > 0) ||
1324 cur_type != GST_SEEK_TYPE_NONE ||
1325 stop_type != GST_SEEK_TYPE_NONE || (flags & GST_SEEK_FLAG_FLUSH)) {
1326 GST_ERROR_OBJECT (qtdemux,
1327 "Instant rate change seeks only supported in the "
1328 "same direction, without flushing and position change");
1329 return FALSE;
1330 }
1331
1332 ev = gst_event_new_instant_rate_change (rate / qtdemux->segment.rate,
1333 (GstSegmentFlags) flags);
1334 gst_event_set_seqnum (ev, seqnum);
1335 gst_qtdemux_push_event (qtdemux, ev);
1336 return TRUE;
1337 }
1338
1339 /* only forward streaming and seeking is possible */
1340 if (rate <= 0)
1341 goto unsupported_seek;
1342
1343 /* convert to TIME if needed and possible */
1344 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1345 stop_type, &stop))
1346 goto no_format;
1347
1348 /* Upstream seek in bytes will have undefined stop, but qtdemux stores
1349 * the original stop position to use when upstream pushes the new segment
1350 * for this seek */
1351 original_stop = stop;
1352 stop = -1;
1353
1354 /* find reasonable corresponding BYTE position,
1355 * also try to mind about keyframes, since we can not go back a bit for them
1356 * later on */
1357 /* determining @next here based on SNAP_BEFORE/SNAP_AFTER should
1358 * mostly just work, but let's not yet boldly go there ... */
1359 gst_qtdemux_adjust_seek (qtdemux, cur, FALSE, FALSE, &key_cur, &byte_cur);
1360
1361 if (byte_cur == -1)
1362 goto abort_seek;
1363
1364 GST_DEBUG_OBJECT (qtdemux, "Pushing BYTE seek rate %g, "
1365 "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, byte_cur,
1366 stop);
1367
1368 GST_OBJECT_LOCK (qtdemux);
1369 qtdemux->seek_offset = byte_cur;
1370 if (!(flags & GST_SEEK_FLAG_KEY_UNIT)) {
1371 qtdemux->push_seek_start = cur;
1372 } else {
1373 qtdemux->push_seek_start = key_cur;
1374 }
1375
1376 if (stop_type == GST_SEEK_TYPE_NONE) {
1377 qtdemux->push_seek_stop = qtdemux->segment.stop;
1378 } else {
1379 qtdemux->push_seek_stop = original_stop;
1380 }
1381 GST_OBJECT_UNLOCK (qtdemux);
1382
1383 qtdemux->segment_seqnum = seqnum;
1384 /* BYTE seek event */
1385 event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type, byte_cur,
1386 stop_type, stop);
1387 gst_event_set_seqnum (event, seqnum);
1388 res = gst_pad_push_event (qtdemux->sinkpad, event);
1389
1390 return res;
1391
1392 /* ERRORS */
1393 abort_seek:
1394 {
1395 GST_DEBUG_OBJECT (qtdemux, "could not determine byte position to seek to, "
1396 "seek aborted.");
1397 return FALSE;
1398 }
1399 unsupported_seek:
1400 {
1401 GST_DEBUG_OBJECT (qtdemux, "unsupported seek, seek aborted.");
1402 return FALSE;
1403 }
1404 no_format:
1405 {
1406 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1407 return FALSE;
1408 }
1409 }
1410
1411 /* perform the seek.
1412 *
1413 * We set all segment_indexes in the streams to unknown and
1414 * adjust the time_position to the desired position. this is enough
1415 * to trigger a segment switch in the streaming thread to start
1416 * streaming from the desired position.
1417 *
1418 * Keyframe seeking is a little more complicated when dealing with
1419 * segments. Ideally we want to move to the previous keyframe in
1420 * the segment but there might not be a keyframe in the segment. In
1421 * fact, none of the segments could contain a keyframe. We take a
1422 * practical approach: seek to the previous keyframe in the segment,
1423 * if there is none, seek to the beginning of the segment.
1424 *
1425 * Called with STREAM_LOCK
1426 */
1427 static gboolean
gst_qtdemux_perform_seek(GstQTDemux * qtdemux,GstSegment * segment,guint32 seqnum,GstSeekFlags flags)1428 gst_qtdemux_perform_seek (GstQTDemux * qtdemux, GstSegment * segment,
1429 guint32 seqnum, GstSeekFlags flags)
1430 {
1431 gint64 desired_offset;
1432 guint i;
1433
1434 desired_offset = segment->position;
1435
1436 GST_DEBUG_OBJECT (qtdemux, "seeking to %" GST_TIME_FORMAT,
1437 GST_TIME_ARGS (desired_offset));
1438
1439 /* may not have enough fragmented info to do this adjustment,
1440 * and we can't scan (and probably should not) at this time with
1441 * possibly flushing upstream */
1442 if ((flags & GST_SEEK_FLAG_KEY_UNIT) && !qtdemux->fragmented) {
1443 gint64 min_offset;
1444 gboolean next, before, after;
1445
1446 before = ! !(flags & GST_SEEK_FLAG_SNAP_BEFORE);
1447 after = ! !(flags & GST_SEEK_FLAG_SNAP_AFTER);
1448 next = after && !before;
1449 if (segment->rate < 0)
1450 next = !next;
1451
1452 gst_qtdemux_adjust_seek (qtdemux, desired_offset, TRUE, next, &min_offset,
1453 NULL);
1454 GST_DEBUG_OBJECT (qtdemux, "keyframe seek, align to %"
1455 GST_TIME_FORMAT, GST_TIME_ARGS (min_offset));
1456 desired_offset = min_offset;
1457 }
1458
1459 /* and set all streams to the final position */
1460 GST_OBJECT_LOCK (qtdemux);
1461 gst_flow_combiner_reset (qtdemux->flowcombiner);
1462 GST_OBJECT_UNLOCK (qtdemux);
1463 qtdemux->segment_seqnum = seqnum;
1464 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
1465 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
1466
1467 stream->time_position = desired_offset;
1468 stream->accumulated_base = 0;
1469 stream->sample_index = -1;
1470 stream->offset_in_sample = 0;
1471 stream->segment_index = -1;
1472 stream->sent_eos = FALSE;
1473 stream->last_keyframe_dts = GST_CLOCK_TIME_NONE;
1474
1475 if (segment->flags & GST_SEEK_FLAG_FLUSH)
1476 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
1477 }
1478 segment->position = desired_offset;
1479 if (segment->rate >= 0) {
1480 segment->start = desired_offset;
1481 /* We need to update time as we update start in that direction */
1482 segment->time = desired_offset;
1483
1484 /* we stop at the end */
1485 if (segment->stop == -1)
1486 segment->stop = segment->duration;
1487 } else {
1488 segment->stop = desired_offset;
1489 }
1490
1491 if (qtdemux->fragmented)
1492 qtdemux->fragmented_seek_pending = TRUE;
1493
1494 return TRUE;
1495 }
1496
1497 /* do a seek in pull based mode */
1498 static gboolean
gst_qtdemux_do_seek(GstQTDemux * qtdemux,GstPad * pad,GstEvent * event)1499 gst_qtdemux_do_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1500 {
1501 gdouble rate = 1.0;
1502 GstFormat format;
1503 GstSeekFlags flags;
1504 GstSeekType cur_type, stop_type;
1505 gint64 cur, stop;
1506 gboolean flush, instant_rate_change;
1507 gboolean update;
1508 GstSegment seeksegment;
1509 guint32 seqnum = GST_SEQNUM_INVALID;
1510 GstEvent *flush_event;
1511 gboolean ret;
1512
1513 GST_DEBUG_OBJECT (qtdemux, "doing seek with event");
1514
1515 gst_event_parse_seek (event, &rate, &format, &flags,
1516 &cur_type, &cur, &stop_type, &stop);
1517 seqnum = gst_event_get_seqnum (event);
1518
1519 /* we have to have a format as the segment format. Try to convert
1520 * if not. */
1521 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1522 stop_type, &stop))
1523 goto no_format;
1524
1525 GST_DEBUG_OBJECT (qtdemux, "seek format %s", gst_format_get_name (format));
1526
1527 flush = ! !(flags & GST_SEEK_FLAG_FLUSH);
1528 instant_rate_change = ! !(flags & GST_SEEK_FLAG_INSTANT_RATE_CHANGE);
1529
1530 /* Directly send the instant-rate-change event here before taking the
1531 * stream-lock so that it can be applied as soon as possible */
1532 if (instant_rate_change) {
1533 GstEvent *ev;
1534
1535 /* instant rate change only supported if direction does not change. All
1536 * other requirements are already checked before creating the seek event
1537 * but let's double-check here to be sure */
1538 if ((qtdemux->segment.rate > 0 && rate < 0) ||
1539 (qtdemux->segment.rate < 0 && rate > 0) ||
1540 cur_type != GST_SEEK_TYPE_NONE ||
1541 stop_type != GST_SEEK_TYPE_NONE || flush) {
1542 GST_ERROR_OBJECT (qtdemux,
1543 "Instant rate change seeks only supported in the "
1544 "same direction, without flushing and position change");
1545 return FALSE;
1546 }
1547
1548 ev = gst_event_new_instant_rate_change (rate / qtdemux->segment.rate,
1549 (GstSegmentFlags) flags);
1550 gst_event_set_seqnum (ev, seqnum);
1551 gst_qtdemux_push_event (qtdemux, ev);
1552 return TRUE;
1553 }
1554
1555 /* stop streaming, either by flushing or by pausing the task */
1556 if (flush) {
1557 flush_event = gst_event_new_flush_start ();
1558 if (seqnum != GST_SEQNUM_INVALID)
1559 gst_event_set_seqnum (flush_event, seqnum);
1560 /* unlock upstream pull_range */
1561 gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event));
1562 /* make sure out loop function exits */
1563 gst_qtdemux_push_event (qtdemux, flush_event);
1564 } else {
1565 /* non flushing seek, pause the task */
1566 gst_pad_pause_task (qtdemux->sinkpad);
1567 }
1568
1569 /* wait for streaming to finish */
1570 GST_PAD_STREAM_LOCK (qtdemux->sinkpad);
1571
1572 /* copy segment, we need this because we still need the old
1573 * segment when we close the current segment. */
1574 memcpy (&seeksegment, &qtdemux->segment, sizeof (GstSegment));
1575
1576 /* configure the segment with the seek variables */
1577 GST_DEBUG_OBJECT (qtdemux, "configuring seek");
1578 if (!gst_segment_do_seek (&seeksegment, rate, format, flags,
1579 cur_type, cur, stop_type, stop, &update)) {
1580 ret = FALSE;
1581 GST_ERROR_OBJECT (qtdemux, "inconsistent seek values, doing nothing");
1582 } else {
1583 /* now do the seek */
1584 ret = gst_qtdemux_perform_seek (qtdemux, &seeksegment, seqnum, flags);
1585 }
1586
1587 /* prepare for streaming again */
1588 if (flush) {
1589 flush_event = gst_event_new_flush_stop (TRUE);
1590 if (seqnum != GST_SEQNUM_INVALID)
1591 gst_event_set_seqnum (flush_event, seqnum);
1592
1593 gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event));
1594 gst_qtdemux_push_event (qtdemux, flush_event);
1595 }
1596
1597 /* commit the new segment */
1598 memcpy (&qtdemux->segment, &seeksegment, sizeof (GstSegment));
1599
1600 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
1601 GstMessage *msg = gst_message_new_segment_start (GST_OBJECT_CAST (qtdemux),
1602 qtdemux->segment.format, qtdemux->segment.position);
1603 if (seqnum != GST_SEQNUM_INVALID)
1604 gst_message_set_seqnum (msg, seqnum);
1605 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
1606 }
1607
1608 /* restart streaming, NEWSEGMENT will be sent from the streaming thread. */
1609 gst_pad_start_task (qtdemux->sinkpad, (GstTaskFunction) gst_qtdemux_loop,
1610 qtdemux->sinkpad, NULL);
1611
1612 GST_PAD_STREAM_UNLOCK (qtdemux->sinkpad);
1613
1614 return ret;
1615
1616 /* ERRORS */
1617 no_format:
1618 {
1619 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1620 return FALSE;
1621 }
1622 }
1623
1624 static gboolean
qtdemux_ensure_index(GstQTDemux * qtdemux)1625 qtdemux_ensure_index (GstQTDemux * qtdemux)
1626 {
1627 guint i;
1628
1629 GST_DEBUG_OBJECT (qtdemux, "collecting all metadata for all streams");
1630
1631 /* Build complete index */
1632 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
1633 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
1634
1635 if (!qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
1636 GST_LOG_OBJECT (qtdemux,
1637 "Building complete index of track-id %u for seeking failed!",
1638 stream->track_id);
1639 return FALSE;
1640 }
1641 }
1642
1643 return TRUE;
1644 }
1645
1646 static gboolean
gst_qtdemux_handle_src_event(GstPad * pad,GstObject * parent,GstEvent * event)1647 gst_qtdemux_handle_src_event (GstPad * pad, GstObject * parent,
1648 GstEvent * event)
1649 {
1650 gboolean res = TRUE;
1651 GstQTDemux *qtdemux = GST_QTDEMUX (parent);
1652
1653 switch (GST_EVENT_TYPE (event)) {
1654 case GST_EVENT_RECONFIGURE:
1655 GST_OBJECT_LOCK (qtdemux);
1656 gst_flow_combiner_reset (qtdemux->flowcombiner);
1657 GST_OBJECT_UNLOCK (qtdemux);
1658 res = gst_pad_event_default (pad, parent, event);
1659 break;
1660 case GST_EVENT_SEEK:
1661 {
1662 GstSeekFlags flags = 0;
1663 GstFormat seek_format;
1664 gboolean instant_rate_change;
1665
1666 #ifndef GST_DISABLE_GST_DEBUG
1667 GstClockTime ts = gst_util_get_timestamp ();
1668 #endif
1669 guint32 seqnum = gst_event_get_seqnum (event);
1670
1671 qtdemux->received_seek = TRUE;
1672
1673 gst_event_parse_seek (event, NULL, &seek_format, &flags, NULL, NULL, NULL,
1674 NULL);
1675 instant_rate_change = ! !(flags & GST_SEEK_FLAG_INSTANT_RATE_CHANGE);
1676
1677 if (seqnum == qtdemux->segment_seqnum) {
1678 GST_LOG_OBJECT (pad,
1679 "Drop duplicated SEEK event seqnum %" G_GUINT32_FORMAT, seqnum);
1680 gst_event_unref (event);
1681 return TRUE;
1682 }
1683
1684 if (qtdemux->upstream_format_is_time && qtdemux->fragmented) {
1685 /* seek should be handled by upstream, we might need to re-download fragments */
1686 GST_DEBUG_OBJECT (qtdemux,
1687 "let upstream handle seek for fragmented playback");
1688 goto upstream;
1689 }
1690
1691 if (seek_format == GST_FORMAT_BYTES) {
1692 GST_DEBUG_OBJECT (pad, "Rejecting seek request in bytes format");
1693 gst_event_unref (event);
1694 return FALSE;
1695 }
1696
1697 gst_event_parse_seek_trickmode_interval (event,
1698 &qtdemux->trickmode_interval);
1699
1700 /* Build complete index for seeking;
1701 * if not a fragmented file at least and we're really doing a seek,
1702 * not just an instant-rate-change */
1703 if (!qtdemux->fragmented && !instant_rate_change) {
1704 if (!qtdemux_ensure_index (qtdemux))
1705 goto index_failed;
1706 }
1707 #ifndef GST_DISABLE_GST_DEBUG
1708 ts = gst_util_get_timestamp () - ts;
1709 GST_INFO_OBJECT (qtdemux,
1710 "Time taken to parse index %" GST_TIME_FORMAT, GST_TIME_ARGS (ts));
1711 #endif
1712 if (qtdemux->pullbased) {
1713 res = gst_qtdemux_do_seek (qtdemux, pad, event);
1714 } else if (gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (event))) {
1715 GST_DEBUG_OBJECT (qtdemux, "Upstream successfully seeked");
1716 res = TRUE;
1717 } else if (qtdemux->state == QTDEMUX_STATE_MOVIE
1718 && QTDEMUX_N_STREAMS (qtdemux)
1719 && !qtdemux->fragmented) {
1720 res = gst_qtdemux_do_push_seek (qtdemux, pad, event);
1721 } else {
1722 GST_DEBUG_OBJECT (qtdemux,
1723 "ignoring seek in push mode in current state");
1724 res = FALSE;
1725 }
1726 gst_event_unref (event);
1727 }
1728 break;
1729 default:
1730 upstream:
1731 res = gst_pad_event_default (pad, parent, event);
1732 break;
1733 }
1734
1735 done:
1736 return res;
1737
1738 /* ERRORS */
1739 index_failed:
1740 {
1741 GST_ERROR_OBJECT (qtdemux, "Index failed");
1742 gst_event_unref (event);
1743 res = FALSE;
1744 goto done;
1745 }
1746 }
1747
1748 /* Find, for each track, the first sample in coding order that has a file offset >= @byte_pos.
1749 *
1750 * If @fw is false, the coding order is explored backwards.
1751 *
1752 * If @set is true, each stream will be moved to its matched sample, or EOS if no matching
1753 * sample is found for that track.
1754 *
1755 * The stream and sample index of the sample with the minimum offset in the direction explored
1756 * (see @fw) is returned in the output parameters @_stream and @_index respectively.
1757 *
1758 * @_time is set to the QTSAMPLE_PTS of the matched sample with the minimum QTSAMPLE_PTS in the
1759 * direction explored, which may not always match the QTSAMPLE_PTS of the sample returned in
1760 * @_stream and @_index. */
1761 static void
gst_qtdemux_find_sample(GstQTDemux * qtdemux,gint64 byte_pos,gboolean fw,gboolean set,QtDemuxStream ** _stream,gint * _index,gint64 * _time)1762 gst_qtdemux_find_sample (GstQTDemux * qtdemux, gint64 byte_pos, gboolean fw,
1763 gboolean set, QtDemuxStream ** _stream, gint * _index, gint64 * _time)
1764 {
1765 gint i, index;
1766 gint64 time, min_time;
1767 QtDemuxStream *stream;
1768 gint iter;
1769
1770 min_time = -1;
1771 stream = NULL;
1772 index = -1;
1773
1774 for (iter = 0; iter < QTDEMUX_N_STREAMS (qtdemux); iter++) {
1775 QtDemuxStream *str;
1776 gint inc;
1777 gboolean set_sample;
1778
1779 str = QTDEMUX_NTH_STREAM (qtdemux, iter);
1780 set_sample = !set;
1781
1782 if (fw) {
1783 i = 0;
1784 inc = 1;
1785 } else {
1786 i = str->n_samples - 1;
1787 inc = -1;
1788 }
1789
1790 for (; (i >= 0) && (i < str->n_samples); i += inc) {
1791 if (str->samples[i].size == 0)
1792 continue;
1793
1794 if (fw && (str->samples[i].offset < byte_pos))
1795 continue;
1796
1797 if (!fw && (str->samples[i].offset + str->samples[i].size > byte_pos))
1798 continue;
1799
1800 /* move stream to first available sample */
1801 if (set) {
1802 gst_qtdemux_move_stream (qtdemux, str, i);
1803 set_sample = TRUE;
1804 }
1805
1806 /* avoid index from sparse streams since they might be far away */
1807 if (!CUR_STREAM (str)->sparse) {
1808 /* determine min/max time */
1809 time = QTSAMPLE_PTS (str, &str->samples[i]);
1810 if (min_time == -1 || (!fw && time > min_time) ||
1811 (fw && time < min_time)) {
1812 min_time = time;
1813 }
1814
1815 /* determine stream with leading sample, to get its position */
1816 if (!stream ||
1817 (fw && (str->samples[i].offset < stream->samples[index].offset)) ||
1818 (!fw && (str->samples[i].offset > stream->samples[index].offset))) {
1819 stream = str;
1820 index = i;
1821 }
1822 }
1823 break;
1824 }
1825
1826 /* no sample for this stream, mark eos */
1827 if (!set_sample)
1828 gst_qtdemux_move_stream (qtdemux, str, str->n_samples);
1829 }
1830
1831 if (_time)
1832 *_time = min_time;
1833 if (_stream)
1834 *_stream = stream;
1835 if (_index)
1836 *_index = index;
1837 }
1838
1839 /* Copied from mpegtsbase code */
1840 /* FIXME: replace this function when we add new util function for stream-id creation */
1841 static gchar *
_get_upstream_id(GstQTDemux * demux)1842 _get_upstream_id (GstQTDemux * demux)
1843 {
1844 gchar *upstream_id = gst_pad_get_stream_id (demux->sinkpad);
1845
1846 if (!upstream_id) {
1847 /* Try to create one from the upstream URI, else use a randome number */
1848 GstQuery *query;
1849 gchar *uri = NULL;
1850
1851 /* Try to generate one from the URI query and
1852 * if it fails take a random number instead */
1853 query = gst_query_new_uri ();
1854 if (gst_element_query (GST_ELEMENT_CAST (demux), query)) {
1855 gst_query_parse_uri (query, &uri);
1856 }
1857
1858 if (uri) {
1859 GChecksum *cs;
1860
1861 /* And then generate an SHA256 sum of the URI */
1862 cs = g_checksum_new (G_CHECKSUM_SHA256);
1863 g_checksum_update (cs, (const guchar *) uri, strlen (uri));
1864 g_free (uri);
1865 upstream_id = g_strdup (g_checksum_get_string (cs));
1866 g_checksum_free (cs);
1867 } else {
1868 /* Just get some random number if the URI query fails */
1869 GST_FIXME_OBJECT (demux, "Creating random stream-id, consider "
1870 "implementing a deterministic way of creating a stream-id");
1871 upstream_id =
1872 g_strdup_printf ("%08x%08x%08x%08x", g_random_int (), g_random_int (),
1873 g_random_int (), g_random_int ());
1874 }
1875
1876 gst_query_unref (query);
1877 }
1878 return upstream_id;
1879 }
1880
1881 static QtDemuxStream *
_create_stream(GstQTDemux * demux,guint32 track_id)1882 _create_stream (GstQTDemux * demux, guint32 track_id)
1883 {
1884 QtDemuxStream *stream;
1885 gchar *upstream_id;
1886
1887 stream = g_new0 (QtDemuxStream, 1);
1888 stream->demux = demux;
1889 stream->track_id = track_id;
1890 upstream_id = _get_upstream_id (demux);
1891 stream->stream_id = g_strdup_printf ("%s/%03u", upstream_id, track_id);
1892 g_free (upstream_id);
1893 /* new streams always need a discont */
1894 stream->discont = TRUE;
1895 /* we enable clipping for raw audio/video streams */
1896 stream->need_clip = FALSE;
1897 stream->process_func = NULL;
1898 stream->segment_index = -1;
1899 stream->time_position = 0;
1900 stream->sample_index = -1;
1901 stream->offset_in_sample = 0;
1902 stream->new_stream = TRUE;
1903 stream->multiview_mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
1904 stream->multiview_flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
1905 stream->protected = FALSE;
1906 stream->protection_scheme_type = 0;
1907 stream->protection_scheme_version = 0;
1908 stream->protection_scheme_info = NULL;
1909 stream->n_samples_moof = 0;
1910 stream->duration_moof = 0;
1911 stream->duration_last_moof = 0;
1912 stream->alignment = 1;
1913 stream->stream_tags = gst_tag_list_new_empty ();
1914 gst_tag_list_set_scope (stream->stream_tags, GST_TAG_SCOPE_STREAM);
1915 g_queue_init (&stream->protection_scheme_event_queue);
1916 stream->ref_count = 1;
1917 /* consistent default for push based mode */
1918 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
1919 #ifdef OHOS_OPT_PERFORMANCE // ohos.opt.performance.0001: demux push first audio/video frame
1920 stream->has_push_first_frame = FALSE;
1921 #endif
1922 return stream;
1923 }
1924
1925 static gboolean
gst_qtdemux_setcaps(GstQTDemux * demux,GstCaps * caps)1926 gst_qtdemux_setcaps (GstQTDemux * demux, GstCaps * caps)
1927 {
1928 GstStructure *structure;
1929 const gchar *variant;
1930 const GstCaps *mediacaps = NULL;
1931
1932 GST_DEBUG_OBJECT (demux, "Sink set caps: %" GST_PTR_FORMAT, caps);
1933
1934 structure = gst_caps_get_structure (caps, 0);
1935 variant = gst_structure_get_string (structure, "variant");
1936
1937 if (variant && strcmp (variant, "mss-fragmented") == 0) {
1938 QtDemuxStream *stream;
1939 const GValue *value;
1940
1941 demux->fragmented = TRUE;
1942 demux->mss_mode = TRUE;
1943
1944 if (QTDEMUX_N_STREAMS (demux) > 1) {
1945 /* can't do this, we can only renegotiate for another mss format */
1946 return FALSE;
1947 }
1948
1949 value = gst_structure_get_value (structure, "media-caps");
1950 /* create stream */
1951 if (value) {
1952 const GValue *timescale_v;
1953
1954 /* TODO update when stream changes during playback */
1955
1956 if (QTDEMUX_N_STREAMS (demux) == 0) {
1957 stream = _create_stream (demux, 1);
1958 g_ptr_array_add (demux->active_streams, stream);
1959 /* mss has no stsd/stsd entry, use id 0 as default */
1960 stream->stsd_entries_length = 1;
1961 stream->stsd_sample_description_id = stream->cur_stsd_entry_index = 0;
1962 stream->stsd_entries = g_new0 (QtDemuxStreamStsdEntry, 1);
1963 } else {
1964 stream = QTDEMUX_NTH_STREAM (demux, 0);
1965 }
1966
1967 timescale_v = gst_structure_get_value (structure, "timescale");
1968 if (timescale_v) {
1969 stream->timescale = g_value_get_uint64 (timescale_v);
1970 } else {
1971 /* default mss timescale */
1972 stream->timescale = 10000000;
1973 }
1974 demux->timescale = stream->timescale;
1975
1976 mediacaps = gst_value_get_caps (value);
1977 if (!CUR_STREAM (stream)->caps
1978 || !gst_caps_is_equal_fixed (mediacaps, CUR_STREAM (stream)->caps)) {
1979 GST_DEBUG_OBJECT (demux, "We have a new caps %" GST_PTR_FORMAT,
1980 mediacaps);
1981 stream->new_caps = TRUE;
1982 }
1983 gst_caps_replace (&CUR_STREAM (stream)->caps, (GstCaps *) mediacaps);
1984 structure = gst_caps_get_structure (mediacaps, 0);
1985 if (g_str_has_prefix (gst_structure_get_name (structure), "video")) {
1986 stream->subtype = FOURCC_vide;
1987
1988 gst_structure_get_int (structure, "width", &CUR_STREAM (stream)->width);
1989 gst_structure_get_int (structure, "height",
1990 &CUR_STREAM (stream)->height);
1991 gst_structure_get_fraction (structure, "framerate",
1992 &CUR_STREAM (stream)->fps_n, &CUR_STREAM (stream)->fps_d);
1993 } else if (g_str_has_prefix (gst_structure_get_name (structure), "audio")) {
1994 gint rate = 0;
1995 stream->subtype = FOURCC_soun;
1996 gst_structure_get_int (structure, "channels",
1997 &CUR_STREAM (stream)->n_channels);
1998 gst_structure_get_int (structure, "rate", &rate);
1999 CUR_STREAM (stream)->rate = rate;
2000 } else if (gst_structure_has_name (structure, "application/x-cenc")) {
2001 if (gst_structure_has_field (structure, "original-media-type")) {
2002 const gchar *media_type =
2003 gst_structure_get_string (structure, "original-media-type");
2004 if (g_str_has_prefix (media_type, "video")) {
2005 stream->subtype = FOURCC_vide;
2006 } else if (g_str_has_prefix (media_type, "audio")) {
2007 stream->subtype = FOURCC_soun;
2008 }
2009 }
2010 }
2011 }
2012 gst_caps_replace (&demux->media_caps, (GstCaps *) mediacaps);
2013 } else {
2014 demux->mss_mode = FALSE;
2015 }
2016
2017 return TRUE;
2018 }
2019
2020 static void
gst_qtdemux_reset(GstQTDemux * qtdemux,gboolean hard)2021 gst_qtdemux_reset (GstQTDemux * qtdemux, gboolean hard)
2022 {
2023 gint i;
2024
2025 GST_DEBUG_OBJECT (qtdemux, "Resetting demux");
2026 gst_pad_stop_task (qtdemux->sinkpad);
2027
2028 if (hard || qtdemux->upstream_format_is_time) {
2029 qtdemux->state = QTDEMUX_STATE_INITIAL;
2030 qtdemux->neededbytes = 16;
2031 qtdemux->todrop = 0;
2032 qtdemux->pullbased = FALSE;
2033 g_clear_pointer (&qtdemux->redirect_location, g_free);
2034 qtdemux->first_mdat = -1;
2035 qtdemux->header_size = 0;
2036 qtdemux->mdatoffset = -1;
2037 qtdemux->restoredata_offset = -1;
2038 if (qtdemux->mdatbuffer)
2039 gst_buffer_unref (qtdemux->mdatbuffer);
2040 if (qtdemux->restoredata_buffer)
2041 gst_buffer_unref (qtdemux->restoredata_buffer);
2042 qtdemux->mdatbuffer = NULL;
2043 qtdemux->restoredata_buffer = NULL;
2044 qtdemux->mdatleft = 0;
2045 qtdemux->mdatsize = 0;
2046 if (qtdemux->comp_brands)
2047 gst_buffer_unref (qtdemux->comp_brands);
2048 qtdemux->comp_brands = NULL;
2049 qtdemux->last_moov_offset = -1;
2050 if (qtdemux->moov_node_compressed) {
2051 g_node_destroy (qtdemux->moov_node_compressed);
2052 if (qtdemux->moov_node)
2053 g_free (qtdemux->moov_node->data);
2054 }
2055 qtdemux->moov_node_compressed = NULL;
2056 if (qtdemux->moov_node)
2057 g_node_destroy (qtdemux->moov_node);
2058 qtdemux->moov_node = NULL;
2059 if (qtdemux->tag_list)
2060 gst_mini_object_unref (GST_MINI_OBJECT_CAST (qtdemux->tag_list));
2061 qtdemux->tag_list = gst_tag_list_new_empty ();
2062 gst_tag_list_set_scope (qtdemux->tag_list, GST_TAG_SCOPE_GLOBAL);
2063 #if 0
2064 if (qtdemux->element_index)
2065 gst_object_unref (qtdemux->element_index);
2066 qtdemux->element_index = NULL;
2067 #endif
2068 qtdemux->major_brand = 0;
2069 qtdemux->upstream_format_is_time = FALSE;
2070 qtdemux->upstream_seekable = FALSE;
2071 qtdemux->upstream_size = 0;
2072
2073 qtdemux->fragment_start = -1;
2074 qtdemux->fragment_start_offset = -1;
2075 qtdemux->duration = 0;
2076 qtdemux->moof_offset = 0;
2077 qtdemux->chapters_track_id = 0;
2078 qtdemux->have_group_id = FALSE;
2079 qtdemux->group_id = G_MAXUINT;
2080
2081 g_queue_foreach (&qtdemux->protection_event_queue, (GFunc) gst_event_unref,
2082 NULL);
2083 g_queue_clear (&qtdemux->protection_event_queue);
2084
2085 qtdemux->received_seek = FALSE;
2086 qtdemux->first_moof_already_parsed = FALSE;
2087 }
2088 qtdemux->offset = 0;
2089 gst_adapter_clear (qtdemux->adapter);
2090 gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
2091 qtdemux->need_segment = TRUE;
2092
2093 if (hard) {
2094 qtdemux->segment_seqnum = GST_SEQNUM_INVALID;
2095 qtdemux->trickmode_interval = 0;
2096 g_ptr_array_set_size (qtdemux->active_streams, 0);
2097 g_ptr_array_set_size (qtdemux->old_streams, 0);
2098 qtdemux->n_video_streams = 0;
2099 qtdemux->n_audio_streams = 0;
2100 qtdemux->n_sub_streams = 0;
2101 qtdemux->exposed = FALSE;
2102 qtdemux->fragmented = FALSE;
2103 qtdemux->mss_mode = FALSE;
2104 gst_caps_replace (&qtdemux->media_caps, NULL);
2105 qtdemux->timescale = 0;
2106 qtdemux->got_moov = FALSE;
2107 qtdemux->cenc_aux_info_offset = 0;
2108 qtdemux->cenc_aux_info_sizes = NULL;
2109 qtdemux->cenc_aux_sample_count = 0;
2110 if (qtdemux->protection_system_ids) {
2111 g_ptr_array_free (qtdemux->protection_system_ids, TRUE);
2112 qtdemux->protection_system_ids = NULL;
2113 }
2114 qtdemux->streams_aware = GST_OBJECT_PARENT (qtdemux)
2115 && GST_OBJECT_FLAG_IS_SET (GST_OBJECT_PARENT (qtdemux),
2116 GST_BIN_FLAG_STREAMS_AWARE);
2117
2118 if (qtdemux->preferred_protection_system_id) {
2119 g_free (qtdemux->preferred_protection_system_id);
2120 qtdemux->preferred_protection_system_id = NULL;
2121 }
2122 } else if (qtdemux->mss_mode) {
2123 gst_flow_combiner_reset (qtdemux->flowcombiner);
2124 g_ptr_array_foreach (qtdemux->active_streams,
2125 (GFunc) gst_qtdemux_stream_clear, NULL);
2126 } else {
2127 gst_flow_combiner_reset (qtdemux->flowcombiner);
2128 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
2129 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
2130 stream->sent_eos = FALSE;
2131 stream->time_position = 0;
2132 stream->accumulated_base = 0;
2133 stream->last_keyframe_dts = GST_CLOCK_TIME_NONE;
2134 }
2135 }
2136 }
2137
2138
2139 /* Maps the @segment to the qt edts internal segments and pushes
2140 * the corresponding segment event.
2141 *
2142 * If it ends up being at a empty segment, a gap will be pushed and the next
2143 * edts segment will be activated in sequence.
2144 *
2145 * To be used in push-mode only */
2146 static void
gst_qtdemux_map_and_push_segments(GstQTDemux * qtdemux,GstSegment * segment)2147 gst_qtdemux_map_and_push_segments (GstQTDemux * qtdemux, GstSegment * segment)
2148 {
2149 gint i, iter;
2150
2151 for (iter = 0; iter < QTDEMUX_N_STREAMS (qtdemux); iter++) {
2152 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, iter);
2153
2154 stream->time_position = segment->start;
2155
2156 /* in push mode we should be guaranteed that we will have empty segments
2157 * at the beginning and then one segment after, other scenarios are not
2158 * supported and are discarded when parsing the edts */
2159 for (i = 0; i < stream->n_segments; i++) {
2160 if (stream->segments[i].stop_time > segment->start) {
2161 /* push the empty segment and move to the next one */
2162 gst_qtdemux_activate_segment (qtdemux, stream, i,
2163 stream->time_position);
2164 if (QTSEGMENT_IS_EMPTY (&stream->segments[i])) {
2165 gst_qtdemux_send_gap_for_segment (qtdemux, stream, i,
2166 stream->time_position);
2167
2168 /* accumulate previous segments */
2169 if (GST_CLOCK_TIME_IS_VALID (stream->segment.stop))
2170 stream->accumulated_base +=
2171 (stream->segment.stop -
2172 stream->segment.start) / ABS (stream->segment.rate);
2173 continue;
2174 }
2175
2176 g_assert (i == stream->n_segments - 1);
2177 }
2178 }
2179 }
2180 }
2181
2182 static void
gst_qtdemux_stream_concat(GstQTDemux * qtdemux,GPtrArray * dest,GPtrArray * src)2183 gst_qtdemux_stream_concat (GstQTDemux * qtdemux, GPtrArray * dest,
2184 GPtrArray * src)
2185 {
2186 guint i;
2187 guint len;
2188
2189 len = src->len;
2190
2191 if (len == 0)
2192 return;
2193
2194 for (i = 0; i < len; i++) {
2195 QtDemuxStream *stream = g_ptr_array_index (src, i);
2196
2197 #ifndef GST_DISABLE_GST_DEBUG
2198 GST_DEBUG_OBJECT (qtdemux, "Move stream %p (stream-id %s) to %p",
2199 stream, GST_STR_NULL (stream->stream_id), dest);
2200 #endif
2201 g_ptr_array_add (dest, gst_qtdemux_stream_ref (stream));
2202 }
2203
2204 g_ptr_array_set_size (src, 0);
2205 }
2206
2207 static gboolean
gst_qtdemux_handle_sink_event(GstPad * sinkpad,GstObject * parent,GstEvent * event)2208 gst_qtdemux_handle_sink_event (GstPad * sinkpad, GstObject * parent,
2209 GstEvent * event)
2210 {
2211 GstQTDemux *demux = GST_QTDEMUX (parent);
2212 gboolean res = TRUE;
2213
2214 GST_LOG_OBJECT (demux, "handling %s event", GST_EVENT_TYPE_NAME (event));
2215
2216 switch (GST_EVENT_TYPE (event)) {
2217 case GST_EVENT_SEGMENT:
2218 {
2219 gint64 offset = 0;
2220 QtDemuxStream *stream;
2221 gint idx;
2222 GstSegment segment;
2223
2224 /* some debug output */
2225 gst_event_copy_segment (event, &segment);
2226 GST_DEBUG_OBJECT (demux, "received newsegment %" GST_SEGMENT_FORMAT,
2227 &segment);
2228
2229 if (segment.format == GST_FORMAT_TIME) {
2230 demux->upstream_format_is_time = TRUE;
2231 demux->segment_seqnum = gst_event_get_seqnum (event);
2232 } else {
2233 GST_DEBUG_OBJECT (demux, "Not storing upstream newsegment, "
2234 "not in time format");
2235
2236 /* chain will send initial newsegment after pads have been added */
2237 if (demux->state != QTDEMUX_STATE_MOVIE || !QTDEMUX_N_STREAMS (demux)) {
2238 GST_DEBUG_OBJECT (demux, "still starting, eating event");
2239 goto exit;
2240 }
2241 }
2242
2243 /* check if this matches a time seek we received previously
2244 * FIXME for backwards compatibility reasons we use the
2245 * seek_offset here to compare. In the future we might want to
2246 * change this to use the seqnum as it uniquely should identify
2247 * the segment that corresponds to the seek. */
2248 GST_DEBUG_OBJECT (demux, "Stored seek offset: %" G_GINT64_FORMAT
2249 ", received segment offset %" G_GINT64_FORMAT,
2250 demux->seek_offset, segment.start);
2251 if (segment.format == GST_FORMAT_BYTES
2252 && demux->seek_offset == segment.start) {
2253 GST_OBJECT_LOCK (demux);
2254 offset = segment.start;
2255
2256 segment.format = GST_FORMAT_TIME;
2257 segment.start = demux->push_seek_start;
2258 segment.stop = demux->push_seek_stop;
2259 GST_DEBUG_OBJECT (demux, "Replaced segment with stored seek "
2260 "segment %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT,
2261 GST_TIME_ARGS (segment.start), GST_TIME_ARGS (segment.stop));
2262 GST_OBJECT_UNLOCK (demux);
2263 }
2264
2265 /* we only expect a BYTE segment, e.g. following a seek */
2266 if (segment.format == GST_FORMAT_BYTES) {
2267 if (GST_CLOCK_TIME_IS_VALID (segment.start)) {
2268 offset = segment.start;
2269
2270 gst_qtdemux_find_sample (demux, segment.start, TRUE, FALSE, NULL,
2271 NULL, (gint64 *) & segment.start);
2272 if ((gint64) segment.start < 0)
2273 segment.start = 0;
2274 }
2275 if (GST_CLOCK_TIME_IS_VALID (segment.stop)) {
2276 gst_qtdemux_find_sample (demux, segment.stop, FALSE, FALSE, NULL,
2277 NULL, (gint64 *) & segment.stop);
2278 /* keyframe seeking should already arrange for start >= stop,
2279 * but make sure in other rare cases */
2280 segment.stop = MAX (segment.stop, segment.start);
2281 }
2282 } else if (segment.format == GST_FORMAT_TIME) {
2283 /* push all data on the adapter before starting this
2284 * new segment */
2285 gst_qtdemux_process_adapter (demux, TRUE);
2286 } else {
2287 GST_DEBUG_OBJECT (demux, "unsupported segment format, ignoring");
2288 goto exit;
2289 }
2290
2291 /* We shouldn't modify upstream driven TIME FORMAT segment */
2292 if (!demux->upstream_format_is_time) {
2293 /* accept upstream's notion of segment and distribute along */
2294 segment.format = GST_FORMAT_TIME;
2295 segment.position = segment.time = segment.start;
2296 segment.duration = demux->segment.duration;
2297 segment.base = gst_segment_to_running_time (&demux->segment,
2298 GST_FORMAT_TIME, demux->segment.position);
2299 }
2300
2301 gst_segment_copy_into (&segment, &demux->segment);
2302 GST_DEBUG_OBJECT (demux, "Pushing newseg %" GST_SEGMENT_FORMAT, &segment);
2303
2304 /* map segment to internal qt segments and push on each stream */
2305 if (QTDEMUX_N_STREAMS (demux)) {
2306 demux->need_segment = TRUE;
2307 gst_qtdemux_check_send_pending_segment (demux);
2308 }
2309
2310 /* clear leftover in current segment, if any */
2311 gst_adapter_clear (demux->adapter);
2312
2313 /* set up streaming thread */
2314 demux->offset = offset;
2315 if (demux->upstream_format_is_time) {
2316 GST_DEBUG_OBJECT (demux, "Upstream is driving in time format, "
2317 "set values to restart reading from a new atom");
2318 demux->neededbytes = 16;
2319 demux->todrop = 0;
2320 } else {
2321 gst_qtdemux_find_sample (demux, offset, TRUE, TRUE, &stream, &idx,
2322 NULL);
2323 if (stream) {
2324 demux->todrop = stream->samples[idx].offset - offset;
2325 demux->neededbytes = demux->todrop + stream->samples[idx].size;
2326 } else {
2327 /* set up for EOS */
2328 demux->neededbytes = -1;
2329 demux->todrop = 0;
2330 }
2331 }
2332 exit:
2333 gst_event_unref (event);
2334 res = TRUE;
2335 goto drop;
2336 }
2337 case GST_EVENT_FLUSH_START:
2338 {
2339 if (gst_event_get_seqnum (event) == demux->offset_seek_seqnum) {
2340 gst_event_unref (event);
2341 goto drop;
2342 }
2343 QTDEMUX_EXPOSE_LOCK (demux);
2344 res = gst_pad_event_default (demux->sinkpad, parent, event);
2345 QTDEMUX_EXPOSE_UNLOCK (demux);
2346 goto drop;
2347 }
2348 case GST_EVENT_FLUSH_STOP:
2349 {
2350 guint64 dur;
2351
2352 dur = demux->segment.duration;
2353 gst_qtdemux_reset (demux, FALSE);
2354 demux->segment.duration = dur;
2355
2356 if (gst_event_get_seqnum (event) == demux->offset_seek_seqnum) {
2357 gst_event_unref (event);
2358 goto drop;
2359 }
2360 break;
2361 }
2362 case GST_EVENT_EOS:
2363 /* If we are in push mode, and get an EOS before we've seen any streams,
2364 * then error out - we have nowhere to send the EOS */
2365 if (!demux->pullbased) {
2366 gint i;
2367 gboolean has_valid_stream = FALSE;
2368 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
2369 if (QTDEMUX_NTH_STREAM (demux, i)->pad != NULL) {
2370 has_valid_stream = TRUE;
2371 break;
2372 }
2373 }
2374 if (!has_valid_stream)
2375 gst_qtdemux_post_no_playable_stream_error (demux);
2376 else {
2377 GST_DEBUG_OBJECT (demux, "Data still available after EOS: %u",
2378 (guint) gst_adapter_available (demux->adapter));
2379 if (gst_qtdemux_process_adapter (demux, TRUE) != GST_FLOW_OK) {
2380 res = FALSE;
2381 }
2382 }
2383 }
2384 break;
2385 case GST_EVENT_CAPS:{
2386 GstCaps *caps = NULL;
2387
2388 gst_event_parse_caps (event, &caps);
2389 gst_qtdemux_setcaps (demux, caps);
2390 res = TRUE;
2391 gst_event_unref (event);
2392 goto drop;
2393 }
2394 case GST_EVENT_PROTECTION:
2395 {
2396 const gchar *system_id = NULL;
2397
2398 gst_event_parse_protection (event, &system_id, NULL, NULL);
2399 GST_DEBUG_OBJECT (demux, "Received protection event for system ID %s",
2400 system_id);
2401 gst_qtdemux_append_protection_system_id (demux, system_id);
2402 /* save the event for later, for source pads that have not been created */
2403 g_queue_push_tail (&demux->protection_event_queue, gst_event_ref (event));
2404 /* send it to all pads that already exist */
2405 gst_qtdemux_push_event (demux, event);
2406 res = TRUE;
2407 goto drop;
2408 }
2409 case GST_EVENT_STREAM_START:
2410 {
2411 res = TRUE;
2412 gst_event_unref (event);
2413
2414 /* Drain all the buffers */
2415 gst_qtdemux_process_adapter (demux, TRUE);
2416 gst_qtdemux_reset (demux, FALSE);
2417 /* We expect new moov box after new stream-start event */
2418 if (demux->exposed) {
2419 gst_qtdemux_stream_concat (demux,
2420 demux->old_streams, demux->active_streams);
2421 }
2422
2423 goto drop;
2424 }
2425 default:
2426 break;
2427 }
2428
2429 res = gst_pad_event_default (demux->sinkpad, parent, event) & res;
2430
2431 drop:
2432 return res;
2433 }
2434
2435 static gboolean
gst_qtdemux_handle_sink_query(GstPad * pad,GstObject * parent,GstQuery * query)2436 gst_qtdemux_handle_sink_query (GstPad * pad, GstObject * parent,
2437 GstQuery * query)
2438 {
2439 GstQTDemux *demux = GST_QTDEMUX (parent);
2440 gboolean res = FALSE;
2441
2442 switch (GST_QUERY_TYPE (query)) {
2443 case GST_QUERY_BITRATE:
2444 {
2445 GstClockTime duration;
2446
2447 /* populate demux->upstream_size if not done yet */
2448 gst_qtdemux_check_seekability (demux);
2449
2450 if (demux->upstream_size != -1
2451 && gst_qtdemux_get_duration (demux, &duration)) {
2452 guint bitrate =
2453 gst_util_uint64_scale (8 * demux->upstream_size, GST_SECOND,
2454 duration);
2455
2456 GST_LOG_OBJECT (demux, "bitrate query byte length: %" G_GUINT64_FORMAT
2457 " duration %" GST_TIME_FORMAT " resulting a bitrate of %u",
2458 demux->upstream_size, GST_TIME_ARGS (duration), bitrate);
2459
2460 /* TODO: better results based on ranges/index tables */
2461 gst_query_set_bitrate (query, bitrate);
2462 res = TRUE;
2463 }
2464 break;
2465 }
2466 default:
2467 res = gst_pad_query_default (pad, (GstObject *) demux, query);
2468 break;
2469 }
2470
2471 return res;
2472 }
2473
2474
2475 #if 0
2476 static void
2477 gst_qtdemux_set_index (GstElement * element, GstIndex * index)
2478 {
2479 GstQTDemux *demux = GST_QTDEMUX (element);
2480
2481 GST_OBJECT_LOCK (demux);
2482 if (demux->element_index)
2483 gst_object_unref (demux->element_index);
2484 if (index) {
2485 demux->element_index = gst_object_ref (index);
2486 } else {
2487 demux->element_index = NULL;
2488 }
2489 GST_OBJECT_UNLOCK (demux);
2490 /* object lock might be taken again */
2491 if (index)
2492 gst_index_get_writer_id (index, GST_OBJECT (element), &demux->index_id);
2493 GST_DEBUG_OBJECT (demux, "Set index %" GST_PTR_FORMAT "for writer id %d",
2494 demux->element_index, demux->index_id);
2495 }
2496
2497 static GstIndex *
2498 gst_qtdemux_get_index (GstElement * element)
2499 {
2500 GstIndex *result = NULL;
2501 GstQTDemux *demux = GST_QTDEMUX (element);
2502
2503 GST_OBJECT_LOCK (demux);
2504 if (demux->element_index)
2505 result = gst_object_ref (demux->element_index);
2506 GST_OBJECT_UNLOCK (demux);
2507
2508 GST_DEBUG_OBJECT (demux, "Returning index %" GST_PTR_FORMAT, result);
2509
2510 return result;
2511 }
2512 #endif
2513
2514 static void
gst_qtdemux_stbl_free(QtDemuxStream * stream)2515 gst_qtdemux_stbl_free (QtDemuxStream * stream)
2516 {
2517 g_free ((gpointer) stream->stco.data);
2518 stream->stco.data = NULL;
2519 g_free ((gpointer) stream->stsz.data);
2520 stream->stsz.data = NULL;
2521 g_free ((gpointer) stream->stsc.data);
2522 stream->stsc.data = NULL;
2523 g_free ((gpointer) stream->stts.data);
2524 stream->stts.data = NULL;
2525 g_free ((gpointer) stream->stss.data);
2526 stream->stss.data = NULL;
2527 g_free ((gpointer) stream->stps.data);
2528 stream->stps.data = NULL;
2529 g_free ((gpointer) stream->ctts.data);
2530 stream->ctts.data = NULL;
2531 }
2532
2533 static void
gst_qtdemux_stream_flush_segments_data(QtDemuxStream * stream)2534 gst_qtdemux_stream_flush_segments_data (QtDemuxStream * stream)
2535 {
2536 g_free (stream->segments);
2537 stream->segments = NULL;
2538 stream->segment_index = -1;
2539 stream->accumulated_base = 0;
2540 }
2541
2542 static void
gst_qtdemux_stream_flush_samples_data(QtDemuxStream * stream)2543 gst_qtdemux_stream_flush_samples_data (QtDemuxStream * stream)
2544 {
2545 g_free (stream->samples);
2546 stream->samples = NULL;
2547 gst_qtdemux_stbl_free (stream);
2548
2549 /* fragments */
2550 g_free (stream->ra_entries);
2551 stream->ra_entries = NULL;
2552 stream->n_ra_entries = 0;
2553
2554 stream->sample_index = -1;
2555 stream->stbl_index = -1;
2556 stream->n_samples = 0;
2557 stream->time_position = 0;
2558
2559 stream->n_samples_moof = 0;
2560 stream->duration_moof = 0;
2561 stream->duration_last_moof = 0;
2562 }
2563
2564 static void
gst_qtdemux_stream_clear(QtDemuxStream * stream)2565 gst_qtdemux_stream_clear (QtDemuxStream * stream)
2566 {
2567 gint i;
2568 if (stream->allocator)
2569 gst_object_unref (stream->allocator);
2570 while (stream->buffers) {
2571 gst_buffer_unref (GST_BUFFER_CAST (stream->buffers->data));
2572 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
2573 }
2574 for (i = 0; i < stream->stsd_entries_length; i++) {
2575 QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[i];
2576 if (entry->rgb8_palette) {
2577 gst_memory_unref (entry->rgb8_palette);
2578 entry->rgb8_palette = NULL;
2579 }
2580 entry->sparse = FALSE;
2581 }
2582
2583 if (stream->stream_tags)
2584 gst_tag_list_unref (stream->stream_tags);
2585
2586 stream->stream_tags = gst_tag_list_new_empty ();
2587 gst_tag_list_set_scope (stream->stream_tags, GST_TAG_SCOPE_STREAM);
2588 g_free (stream->redirect_uri);
2589 stream->redirect_uri = NULL;
2590 stream->sent_eos = FALSE;
2591 stream->protected = FALSE;
2592 #ifdef OHOS_OPT_PERFORMANCE // ohos.opt.performance.0001: demux push first audio/video frame
2593 stream->has_push_first_frame = FALSE;
2594 #endif
2595 if (stream->protection_scheme_info) {
2596 if (stream->protection_scheme_type == FOURCC_cenc
2597 || stream->protection_scheme_type == FOURCC_cbcs) {
2598 QtDemuxCencSampleSetInfo *info =
2599 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
2600 if (info->default_properties)
2601 gst_structure_free (info->default_properties);
2602 if (info->crypto_info)
2603 g_ptr_array_free (info->crypto_info, TRUE);
2604 }
2605 if (stream->protection_scheme_type == FOURCC_aavd) {
2606 QtDemuxAavdEncryptionInfo *info =
2607 (QtDemuxAavdEncryptionInfo *) stream->protection_scheme_info;
2608 if (info->default_properties)
2609 gst_structure_free (info->default_properties);
2610 }
2611 g_free (stream->protection_scheme_info);
2612 stream->protection_scheme_info = NULL;
2613 }
2614 stream->protection_scheme_type = 0;
2615 stream->protection_scheme_version = 0;
2616 g_queue_foreach (&stream->protection_scheme_event_queue,
2617 (GFunc) gst_event_unref, NULL);
2618 g_queue_clear (&stream->protection_scheme_event_queue);
2619 gst_qtdemux_stream_flush_segments_data (stream);
2620 gst_qtdemux_stream_flush_samples_data (stream);
2621 }
2622
2623 static void
gst_qtdemux_stream_reset(QtDemuxStream * stream)2624 gst_qtdemux_stream_reset (QtDemuxStream * stream)
2625 {
2626 gint i;
2627 gst_qtdemux_stream_clear (stream);
2628 for (i = 0; i < stream->stsd_entries_length; i++) {
2629 QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[i];
2630 if (entry->caps) {
2631 gst_caps_unref (entry->caps);
2632 entry->caps = NULL;
2633 }
2634 }
2635 g_free (stream->stsd_entries);
2636 stream->stsd_entries = NULL;
2637 stream->stsd_entries_length = 0;
2638 }
2639
2640 static QtDemuxStream *
gst_qtdemux_stream_ref(QtDemuxStream * stream)2641 gst_qtdemux_stream_ref (QtDemuxStream * stream)
2642 {
2643 g_atomic_int_add (&stream->ref_count, 1);
2644
2645 return stream;
2646 }
2647
2648 static void
gst_qtdemux_stream_unref(QtDemuxStream * stream)2649 gst_qtdemux_stream_unref (QtDemuxStream * stream)
2650 {
2651 if (g_atomic_int_dec_and_test (&stream->ref_count)) {
2652 gst_qtdemux_stream_reset (stream);
2653 gst_tag_list_unref (stream->stream_tags);
2654 if (stream->pad) {
2655 GstQTDemux *demux = stream->demux;
2656 gst_element_remove_pad (GST_ELEMENT_CAST (demux), stream->pad);
2657 GST_OBJECT_LOCK (demux);
2658 gst_flow_combiner_remove_pad (demux->flowcombiner, stream->pad);
2659 GST_OBJECT_UNLOCK (demux);
2660 }
2661 g_free (stream->stream_id);
2662 g_free (stream);
2663 }
2664 }
2665
2666 static GstStateChangeReturn
gst_qtdemux_change_state(GstElement * element,GstStateChange transition)2667 gst_qtdemux_change_state (GstElement * element, GstStateChange transition)
2668 {
2669 GstQTDemux *qtdemux = GST_QTDEMUX (element);
2670 GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
2671
2672 switch (transition) {
2673 case GST_STATE_CHANGE_READY_TO_PAUSED:
2674 gst_qtdemux_reset (qtdemux, TRUE);
2675 break;
2676 default:
2677 break;
2678 }
2679
2680 result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
2681
2682 switch (transition) {
2683 case GST_STATE_CHANGE_PAUSED_TO_READY:{
2684 gst_qtdemux_reset (qtdemux, TRUE);
2685 break;
2686 }
2687 default:
2688 break;
2689 }
2690
2691 return result;
2692 }
2693
2694 static void
gst_qtdemux_set_context(GstElement * element,GstContext * context)2695 gst_qtdemux_set_context (GstElement * element, GstContext * context)
2696 {
2697 GstQTDemux *qtdemux = GST_QTDEMUX (element);
2698
2699 g_return_if_fail (GST_IS_CONTEXT (context));
2700
2701 if (gst_context_has_context_type (context,
2702 "drm-preferred-decryption-system-id")) {
2703 const GstStructure *s;
2704
2705 s = gst_context_get_structure (context);
2706 g_free (qtdemux->preferred_protection_system_id);
2707 qtdemux->preferred_protection_system_id =
2708 g_strdup (gst_structure_get_string (s, "decryption-system-id"));
2709 GST_DEBUG_OBJECT (element, "set preferred decryption system to %s",
2710 qtdemux->preferred_protection_system_id);
2711 }
2712
2713 GST_ELEMENT_CLASS (parent_class)->set_context (element, context);
2714 }
2715
2716 static void
qtdemux_parse_ftyp(GstQTDemux * qtdemux,const guint8 * buffer,gint length)2717 qtdemux_parse_ftyp (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2718 {
2719 /* counts as header data */
2720 qtdemux->header_size += length;
2721
2722 /* only consider at least a sufficiently complete ftyp atom */
2723 if (length >= 20) {
2724 GstBuffer *buf;
2725
2726 qtdemux->major_brand = QT_FOURCC (buffer + 8);
2727 GST_DEBUG_OBJECT (qtdemux, "major brand: %" GST_FOURCC_FORMAT,
2728 GST_FOURCC_ARGS (qtdemux->major_brand));
2729 if (qtdemux->comp_brands)
2730 gst_buffer_unref (qtdemux->comp_brands);
2731 buf = qtdemux->comp_brands = gst_buffer_new_and_alloc (length - 16);
2732 gst_buffer_fill (buf, 0, buffer + 16, length - 16);
2733 }
2734 }
2735
2736 static void
qtdemux_update_default_sample_cenc_settings(GstQTDemux * qtdemux,QtDemuxCencSampleSetInfo * info,guint32 is_encrypted,guint32 protection_scheme_type,guint8 iv_size,const guint8 * kid,guint crypt_byte_block,guint skip_byte_block,guint8 constant_iv_size,const guint8 * constant_iv)2737 qtdemux_update_default_sample_cenc_settings (GstQTDemux * qtdemux,
2738 QtDemuxCencSampleSetInfo * info, guint32 is_encrypted,
2739 guint32 protection_scheme_type, guint8 iv_size, const guint8 * kid,
2740 guint crypt_byte_block, guint skip_byte_block, guint8 constant_iv_size,
2741 const guint8 * constant_iv)
2742 {
2743 GstBuffer *kid_buf = gst_buffer_new_allocate (NULL, 16, NULL);
2744 gst_buffer_fill (kid_buf, 0, kid, 16);
2745 if (info->default_properties)
2746 gst_structure_free (info->default_properties);
2747 info->default_properties =
2748 gst_structure_new ("application/x-cenc",
2749 "iv_size", G_TYPE_UINT, iv_size,
2750 "encrypted", G_TYPE_BOOLEAN, (is_encrypted == 1),
2751 "kid", GST_TYPE_BUFFER, kid_buf, NULL);
2752 GST_DEBUG_OBJECT (qtdemux, "default sample properties: "
2753 "is_encrypted=%u, iv_size=%u", is_encrypted, iv_size);
2754 gst_buffer_unref (kid_buf);
2755 if (protection_scheme_type == FOURCC_cbcs) {
2756 if (crypt_byte_block != 0 || skip_byte_block != 0) {
2757 gst_structure_set (info->default_properties, "crypt_byte_block",
2758 G_TYPE_UINT, crypt_byte_block, "skip_byte_block", G_TYPE_UINT,
2759 skip_byte_block, NULL);
2760 }
2761 if (constant_iv != NULL) {
2762 GstBuffer *constant_iv_buf =
2763 gst_buffer_new_allocate (NULL, constant_iv_size, NULL);
2764 gst_buffer_fill (constant_iv_buf, 0, constant_iv, constant_iv_size);
2765 gst_structure_set (info->default_properties, "constant_iv_size",
2766 G_TYPE_UINT, constant_iv_size, "iv", GST_TYPE_BUFFER, constant_iv_buf,
2767 NULL);
2768 gst_buffer_unref (constant_iv_buf);
2769 }
2770 gst_structure_set (info->default_properties, "cipher-mode",
2771 G_TYPE_STRING, "cbcs", NULL);
2772 } else {
2773 gst_structure_set (info->default_properties, "cipher-mode",
2774 G_TYPE_STRING, "cenc", NULL);
2775 }
2776 }
2777
2778 static gboolean
qtdemux_update_default_piff_encryption_settings(GstQTDemux * qtdemux,QtDemuxCencSampleSetInfo * info,GstByteReader * br)2779 qtdemux_update_default_piff_encryption_settings (GstQTDemux * qtdemux,
2780 QtDemuxCencSampleSetInfo * info, GstByteReader * br)
2781 {
2782 guint32 algorithm_id = 0;
2783 const guint8 *kid;
2784 gboolean is_encrypted = TRUE;
2785 guint8 iv_size = 8;
2786
2787 if (!gst_byte_reader_get_uint24_le (br, &algorithm_id)) {
2788 GST_ERROR_OBJECT (qtdemux, "Error getting box's algorithm ID field");
2789 return FALSE;
2790 }
2791
2792 algorithm_id >>= 8;
2793 if (algorithm_id == 0) {
2794 is_encrypted = FALSE;
2795 } else if (algorithm_id == 1) {
2796 GST_DEBUG_OBJECT (qtdemux, "AES 128-bits CTR encrypted stream");
2797 } else if (algorithm_id == 2) {
2798 GST_DEBUG_OBJECT (qtdemux, "AES 128-bits CBC encrypted stream");
2799 }
2800
2801 if (!gst_byte_reader_get_uint8 (br, &iv_size))
2802 return FALSE;
2803
2804 if (!gst_byte_reader_get_data (br, 16, &kid))
2805 return FALSE;
2806
2807 qtdemux_update_default_sample_cenc_settings (qtdemux, info,
2808 is_encrypted, FOURCC_cenc, iv_size, kid, 0, 0, 0, NULL);
2809 gst_structure_set (info->default_properties, "piff_algorithm_id",
2810 G_TYPE_UINT, algorithm_id, NULL);
2811 return TRUE;
2812 }
2813
2814
2815 static void
qtdemux_parse_piff(GstQTDemux * qtdemux,const guint8 * buffer,gint length,guint offset)2816 qtdemux_parse_piff (GstQTDemux * qtdemux, const guint8 * buffer, gint length,
2817 guint offset)
2818 {
2819 GstByteReader br;
2820 guint8 version;
2821 guint32 flags = 0;
2822 guint i;
2823 guint iv_size = 8;
2824 QtDemuxStream *stream;
2825 GstStructure *structure;
2826 QtDemuxCencSampleSetInfo *ss_info = NULL;
2827 const gchar *system_id;
2828 gboolean uses_sub_sample_encryption = FALSE;
2829 guint32 sample_count;
2830
2831 if (QTDEMUX_N_STREAMS (qtdemux) == 0)
2832 return;
2833
2834 stream = QTDEMUX_NTH_STREAM (qtdemux, 0);
2835
2836 structure = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
2837 if (!gst_structure_has_name (structure, "application/x-cenc")) {
2838 GST_WARNING_OBJECT (qtdemux,
2839 "Attempting PIFF box parsing on an unencrypted stream.");
2840 return;
2841 }
2842
2843 gst_structure_get (structure, GST_PROTECTION_SYSTEM_ID_CAPS_FIELD,
2844 G_TYPE_STRING, &system_id, NULL);
2845 gst_qtdemux_append_protection_system_id (qtdemux, system_id);
2846
2847 stream->protected = TRUE;
2848 stream->protection_scheme_type = FOURCC_cenc;
2849
2850 if (!stream->protection_scheme_info)
2851 stream->protection_scheme_info = g_new0 (QtDemuxCencSampleSetInfo, 1);
2852
2853 ss_info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
2854 if (!ss_info->default_properties) {
2855 ss_info->default_properties =
2856 gst_structure_new ("application/x-cenc",
2857 "iv_size", G_TYPE_UINT, iv_size, "encrypted", G_TYPE_BOOLEAN, TRUE,
2858 NULL);
2859
2860 }
2861
2862 if (ss_info->crypto_info) {
2863 GST_LOG_OBJECT (qtdemux, "unreffing existing crypto_info");
2864 g_ptr_array_free (ss_info->crypto_info, TRUE);
2865 ss_info->crypto_info = NULL;
2866 }
2867
2868 /* skip UUID */
2869 gst_byte_reader_init (&br, buffer + offset + 16, length - offset - 16);
2870
2871 if (!gst_byte_reader_get_uint8 (&br, &version)) {
2872 GST_ERROR_OBJECT (qtdemux, "Error getting box's version field");
2873 return;
2874 }
2875
2876 if (!gst_byte_reader_get_uint24_be (&br, &flags)) {
2877 GST_ERROR_OBJECT (qtdemux, "Error getting box's flags field");
2878 return;
2879 }
2880
2881 if ((flags & 0x000001)) {
2882 if (!qtdemux_update_default_piff_encryption_settings (qtdemux, ss_info,
2883 &br))
2884 return;
2885 } else if ((flags & 0x000002)) {
2886 uses_sub_sample_encryption = TRUE;
2887 }
2888
2889 if (!gst_structure_get_uint (ss_info->default_properties, "iv_size",
2890 &iv_size)) {
2891 GST_ERROR_OBJECT (qtdemux, "Error getting encryption IV size field");
2892 return;
2893 }
2894
2895 if (!gst_byte_reader_get_uint32_be (&br, &sample_count)) {
2896 GST_ERROR_OBJECT (qtdemux, "Error getting box's sample count field");
2897 return;
2898 }
2899
2900 ss_info->crypto_info =
2901 g_ptr_array_new_full (sample_count,
2902 (GDestroyNotify) qtdemux_gst_structure_free);
2903
2904 for (i = 0; i < sample_count; ++i) {
2905 GstStructure *properties;
2906 guint8 *data;
2907 GstBuffer *buf;
2908
2909 properties = qtdemux_get_cenc_sample_properties (qtdemux, stream, i);
2910 if (properties == NULL) {
2911 GST_ERROR_OBJECT (qtdemux, "failed to get properties for sample %u", i);
2912 qtdemux->cenc_aux_sample_count = i;
2913 return;
2914 }
2915
2916 if (!gst_byte_reader_dup_data (&br, iv_size, &data)) {
2917 GST_ERROR_OBJECT (qtdemux, "IV data not present for sample %u", i);
2918 gst_structure_free (properties);
2919 qtdemux->cenc_aux_sample_count = i;
2920 return;
2921 }
2922 buf = gst_buffer_new_wrapped (data, iv_size);
2923 gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL);
2924 gst_buffer_unref (buf);
2925
2926 if (uses_sub_sample_encryption) {
2927 guint16 n_subsamples;
2928 const GValue *kid_buf_value;
2929
2930 if (!gst_byte_reader_get_uint16_be (&br, &n_subsamples)
2931 || n_subsamples == 0) {
2932 GST_ERROR_OBJECT (qtdemux,
2933 "failed to get subsample count for sample %u", i);
2934 gst_structure_free (properties);
2935 qtdemux->cenc_aux_sample_count = i;
2936 return;
2937 }
2938 GST_LOG_OBJECT (qtdemux, "subsample count: %u", n_subsamples);
2939 if (!gst_byte_reader_dup_data (&br, n_subsamples * 6, &data)) {
2940 GST_ERROR_OBJECT (qtdemux, "failed to get subsample data for sample %u",
2941 i);
2942 gst_structure_free (properties);
2943 qtdemux->cenc_aux_sample_count = i;
2944 return;
2945 }
2946 buf = gst_buffer_new_wrapped (data, n_subsamples * 6);
2947
2948 kid_buf_value =
2949 gst_structure_get_value (ss_info->default_properties, "kid");
2950
2951 gst_structure_set (properties,
2952 "subsample_count", G_TYPE_UINT, n_subsamples,
2953 "subsamples", GST_TYPE_BUFFER, buf, NULL);
2954 gst_structure_set_value (properties, "kid", kid_buf_value);
2955 gst_buffer_unref (buf);
2956 } else {
2957 gst_structure_set (properties, "subsample_count", G_TYPE_UINT, 0, NULL);
2958 }
2959
2960 g_ptr_array_add (ss_info->crypto_info, properties);
2961 }
2962
2963 qtdemux->cenc_aux_sample_count = sample_count;
2964 }
2965
2966 static void
qtdemux_parse_uuid(GstQTDemux * qtdemux,const guint8 * buffer,gint length)2967 qtdemux_parse_uuid (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2968 {
2969 static const guint8 xmp_uuid[] = { 0xBE, 0x7A, 0xCF, 0xCB,
2970 0x97, 0xA9, 0x42, 0xE8,
2971 0x9C, 0x71, 0x99, 0x94,
2972 0x91, 0xE3, 0xAF, 0xAC
2973 };
2974 static const guint8 playready_uuid[] = {
2975 0xd0, 0x8a, 0x4f, 0x18, 0x10, 0xf3, 0x4a, 0x82,
2976 0xb6, 0xc8, 0x32, 0xd8, 0xab, 0xa1, 0x83, 0xd3
2977 };
2978
2979 static const guint8 piff_sample_encryption_uuid[] = {
2980 0xa2, 0x39, 0x4f, 0x52, 0x5a, 0x9b, 0x4f, 0x14,
2981 0xa2, 0x44, 0x6c, 0x42, 0x7c, 0x64, 0x8d, 0xf4
2982 };
2983
2984 guint offset;
2985
2986 /* counts as header data */
2987 qtdemux->header_size += length;
2988
2989 offset = (QT_UINT32 (buffer) == 0) ? 16 : 8;
2990
2991 if (length <= offset + 16) {
2992 GST_DEBUG_OBJECT (qtdemux, "uuid atom is too short, skipping");
2993 return;
2994 }
2995
2996 if (memcmp (buffer + offset, xmp_uuid, 16) == 0) {
2997 GstBuffer *buf;
2998 GstTagList *taglist;
2999
3000 buf = _gst_buffer_new_wrapped ((guint8 *) buffer + offset + 16,
3001 length - offset - 16, NULL);
3002 taglist = gst_tag_list_from_xmp_buffer (buf);
3003 gst_buffer_unref (buf);
3004
3005 /* make sure we have a usable taglist */
3006 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
3007
3008 qtdemux_handle_xmp_taglist (qtdemux, qtdemux->tag_list, taglist);
3009
3010 } else if (memcmp (buffer + offset, playready_uuid, 16) == 0) {
3011 int len;
3012 const gunichar2 *s_utf16;
3013 char *contents;
3014
3015 len = GST_READ_UINT16_LE (buffer + offset + 0x30);
3016 s_utf16 = (const gunichar2 *) (buffer + offset + 0x32);
3017 contents = g_utf16_to_utf8 (s_utf16, len / 2, NULL, NULL, NULL);
3018 GST_ERROR_OBJECT (qtdemux, "contents: %s", contents);
3019
3020 g_free (contents);
3021
3022 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT,
3023 (_("Cannot play stream because it is encrypted with PlayReady DRM.")),
3024 (NULL));
3025 } else if (memcmp (buffer + offset, piff_sample_encryption_uuid, 16) == 0) {
3026 qtdemux_parse_piff (qtdemux, buffer, length, offset);
3027 } else {
3028 GST_DEBUG_OBJECT (qtdemux, "Ignoring unknown uuid: %08x-%08x-%08x-%08x",
3029 GST_READ_UINT32_LE (buffer + offset),
3030 GST_READ_UINT32_LE (buffer + offset + 4),
3031 GST_READ_UINT32_LE (buffer + offset + 8),
3032 GST_READ_UINT32_LE (buffer + offset + 12));
3033 }
3034 }
3035
3036 static void
qtdemux_parse_sidx(GstQTDemux * qtdemux,const guint8 * buffer,gint length)3037 qtdemux_parse_sidx (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
3038 {
3039 GstSidxParser sidx_parser;
3040 GstIsoffParserResult res;
3041 guint consumed;
3042
3043 gst_isoff_qt_sidx_parser_init (&sidx_parser);
3044
3045 res =
3046 gst_isoff_qt_sidx_parser_add_data (&sidx_parser, buffer, length,
3047 &consumed);
3048 GST_DEBUG_OBJECT (qtdemux, "sidx parse result: %d", res);
3049 if (res == GST_ISOFF_QT_PARSER_DONE) {
3050 check_update_duration (qtdemux, sidx_parser.cumulative_pts);
3051 }
3052 gst_isoff_qt_sidx_parser_clear (&sidx_parser);
3053 }
3054
3055 /* caller verifies at least 8 bytes in buf */
3056 static void
extract_initial_length_and_fourcc(const guint8 * data,guint size,guint64 * plength,guint32 * pfourcc)3057 extract_initial_length_and_fourcc (const guint8 * data, guint size,
3058 guint64 * plength, guint32 * pfourcc)
3059 {
3060 guint64 length;
3061 guint32 fourcc;
3062
3063 length = QT_UINT32 (data);
3064 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
3065 fourcc = QT_FOURCC (data + 4);
3066 GST_DEBUG ("atom type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
3067
3068 if (length == 0) {
3069 length = G_MAXUINT64;
3070 } else if (length == 1 && size >= 16) {
3071 /* this means we have an extended size, which is the 64 bit value of
3072 * the next 8 bytes */
3073 length = QT_UINT64 (data + 8);
3074 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
3075 }
3076
3077 if (plength)
3078 *plength = length;
3079 if (pfourcc)
3080 *pfourcc = fourcc;
3081 }
3082
3083 static gboolean
qtdemux_parse_mehd(GstQTDemux * qtdemux,GstByteReader * br)3084 qtdemux_parse_mehd (GstQTDemux * qtdemux, GstByteReader * br)
3085 {
3086 guint32 version = 0;
3087 GstClockTime duration = 0;
3088
3089 if (!gst_byte_reader_get_uint32_be (br, &version))
3090 goto failed;
3091
3092 version >>= 24;
3093 if (version == 1) {
3094 if (!gst_byte_reader_get_uint64_be (br, &duration))
3095 goto failed;
3096 } else {
3097 guint32 dur = 0;
3098
3099 if (!gst_byte_reader_get_uint32_be (br, &dur))
3100 goto failed;
3101 duration = dur;
3102 }
3103
3104 GST_INFO_OBJECT (qtdemux, "mehd duration: %" G_GUINT64_FORMAT, duration);
3105 qtdemux->duration = duration;
3106
3107 return TRUE;
3108
3109 failed:
3110 {
3111 GST_DEBUG_OBJECT (qtdemux, "parsing mehd failed");
3112 return FALSE;
3113 }
3114 }
3115
3116 static gboolean
qtdemux_parse_trex(GstQTDemux * qtdemux,QtDemuxStream * stream,guint32 * ds_duration,guint32 * ds_size,guint32 * ds_flags)3117 qtdemux_parse_trex (GstQTDemux * qtdemux, QtDemuxStream * stream,
3118 guint32 * ds_duration, guint32 * ds_size, guint32 * ds_flags)
3119 {
3120 if (!stream->parsed_trex && qtdemux->moov_node) {
3121 GNode *mvex, *trex;
3122 GstByteReader trex_data;
3123
3124 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
3125 if (mvex) {
3126 trex = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_trex,
3127 &trex_data);
3128 while (trex) {
3129 guint32 id = 0, sdi = 0, dur = 0, size = 0, flags = 0;
3130
3131 /* skip version/flags */
3132 if (!gst_byte_reader_skip (&trex_data, 4))
3133 goto next;
3134 if (!gst_byte_reader_get_uint32_be (&trex_data, &id))
3135 goto next;
3136 if (id != stream->track_id)
3137 goto next;
3138 if (!gst_byte_reader_get_uint32_be (&trex_data, &sdi))
3139 goto next;
3140 if (!gst_byte_reader_get_uint32_be (&trex_data, &dur))
3141 goto next;
3142 if (!gst_byte_reader_get_uint32_be (&trex_data, &size))
3143 goto next;
3144 if (!gst_byte_reader_get_uint32_be (&trex_data, &flags))
3145 goto next;
3146
3147 GST_DEBUG_OBJECT (qtdemux, "fragment defaults for stream %d; "
3148 "duration %d, size %d, flags 0x%x", stream->track_id,
3149 dur, size, flags);
3150
3151 stream->parsed_trex = TRUE;
3152 stream->def_sample_description_index = sdi;
3153 stream->def_sample_duration = dur;
3154 stream->def_sample_size = size;
3155 stream->def_sample_flags = flags;
3156
3157 next:
3158 /* iterate all siblings */
3159 trex = qtdemux_tree_get_sibling_by_type_full (trex, FOURCC_trex,
3160 &trex_data);
3161 }
3162 }
3163 }
3164
3165 *ds_duration = stream->def_sample_duration;
3166 *ds_size = stream->def_sample_size;
3167 *ds_flags = stream->def_sample_flags;
3168
3169 /* even then, above values are better than random ... */
3170 if (G_UNLIKELY (!stream->parsed_trex)) {
3171 GST_WARNING_OBJECT (qtdemux,
3172 "failed to find fragment defaults for stream %d", stream->track_id);
3173 return FALSE;
3174 }
3175
3176 return TRUE;
3177 }
3178
3179 /* This method should be called whenever a more accurate duration might
3180 * have been found. It will update all relevant variables if/where needed
3181 */
3182 static void
check_update_duration(GstQTDemux * qtdemux,GstClockTime duration)3183 check_update_duration (GstQTDemux * qtdemux, GstClockTime duration)
3184 {
3185 guint i;
3186 guint64 movdur;
3187 GstClockTime prevdur;
3188
3189 movdur = GSTTIME_TO_QTTIME (qtdemux, duration);
3190
3191 if (movdur > qtdemux->duration) {
3192 prevdur = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
3193 GST_DEBUG_OBJECT (qtdemux,
3194 "Updating total duration to %" GST_TIME_FORMAT " was %" GST_TIME_FORMAT,
3195 GST_TIME_ARGS (duration), GST_TIME_ARGS (prevdur));
3196 qtdemux->duration = movdur;
3197 GST_DEBUG_OBJECT (qtdemux,
3198 "qtdemux->segment.duration: %" GST_TIME_FORMAT " .stop: %"
3199 GST_TIME_FORMAT, GST_TIME_ARGS (qtdemux->segment.duration),
3200 GST_TIME_ARGS (qtdemux->segment.stop));
3201 if (qtdemux->segment.duration == prevdur) {
3202 /* If the current segment has duration/stop identical to previous duration
3203 * update them also (because they were set at that point in time with
3204 * the wrong duration */
3205 /* We convert the value *from* the timescale version to avoid rounding errors */
3206 GstClockTime fixeddur = QTTIME_TO_GSTTIME (qtdemux, movdur);
3207 GST_DEBUG_OBJECT (qtdemux, "Updated segment.duration and segment.stop");
3208 qtdemux->segment.duration = fixeddur;
3209 qtdemux->segment.stop = fixeddur;
3210 }
3211 }
3212
3213 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
3214 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
3215
3216 movdur = GSTTIME_TO_QTSTREAMTIME (stream, duration);
3217 if (movdur > stream->duration) {
3218 GST_DEBUG_OBJECT (qtdemux,
3219 "Updating stream #%d duration to %" GST_TIME_FORMAT, i,
3220 GST_TIME_ARGS (duration));
3221 stream->duration = movdur;
3222 /* internal duration tracking state has been updated above, so */
3223 /* preserve an open-ended dummy segment rather than repeatedly updating
3224 * it and spamming downstream accordingly with segment events */
3225 /* also mangle the edit list end time when fragmented with a single edit
3226 * list that may only cover any non-fragmented data */
3227 if ((stream->dummy_segment ||
3228 (qtdemux->fragmented && stream->n_segments == 1)) &&
3229 GST_CLOCK_TIME_IS_VALID (stream->segments[0].duration)) {
3230 /* Update all dummy values to new duration */
3231 stream->segments[0].stop_time = duration;
3232 stream->segments[0].duration = duration;
3233 stream->segments[0].media_stop = duration;
3234
3235 /* let downstream know we possibly have a new stop time */
3236 if (stream->segment_index != -1) {
3237 GstClockTime pos;
3238
3239 if (qtdemux->segment.rate >= 0) {
3240 pos = stream->segment.start;
3241 } else {
3242 pos = stream->segment.stop;
3243 }
3244
3245 gst_qtdemux_stream_update_segment (qtdemux, stream,
3246 stream->segment_index, pos, NULL, NULL);
3247 }
3248 }
3249 }
3250 }
3251 }
3252
3253 static gboolean
qtdemux_parse_trun(GstQTDemux * qtdemux,GstByteReader * trun,QtDemuxStream * stream,guint32 d_sample_duration,guint32 d_sample_size,guint32 d_sample_flags,gint64 moof_offset,gint64 moof_length,gint64 * base_offset,gint64 * running_offset,gint64 decode_ts,gboolean has_tfdt)3254 qtdemux_parse_trun (GstQTDemux * qtdemux, GstByteReader * trun,
3255 QtDemuxStream * stream, guint32 d_sample_duration, guint32 d_sample_size,
3256 guint32 d_sample_flags, gint64 moof_offset, gint64 moof_length,
3257 gint64 * base_offset, gint64 * running_offset, gint64 decode_ts,
3258 gboolean has_tfdt)
3259 {
3260 GstClockTime gst_ts = GST_CLOCK_TIME_NONE;
3261 guint64 timestamp;
3262 gint32 data_offset = 0;
3263 guint8 version;
3264 guint32 flags = 0, first_flags = 0, samples_count = 0;
3265 gint i;
3266 guint8 *data;
3267 guint entry_size, dur_offset, size_offset, flags_offset = 0, ct_offset = 0;
3268 QtDemuxSample *sample;
3269 gboolean ismv = FALSE;
3270 gint64 initial_offset;
3271 gint32 min_ct = 0;
3272
3273 GST_LOG_OBJECT (qtdemux, "parsing trun track-id %d; "
3274 "default dur %d, size %d, flags 0x%x, base offset %" G_GINT64_FORMAT ", "
3275 "decode ts %" G_GINT64_FORMAT, stream->track_id, d_sample_duration,
3276 d_sample_size, d_sample_flags, *base_offset, decode_ts);
3277
3278 if (stream->pending_seek && moof_offset < stream->pending_seek->moof_offset) {
3279 GST_INFO_OBJECT (stream->pad, "skipping trun before seek target fragment");
3280 return TRUE;
3281 }
3282
3283 /* presence of stss or not can't really tell us much,
3284 * and flags and so on tend to be marginally reliable in these files */
3285 if (stream->subtype == FOURCC_soun) {
3286 GST_DEBUG_OBJECT (qtdemux,
3287 "sound track in fragmented file; marking all keyframes");
3288 stream->all_keyframe = TRUE;
3289 }
3290
3291 if (!gst_byte_reader_get_uint8 (trun, &version) ||
3292 !gst_byte_reader_get_uint24_be (trun, &flags))
3293 goto fail;
3294
3295 if (!gst_byte_reader_get_uint32_be (trun, &samples_count))
3296 goto fail;
3297
3298 if (flags & TR_DATA_OFFSET) {
3299 /* note this is really signed */
3300 if (!gst_byte_reader_get_int32_be (trun, &data_offset))
3301 goto fail;
3302 GST_LOG_OBJECT (qtdemux, "trun data offset %d", data_offset);
3303 /* default base offset = first byte of moof */
3304 if (*base_offset == -1) {
3305 GST_LOG_OBJECT (qtdemux, "base_offset at moof");
3306 *base_offset = moof_offset;
3307 }
3308 *running_offset = *base_offset + data_offset;
3309 } else {
3310 /* if no offset at all, that would mean data starts at moof start,
3311 * which is a bit wrong and is ismv crappy way, so compensate
3312 * assuming data is in mdat following moof */
3313 if (*base_offset == -1) {
3314 *base_offset = moof_offset + moof_length + 8;
3315 GST_LOG_OBJECT (qtdemux, "base_offset assumed in mdat after moof");
3316 ismv = TRUE;
3317 }
3318 if (*running_offset == -1)
3319 *running_offset = *base_offset;
3320 }
3321
3322 GST_LOG_OBJECT (qtdemux, "running offset now %" G_GINT64_FORMAT,
3323 *running_offset);
3324 GST_LOG_OBJECT (qtdemux, "trun offset %d, flags 0x%x, entries %d",
3325 data_offset, flags, samples_count);
3326
3327 if (flags & TR_FIRST_SAMPLE_FLAGS) {
3328 if (G_UNLIKELY (flags & TR_SAMPLE_FLAGS)) {
3329 GST_DEBUG_OBJECT (qtdemux,
3330 "invalid flags; SAMPLE and FIRST_SAMPLE present, discarding latter");
3331 flags ^= TR_FIRST_SAMPLE_FLAGS;
3332 } else {
3333 if (!gst_byte_reader_get_uint32_be (trun, &first_flags))
3334 goto fail;
3335 GST_LOG_OBJECT (qtdemux, "first flags: 0x%x", first_flags);
3336 }
3337 }
3338
3339 /* FIXME ? spec says other bits should also be checked to determine
3340 * entry size (and prefix size for that matter) */
3341 entry_size = 0;
3342 dur_offset = size_offset = 0;
3343 if (flags & TR_SAMPLE_DURATION) {
3344 GST_LOG_OBJECT (qtdemux, "entry duration present");
3345 dur_offset = entry_size;
3346 entry_size += 4;
3347 }
3348 if (flags & TR_SAMPLE_SIZE) {
3349 GST_LOG_OBJECT (qtdemux, "entry size present");
3350 size_offset = entry_size;
3351 entry_size += 4;
3352 }
3353 if (flags & TR_SAMPLE_FLAGS) {
3354 GST_LOG_OBJECT (qtdemux, "entry flags present");
3355 flags_offset = entry_size;
3356 entry_size += 4;
3357 }
3358 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
3359 GST_LOG_OBJECT (qtdemux, "entry ct offset present");
3360 ct_offset = entry_size;
3361 entry_size += 4;
3362 }
3363
3364 if (!qt_atom_parser_has_chunks (trun, samples_count, entry_size))
3365 goto fail;
3366 data = (guint8 *) gst_byte_reader_peek_data_unchecked (trun);
3367
3368 if (stream->n_samples + samples_count >=
3369 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample))
3370 goto index_too_big;
3371
3372 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
3373 stream->n_samples + samples_count, (guint) sizeof (QtDemuxSample),
3374 (stream->n_samples + samples_count) *
3375 sizeof (QtDemuxSample) / (1024.0 * 1024.0));
3376
3377 /* create a new array of samples if it's the first sample parsed */
3378 if (stream->n_samples == 0) {
3379 g_assert (stream->samples == NULL);
3380 stream->samples = g_try_new0 (QtDemuxSample, samples_count);
3381 /* or try to reallocate it with space enough to insert the new samples */
3382 } else
3383 stream->samples = g_try_renew (QtDemuxSample, stream->samples,
3384 stream->n_samples + samples_count);
3385 if (stream->samples == NULL)
3386 goto out_of_memory;
3387
3388 if (qtdemux->fragment_start != -1) {
3389 timestamp = GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->fragment_start);
3390 qtdemux->fragment_start = -1;
3391 } else {
3392 if (stream->n_samples == 0) {
3393 if (decode_ts > 0) {
3394 timestamp = decode_ts;
3395 } else if (stream->pending_seek != NULL) {
3396 /* if we don't have a timestamp from a tfdt box, we'll use the one
3397 * from the mfra seek table */
3398 GST_INFO_OBJECT (stream->pad, "pending seek ts = %" GST_TIME_FORMAT,
3399 GST_TIME_ARGS (stream->pending_seek->ts));
3400
3401 /* FIXME: this is not fully correct, the timestamp refers to the random
3402 * access sample refered to in the tfra entry, which may not necessarily
3403 * be the first sample in the tfrag/trun (but hopefully/usually is) */
3404 timestamp = GSTTIME_TO_QTSTREAMTIME (stream, stream->pending_seek->ts);
3405 } else {
3406 timestamp = 0;
3407 }
3408
3409 gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
3410 GST_INFO_OBJECT (stream->pad, "first sample ts %" GST_TIME_FORMAT,
3411 GST_TIME_ARGS (gst_ts));
3412 } else {
3413 /* subsequent fragments extend stream */
3414 timestamp =
3415 stream->samples[stream->n_samples - 1].timestamp +
3416 stream->samples[stream->n_samples - 1].duration;
3417
3418 /* If this is a GST_FORMAT_BYTES stream and there's a significant
3419 * difference (1 sec.) between decode_ts and timestamp, prefer the
3420 * former */
3421 if (has_tfdt && !qtdemux->upstream_format_is_time
3422 && ABSDIFF (decode_ts, timestamp) >
3423 MAX (stream->duration_last_moof / 2,
3424 GSTTIME_TO_QTSTREAMTIME (stream, GST_SECOND))) {
3425 GST_INFO_OBJECT (qtdemux,
3426 "decode_ts (%" GST_TIME_FORMAT ") and timestamp (%" GST_TIME_FORMAT
3427 ") are significantly different (more than %" GST_TIME_FORMAT
3428 "), using decode_ts",
3429 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, decode_ts)),
3430 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, timestamp)),
3431 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream,
3432 MAX (stream->duration_last_moof / 2,
3433 GSTTIME_TO_QTSTREAMTIME (stream, GST_SECOND)))));
3434 timestamp = decode_ts;
3435 }
3436
3437 gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
3438 GST_INFO_OBJECT (qtdemux, "first sample ts %" GST_TIME_FORMAT
3439 " (extends previous samples)", GST_TIME_ARGS (gst_ts));
3440 }
3441 }
3442
3443 initial_offset = *running_offset;
3444
3445 sample = stream->samples + stream->n_samples;
3446 for (i = 0; i < samples_count; i++) {
3447 guint32 dur, size, sflags;
3448 gint32 ct;
3449
3450 /* first read sample data */
3451 if (flags & TR_SAMPLE_DURATION) {
3452 dur = QT_UINT32 (data + dur_offset);
3453 } else {
3454 dur = d_sample_duration;
3455 }
3456 if (flags & TR_SAMPLE_SIZE) {
3457 size = QT_UINT32 (data + size_offset);
3458 } else {
3459 size = d_sample_size;
3460 }
3461 if (flags & TR_FIRST_SAMPLE_FLAGS) {
3462 if (i == 0) {
3463 sflags = first_flags;
3464 } else {
3465 sflags = d_sample_flags;
3466 }
3467 } else if (flags & TR_SAMPLE_FLAGS) {
3468 sflags = QT_UINT32 (data + flags_offset);
3469 } else {
3470 sflags = d_sample_flags;
3471 }
3472
3473 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
3474 /* Read offsets as signed numbers regardless of trun version as very
3475 * high offsets are unlikely and there are files out there that use
3476 * version=0 truns with negative offsets */
3477 ct = QT_UINT32 (data + ct_offset);
3478
3479 /* FIXME: Set offset to 0 for "no decode samples". This needs
3480 * to be handled in a codec specific manner ideally. */
3481 if (ct == G_MININT32)
3482 ct = 0;
3483 } else {
3484 ct = 0;
3485 }
3486 data += entry_size;
3487
3488 /* fill the sample information */
3489 sample->offset = *running_offset;
3490 sample->pts_offset = ct;
3491 sample->size = size;
3492 sample->timestamp = timestamp;
3493 sample->duration = dur;
3494 /* sample-is-difference-sample */
3495 /* ismv seems to use 0x40 for keyframe, 0xc0 for non-keyframe,
3496 * now idea how it relates to bitfield other than massive LE/BE confusion */
3497 sample->keyframe = ismv ? ((sflags & 0xff) == 0x40) : !(sflags & 0x10000);
3498 *running_offset += size;
3499 timestamp += dur;
3500 stream->duration_moof += dur;
3501 sample++;
3502
3503 if (ct < min_ct)
3504 min_ct = ct;
3505 }
3506
3507 /* Shift PTS/DTS to allow for negative composition offsets while keeping
3508 * A/V sync in place. This is similar to the code handling ctts/cslg in the
3509 * non-fragmented case.
3510 */
3511 if (min_ct < 0)
3512 stream->cslg_shift = -min_ct;
3513 else
3514 stream->cslg_shift = 0;
3515
3516 GST_DEBUG_OBJECT (qtdemux, "Using clsg_shift %" G_GUINT64_FORMAT,
3517 stream->cslg_shift);
3518
3519 /* Update total duration if needed */
3520 check_update_duration (qtdemux, QTSTREAMTIME_TO_GSTTIME (stream, timestamp));
3521
3522 /* Pre-emptively figure out size of mdat based on trun information.
3523 * If the [mdat] atom is effectivelly read, it will be replaced by the actual
3524 * size, else we will still be able to use this when dealing with gap'ed
3525 * input */
3526 qtdemux->mdatleft = *running_offset - initial_offset;
3527 qtdemux->mdatoffset = initial_offset;
3528 qtdemux->mdatsize = qtdemux->mdatleft;
3529
3530 stream->n_samples += samples_count;
3531 stream->n_samples_moof += samples_count;
3532
3533 if (stream->pending_seek != NULL)
3534 stream->pending_seek = NULL;
3535
3536 return TRUE;
3537
3538 fail:
3539 {
3540 GST_WARNING_OBJECT (qtdemux, "failed to parse trun");
3541 return FALSE;
3542 }
3543 out_of_memory:
3544 {
3545 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
3546 stream->n_samples);
3547 return FALSE;
3548 }
3549 index_too_big:
3550 {
3551 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
3552 "be larger than %uMB (broken file?)", stream->n_samples,
3553 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
3554 return FALSE;
3555 }
3556 }
3557
3558 /* find stream with @id */
3559 static inline QtDemuxStream *
qtdemux_find_stream(GstQTDemux * qtdemux,guint32 id)3560 qtdemux_find_stream (GstQTDemux * qtdemux, guint32 id)
3561 {
3562 QtDemuxStream *stream;
3563 gint i;
3564
3565 /* check */
3566 if (G_UNLIKELY (!id)) {
3567 GST_DEBUG_OBJECT (qtdemux, "invalid track id 0");
3568 return NULL;
3569 }
3570
3571 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
3572 stream = QTDEMUX_NTH_STREAM (qtdemux, i);
3573 if (stream->track_id == id)
3574 return stream;
3575 }
3576 if (qtdemux->mss_mode) {
3577 /* mss should have only 1 stream anyway */
3578 return QTDEMUX_NTH_STREAM (qtdemux, 0);
3579 }
3580
3581 return NULL;
3582 }
3583
3584 static gboolean
qtdemux_parse_mfhd(GstQTDemux * qtdemux,GstByteReader * mfhd,guint32 * fragment_number)3585 qtdemux_parse_mfhd (GstQTDemux * qtdemux, GstByteReader * mfhd,
3586 guint32 * fragment_number)
3587 {
3588 if (!gst_byte_reader_skip (mfhd, 4))
3589 goto fail;
3590 if (!gst_byte_reader_get_uint32_be (mfhd, fragment_number))
3591 goto fail;
3592 return TRUE;
3593 fail:
3594 {
3595 GST_WARNING_OBJECT (qtdemux, "Failed to parse mfhd atom");
3596 return FALSE;
3597 }
3598 }
3599
3600 static gboolean
qtdemux_parse_tfhd(GstQTDemux * qtdemux,GstByteReader * tfhd,QtDemuxStream ** stream,guint32 * default_sample_duration,guint32 * default_sample_size,guint32 * default_sample_flags,gint64 * base_offset)3601 qtdemux_parse_tfhd (GstQTDemux * qtdemux, GstByteReader * tfhd,
3602 QtDemuxStream ** stream, guint32 * default_sample_duration,
3603 guint32 * default_sample_size, guint32 * default_sample_flags,
3604 gint64 * base_offset)
3605 {
3606 guint32 flags = 0;
3607 guint32 track_id = 0;
3608
3609 if (!gst_byte_reader_skip (tfhd, 1) ||
3610 !gst_byte_reader_get_uint24_be (tfhd, &flags))
3611 goto invalid_track;
3612
3613 if (!gst_byte_reader_get_uint32_be (tfhd, &track_id))
3614 goto invalid_track;
3615
3616 *stream = qtdemux_find_stream (qtdemux, track_id);
3617 if (G_UNLIKELY (!*stream))
3618 goto unknown_stream;
3619
3620 if (flags & TF_DEFAULT_BASE_IS_MOOF)
3621 *base_offset = qtdemux->moof_offset;
3622
3623 if (flags & TF_BASE_DATA_OFFSET)
3624 if (!gst_byte_reader_get_uint64_be (tfhd, (guint64 *) base_offset))
3625 goto invalid_track;
3626
3627 /* obtain stream defaults */
3628 qtdemux_parse_trex (qtdemux, *stream,
3629 default_sample_duration, default_sample_size, default_sample_flags);
3630
3631 (*stream)->stsd_sample_description_id =
3632 (*stream)->def_sample_description_index - 1;
3633
3634 if (flags & TF_SAMPLE_DESCRIPTION_INDEX) {
3635 guint32 sample_description_index;
3636 if (!gst_byte_reader_get_uint32_be (tfhd, &sample_description_index))
3637 goto invalid_track;
3638 (*stream)->stsd_sample_description_id = sample_description_index - 1;
3639 }
3640
3641 if (qtdemux->mss_mode) {
3642 /* mss has no stsd entry */
3643 (*stream)->stsd_sample_description_id = 0;
3644 }
3645
3646 if (flags & TF_DEFAULT_SAMPLE_DURATION)
3647 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_duration))
3648 goto invalid_track;
3649
3650 if (flags & TF_DEFAULT_SAMPLE_SIZE)
3651 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_size))
3652 goto invalid_track;
3653
3654 if (flags & TF_DEFAULT_SAMPLE_FLAGS)
3655 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_flags))
3656 goto invalid_track;
3657
3658 return TRUE;
3659
3660 invalid_track:
3661 {
3662 GST_WARNING_OBJECT (qtdemux, "invalid track fragment header");
3663 return FALSE;
3664 }
3665 unknown_stream:
3666 {
3667 GST_DEBUG_OBJECT (qtdemux, "unknown stream (%u) in tfhd", track_id);
3668 return TRUE;
3669 }
3670 }
3671
3672 static gboolean
qtdemux_parse_tfdt(GstQTDemux * qtdemux,GstByteReader * br,guint64 * decode_time)3673 qtdemux_parse_tfdt (GstQTDemux * qtdemux, GstByteReader * br,
3674 guint64 * decode_time)
3675 {
3676 guint32 version = 0;
3677
3678 if (!gst_byte_reader_get_uint32_be (br, &version))
3679 return FALSE;
3680
3681 version >>= 24;
3682 if (version == 1) {
3683 if (!gst_byte_reader_get_uint64_be (br, decode_time))
3684 goto failed;
3685 } else {
3686 guint32 dec_time = 0;
3687 if (!gst_byte_reader_get_uint32_be (br, &dec_time))
3688 goto failed;
3689 *decode_time = dec_time;
3690 }
3691
3692 GST_INFO_OBJECT (qtdemux, "Track fragment decode time: %" G_GUINT64_FORMAT,
3693 *decode_time);
3694
3695 return TRUE;
3696
3697 failed:
3698 {
3699 GST_DEBUG_OBJECT (qtdemux, "parsing tfdt failed");
3700 return FALSE;
3701 }
3702 }
3703
3704 /* Returns a pointer to a GstStructure containing the properties of
3705 * the stream sample identified by @sample_index. The caller must unref
3706 * the returned object after use. Returns NULL if unsuccessful. */
3707 static GstStructure *
qtdemux_get_cenc_sample_properties(GstQTDemux * qtdemux,QtDemuxStream * stream,guint sample_index)3708 qtdemux_get_cenc_sample_properties (GstQTDemux * qtdemux,
3709 QtDemuxStream * stream, guint sample_index)
3710 {
3711 QtDemuxCencSampleSetInfo *info = NULL;
3712
3713 g_return_val_if_fail (stream != NULL, NULL);
3714 g_return_val_if_fail (stream->protected, NULL);
3715 g_return_val_if_fail (stream->protection_scheme_info != NULL, NULL);
3716
3717 info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
3718
3719 /* Currently, cenc properties for groups of samples are not supported, so
3720 * simply return a copy of the default sample properties */
3721 return gst_structure_copy (info->default_properties);
3722 }
3723
3724 /* Parses the sizes of sample auxiliary information contained within a stream,
3725 * as given in a saiz box. Returns array of sample_count guint8 size values,
3726 * or NULL on failure */
3727 static guint8 *
qtdemux_parse_saiz(GstQTDemux * qtdemux,QtDemuxStream * stream,GstByteReader * br,guint32 * sample_count)3728 qtdemux_parse_saiz (GstQTDemux * qtdemux, QtDemuxStream * stream,
3729 GstByteReader * br, guint32 * sample_count)
3730 {
3731 guint32 flags = 0;
3732 guint8 *info_sizes;
3733 guint8 default_info_size;
3734
3735 g_return_val_if_fail (qtdemux != NULL, NULL);
3736 g_return_val_if_fail (stream != NULL, NULL);
3737 g_return_val_if_fail (br != NULL, NULL);
3738 g_return_val_if_fail (sample_count != NULL, NULL);
3739
3740 if (!gst_byte_reader_get_uint32_be (br, &flags))
3741 return NULL;
3742
3743 if (flags & 0x1) {
3744 /* aux_info_type and aux_info_type_parameter are ignored */
3745 if (!gst_byte_reader_skip (br, 8))
3746 return NULL;
3747 }
3748
3749 if (!gst_byte_reader_get_uint8 (br, &default_info_size))
3750 return NULL;
3751 GST_DEBUG_OBJECT (qtdemux, "default_info_size: %u", default_info_size);
3752
3753 if (!gst_byte_reader_get_uint32_be (br, sample_count))
3754 return NULL;
3755 GST_DEBUG_OBJECT (qtdemux, "sample_count: %u", *sample_count);
3756
3757
3758 if (default_info_size == 0) {
3759 if (!gst_byte_reader_dup_data (br, *sample_count, &info_sizes)) {
3760 return NULL;
3761 }
3762 } else {
3763 info_sizes = g_new (guint8, *sample_count);
3764 memset (info_sizes, default_info_size, *sample_count);
3765 }
3766
3767 return info_sizes;
3768 }
3769
3770 /* Parses the offset of sample auxiliary information contained within a stream,
3771 * as given in a saio box. Returns TRUE if successful; FALSE otherwise. */
3772 static gboolean
qtdemux_parse_saio(GstQTDemux * qtdemux,QtDemuxStream * stream,GstByteReader * br,guint32 * info_type,guint32 * info_type_parameter,guint64 * offset)3773 qtdemux_parse_saio (GstQTDemux * qtdemux, QtDemuxStream * stream,
3774 GstByteReader * br, guint32 * info_type, guint32 * info_type_parameter,
3775 guint64 * offset)
3776 {
3777 guint8 version = 0;
3778 guint32 flags = 0;
3779 guint32 aux_info_type = 0;
3780 guint32 aux_info_type_parameter = 0;
3781 guint32 entry_count;
3782 guint32 off_32;
3783 guint64 off_64;
3784 const guint8 *aux_info_type_data = NULL;
3785
3786 g_return_val_if_fail (qtdemux != NULL, FALSE);
3787 g_return_val_if_fail (stream != NULL, FALSE);
3788 g_return_val_if_fail (br != NULL, FALSE);
3789 g_return_val_if_fail (offset != NULL, FALSE);
3790
3791 if (!gst_byte_reader_get_uint8 (br, &version))
3792 return FALSE;
3793
3794 if (!gst_byte_reader_get_uint24_be (br, &flags))
3795 return FALSE;
3796
3797 if (flags & 0x1) {
3798
3799 if (!gst_byte_reader_get_data (br, 4, &aux_info_type_data))
3800 return FALSE;
3801 aux_info_type = QT_FOURCC (aux_info_type_data);
3802
3803 if (!gst_byte_reader_get_uint32_be (br, &aux_info_type_parameter))
3804 return FALSE;
3805 } else if (stream->protected) {
3806 aux_info_type = stream->protection_scheme_type;
3807 } else {
3808 aux_info_type = CUR_STREAM (stream)->fourcc;
3809 }
3810
3811 if (info_type)
3812 *info_type = aux_info_type;
3813 if (info_type_parameter)
3814 *info_type_parameter = aux_info_type_parameter;
3815
3816 GST_DEBUG_OBJECT (qtdemux, "aux_info_type: '%" GST_FOURCC_FORMAT "', "
3817 "aux_info_type_parameter: %#06x",
3818 GST_FOURCC_ARGS (aux_info_type), aux_info_type_parameter);
3819
3820 if (!gst_byte_reader_get_uint32_be (br, &entry_count))
3821 return FALSE;
3822
3823 if (entry_count != 1) {
3824 GST_ERROR_OBJECT (qtdemux, "multiple offsets are not supported");
3825 return FALSE;
3826 }
3827
3828 if (version == 0) {
3829 if (!gst_byte_reader_get_uint32_be (br, &off_32))
3830 return FALSE;
3831 *offset = (guint64) off_32;
3832 } else {
3833 if (!gst_byte_reader_get_uint64_be (br, &off_64))
3834 return FALSE;
3835 *offset = off_64;
3836 }
3837
3838 GST_DEBUG_OBJECT (qtdemux, "offset: %" G_GUINT64_FORMAT, *offset);
3839 return TRUE;
3840 }
3841
3842 static void
qtdemux_gst_structure_free(GstStructure * gststructure)3843 qtdemux_gst_structure_free (GstStructure * gststructure)
3844 {
3845 if (gststructure) {
3846 gst_structure_free (gststructure);
3847 }
3848 }
3849
3850 /* Parses auxiliary information relating to samples protected using
3851 * Common Encryption (cenc); the format of this information
3852 * is defined in ISO/IEC 23001-7. Returns TRUE if successful; FALSE
3853 * otherwise. */
3854 static gboolean
qtdemux_parse_cenc_aux_info(GstQTDemux * qtdemux,QtDemuxStream * stream,GstByteReader * br,guint8 * info_sizes,guint32 sample_count)3855 qtdemux_parse_cenc_aux_info (GstQTDemux * qtdemux, QtDemuxStream * stream,
3856 GstByteReader * br, guint8 * info_sizes, guint32 sample_count)
3857 {
3858 QtDemuxCencSampleSetInfo *ss_info = NULL;
3859 guint8 size;
3860 gint i;
3861 GPtrArray *old_crypto_info = NULL;
3862 guint old_entries = 0;
3863
3864 g_return_val_if_fail (qtdemux != NULL, FALSE);
3865 g_return_val_if_fail (stream != NULL, FALSE);
3866 g_return_val_if_fail (br != NULL, FALSE);
3867 g_return_val_if_fail (stream->protected, FALSE);
3868 g_return_val_if_fail (stream->protection_scheme_info != NULL, FALSE);
3869
3870 ss_info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
3871
3872 if (ss_info->crypto_info) {
3873 old_crypto_info = ss_info->crypto_info;
3874 /* Count number of non-null entries remaining at the tail end */
3875 for (i = old_crypto_info->len - 1; i >= 0; i--) {
3876 if (g_ptr_array_index (old_crypto_info, i) == NULL)
3877 break;
3878 old_entries++;
3879 }
3880 }
3881
3882 ss_info->crypto_info =
3883 g_ptr_array_new_full (sample_count + old_entries,
3884 (GDestroyNotify) qtdemux_gst_structure_free);
3885
3886 /* We preserve old entries because we parse the next moof in advance
3887 * of consuming all samples from the previous moof, and otherwise
3888 * we'd discard the corresponding crypto info for the samples
3889 * from the previous fragment. */
3890 if (old_entries) {
3891 GST_DEBUG_OBJECT (qtdemux, "Preserving %d old crypto info entries",
3892 old_entries);
3893 for (i = old_crypto_info->len - old_entries; i < old_crypto_info->len; i++) {
3894 g_ptr_array_add (ss_info->crypto_info, g_ptr_array_index (old_crypto_info,
3895 i));
3896 g_ptr_array_index (old_crypto_info, i) = NULL;
3897 }
3898 }
3899
3900 if (old_crypto_info) {
3901 /* Everything now belongs to the new array */
3902 g_ptr_array_free (old_crypto_info, TRUE);
3903 }
3904
3905 for (i = 0; i < sample_count; ++i) {
3906 GstStructure *properties;
3907 guint16 n_subsamples = 0;
3908 guint8 *data;
3909 guint iv_size;
3910 GstBuffer *buf;
3911 gboolean could_read_iv;
3912
3913 properties = qtdemux_get_cenc_sample_properties (qtdemux, stream, i);
3914 if (properties == NULL) {
3915 GST_ERROR_OBJECT (qtdemux, "failed to get properties for sample %u", i);
3916 return FALSE;
3917 }
3918 if (!gst_structure_get_uint (properties, "iv_size", &iv_size)) {
3919 GST_ERROR_OBJECT (qtdemux, "failed to get iv_size for sample %u", i);
3920 gst_structure_free (properties);
3921 return FALSE;
3922 }
3923 could_read_iv =
3924 iv_size > 0 ? gst_byte_reader_dup_data (br, iv_size, &data) : FALSE;
3925 if (could_read_iv) {
3926 buf = gst_buffer_new_wrapped (data, iv_size);
3927 gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL);
3928 gst_buffer_unref (buf);
3929 } else if (stream->protection_scheme_type == FOURCC_cbcs) {
3930 const GValue *constant_iv_size_value =
3931 gst_structure_get_value (properties, "constant_iv_size");
3932 const GValue *constant_iv_value =
3933 gst_structure_get_value (properties, "iv");
3934 if (constant_iv_size_value == NULL || constant_iv_value == NULL) {
3935 GST_ERROR_OBJECT (qtdemux, "failed to get constant_iv");
3936 gst_structure_free (properties);
3937 return FALSE;
3938 }
3939 gst_structure_set_value (properties, "iv_size", constant_iv_size_value);
3940 gst_structure_remove_field (properties, "constant_iv_size");
3941 } else if (stream->protection_scheme_type == FOURCC_cenc) {
3942 GST_ERROR_OBJECT (qtdemux, "failed to get IV for sample %u", i);
3943 gst_structure_free (properties);
3944 return FALSE;
3945 }
3946 size = info_sizes[i];
3947 if (size > iv_size) {
3948 if (!gst_byte_reader_get_uint16_be (br, &n_subsamples)
3949 || !(n_subsamples > 0)) {
3950 gst_structure_free (properties);
3951 GST_ERROR_OBJECT (qtdemux,
3952 "failed to get subsample count for sample %u", i);
3953 return FALSE;
3954 }
3955 GST_LOG_OBJECT (qtdemux, "subsample count: %u", n_subsamples);
3956 if (!gst_byte_reader_dup_data (br, n_subsamples * 6, &data)) {
3957 GST_ERROR_OBJECT (qtdemux, "failed to get subsample data for sample %u",
3958 i);
3959 gst_structure_free (properties);
3960 return FALSE;
3961 }
3962 buf = gst_buffer_new_wrapped (data, n_subsamples * 6);
3963 if (!buf) {
3964 gst_structure_free (properties);
3965 return FALSE;
3966 }
3967 gst_structure_set (properties,
3968 "subsample_count", G_TYPE_UINT, n_subsamples,
3969 "subsamples", GST_TYPE_BUFFER, buf, NULL);
3970 gst_buffer_unref (buf);
3971 } else {
3972 gst_structure_set (properties, "subsample_count", G_TYPE_UINT, 0, NULL);
3973 }
3974 g_ptr_array_add (ss_info->crypto_info, properties);
3975 }
3976 return TRUE;
3977 }
3978
3979 /* Converts a UUID in raw byte form to a string representation, as defined in
3980 * RFC 4122. The caller takes ownership of the returned string and is
3981 * responsible for freeing it after use. */
3982 static gchar *
qtdemux_uuid_bytes_to_string(gconstpointer uuid_bytes)3983 qtdemux_uuid_bytes_to_string (gconstpointer uuid_bytes)
3984 {
3985 const guint8 *uuid = (const guint8 *) uuid_bytes;
3986
3987 return g_strdup_printf ("%02x%02x%02x%02x-%02x%02x-%02x%02x-"
3988 "%02x%02x-%02x%02x%02x%02x%02x%02x",
3989 uuid[0], uuid[1], uuid[2], uuid[3],
3990 uuid[4], uuid[5], uuid[6], uuid[7],
3991 uuid[8], uuid[9], uuid[10], uuid[11],
3992 uuid[12], uuid[13], uuid[14], uuid[15]);
3993 }
3994
3995 /* Parses a Protection System Specific Header box (pssh), as defined in the
3996 * Common Encryption (cenc) standard (ISO/IEC 23001-7), which contains
3997 * information needed by a specific content protection system in order to
3998 * decrypt cenc-protected tracks. Returns TRUE if successful; FALSE
3999 * otherwise. */
4000 static gboolean
qtdemux_parse_pssh(GstQTDemux * qtdemux,GNode * node)4001 qtdemux_parse_pssh (GstQTDemux * qtdemux, GNode * node)
4002 {
4003 gchar *sysid_string;
4004 guint32 pssh_size = QT_UINT32 (node->data);
4005 GstBuffer *pssh = NULL;
4006 GstEvent *event = NULL;
4007 guint32 parent_box_type;
4008 gint i;
4009
4010 if (G_UNLIKELY (pssh_size < 32U)) {
4011 GST_ERROR_OBJECT (qtdemux, "invalid box size");
4012 return FALSE;
4013 }
4014
4015 sysid_string =
4016 qtdemux_uuid_bytes_to_string ((const guint8 *) node->data + 12);
4017
4018 gst_qtdemux_append_protection_system_id (qtdemux, sysid_string);
4019
4020 pssh = gst_buffer_new_memdup (node->data, pssh_size);
4021 GST_LOG_OBJECT (qtdemux, "cenc pssh size: %" G_GSIZE_FORMAT,
4022 gst_buffer_get_size (pssh));
4023
4024 parent_box_type = QT_FOURCC ((const guint8 *) node->parent->data + 4);
4025
4026 /* Push an event containing the pssh box onto the queues of all streams. */
4027 event = gst_event_new_protection (sysid_string, pssh,
4028 (parent_box_type == FOURCC_moov) ? "isobmff/moov" : "isobmff/moof");
4029 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
4030 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
4031 GST_TRACE_OBJECT (qtdemux,
4032 "adding protection event for stream %s and system %s",
4033 stream->stream_id, sysid_string);
4034 g_queue_push_tail (&stream->protection_scheme_event_queue,
4035 gst_event_ref (event));
4036 }
4037 g_free (sysid_string);
4038 gst_event_unref (event);
4039 gst_buffer_unref (pssh);
4040 return TRUE;
4041 }
4042
4043 static gboolean
qtdemux_parse_moof(GstQTDemux * qtdemux,const guint8 * buffer,guint length,guint64 moof_offset,QtDemuxStream * stream)4044 qtdemux_parse_moof (GstQTDemux * qtdemux, const guint8 * buffer, guint length,
4045 guint64 moof_offset, QtDemuxStream * stream)
4046 {
4047 GNode *moof_node, *traf_node, *tfhd_node, *trun_node, *tfdt_node, *mfhd_node;
4048 GNode *uuid_node;
4049 GstByteReader mfhd_data, trun_data, tfhd_data, tfdt_data;
4050 GNode *saiz_node, *saio_node, *pssh_node;
4051 GstByteReader saiz_data, saio_data;
4052 guint32 ds_size = 0, ds_duration = 0, ds_flags = 0;
4053 gint64 base_offset, running_offset;
4054 guint32 frag_num;
4055 GstClockTime min_dts = GST_CLOCK_TIME_NONE;
4056
4057 /* NOTE @stream ignored */
4058
4059 moof_node = g_node_new ((guint8 *) buffer);
4060 qtdemux_parse_node (qtdemux, moof_node, buffer, length);
4061 qtdemux_node_dump (qtdemux, moof_node);
4062
4063 /* Get fragment number from mfhd and check it's valid */
4064 mfhd_node =
4065 qtdemux_tree_get_child_by_type_full (moof_node, FOURCC_mfhd, &mfhd_data);
4066 if (mfhd_node == NULL)
4067 goto missing_mfhd;
4068 if (!qtdemux_parse_mfhd (qtdemux, &mfhd_data, &frag_num))
4069 goto fail;
4070 GST_DEBUG_OBJECT (qtdemux, "Fragment #%d", frag_num);
4071
4072 /* unknown base_offset to start with */
4073 base_offset = running_offset = -1;
4074 traf_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_traf);
4075 while (traf_node) {
4076 guint64 decode_time = 0;
4077
4078 /* Fragment Header node */
4079 tfhd_node =
4080 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfhd,
4081 &tfhd_data);
4082 if (!tfhd_node)
4083 goto missing_tfhd;
4084 if (!qtdemux_parse_tfhd (qtdemux, &tfhd_data, &stream, &ds_duration,
4085 &ds_size, &ds_flags, &base_offset))
4086 goto missing_tfhd;
4087
4088 /* The following code assumes at most a single set of sample auxiliary
4089 * data in the fragment (consisting of a saiz box and a corresponding saio
4090 * box); in theory, however, there could be multiple sets of sample
4091 * auxiliary data in a fragment. */
4092 saiz_node =
4093 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saiz,
4094 &saiz_data);
4095 if (saiz_node) {
4096 guint32 info_type = 0;
4097 guint64 offset = 0;
4098 guint32 info_type_parameter = 0;
4099
4100 g_free (qtdemux->cenc_aux_info_sizes);
4101
4102 qtdemux->cenc_aux_info_sizes =
4103 qtdemux_parse_saiz (qtdemux, stream, &saiz_data,
4104 &qtdemux->cenc_aux_sample_count);
4105 if (qtdemux->cenc_aux_info_sizes == NULL) {
4106 GST_ERROR_OBJECT (qtdemux, "failed to parse saiz box");
4107 goto fail;
4108 }
4109 saio_node =
4110 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saio,
4111 &saio_data);
4112 if (!saio_node) {
4113 GST_ERROR_OBJECT (qtdemux, "saiz box without a corresponding saio box");
4114 g_free (qtdemux->cenc_aux_info_sizes);
4115 qtdemux->cenc_aux_info_sizes = NULL;
4116 goto fail;
4117 }
4118
4119 if (G_UNLIKELY (!qtdemux_parse_saio (qtdemux, stream, &saio_data,
4120 &info_type, &info_type_parameter, &offset))) {
4121 GST_ERROR_OBJECT (qtdemux, "failed to parse saio box");
4122 g_free (qtdemux->cenc_aux_info_sizes);
4123 qtdemux->cenc_aux_info_sizes = NULL;
4124 goto fail;
4125 }
4126 if (base_offset > -1 && base_offset > qtdemux->moof_offset)
4127 offset += (guint64) (base_offset - qtdemux->moof_offset);
4128 if ((info_type == FOURCC_cenc || info_type == FOURCC_cbcs)
4129 && info_type_parameter == 0U) {
4130 GstByteReader br;
4131 if (offset > length) {
4132 GST_DEBUG_OBJECT (qtdemux, "cenc auxiliary info stored out of moof");
4133 qtdemux->cenc_aux_info_offset = offset;
4134 } else {
4135 gst_byte_reader_init (&br, buffer + offset, length - offset);
4136 if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
4137 qtdemux->cenc_aux_info_sizes,
4138 qtdemux->cenc_aux_sample_count)) {
4139 GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
4140 g_free (qtdemux->cenc_aux_info_sizes);
4141 qtdemux->cenc_aux_info_sizes = NULL;
4142 goto fail;
4143 }
4144 }
4145 }
4146 }
4147
4148 tfdt_node =
4149 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfdt,
4150 &tfdt_data);
4151 if (tfdt_node) {
4152 /* We'll use decode_time to interpolate timestamps
4153 * in case the input timestamps are missing */
4154 qtdemux_parse_tfdt (qtdemux, &tfdt_data, &decode_time);
4155
4156 GST_DEBUG_OBJECT (qtdemux, "decode time %" G_GINT64_FORMAT
4157 " (%" GST_TIME_FORMAT ")", decode_time,
4158 GST_TIME_ARGS (stream ? QTSTREAMTIME_TO_GSTTIME (stream,
4159 decode_time) : GST_CLOCK_TIME_NONE));
4160
4161 /* Discard the fragment buffer timestamp info to avoid using it.
4162 * Rely on tfdt instead as it is more accurate than the timestamp
4163 * that is fetched from a manifest/playlist and is usually
4164 * less accurate. */
4165 qtdemux->fragment_start = -1;
4166 }
4167
4168 if (G_UNLIKELY (!stream)) {
4169 /* we lost track of offset, we'll need to regain it,
4170 * but can delay complaining until later or avoid doing so altogether */
4171 base_offset = -2;
4172 goto next;
4173 }
4174 if (G_UNLIKELY (base_offset < -1))
4175 goto lost_offset;
4176
4177 min_dts = MIN (min_dts, QTSTREAMTIME_TO_GSTTIME (stream, decode_time));
4178
4179 if (!qtdemux->pullbased) {
4180 /* Sample tables can grow enough to be problematic if the system memory
4181 * is very low (e.g. embedded devices) and the videos very long
4182 * (~8 MiB/hour for 25-30 fps video + typical AAC audio frames).
4183 * Fortunately, we can easily discard them for each new fragment when
4184 * we know qtdemux will not receive seeks outside of the current fragment.
4185 * adaptivedemux honors this assumption.
4186 * This optimization is also useful for applications that use qtdemux as
4187 * a push-based simple demuxer, like Media Source Extensions. */
4188 gst_qtdemux_stream_flush_samples_data (stream);
4189 }
4190
4191 /* initialise moof sample data */
4192 stream->n_samples_moof = 0;
4193 stream->duration_last_moof = stream->duration_moof;
4194 stream->duration_moof = 0;
4195
4196 /* Track Run node */
4197 trun_node =
4198 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_trun,
4199 &trun_data);
4200 while (trun_node) {
4201 qtdemux_parse_trun (qtdemux, &trun_data, stream,
4202 ds_duration, ds_size, ds_flags, moof_offset, length, &base_offset,
4203 &running_offset, decode_time, (tfdt_node != NULL));
4204 /* iterate all siblings */
4205 trun_node = qtdemux_tree_get_sibling_by_type_full (trun_node, FOURCC_trun,
4206 &trun_data);
4207 /* don't use tfdt for subsequent trun as it only refers to the first */
4208 tfdt_node = NULL;
4209 }
4210
4211 uuid_node = qtdemux_tree_get_child_by_type (traf_node, FOURCC_uuid);
4212 if (uuid_node) {
4213 guint8 *uuid_buffer = (guint8 *) uuid_node->data;
4214 guint32 box_length = QT_UINT32 (uuid_buffer);
4215
4216 qtdemux_parse_uuid (qtdemux, uuid_buffer, box_length);
4217 }
4218
4219 /* if no new base_offset provided for next traf,
4220 * base is end of current traf */
4221 base_offset = running_offset;
4222 running_offset = -1;
4223
4224 if (stream->n_samples_moof && stream->duration_moof)
4225 stream->new_caps = TRUE;
4226
4227 next:
4228 /* iterate all siblings */
4229 traf_node = qtdemux_tree_get_sibling_by_type (traf_node, FOURCC_traf);
4230 }
4231
4232 /* parse any protection system info */
4233 pssh_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_pssh);
4234 while (pssh_node) {
4235 GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
4236 qtdemux_parse_pssh (qtdemux, pssh_node);
4237 pssh_node = qtdemux_tree_get_sibling_by_type (pssh_node, FOURCC_pssh);
4238 }
4239
4240 if (!qtdemux->upstream_format_is_time && !qtdemux->first_moof_already_parsed
4241 && !qtdemux->received_seek && GST_CLOCK_TIME_IS_VALID (min_dts)
4242 && min_dts != 0) {
4243 /* Unless the user has explicitly requested another seek, perform an
4244 * internal seek to the time specified in the tfdt.
4245 *
4246 * This way if the user opens a file where the first tfdt is 1 hour
4247 * into the presentation, they will not have to wait 1 hour for run
4248 * time to catch up and actual playback to start. */
4249 gint i;
4250
4251 GST_DEBUG_OBJECT (qtdemux, "First fragment has a non-zero tfdt, "
4252 "performing an internal seek to %" GST_TIME_FORMAT,
4253 GST_TIME_ARGS (min_dts));
4254
4255 qtdemux->segment.start = min_dts;
4256 qtdemux->segment.time = qtdemux->segment.position = min_dts;
4257
4258 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
4259 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
4260 stream->time_position = min_dts;
4261 }
4262
4263 /* Before this code was run a segment was already sent when the moov was
4264 * parsed... which is OK -- some apps (mostly tests) expect a segment to
4265 * be emitted after a moov, and we can emit a second segment anyway for
4266 * special cases like this. */
4267 qtdemux->need_segment = TRUE;
4268 }
4269
4270 qtdemux->first_moof_already_parsed = TRUE;
4271
4272 g_node_destroy (moof_node);
4273 return TRUE;
4274
4275 missing_tfhd:
4276 {
4277 GST_DEBUG_OBJECT (qtdemux, "missing tfhd box");
4278 goto fail;
4279 }
4280 missing_mfhd:
4281 {
4282 GST_DEBUG_OBJECT (qtdemux, "Missing mfhd box");
4283 goto fail;
4284 }
4285 lost_offset:
4286 {
4287 GST_DEBUG_OBJECT (qtdemux, "lost offset");
4288 goto fail;
4289 }
4290 fail:
4291 {
4292 g_node_destroy (moof_node);
4293 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4294 (_("This file is corrupt and cannot be played.")), (NULL));
4295 return FALSE;
4296 }
4297 }
4298
4299 #if 0
4300 /* might be used if some day we actually use mfra & co
4301 * for random access to fragments,
4302 * but that will require quite some modifications and much less relying
4303 * on a sample array */
4304 #endif
4305
4306 static gboolean
qtdemux_parse_tfra(GstQTDemux * qtdemux,GNode * tfra_node)4307 qtdemux_parse_tfra (GstQTDemux * qtdemux, GNode * tfra_node)
4308 {
4309 QtDemuxStream *stream;
4310 guint32 ver_flags, track_id, len, num_entries, i;
4311 guint value_size, traf_size, trun_size, sample_size;
4312 guint64 time = 0, moof_offset = 0;
4313 #if 0
4314 GstBuffer *buf = NULL;
4315 GstFlowReturn ret;
4316 #endif
4317 GstByteReader tfra;
4318
4319 gst_byte_reader_init (&tfra, tfra_node->data, QT_UINT32 (tfra_node->data));
4320
4321 if (!gst_byte_reader_skip (&tfra, 8))
4322 return FALSE;
4323
4324 if (!gst_byte_reader_get_uint32_be (&tfra, &ver_flags))
4325 return FALSE;
4326
4327 if (!gst_byte_reader_get_uint32_be (&tfra, &track_id)
4328 || !gst_byte_reader_get_uint32_be (&tfra, &len)
4329 || !gst_byte_reader_get_uint32_be (&tfra, &num_entries))
4330 return FALSE;
4331
4332 GST_DEBUG_OBJECT (qtdemux, "parsing tfra box for track id %u", track_id);
4333
4334 stream = qtdemux_find_stream (qtdemux, track_id);
4335 if (stream == NULL)
4336 goto unknown_trackid;
4337
4338 value_size = ((ver_flags >> 24) == 1) ? sizeof (guint64) : sizeof (guint32);
4339 sample_size = (len & 3) + 1;
4340 trun_size = ((len & 12) >> 2) + 1;
4341 traf_size = ((len & 48) >> 4) + 1;
4342
4343 GST_DEBUG_OBJECT (qtdemux, "%u entries, sizes: value %u, traf %u, trun %u, "
4344 "sample %u", num_entries, value_size, traf_size, trun_size, sample_size);
4345
4346 if (num_entries == 0)
4347 goto no_samples;
4348
4349 if (!qt_atom_parser_has_chunks (&tfra, num_entries,
4350 value_size + value_size + traf_size + trun_size + sample_size))
4351 goto corrupt_file;
4352
4353 g_free (stream->ra_entries);
4354 stream->ra_entries = g_new (QtDemuxRandomAccessEntry, num_entries);
4355 stream->n_ra_entries = num_entries;
4356
4357 for (i = 0; i < num_entries; i++) {
4358 qt_atom_parser_get_offset (&tfra, value_size, &time);
4359 qt_atom_parser_get_offset (&tfra, value_size, &moof_offset);
4360 qt_atom_parser_get_uint_with_size_unchecked (&tfra, traf_size);
4361 qt_atom_parser_get_uint_with_size_unchecked (&tfra, trun_size);
4362 qt_atom_parser_get_uint_with_size_unchecked (&tfra, sample_size);
4363
4364 time = QTSTREAMTIME_TO_GSTTIME (stream, time);
4365
4366 GST_LOG_OBJECT (qtdemux, "fragment time: %" GST_TIME_FORMAT ", "
4367 " moof_offset: %" G_GUINT64_FORMAT, GST_TIME_ARGS (time), moof_offset);
4368
4369 stream->ra_entries[i].ts = time;
4370 stream->ra_entries[i].moof_offset = moof_offset;
4371
4372 /* don't want to go through the entire file and read all moofs at startup */
4373 #if 0
4374 ret = gst_qtdemux_pull_atom (qtdemux, moof_offset, 0, &buf);
4375 if (ret != GST_FLOW_OK)
4376 goto corrupt_file;
4377 qtdemux_parse_moof (qtdemux, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf),
4378 moof_offset, stream);
4379 gst_buffer_unref (buf);
4380 #endif
4381 }
4382
4383 check_update_duration (qtdemux, time);
4384
4385 return TRUE;
4386
4387 /* ERRORS */
4388 unknown_trackid:
4389 {
4390 GST_WARNING_OBJECT (qtdemux, "Couldn't find stream for track %u", track_id);
4391 return FALSE;
4392 }
4393 corrupt_file:
4394 {
4395 GST_WARNING_OBJECT (qtdemux, "broken traf box, ignoring");
4396 return FALSE;
4397 }
4398 no_samples:
4399 {
4400 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
4401 return FALSE;
4402 }
4403 }
4404
4405 static gboolean
qtdemux_pull_mfro_mfra(GstQTDemux * qtdemux)4406 qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux)
4407 {
4408 GstMapInfo mfro_map = GST_MAP_INFO_INIT;
4409 GstMapInfo mfra_map = GST_MAP_INFO_INIT;
4410 GstBuffer *mfro = NULL, *mfra = NULL;
4411 GstFlowReturn flow;
4412 gboolean ret = FALSE;
4413 GNode *mfra_node, *tfra_node;
4414 guint64 mfra_offset = 0;
4415 guint32 fourcc, mfra_size;
4416 gint64 len;
4417
4418 /* query upstream size in bytes */
4419 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &len))
4420 goto size_query_failed;
4421
4422 /* mfro box should be at the very end of the file */
4423 flow = gst_qtdemux_pull_atom (qtdemux, len - 16, 16, &mfro);
4424 if (flow != GST_FLOW_OK)
4425 goto exit;
4426
4427 gst_buffer_map (mfro, &mfro_map, GST_MAP_READ);
4428
4429 fourcc = QT_FOURCC (mfro_map.data + 4);
4430 if (fourcc != FOURCC_mfro)
4431 goto exit;
4432
4433 GST_INFO_OBJECT (qtdemux, "Found mfro box");
4434 if (mfro_map.size < 16)
4435 goto invalid_mfro_size;
4436
4437 mfra_size = QT_UINT32 (mfro_map.data + 12);
4438 if (mfra_size >= len)
4439 goto invalid_mfra_size;
4440
4441 mfra_offset = len - mfra_size;
4442
4443 GST_INFO_OBJECT (qtdemux, "mfra offset: %" G_GUINT64_FORMAT ", size %u",
4444 mfra_offset, mfra_size);
4445
4446 /* now get and parse mfra box */
4447 flow = gst_qtdemux_pull_atom (qtdemux, mfra_offset, mfra_size, &mfra);
4448 if (flow != GST_FLOW_OK)
4449 goto broken_file;
4450
4451 gst_buffer_map (mfra, &mfra_map, GST_MAP_READ);
4452
4453 mfra_node = g_node_new ((guint8 *) mfra_map.data);
4454 qtdemux_parse_node (qtdemux, mfra_node, mfra_map.data, mfra_map.size);
4455
4456 tfra_node = qtdemux_tree_get_child_by_type (mfra_node, FOURCC_tfra);
4457
4458 while (tfra_node) {
4459 qtdemux_parse_tfra (qtdemux, tfra_node);
4460 /* iterate all siblings */
4461 tfra_node = qtdemux_tree_get_sibling_by_type (tfra_node, FOURCC_tfra);
4462 }
4463 g_node_destroy (mfra_node);
4464
4465 GST_INFO_OBJECT (qtdemux, "parsed movie fragment random access box (mfra)");
4466 ret = TRUE;
4467
4468 exit:
4469
4470 if (mfro) {
4471 if (mfro_map.memory != NULL)
4472 gst_buffer_unmap (mfro, &mfro_map);
4473 gst_buffer_unref (mfro);
4474 }
4475 if (mfra) {
4476 if (mfra_map.memory != NULL)
4477 gst_buffer_unmap (mfra, &mfra_map);
4478 gst_buffer_unref (mfra);
4479 }
4480 return ret;
4481
4482 /* ERRORS */
4483 size_query_failed:
4484 {
4485 GST_WARNING_OBJECT (qtdemux, "could not query upstream size");
4486 goto exit;
4487 }
4488 invalid_mfro_size:
4489 {
4490 GST_WARNING_OBJECT (qtdemux, "mfro size is too small");
4491 goto exit;
4492 }
4493 invalid_mfra_size:
4494 {
4495 GST_WARNING_OBJECT (qtdemux, "mfra_size in mfro box is invalid");
4496 goto exit;
4497 }
4498 broken_file:
4499 {
4500 GST_WARNING_OBJECT (qtdemux, "bogus mfra offset or size, broken file");
4501 goto exit;
4502 }
4503 }
4504
4505 static guint64
add_offset(guint64 offset,guint64 advance)4506 add_offset (guint64 offset, guint64 advance)
4507 {
4508 /* Avoid 64-bit overflow by clamping */
4509 if (offset > G_MAXUINT64 - advance)
4510 return G_MAXUINT64;
4511 return offset + advance;
4512 }
4513
4514 static GstFlowReturn
gst_qtdemux_loop_state_header(GstQTDemux * qtdemux)4515 gst_qtdemux_loop_state_header (GstQTDemux * qtdemux)
4516 {
4517 guint64 length = 0;
4518 guint32 fourcc = 0;
4519 GstBuffer *buf = NULL;
4520 GstFlowReturn ret = GST_FLOW_OK;
4521 guint64 cur_offset = qtdemux->offset;
4522 GstMapInfo map;
4523
4524 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, 16, &buf);
4525 if (G_UNLIKELY (ret != GST_FLOW_OK))
4526 goto beach;
4527 gst_buffer_map (buf, &map, GST_MAP_READ);
4528 if (G_LIKELY (map.size >= 8))
4529 extract_initial_length_and_fourcc (map.data, map.size, &length, &fourcc);
4530 gst_buffer_unmap (buf, &map);
4531 gst_buffer_unref (buf);
4532
4533 /* maybe we already got most we needed, so only consider this eof */
4534 if (G_UNLIKELY (length == 0)) {
4535 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
4536 (_("Invalid atom size.")),
4537 ("Header atom '%" GST_FOURCC_FORMAT "' has empty length",
4538 GST_FOURCC_ARGS (fourcc)));
4539 ret = GST_FLOW_EOS;
4540 goto beach;
4541 }
4542
4543 switch (fourcc) {
4544 case FOURCC_moof:
4545 /* record for later parsing when needed */
4546 if (!qtdemux->moof_offset) {
4547 qtdemux->moof_offset = qtdemux->offset;
4548 }
4549 if (qtdemux_pull_mfro_mfra (qtdemux)) {
4550 /* FIXME */
4551 } else {
4552 qtdemux->offset += length; /* skip moof and keep going */
4553 }
4554 if (qtdemux->got_moov) {
4555 GST_INFO_OBJECT (qtdemux, "moof header, got moov, done with headers");
4556 ret = GST_FLOW_EOS;
4557 goto beach;
4558 }
4559 break;
4560 case FOURCC_mdat:
4561 case FOURCC_free:
4562 case FOURCC_skip:
4563 case FOURCC_wide:
4564 case FOURCC_PICT:
4565 case FOURCC_pnot:
4566 {
4567 GST_LOG_OBJECT (qtdemux,
4568 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
4569 GST_FOURCC_ARGS (fourcc), cur_offset);
4570 qtdemux->offset = add_offset (qtdemux->offset, length);
4571 break;
4572 }
4573 case FOURCC_moov:
4574 {
4575 GstBuffer *moov = NULL;
4576
4577 if (qtdemux->got_moov) {
4578 GST_DEBUG_OBJECT (qtdemux, "Skipping moov atom as we have one already");
4579 qtdemux->offset = add_offset (qtdemux->offset, length);
4580 goto beach;
4581 }
4582
4583 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, length, &moov);
4584 if (ret != GST_FLOW_OK)
4585 goto beach;
4586 gst_buffer_map (moov, &map, GST_MAP_READ);
4587
4588 if (length != map.size) {
4589 /* Some files have a 'moov' atom at the end of the file which contains
4590 * a terminal 'free' atom where the body of the atom is missing.
4591 * Check for, and permit, this special case.
4592 */
4593 if (map.size >= 8) {
4594 guint8 *final_data = map.data + (map.size - 8);
4595 guint32 final_length = QT_UINT32 (final_data);
4596 guint32 final_fourcc = QT_FOURCC (final_data + 4);
4597
4598 if (final_fourcc == FOURCC_free
4599 && map.size + final_length - 8 == length) {
4600 /* Ok, we've found that special case. Allocate a new buffer with
4601 * that free atom actually present. */
4602 GstBuffer *newmoov = gst_buffer_new_and_alloc (length);
4603 gst_buffer_fill (newmoov, 0, map.data, map.size);
4604 gst_buffer_memset (newmoov, map.size, 0, final_length - 8);
4605 gst_buffer_unmap (moov, &map);
4606 gst_buffer_unref (moov);
4607 moov = newmoov;
4608 gst_buffer_map (moov, &map, GST_MAP_READ);
4609 }
4610 }
4611 }
4612
4613 if (length != map.size) {
4614 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4615 (_("This file is incomplete and cannot be played.")),
4616 ("We got less than expected (received %" G_GSIZE_FORMAT
4617 ", wanted %u, offset %" G_GUINT64_FORMAT ")", map.size,
4618 (guint) length, cur_offset));
4619 gst_buffer_unmap (moov, &map);
4620 gst_buffer_unref (moov);
4621 ret = GST_FLOW_ERROR;
4622 goto beach;
4623 }
4624 qtdemux->offset += length;
4625
4626 qtdemux_parse_moov (qtdemux, map.data, length);
4627 qtdemux_node_dump (qtdemux, qtdemux->moov_node);
4628
4629 qtdemux_parse_tree (qtdemux);
4630 if (qtdemux->moov_node_compressed) {
4631 g_node_destroy (qtdemux->moov_node_compressed);
4632 g_free (qtdemux->moov_node->data);
4633 }
4634 qtdemux->moov_node_compressed = NULL;
4635 g_node_destroy (qtdemux->moov_node);
4636 qtdemux->moov_node = NULL;
4637 gst_buffer_unmap (moov, &map);
4638 gst_buffer_unref (moov);
4639 qtdemux->got_moov = TRUE;
4640
4641 break;
4642 }
4643 case FOURCC_ftyp:
4644 {
4645 GstBuffer *ftyp = NULL;
4646
4647 /* extract major brand; might come in handy for ISO vs QT issues */
4648 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &ftyp);
4649 if (ret != GST_FLOW_OK)
4650 goto beach;
4651 qtdemux->offset += length;
4652 gst_buffer_map (ftyp, &map, GST_MAP_READ);
4653 qtdemux_parse_ftyp (qtdemux, map.data, map.size);
4654 gst_buffer_unmap (ftyp, &map);
4655 gst_buffer_unref (ftyp);
4656 break;
4657 }
4658 case FOURCC_uuid:
4659 {
4660 GstBuffer *uuid = NULL;
4661
4662 /* uuid are extension atoms */
4663 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &uuid);
4664 if (ret != GST_FLOW_OK)
4665 goto beach;
4666 qtdemux->offset += length;
4667 gst_buffer_map (uuid, &map, GST_MAP_READ);
4668 qtdemux_parse_uuid (qtdemux, map.data, map.size);
4669 gst_buffer_unmap (uuid, &map);
4670 gst_buffer_unref (uuid);
4671 break;
4672 }
4673 case FOURCC_sidx:
4674 {
4675 GstBuffer *sidx = NULL;
4676 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &sidx);
4677 if (ret != GST_FLOW_OK)
4678 goto beach;
4679 qtdemux->offset += length;
4680 gst_buffer_map (sidx, &map, GST_MAP_READ);
4681 qtdemux_parse_sidx (qtdemux, map.data, map.size);
4682 gst_buffer_unmap (sidx, &map);
4683 gst_buffer_unref (sidx);
4684 break;
4685 }
4686 default:
4687 {
4688 GstBuffer *unknown = NULL;
4689
4690 GST_LOG_OBJECT (qtdemux,
4691 "unknown %08x '%" GST_FOURCC_FORMAT "' of size %" G_GUINT64_FORMAT
4692 " at %" G_GUINT64_FORMAT, fourcc, GST_FOURCC_ARGS (fourcc), length,
4693 cur_offset);
4694 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &unknown);
4695 if (ret != GST_FLOW_OK)
4696 goto beach;
4697 gst_buffer_map (unknown, &map, GST_MAP_READ);
4698 GST_MEMDUMP ("Unknown tag", map.data, map.size);
4699 gst_buffer_unmap (unknown, &map);
4700 gst_buffer_unref (unknown);
4701 qtdemux->offset += length;
4702 break;
4703 }
4704 }
4705
4706 beach:
4707 if (ret == GST_FLOW_EOS && (qtdemux->got_moov || qtdemux->media_caps)) {
4708 /* digested all data, show what we have */
4709 qtdemux_prepare_streams (qtdemux);
4710 QTDEMUX_EXPOSE_LOCK (qtdemux);
4711 ret = qtdemux_expose_streams (qtdemux);
4712 QTDEMUX_EXPOSE_UNLOCK (qtdemux);
4713
4714 qtdemux->state = QTDEMUX_STATE_MOVIE;
4715 GST_DEBUG_OBJECT (qtdemux, "switching state to STATE_MOVIE (%d)",
4716 qtdemux->state);
4717 return ret;
4718 }
4719 return ret;
4720 }
4721
4722 /* Seeks to the previous keyframe of the indexed stream and
4723 * aligns other streams with respect to the keyframe timestamp
4724 * of indexed stream. Only called in case of Reverse Playback
4725 */
4726 static GstFlowReturn
gst_qtdemux_seek_to_previous_keyframe(GstQTDemux * qtdemux)4727 gst_qtdemux_seek_to_previous_keyframe (GstQTDemux * qtdemux)
4728 {
4729 guint32 seg_idx = 0, k_index = 0;
4730 guint32 ref_seg_idx, ref_k_index;
4731 GstClockTime k_pos = 0, last_stop = 0;
4732 QtDemuxSegment *seg = NULL;
4733 QtDemuxStream *ref_str = NULL;
4734 guint64 seg_media_start_mov; /* segment media start time in mov format */
4735 guint64 target_ts;
4736 gint i;
4737
4738 /* Now we choose an arbitrary stream, get the previous keyframe timestamp
4739 * and finally align all the other streams on that timestamp with their
4740 * respective keyframes */
4741 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
4742 QtDemuxStream *str = QTDEMUX_NTH_STREAM (qtdemux, i);
4743
4744 /* No candidate yet, take the first stream */
4745 if (!ref_str) {
4746 ref_str = str;
4747 continue;
4748 }
4749
4750 /* So that stream has a segment, we prefer video streams */
4751 if (str->subtype == FOURCC_vide) {
4752 ref_str = str;
4753 break;
4754 }
4755 }
4756
4757 if (G_UNLIKELY (!ref_str)) {
4758 GST_DEBUG_OBJECT (qtdemux, "couldn't find any stream");
4759 goto eos;
4760 }
4761
4762 if (G_UNLIKELY (!ref_str->from_sample)) {
4763 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of the file");
4764 goto eos;
4765 }
4766
4767 /* So that stream has been playing from from_sample to to_sample. We will
4768 * get the timestamp of the previous sample and search for a keyframe before
4769 * that. For audio streams we do an arbitrary jump in the past (10 samples) */
4770 if (ref_str->subtype == FOURCC_vide) {
4771 k_index = gst_qtdemux_find_keyframe (qtdemux, ref_str,
4772 ref_str->from_sample - 1, FALSE);
4773 } else {
4774 if (ref_str->from_sample >= 10)
4775 k_index = ref_str->from_sample - 10;
4776 else
4777 k_index = 0;
4778 }
4779
4780 target_ts =
4781 ref_str->samples[k_index].timestamp +
4782 ref_str->samples[k_index].pts_offset;
4783
4784 /* get current segment for that stream */
4785 seg = &ref_str->segments[ref_str->segment_index];
4786 /* Use segment start in original timescale for comparisons */
4787 seg_media_start_mov = seg->trak_media_start;
4788
4789 GST_LOG_OBJECT (qtdemux, "keyframe index %u ts %" G_GUINT64_FORMAT
4790 " seg start %" G_GUINT64_FORMAT " %" GST_TIME_FORMAT,
4791 k_index, target_ts, seg_media_start_mov,
4792 GST_TIME_ARGS (seg->media_start));
4793
4794 /* Crawl back through segments to find the one containing this I frame */
4795 while (target_ts < seg_media_start_mov) {
4796 GST_DEBUG_OBJECT (qtdemux,
4797 "keyframe position (sample %u) is out of segment %u " " target %"
4798 G_GUINT64_FORMAT " seg start %" G_GUINT64_FORMAT, k_index,
4799 ref_str->segment_index, target_ts, seg_media_start_mov);
4800
4801 if (G_UNLIKELY (!ref_str->segment_index)) {
4802 /* Reached first segment, let's consider it's EOS */
4803 goto eos;
4804 }
4805 ref_str->segment_index--;
4806 seg = &ref_str->segments[ref_str->segment_index];
4807 /* Use segment start in original timescale for comparisons */
4808 seg_media_start_mov = seg->trak_media_start;
4809 }
4810 /* Calculate time position of the keyframe and where we should stop */
4811 k_pos =
4812 QTSTREAMTIME_TO_GSTTIME (ref_str,
4813 target_ts - seg->trak_media_start) + seg->time;
4814 last_stop =
4815 QTSTREAMTIME_TO_GSTTIME (ref_str,
4816 ref_str->samples[ref_str->from_sample].timestamp -
4817 seg->trak_media_start) + seg->time;
4818
4819 GST_DEBUG_OBJECT (qtdemux, "preferred stream played from sample %u, "
4820 "now going to sample %u (pts %" GST_TIME_FORMAT ")", ref_str->from_sample,
4821 k_index, GST_TIME_ARGS (k_pos));
4822
4823 /* Set last_stop with the keyframe timestamp we pushed of that stream */
4824 qtdemux->segment.position = last_stop;
4825 GST_DEBUG_OBJECT (qtdemux, "last_stop now is %" GST_TIME_FORMAT,
4826 GST_TIME_ARGS (last_stop));
4827
4828 if (G_UNLIKELY (last_stop < qtdemux->segment.start)) {
4829 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of segment");
4830 goto eos;
4831 }
4832
4833 ref_seg_idx = ref_str->segment_index;
4834 ref_k_index = k_index;
4835
4836 /* Align them all on this */
4837 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
4838 guint32 index = 0;
4839 GstClockTime seg_time = 0;
4840 QtDemuxStream *str = QTDEMUX_NTH_STREAM (qtdemux, i);
4841
4842 /* aligning reference stream again might lead to backing up to yet another
4843 * keyframe (due to timestamp rounding issues),
4844 * potentially putting more load on downstream; so let's try to avoid */
4845 if (str == ref_str) {
4846 seg_idx = ref_seg_idx;
4847 seg = &str->segments[seg_idx];
4848 k_index = ref_k_index;
4849 GST_DEBUG_OBJECT (qtdemux, "reference track-id %u segment %d, "
4850 "sample at index %d", str->track_id, ref_str->segment_index, k_index);
4851 } else {
4852 seg_idx = gst_qtdemux_find_segment (qtdemux, str, k_pos);
4853 GST_DEBUG_OBJECT (qtdemux,
4854 "track-id %u align segment %d for keyframe pos %" GST_TIME_FORMAT,
4855 str->track_id, seg_idx, GST_TIME_ARGS (k_pos));
4856
4857 /* get segment and time in the segment */
4858 seg = &str->segments[seg_idx];
4859 seg_time = k_pos - seg->time;
4860
4861 /* get the media time in the segment.
4862 * No adjustment for empty "filler" segments */
4863 if (seg->media_start != GST_CLOCK_TIME_NONE)
4864 seg_time += seg->media_start;
4865
4866 /* get the index of the sample with media time */
4867 index = gst_qtdemux_find_index_linear (qtdemux, str, seg_time);
4868 GST_DEBUG_OBJECT (qtdemux,
4869 "track-id %u sample for %" GST_TIME_FORMAT " at %u", str->track_id,
4870 GST_TIME_ARGS (seg_time), index);
4871
4872 /* find previous keyframe */
4873 k_index = gst_qtdemux_find_keyframe (qtdemux, str, index, FALSE);
4874 }
4875
4876 /* Remember until where we want to go */
4877 str->to_sample = str->from_sample - 1;
4878 /* Define our time position */
4879 target_ts =
4880 str->samples[k_index].timestamp + str->samples[k_index].pts_offset;
4881 str->time_position = QTSTREAMTIME_TO_GSTTIME (str, target_ts) + seg->time;
4882 if (seg->media_start != GST_CLOCK_TIME_NONE)
4883 str->time_position -= seg->media_start;
4884
4885 /* Now seek back in time */
4886 gst_qtdemux_move_stream (qtdemux, str, k_index);
4887 GST_DEBUG_OBJECT (qtdemux, "track-id %u keyframe at %u, time position %"
4888 GST_TIME_FORMAT " playing from sample %u to %u", str->track_id, k_index,
4889 GST_TIME_ARGS (str->time_position), str->from_sample, str->to_sample);
4890 }
4891
4892 return GST_FLOW_OK;
4893
4894 eos:
4895 return GST_FLOW_EOS;
4896 }
4897
4898 /*
4899 * Gets the current qt segment start, stop and position for the
4900 * given time offset. This is used in update_segment()
4901 */
4902 static void
gst_qtdemux_stream_segment_get_boundaries(GstQTDemux * qtdemux,QtDemuxStream * stream,GstClockTime offset,GstClockTime * _start,GstClockTime * _stop,GstClockTime * _time)4903 gst_qtdemux_stream_segment_get_boundaries (GstQTDemux * qtdemux,
4904 QtDemuxStream * stream, GstClockTime offset,
4905 GstClockTime * _start, GstClockTime * _stop, GstClockTime * _time)
4906 {
4907 GstClockTime seg_time;
4908 GstClockTime start, stop, time;
4909 QtDemuxSegment *segment;
4910
4911 segment = &stream->segments[stream->segment_index];
4912
4913 /* get time in this segment */
4914 seg_time = (offset - segment->time) * segment->rate;
4915
4916 GST_LOG_OBJECT (stream->pad, "seg_time %" GST_TIME_FORMAT,
4917 GST_TIME_ARGS (seg_time));
4918
4919 if (G_UNLIKELY (seg_time > segment->duration)) {
4920 GST_LOG_OBJECT (stream->pad,
4921 "seg_time > segment->duration %" GST_TIME_FORMAT,
4922 GST_TIME_ARGS (segment->duration));
4923 seg_time = segment->duration;
4924 }
4925
4926 /* qtdemux->segment.stop is in outside-time-realm, whereas
4927 * segment->media_stop is in track-time-realm.
4928 *
4929 * In order to compare the two, we need to bring segment.stop
4930 * into the track-time-realm
4931 *
4932 * FIXME - does this comment still hold? Don't see any conversion here */
4933
4934 stop = qtdemux->segment.stop;
4935 if (stop == GST_CLOCK_TIME_NONE)
4936 stop = qtdemux->segment.duration;
4937 if (stop == GST_CLOCK_TIME_NONE)
4938 stop = segment->media_stop;
4939 else
4940 stop =
4941 MIN (segment->media_stop, stop - segment->time + segment->media_start);
4942
4943 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
4944 start = segment->time + seg_time;
4945 time = offset;
4946 stop = start - seg_time + segment->duration;
4947 } else if (qtdemux->segment.rate >= 0) {
4948 start = MIN (segment->media_start + seg_time, stop);
4949 time = offset;
4950 } else {
4951 if (segment->media_start >= qtdemux->segment.start) {
4952 time = segment->time;
4953 } else {
4954 time = segment->time + (qtdemux->segment.start - segment->media_start);
4955 }
4956
4957 start = MAX (segment->media_start, qtdemux->segment.start);
4958 stop = MIN (segment->media_start + seg_time, stop);
4959 }
4960
4961 *_start = start;
4962 *_stop = stop;
4963 *_time = time;
4964 }
4965
4966 /*
4967 * Updates the qt segment used for the stream and pushes a new segment event
4968 * downstream on this stream's pad.
4969 */
4970 static gboolean
gst_qtdemux_stream_update_segment(GstQTDemux * qtdemux,QtDemuxStream * stream,gint seg_idx,GstClockTime offset,GstClockTime * _start,GstClockTime * _stop)4971 gst_qtdemux_stream_update_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
4972 gint seg_idx, GstClockTime offset, GstClockTime * _start,
4973 GstClockTime * _stop)
4974 {
4975 QtDemuxSegment *segment;
4976 GstClockTime start = 0, stop = GST_CLOCK_TIME_NONE, time = 0;
4977 gdouble rate;
4978 GstEvent *event;
4979
4980 /* update the current segment */
4981 stream->segment_index = seg_idx;
4982
4983 /* get the segment */
4984 segment = &stream->segments[seg_idx];
4985
4986 if (G_UNLIKELY (offset < segment->time)) {
4987 GST_WARNING_OBJECT (stream->pad, "offset < segment->time %" GST_TIME_FORMAT,
4988 GST_TIME_ARGS (segment->time));
4989 return FALSE;
4990 }
4991
4992 /* segment lies beyond total indicated duration */
4993 if (G_UNLIKELY (qtdemux->segment.duration != GST_CLOCK_TIME_NONE &&
4994 segment->time > qtdemux->segment.duration)) {
4995 GST_WARNING_OBJECT (stream->pad, "file duration %" GST_TIME_FORMAT
4996 " < segment->time %" GST_TIME_FORMAT,
4997 GST_TIME_ARGS (qtdemux->segment.duration),
4998 GST_TIME_ARGS (segment->time));
4999 return FALSE;
5000 }
5001
5002 gst_qtdemux_stream_segment_get_boundaries (qtdemux, stream, offset,
5003 &start, &stop, &time);
5004
5005 GST_DEBUG_OBJECT (stream->pad, "new segment %d from %" GST_TIME_FORMAT
5006 " to %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT, seg_idx,
5007 GST_TIME_ARGS (start), GST_TIME_ARGS (stop), GST_TIME_ARGS (time));
5008
5009 /* combine global rate with that of the segment */
5010 rate = segment->rate * qtdemux->segment.rate;
5011
5012 /* Copy flags from main segment */
5013 stream->segment.flags = qtdemux->segment.flags;
5014
5015 /* update the segment values used for clipping */
5016 stream->segment.offset = qtdemux->segment.offset;
5017 stream->segment.base = qtdemux->segment.base + stream->accumulated_base;
5018 stream->segment.applied_rate = qtdemux->segment.applied_rate;
5019 stream->segment.rate = rate;
5020 stream->segment.start = start + QTSTREAMTIME_TO_GSTTIME (stream,
5021 stream->cslg_shift);
5022 if (stop != -1)
5023 stream->segment.stop = stop + QTSTREAMTIME_TO_GSTTIME (stream,
5024 stream->cslg_shift);
5025 else
5026 stream->segment.stop = stop;
5027 stream->segment.time = time;
5028 stream->segment.position = stream->segment.start;
5029
5030 GST_DEBUG_OBJECT (stream->pad, "New segment: %" GST_SEGMENT_FORMAT,
5031 &stream->segment);
5032
5033 /* now prepare and send the segment */
5034 if (stream->pad) {
5035 event = gst_event_new_segment (&stream->segment);
5036 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID) {
5037 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
5038 }
5039 gst_pad_push_event (stream->pad, event);
5040 /* assume we can send more data now */
5041 GST_PAD_LAST_FLOW_RETURN (stream->pad) = GST_FLOW_OK;
5042 /* clear to send tags on this pad now */
5043 gst_qtdemux_push_tags (qtdemux, stream);
5044 }
5045
5046 if (_start)
5047 *_start = start;
5048 if (_stop)
5049 *_stop = stop;
5050
5051 return TRUE;
5052 }
5053
5054 /* activate the given segment number @seg_idx of @stream at time @offset.
5055 * @offset is an absolute global position over all the segments.
5056 *
5057 * This will push out a NEWSEGMENT event with the right values and
5058 * position the stream index to the first decodable sample before
5059 * @offset.
5060 */
5061 static gboolean
gst_qtdemux_activate_segment(GstQTDemux * qtdemux,QtDemuxStream * stream,guint32 seg_idx,GstClockTime offset)5062 gst_qtdemux_activate_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
5063 guint32 seg_idx, GstClockTime offset)
5064 {
5065 QtDemuxSegment *segment;
5066 guint32 index, kf_index;
5067 GstClockTime start = 0, stop = GST_CLOCK_TIME_NONE;
5068
5069 GST_LOG_OBJECT (stream->pad, "activate segment %d, offset %" GST_TIME_FORMAT,
5070 seg_idx, GST_TIME_ARGS (offset));
5071
5072 if (!gst_qtdemux_stream_update_segment (qtdemux, stream, seg_idx, offset,
5073 &start, &stop))
5074 return FALSE;
5075
5076 segment = &stream->segments[stream->segment_index];
5077
5078 /* in the fragmented case, we pick a fragment that starts before our
5079 * desired position and rely on downstream to wait for a keyframe
5080 * (FIXME: doesn't seem to work so well with ismv and wmv, as no parser; the
5081 * tfra entries tells us which trun/sample the key unit is in, but we don't
5082 * make use of this additional information at the moment) */
5083 if (qtdemux->fragmented && !qtdemux->fragmented_seek_pending) {
5084 stream->to_sample = G_MAXUINT32;
5085 return TRUE;
5086 } else {
5087 /* well, it will be taken care of below */
5088 qtdemux->fragmented_seek_pending = FALSE;
5089 /* FIXME ideally the do_fragmented_seek can be done right here,
5090 * rather than at loop level
5091 * (which might even allow handling edit lists in a fragmented file) */
5092 }
5093
5094 /* We don't need to look for a sample in push-based */
5095 if (!qtdemux->pullbased)
5096 return TRUE;
5097
5098 /* and move to the keyframe before the indicated media time of the
5099 * segment */
5100 if (G_LIKELY (!QTSEGMENT_IS_EMPTY (segment))) {
5101 if (qtdemux->segment.rate >= 0) {
5102 index = gst_qtdemux_find_index_linear (qtdemux, stream, start);
5103 stream->to_sample = G_MAXUINT32;
5104 GST_DEBUG_OBJECT (stream->pad,
5105 "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
5106 GST_TIME_FORMAT, GST_TIME_ARGS (start), index,
5107 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
5108 } else {
5109 index = gst_qtdemux_find_index_linear (qtdemux, stream, stop);
5110 stream->to_sample = index;
5111 GST_DEBUG_OBJECT (stream->pad,
5112 "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
5113 GST_TIME_FORMAT, GST_TIME_ARGS (stop), index,
5114 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
5115 }
5116 } else {
5117 GST_DEBUG_OBJECT (stream->pad, "No need to look for keyframe, "
5118 "this is an empty segment");
5119 return TRUE;
5120 }
5121
5122 /* gst_qtdemux_parse_sample () called from gst_qtdemux_find_index_linear ()
5123 * encountered an error and printed a message so we return appropriately */
5124 if (index == -1)
5125 return FALSE;
5126
5127 /* we're at the right spot */
5128 if (index == stream->sample_index) {
5129 GST_DEBUG_OBJECT (stream->pad, "we are at the right index");
5130 return TRUE;
5131 }
5132
5133 /* find keyframe of the target index */
5134 kf_index = gst_qtdemux_find_keyframe (qtdemux, stream, index, FALSE);
5135
5136 /* go back two frames to provide lead-in for non-raw audio decoders */
5137 if (stream->subtype == FOURCC_soun && !stream->need_clip) {
5138 guint32 lead_in = 2;
5139 guint32 old_index = kf_index;
5140 GstStructure *s = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
5141
5142 if (gst_structure_has_name (s, "audio/mpeg")) {
5143 gint mpegversion;
5144 if (gst_structure_get_int (s, "mpegversion", &mpegversion)
5145 && mpegversion == 1) {
5146 /* mp3 could need up to 30 frames of lead-in per mpegaudioparse */
5147 lead_in = 30;
5148 }
5149 }
5150
5151 kf_index = MAX (kf_index, lead_in) - lead_in;
5152 if (qtdemux_parse_samples (qtdemux, stream, kf_index)) {
5153 GST_DEBUG_OBJECT (stream->pad,
5154 "Moving backwards %u frames to ensure sufficient sound lead-in",
5155 old_index - kf_index);
5156 } else {
5157 kf_index = old_index;
5158 }
5159 }
5160
5161 /* if we move forwards, we don't have to go back to the previous
5162 * keyframe since we already sent that. We can also just jump to
5163 * the keyframe right before the target index if there is one. */
5164 if (index > stream->sample_index) {
5165 /* moving forwards check if we move past a keyframe */
5166 if (kf_index > stream->sample_index) {
5167 GST_DEBUG_OBJECT (stream->pad,
5168 "moving forwards to keyframe at %u "
5169 "(pts %" GST_TIME_FORMAT " dts %" GST_TIME_FORMAT " )",
5170 kf_index,
5171 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[kf_index])),
5172 GST_TIME_ARGS (QTSAMPLE_DTS (stream, &stream->samples[kf_index])));
5173 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
5174 } else {
5175 GST_DEBUG_OBJECT (stream->pad,
5176 "moving forwards, keyframe at %u "
5177 "(pts %" GST_TIME_FORMAT " dts %" GST_TIME_FORMAT " ) already sent",
5178 kf_index,
5179 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[kf_index])),
5180 GST_TIME_ARGS (QTSAMPLE_DTS (stream, &stream->samples[kf_index])));
5181 }
5182 } else {
5183 GST_DEBUG_OBJECT (stream->pad,
5184 "moving backwards to %sframe at %u "
5185 "(pts %" GST_TIME_FORMAT " dts %" GST_TIME_FORMAT " )",
5186 (stream->subtype == FOURCC_soun) ? "audio " : "key", kf_index,
5187 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[kf_index])),
5188 GST_TIME_ARGS (QTSAMPLE_DTS (stream, &stream->samples[kf_index])));
5189 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
5190 }
5191
5192 return TRUE;
5193 }
5194
5195 /* prepare to get the current sample of @stream, getting essential values.
5196 *
5197 * This function will also prepare and send the segment when needed.
5198 *
5199 * Return FALSE if the stream is EOS.
5200 *
5201 * PULL-BASED
5202 */
5203 static gboolean
gst_qtdemux_prepare_current_sample(GstQTDemux * qtdemux,QtDemuxStream * stream,gboolean * empty,guint64 * offset,guint * size,GstClockTime * dts,GstClockTime * pts,GstClockTime * duration,gboolean * keyframe)5204 gst_qtdemux_prepare_current_sample (GstQTDemux * qtdemux,
5205 QtDemuxStream * stream, gboolean * empty, guint64 * offset, guint * size,
5206 GstClockTime * dts, GstClockTime * pts, GstClockTime * duration,
5207 gboolean * keyframe)
5208 {
5209 QtDemuxSample *sample;
5210 GstClockTime time_position;
5211 guint32 seg_idx;
5212
5213 g_return_val_if_fail (stream != NULL, FALSE);
5214
5215 time_position = stream->time_position;
5216 if (G_UNLIKELY (time_position == GST_CLOCK_TIME_NONE))
5217 goto eos;
5218
5219 seg_idx = stream->segment_index;
5220 if (G_UNLIKELY (seg_idx == -1)) {
5221 /* find segment corresponding to time_position if we are looking
5222 * for a segment. */
5223 seg_idx = gst_qtdemux_find_segment (qtdemux, stream, time_position);
5224 }
5225
5226 /* different segment, activate it, sample_index will be set. */
5227 if (G_UNLIKELY (stream->segment_index != seg_idx))
5228 gst_qtdemux_activate_segment (qtdemux, stream, seg_idx, time_position);
5229
5230 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (&stream->
5231 segments[stream->segment_index]))) {
5232 QtDemuxSegment *seg = &stream->segments[stream->segment_index];
5233
5234 GST_LOG_OBJECT (qtdemux, "Empty segment activated,"
5235 " prepare empty sample");
5236
5237 *empty = TRUE;
5238 *pts = *dts = time_position;
5239 *duration = seg->duration - (time_position - seg->time);
5240
5241 return TRUE;
5242 }
5243
5244 *empty = FALSE;
5245
5246 if (stream->sample_index == -1)
5247 stream->sample_index = 0;
5248
5249 GST_LOG_OBJECT (qtdemux, "segment active, index = %u of %u",
5250 stream->sample_index, stream->n_samples);
5251
5252 if (G_UNLIKELY (stream->sample_index >= stream->n_samples)) {
5253 if (!qtdemux->fragmented)
5254 goto eos;
5255
5256 GST_INFO_OBJECT (qtdemux, "out of samples, trying to add more");
5257 do {
5258 GstFlowReturn flow;
5259
5260 GST_OBJECT_LOCK (qtdemux);
5261 flow = qtdemux_add_fragmented_samples (qtdemux);
5262 GST_OBJECT_UNLOCK (qtdemux);
5263
5264 if (flow != GST_FLOW_OK)
5265 goto eos;
5266 }
5267 while (stream->sample_index >= stream->n_samples);
5268 }
5269
5270 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
5271 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
5272 stream->sample_index);
5273 return FALSE;
5274 }
5275
5276 /* now get the info for the sample we're at */
5277 sample = &stream->samples[stream->sample_index];
5278
5279 *dts = QTSAMPLE_DTS (stream, sample);
5280 *pts = QTSAMPLE_PTS (stream, sample);
5281 *offset = sample->offset;
5282 *size = sample->size;
5283 *duration = QTSAMPLE_DUR_DTS (stream, sample, *dts);
5284 *keyframe = QTSAMPLE_KEYFRAME (stream, sample);
5285
5286 return TRUE;
5287
5288 /* special cases */
5289 eos:
5290 {
5291 stream->time_position = GST_CLOCK_TIME_NONE;
5292 return FALSE;
5293 }
5294 }
5295
5296 /* move to the next sample in @stream.
5297 *
5298 * Moves to the next segment when needed.
5299 */
5300 static void
gst_qtdemux_advance_sample(GstQTDemux * qtdemux,QtDemuxStream * stream)5301 gst_qtdemux_advance_sample (GstQTDemux * qtdemux, QtDemuxStream * stream)
5302 {
5303 QtDemuxSample *sample;
5304 QtDemuxSegment *segment;
5305
5306 /* get current segment */
5307 segment = &stream->segments[stream->segment_index];
5308
5309 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
5310 GST_DEBUG_OBJECT (qtdemux, "Empty segment, no samples to advance");
5311 goto next_segment;
5312 }
5313
5314 if (G_UNLIKELY (stream->sample_index >= stream->to_sample)) {
5315 /* Mark the stream as EOS */
5316 GST_DEBUG_OBJECT (qtdemux,
5317 "reached max allowed sample %u, mark EOS", stream->to_sample);
5318 stream->time_position = GST_CLOCK_TIME_NONE;
5319 return;
5320 }
5321
5322 /* move to next sample */
5323 stream->sample_index++;
5324 stream->offset_in_sample = 0;
5325
5326 GST_TRACE_OBJECT (qtdemux, "advance to sample %u/%u", stream->sample_index,
5327 stream->n_samples);
5328
5329 /* reached the last sample, we need the next segment */
5330 if (G_UNLIKELY (stream->sample_index >= stream->n_samples))
5331 goto next_segment;
5332
5333 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
5334 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
5335 stream->sample_index);
5336 return;
5337 }
5338
5339 /* get next sample */
5340 sample = &stream->samples[stream->sample_index];
5341
5342 GST_TRACE_OBJECT (qtdemux, "sample dts %" GST_TIME_FORMAT " media_stop: %"
5343 GST_TIME_FORMAT, GST_TIME_ARGS (QTSAMPLE_DTS (stream, sample)),
5344 GST_TIME_ARGS (segment->media_stop));
5345
5346 /* see if we are past the segment */
5347 if (G_UNLIKELY (QTSAMPLE_DTS (stream, sample) >= segment->media_stop))
5348 goto next_segment;
5349
5350 if (QTSAMPLE_DTS (stream, sample) >= segment->media_start) {
5351 /* inside the segment, update time_position, looks very familiar to
5352 * GStreamer segments, doesn't it? */
5353 stream->time_position =
5354 QTSAMPLE_DTS (stream, sample) - segment->media_start + segment->time;
5355 } else {
5356 /* not yet in segment, time does not yet increment. This means
5357 * that we are still prerolling keyframes to the decoder so it can
5358 * decode the first sample of the segment. */
5359 stream->time_position = segment->time;
5360 }
5361 return;
5362
5363 /* move to the next segment */
5364 next_segment:
5365 {
5366 GST_DEBUG_OBJECT (qtdemux, "segment %d ended ", stream->segment_index);
5367
5368 if (stream->segment_index == stream->n_segments - 1) {
5369 /* are we at the end of the last segment, we're EOS */
5370 stream->time_position = GST_CLOCK_TIME_NONE;
5371 } else {
5372 /* else we're only at the end of the current segment */
5373 stream->time_position = segment->stop_time;
5374 }
5375 /* make sure we select a new segment */
5376
5377 /* accumulate previous segments */
5378 if (GST_CLOCK_TIME_IS_VALID (stream->segment.stop))
5379 stream->accumulated_base +=
5380 (stream->segment.stop -
5381 stream->segment.start) / ABS (stream->segment.rate);
5382
5383 stream->segment_index = -1;
5384 }
5385 }
5386
5387 static void
gst_qtdemux_sync_streams(GstQTDemux * demux)5388 gst_qtdemux_sync_streams (GstQTDemux * demux)
5389 {
5390 gint i;
5391
5392 if (QTDEMUX_N_STREAMS (demux) <= 1)
5393 return;
5394
5395 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
5396 QtDemuxStream *stream;
5397 GstClockTime end_time;
5398
5399 stream = QTDEMUX_NTH_STREAM (demux, i);
5400
5401 if (!stream->pad)
5402 continue;
5403
5404 /* TODO advance time on subtitle streams here, if any some day */
5405
5406 /* some clips/trailers may have unbalanced streams at the end,
5407 * so send EOS on shorter stream to prevent stalling others */
5408
5409 /* do not mess with EOS if SEGMENT seeking */
5410 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT)
5411 continue;
5412
5413 if (demux->pullbased) {
5414 /* loop mode is sample time based */
5415 if (!STREAM_IS_EOS (stream))
5416 continue;
5417 } else {
5418 /* push mode is byte position based */
5419 if (stream->n_samples &&
5420 stream->samples[stream->n_samples - 1].offset >= demux->offset)
5421 continue;
5422 }
5423
5424 if (stream->sent_eos)
5425 continue;
5426
5427 /* only act if some gap */
5428 end_time = stream->segments[stream->n_segments - 1].stop_time;
5429 GST_LOG_OBJECT (demux, "current position: %" GST_TIME_FORMAT
5430 ", stream end: %" GST_TIME_FORMAT,
5431 GST_TIME_ARGS (demux->segment.position), GST_TIME_ARGS (end_time));
5432 if (GST_CLOCK_TIME_IS_VALID (end_time)
5433 && (end_time + 2 * GST_SECOND < demux->segment.position)) {
5434 GstEvent *event;
5435
5436 GST_DEBUG_OBJECT (demux, "sending EOS for stream %s",
5437 GST_PAD_NAME (stream->pad));
5438 stream->sent_eos = TRUE;
5439 event = gst_event_new_eos ();
5440 if (demux->segment_seqnum != GST_SEQNUM_INVALID)
5441 gst_event_set_seqnum (event, demux->segment_seqnum);
5442 gst_pad_push_event (stream->pad, event);
5443 }
5444 }
5445 }
5446
5447 /* EOS and NOT_LINKED need to be combined. This means that we return:
5448 *
5449 * GST_FLOW_NOT_LINKED: when all pads NOT_LINKED.
5450 * GST_FLOW_EOS: when all pads EOS or NOT_LINKED.
5451 */
5452 static GstFlowReturn
gst_qtdemux_combine_flows(GstQTDemux * demux,QtDemuxStream * stream,GstFlowReturn ret)5453 gst_qtdemux_combine_flows (GstQTDemux * demux, QtDemuxStream * stream,
5454 GstFlowReturn ret)
5455 {
5456 GST_LOG_OBJECT (demux, "flow return: %s", gst_flow_get_name (ret));
5457
5458 if (stream->pad)
5459 ret = gst_flow_combiner_update_pad_flow (demux->flowcombiner, stream->pad,
5460 ret);
5461 else
5462 ret = gst_flow_combiner_update_flow (demux->flowcombiner, ret);
5463
5464 GST_LOG_OBJECT (demux, "combined flow return: %s", gst_flow_get_name (ret));
5465 return ret;
5466 }
5467
5468 /* the input buffer metadata must be writable. Returns NULL when the buffer is
5469 * completely clipped
5470 *
5471 * Should be used only with raw buffers */
5472 static GstBuffer *
gst_qtdemux_clip_buffer(GstQTDemux * qtdemux,QtDemuxStream * stream,GstBuffer * buf)5473 gst_qtdemux_clip_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
5474 GstBuffer * buf)
5475 {
5476 guint64 start, stop, cstart, cstop, diff;
5477 GstClockTime pts, duration;
5478 gsize size, osize;
5479 gint num_rate, denom_rate;
5480 gint frame_size;
5481 gboolean clip_data;
5482 guint offset;
5483
5484 osize = size = gst_buffer_get_size (buf);
5485 offset = 0;
5486
5487 /* depending on the type, setup the clip parameters */
5488 if (stream->subtype == FOURCC_soun) {
5489 frame_size = CUR_STREAM (stream)->bytes_per_frame;
5490 num_rate = GST_SECOND;
5491 denom_rate = (gint) CUR_STREAM (stream)->rate;
5492 clip_data = TRUE;
5493 } else if (stream->subtype == FOURCC_vide) {
5494 frame_size = size;
5495 num_rate = CUR_STREAM (stream)->fps_n;
5496 denom_rate = CUR_STREAM (stream)->fps_d;
5497 clip_data = FALSE;
5498 } else
5499 goto wrong_type;
5500
5501 if (frame_size <= 0)
5502 goto bad_frame_size;
5503
5504 /* we can only clip if we have a valid pts */
5505 pts = GST_BUFFER_PTS (buf);
5506 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (pts)))
5507 goto no_pts;
5508
5509 duration = GST_BUFFER_DURATION (buf);
5510
5511 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (duration))) {
5512 duration =
5513 gst_util_uint64_scale_int (size / frame_size, num_rate, denom_rate);
5514 }
5515
5516 start = pts;
5517 stop = start + duration;
5518
5519 if (G_UNLIKELY (!gst_segment_clip (&stream->segment,
5520 GST_FORMAT_TIME, start, stop, &cstart, &cstop)))
5521 goto clipped;
5522
5523 /* see if some clipping happened */
5524 diff = cstart - start;
5525 if (diff > 0) {
5526 pts += diff;
5527 duration -= diff;
5528
5529 if (clip_data) {
5530 /* bring clipped time to samples and to bytes */
5531 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
5532 diff *= frame_size;
5533
5534 GST_DEBUG_OBJECT (qtdemux,
5535 "clipping start to %" GST_TIME_FORMAT " %"
5536 G_GUINT64_FORMAT " bytes", GST_TIME_ARGS (cstart), diff);
5537
5538 offset = diff;
5539 size -= diff;
5540 }
5541 }
5542 diff = stop - cstop;
5543 if (diff > 0) {
5544 duration -= diff;
5545
5546 if (clip_data) {
5547 /* bring clipped time to samples and then to bytes */
5548 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
5549 diff *= frame_size;
5550 GST_DEBUG_OBJECT (qtdemux,
5551 "clipping stop to %" GST_TIME_FORMAT " %" G_GUINT64_FORMAT
5552 " bytes", GST_TIME_ARGS (cstop), diff);
5553 size -= diff;
5554 }
5555 }
5556
5557 if (offset != 0 || size != osize)
5558 gst_buffer_resize (buf, offset, size);
5559
5560 GST_BUFFER_DTS (buf) = GST_CLOCK_TIME_NONE;
5561 GST_BUFFER_PTS (buf) = pts;
5562 GST_BUFFER_DURATION (buf) = duration;
5563
5564 return buf;
5565
5566 /* dropped buffer */
5567 wrong_type:
5568 {
5569 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
5570 return buf;
5571 }
5572 bad_frame_size:
5573 {
5574 GST_DEBUG_OBJECT (qtdemux, "bad frame size");
5575 return buf;
5576 }
5577 no_pts:
5578 {
5579 GST_DEBUG_OBJECT (qtdemux, "no pts on buffer");
5580 return buf;
5581 }
5582 clipped:
5583 {
5584 GST_DEBUG_OBJECT (qtdemux, "clipped buffer");
5585 gst_buffer_unref (buf);
5586 return NULL;
5587 }
5588 }
5589
5590 static GstBuffer *
gst_qtdemux_align_buffer(GstQTDemux * demux,GstBuffer * buffer,gsize alignment)5591 gst_qtdemux_align_buffer (GstQTDemux * demux,
5592 GstBuffer * buffer, gsize alignment)
5593 {
5594 GstMapInfo map;
5595
5596 gst_buffer_map (buffer, &map, GST_MAP_READ);
5597
5598 if (map.size < sizeof (guintptr)) {
5599 gst_buffer_unmap (buffer, &map);
5600 return buffer;
5601 }
5602
5603 if (((guintptr) map.data) & (alignment - 1)) {
5604 GstBuffer *new_buffer;
5605 GstAllocationParams params = { 0, alignment - 1, 0, 0, };
5606
5607 new_buffer = gst_buffer_new_allocate (NULL,
5608 gst_buffer_get_size (buffer), ¶ms);
5609
5610 /* Copy data "by hand", so ensure alignment is kept: */
5611 gst_buffer_fill (new_buffer, 0, map.data, map.size);
5612
5613 gst_buffer_copy_into (new_buffer, buffer, GST_BUFFER_COPY_METADATA, 0, -1);
5614 GST_DEBUG_OBJECT (demux,
5615 "We want output aligned on %" G_GSIZE_FORMAT ", reallocated",
5616 alignment);
5617
5618 gst_buffer_unmap (buffer, &map);
5619 gst_buffer_unref (buffer);
5620
5621 return new_buffer;
5622 }
5623
5624 gst_buffer_unmap (buffer, &map);
5625 return buffer;
5626 }
5627
5628 static guint8 *
convert_to_s334_1a(const guint8 * ccpair,guint8 ccpair_size,guint field,gsize * res)5629 convert_to_s334_1a (const guint8 * ccpair, guint8 ccpair_size, guint field,
5630 gsize * res)
5631 {
5632 guint8 *storage;
5633 gsize i;
5634
5635 /* We are converting from pairs to triplets */
5636 *res = ccpair_size / 2 * 3;
5637 storage = g_malloc (*res);
5638 for (i = 0; i * 2 < ccpair_size; i += 1) {
5639 /* FIXME: Use line offset 0 as we simply can't know here */
5640 if (field == 1)
5641 storage[i * 3] = 0x80 | 0x00;
5642 else
5643 storage[i * 3] = 0x00 | 0x00;
5644 storage[i * 3 + 1] = ccpair[i * 2];
5645 storage[i * 3 + 2] = ccpair[i * 2 + 1];
5646 }
5647
5648 return storage;
5649 }
5650
5651 static guint8 *
extract_cc_from_data(QtDemuxStream * stream,const guint8 * data,gsize size,gsize * cclen)5652 extract_cc_from_data (QtDemuxStream * stream, const guint8 * data, gsize size,
5653 gsize * cclen)
5654 {
5655 guint8 *res = NULL;
5656 guint32 atom_length, fourcc;
5657 QtDemuxStreamStsdEntry *stsd_entry;
5658
5659 GST_MEMDUMP ("caption atom", data, size);
5660
5661 /* There might be multiple atoms */
5662
5663 *cclen = 0;
5664 if (size < 8)
5665 goto invalid_cdat;
5666 atom_length = QT_UINT32 (data);
5667 fourcc = QT_FOURCC (data + 4);
5668 if (G_UNLIKELY (atom_length > size || atom_length == 8))
5669 goto invalid_cdat;
5670
5671 GST_DEBUG_OBJECT (stream->pad, "here");
5672
5673 /* Check if we have something compatible */
5674 stsd_entry = CUR_STREAM (stream);
5675 switch (stsd_entry->fourcc) {
5676 case FOURCC_c608:{
5677 guint8 *cdat = NULL, *cdt2 = NULL;
5678 gsize cdat_size = 0, cdt2_size = 0;
5679 /* Should be cdat or cdt2 */
5680 if (fourcc != FOURCC_cdat && fourcc != FOURCC_cdt2) {
5681 GST_WARNING_OBJECT (stream->pad,
5682 "Unknown data atom (%" GST_FOURCC_FORMAT ") for CEA608",
5683 GST_FOURCC_ARGS (fourcc));
5684 goto invalid_cdat;
5685 }
5686
5687 /* Convert to S334-1 Annex A byte triplet */
5688 if (fourcc == FOURCC_cdat)
5689 cdat = convert_to_s334_1a (data + 8, atom_length - 8, 1, &cdat_size);
5690 else
5691 cdt2 = convert_to_s334_1a (data + 8, atom_length - 8, 2, &cdt2_size);
5692 GST_DEBUG_OBJECT (stream->pad, "size:%" G_GSIZE_FORMAT " atom_length:%u",
5693 size, atom_length);
5694
5695 /* Check for another atom ? */
5696 if (size > atom_length + 8) {
5697 guint32 new_atom_length = QT_UINT32 (data + atom_length);
5698 if (size >= atom_length + new_atom_length) {
5699 fourcc = QT_FOURCC (data + atom_length + 4);
5700 if (fourcc == FOURCC_cdat) {
5701 if (cdat == NULL)
5702 cdat =
5703 convert_to_s334_1a (data + atom_length + 8,
5704 new_atom_length - 8, 1, &cdat_size);
5705 else
5706 GST_WARNING_OBJECT (stream->pad,
5707 "Got multiple [cdat] atoms in a c608 sample. This is unsupported for now. Please file a bug");
5708 } else {
5709 if (cdt2 == NULL)
5710 cdt2 =
5711 convert_to_s334_1a (data + atom_length + 8,
5712 new_atom_length - 8, 2, &cdt2_size);
5713 else
5714 GST_WARNING_OBJECT (stream->pad,
5715 "Got multiple [cdt2] atoms in a c608 sample. This is unsupported for now. Please file a bug");
5716 }
5717 }
5718 }
5719
5720 *cclen = cdat_size + cdt2_size;
5721 res = g_malloc (*cclen);
5722 if (cdat_size)
5723 memcpy (res, cdat, cdat_size);
5724 if (cdt2_size)
5725 memcpy (res + cdat_size, cdt2, cdt2_size);
5726 g_free (cdat);
5727 g_free (cdt2);
5728 }
5729 break;
5730 case FOURCC_c708:
5731 if (fourcc != FOURCC_ccdp) {
5732 GST_WARNING_OBJECT (stream->pad,
5733 "Unknown data atom (%" GST_FOURCC_FORMAT ") for CEA708",
5734 GST_FOURCC_ARGS (fourcc));
5735 goto invalid_cdat;
5736 }
5737 *cclen = atom_length - 8;
5738 res = g_memdup2 (data + 8, *cclen);
5739 break;
5740 default:
5741 /* Keep this here in case other closed caption formats are added */
5742 g_assert_not_reached ();
5743 break;
5744 }
5745
5746 GST_MEMDUMP ("Output", res, *cclen);
5747 return res;
5748
5749 /* Errors */
5750 invalid_cdat:
5751 GST_WARNING ("[cdat] atom is too small or invalid");
5752 return NULL;
5753 }
5754
5755 /* Handle Closed Caption sample buffers.
5756 * The input buffer metadata must be writable,
5757 * but time/duration etc not yet set and need not be preserved */
5758 static GstBuffer *
gst_qtdemux_process_buffer_clcp(GstQTDemux * qtdemux,QtDemuxStream * stream,GstBuffer * buf)5759 gst_qtdemux_process_buffer_clcp (GstQTDemux * qtdemux, QtDemuxStream * stream,
5760 GstBuffer * buf)
5761 {
5762 GstBuffer *outbuf = NULL;
5763 GstMapInfo map;
5764 guint8 *cc;
5765 gsize cclen = 0;
5766
5767 gst_buffer_map (buf, &map, GST_MAP_READ);
5768
5769 /* empty buffer is sent to terminate previous subtitle */
5770 if (map.size <= 2) {
5771 gst_buffer_unmap (buf, &map);
5772 gst_buffer_unref (buf);
5773 return NULL;
5774 }
5775
5776 /* For closed caption, we need to extract the information from the
5777 * [cdat],[cdt2] or [ccdp] atom */
5778 cc = extract_cc_from_data (stream, map.data, map.size, &cclen);
5779 gst_buffer_unmap (buf, &map);
5780 if (cc) {
5781 outbuf = _gst_buffer_new_wrapped (cc, cclen, g_free);
5782 gst_buffer_copy_into (outbuf, buf, GST_BUFFER_COPY_METADATA, 0, -1);
5783 } else {
5784 /* Conversion failed or there's nothing */
5785 }
5786 gst_buffer_unref (buf);
5787
5788 return outbuf;
5789 }
5790
5791 /* DVD subpicture specific sample handling.
5792 * the input buffer metadata must be writable,
5793 * but time/duration etc not yet set and need not be preserved */
5794 static GstBuffer *
gst_qtdemux_process_buffer_dvd(GstQTDemux * qtdemux,QtDemuxStream * stream,GstBuffer * buf)5795 gst_qtdemux_process_buffer_dvd (GstQTDemux * qtdemux, QtDemuxStream * stream,
5796 GstBuffer * buf)
5797 {
5798 /* send a one time dvd clut event */
5799 if (stream->pending_event && stream->pad)
5800 gst_pad_push_event (stream->pad, stream->pending_event);
5801 stream->pending_event = NULL;
5802
5803 /* empty buffer is sent to terminate previous subtitle */
5804 if (gst_buffer_get_size (buf) <= 2) {
5805 gst_buffer_unref (buf);
5806 return NULL;
5807 }
5808
5809 /* That's all the processing needed for subpictures */
5810 return buf;
5811 }
5812
5813 /* Timed text formats
5814 * the input buffer metadata must be writable,
5815 * but time/duration etc not yet set and need not be preserved */
5816 static GstBuffer *
gst_qtdemux_process_buffer_text(GstQTDemux * qtdemux,QtDemuxStream * stream,GstBuffer * buf)5817 gst_qtdemux_process_buffer_text (GstQTDemux * qtdemux, QtDemuxStream * stream,
5818 GstBuffer * buf)
5819 {
5820 GstBuffer *outbuf = NULL;
5821 GstMapInfo map;
5822 guint nsize = 0;
5823 gchar *str;
5824
5825 /* not many cases for now */
5826 if (G_UNLIKELY (stream->subtype != FOURCC_text &&
5827 stream->subtype != FOURCC_sbtl)) {
5828 return buf;
5829 }
5830
5831 gst_buffer_map (buf, &map, GST_MAP_READ);
5832
5833 /* empty buffer is sent to terminate previous subtitle */
5834 if (map.size <= 2) {
5835 gst_buffer_unmap (buf, &map);
5836 gst_buffer_unref (buf);
5837 return NULL;
5838 }
5839
5840 nsize = GST_READ_UINT16_BE (map.data);
5841 nsize = MIN (nsize, map.size - 2);
5842
5843 GST_LOG_OBJECT (qtdemux, "3GPP timed text subtitle: %d/%" G_GSIZE_FORMAT "",
5844 nsize, map.size);
5845
5846 /* takes care of UTF-8 validation or UTF-16 recognition,
5847 * no other encoding expected */
5848 str = gst_tag_freeform_string_to_utf8 ((gchar *) map.data + 2, nsize, NULL);
5849 gst_buffer_unmap (buf, &map);
5850
5851 if (str) {
5852 outbuf = _gst_buffer_new_wrapped (str, strlen (str), g_free);
5853 gst_buffer_copy_into (outbuf, buf, GST_BUFFER_COPY_METADATA, 0, -1);
5854 } else {
5855 /* this should not really happen unless the subtitle is corrupted */
5856 }
5857 gst_buffer_unref (buf);
5858
5859 /* FIXME ? convert optional subsequent style info to markup */
5860
5861 return outbuf;
5862 }
5863
5864 /* WebVTT sample handling according to 14496-30 */
5865 static GstBuffer *
gst_qtdemux_process_buffer_wvtt(GstQTDemux * qtdemux,QtDemuxStream * stream,GstBuffer * buf)5866 gst_qtdemux_process_buffer_wvtt (GstQTDemux * qtdemux, QtDemuxStream * stream,
5867 GstBuffer * buf)
5868 {
5869 GstBuffer *outbuf = NULL;
5870 GstMapInfo map;
5871
5872 if (!gst_buffer_map (buf, &map, GST_MAP_READ)) {
5873 g_assert_not_reached (); /* The buffer must be mappable */
5874 }
5875
5876 if (qtdemux_webvtt_is_empty (qtdemux, map.data, map.size)) {
5877 GstEvent *gap = NULL;
5878 /* Push a gap event */
5879 stream->segment.position = GST_BUFFER_PTS (buf);
5880 gap =
5881 gst_event_new_gap (stream->segment.position, GST_BUFFER_DURATION (buf));
5882 gst_pad_push_event (stream->pad, gap);
5883
5884 if (GST_BUFFER_DURATION_IS_VALID (buf))
5885 stream->segment.position += GST_BUFFER_DURATION (buf);
5886 } else {
5887 outbuf =
5888 qtdemux_webvtt_decode (qtdemux, GST_BUFFER_PTS (buf),
5889 GST_BUFFER_DURATION (buf), map.data, map.size);
5890 gst_buffer_copy_into (outbuf, buf, GST_BUFFER_COPY_METADATA, 0, -1);
5891 }
5892
5893 gst_buffer_unmap (buf, &map);
5894 gst_buffer_unref (buf);
5895
5896 return outbuf;
5897 }
5898
5899 #ifdef OHOS_OPT_PERFORMANCE // ohos.opt.performance.0001: demux push first audio/video frame
5900 static void
kpi_log_demux_push_first_frame(GstQTDemux * qtdemux,QtDemuxStream * stream)5901 kpi_log_demux_push_first_frame (GstQTDemux *qtdemux, QtDemuxStream *stream)
5902 {
5903 if (stream->has_push_first_frame) {
5904 return;
5905 }
5906
5907 if (stream->subtype == FOURCC_vide && stream->on_keyframe) {
5908 stream->has_push_first_frame = TRUE;
5909 GST_WARNING_OBJECT(qtdemux, "KPI-TRACE: FIRST-VIDEO-FRAME demux push first video keyframe");
5910 } else if (stream->subtype == FOURCC_soun) {
5911 stream->has_push_first_frame = TRUE;
5912 GST_WARNING_OBJECT(qtdemux, "KPI-TRACE: demux push first audio frame");
5913 }
5914 }
5915 #endif
5916
5917 static GstFlowReturn
gst_qtdemux_push_buffer(GstQTDemux * qtdemux,QtDemuxStream * stream,GstBuffer * buf)5918 gst_qtdemux_push_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
5919 GstBuffer * buf)
5920 {
5921 GstFlowReturn ret = GST_FLOW_OK;
5922 GstClockTime pts, duration;
5923
5924 if (stream->need_clip)
5925 buf = gst_qtdemux_clip_buffer (qtdemux, stream, buf);
5926
5927 if (G_UNLIKELY (buf == NULL))
5928 goto exit;
5929
5930 if (G_UNLIKELY (stream->discont)) {
5931 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
5932 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
5933 stream->discont = FALSE;
5934 } else {
5935 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
5936 }
5937
5938 GST_LOG_OBJECT (qtdemux,
5939 "Pushing buffer with dts %" GST_TIME_FORMAT ", pts %" GST_TIME_FORMAT
5940 ", duration %" GST_TIME_FORMAT " on pad %s",
5941 GST_TIME_ARGS (GST_BUFFER_DTS (buf)),
5942 GST_TIME_ARGS (GST_BUFFER_PTS (buf)),
5943 GST_TIME_ARGS (GST_BUFFER_DURATION (buf)), GST_PAD_NAME (stream->pad));
5944
5945 if (stream->protected && stream->protection_scheme_type == FOURCC_aavd) {
5946 GstStructure *crypto_info;
5947 QtDemuxAavdEncryptionInfo *info =
5948 (QtDemuxAavdEncryptionInfo *) stream->protection_scheme_info;
5949
5950 crypto_info = gst_structure_copy (info->default_properties);
5951 if (!crypto_info || !gst_buffer_add_protection_meta (buf, crypto_info))
5952 GST_ERROR_OBJECT (qtdemux, "failed to attach aavd metadata to buffer");
5953 }
5954
5955 if (stream->protected && (stream->protection_scheme_type == FOURCC_cenc
5956 || stream->protection_scheme_type == FOURCC_cbcs)) {
5957 GstStructure *crypto_info;
5958 QtDemuxCencSampleSetInfo *info =
5959 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
5960 gint index;
5961 GstEvent *event;
5962
5963 while ((event = g_queue_pop_head (&stream->protection_scheme_event_queue))) {
5964 GST_TRACE_OBJECT (stream->pad, "pushing protection event: %"
5965 GST_PTR_FORMAT, event);
5966 gst_pad_push_event (stream->pad, event);
5967 }
5968
5969 if (info->crypto_info == NULL) {
5970 if (stream->protection_scheme_type == FOURCC_cbcs) {
5971 crypto_info = qtdemux_get_cenc_sample_properties (qtdemux, stream, 0);
5972 if (!crypto_info || !gst_buffer_add_protection_meta (buf, crypto_info)) {
5973 GST_ERROR_OBJECT (qtdemux,
5974 "failed to attach cbcs metadata to buffer");
5975 qtdemux_gst_structure_free (crypto_info);
5976 } else {
5977 GST_TRACE_OBJECT (qtdemux, "added cbcs protection metadata");
5978 }
5979 } else {
5980 GST_DEBUG_OBJECT (qtdemux,
5981 "cenc metadata hasn't been parsed yet, pushing buffer as if it wasn't encrypted");
5982 }
5983 } else {
5984 /* The end of the crypto_info array matches our n_samples position,
5985 * so count backward from there */
5986 index = stream->sample_index - stream->n_samples + info->crypto_info->len;
5987 if (G_LIKELY (index >= 0 && index < info->crypto_info->len)) {
5988 /* steal structure from array */
5989 crypto_info = g_ptr_array_index (info->crypto_info, index);
5990 g_ptr_array_index (info->crypto_info, index) = NULL;
5991 GST_LOG_OBJECT (qtdemux, "attaching cenc metadata [%u/%u]", index,
5992 info->crypto_info->len);
5993 if (!crypto_info || !gst_buffer_add_protection_meta (buf, crypto_info))
5994 GST_ERROR_OBJECT (qtdemux,
5995 "failed to attach cenc metadata to buffer");
5996 } else {
5997 GST_INFO_OBJECT (qtdemux, "No crypto info with index %d and sample %d",
5998 index, stream->sample_index);
5999 }
6000 }
6001 }
6002
6003 if (stream->alignment > 1)
6004 buf = gst_qtdemux_align_buffer (qtdemux, buf, stream->alignment);
6005
6006 pts = GST_BUFFER_PTS (buf);
6007 duration = GST_BUFFER_DURATION (buf);
6008
6009 #ifdef OHOS_OPT_PERFORMANCE // ohos.opt.performance.0001: add log for kpi
6010 kpi_log_demux_push_first_frame (qtdemux, stream);
6011 #endif
6012 #ifdef OHOS_OPT_PERFORMANCE
6013 // ohos.opt.performance.0005
6014 // add trace
6015 {
6016 GstStartTrace("Qtdemux:pad_push");
6017 ret = gst_pad_push (stream->pad, buf);
6018 GstFinishTrace();
6019 }
6020 #else
6021 ret = gst_pad_push (stream->pad, buf);
6022 #endif
6023
6024 if (GST_CLOCK_TIME_IS_VALID (pts) && GST_CLOCK_TIME_IS_VALID (duration)) {
6025 /* mark position in stream, we'll need this to know when to send GAP event */
6026 stream->segment.position = pts + duration;
6027 }
6028
6029 exit:
6030
6031 return ret;
6032 }
6033
6034 static GstFlowReturn
gst_qtdemux_split_and_push_buffer(GstQTDemux * qtdemux,QtDemuxStream * stream,GstBuffer * buf)6035 gst_qtdemux_split_and_push_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
6036 GstBuffer * buf)
6037 {
6038 GstFlowReturn ret = GST_FLOW_OK;
6039
6040 if (stream->subtype == FOURCC_clcp
6041 && CUR_STREAM (stream)->fourcc == FOURCC_c608 && stream->need_split) {
6042 GstMapInfo map;
6043 guint n_output_buffers, n_field1 = 0, n_field2 = 0;
6044 guint n_triplets, i;
6045 guint field1_off = 0, field2_off = 0;
6046
6047 /* We have to split CEA608 buffers so that each outgoing buffer contains
6048 * one byte pair per field according to the framerate of the video track.
6049 *
6050 * If there is only a single byte pair per field we don't have to do
6051 * anything
6052 */
6053
6054 gst_buffer_map (buf, &map, GST_MAP_READ);
6055
6056 n_triplets = map.size / 3;
6057 for (i = 0; i < n_triplets; i++) {
6058 if (map.data[3 * i] & 0x80)
6059 n_field1++;
6060 else
6061 n_field2++;
6062 }
6063
6064 g_assert (n_field1 || n_field2);
6065
6066 /* If there's more than 1 frame we have to split, otherwise we can just
6067 * pass through */
6068 if (n_field1 > 1 || n_field2 > 1) {
6069 n_output_buffers =
6070 gst_util_uint64_scale (GST_BUFFER_DURATION (buf),
6071 CUR_STREAM (stream)->fps_n, GST_SECOND * CUR_STREAM (stream)->fps_d);
6072
6073 for (i = 0; i < n_output_buffers; i++) {
6074 GstBuffer *outbuf =
6075 gst_buffer_new_and_alloc ((n_field1 ? 3 : 0) + (n_field2 ? 3 : 0));
6076 GstMapInfo outmap;
6077 guint8 *outptr;
6078
6079 gst_buffer_map (outbuf, &outmap, GST_MAP_WRITE);
6080 outptr = outmap.data;
6081
6082 if (n_field1) {
6083 gboolean found = FALSE;
6084
6085 while (map.data + field1_off < map.data + map.size) {
6086 if (map.data[field1_off] & 0x80) {
6087 memcpy (outptr, &map.data[field1_off], 3);
6088 field1_off += 3;
6089 found = TRUE;
6090 break;
6091 }
6092 field1_off += 3;
6093 }
6094
6095 if (!found) {
6096 const guint8 empty[] = { 0x80, 0x80, 0x80 };
6097
6098 memcpy (outptr, empty, 3);
6099 }
6100
6101 outptr += 3;
6102 }
6103
6104 if (n_field2) {
6105 gboolean found = FALSE;
6106
6107 while (map.data + field2_off < map.data + map.size) {
6108 if ((map.data[field2_off] & 0x80) == 0) {
6109 memcpy (outptr, &map.data[field2_off], 3);
6110 field2_off += 3;
6111 found = TRUE;
6112 break;
6113 }
6114 field2_off += 3;
6115 }
6116
6117 if (!found) {
6118 const guint8 empty[] = { 0x00, 0x80, 0x80 };
6119
6120 memcpy (outptr, empty, 3);
6121 }
6122
6123 outptr += 3;
6124 }
6125
6126 gst_buffer_unmap (outbuf, &outmap);
6127
6128 GST_BUFFER_PTS (outbuf) =
6129 GST_BUFFER_PTS (buf) + gst_util_uint64_scale (i,
6130 GST_SECOND * CUR_STREAM (stream)->fps_d,
6131 CUR_STREAM (stream)->fps_n);
6132 GST_BUFFER_DURATION (outbuf) =
6133 gst_util_uint64_scale (GST_SECOND, CUR_STREAM (stream)->fps_d,
6134 CUR_STREAM (stream)->fps_n);
6135 GST_BUFFER_OFFSET (outbuf) = -1;
6136 GST_BUFFER_OFFSET_END (outbuf) = -1;
6137
6138 ret = gst_qtdemux_push_buffer (qtdemux, stream, outbuf);
6139
6140 if (ret != GST_FLOW_OK && ret != GST_FLOW_NOT_LINKED)
6141 break;
6142 }
6143 gst_buffer_unmap (buf, &map);
6144 gst_buffer_unref (buf);
6145 } else {
6146 gst_buffer_unmap (buf, &map);
6147 ret = gst_qtdemux_push_buffer (qtdemux, stream, buf);
6148 }
6149 } else {
6150 ret = gst_qtdemux_push_buffer (qtdemux, stream, buf);
6151 }
6152
6153 return ret;
6154 }
6155
6156 /* Sets a buffer's attributes properly and pushes it downstream.
6157 * Also checks for additional actions and custom processing that may
6158 * need to be done first.
6159 */
6160 static GstFlowReturn
gst_qtdemux_decorate_and_push_buffer(GstQTDemux * qtdemux,QtDemuxStream * stream,GstBuffer * buf,GstClockTime dts,GstClockTime pts,GstClockTime duration,gboolean keyframe,GstClockTime position,guint64 byte_position)6161 gst_qtdemux_decorate_and_push_buffer (GstQTDemux * qtdemux,
6162 QtDemuxStream * stream, GstBuffer * buf,
6163 GstClockTime dts, GstClockTime pts, GstClockTime duration,
6164 gboolean keyframe, GstClockTime position, guint64 byte_position)
6165 {
6166 GstFlowReturn ret = GST_FLOW_OK;
6167
6168 /* offset the timestamps according to the edit list */
6169
6170 if (G_UNLIKELY (CUR_STREAM (stream)->fourcc == FOURCC_rtsp)) {
6171 gchar *url;
6172 GstMapInfo map;
6173
6174 gst_buffer_map (buf, &map, GST_MAP_READ);
6175 url = g_strndup ((gchar *) map.data, map.size);
6176 gst_buffer_unmap (buf, &map);
6177 if (url != NULL && strlen (url) != 0) {
6178 /* we have RTSP redirect now */
6179 g_free (qtdemux->redirect_location);
6180 qtdemux->redirect_location = g_strdup (url);
6181 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
6182 gst_message_new_element (GST_OBJECT_CAST (qtdemux),
6183 gst_structure_new ("redirect",
6184 "new-location", G_TYPE_STRING, url, NULL)));
6185 } else {
6186 GST_WARNING_OBJECT (qtdemux, "Redirect URI of stream is empty, not "
6187 "posting");
6188 }
6189 g_free (url);
6190 }
6191
6192 /* position reporting */
6193 if (qtdemux->segment.rate >= 0) {
6194 qtdemux->segment.position = position;
6195 gst_qtdemux_sync_streams (qtdemux);
6196 }
6197
6198 if (G_UNLIKELY (!stream->pad)) {
6199 GST_DEBUG_OBJECT (qtdemux, "No output pad for stream, ignoring");
6200 gst_buffer_unref (buf);
6201 goto exit;
6202 }
6203
6204 /* send out pending buffers */
6205 while (stream->buffers) {
6206 GstBuffer *buffer = (GstBuffer *) stream->buffers->data;
6207
6208 if (G_UNLIKELY (stream->discont)) {
6209 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
6210 GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
6211 stream->discont = FALSE;
6212 } else {
6213 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
6214 }
6215
6216 if (stream->alignment > 1)
6217 buffer = gst_qtdemux_align_buffer (qtdemux, buffer, stream->alignment);
6218 #ifdef OHOS_OPT_PERFORMANCE
6219 // ohos.opt.performance.0005
6220 // add trace
6221 {
6222 GstStartTrace("Qtdemux:pad_push");
6223 gst_pad_push (stream->pad, buffer);
6224 GstFinishTrace();
6225 }
6226 #else
6227 gst_pad_push (stream->pad, buffer);
6228 #endif
6229
6230 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
6231 }
6232
6233 /* we're going to modify the metadata */
6234 buf = gst_buffer_make_writable (buf);
6235
6236 GST_BUFFER_DTS (buf) = dts;
6237 GST_BUFFER_PTS (buf) = pts;
6238 GST_BUFFER_DURATION (buf) = duration;
6239 GST_BUFFER_OFFSET (buf) = -1;
6240 GST_BUFFER_OFFSET_END (buf) = -1;
6241
6242 if (G_UNLIKELY (stream->process_func))
6243 buf = stream->process_func (qtdemux, stream, buf);
6244
6245 if (!buf) {
6246 goto exit;
6247 }
6248
6249 if (!keyframe) {
6250 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
6251 stream->on_keyframe = FALSE;
6252 } else {
6253 stream->on_keyframe = TRUE;
6254 }
6255
6256 if (G_UNLIKELY (CUR_STREAM (stream)->rgb8_palette))
6257 gst_buffer_append_memory (buf,
6258 gst_memory_ref (CUR_STREAM (stream)->rgb8_palette));
6259
6260 if (G_UNLIKELY (CUR_STREAM (stream)->padding)) {
6261 gst_buffer_resize (buf, CUR_STREAM (stream)->padding, -1);
6262 }
6263 #if 0
6264 if (G_UNLIKELY (qtdemux->element_index)) {
6265 GstClockTime stream_time;
6266
6267 stream_time =
6268 gst_segment_to_stream_time (&stream->segment, GST_FORMAT_TIME,
6269 timestamp);
6270 if (GST_CLOCK_TIME_IS_VALID (stream_time)) {
6271 GST_LOG_OBJECT (qtdemux,
6272 "adding association %" GST_TIME_FORMAT "-> %"
6273 G_GUINT64_FORMAT, GST_TIME_ARGS (stream_time), byte_position);
6274 gst_index_add_association (qtdemux->element_index,
6275 qtdemux->index_id,
6276 keyframe ? GST_ASSOCIATION_FLAG_KEY_UNIT :
6277 GST_ASSOCIATION_FLAG_DELTA_UNIT, GST_FORMAT_TIME, stream_time,
6278 GST_FORMAT_BYTES, byte_position, NULL);
6279 }
6280 }
6281 #endif
6282
6283 #ifdef OHOS_OPT_PERFORMANCE
6284 // ohos.opt.performance.0005
6285 // add trace
6286 {
6287 GstStartTrace("Qtdemux:split_push");
6288 ret = gst_qtdemux_split_and_push_buffer (qtdemux, stream, buf);
6289 GstFinishTrace();
6290 }
6291 #else
6292 ret = gst_qtdemux_split_and_push_buffer (qtdemux, stream, buf);
6293 #endif
6294
6295 exit:
6296 return ret;
6297 }
6298
6299 static const QtDemuxRandomAccessEntry *
gst_qtdemux_stream_seek_fragment(GstQTDemux * qtdemux,QtDemuxStream * stream,GstClockTime pos,gboolean after)6300 gst_qtdemux_stream_seek_fragment (GstQTDemux * qtdemux, QtDemuxStream * stream,
6301 GstClockTime pos, gboolean after)
6302 {
6303 QtDemuxRandomAccessEntry *entries = stream->ra_entries;
6304 guint n_entries = stream->n_ra_entries;
6305 guint i;
6306
6307 /* we assume the table is sorted */
6308 for (i = 0; i < n_entries; ++i) {
6309 if (entries[i].ts > pos)
6310 break;
6311 }
6312
6313 /* FIXME: maybe save first moof_offset somewhere instead, but for now it's
6314 * probably okay to assume that the index lists the very first fragment */
6315 if (i == 0)
6316 return &entries[0];
6317
6318 if (after)
6319 return &entries[i];
6320 else
6321 return &entries[i - 1];
6322 }
6323
6324 static gboolean
gst_qtdemux_do_fragmented_seek(GstQTDemux * qtdemux)6325 gst_qtdemux_do_fragmented_seek (GstQTDemux * qtdemux)
6326 {
6327 const QtDemuxRandomAccessEntry *best_entry = NULL;
6328 gint i;
6329
6330 GST_OBJECT_LOCK (qtdemux);
6331
6332 g_assert (QTDEMUX_N_STREAMS (qtdemux) > 0);
6333
6334 /* first see if we can determine where to go to using mfra,
6335 * before we start clearing things */
6336 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
6337 const QtDemuxRandomAccessEntry *entry;
6338 QtDemuxStream *stream;
6339 gboolean is_audio_or_video;
6340
6341 stream = QTDEMUX_NTH_STREAM (qtdemux, i);
6342
6343 if (stream->ra_entries == NULL)
6344 continue;
6345
6346 if (stream->subtype == FOURCC_vide || stream->subtype == FOURCC_soun)
6347 is_audio_or_video = TRUE;
6348 else
6349 is_audio_or_video = FALSE;
6350
6351 entry =
6352 gst_qtdemux_stream_seek_fragment (qtdemux, stream,
6353 stream->time_position, !is_audio_or_video);
6354
6355 GST_INFO_OBJECT (stream->pad, "%" GST_TIME_FORMAT " at offset "
6356 "%" G_GUINT64_FORMAT, GST_TIME_ARGS (entry->ts), entry->moof_offset);
6357
6358 stream->pending_seek = entry;
6359
6360 /* decide position to jump to just based on audio/video tracks, not subs */
6361 if (!is_audio_or_video)
6362 continue;
6363
6364 if (best_entry == NULL || entry->moof_offset < best_entry->moof_offset)
6365 best_entry = entry;
6366 }
6367
6368 /* no luck, will handle seek otherwise */
6369 if (best_entry == NULL) {
6370 GST_OBJECT_UNLOCK (qtdemux);
6371 return FALSE;
6372 }
6373
6374 /* ok, now we can prepare for processing as of located moof */
6375 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
6376 QtDemuxStream *stream;
6377
6378 stream = QTDEMUX_NTH_STREAM (qtdemux, i);
6379
6380 g_free (stream->samples);
6381 stream->samples = NULL;
6382 stream->n_samples = 0;
6383 stream->stbl_index = -1; /* no samples have yet been parsed */
6384 stream->sample_index = -1;
6385
6386 if (stream->protection_scheme_info) {
6387 /* Clear out any old cenc crypto info entries as we'll move to a new moof */
6388 if (stream->protection_scheme_type == FOURCC_cenc
6389 || stream->protection_scheme_type == FOURCC_cbcs) {
6390 QtDemuxCencSampleSetInfo *info =
6391 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
6392 if (info->crypto_info) {
6393 g_ptr_array_free (info->crypto_info, TRUE);
6394 info->crypto_info = NULL;
6395 }
6396 }
6397 }
6398 }
6399
6400 GST_INFO_OBJECT (qtdemux, "seek to %" GST_TIME_FORMAT ", best fragment "
6401 "moof offset: %" G_GUINT64_FORMAT ", ts %" GST_TIME_FORMAT,
6402 GST_TIME_ARGS (QTDEMUX_NTH_STREAM (qtdemux, 0)->time_position),
6403 best_entry->moof_offset, GST_TIME_ARGS (best_entry->ts));
6404
6405 qtdemux->moof_offset = best_entry->moof_offset;
6406
6407 qtdemux_add_fragmented_samples (qtdemux);
6408
6409 GST_OBJECT_UNLOCK (qtdemux);
6410 return TRUE;
6411 }
6412
6413 static GstFlowReturn
gst_qtdemux_loop_state_movie(GstQTDemux * qtdemux)6414 gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux)
6415 {
6416 GstFlowReturn ret = GST_FLOW_OK;
6417 GstBuffer *buf = NULL;
6418 QtDemuxStream *stream, *target_stream = NULL;
6419 GstClockTime min_time;
6420 guint64 offset = 0;
6421 GstClockTime dts = GST_CLOCK_TIME_NONE;
6422 GstClockTime pts = GST_CLOCK_TIME_NONE;
6423 GstClockTime duration = 0;
6424 gboolean keyframe = FALSE;
6425 guint sample_size = 0;
6426 guint num_samples = 1;
6427 gboolean empty = 0;
6428 guint size;
6429 gint i;
6430
6431 if (qtdemux->fragmented_seek_pending) {
6432 GST_INFO_OBJECT (qtdemux, "pending fragmented seek");
6433 if (gst_qtdemux_do_fragmented_seek (qtdemux)) {
6434 GST_INFO_OBJECT (qtdemux, "fragmented seek done!");
6435 qtdemux->fragmented_seek_pending = FALSE;
6436 } else {
6437 GST_INFO_OBJECT (qtdemux, "fragmented seek still pending");
6438 }
6439 }
6440
6441 /* Figure out the next stream sample to output, min_time is expressed in
6442 * global time and runs over the edit list segments. */
6443 min_time = G_MAXUINT64;
6444 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
6445 GstClockTime position;
6446
6447 stream = QTDEMUX_NTH_STREAM (qtdemux, i);
6448 position = stream->time_position;
6449
6450 if (!GST_CLOCK_TIME_IS_VALID (position))
6451 continue;
6452
6453 if (stream->segment_index != -1) {
6454 QtDemuxSegment *segment = &stream->segments[stream->segment_index];
6455 position += segment->media_start;
6456 }
6457
6458 /* position of -1 is EOS */
6459 if (position < min_time) {
6460 min_time = position;
6461 target_stream = stream;
6462 }
6463 }
6464 /* all are EOS */
6465 if (G_UNLIKELY (target_stream == NULL)) {
6466 GST_DEBUG_OBJECT (qtdemux, "all streams are EOS");
6467 goto eos;
6468 }
6469
6470 /* check for segment end */
6471 if (G_UNLIKELY (qtdemux->segment.stop != -1
6472 && qtdemux->segment.rate >= 0
6473 && qtdemux->segment.stop <= min_time && target_stream->on_keyframe)) {
6474 GST_DEBUG_OBJECT (qtdemux, "we reached the end of our segment.");
6475 target_stream->time_position = GST_CLOCK_TIME_NONE;
6476 goto eos_stream;
6477 }
6478
6479 /* gap events for subtitle streams */
6480 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
6481 stream = QTDEMUX_NTH_STREAM (qtdemux, i);
6482 if (stream->pad) {
6483 GstClockTime gap_threshold;
6484
6485 /* Only send gap events on non-subtitle streams if lagging way behind. */
6486 if (stream->subtype == FOURCC_subp
6487 || stream->subtype == FOURCC_text || stream->subtype == FOURCC_sbtl ||
6488 stream->subtype == FOURCC_wvtt)
6489 gap_threshold = 1 * GST_SECOND;
6490 else
6491 gap_threshold = 3 * GST_SECOND;
6492
6493 /* send gap events until the stream catches up */
6494 /* gaps can only be sent after segment is activated (segment.stop is no longer -1) */
6495 while (GST_CLOCK_TIME_IS_VALID (stream->segment.stop) &&
6496 GST_CLOCK_TIME_IS_VALID (stream->segment.position) &&
6497 stream->segment.position + gap_threshold < min_time) {
6498 GstEvent *gap =
6499 gst_event_new_gap (stream->segment.position, gap_threshold);
6500 gst_pad_push_event (stream->pad, gap);
6501 stream->segment.position += gap_threshold;
6502 }
6503 }
6504 }
6505
6506 stream = target_stream;
6507 /* fetch info for the current sample of this stream */
6508 if (G_UNLIKELY (!gst_qtdemux_prepare_current_sample (qtdemux, stream, &empty,
6509 &offset, &sample_size, &dts, &pts, &duration, &keyframe)))
6510 goto eos_stream;
6511
6512 gst_qtdemux_stream_check_and_change_stsd_index (qtdemux, stream);
6513 if (stream->new_caps) {
6514 gst_qtdemux_configure_stream (qtdemux, stream);
6515 qtdemux_do_allocation (stream, qtdemux);
6516 }
6517
6518 /* If we're doing a keyframe-only trickmode, only push keyframes on video streams */
6519 if (G_UNLIKELY (qtdemux->segment.
6520 flags & GST_SEGMENT_FLAG_TRICKMODE_KEY_UNITS)) {
6521 if (stream->subtype == FOURCC_vide) {
6522 if (!keyframe) {
6523 GST_LOG_OBJECT (qtdemux, "Skipping non-keyframe on track-id %u",
6524 stream->track_id);
6525 goto next;
6526 } else if (qtdemux->trickmode_interval > 0) {
6527 GstClockTimeDiff interval;
6528
6529 if (qtdemux->segment.rate > 0)
6530 interval = stream->time_position - stream->last_keyframe_dts;
6531 else
6532 interval = stream->last_keyframe_dts - stream->time_position;
6533
6534 if (GST_CLOCK_TIME_IS_VALID (stream->last_keyframe_dts)
6535 && interval < qtdemux->trickmode_interval) {
6536 GST_LOG_OBJECT (qtdemux,
6537 "Skipping keyframe within interval on track-id %u",
6538 stream->track_id);
6539 goto next;
6540 } else {
6541 stream->last_keyframe_dts = stream->time_position;
6542 }
6543 }
6544 }
6545 }
6546
6547 GST_DEBUG_OBJECT (qtdemux,
6548 "pushing from track-id %u, empty %d offset %" G_GUINT64_FORMAT
6549 ", size %d, dts=%" GST_TIME_FORMAT ", pts=%" GST_TIME_FORMAT
6550 ", duration %" GST_TIME_FORMAT, stream->track_id, empty, offset,
6551 sample_size, GST_TIME_ARGS (dts), GST_TIME_ARGS (pts),
6552 GST_TIME_ARGS (duration));
6553
6554 if (G_UNLIKELY (empty)) {
6555 /* empty segment, push a gap if there's a second or more
6556 * difference and move to the next one */
6557 if ((pts + duration - stream->segment.position) >= GST_SECOND)
6558 gst_pad_push_event (stream->pad, gst_event_new_gap (pts, duration));
6559 stream->segment.position = pts + duration;
6560 goto next;
6561 }
6562
6563 /* hmm, empty sample, skip and move to next sample */
6564 if (G_UNLIKELY (sample_size <= 0))
6565 goto next;
6566
6567 /* last pushed sample was out of boundary, goto next sample */
6568 if (G_UNLIKELY (GST_PAD_LAST_FLOW_RETURN (stream->pad) == GST_FLOW_EOS))
6569 goto next;
6570
6571 if (stream->max_buffer_size != 0 && sample_size > stream->max_buffer_size) {
6572 GST_DEBUG_OBJECT (qtdemux,
6573 "size %d larger than stream max_buffer_size %d, trimming",
6574 sample_size, stream->max_buffer_size);
6575 size =
6576 MIN (sample_size - stream->offset_in_sample, stream->max_buffer_size);
6577 } else if (stream->min_buffer_size != 0 && stream->offset_in_sample == 0
6578 && sample_size < stream->min_buffer_size) {
6579 guint start_sample_index = stream->sample_index;
6580 guint accumulated_size = sample_size;
6581 guint64 expected_next_offset = offset + sample_size;
6582
6583 GST_DEBUG_OBJECT (qtdemux,
6584 "size %d smaller than stream min_buffer_size %d, combining with the next",
6585 sample_size, stream->min_buffer_size);
6586
6587 while (stream->sample_index < stream->to_sample
6588 && stream->sample_index + 1 < stream->n_samples) {
6589 const QtDemuxSample *next_sample;
6590
6591 /* Increment temporarily */
6592 stream->sample_index++;
6593
6594 /* Failed to parse sample so let's go back to the previous one that was
6595 * still successful */
6596 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
6597 stream->sample_index--;
6598 break;
6599 }
6600
6601 next_sample = &stream->samples[stream->sample_index];
6602
6603 /* Not contiguous with the previous sample so let's go back to the
6604 * previous one that was still successful */
6605 if (next_sample->offset != expected_next_offset) {
6606 stream->sample_index--;
6607 break;
6608 }
6609
6610 accumulated_size += next_sample->size;
6611 expected_next_offset += next_sample->size;
6612 if (accumulated_size >= stream->min_buffer_size)
6613 break;
6614 }
6615
6616 num_samples = stream->sample_index + 1 - start_sample_index;
6617 stream->sample_index = start_sample_index;
6618 GST_DEBUG_OBJECT (qtdemux, "Pulling %u samples of size %u at once",
6619 num_samples, accumulated_size);
6620 size = accumulated_size;
6621 } else {
6622 size = sample_size;
6623 }
6624
6625 if (qtdemux->cenc_aux_info_offset > 0) {
6626 GstMapInfo map;
6627 GstByteReader br;
6628 GstBuffer *aux_info = NULL;
6629
6630 /* pull the data stored before the sample */
6631 ret =
6632 gst_qtdemux_pull_atom (qtdemux, qtdemux->offset,
6633 offset + stream->offset_in_sample - qtdemux->offset, &aux_info);
6634 if (G_UNLIKELY (ret != GST_FLOW_OK))
6635 goto beach;
6636 gst_buffer_map (aux_info, &map, GST_MAP_READ);
6637 GST_DEBUG_OBJECT (qtdemux, "parsing cenc auxiliary info");
6638 gst_byte_reader_init (&br, map.data + 8, map.size);
6639 if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
6640 qtdemux->cenc_aux_info_sizes, qtdemux->cenc_aux_sample_count)) {
6641 GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
6642 gst_buffer_unmap (aux_info, &map);
6643 gst_buffer_unref (aux_info);
6644 ret = GST_FLOW_ERROR;
6645 goto beach;
6646 }
6647 gst_buffer_unmap (aux_info, &map);
6648 gst_buffer_unref (aux_info);
6649 }
6650
6651 GST_LOG_OBJECT (qtdemux, "reading %d bytes @ %" G_GUINT64_FORMAT, size,
6652 offset);
6653
6654 if (stream->use_allocator) {
6655 /* if we have a per-stream allocator, use it */
6656 buf = gst_buffer_new_allocate (stream->allocator, size, &stream->params);
6657 }
6658
6659 ret = gst_qtdemux_pull_atom (qtdemux, offset + stream->offset_in_sample,
6660 size, &buf);
6661 if (G_UNLIKELY (ret != GST_FLOW_OK))
6662 goto beach;
6663
6664 /* Update for both splitting and combining of samples */
6665 if (size != sample_size) {
6666 pts += gst_util_uint64_scale_int (GST_SECOND,
6667 stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame,
6668 stream->timescale);
6669 dts +=
6670 gst_util_uint64_scale_int (GST_SECOND,
6671 stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame,
6672 stream->timescale);
6673 duration =
6674 gst_util_uint64_scale_int (GST_SECOND,
6675 size / CUR_STREAM (stream)->bytes_per_frame, stream->timescale);
6676 }
6677
6678 ret = gst_qtdemux_decorate_and_push_buffer (qtdemux, stream, buf,
6679 dts, pts, duration, keyframe, min_time, offset);
6680
6681 if (size < sample_size) {
6682 QtDemuxSample *sample = &stream->samples[stream->sample_index];
6683 QtDemuxSegment *segment = &stream->segments[stream->segment_index];
6684
6685 GstClockTime time_position = QTSTREAMTIME_TO_GSTTIME (stream,
6686 sample->timestamp +
6687 stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame);
6688 if (time_position >= segment->media_start) {
6689 /* inside the segment, update time_position, looks very familiar to
6690 * GStreamer segments, doesn't it? */
6691 stream->time_position = (time_position - segment->media_start) +
6692 segment->time;
6693 } else {
6694 /* not yet in segment, time does not yet increment. This means
6695 * that we are still prerolling keyframes to the decoder so it can
6696 * decode the first sample of the segment. */
6697 stream->time_position = segment->time;
6698 }
6699 } else if (size > sample_size) {
6700 /* Increase to the last sample we already pulled so that advancing
6701 * below brings us to the next sample we need to pull */
6702 stream->sample_index += num_samples - 1;
6703 }
6704
6705 /* combine flows */
6706 GST_OBJECT_LOCK (qtdemux);
6707 ret = gst_qtdemux_combine_flows (qtdemux, stream, ret);
6708 GST_OBJECT_UNLOCK (qtdemux);
6709 /* ignore unlinked, we will not push on the pad anymore and we will EOS when
6710 * we have no more data for the pad to push */
6711 if (ret == GST_FLOW_EOS)
6712 ret = GST_FLOW_OK;
6713
6714 stream->offset_in_sample += size;
6715 if (stream->offset_in_sample >= sample_size) {
6716 gst_qtdemux_advance_sample (qtdemux, stream);
6717 }
6718 goto beach;
6719
6720 next:
6721 gst_qtdemux_advance_sample (qtdemux, stream);
6722
6723 beach:
6724 return ret;
6725
6726 /* special cases */
6727 eos:
6728 {
6729 GST_DEBUG_OBJECT (qtdemux, "No samples left for any streams - EOS");
6730 ret = GST_FLOW_EOS;
6731 goto beach;
6732 }
6733 eos_stream:
6734 {
6735 GST_DEBUG_OBJECT (qtdemux, "No samples left for stream");
6736 /* EOS will be raised if all are EOS */
6737 ret = GST_FLOW_OK;
6738 goto beach;
6739 }
6740 }
6741
6742 static void
gst_qtdemux_loop(GstPad * pad)6743 gst_qtdemux_loop (GstPad * pad)
6744 {
6745 GstQTDemux *qtdemux;
6746 guint64 cur_offset;
6747 GstFlowReturn ret;
6748
6749 qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
6750
6751 cur_offset = qtdemux->offset;
6752 GST_LOG_OBJECT (qtdemux, "loop at position %" G_GUINT64_FORMAT ", state %s",
6753 cur_offset, qt_demux_state_string (qtdemux->state));
6754
6755 switch (qtdemux->state) {
6756 case QTDEMUX_STATE_INITIAL:
6757 case QTDEMUX_STATE_HEADER:
6758 #ifdef OHOS_OPT_PERFORMANCE
6759 // ohos.opt.performance.0005
6760 // add trace
6761 {
6762 GstStartTrace("Qtdemux:state_header");
6763 ret = gst_qtdemux_loop_state_header (qtdemux);
6764 GstFinishTrace();
6765 }
6766 #else
6767 ret = gst_qtdemux_loop_state_header (qtdemux);
6768 #endif
6769 break;
6770 case QTDEMUX_STATE_MOVIE:
6771 ret = gst_qtdemux_loop_state_movie (qtdemux);
6772 if (qtdemux->segment.rate < 0 && ret == GST_FLOW_EOS) {
6773 ret = gst_qtdemux_seek_to_previous_keyframe (qtdemux);
6774 }
6775 break;
6776 default:
6777 /* ouch */
6778 goto invalid_state;
6779 }
6780
6781 /* if something went wrong, pause */
6782 if (ret != GST_FLOW_OK)
6783 goto pause;
6784
6785 done:
6786 gst_object_unref (qtdemux);
6787 return;
6788
6789 /* ERRORS */
6790 invalid_state:
6791 {
6792 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
6793 (NULL), ("streaming stopped, invalid state"));
6794 gst_pad_pause_task (pad);
6795 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
6796 goto done;
6797 }
6798 pause:
6799 {
6800 const gchar *reason = gst_flow_get_name (ret);
6801
6802 GST_LOG_OBJECT (qtdemux, "pausing task, reason %s", reason);
6803
6804 gst_pad_pause_task (pad);
6805
6806 /* fatal errors need special actions */
6807 /* check EOS */
6808 if (ret == GST_FLOW_EOS) {
6809 if (QTDEMUX_N_STREAMS (qtdemux) == 0) {
6810 /* we have no streams, post an error */
6811 gst_qtdemux_post_no_playable_stream_error (qtdemux);
6812 }
6813 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
6814 gint64 stop;
6815
6816 if ((stop = qtdemux->segment.stop) == -1)
6817 stop = qtdemux->segment.duration;
6818
6819 if (qtdemux->segment.rate >= 0) {
6820 GstMessage *message;
6821 GstEvent *event;
6822
6823 GST_LOG_OBJECT (qtdemux, "Sending segment done, at end of segment");
6824 message = gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
6825 GST_FORMAT_TIME, stop);
6826 event = gst_event_new_segment_done (GST_FORMAT_TIME, stop);
6827 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID) {
6828 gst_message_set_seqnum (message, qtdemux->segment_seqnum);
6829 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
6830 }
6831 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), message);
6832 gst_qtdemux_push_event (qtdemux, event);
6833 } else {
6834 GstMessage *message;
6835 GstEvent *event;
6836
6837 /* For Reverse Playback */
6838 GST_LOG_OBJECT (qtdemux, "Sending segment done, at start of segment");
6839 message = gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
6840 GST_FORMAT_TIME, qtdemux->segment.start);
6841 event = gst_event_new_segment_done (GST_FORMAT_TIME,
6842 qtdemux->segment.start);
6843 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID) {
6844 gst_message_set_seqnum (message, qtdemux->segment_seqnum);
6845 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
6846 }
6847 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), message);
6848 gst_qtdemux_push_event (qtdemux, event);
6849 }
6850 } else {
6851 GstEvent *event;
6852
6853 GST_LOG_OBJECT (qtdemux, "Sending EOS at end of segment");
6854 event = gst_event_new_eos ();
6855 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID)
6856 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
6857 gst_qtdemux_push_event (qtdemux, event);
6858 }
6859 } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
6860 GST_ELEMENT_FLOW_ERROR (qtdemux, ret);
6861 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
6862 }
6863 goto done;
6864 }
6865 }
6866
6867 /*
6868 * has_next_entry
6869 *
6870 * Returns if there are samples to be played.
6871 */
6872 static gboolean
has_next_entry(GstQTDemux * demux)6873 has_next_entry (GstQTDemux * demux)
6874 {
6875 QtDemuxStream *stream;
6876 gint i;
6877
6878 GST_DEBUG_OBJECT (demux, "Checking if there are samples not played yet");
6879
6880 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
6881 stream = QTDEMUX_NTH_STREAM (demux, i);
6882
6883 if (stream->sample_index == -1) {
6884 stream->sample_index = 0;
6885 stream->offset_in_sample = 0;
6886 }
6887
6888 if (stream->sample_index >= stream->n_samples) {
6889 GST_LOG_OBJECT (demux, "track-id %u samples exhausted", stream->track_id);
6890 continue;
6891 }
6892 GST_DEBUG_OBJECT (demux, "Found a sample");
6893 return TRUE;
6894 }
6895
6896 GST_DEBUG_OBJECT (demux, "There wasn't any next sample");
6897 return FALSE;
6898 }
6899
6900 /*
6901 * next_entry_size
6902 *
6903 * Returns the size of the first entry at the current offset.
6904 * If -1, there are none (which means EOS or empty file).
6905 */
6906 static guint64
next_entry_size(GstQTDemux * demux)6907 next_entry_size (GstQTDemux * demux)
6908 {
6909 QtDemuxStream *stream, *target_stream = NULL;
6910 guint64 smalloffs = (guint64) - 1;
6911 QtDemuxSample *sample;
6912 gint i;
6913
6914 GST_LOG_OBJECT (demux, "Finding entry at offset %" G_GUINT64_FORMAT,
6915 demux->offset);
6916
6917 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
6918 stream = QTDEMUX_NTH_STREAM (demux, i);
6919
6920 if (stream->sample_index == -1) {
6921 stream->sample_index = 0;
6922 stream->offset_in_sample = 0;
6923 }
6924
6925 if (stream->sample_index >= stream->n_samples) {
6926 GST_LOG_OBJECT (demux, "track-id %u samples exhausted", stream->track_id);
6927 continue;
6928 }
6929
6930 if (!qtdemux_parse_samples (demux, stream, stream->sample_index)) {
6931 GST_LOG_OBJECT (demux, "Parsing of index %u from stbl atom failed!",
6932 stream->sample_index);
6933 return -1;
6934 }
6935
6936 sample = &stream->samples[stream->sample_index];
6937
6938 GST_LOG_OBJECT (demux,
6939 "Checking track-id %u (sample_index:%d / offset:%" G_GUINT64_FORMAT
6940 " / size:%" G_GUINT32_FORMAT ")", stream->track_id,
6941 stream->sample_index, sample->offset, sample->size);
6942
6943 if (((smalloffs == -1)
6944 || (sample->offset < smalloffs)) && (sample->size)) {
6945 smalloffs = sample->offset;
6946 target_stream = stream;
6947 }
6948 }
6949
6950 if (!target_stream)
6951 return -1;
6952
6953 GST_LOG_OBJECT (demux,
6954 "track-id %u offset %" G_GUINT64_FORMAT " demux->offset :%"
6955 G_GUINT64_FORMAT, target_stream->track_id, smalloffs, demux->offset);
6956
6957 stream = target_stream;
6958 sample = &stream->samples[stream->sample_index];
6959
6960 if (sample->offset >= demux->offset) {
6961 demux->todrop = sample->offset - demux->offset;
6962 return sample->size + demux->todrop;
6963 }
6964
6965 GST_DEBUG_OBJECT (demux,
6966 "There wasn't any entry at offset %" G_GUINT64_FORMAT, demux->offset);
6967 return -1;
6968 }
6969
6970 static void
gst_qtdemux_post_progress(GstQTDemux * demux,gint num,gint denom)6971 gst_qtdemux_post_progress (GstQTDemux * demux, gint num, gint denom)
6972 {
6973 gint perc = (gint) ((gdouble) num * 100.0 / (gdouble) denom);
6974
6975 gst_element_post_message (GST_ELEMENT_CAST (demux),
6976 gst_message_new_element (GST_OBJECT_CAST (demux),
6977 gst_structure_new ("progress", "percent", G_TYPE_INT, perc, NULL)));
6978 }
6979
6980 static gboolean
qtdemux_seek_offset(GstQTDemux * demux,guint64 offset)6981 qtdemux_seek_offset (GstQTDemux * demux, guint64 offset)
6982 {
6983 GstEvent *event;
6984 gboolean res = 0;
6985
6986 GST_DEBUG_OBJECT (demux, "Seeking to %" G_GUINT64_FORMAT, offset);
6987
6988 event =
6989 gst_event_new_seek (1.0, GST_FORMAT_BYTES,
6990 GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset,
6991 GST_SEEK_TYPE_NONE, -1);
6992
6993 /* store seqnum to drop flush events, they don't need to reach downstream */
6994 demux->offset_seek_seqnum = gst_event_get_seqnum (event);
6995 res = gst_pad_push_event (demux->sinkpad, event);
6996 demux->offset_seek_seqnum = GST_SEQNUM_INVALID;
6997
6998 return res;
6999 }
7000
7001 /* check for seekable upstream, above and beyond a mere query */
7002 static void
gst_qtdemux_check_seekability(GstQTDemux * demux)7003 gst_qtdemux_check_seekability (GstQTDemux * demux)
7004 {
7005 GstQuery *query;
7006 gboolean seekable = FALSE;
7007 gint64 start = -1, stop = -1;
7008
7009 if (demux->upstream_size)
7010 return;
7011
7012 if (demux->upstream_format_is_time)
7013 return;
7014
7015 query = gst_query_new_seeking (GST_FORMAT_BYTES);
7016 if (!gst_pad_peer_query (demux->sinkpad, query)) {
7017 GST_DEBUG_OBJECT (demux, "seeking query failed");
7018 goto done;
7019 }
7020
7021 gst_query_parse_seeking (query, NULL, &seekable, &start, &stop);
7022
7023 /* try harder to query upstream size if we didn't get it the first time */
7024 if (seekable && stop == -1) {
7025 GST_DEBUG_OBJECT (demux, "doing duration query to fix up unset stop");
7026 gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &stop);
7027 }
7028
7029 /* if upstream doesn't know the size, it's likely that it's not seekable in
7030 * practice even if it technically may be seekable */
7031 if (seekable && (start != 0 || stop <= start)) {
7032 GST_DEBUG_OBJECT (demux, "seekable but unknown start/stop -> disable");
7033 seekable = FALSE;
7034 }
7035
7036 done:
7037 gst_query_unref (query);
7038
7039 GST_DEBUG_OBJECT (demux, "seekable: %d (%" G_GUINT64_FORMAT " - %"
7040 G_GUINT64_FORMAT ")", seekable, start, stop);
7041 demux->upstream_seekable = seekable;
7042 demux->upstream_size = seekable ? stop : -1;
7043 }
7044
7045 static void
gst_qtdemux_drop_data(GstQTDemux * demux,gint bytes)7046 gst_qtdemux_drop_data (GstQTDemux * demux, gint bytes)
7047 {
7048 g_return_if_fail (bytes <= demux->todrop);
7049
7050 GST_LOG_OBJECT (demux, "Dropping %d bytes", bytes);
7051 gst_adapter_flush (demux->adapter, bytes);
7052 demux->neededbytes -= bytes;
7053 demux->offset += bytes;
7054 demux->todrop -= bytes;
7055 }
7056
7057 /* PUSH-MODE only: Send a segment, if not done already. */
7058 static void
gst_qtdemux_check_send_pending_segment(GstQTDemux * demux)7059 gst_qtdemux_check_send_pending_segment (GstQTDemux * demux)
7060 {
7061 if (G_UNLIKELY (demux->need_segment)) {
7062 gint i;
7063
7064 if (!demux->upstream_format_is_time) {
7065 gst_qtdemux_map_and_push_segments (demux, &demux->segment);
7066 } else {
7067 GstEvent *segment_event;
7068 segment_event = gst_event_new_segment (&demux->segment);
7069 if (demux->segment_seqnum != GST_SEQNUM_INVALID)
7070 gst_event_set_seqnum (segment_event, demux->segment_seqnum);
7071 gst_qtdemux_push_event (demux, segment_event);
7072 }
7073
7074 demux->need_segment = FALSE;
7075
7076 /* clear to send tags on all streams */
7077 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
7078 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (demux, i);
7079 gst_qtdemux_push_tags (demux, stream);
7080 if (CUR_STREAM (stream)->sparse) {
7081 GST_INFO_OBJECT (demux, "Sending gap event on stream %d", i);
7082 gst_pad_push_event (stream->pad,
7083 gst_event_new_gap (stream->segment.position, GST_CLOCK_TIME_NONE));
7084 }
7085 }
7086 }
7087 }
7088
7089 /* Used for push mode only. */
7090 static void
gst_qtdemux_send_gap_for_segment(GstQTDemux * demux,QtDemuxStream * stream,gint segment_index,GstClockTime pos)7091 gst_qtdemux_send_gap_for_segment (GstQTDemux * demux,
7092 QtDemuxStream * stream, gint segment_index, GstClockTime pos)
7093 {
7094 GstClockTime ts, dur;
7095
7096 ts = pos;
7097 dur =
7098 stream->segments[segment_index].duration - (pos -
7099 stream->segments[segment_index].time);
7100 stream->time_position += dur;
7101
7102 /* Only gaps with a duration of at least one second are propagated.
7103 * Same workaround as in pull mode.
7104 * (See 2e45926a96ec5298c6ef29bf912e5e6a06dc3e0e) */
7105 if (dur >= GST_SECOND) {
7106 GstEvent *gap;
7107 gap = gst_event_new_gap (ts, dur);
7108
7109 GST_DEBUG_OBJECT (stream->pad, "Pushing gap for empty "
7110 "segment: %" GST_PTR_FORMAT, gap);
7111 gst_pad_push_event (stream->pad, gap);
7112 }
7113 }
7114
7115 static GstFlowReturn
gst_qtdemux_chain(GstPad * sinkpad,GstObject * parent,GstBuffer * inbuf)7116 gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent, GstBuffer * inbuf)
7117 {
7118 GstQTDemux *demux;
7119
7120 demux = GST_QTDEMUX (parent);
7121
7122 GST_DEBUG_OBJECT (demux,
7123 "Received buffer pts:%" GST_TIME_FORMAT " dts:%" GST_TIME_FORMAT
7124 " offset:%" G_GUINT64_FORMAT " size:%" G_GSIZE_FORMAT " demux offset:%"
7125 G_GUINT64_FORMAT, GST_TIME_ARGS (GST_BUFFER_PTS (inbuf)),
7126 GST_TIME_ARGS (GST_BUFFER_DTS (inbuf)), GST_BUFFER_OFFSET (inbuf),
7127 gst_buffer_get_size (inbuf), demux->offset);
7128
7129 if (GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_DISCONT)) {
7130 gboolean is_gap_input = FALSE;
7131 gint i;
7132
7133 GST_DEBUG_OBJECT (demux, "Got DISCONT, marking all streams as DISCONT");
7134
7135 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
7136 QTDEMUX_NTH_STREAM (demux, i)->discont = TRUE;
7137 }
7138
7139 /* Check if we can land back on our feet in the case where upstream is
7140 * handling the seeking/pushing of samples with gaps in between (like
7141 * in the case of trick-mode DASH for example) */
7142 if (demux->upstream_format_is_time
7143 && GST_BUFFER_OFFSET (inbuf) != GST_BUFFER_OFFSET_NONE) {
7144 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
7145 guint32 res;
7146 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (demux, i);
7147 GST_LOG_OBJECT (demux,
7148 "track-id #%u , checking if offset %" G_GUINT64_FORMAT
7149 " is a sample start", stream->track_id, GST_BUFFER_OFFSET (inbuf));
7150 res =
7151 gst_qtdemux_find_index_for_given_media_offset_linear (demux,
7152 stream, GST_BUFFER_OFFSET (inbuf));
7153 if (res != -1) {
7154 QtDemuxSample *sample = &stream->samples[res];
7155 GST_LOG_OBJECT (demux,
7156 "Checking if sample %d from track-id %u is valid (offset:%"
7157 G_GUINT64_FORMAT " size:%" G_GUINT32_FORMAT ")", res,
7158 stream->track_id, sample->offset, sample->size);
7159 if (sample->offset == GST_BUFFER_OFFSET (inbuf)) {
7160 GST_LOG_OBJECT (demux,
7161 "new buffer corresponds to a valid sample : %" G_GUINT32_FORMAT,
7162 res);
7163 is_gap_input = TRUE;
7164 /* We can go back to standard playback mode */
7165 demux->state = QTDEMUX_STATE_MOVIE;
7166 /* Remember which sample this stream is at */
7167 stream->sample_index = res;
7168 /* Finally update all push-based values to the expected values */
7169 demux->neededbytes = stream->samples[res].size;
7170 demux->offset = GST_BUFFER_OFFSET (inbuf);
7171 demux->mdatleft =
7172 demux->mdatsize - demux->offset + demux->mdatoffset;
7173 demux->todrop = 0;
7174 }
7175 }
7176 }
7177 if (!is_gap_input) {
7178 GST_DEBUG_OBJECT (demux, "Resetting, actual DISCONT");
7179 /* Reset state if it's a real discont */
7180 demux->neededbytes = 16;
7181 demux->state = QTDEMUX_STATE_INITIAL;
7182 demux->offset = GST_BUFFER_OFFSET (inbuf);
7183 gst_adapter_clear (demux->adapter);
7184 }
7185 }
7186 /* Reverse fragmented playback, need to flush all we have before
7187 * consuming a new fragment.
7188 * The samples array have the timestamps calculated by accumulating the
7189 * durations but this won't work for reverse playback of fragments as
7190 * the timestamps of a subsequent fragment should be smaller than the
7191 * previously received one. */
7192 if (!is_gap_input && demux->fragmented && demux->segment.rate < 0) {
7193 gst_qtdemux_process_adapter (demux, TRUE);
7194 g_ptr_array_foreach (demux->active_streams,
7195 (GFunc) gst_qtdemux_stream_flush_samples_data, NULL);
7196 }
7197 }
7198
7199 gst_adapter_push (demux->adapter, inbuf);
7200
7201 GST_DEBUG_OBJECT (demux,
7202 "pushing in inbuf %p, neededbytes:%u, available:%" G_GSIZE_FORMAT, inbuf,
7203 demux->neededbytes, gst_adapter_available (demux->adapter));
7204
7205 return gst_qtdemux_process_adapter (demux, FALSE);
7206 }
7207
7208 static GstFlowReturn
gst_qtdemux_process_adapter(GstQTDemux * demux,gboolean force)7209 gst_qtdemux_process_adapter (GstQTDemux * demux, gboolean force)
7210 {
7211 GstFlowReturn ret = GST_FLOW_OK;
7212
7213 /* we never really mean to buffer that much */
7214 if (demux->neededbytes == -1) {
7215 goto eos;
7216 }
7217
7218 while (((gst_adapter_available (demux->adapter)) >= demux->neededbytes) &&
7219 (ret == GST_FLOW_OK || (ret == GST_FLOW_NOT_LINKED && force))) {
7220
7221 #ifndef GST_DISABLE_GST_DEBUG
7222 {
7223 guint64 discont_offset, distance_from_discont;
7224
7225 discont_offset = gst_adapter_offset_at_discont (demux->adapter);
7226 distance_from_discont =
7227 gst_adapter_distance_from_discont (demux->adapter);
7228
7229 GST_DEBUG_OBJECT (demux,
7230 "state:%s , demux->neededbytes:%d, demux->offset:%" G_GUINT64_FORMAT
7231 " adapter offset :%" G_GUINT64_FORMAT " (+ %" G_GUINT64_FORMAT
7232 " bytes)", qt_demux_state_string (demux->state), demux->neededbytes,
7233 demux->offset, discont_offset, distance_from_discont);
7234 }
7235 #endif
7236
7237 switch (demux->state) {
7238 case QTDEMUX_STATE_INITIAL:{
7239 const guint8 *data;
7240 guint32 fourcc;
7241 guint64 size;
7242
7243 gst_qtdemux_check_seekability (demux);
7244
7245 data = gst_adapter_map (demux->adapter, demux->neededbytes);
7246
7247 /* get fourcc/length, set neededbytes */
7248 extract_initial_length_and_fourcc ((guint8 *) data, demux->neededbytes,
7249 &size, &fourcc);
7250 gst_adapter_unmap (demux->adapter);
7251 data = NULL;
7252 GST_DEBUG_OBJECT (demux, "Peeking found [%" GST_FOURCC_FORMAT "] "
7253 "size: %" G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), size);
7254 if (size == 0) {
7255 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
7256 (_("This file is invalid and cannot be played.")),
7257 ("initial atom '%" GST_FOURCC_FORMAT "' has empty length",
7258 GST_FOURCC_ARGS (fourcc)));
7259 ret = GST_FLOW_ERROR;
7260 break;
7261 }
7262 if (fourcc == FOURCC_mdat) {
7263 gint next_entry = next_entry_size (demux);
7264 if (QTDEMUX_N_STREAMS (demux) > 0 && (next_entry != -1
7265 || !demux->fragmented)) {
7266 /* we have the headers, start playback */
7267 demux->state = QTDEMUX_STATE_MOVIE;
7268 demux->neededbytes = next_entry;
7269 demux->mdatleft = size;
7270 demux->mdatsize = demux->mdatleft;
7271 } else {
7272 /* no headers yet, try to get them */
7273 guint bs;
7274 gboolean res;
7275 guint64 old, target;
7276
7277 buffer_data:
7278 old = demux->offset;
7279 target = old + size;
7280
7281 /* try to jump over the atom with a seek */
7282 /* only bother if it seems worth doing so,
7283 * and avoids possible upstream/server problems */
7284 if (demux->upstream_seekable &&
7285 demux->upstream_size > 4 * (1 << 20)) {
7286 res = qtdemux_seek_offset (demux, target);
7287 } else {
7288 GST_DEBUG_OBJECT (demux, "skipping seek");
7289 res = FALSE;
7290 }
7291
7292 if (res) {
7293 GST_DEBUG_OBJECT (demux, "seek success");
7294 /* remember the offset fo the first mdat so we can seek back to it
7295 * after we have the headers */
7296 if (fourcc == FOURCC_mdat && demux->first_mdat == -1) {
7297 demux->first_mdat = old;
7298 GST_DEBUG_OBJECT (demux, "first mdat at %" G_GUINT64_FORMAT,
7299 demux->first_mdat);
7300 }
7301 /* seek worked, continue reading */
7302 demux->offset = target;
7303 demux->neededbytes = 16;
7304 demux->state = QTDEMUX_STATE_INITIAL;
7305 } else {
7306 /* seek failed, need to buffer */
7307 demux->offset = old;
7308 GST_DEBUG_OBJECT (demux, "seek failed/skipped");
7309 /* there may be multiple mdat (or alike) buffers */
7310 /* sanity check */
7311 if (demux->mdatbuffer)
7312 bs = gst_buffer_get_size (demux->mdatbuffer);
7313 else
7314 bs = 0;
7315 if (size + bs > 10 * (1 << 20))
7316 goto no_moov;
7317 demux->state = QTDEMUX_STATE_BUFFER_MDAT;
7318 demux->neededbytes = size;
7319 if (!demux->mdatbuffer)
7320 demux->mdatoffset = demux->offset;
7321 }
7322 }
7323 } else if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
7324 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
7325 (_("This file is invalid and cannot be played.")),
7326 ("atom %" GST_FOURCC_FORMAT " has bogus size %" G_GUINT64_FORMAT,
7327 GST_FOURCC_ARGS (fourcc), size));
7328 ret = GST_FLOW_ERROR;
7329 break;
7330 } else {
7331 /* this means we already started buffering and still no moov header,
7332 * let's continue buffering everything till we get moov */
7333 if (demux->mdatbuffer && !(fourcc == FOURCC_moov
7334 || fourcc == FOURCC_moof))
7335 goto buffer_data;
7336 demux->neededbytes = size;
7337 demux->state = QTDEMUX_STATE_HEADER;
7338 }
7339 break;
7340 }
7341 case QTDEMUX_STATE_HEADER:{
7342 const guint8 *data;
7343 guint32 fourcc;
7344
7345 GST_DEBUG_OBJECT (demux, "In header");
7346
7347 data = gst_adapter_map (demux->adapter, demux->neededbytes);
7348
7349 /* parse the header */
7350 extract_initial_length_and_fourcc (data, demux->neededbytes, NULL,
7351 &fourcc);
7352 if (fourcc == FOURCC_moov) {
7353 /* in usual fragmented setup we could try to scan for more
7354 * and end up at the the moov (after mdat) again */
7355 if (demux->got_moov && QTDEMUX_N_STREAMS (demux) > 0 &&
7356 (!demux->fragmented
7357 || demux->last_moov_offset == demux->offset)) {
7358 GST_DEBUG_OBJECT (demux,
7359 "Skipping moov atom as we have (this) one already");
7360 } else {
7361 GST_DEBUG_OBJECT (demux, "Parsing [moov]");
7362
7363 if (demux->got_moov && demux->fragmented) {
7364 GST_DEBUG_OBJECT (demux,
7365 "Got a second moov, clean up data from old one");
7366 if (demux->moov_node_compressed) {
7367 g_node_destroy (demux->moov_node_compressed);
7368 if (demux->moov_node)
7369 g_free (demux->moov_node->data);
7370 }
7371 demux->moov_node_compressed = NULL;
7372 if (demux->moov_node)
7373 g_node_destroy (demux->moov_node);
7374 demux->moov_node = NULL;
7375 }
7376
7377 demux->last_moov_offset = demux->offset;
7378
7379 /* Update streams with new moov */
7380 gst_qtdemux_stream_concat (demux,
7381 demux->old_streams, demux->active_streams);
7382
7383 qtdemux_parse_moov (demux, data, demux->neededbytes);
7384 qtdemux_node_dump (demux, demux->moov_node);
7385 qtdemux_parse_tree (demux);
7386 qtdemux_prepare_streams (demux);
7387 QTDEMUX_EXPOSE_LOCK (demux);
7388 qtdemux_expose_streams (demux);
7389 QTDEMUX_EXPOSE_UNLOCK (demux);
7390
7391 demux->got_moov = TRUE;
7392
7393 gst_qtdemux_check_send_pending_segment (demux);
7394
7395 if (demux->moov_node_compressed) {
7396 g_node_destroy (demux->moov_node_compressed);
7397 g_free (demux->moov_node->data);
7398 }
7399 demux->moov_node_compressed = NULL;
7400 g_node_destroy (demux->moov_node);
7401 demux->moov_node = NULL;
7402 GST_DEBUG_OBJECT (demux, "Finished parsing the header");
7403 }
7404 } else if (fourcc == FOURCC_moof) {
7405 if ((demux->got_moov || demux->media_caps) && demux->fragmented) {
7406 guint64 dist = 0;
7407 GstClockTime prev_pts;
7408 guint64 prev_offset;
7409 guint64 adapter_discont_offset, adapter_discont_dist;
7410
7411 GST_DEBUG_OBJECT (demux, "Parsing [moof]");
7412
7413 /*
7414 * The timestamp of the moof buffer is relevant as some scenarios
7415 * won't have the initial timestamp in the atoms. Whenever a new
7416 * buffer has started, we get that buffer's PTS and use it as a base
7417 * timestamp for the trun entries.
7418 *
7419 * To keep track of the current buffer timestamp and starting point
7420 * we use gst_adapter_prev_pts that gives us the PTS and the distance
7421 * from the beginning of the buffer, with the distance and demux->offset
7422 * we know if it is still the same buffer or not.
7423 */
7424 prev_pts = gst_adapter_prev_pts (demux->adapter, &dist);
7425 prev_offset = demux->offset - dist;
7426 if (demux->fragment_start_offset == -1
7427 || prev_offset > demux->fragment_start_offset) {
7428 demux->fragment_start_offset = prev_offset;
7429 demux->fragment_start = prev_pts;
7430 GST_DEBUG_OBJECT (demux,
7431 "New fragment start found at: %" G_GUINT64_FORMAT " : %"
7432 GST_TIME_FORMAT, demux->fragment_start_offset,
7433 GST_TIME_ARGS (demux->fragment_start));
7434 }
7435
7436 /* We can't use prev_offset() here because this would require
7437 * upstream to set consistent and correct offsets on all buffers
7438 * since the discont. Nothing ever did that in the past and we
7439 * would break backwards compatibility here then.
7440 * Instead take the offset we had at the last discont and count
7441 * the bytes from there. This works with old code as there would
7442 * be no discont between moov and moof, and also works with
7443 * adaptivedemux which correctly sets offset and will set the
7444 * DISCONT flag accordingly when needed.
7445 *
7446 * We also only do this for upstream TIME segments as otherwise
7447 * there are potential backwards compatibility problems with
7448 * seeking in PUSH mode and upstream providing inconsistent
7449 * timestamps. */
7450 adapter_discont_offset =
7451 gst_adapter_offset_at_discont (demux->adapter);
7452 adapter_discont_dist =
7453 gst_adapter_distance_from_discont (demux->adapter);
7454
7455 GST_DEBUG_OBJECT (demux,
7456 "demux offset %" G_GUINT64_FORMAT " adapter offset %"
7457 G_GUINT64_FORMAT " (+ %" G_GUINT64_FORMAT " bytes)",
7458 demux->offset, adapter_discont_offset, adapter_discont_dist);
7459
7460 if (demux->upstream_format_is_time) {
7461 demux->moof_offset = adapter_discont_offset;
7462 if (demux->moof_offset != GST_BUFFER_OFFSET_NONE)
7463 demux->moof_offset += adapter_discont_dist;
7464 if (demux->moof_offset == GST_BUFFER_OFFSET_NONE)
7465 demux->moof_offset = demux->offset;
7466 } else {
7467 demux->moof_offset = demux->offset;
7468 }
7469
7470 if (!qtdemux_parse_moof (demux, data, demux->neededbytes,
7471 demux->moof_offset, NULL)) {
7472 gst_adapter_unmap (demux->adapter);
7473 ret = GST_FLOW_ERROR;
7474 goto done;
7475 }
7476
7477 /* in MSS we need to expose the pads after the first moof as we won't get a moov */
7478 if (demux->mss_mode && !demux->exposed) {
7479 QTDEMUX_EXPOSE_LOCK (demux);
7480 qtdemux_expose_streams (demux);
7481 QTDEMUX_EXPOSE_UNLOCK (demux);
7482 }
7483
7484 gst_qtdemux_check_send_pending_segment (demux);
7485 } else {
7486 GST_DEBUG_OBJECT (demux, "Discarding [moof]");
7487 }
7488 } else if (fourcc == FOURCC_ftyp) {
7489 GST_DEBUG_OBJECT (demux, "Parsing [ftyp]");
7490 qtdemux_parse_ftyp (demux, data, demux->neededbytes);
7491 } else if (fourcc == FOURCC_uuid) {
7492 GST_DEBUG_OBJECT (demux, "Parsing [uuid]");
7493 qtdemux_parse_uuid (demux, data, demux->neededbytes);
7494 } else if (fourcc == FOURCC_sidx) {
7495 GST_DEBUG_OBJECT (demux, "Parsing [sidx]");
7496 qtdemux_parse_sidx (demux, data, demux->neededbytes);
7497 } else {
7498 switch (fourcc) {
7499 case FOURCC_styp:
7500 /* [styp] is like a [ftyp], but in fragment header. We ignore it for now
7501 * FALLTHROUGH */
7502 case FOURCC_skip:
7503 case FOURCC_free:
7504 /* [free] and [skip] are padding atoms */
7505 GST_DEBUG_OBJECT (demux,
7506 "Skipping fourcc while parsing header : %" GST_FOURCC_FORMAT,
7507 GST_FOURCC_ARGS (fourcc));
7508 break;
7509 default:
7510 GST_WARNING_OBJECT (demux,
7511 "Unknown fourcc while parsing header : %" GST_FOURCC_FORMAT,
7512 GST_FOURCC_ARGS (fourcc));
7513 /* Let's jump that one and go back to initial state */
7514 break;
7515 }
7516 }
7517 gst_adapter_unmap (demux->adapter);
7518 data = NULL;
7519
7520 if (demux->mdatbuffer && QTDEMUX_N_STREAMS (demux)) {
7521 gsize remaining_data_size = 0;
7522
7523 /* the mdat was before the header */
7524 GST_DEBUG_OBJECT (demux, "We have n_streams:%d and mdatbuffer:%p",
7525 QTDEMUX_N_STREAMS (demux), demux->mdatbuffer);
7526 /* restore our adapter/offset view of things with upstream;
7527 * put preceding buffered data ahead of current moov data.
7528 * This should also handle evil mdat, moov, mdat cases and alike */
7529 gst_adapter_flush (demux->adapter, demux->neededbytes);
7530
7531 /* Store any remaining data after the mdat for later usage */
7532 remaining_data_size = gst_adapter_available (demux->adapter);
7533 if (remaining_data_size > 0) {
7534 g_assert (demux->restoredata_buffer == NULL);
7535 demux->restoredata_buffer =
7536 gst_adapter_take_buffer (demux->adapter, remaining_data_size);
7537 demux->restoredata_offset = demux->offset + demux->neededbytes;
7538 GST_DEBUG_OBJECT (demux,
7539 "Stored %" G_GSIZE_FORMAT " post mdat bytes at offset %"
7540 G_GUINT64_FORMAT, remaining_data_size,
7541 demux->restoredata_offset);
7542 }
7543
7544 gst_adapter_push (demux->adapter, demux->mdatbuffer);
7545 demux->mdatbuffer = NULL;
7546 demux->offset = demux->mdatoffset;
7547 demux->neededbytes = next_entry_size (demux);
7548 demux->state = QTDEMUX_STATE_MOVIE;
7549 demux->mdatleft = gst_adapter_available (demux->adapter);
7550 demux->mdatsize = demux->mdatleft;
7551 } else {
7552 GST_DEBUG_OBJECT (demux, "Carrying on normally");
7553 gst_adapter_flush (demux->adapter, demux->neededbytes);
7554
7555 /* only go back to the mdat if there are samples to play */
7556 if (demux->got_moov && demux->first_mdat != -1
7557 && has_next_entry (demux)) {
7558 gboolean res;
7559
7560 /* we need to seek back */
7561 res = qtdemux_seek_offset (demux, demux->first_mdat);
7562 if (res) {
7563 demux->offset = demux->first_mdat;
7564 } else {
7565 GST_DEBUG_OBJECT (demux, "Seek back failed");
7566 }
7567 } else {
7568 demux->offset += demux->neededbytes;
7569 }
7570 demux->neededbytes = 16;
7571 demux->state = QTDEMUX_STATE_INITIAL;
7572 }
7573
7574 break;
7575 }
7576 case QTDEMUX_STATE_BUFFER_MDAT:{
7577 GstBuffer *buf;
7578 guint8 fourcc[4];
7579
7580 GST_DEBUG_OBJECT (demux, "Got our buffer at offset %" G_GUINT64_FORMAT,
7581 demux->offset);
7582 buf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
7583 gst_buffer_extract (buf, 0, fourcc, 4);
7584 GST_DEBUG_OBJECT (demux, "mdatbuffer starts with %" GST_FOURCC_FORMAT,
7585 GST_FOURCC_ARGS (QT_FOURCC (fourcc)));
7586 if (demux->mdatbuffer)
7587 demux->mdatbuffer = gst_buffer_append (demux->mdatbuffer, buf);
7588 else
7589 demux->mdatbuffer = buf;
7590 demux->offset += demux->neededbytes;
7591 demux->neededbytes = 16;
7592 demux->state = QTDEMUX_STATE_INITIAL;
7593 gst_qtdemux_post_progress (demux, 1, 1);
7594
7595 break;
7596 }
7597 case QTDEMUX_STATE_MOVIE:{
7598 QtDemuxStream *stream = NULL;
7599 QtDemuxSample *sample;
7600 GstClockTime dts, pts, duration;
7601 gboolean keyframe;
7602 gint i;
7603
7604 GST_DEBUG_OBJECT (demux,
7605 "BEGIN // in MOVIE for offset %" G_GUINT64_FORMAT, demux->offset);
7606
7607 if (demux->fragmented) {
7608 GST_DEBUG_OBJECT (demux, "mdat remaining %" G_GUINT64_FORMAT,
7609 demux->mdatleft);
7610 if (G_LIKELY (demux->todrop < demux->mdatleft)) {
7611 /* if needed data starts within this atom,
7612 * then it should not exceed this atom */
7613 if (G_UNLIKELY (demux->neededbytes > demux->mdatleft)) {
7614 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
7615 (_("This file is invalid and cannot be played.")),
7616 ("sample data crosses atom boundary"));
7617 ret = GST_FLOW_ERROR;
7618 break;
7619 }
7620 demux->mdatleft -= demux->neededbytes;
7621 } else {
7622 GST_DEBUG_OBJECT (demux, "data atom emptied; resuming atom scan");
7623 /* so we are dropping more than left in this atom */
7624 gst_qtdemux_drop_data (demux, demux->mdatleft);
7625 demux->mdatleft = 0;
7626
7627 /* need to resume atom parsing so we do not miss any other pieces */
7628 demux->state = QTDEMUX_STATE_INITIAL;
7629 demux->neededbytes = 16;
7630
7631 /* check if there was any stored post mdat data from previous buffers */
7632 if (demux->restoredata_buffer) {
7633 g_assert (gst_adapter_available (demux->adapter) == 0);
7634
7635 gst_adapter_push (demux->adapter, demux->restoredata_buffer);
7636 demux->restoredata_buffer = NULL;
7637 demux->offset = demux->restoredata_offset;
7638 }
7639
7640 break;
7641 }
7642 }
7643
7644 if (demux->todrop) {
7645 if (demux->cenc_aux_info_offset > 0) {
7646 GstByteReader br;
7647 const guint8 *data;
7648
7649 GST_DEBUG_OBJECT (demux, "parsing cenc auxiliary info");
7650 data = gst_adapter_map (demux->adapter, demux->todrop);
7651 gst_byte_reader_init (&br, data + 8, demux->todrop);
7652 if (!qtdemux_parse_cenc_aux_info (demux,
7653 QTDEMUX_NTH_STREAM (demux, 0), &br,
7654 demux->cenc_aux_info_sizes, demux->cenc_aux_sample_count)) {
7655 GST_ERROR_OBJECT (demux, "failed to parse cenc auxiliary info");
7656 ret = GST_FLOW_ERROR;
7657 gst_adapter_unmap (demux->adapter);
7658 g_free (demux->cenc_aux_info_sizes);
7659 demux->cenc_aux_info_sizes = NULL;
7660 goto done;
7661 }
7662 demux->cenc_aux_info_offset = 0;
7663 g_free (demux->cenc_aux_info_sizes);
7664 demux->cenc_aux_info_sizes = NULL;
7665 gst_adapter_unmap (demux->adapter);
7666 }
7667 gst_qtdemux_drop_data (demux, demux->todrop);
7668 }
7669
7670 /* first buffer? */
7671 /* initial newsegment sent here after having added pads,
7672 * possible others in sink_event */
7673 gst_qtdemux_check_send_pending_segment (demux);
7674
7675 /* Figure out which stream this packet belongs to */
7676 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
7677 stream = QTDEMUX_NTH_STREAM (demux, i);
7678 if (stream->sample_index >= stream->n_samples) {
7679 /* reset to be checked below G_UNLIKELY (stream == NULL) */
7680 stream = NULL;
7681 continue;
7682 }
7683 GST_LOG_OBJECT (demux,
7684 "Checking track-id %u (sample_index:%d / offset:%"
7685 G_GUINT64_FORMAT " / size:%d)", stream->track_id,
7686 stream->sample_index,
7687 stream->samples[stream->sample_index].offset,
7688 stream->samples[stream->sample_index].size);
7689
7690 if (stream->samples[stream->sample_index].offset == demux->offset)
7691 break;
7692 }
7693
7694 if (G_UNLIKELY (stream == NULL))
7695 goto unknown_stream;
7696
7697 gst_qtdemux_stream_check_and_change_stsd_index (demux, stream);
7698
7699 if (stream->new_caps) {
7700 gst_qtdemux_configure_stream (demux, stream);
7701 }
7702
7703 /* Put data in a buffer, set timestamps, caps, ... */
7704 sample = &stream->samples[stream->sample_index];
7705
7706 if (G_LIKELY (!(STREAM_IS_EOS (stream)))) {
7707 GST_DEBUG_OBJECT (demux, "stream : %" GST_FOURCC_FORMAT,
7708 GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
7709
7710 dts = QTSAMPLE_DTS (stream, sample);
7711 pts = QTSAMPLE_PTS (stream, sample);
7712 duration = QTSAMPLE_DUR_DTS (stream, sample, dts);
7713 keyframe = QTSAMPLE_KEYFRAME (stream, sample);
7714
7715 /* check for segment end */
7716 if (G_UNLIKELY (demux->segment.stop != -1
7717 && demux->segment.stop <= pts && stream->on_keyframe)
7718 && !(demux->upstream_format_is_time && demux->segment.rate < 0)) {
7719 GST_DEBUG_OBJECT (demux, "we reached the end of our segment.");
7720 stream->time_position = GST_CLOCK_TIME_NONE; /* this means EOS */
7721
7722 /* skip this data, stream is EOS */
7723 gst_adapter_flush (demux->adapter, demux->neededbytes);
7724 demux->offset += demux->neededbytes;
7725
7726 /* check if all streams are eos */
7727 ret = GST_FLOW_EOS;
7728 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
7729 if (!STREAM_IS_EOS (QTDEMUX_NTH_STREAM (demux, i))) {
7730 ret = GST_FLOW_OK;
7731 break;
7732 }
7733 }
7734 } else {
7735 GstBuffer *outbuf;
7736
7737 outbuf =
7738 gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
7739
7740 /* FIXME: should either be an assert or a plain check */
7741 g_return_val_if_fail (outbuf != NULL, GST_FLOW_ERROR);
7742
7743 ret = gst_qtdemux_decorate_and_push_buffer (demux, stream, outbuf,
7744 dts, pts, duration, keyframe, dts, demux->offset);
7745 }
7746
7747 /* combine flows */
7748 GST_OBJECT_LOCK (demux);
7749 ret = gst_qtdemux_combine_flows (demux, stream, ret);
7750 GST_OBJECT_UNLOCK (demux);
7751 } else {
7752 /* skip this data, stream is EOS */
7753 gst_adapter_flush (demux->adapter, demux->neededbytes);
7754 }
7755
7756 stream->sample_index++;
7757 stream->offset_in_sample = 0;
7758
7759 /* update current offset and figure out size of next buffer */
7760 GST_LOG_OBJECT (demux, "increasing offset %" G_GUINT64_FORMAT " by %u",
7761 demux->offset, demux->neededbytes);
7762 demux->offset += demux->neededbytes;
7763 GST_LOG_OBJECT (demux, "offset is now %" G_GUINT64_FORMAT,
7764 demux->offset);
7765
7766
7767 if (ret == GST_FLOW_EOS) {
7768 GST_DEBUG_OBJECT (demux, "All streams are EOS, signal upstream");
7769 demux->neededbytes = -1;
7770 goto eos;
7771 }
7772
7773 if ((demux->neededbytes = next_entry_size (demux)) == -1) {
7774 if (demux->fragmented) {
7775 GST_DEBUG_OBJECT (demux, "(temporarily) out of fragmented samples");
7776 /* there may be more to follow, only finish this atom */
7777 demux->todrop = demux->mdatleft;
7778 demux->neededbytes = demux->todrop;
7779 break;
7780 }
7781 goto eos;
7782 }
7783 if (ret != GST_FLOW_OK && ret != GST_FLOW_NOT_LINKED) {
7784 goto non_ok_unlinked_flow;
7785 }
7786 break;
7787 }
7788 default:
7789 goto invalid_state;
7790 }
7791 }
7792
7793 /* when buffering movie data, at least show user something is happening */
7794 if (ret == GST_FLOW_OK && demux->state == QTDEMUX_STATE_BUFFER_MDAT &&
7795 gst_adapter_available (demux->adapter) <= demux->neededbytes) {
7796 gst_qtdemux_post_progress (demux, gst_adapter_available (demux->adapter),
7797 demux->neededbytes);
7798 }
7799 done:
7800
7801 return ret;
7802
7803 /* ERRORS */
7804 non_ok_unlinked_flow:
7805 {
7806 GST_DEBUG_OBJECT (demux, "Stopping, combined return flow %s",
7807 gst_flow_get_name (ret));
7808 return ret;
7809 }
7810 unknown_stream:
7811 {
7812 GST_ELEMENT_ERROR (demux, STREAM, FAILED, (NULL), ("unknown stream found"));
7813 ret = GST_FLOW_ERROR;
7814 goto done;
7815 }
7816 eos:
7817 {
7818 GST_DEBUG_OBJECT (demux, "no next entry, EOS");
7819 ret = GST_FLOW_EOS;
7820 goto done;
7821 }
7822 invalid_state:
7823 {
7824 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
7825 (NULL), ("qtdemuxer invalid state %d", demux->state));
7826 ret = GST_FLOW_ERROR;
7827 goto done;
7828 }
7829 no_moov:
7830 {
7831 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
7832 (NULL), ("no 'moov' atom within the first 10 MB"));
7833 ret = GST_FLOW_ERROR;
7834 goto done;
7835 }
7836 }
7837
7838 static gboolean
qtdemux_sink_activate(GstPad * sinkpad,GstObject * parent)7839 qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent)
7840 {
7841 GstQuery *query;
7842 gboolean pull_mode;
7843
7844 query = gst_query_new_scheduling ();
7845
7846 if (!gst_pad_peer_query (sinkpad, query)) {
7847 gst_query_unref (query);
7848 goto activate_push;
7849 }
7850
7851 pull_mode = gst_query_has_scheduling_mode_with_flags (query,
7852 GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
7853 gst_query_unref (query);
7854
7855 if (!pull_mode)
7856 goto activate_push;
7857
7858 GST_DEBUG_OBJECT (sinkpad, "activating pull");
7859 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
7860
7861 activate_push:
7862 {
7863 GST_DEBUG_OBJECT (sinkpad, "activating push");
7864 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
7865 }
7866 }
7867
7868 static gboolean
qtdemux_sink_activate_mode(GstPad * sinkpad,GstObject * parent,GstPadMode mode,gboolean active)7869 qtdemux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
7870 GstPadMode mode, gboolean active)
7871 {
7872 gboolean res;
7873 GstQTDemux *demux = GST_QTDEMUX (parent);
7874
7875 switch (mode) {
7876 case GST_PAD_MODE_PUSH:
7877 demux->pullbased = FALSE;
7878 res = TRUE;
7879 break;
7880 case GST_PAD_MODE_PULL:
7881 if (active) {
7882 demux->pullbased = TRUE;
7883 res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_qtdemux_loop,
7884 sinkpad, NULL);
7885 } else {
7886 res = gst_pad_stop_task (sinkpad);
7887 }
7888 break;
7889 default:
7890 res = FALSE;
7891 break;
7892 }
7893 return res;
7894 }
7895
7896 #ifdef HAVE_ZLIB
7897 static void *
qtdemux_inflate(void * z_buffer,guint z_length,guint * length)7898 qtdemux_inflate (void *z_buffer, guint z_length, guint * length)
7899 {
7900 guint8 *buffer;
7901 z_stream z;
7902 int ret;
7903
7904 memset (&z, 0, sizeof (z));
7905 z.zalloc = NULL;
7906 z.zfree = NULL;
7907 z.opaque = NULL;
7908
7909 if ((ret = inflateInit (&z)) != Z_OK) {
7910 GST_ERROR ("inflateInit() returned %d", ret);
7911 return NULL;
7912 }
7913
7914 z.next_in = z_buffer;
7915 z.avail_in = z_length;
7916
7917 buffer = (guint8 *) g_malloc (*length);
7918 z.avail_out = *length;
7919 z.next_out = (Bytef *) buffer;
7920 do {
7921 ret = inflate (&z, Z_NO_FLUSH);
7922 if (ret == Z_STREAM_END) {
7923 break;
7924 } else if (ret != Z_OK) {
7925 GST_WARNING ("inflate() returned %d", ret);
7926 break;
7927 }
7928
7929 if (*length > G_MAXUINT - 4096 || *length > QTDEMUX_MAX_SAMPLE_INDEX_SIZE) {
7930 GST_WARNING ("too big decompressed data");
7931 ret = Z_MEM_ERROR;
7932 break;
7933 }
7934
7935 *length += 4096;
7936 buffer = (guint8 *) g_realloc (buffer, *length);
7937 z.next_out = (Bytef *) (buffer + z.total_out);
7938 z.avail_out += *length - z.total_out;
7939 } while (z.avail_in > 0);
7940
7941 if (ret != Z_STREAM_END) {
7942 g_free (buffer);
7943 buffer = NULL;
7944 *length = 0;
7945 } else {
7946 *length = z.total_out;
7947 }
7948
7949 inflateEnd (&z);
7950
7951 return buffer;
7952 }
7953 #endif /* HAVE_ZLIB */
7954
7955 static gboolean
qtdemux_parse_moov(GstQTDemux * qtdemux,const guint8 * buffer,guint length)7956 qtdemux_parse_moov (GstQTDemux * qtdemux, const guint8 * buffer, guint length)
7957 {
7958 GNode *cmov;
7959
7960 qtdemux->moov_node = g_node_new ((guint8 *) buffer);
7961
7962 /* counts as header data */
7963 qtdemux->header_size += length;
7964
7965 GST_DEBUG_OBJECT (qtdemux, "parsing 'moov' atom");
7966 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buffer, length);
7967
7968 cmov = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_cmov);
7969 if (cmov) {
7970 guint32 method;
7971 GNode *dcom;
7972 GNode *cmvd;
7973 guint32 dcom_len;
7974
7975 dcom = qtdemux_tree_get_child_by_type (cmov, FOURCC_dcom);
7976 cmvd = qtdemux_tree_get_child_by_type (cmov, FOURCC_cmvd);
7977 if (dcom == NULL || cmvd == NULL)
7978 goto invalid_compression;
7979
7980 dcom_len = QT_UINT32 (dcom->data);
7981 if (dcom_len < 12)
7982 goto invalid_compression;
7983
7984 method = QT_FOURCC ((guint8 *) dcom->data + 8);
7985 switch (method) {
7986 #ifdef HAVE_ZLIB
7987 case FOURCC_zlib:{
7988 guint uncompressed_length;
7989 guint compressed_length;
7990 guint8 *buf;
7991 guint32 cmvd_len;
7992
7993 cmvd_len = QT_UINT32 ((guint8 *) cmvd->data);
7994 if (cmvd_len < 12)
7995 goto invalid_compression;
7996
7997 uncompressed_length = QT_UINT32 ((guint8 *) cmvd->data + 8);
7998 compressed_length = cmvd_len - 12;
7999 GST_LOG ("length = %u", uncompressed_length);
8000
8001 buf =
8002 (guint8 *) qtdemux_inflate ((guint8 *) cmvd->data + 12,
8003 compressed_length, &uncompressed_length);
8004
8005 if (buf) {
8006 qtdemux->moov_node_compressed = qtdemux->moov_node;
8007 qtdemux->moov_node = g_node_new (buf);
8008
8009 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buf,
8010 uncompressed_length);
8011 }
8012 break;
8013 }
8014 #endif /* HAVE_ZLIB */
8015 default:
8016 GST_WARNING_OBJECT (qtdemux, "unknown or unhandled header compression "
8017 "type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (method));
8018 break;
8019 }
8020 }
8021 return TRUE;
8022
8023 /* ERRORS */
8024 invalid_compression:
8025 {
8026 GST_ERROR_OBJECT (qtdemux, "invalid compressed header");
8027 return FALSE;
8028 }
8029 }
8030
8031 static gboolean
qtdemux_parse_container(GstQTDemux * qtdemux,GNode * node,const guint8 * buf,const guint8 * end)8032 qtdemux_parse_container (GstQTDemux * qtdemux, GNode * node, const guint8 * buf,
8033 const guint8 * end)
8034 {
8035 while (G_UNLIKELY (buf < end)) {
8036 GNode *child;
8037 guint32 len;
8038
8039 if (G_UNLIKELY (buf + 4 > end)) {
8040 GST_LOG_OBJECT (qtdemux, "buffer overrun");
8041 break;
8042 }
8043 len = QT_UINT32 (buf);
8044 if (G_UNLIKELY (len == 0)) {
8045 GST_LOG_OBJECT (qtdemux, "empty container");
8046 break;
8047 }
8048 if (G_UNLIKELY (len < 8)) {
8049 GST_WARNING_OBJECT (qtdemux, "length too short (%d < 8)", len);
8050 break;
8051 }
8052 if (G_UNLIKELY (len > (end - buf))) {
8053 GST_WARNING_OBJECT (qtdemux, "length too long (%d > %d)", len,
8054 (gint) (end - buf));
8055 break;
8056 }
8057
8058 child = g_node_new ((guint8 *) buf);
8059 g_node_append (node, child);
8060 GST_LOG_OBJECT (qtdemux, "adding new node of len %d", len);
8061 qtdemux_parse_node (qtdemux, child, buf, len);
8062
8063 buf += len;
8064 }
8065 return TRUE;
8066 }
8067
8068 static gboolean
qtdemux_parse_theora_extension(GstQTDemux * qtdemux,QtDemuxStream * stream,GNode * xdxt)8069 qtdemux_parse_theora_extension (GstQTDemux * qtdemux, QtDemuxStream * stream,
8070 GNode * xdxt)
8071 {
8072 int len = QT_UINT32 (xdxt->data);
8073 guint8 *buf = xdxt->data;
8074 guint8 *end = buf + len;
8075 GstBuffer *buffer;
8076
8077 /* skip size and type */
8078 buf += 8;
8079 end -= 8;
8080
8081 while (buf < end) {
8082 gint size;
8083 guint32 type;
8084
8085 size = QT_UINT32 (buf);
8086 type = QT_FOURCC (buf + 4);
8087
8088 GST_LOG_OBJECT (qtdemux, "%p %p", buf, end);
8089
8090 if (buf + size > end || size <= 0)
8091 break;
8092
8093 buf += 8;
8094 size -= 8;
8095
8096 GST_WARNING_OBJECT (qtdemux, "have cookie %" GST_FOURCC_FORMAT,
8097 GST_FOURCC_ARGS (type));
8098
8099 switch (type) {
8100 case FOURCC_tCtH:
8101 buffer = gst_buffer_new_and_alloc (size);
8102 gst_buffer_fill (buffer, 0, buf, size);
8103 stream->buffers = g_slist_append (stream->buffers, buffer);
8104 GST_LOG_OBJECT (qtdemux, "parsing theora header");
8105 break;
8106 case FOURCC_tCt_:
8107 buffer = gst_buffer_new_and_alloc (size);
8108 gst_buffer_fill (buffer, 0, buf, size);
8109 stream->buffers = g_slist_append (stream->buffers, buffer);
8110 GST_LOG_OBJECT (qtdemux, "parsing theora comment");
8111 break;
8112 case FOURCC_tCtC:
8113 buffer = gst_buffer_new_and_alloc (size);
8114 gst_buffer_fill (buffer, 0, buf, size);
8115 stream->buffers = g_slist_append (stream->buffers, buffer);
8116 GST_LOG_OBJECT (qtdemux, "parsing theora codebook");
8117 break;
8118 default:
8119 GST_WARNING_OBJECT (qtdemux,
8120 "unknown theora cookie %" GST_FOURCC_FORMAT,
8121 GST_FOURCC_ARGS (type));
8122 break;
8123 }
8124 buf += size;
8125 }
8126 return TRUE;
8127 }
8128
8129 static gboolean
qtdemux_parse_node(GstQTDemux * qtdemux,GNode * node,const guint8 * buffer,guint length)8130 qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node, const guint8 * buffer,
8131 guint length)
8132 {
8133 guint32 fourcc = 0;
8134 guint32 node_length = 0;
8135 const QtNodeType *type;
8136 const guint8 *end;
8137
8138 GST_LOG_OBJECT (qtdemux, "qtdemux_parse buffer %p length %u", buffer, length);
8139
8140 if (G_UNLIKELY (length < 8))
8141 goto not_enough_data;
8142
8143 node_length = QT_UINT32 (buffer);
8144 fourcc = QT_FOURCC (buffer + 4);
8145
8146 /* ignore empty nodes */
8147 if (G_UNLIKELY (fourcc == 0 || node_length == 8))
8148 return TRUE;
8149
8150 type = qtdemux_type_get (fourcc);
8151
8152 end = buffer + length;
8153
8154 GST_LOG_OBJECT (qtdemux,
8155 "parsing '%" GST_FOURCC_FORMAT "', length=%u, name '%s'",
8156 GST_FOURCC_ARGS (fourcc), node_length, type->name);
8157
8158 if (node_length > length)
8159 goto broken_atom_size;
8160
8161 if (type->flags & QT_FLAG_CONTAINER) {
8162 qtdemux_parse_container (qtdemux, node, buffer + 8, end);
8163 } else {
8164 switch (fourcc) {
8165 case FOURCC_stsd:
8166 {
8167 if (node_length < 20) {
8168 GST_LOG_OBJECT (qtdemux, "skipping small stsd box");
8169 break;
8170 }
8171 GST_DEBUG_OBJECT (qtdemux,
8172 "parsing stsd (sample table, sample description) atom");
8173 /* Skip over 8 byte atom hdr + 1 byte version, 3 bytes flags, 4 byte num_entries */
8174 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
8175 break;
8176 }
8177 case FOURCC_mp4a:
8178 case FOURCC_alac:
8179 case FOURCC_fLaC:
8180 case FOURCC_aavd:
8181 {
8182 guint32 version;
8183 guint32 offset;
8184 guint min_size;
8185
8186 /* also read alac (or whatever) in stead of mp4a in the following,
8187 * since a similar layout is used in other cases as well */
8188 if (fourcc == FOURCC_mp4a)
8189 min_size = 20;
8190 else if (fourcc == FOURCC_fLaC)
8191 min_size = 86;
8192 else
8193 min_size = 40;
8194
8195 /* There are two things we might encounter here: a true mp4a atom, and
8196 an mp4a entry in an stsd atom. The latter is what we're interested
8197 in, and it looks like an atom, but isn't really one. The true mp4a
8198 atom is short, so we detect it based on length here. */
8199 if (length < min_size) {
8200 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
8201 GST_FOURCC_ARGS (fourcc));
8202 break;
8203 }
8204
8205 /* 'version' here is the sound sample description version. Types 0 and
8206 1 are documented in the QTFF reference, but type 2 is not: it's
8207 described in Apple header files instead (struct SoundDescriptionV2
8208 in Movies.h) */
8209 version = QT_UINT16 (buffer + 16);
8210
8211 GST_DEBUG_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT " version 0x%08x",
8212 GST_FOURCC_ARGS (fourcc), version);
8213
8214 /* parse any esds descriptors */
8215 switch (version) {
8216 case 0:
8217 offset = 0x24;
8218 break;
8219 case 1:
8220 offset = 0x34;
8221 break;
8222 case 2:
8223 offset = 0x48;
8224 break;
8225 default:
8226 GST_WARNING_OBJECT (qtdemux,
8227 "unhandled %" GST_FOURCC_FORMAT " version 0x%08x",
8228 GST_FOURCC_ARGS (fourcc), version);
8229 offset = 0;
8230 break;
8231 }
8232 if (offset)
8233 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
8234 break;
8235 }
8236 case FOURCC_mp4v:
8237 case FOURCC_MP4V:
8238 case FOURCC_fmp4:
8239 case FOURCC_FMP4:
8240 case FOURCC_apcs:
8241 case FOURCC_apch:
8242 case FOURCC_apcn:
8243 case FOURCC_apco:
8244 case FOURCC_ap4h:
8245 case FOURCC_xvid:
8246 case FOURCC_XVID:
8247 case FOURCC_H264:
8248 case FOURCC_avc1:
8249 case FOURCC_avc3:
8250 case FOURCC_H265:
8251 case FOURCC_hvc1:
8252 case FOURCC_hev1:
8253 case FOURCC_dvh1:
8254 case FOURCC_dvhe:
8255 case FOURCC_mjp2:
8256 case FOURCC_encv:
8257 {
8258 guint32 version;
8259 guint32 str_len;
8260
8261 /* codec_data is contained inside these atoms, which all have
8262 * the same format. */
8263 /* video sample description size is 86 bytes without extension.
8264 * node_length have to be bigger than 86 bytes because video sample
8265 * description can include extensions such as esds, fiel, glbl, etc. */
8266 if (node_length < 86) {
8267 GST_WARNING_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT
8268 " sample description length too short (%u < 86)",
8269 GST_FOURCC_ARGS (fourcc), node_length);
8270 break;
8271 }
8272
8273 GST_DEBUG_OBJECT (qtdemux, "parsing in %" GST_FOURCC_FORMAT,
8274 GST_FOURCC_ARGS (fourcc));
8275
8276 /* version (2 bytes) : this is set to 0, unless a compressor has changed
8277 * its data format.
8278 * revision level (2 bytes) : must be set to 0. */
8279 version = QT_UINT32 (buffer + 16);
8280 GST_DEBUG_OBJECT (qtdemux, "version %08x", version);
8281
8282 /* compressor name : PASCAL string and informative purposes
8283 * first byte : the number of bytes to be displayed.
8284 * it has to be less than 32 because it is reserved
8285 * space of 32 bytes total including itself. */
8286 str_len = QT_UINT8 (buffer + 50);
8287 if (str_len < 32)
8288 GST_DEBUG_OBJECT (qtdemux, "compressorname = %.*s", str_len,
8289 (char *) buffer + 51);
8290 else
8291 GST_WARNING_OBJECT (qtdemux,
8292 "compressorname length too big (%u > 31)", str_len);
8293
8294 GST_MEMDUMP_OBJECT (qtdemux, "video sample description", buffer,
8295 end - buffer);
8296 qtdemux_parse_container (qtdemux, node, buffer + 86, end);
8297 break;
8298 }
8299 case FOURCC_meta:
8300 {
8301 GST_DEBUG_OBJECT (qtdemux, "parsing meta atom");
8302
8303 /* You are reading this correctly. QTFF specifies that the
8304 * metadata atom is a short atom, whereas ISO BMFF specifies
8305 * it's a full atom. But since so many people are doing things
8306 * differently, we actually peek into the atom to see which
8307 * variant it is */
8308 if (length < 16) {
8309 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
8310 GST_FOURCC_ARGS (fourcc));
8311 break;
8312 }
8313 if (QT_FOURCC (buffer + 12) == FOURCC_hdlr) {
8314 /* Variant 1: What QTFF specifies. 'meta' is a short header which
8315 * starts with a 'hdlr' atom */
8316 qtdemux_parse_container (qtdemux, node, buffer + 8, end);
8317 } else if (QT_UINT32 (buffer + 8) == 0x00000000) {
8318 /* Variant 2: What ISO BMFF specifies. 'meta' is a _full_ atom
8319 * with version/flags both set to zero */
8320 qtdemux_parse_container (qtdemux, node, buffer + 12, end);
8321 } else
8322 GST_WARNING_OBJECT (qtdemux, "Unknown 'meta' atom format");
8323 break;
8324 }
8325 case FOURCC_mp4s:
8326 {
8327 GST_MEMDUMP_OBJECT (qtdemux, "mp4s", buffer, end - buffer);
8328 /* Skip 8 byte header, plus 8 byte version + flags + entry_count */
8329 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
8330 break;
8331 }
8332 case FOURCC_XiTh:
8333 {
8334 guint32 version;
8335 guint32 offset;
8336
8337 if (length < 16) {
8338 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
8339 GST_FOURCC_ARGS (fourcc));
8340 break;
8341 }
8342
8343 version = QT_UINT32 (buffer + 12);
8344 GST_DEBUG_OBJECT (qtdemux, "parsing XiTh atom version 0x%08x", version);
8345
8346 switch (version) {
8347 case 0x00000001:
8348 offset = 0x62;
8349 break;
8350 default:
8351 GST_DEBUG_OBJECT (qtdemux, "unknown version 0x%08x", version);
8352 offset = 0;
8353 break;
8354 }
8355 if (offset) {
8356 if (length < offset) {
8357 GST_WARNING_OBJECT (qtdemux,
8358 "skipping too small %" GST_FOURCC_FORMAT " box",
8359 GST_FOURCC_ARGS (fourcc));
8360 break;
8361 }
8362 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
8363 }
8364 break;
8365 }
8366 case FOURCC_in24:
8367 {
8368 qtdemux_parse_container (qtdemux, node, buffer + 0x34, end);
8369 break;
8370 }
8371 case FOURCC_uuid:
8372 {
8373 qtdemux_parse_uuid (qtdemux, buffer, end - buffer);
8374 break;
8375 }
8376 case FOURCC_enca:
8377 {
8378 qtdemux_parse_container (qtdemux, node, buffer + 36, end);
8379 break;
8380 }
8381 default:
8382 if (!strcmp (type->name, "unknown"))
8383 GST_MEMDUMP ("Unknown tag", buffer + 4, end - buffer - 4);
8384 break;
8385 }
8386 }
8387 GST_LOG_OBJECT (qtdemux, "parsed '%" GST_FOURCC_FORMAT "'",
8388 GST_FOURCC_ARGS (fourcc));
8389 return TRUE;
8390
8391 /* ERRORS */
8392 not_enough_data:
8393 {
8394 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8395 (_("This file is corrupt and cannot be played.")),
8396 ("Not enough data for an atom header, got only %u bytes", length));
8397 return FALSE;
8398 }
8399 broken_atom_size:
8400 {
8401 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8402 (_("This file is corrupt and cannot be played.")),
8403 ("Atom '%" GST_FOURCC_FORMAT "' has size of %u bytes, but we have only "
8404 "%u bytes available.", GST_FOURCC_ARGS (fourcc), node_length,
8405 length));
8406 return FALSE;
8407 }
8408 }
8409
8410 static void
qtdemux_do_allocation(QtDemuxStream * stream,GstQTDemux * qtdemux)8411 qtdemux_do_allocation (QtDemuxStream * stream, GstQTDemux * qtdemux)
8412 {
8413 /* FIXME: This can only reliably work if demuxers have a
8414 * separate streaming thread per srcpad. This should be
8415 * done in a demuxer base class, which integrates parts
8416 * of multiqueue
8417 *
8418 * https://bugzilla.gnome.org/show_bug.cgi?id=701856
8419 */
8420 #if 0
8421 GstQuery *query;
8422
8423 query = gst_query_new_allocation (stream->caps, FALSE);
8424
8425 if (!gst_pad_peer_query (stream->pad, query)) {
8426 /* not a problem, just debug a little */
8427 GST_DEBUG_OBJECT (qtdemux, "peer ALLOCATION query failed");
8428 }
8429
8430 if (stream->allocator)
8431 gst_object_unref (stream->allocator);
8432
8433 if (gst_query_get_n_allocation_params (query) > 0) {
8434 /* try the allocator */
8435 gst_query_parse_nth_allocation_param (query, 0, &stream->allocator,
8436 &stream->params);
8437 stream->use_allocator = TRUE;
8438 } else {
8439 stream->allocator = NULL;
8440 gst_allocation_params_init (&stream->params);
8441 stream->use_allocator = FALSE;
8442 }
8443 gst_query_unref (query);
8444 #endif
8445 }
8446
8447 static gboolean
pad_query(const GValue * item,GValue * value,gpointer user_data)8448 pad_query (const GValue * item, GValue * value, gpointer user_data)
8449 {
8450 GstPad *pad = g_value_get_object (item);
8451 GstQuery *query = user_data;
8452 gboolean res;
8453
8454 res = gst_pad_peer_query (pad, query);
8455
8456 if (res) {
8457 g_value_set_boolean (value, TRUE);
8458 return FALSE;
8459 }
8460
8461 GST_INFO_OBJECT (pad, "pad peer query failed");
8462 return TRUE;
8463 }
8464
8465 static gboolean
gst_qtdemux_run_query(GstElement * element,GstQuery * query,GstPadDirection direction)8466 gst_qtdemux_run_query (GstElement * element, GstQuery * query,
8467 GstPadDirection direction)
8468 {
8469 GstIterator *it;
8470 GstIteratorFoldFunction func = pad_query;
8471 GValue res = { 0, };
8472
8473 g_value_init (&res, G_TYPE_BOOLEAN);
8474 g_value_set_boolean (&res, FALSE);
8475
8476 /* Ask neighbor */
8477 if (direction == GST_PAD_SRC)
8478 it = gst_element_iterate_src_pads (element);
8479 else
8480 it = gst_element_iterate_sink_pads (element);
8481
8482 while (gst_iterator_fold (it, func, &res, query) == GST_ITERATOR_RESYNC)
8483 gst_iterator_resync (it);
8484
8485 gst_iterator_free (it);
8486
8487 return g_value_get_boolean (&res);
8488 }
8489
8490 static void
gst_qtdemux_request_protection_context(GstQTDemux * qtdemux,QtDemuxStream * stream)8491 gst_qtdemux_request_protection_context (GstQTDemux * qtdemux,
8492 QtDemuxStream * stream)
8493 {
8494 GstQuery *query;
8495 GstContext *ctxt;
8496 GstElement *element = GST_ELEMENT (qtdemux);
8497 GstStructure *st;
8498 gchar **filtered_sys_ids;
8499 GValue event_list = G_VALUE_INIT;
8500 GList *walk;
8501
8502 /* 1. Check if we already have the context. */
8503 if (qtdemux->preferred_protection_system_id != NULL) {
8504 GST_LOG_OBJECT (element,
8505 "already have the protection context, no need to request it again");
8506 return;
8507 }
8508
8509 g_ptr_array_add (qtdemux->protection_system_ids, NULL);
8510 filtered_sys_ids = gst_protection_filter_systems_by_available_decryptors (
8511 (const gchar **) qtdemux->protection_system_ids->pdata);
8512
8513 g_ptr_array_remove_index (qtdemux->protection_system_ids,
8514 qtdemux->protection_system_ids->len - 1);
8515 GST_TRACE_OBJECT (qtdemux, "detected %u protection systems, we have "
8516 "decryptors for %u of them, running context request",
8517 qtdemux->protection_system_ids->len,
8518 filtered_sys_ids ? g_strv_length (filtered_sys_ids) : 0);
8519
8520
8521 if (stream->protection_scheme_event_queue.length) {
8522 GST_TRACE_OBJECT (qtdemux, "using stream event queue, length %u",
8523 stream->protection_scheme_event_queue.length);
8524 walk = stream->protection_scheme_event_queue.tail;
8525 } else {
8526 GST_TRACE_OBJECT (qtdemux, "using demuxer event queue, length %u",
8527 qtdemux->protection_event_queue.length);
8528 walk = qtdemux->protection_event_queue.tail;
8529 }
8530
8531 g_value_init (&event_list, GST_TYPE_LIST);
8532 for (; walk; walk = g_list_previous (walk)) {
8533 GValue *event_value = g_new0 (GValue, 1);
8534 g_value_init (event_value, GST_TYPE_EVENT);
8535 g_value_set_boxed (event_value, walk->data);
8536 gst_value_list_append_and_take_value (&event_list, event_value);
8537 }
8538
8539 /* 2a) Query downstream with GST_QUERY_CONTEXT for the context and
8540 * check if downstream already has a context of the specific type
8541 * 2b) Query upstream as above.
8542 */
8543 query = gst_query_new_context ("drm-preferred-decryption-system-id");
8544 st = gst_query_writable_structure (query);
8545 gst_structure_set (st, "track-id", G_TYPE_UINT, stream->track_id,
8546 "available-stream-encryption-systems", G_TYPE_STRV, filtered_sys_ids,
8547 NULL);
8548 gst_structure_set_value (st, "stream-encryption-events", &event_list);
8549 if (gst_qtdemux_run_query (element, query, GST_PAD_SRC)) {
8550 gst_query_parse_context (query, &ctxt);
8551 GST_INFO_OBJECT (element, "found context (%p) in downstream query", ctxt);
8552 gst_element_set_context (element, ctxt);
8553 } else if (gst_qtdemux_run_query (element, query, GST_PAD_SINK)) {
8554 gst_query_parse_context (query, &ctxt);
8555 GST_INFO_OBJECT (element, "found context (%p) in upstream query", ctxt);
8556 gst_element_set_context (element, ctxt);
8557 } else {
8558 /* 3) Post a GST_MESSAGE_NEED_CONTEXT message on the bus with
8559 * the required context type and afterwards check if a
8560 * usable context was set now as in 1). The message could
8561 * be handled by the parent bins of the element and the
8562 * application.
8563 */
8564 GstMessage *msg;
8565
8566 GST_INFO_OBJECT (element, "posting need context message");
8567 msg = gst_message_new_need_context (GST_OBJECT_CAST (element),
8568 "drm-preferred-decryption-system-id");
8569 st = (GstStructure *) gst_message_get_structure (msg);
8570 gst_structure_set (st, "track-id", G_TYPE_UINT, stream->track_id,
8571 "available-stream-encryption-systems", G_TYPE_STRV, filtered_sys_ids,
8572 NULL);
8573
8574 gst_structure_set_value (st, "stream-encryption-events", &event_list);
8575 gst_element_post_message (element, msg);
8576 }
8577
8578 g_strfreev (filtered_sys_ids);
8579 g_value_unset (&event_list);
8580 gst_query_unref (query);
8581 }
8582
8583 static gboolean
gst_qtdemux_configure_protected_caps(GstQTDemux * qtdemux,QtDemuxStream * stream)8584 gst_qtdemux_configure_protected_caps (GstQTDemux * qtdemux,
8585 QtDemuxStream * stream)
8586 {
8587 GstStructure *s;
8588 const gchar *selected_system = NULL;
8589
8590 g_return_val_if_fail (qtdemux != NULL, FALSE);
8591 g_return_val_if_fail (stream != NULL, FALSE);
8592 g_return_val_if_fail (gst_caps_get_size (CUR_STREAM (stream)->caps) == 1,
8593 FALSE);
8594
8595 if (stream->protection_scheme_type == FOURCC_aavd) {
8596 s = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
8597 if (!gst_structure_has_name (s, "application/x-aavd")) {
8598 gst_structure_set (s,
8599 "original-media-type", G_TYPE_STRING, gst_structure_get_name (s),
8600 NULL);
8601 gst_structure_set_name (s, "application/x-aavd");
8602 }
8603 return TRUE;
8604 }
8605
8606 if (stream->protection_scheme_type != FOURCC_cenc
8607 && stream->protection_scheme_type != FOURCC_cbcs) {
8608 GST_ERROR_OBJECT (qtdemux,
8609 "unsupported protection scheme: %" GST_FOURCC_FORMAT,
8610 GST_FOURCC_ARGS (stream->protection_scheme_type));
8611 return FALSE;
8612 }
8613
8614 s = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
8615 if (!gst_structure_has_name (s, "application/x-cenc")) {
8616 gst_structure_set (s,
8617 "original-media-type", G_TYPE_STRING, gst_structure_get_name (s), NULL);
8618 gst_structure_set (s, "cipher-mode", G_TYPE_STRING,
8619 (stream->protection_scheme_type == FOURCC_cbcs) ? "cbcs" : "cenc",
8620 NULL);
8621 gst_structure_set_name (s, "application/x-cenc");
8622 }
8623
8624 if (qtdemux->protection_system_ids == NULL) {
8625 GST_DEBUG_OBJECT (qtdemux, "stream is protected using cenc, but no "
8626 "cenc protection system information has been found, not setting a "
8627 "protection system UUID");
8628 return TRUE;
8629 }
8630
8631 gst_qtdemux_request_protection_context (qtdemux, stream);
8632 if (qtdemux->preferred_protection_system_id != NULL) {
8633 const gchar *preferred_system_array[] =
8634 { qtdemux->preferred_protection_system_id, NULL };
8635
8636 selected_system = gst_protection_select_system (preferred_system_array);
8637
8638 if (selected_system) {
8639 GST_TRACE_OBJECT (qtdemux, "selected preferred system %s",
8640 qtdemux->preferred_protection_system_id);
8641 } else {
8642 GST_WARNING_OBJECT (qtdemux, "could not select preferred system %s "
8643 "because there is no available decryptor",
8644 qtdemux->preferred_protection_system_id);
8645 }
8646 }
8647
8648 if (!selected_system) {
8649 g_ptr_array_add (qtdemux->protection_system_ids, NULL);
8650 selected_system = gst_protection_select_system ((const gchar **)
8651 qtdemux->protection_system_ids->pdata);
8652 g_ptr_array_remove_index (qtdemux->protection_system_ids,
8653 qtdemux->protection_system_ids->len - 1);
8654 }
8655
8656 if (!selected_system) {
8657 GST_ERROR_OBJECT (qtdemux, "stream is protected, but no "
8658 "suitable decryptor element has been found");
8659 return FALSE;
8660 }
8661
8662 GST_DEBUG_OBJECT (qtdemux, "selected protection system is %s",
8663 selected_system);
8664
8665 gst_structure_set (s,
8666 GST_PROTECTION_SYSTEM_ID_CAPS_FIELD, G_TYPE_STRING, selected_system,
8667 NULL);
8668
8669 return TRUE;
8670 }
8671
8672 static gboolean
gst_qtdemux_guess_framerate(GstQTDemux * qtdemux,QtDemuxStream * stream)8673 gst_qtdemux_guess_framerate (GstQTDemux * qtdemux, QtDemuxStream * stream)
8674 {
8675 /* fps is calculated base on the duration of the average framerate since
8676 * qt does not have a fixed framerate. */
8677 gboolean fps_available = TRUE;
8678 guint32 first_duration = 0;
8679
8680 if (stream->n_samples > 0)
8681 first_duration = stream->samples[0].duration;
8682
8683 if ((stream->n_samples == 1 && first_duration == 0)
8684 || (qtdemux->fragmented && stream->n_samples_moof == 1)) {
8685 /* still frame */
8686 CUR_STREAM (stream)->fps_n = 0;
8687 CUR_STREAM (stream)->fps_d = 1;
8688 } else {
8689 if (stream->duration == 0 || stream->n_samples < 2) {
8690 CUR_STREAM (stream)->fps_n = stream->timescale;
8691 CUR_STREAM (stream)->fps_d = 1;
8692 fps_available = FALSE;
8693 } else {
8694 GstClockTime avg_duration;
8695 guint64 duration;
8696 guint32 n_samples;
8697
8698 /* duration and n_samples can be updated for fragmented format
8699 * so, framerate of fragmented format is calculated using data in a moof */
8700 if (qtdemux->fragmented && stream->n_samples_moof > 0
8701 && stream->duration_moof > 0) {
8702 n_samples = stream->n_samples_moof;
8703 duration = stream->duration_moof;
8704 } else {
8705 n_samples = stream->n_samples;
8706 duration = stream->duration;
8707 }
8708
8709 /* Calculate a framerate, ignoring the first sample which is sometimes truncated */
8710 /* stream->duration is guint64, timescale, n_samples are guint32 */
8711 avg_duration =
8712 gst_util_uint64_scale_round (duration -
8713 first_duration, GST_SECOND,
8714 (guint64) (stream->timescale) * (n_samples - 1));
8715
8716 GST_LOG_OBJECT (qtdemux,
8717 "Calculating avg sample duration based on stream (or moof) duration %"
8718 G_GUINT64_FORMAT
8719 " minus first sample %u, leaving %d samples gives %"
8720 GST_TIME_FORMAT, duration, first_duration,
8721 n_samples - 1, GST_TIME_ARGS (avg_duration));
8722 #ifdef OHOS_OPT_COMPAT
8723 /**
8724 * ohos.opt.compat.0038
8725 * Solve the problem of correct frame rate not passing forward
8726 */
8727 if (avg_duration == 0) {
8728 fps_available = FALSE;
8729 GST_ERROR_OBJECT (qtdemux, "Calculating avg duration abnormal");
8730 } else {
8731 gst_video_guess_framerate (avg_duration, &CUR_STREAM (stream)->fps_n, &CUR_STREAM (stream)->fps_d);
8732 GST_DEBUG_OBJECT (qtdemux, "Guess framerate fps_n %d fps_d %d",
8733 CUR_STREAM (stream)->fps_n, CUR_STREAM (stream)->fps_d);
8734 }
8735 #else
8736 fps_available =
8737 gst_video_guess_framerate (avg_duration,
8738 &CUR_STREAM (stream)->fps_n, &CUR_STREAM (stream)->fps_d);
8739 #endif
8740 GST_DEBUG_OBJECT (qtdemux,
8741 "Calculating framerate, timescale %u gave fps_n %d fps_d %d",
8742 stream->timescale, CUR_STREAM (stream)->fps_n,
8743 CUR_STREAM (stream)->fps_d);
8744 }
8745 }
8746
8747 return fps_available;
8748 }
8749
8750 static gboolean
gst_qtdemux_configure_stream(GstQTDemux * qtdemux,QtDemuxStream * stream)8751 gst_qtdemux_configure_stream (GstQTDemux * qtdemux, QtDemuxStream * stream)
8752 {
8753 if (stream->subtype == FOURCC_vide) {
8754 gboolean fps_available = gst_qtdemux_guess_framerate (qtdemux, stream);
8755
8756 if (CUR_STREAM (stream)->caps) {
8757 CUR_STREAM (stream)->caps =
8758 gst_caps_make_writable (CUR_STREAM (stream)->caps);
8759
8760 if (CUR_STREAM (stream)->width && CUR_STREAM (stream)->height)
8761 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8762 "width", G_TYPE_INT, CUR_STREAM (stream)->width,
8763 "height", G_TYPE_INT, CUR_STREAM (stream)->height, NULL);
8764
8765 /* set framerate if calculated framerate is reliable */
8766 if (fps_available) {
8767 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8768 "framerate", GST_TYPE_FRACTION, CUR_STREAM (stream)->fps_n,
8769 CUR_STREAM (stream)->fps_d, NULL);
8770 }
8771
8772 /* calculate pixel-aspect-ratio using display width and height */
8773 GST_DEBUG_OBJECT (qtdemux,
8774 "video size %dx%d, target display size %dx%d",
8775 CUR_STREAM (stream)->width, CUR_STREAM (stream)->height,
8776 stream->display_width, stream->display_height);
8777 /* qt file might have pasp atom */
8778 if (CUR_STREAM (stream)->par_w > 0 && CUR_STREAM (stream)->par_h > 0) {
8779 GST_DEBUG_OBJECT (qtdemux, "par %d:%d", CUR_STREAM (stream)->par_w,
8780 CUR_STREAM (stream)->par_h);
8781 gst_caps_set_simple (CUR_STREAM (stream)->caps, "pixel-aspect-ratio",
8782 GST_TYPE_FRACTION, CUR_STREAM (stream)->par_w,
8783 CUR_STREAM (stream)->par_h, NULL);
8784 } else if (stream->display_width > 0 && stream->display_height > 0
8785 && CUR_STREAM (stream)->width > 0
8786 && CUR_STREAM (stream)->height > 0) {
8787 gint n, d;
8788
8789 /* calculate the pixel aspect ratio using the display and pixel w/h */
8790 n = stream->display_width * CUR_STREAM (stream)->height;
8791 d = stream->display_height * CUR_STREAM (stream)->width;
8792 if (n == d)
8793 n = d = 1;
8794 GST_DEBUG_OBJECT (qtdemux, "setting PAR to %d/%d", n, d);
8795 CUR_STREAM (stream)->par_w = n;
8796 CUR_STREAM (stream)->par_h = d;
8797 gst_caps_set_simple (CUR_STREAM (stream)->caps, "pixel-aspect-ratio",
8798 GST_TYPE_FRACTION, CUR_STREAM (stream)->par_w,
8799 CUR_STREAM (stream)->par_h, NULL);
8800 }
8801
8802 if (CUR_STREAM (stream)->interlace_mode > 0) {
8803 if (CUR_STREAM (stream)->interlace_mode == 1) {
8804 gst_caps_set_simple (CUR_STREAM (stream)->caps, "interlace-mode",
8805 G_TYPE_STRING, "progressive", NULL);
8806 } else if (CUR_STREAM (stream)->interlace_mode == 2) {
8807 gst_caps_set_simple (CUR_STREAM (stream)->caps, "interlace-mode",
8808 G_TYPE_STRING, "interleaved", NULL);
8809 if (CUR_STREAM (stream)->field_order == 9) {
8810 gst_caps_set_simple (CUR_STREAM (stream)->caps, "field-order",
8811 G_TYPE_STRING, "top-field-first", NULL);
8812 } else if (CUR_STREAM (stream)->field_order == 14) {
8813 gst_caps_set_simple (CUR_STREAM (stream)->caps, "field-order",
8814 G_TYPE_STRING, "bottom-field-first", NULL);
8815 }
8816 }
8817 }
8818
8819 /* Create incomplete colorimetry here if needed */
8820 if (CUR_STREAM (stream)->colorimetry.range ||
8821 CUR_STREAM (stream)->colorimetry.matrix ||
8822 CUR_STREAM (stream)->colorimetry.transfer
8823 || CUR_STREAM (stream)->colorimetry.primaries) {
8824 gchar *colorimetry =
8825 gst_video_colorimetry_to_string (&CUR_STREAM (stream)->colorimetry);
8826 gst_caps_set_simple (CUR_STREAM (stream)->caps, "colorimetry",
8827 G_TYPE_STRING, colorimetry, NULL);
8828 g_free (colorimetry);
8829 }
8830
8831 if (stream->multiview_mode != GST_VIDEO_MULTIVIEW_MODE_NONE) {
8832 guint par_w = 1, par_h = 1;
8833
8834 if (CUR_STREAM (stream)->par_w > 0 && CUR_STREAM (stream)->par_h > 0) {
8835 par_w = CUR_STREAM (stream)->par_w;
8836 par_h = CUR_STREAM (stream)->par_h;
8837 }
8838
8839 if (gst_video_multiview_guess_half_aspect (stream->multiview_mode,
8840 CUR_STREAM (stream)->width, CUR_STREAM (stream)->height, par_w,
8841 par_h)) {
8842 stream->multiview_flags |= GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT;
8843 }
8844
8845 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8846 "multiview-mode", G_TYPE_STRING,
8847 gst_video_multiview_mode_to_caps_string (stream->multiview_mode),
8848 "multiview-flags", GST_TYPE_VIDEO_MULTIVIEW_FLAGSET,
8849 stream->multiview_flags, GST_FLAG_SET_MASK_EXACT, NULL);
8850 }
8851 }
8852 }
8853
8854 else if (stream->subtype == FOURCC_soun) {
8855 if (CUR_STREAM (stream)->caps) {
8856 CUR_STREAM (stream)->caps =
8857 gst_caps_make_writable (CUR_STREAM (stream)->caps);
8858 if (CUR_STREAM (stream)->rate > 0)
8859 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8860 "rate", G_TYPE_INT, (int) CUR_STREAM (stream)->rate, NULL);
8861 if (CUR_STREAM (stream)->n_channels > 0)
8862 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8863 "channels", G_TYPE_INT, CUR_STREAM (stream)->n_channels, NULL);
8864 if (CUR_STREAM (stream)->n_channels > 2) {
8865 /* FIXME: Need to parse the 'chan' atom to get channel layouts
8866 * correctly; this is just the minimum we can do - assume
8867 * we don't actually have any channel positions. */
8868 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8869 "channel-mask", GST_TYPE_BITMASK, G_GUINT64_CONSTANT (0), NULL);
8870 }
8871 }
8872 }
8873
8874 else if (stream->subtype == FOURCC_clcp && CUR_STREAM (stream)->caps) {
8875 const GstStructure *s;
8876 QtDemuxStream *fps_stream = NULL;
8877 gboolean fps_available = FALSE;
8878
8879 /* CEA608 closed caption tracks are a bit special in that each sample
8880 * can contain CCs for multiple frames, and CCs can be omitted and have to
8881 * be inferred from the duration of the sample then.
8882 *
8883 * As such we take the framerate from the (first) video track here for
8884 * CEA608 as there must be one CC byte pair for every video frame
8885 * according to the spec.
8886 *
8887 * For CEA708 all is fine and there is one sample per frame.
8888 */
8889
8890 s = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
8891 if (gst_structure_has_name (s, "closedcaption/x-cea-608")) {
8892 gint i;
8893
8894 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
8895 QtDemuxStream *tmp = QTDEMUX_NTH_STREAM (qtdemux, i);
8896
8897 if (tmp->subtype == FOURCC_vide) {
8898 fps_stream = tmp;
8899 break;
8900 }
8901 }
8902
8903 if (fps_stream) {
8904 fps_available = gst_qtdemux_guess_framerate (qtdemux, fps_stream);
8905 CUR_STREAM (stream)->fps_n = CUR_STREAM (fps_stream)->fps_n;
8906 CUR_STREAM (stream)->fps_d = CUR_STREAM (fps_stream)->fps_d;
8907 }
8908 } else {
8909 fps_available = gst_qtdemux_guess_framerate (qtdemux, stream);
8910 fps_stream = stream;
8911 }
8912
8913 CUR_STREAM (stream)->caps =
8914 gst_caps_make_writable (CUR_STREAM (stream)->caps);
8915
8916 /* set framerate if calculated framerate is reliable */
8917 if (fps_available) {
8918 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8919 "framerate", GST_TYPE_FRACTION, CUR_STREAM (stream)->fps_n,
8920 CUR_STREAM (stream)->fps_d, NULL);
8921 }
8922 }
8923
8924 if (stream->pad) {
8925 GstCaps *prev_caps = NULL;
8926
8927 GST_PAD_ELEMENT_PRIVATE (stream->pad) = stream;
8928 gst_pad_set_event_function (stream->pad, gst_qtdemux_handle_src_event);
8929 gst_pad_set_query_function (stream->pad, gst_qtdemux_handle_src_query);
8930 gst_pad_set_active (stream->pad, TRUE);
8931
8932 gst_pad_use_fixed_caps (stream->pad);
8933
8934 if (stream->protected) {
8935 if (!gst_qtdemux_configure_protected_caps (qtdemux, stream)) {
8936 GST_ERROR_OBJECT (qtdemux,
8937 "Failed to configure protected stream caps.");
8938 return FALSE;
8939 }
8940 }
8941
8942 GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT,
8943 CUR_STREAM (stream)->caps);
8944 if (stream->new_stream) {
8945 GstEvent *event;
8946 GstStreamFlags stream_flags = GST_STREAM_FLAG_NONE;
8947
8948 event =
8949 gst_pad_get_sticky_event (qtdemux->sinkpad, GST_EVENT_STREAM_START,
8950 0);
8951 if (event) {
8952 gst_event_parse_stream_flags (event, &stream_flags);
8953 if (gst_event_parse_group_id (event, &qtdemux->group_id))
8954 qtdemux->have_group_id = TRUE;
8955 else
8956 qtdemux->have_group_id = FALSE;
8957 gst_event_unref (event);
8958 } else if (!qtdemux->have_group_id) {
8959 qtdemux->have_group_id = TRUE;
8960 qtdemux->group_id = gst_util_group_id_next ();
8961 }
8962
8963 stream->new_stream = FALSE;
8964 event = gst_event_new_stream_start (stream->stream_id);
8965 if (qtdemux->have_group_id)
8966 gst_event_set_group_id (event, qtdemux->group_id);
8967 if (stream->disabled)
8968 stream_flags |= GST_STREAM_FLAG_UNSELECT;
8969 if (CUR_STREAM (stream)->sparse) {
8970 stream_flags |= GST_STREAM_FLAG_SPARSE;
8971 } else {
8972 stream_flags &= ~GST_STREAM_FLAG_SPARSE;
8973 }
8974 gst_event_set_stream_flags (event, stream_flags);
8975 gst_pad_push_event (stream->pad, event);
8976 }
8977
8978 prev_caps = gst_pad_get_current_caps (stream->pad);
8979
8980 if (CUR_STREAM (stream)->caps) {
8981 if (!prev_caps
8982 || !gst_caps_is_equal_fixed (prev_caps, CUR_STREAM (stream)->caps)) {
8983 GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT,
8984 CUR_STREAM (stream)->caps);
8985 gst_pad_set_caps (stream->pad, CUR_STREAM (stream)->caps);
8986 } else {
8987 GST_DEBUG_OBJECT (qtdemux, "ignore duplicated caps");
8988 }
8989 } else {
8990 GST_WARNING_OBJECT (qtdemux, "stream without caps");
8991 }
8992
8993 if (prev_caps)
8994 gst_caps_unref (prev_caps);
8995 stream->new_caps = FALSE;
8996 }
8997 return TRUE;
8998 }
8999
9000 static void
gst_qtdemux_stream_check_and_change_stsd_index(GstQTDemux * demux,QtDemuxStream * stream)9001 gst_qtdemux_stream_check_and_change_stsd_index (GstQTDemux * demux,
9002 QtDemuxStream * stream)
9003 {
9004 if (stream->cur_stsd_entry_index == stream->stsd_sample_description_id)
9005 return;
9006
9007 GST_DEBUG_OBJECT (stream->pad, "Changing stsd index from '%u' to '%u'",
9008 stream->cur_stsd_entry_index, stream->stsd_sample_description_id);
9009 if (G_UNLIKELY (stream->stsd_sample_description_id >=
9010 stream->stsd_entries_length)) {
9011 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
9012 (_("This file is invalid and cannot be played.")),
9013 ("New sample description id is out of bounds (%d >= %d)",
9014 stream->stsd_sample_description_id, stream->stsd_entries_length));
9015 } else {
9016 stream->cur_stsd_entry_index = stream->stsd_sample_description_id;
9017 stream->new_caps = TRUE;
9018 }
9019 }
9020
9021 static gboolean
gst_qtdemux_add_stream(GstQTDemux * qtdemux,QtDemuxStream * stream,GstTagList * list)9022 gst_qtdemux_add_stream (GstQTDemux * qtdemux,
9023 QtDemuxStream * stream, GstTagList * list)
9024 {
9025 gboolean ret = TRUE;
9026
9027 if (stream->subtype == FOURCC_vide) {
9028 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
9029
9030 stream->pad =
9031 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
9032 g_free (name);
9033
9034 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
9035 gst_object_unref (stream->pad);
9036 stream->pad = NULL;
9037 ret = FALSE;
9038 goto done;
9039 }
9040
9041 qtdemux->n_video_streams++;
9042 } else if (stream->subtype == FOURCC_soun) {
9043 gchar *name = g_strdup_printf ("audio_%u", qtdemux->n_audio_streams);
9044
9045 stream->pad =
9046 gst_pad_new_from_static_template (&gst_qtdemux_audiosrc_template, name);
9047 g_free (name);
9048 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
9049 gst_object_unref (stream->pad);
9050 stream->pad = NULL;
9051 ret = FALSE;
9052 goto done;
9053 }
9054 qtdemux->n_audio_streams++;
9055 } else if (stream->subtype == FOURCC_strm) {
9056 GST_DEBUG_OBJECT (qtdemux, "stream type, not creating pad");
9057 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
9058 || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt
9059 || stream->subtype == FOURCC_clcp || stream->subtype == FOURCC_wvtt) {
9060 gchar *name = g_strdup_printf ("subtitle_%u", qtdemux->n_sub_streams);
9061
9062 stream->pad =
9063 gst_pad_new_from_static_template (&gst_qtdemux_subsrc_template, name);
9064 g_free (name);
9065 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
9066 gst_object_unref (stream->pad);
9067 stream->pad = NULL;
9068 ret = FALSE;
9069 goto done;
9070 }
9071 qtdemux->n_sub_streams++;
9072 } else if (CUR_STREAM (stream)->caps) {
9073 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
9074
9075 stream->pad =
9076 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
9077 g_free (name);
9078 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
9079 gst_object_unref (stream->pad);
9080 stream->pad = NULL;
9081 ret = FALSE;
9082 goto done;
9083 }
9084 qtdemux->n_video_streams++;
9085 } else {
9086 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
9087 goto done;
9088 }
9089
9090 if (stream->pad) {
9091 GList *l;
9092
9093 GST_DEBUG_OBJECT (qtdemux, "adding pad %s %p to qtdemux %p",
9094 GST_OBJECT_NAME (stream->pad), stream->pad, qtdemux);
9095 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
9096 GST_OBJECT_LOCK (qtdemux);
9097 gst_flow_combiner_add_pad (qtdemux->flowcombiner, stream->pad);
9098 GST_OBJECT_UNLOCK (qtdemux);
9099
9100 if (stream->stream_tags)
9101 gst_tag_list_unref (stream->stream_tags);
9102 stream->stream_tags = list;
9103 list = NULL;
9104 /* global tags go on each pad anyway */
9105 stream->send_global_tags = TRUE;
9106 /* send upstream GST_EVENT_PROTECTION events that were received before
9107 this source pad was created */
9108 for (l = qtdemux->protection_event_queue.head; l != NULL; l = l->next)
9109 gst_pad_push_event (stream->pad, gst_event_ref (l->data));
9110 }
9111 done:
9112 if (list)
9113 gst_tag_list_unref (list);
9114 return ret;
9115 }
9116
9117 /* find next atom with @fourcc starting at @offset */
9118 static GstFlowReturn
qtdemux_find_atom(GstQTDemux * qtdemux,guint64 * offset,guint64 * length,guint32 fourcc)9119 qtdemux_find_atom (GstQTDemux * qtdemux, guint64 * offset,
9120 guint64 * length, guint32 fourcc)
9121 {
9122 GstFlowReturn ret;
9123 guint32 lfourcc;
9124 GstBuffer *buf;
9125
9126 GST_LOG_OBJECT (qtdemux, "finding fourcc %" GST_FOURCC_FORMAT " at offset %"
9127 G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), *offset);
9128
9129 while (TRUE) {
9130 GstMapInfo map;
9131
9132 buf = NULL;
9133 ret = gst_pad_pull_range (qtdemux->sinkpad, *offset, 16, &buf);
9134 if (G_UNLIKELY (ret != GST_FLOW_OK))
9135 goto locate_failed;
9136 if (G_UNLIKELY (gst_buffer_get_size (buf) != 16)) {
9137 /* likely EOF */
9138 ret = GST_FLOW_EOS;
9139 gst_buffer_unref (buf);
9140 goto locate_failed;
9141 }
9142 gst_buffer_map (buf, &map, GST_MAP_READ);
9143 extract_initial_length_and_fourcc (map.data, 16, length, &lfourcc);
9144 gst_buffer_unmap (buf, &map);
9145 gst_buffer_unref (buf);
9146
9147 if (G_UNLIKELY (*length == 0)) {
9148 GST_DEBUG_OBJECT (qtdemux, "invalid length 0");
9149 ret = GST_FLOW_ERROR;
9150 goto locate_failed;
9151 }
9152
9153 if (lfourcc == fourcc) {
9154 GST_DEBUG_OBJECT (qtdemux, "found '%" GST_FOURCC_FORMAT " at offset %"
9155 G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), *offset);
9156 break;
9157 } else {
9158 GST_LOG_OBJECT (qtdemux,
9159 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
9160 GST_FOURCC_ARGS (lfourcc), *offset);
9161 if (*offset == G_MAXUINT64)
9162 goto locate_failed;
9163 *offset += *length;
9164 }
9165 }
9166
9167 return GST_FLOW_OK;
9168
9169 locate_failed:
9170 {
9171 /* might simply have had last one */
9172 GST_DEBUG_OBJECT (qtdemux, "fourcc not found");
9173 return ret;
9174 }
9175 }
9176
9177 /* should only do something in pull mode */
9178 /* call with OBJECT lock */
9179 static GstFlowReturn
qtdemux_add_fragmented_samples(GstQTDemux * qtdemux)9180 qtdemux_add_fragmented_samples (GstQTDemux * qtdemux)
9181 {
9182 guint64 length, offset;
9183 GstBuffer *buf = NULL;
9184 GstFlowReturn ret = GST_FLOW_OK;
9185 GstFlowReturn res = GST_FLOW_OK;
9186 GstMapInfo map;
9187
9188 offset = qtdemux->moof_offset;
9189 GST_DEBUG_OBJECT (qtdemux, "next moof at offset %" G_GUINT64_FORMAT, offset);
9190
9191 if (!offset) {
9192 GST_DEBUG_OBJECT (qtdemux, "no next moof");
9193 return GST_FLOW_EOS;
9194 }
9195
9196 /* best not do pull etc with lock held */
9197 GST_OBJECT_UNLOCK (qtdemux);
9198
9199 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
9200 if (ret != GST_FLOW_OK)
9201 goto flow_failed;
9202
9203 ret = gst_qtdemux_pull_atom (qtdemux, offset, length, &buf);
9204 if (G_UNLIKELY (ret != GST_FLOW_OK))
9205 goto flow_failed;
9206 gst_buffer_map (buf, &map, GST_MAP_READ);
9207 if (!qtdemux_parse_moof (qtdemux, map.data, map.size, offset, NULL)) {
9208 gst_buffer_unmap (buf, &map);
9209 gst_buffer_unref (buf);
9210 buf = NULL;
9211 goto parse_failed;
9212 }
9213
9214 gst_buffer_unmap (buf, &map);
9215 gst_buffer_unref (buf);
9216 buf = NULL;
9217
9218 offset += length;
9219 /* look for next moof */
9220 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
9221 if (G_UNLIKELY (ret != GST_FLOW_OK))
9222 goto flow_failed;
9223
9224 exit:
9225 GST_OBJECT_LOCK (qtdemux);
9226
9227 qtdemux->moof_offset = offset;
9228
9229 return res;
9230
9231 parse_failed:
9232 {
9233 GST_DEBUG_OBJECT (qtdemux, "failed to parse moof");
9234 offset = 0;
9235 res = GST_FLOW_ERROR;
9236 goto exit;
9237 }
9238 flow_failed:
9239 {
9240 /* maybe upstream temporarily flushing */
9241 if (ret != GST_FLOW_FLUSHING) {
9242 GST_DEBUG_OBJECT (qtdemux, "no next moof");
9243 offset = 0;
9244 } else {
9245 GST_DEBUG_OBJECT (qtdemux, "upstream WRONG_STATE");
9246 /* resume at current position next time */
9247 }
9248 res = ret;
9249 goto exit;
9250 }
9251 }
9252
9253 static void
qtdemux_merge_sample_table(GstQTDemux * qtdemux,QtDemuxStream * stream)9254 qtdemux_merge_sample_table (GstQTDemux * qtdemux, QtDemuxStream * stream)
9255 {
9256 guint i;
9257 guint32 num_chunks;
9258 gint32 stts_duration;
9259 GstByteWriter stsc, stts, stsz;
9260
9261 /* Each sample has a different size, which we don't support for merging */
9262 if (stream->sample_size == 0) {
9263 GST_DEBUG_OBJECT (qtdemux,
9264 "Not all samples have the same size, not merging");
9265 return;
9266 }
9267
9268 /* The stream has a ctts table, we don't support that */
9269 if (stream->ctts_present) {
9270 GST_DEBUG_OBJECT (qtdemux, "Have ctts, not merging");
9271 return;
9272 }
9273
9274 /* If there's a sync sample table also ignore this stream */
9275 if (stream->stps_present || stream->stss_present) {
9276 GST_DEBUG_OBJECT (qtdemux, "Have stss/stps, not merging");
9277 return;
9278 }
9279
9280 /* If chunks are considered samples already ignore this stream */
9281 if (stream->chunks_are_samples) {
9282 GST_DEBUG_OBJECT (qtdemux, "Chunks are samples, not merging");
9283 return;
9284 }
9285
9286 /* Require that all samples have the same duration */
9287 if (stream->n_sample_times > 1) {
9288 GST_DEBUG_OBJECT (qtdemux, "Not all samples have the same duration");
9289 return;
9290 }
9291
9292 /* Parse the stts to get the sample duration and number of samples */
9293 gst_byte_reader_skip_unchecked (&stream->stts, 4);
9294 stts_duration = gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
9295
9296 /* Parse the number of chunks from the stco manually because the
9297 * reader is already behind that */
9298 num_chunks = GST_READ_UINT32_BE (stream->stco.data + 4);
9299
9300 GST_DEBUG_OBJECT (qtdemux, "sample_duration %d, num_chunks %u", stts_duration,
9301 num_chunks);
9302
9303 /* Now parse stsc, convert chunks into single samples and generate a
9304 * new stsc, stts and stsz from this information */
9305 gst_byte_writer_init (&stsc);
9306 gst_byte_writer_init (&stts);
9307 gst_byte_writer_init (&stsz);
9308
9309 /* Note: we skip fourccs, size, version, flags and other fields of the new
9310 * atoms as the byte readers with them are already behind that position
9311 * anyway and only update the values of those inside the stream directly.
9312 */
9313 stream->n_sample_times = 0;
9314 stream->n_samples = 0;
9315 for (i = 0; i < stream->n_samples_per_chunk; i++) {
9316 guint j;
9317 guint32 first_chunk, last_chunk, samples_per_chunk, sample_description_id;
9318
9319 first_chunk = gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9320 samples_per_chunk = gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9321 sample_description_id =
9322 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9323
9324 if (i == stream->n_samples_per_chunk - 1) {
9325 /* +1 because first_chunk is 1-based */
9326 last_chunk = num_chunks + 1;
9327 } else {
9328 last_chunk = gst_byte_reader_peek_uint32_be_unchecked (&stream->stsc);
9329 }
9330
9331 GST_DEBUG_OBJECT (qtdemux,
9332 "Merging first_chunk: %u, last_chunk: %u, samples_per_chunk: %u, sample_description_id: %u",
9333 first_chunk, last_chunk, samples_per_chunk, sample_description_id);
9334
9335 gst_byte_writer_put_uint32_be (&stsc, first_chunk);
9336 /* One sample in this chunk */
9337 gst_byte_writer_put_uint32_be (&stsc, 1);
9338 gst_byte_writer_put_uint32_be (&stsc, sample_description_id);
9339
9340 /* For each chunk write a stts and stsz entry now */
9341 gst_byte_writer_put_uint32_be (&stts, last_chunk - first_chunk);
9342 gst_byte_writer_put_uint32_be (&stts, stts_duration * samples_per_chunk);
9343 for (j = first_chunk; j < last_chunk; j++) {
9344 gst_byte_writer_put_uint32_be (&stsz,
9345 stream->sample_size * samples_per_chunk);
9346 }
9347
9348 stream->n_sample_times += 1;
9349 stream->n_samples += last_chunk - first_chunk;
9350 }
9351
9352 g_assert_cmpint (stream->n_samples, ==, num_chunks);
9353
9354 GST_DEBUG_OBJECT (qtdemux, "Have %u samples and %u sample times",
9355 stream->n_samples, stream->n_sample_times);
9356
9357 /* We don't have a fixed sample size anymore */
9358 stream->sample_size = 0;
9359
9360 /* Free old data for the atoms */
9361 g_free ((gpointer) stream->stsz.data);
9362 stream->stsz.data = NULL;
9363 g_free ((gpointer) stream->stsc.data);
9364 stream->stsc.data = NULL;
9365 g_free ((gpointer) stream->stts.data);
9366 stream->stts.data = NULL;
9367
9368 /* Store new data and replace byte readers */
9369 stream->stsz.size = gst_byte_writer_get_size (&stsz);
9370 stream->stsz.data = gst_byte_writer_reset_and_get_data (&stsz);
9371 gst_byte_reader_init (&stream->stsz, stream->stsz.data, stream->stsz.size);
9372 stream->stts.size = gst_byte_writer_get_size (&stts);
9373 stream->stts.data = gst_byte_writer_reset_and_get_data (&stts);
9374 gst_byte_reader_init (&stream->stts, stream->stts.data, stream->stts.size);
9375 stream->stsc.size = gst_byte_writer_get_size (&stsc);
9376 stream->stsc.data = gst_byte_writer_reset_and_get_data (&stsc);
9377 gst_byte_reader_init (&stream->stsc, stream->stsc.data, stream->stsc.size);
9378 }
9379
9380 /* initialise bytereaders for stbl sub-atoms */
9381 static gboolean
qtdemux_stbl_init(GstQTDemux * qtdemux,QtDemuxStream * stream,GNode * stbl)9382 qtdemux_stbl_init (GstQTDemux * qtdemux, QtDemuxStream * stream, GNode * stbl)
9383 {
9384 stream->stbl_index = -1; /* no samples have yet been parsed */
9385 stream->sample_index = -1;
9386
9387 /* time-to-sample atom */
9388 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stts, &stream->stts))
9389 goto corrupt_file;
9390
9391 /* copy atom data into a new buffer for later use */
9392 stream->stts.data = g_memdup2 (stream->stts.data, stream->stts.size);
9393
9394 /* skip version + flags */
9395 if (!gst_byte_reader_skip (&stream->stts, 1 + 3) ||
9396 !gst_byte_reader_get_uint32_be (&stream->stts, &stream->n_sample_times))
9397 goto corrupt_file;
9398 GST_LOG_OBJECT (qtdemux, "%u timestamp blocks", stream->n_sample_times);
9399
9400 /* make sure there's enough data */
9401 if (!qt_atom_parser_has_chunks (&stream->stts, stream->n_sample_times, 8)) {
9402 stream->n_sample_times = gst_byte_reader_get_remaining (&stream->stts) / 8;
9403 GST_LOG_OBJECT (qtdemux, "overriding to %u timestamp blocks",
9404 stream->n_sample_times);
9405 if (!stream->n_sample_times)
9406 goto corrupt_file;
9407 }
9408
9409 /* sync sample atom */
9410 stream->stps_present = FALSE;
9411 if ((stream->stss_present =
9412 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stss,
9413 &stream->stss) ? TRUE : FALSE) == TRUE) {
9414 /* copy atom data into a new buffer for later use */
9415 stream->stss.data = g_memdup2 (stream->stss.data, stream->stss.size);
9416
9417 /* skip version + flags */
9418 if (!gst_byte_reader_skip (&stream->stss, 1 + 3) ||
9419 !gst_byte_reader_get_uint32_be (&stream->stss, &stream->n_sample_syncs))
9420 goto corrupt_file;
9421
9422 if (stream->n_sample_syncs) {
9423 /* make sure there's enough data */
9424 if (!qt_atom_parser_has_chunks (&stream->stss, stream->n_sample_syncs, 4))
9425 goto corrupt_file;
9426 }
9427
9428 /* partial sync sample atom */
9429 if ((stream->stps_present =
9430 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stps,
9431 &stream->stps) ? TRUE : FALSE) == TRUE) {
9432 /* copy atom data into a new buffer for later use */
9433 stream->stps.data = g_memdup2 (stream->stps.data, stream->stps.size);
9434
9435 /* skip version + flags */
9436 if (!gst_byte_reader_skip (&stream->stps, 1 + 3) ||
9437 !gst_byte_reader_get_uint32_be (&stream->stps,
9438 &stream->n_sample_partial_syncs))
9439 goto corrupt_file;
9440
9441 /* if there are no entries, the stss table contains the real
9442 * sync samples */
9443 if (stream->n_sample_partial_syncs) {
9444 /* make sure there's enough data */
9445 if (!qt_atom_parser_has_chunks (&stream->stps,
9446 stream->n_sample_partial_syncs, 4))
9447 goto corrupt_file;
9448 }
9449 }
9450 }
9451
9452 /* sample size */
9453 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsz, &stream->stsz))
9454 goto no_samples;
9455
9456 /* copy atom data into a new buffer for later use */
9457 stream->stsz.data = g_memdup2 (stream->stsz.data, stream->stsz.size);
9458
9459 /* skip version + flags */
9460 if (!gst_byte_reader_skip (&stream->stsz, 1 + 3) ||
9461 !gst_byte_reader_get_uint32_be (&stream->stsz, &stream->sample_size))
9462 goto corrupt_file;
9463
9464 if (!gst_byte_reader_get_uint32_be (&stream->stsz, &stream->n_samples))
9465 goto corrupt_file;
9466
9467 if (!stream->n_samples)
9468 goto no_samples;
9469
9470 /* sample-to-chunk atom */
9471 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsc, &stream->stsc))
9472 goto corrupt_file;
9473
9474 /* copy atom data into a new buffer for later use */
9475 stream->stsc.data = g_memdup2 (stream->stsc.data, stream->stsc.size);
9476
9477 /* skip version + flags */
9478 if (!gst_byte_reader_skip (&stream->stsc, 1 + 3) ||
9479 !gst_byte_reader_get_uint32_be (&stream->stsc,
9480 &stream->n_samples_per_chunk))
9481 goto corrupt_file;
9482
9483 GST_DEBUG_OBJECT (qtdemux, "n_samples_per_chunk %u",
9484 stream->n_samples_per_chunk);
9485
9486 /* make sure there's enough data */
9487 if (!qt_atom_parser_has_chunks (&stream->stsc, stream->n_samples_per_chunk,
9488 12))
9489 goto corrupt_file;
9490
9491
9492 /* chunk offset */
9493 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stco, &stream->stco))
9494 stream->co_size = sizeof (guint32);
9495 else if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_co64,
9496 &stream->stco))
9497 stream->co_size = sizeof (guint64);
9498 else
9499 goto corrupt_file;
9500
9501 /* copy atom data into a new buffer for later use */
9502 stream->stco.data = g_memdup2 (stream->stco.data, stream->stco.size);
9503
9504 /* skip version + flags */
9505 if (!gst_byte_reader_skip (&stream->stco, 1 + 3))
9506 goto corrupt_file;
9507
9508 /* chunks_are_samples == TRUE means treat chunks as samples */
9509 stream->chunks_are_samples = stream->sample_size
9510 && !CUR_STREAM (stream)->sampled;
9511 if (stream->chunks_are_samples) {
9512 /* treat chunks as samples */
9513 if (!gst_byte_reader_get_uint32_be (&stream->stco, &stream->n_samples))
9514 goto corrupt_file;
9515 } else {
9516 /* skip number of entries */
9517 if (!gst_byte_reader_skip (&stream->stco, 4))
9518 goto corrupt_file;
9519
9520 /* make sure there are enough data in the stsz atom */
9521 if (!stream->sample_size) {
9522 /* different sizes for each sample */
9523 if (!qt_atom_parser_has_chunks (&stream->stsz, stream->n_samples, 4))
9524 goto corrupt_file;
9525 }
9526 }
9527
9528 /* composition time-to-sample */
9529 if ((stream->ctts_present =
9530 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_ctts,
9531 &stream->ctts) ? TRUE : FALSE) == TRUE) {
9532 GstByteReader cslg = GST_BYTE_READER_INIT (NULL, 0);
9533 guint8 ctts_version;
9534 gboolean checked_ctts = FALSE;
9535
9536 /* copy atom data into a new buffer for later use */
9537 stream->ctts.data = g_memdup2 (stream->ctts.data, stream->ctts.size);
9538
9539 /* version 1 has signed offsets */
9540 if (!gst_byte_reader_get_uint8 (&stream->ctts, &ctts_version))
9541 goto corrupt_file;
9542
9543 /* flags */
9544 if (!gst_byte_reader_skip (&stream->ctts, 3)
9545 || !gst_byte_reader_get_uint32_be (&stream->ctts,
9546 &stream->n_composition_times))
9547 goto corrupt_file;
9548
9549 /* make sure there's enough data */
9550 if (!qt_atom_parser_has_chunks (&stream->ctts, stream->n_composition_times,
9551 4 + 4))
9552 goto corrupt_file;
9553
9554 /* This is optional, if missing we iterate the ctts */
9555 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_cslg, &cslg)) {
9556 guint8 cslg_version;
9557
9558 /* cslg version 1 has 64 bit fields */
9559 if (!gst_byte_reader_get_uint8 (&cslg, &cslg_version))
9560 goto corrupt_file;
9561
9562 /* skip flags */
9563 if (!gst_byte_reader_skip (&cslg, 3))
9564 goto corrupt_file;
9565
9566 if (cslg_version == 0) {
9567 gint32 composition_to_dts_shift;
9568
9569 if (!gst_byte_reader_get_int32_be (&cslg, &composition_to_dts_shift))
9570 goto corrupt_file;
9571
9572 stream->cslg_shift = MAX (0, composition_to_dts_shift);
9573 } else {
9574 gint64 composition_to_dts_shift;
9575
9576 if (!gst_byte_reader_get_int64_be (&cslg, &composition_to_dts_shift))
9577 goto corrupt_file;
9578
9579 stream->cslg_shift = MAX (0, composition_to_dts_shift);
9580 }
9581 } else {
9582 gint32 cslg_least = 0;
9583 guint num_entries, pos;
9584 gint i;
9585
9586 pos = gst_byte_reader_get_pos (&stream->ctts);
9587 num_entries = stream->n_composition_times;
9588
9589 checked_ctts = TRUE;
9590
9591 stream->cslg_shift = 0;
9592
9593 for (i = 0; i < num_entries; i++) {
9594 gint32 offset;
9595
9596 gst_byte_reader_skip_unchecked (&stream->ctts, 4);
9597 offset = gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
9598 /* HACK: if sample_offset is larger than 2 * duration, ignore the box.
9599 * slightly inaccurate PTS could be more usable than corrupted one */
9600 if (G_UNLIKELY ((ctts_version == 0 || offset != G_MININT32)
9601 && ABS (offset) / 2 > stream->duration)) {
9602 GST_WARNING_OBJECT (qtdemux,
9603 "Ignore corrupted ctts, sample_offset %" G_GINT32_FORMAT
9604 " larger than duration %" G_GUINT64_FORMAT, offset,
9605 stream->duration);
9606
9607 stream->cslg_shift = 0;
9608 stream->ctts_present = FALSE;
9609 goto done;
9610 }
9611
9612 /* Don't consider "no decode samples" with offset G_MININT32
9613 * for the DTS/PTS shift */
9614 if (offset != G_MININT32 && offset < cslg_least)
9615 cslg_least = offset;
9616 }
9617
9618 if (cslg_least < 0)
9619 stream->cslg_shift = -cslg_least;
9620 else
9621 stream->cslg_shift = 0;
9622
9623 /* reset the reader so we can generate sample table */
9624 gst_byte_reader_set_pos (&stream->ctts, pos);
9625 }
9626
9627 /* Check if ctts values are looking reasonable if that didn't happen above */
9628 if (!checked_ctts) {
9629 guint num_entries, pos;
9630 gint i;
9631
9632 pos = gst_byte_reader_get_pos (&stream->ctts);
9633 num_entries = stream->n_composition_times;
9634
9635 for (i = 0; i < num_entries; i++) {
9636 gint32 offset;
9637
9638 gst_byte_reader_skip_unchecked (&stream->ctts, 4);
9639 offset = gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
9640 /* HACK: if sample_offset is larger than 2 * duration, ignore the box.
9641 * slightly inaccurate PTS could be more usable than corrupted one */
9642 if (G_UNLIKELY ((ctts_version == 0 || offset != G_MININT32)
9643 && ABS (offset) / 2 > stream->duration)) {
9644 GST_WARNING_OBJECT (qtdemux,
9645 "Ignore corrupted ctts, sample_offset %" G_GINT32_FORMAT
9646 " larger than duration %" G_GUINT64_FORMAT, offset,
9647 stream->duration);
9648
9649 stream->cslg_shift = 0;
9650 stream->ctts_present = FALSE;
9651 goto done;
9652 }
9653 }
9654
9655 /* reset the reader so we can generate sample table */
9656 gst_byte_reader_set_pos (&stream->ctts, pos);
9657 }
9658 } else {
9659 /* Ensure the cslg_shift value is consistent so we can use it
9660 * unconditionally to produce TS and Segment */
9661 stream->cslg_shift = 0;
9662 }
9663
9664 GST_DEBUG_OBJECT (qtdemux, "Using clsg_shift %" G_GUINT64_FORMAT,
9665 stream->cslg_shift);
9666
9667 /* For raw audio streams especially we might want to merge the samples
9668 * to not output one audio sample per buffer. We're doing this here
9669 * before allocating the sample tables so that from this point onwards
9670 * the number of container samples are static */
9671 if (stream->min_buffer_size > 0) {
9672 qtdemux_merge_sample_table (qtdemux, stream);
9673 }
9674
9675 done:
9676 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
9677 stream->n_samples, (guint) sizeof (QtDemuxSample),
9678 stream->n_samples * sizeof (QtDemuxSample) / (1024.0 * 1024.0));
9679
9680 if (stream->n_samples >=
9681 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample)) {
9682 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
9683 "be larger than %uMB (broken file?)", stream->n_samples,
9684 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
9685 return FALSE;
9686 }
9687
9688 g_assert (stream->samples == NULL);
9689 stream->samples = g_try_new0 (QtDemuxSample, stream->n_samples);
9690 if (!stream->samples) {
9691 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
9692 stream->n_samples);
9693 return FALSE;
9694 }
9695
9696 return TRUE;
9697
9698 corrupt_file:
9699 {
9700 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
9701 (_("This file is corrupt and cannot be played.")), (NULL));
9702 return FALSE;
9703 }
9704 no_samples:
9705 {
9706 gst_qtdemux_stbl_free (stream);
9707 if (!qtdemux->fragmented) {
9708 /* not quite good */
9709 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
9710 return FALSE;
9711 } else {
9712 /* may pick up samples elsewhere */
9713 return TRUE;
9714 }
9715 }
9716 }
9717
9718 /* collect samples from the next sample to be parsed up to sample @n for @stream
9719 * by reading the info from @stbl
9720 *
9721 * This code can be executed from both the streaming thread and the seeking
9722 * thread so it takes the object lock to protect itself
9723 */
9724 static gboolean
qtdemux_parse_samples(GstQTDemux * qtdemux,QtDemuxStream * stream,guint32 n)9725 qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream, guint32 n)
9726 {
9727 gint i, j, k;
9728 QtDemuxSample *samples, *first, *cur, *last;
9729 guint32 n_samples_per_chunk;
9730 guint32 n_samples;
9731
9732 GST_LOG_OBJECT (qtdemux, "parsing samples for stream fourcc %"
9733 GST_FOURCC_FORMAT ", pad %s",
9734 GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc),
9735 stream->pad ? GST_PAD_NAME (stream->pad) : "(NULL)");
9736
9737 n_samples = stream->n_samples;
9738
9739 if (n >= n_samples)
9740 goto out_of_samples;
9741
9742 GST_OBJECT_LOCK (qtdemux);
9743 if (n <= stream->stbl_index)
9744 goto already_parsed;
9745
9746 GST_DEBUG_OBJECT (qtdemux, "parsing up to sample %u", n);
9747
9748 if (!stream->stsz.data) {
9749 /* so we already parsed and passed all the moov samples;
9750 * onto fragmented ones */
9751 g_assert (qtdemux->fragmented);
9752 goto done;
9753 }
9754
9755 /* pointer to the sample table */
9756 samples = stream->samples;
9757
9758 /* starts from -1, moves to the next sample index to parse */
9759 stream->stbl_index++;
9760
9761 /* keep track of the first and last sample to fill */
9762 first = &samples[stream->stbl_index];
9763 last = &samples[n];
9764
9765 if (!stream->chunks_are_samples) {
9766 /* set the sample sizes */
9767 if (stream->sample_size == 0) {
9768 /* different sizes for each sample */
9769 for (cur = first; cur <= last; cur++) {
9770 cur->size = gst_byte_reader_get_uint32_be_unchecked (&stream->stsz);
9771 GST_LOG_OBJECT (qtdemux, "sample %d has size %u",
9772 (guint) (cur - samples), cur->size);
9773 }
9774 } else {
9775 /* samples have the same size */
9776 GST_LOG_OBJECT (qtdemux, "all samples have size %u", stream->sample_size);
9777 for (cur = first; cur <= last; cur++)
9778 cur->size = stream->sample_size;
9779 }
9780 }
9781
9782 n_samples_per_chunk = stream->n_samples_per_chunk;
9783 cur = first;
9784
9785 for (i = stream->stsc_index; i < n_samples_per_chunk; i++) {
9786 guint32 last_chunk;
9787
9788 if (stream->stsc_chunk_index >= stream->last_chunk
9789 || stream->stsc_chunk_index < stream->first_chunk) {
9790 stream->first_chunk =
9791 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9792 stream->samples_per_chunk =
9793 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9794 /* starts from 1 */
9795 stream->stsd_sample_description_id =
9796 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc) - 1;
9797
9798 /* chunk numbers are counted from 1 it seems */
9799 if (G_UNLIKELY (stream->first_chunk == 0))
9800 goto corrupt_file;
9801
9802 --stream->first_chunk;
9803
9804 /* the last chunk of each entry is calculated by taking the first chunk
9805 * of the next entry; except if there is no next, where we fake it with
9806 * INT_MAX */
9807 if (G_UNLIKELY (i == (stream->n_samples_per_chunk - 1))) {
9808 stream->last_chunk = G_MAXUINT32;
9809 } else {
9810 stream->last_chunk =
9811 gst_byte_reader_peek_uint32_be_unchecked (&stream->stsc);
9812 if (G_UNLIKELY (stream->last_chunk == 0))
9813 goto corrupt_file;
9814
9815 --stream->last_chunk;
9816 }
9817
9818 GST_LOG_OBJECT (qtdemux,
9819 "entry %d has first_chunk %d, last_chunk %d, samples_per_chunk %d"
9820 "sample desc ID: %d", i, stream->first_chunk, stream->last_chunk,
9821 stream->samples_per_chunk, stream->stsd_sample_description_id);
9822
9823 if (G_UNLIKELY (stream->last_chunk < stream->first_chunk))
9824 goto corrupt_file;
9825
9826 if (stream->last_chunk != G_MAXUINT32) {
9827 if (!qt_atom_parser_peek_sub (&stream->stco,
9828 stream->first_chunk * stream->co_size,
9829 (stream->last_chunk - stream->first_chunk) * stream->co_size,
9830 &stream->co_chunk))
9831 goto corrupt_file;
9832
9833 } else {
9834 stream->co_chunk = stream->stco;
9835 if (!gst_byte_reader_skip (&stream->co_chunk,
9836 stream->first_chunk * stream->co_size))
9837 goto corrupt_file;
9838 }
9839
9840 stream->stsc_chunk_index = stream->first_chunk;
9841 }
9842
9843 last_chunk = stream->last_chunk;
9844
9845 if (stream->chunks_are_samples) {
9846 cur = &samples[stream->stsc_chunk_index];
9847
9848 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
9849 if (j > n) {
9850 /* save state */
9851 stream->stsc_chunk_index = j;
9852 goto done;
9853 }
9854
9855 cur->offset =
9856 qt_atom_parser_get_offset_unchecked (&stream->co_chunk,
9857 stream->co_size);
9858
9859 GST_LOG_OBJECT (qtdemux, "Created entry %d with offset "
9860 "%" G_GUINT64_FORMAT, j, cur->offset);
9861
9862 if (CUR_STREAM (stream)->samples_per_frame > 0 &&
9863 CUR_STREAM (stream)->bytes_per_frame > 0) {
9864 cur->size =
9865 (stream->samples_per_chunk * CUR_STREAM (stream)->n_channels) /
9866 CUR_STREAM (stream)->samples_per_frame *
9867 CUR_STREAM (stream)->bytes_per_frame;
9868 } else {
9869 cur->size = stream->samples_per_chunk;
9870 }
9871
9872 GST_DEBUG_OBJECT (qtdemux,
9873 "keyframe sample %d: timestamp %" GST_TIME_FORMAT ", size %u",
9874 j, GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream,
9875 stream->stco_sample_index)), cur->size);
9876
9877 cur->timestamp = stream->stco_sample_index;
9878 cur->duration = stream->samples_per_chunk;
9879 cur->keyframe = TRUE;
9880 cur++;
9881
9882 stream->stco_sample_index += stream->samples_per_chunk;
9883 }
9884 stream->stsc_chunk_index = j;
9885 } else {
9886 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
9887 guint32 samples_per_chunk;
9888 guint64 chunk_offset;
9889
9890 if (!stream->stsc_sample_index
9891 && !qt_atom_parser_get_offset (&stream->co_chunk, stream->co_size,
9892 &stream->chunk_offset))
9893 goto corrupt_file;
9894
9895 samples_per_chunk = stream->samples_per_chunk;
9896 chunk_offset = stream->chunk_offset;
9897
9898 for (k = stream->stsc_sample_index; k < samples_per_chunk; k++) {
9899 GST_LOG_OBJECT (qtdemux, "creating entry %d with offset %"
9900 G_GUINT64_FORMAT " and size %d",
9901 (guint) (cur - samples), chunk_offset, cur->size);
9902
9903 cur->offset = chunk_offset;
9904 chunk_offset += cur->size;
9905 cur++;
9906
9907 if (G_UNLIKELY (cur > last)) {
9908 /* save state */
9909 stream->stsc_sample_index = k + 1;
9910 stream->chunk_offset = chunk_offset;
9911 stream->stsc_chunk_index = j;
9912 goto done2;
9913 }
9914 }
9915 stream->stsc_sample_index = 0;
9916 }
9917 stream->stsc_chunk_index = j;
9918 }
9919 stream->stsc_index++;
9920 }
9921
9922 if (stream->chunks_are_samples)
9923 goto ctts;
9924 done2:
9925 {
9926 guint32 n_sample_times;
9927
9928 n_sample_times = stream->n_sample_times;
9929 cur = first;
9930
9931 for (i = stream->stts_index; i < n_sample_times; i++) {
9932 guint32 stts_samples;
9933 gint32 stts_duration;
9934 gint64 stts_time;
9935
9936 if (stream->stts_sample_index >= stream->stts_samples
9937 || !stream->stts_sample_index) {
9938
9939 stream->stts_samples =
9940 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
9941 stream->stts_duration =
9942 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
9943
9944 GST_LOG_OBJECT (qtdemux, "block %d, %u timestamps, duration %u",
9945 i, stream->stts_samples, stream->stts_duration);
9946
9947 stream->stts_sample_index = 0;
9948 }
9949
9950 stts_samples = stream->stts_samples;
9951 stts_duration = stream->stts_duration;
9952 stts_time = stream->stts_time;
9953
9954 for (j = stream->stts_sample_index; j < stts_samples; j++) {
9955 GST_DEBUG_OBJECT (qtdemux,
9956 "sample %d: index %d, timestamp %" GST_TIME_FORMAT,
9957 (guint) (cur - samples), j,
9958 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stts_time)));
9959
9960 cur->timestamp = stts_time;
9961 cur->duration = stts_duration;
9962
9963 /* avoid 32-bit wrap-around,
9964 * but still mind possible 'negative' duration */
9965 stts_time += (gint64) stts_duration;
9966 cur++;
9967
9968 if (G_UNLIKELY (cur > last)) {
9969 /* save values */
9970 stream->stts_time = stts_time;
9971 stream->stts_sample_index = j + 1;
9972 if (stream->stts_sample_index >= stream->stts_samples)
9973 stream->stts_index++;
9974 goto done3;
9975 }
9976 }
9977 stream->stts_sample_index = 0;
9978 stream->stts_time = stts_time;
9979 stream->stts_index++;
9980 }
9981 /* fill up empty timestamps with the last timestamp, this can happen when
9982 * the last samples do not decode and so we don't have timestamps for them.
9983 * We however look at the last timestamp to estimate the track length so we
9984 * need something in here. */
9985 for (; cur < last; cur++) {
9986 GST_DEBUG_OBJECT (qtdemux,
9987 "fill sample %d: timestamp %" GST_TIME_FORMAT,
9988 (guint) (cur - samples),
9989 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stream->stts_time)));
9990 cur->timestamp = stream->stts_time;
9991 cur->duration = -1;
9992 }
9993 }
9994 done3:
9995 {
9996 /* sample sync, can be NULL */
9997 if (stream->stss_present == TRUE) {
9998 guint32 n_sample_syncs;
9999
10000 n_sample_syncs = stream->n_sample_syncs;
10001
10002 if (!n_sample_syncs) {
10003 GST_DEBUG_OBJECT (qtdemux, "all samples are keyframes");
10004 stream->all_keyframe = TRUE;
10005 } else {
10006 for (i = stream->stss_index; i < n_sample_syncs; i++) {
10007 /* note that the first sample is index 1, not 0 */
10008 guint32 index;
10009
10010 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stss);
10011
10012 if (G_LIKELY (index > 0 && index <= n_samples)) {
10013 index -= 1;
10014 samples[index].keyframe = TRUE;
10015 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
10016 /* and exit if we have enough samples */
10017 if (G_UNLIKELY (index >= n)) {
10018 i++;
10019 break;
10020 }
10021 }
10022 }
10023 /* save state */
10024 stream->stss_index = i;
10025 }
10026
10027 /* stps marks partial sync frames like open GOP I-Frames */
10028 if (stream->stps_present == TRUE) {
10029 guint32 n_sample_partial_syncs;
10030
10031 n_sample_partial_syncs = stream->n_sample_partial_syncs;
10032
10033 /* if there are no entries, the stss table contains the real
10034 * sync samples */
10035 if (n_sample_partial_syncs) {
10036 for (i = stream->stps_index; i < n_sample_partial_syncs; i++) {
10037 /* note that the first sample is index 1, not 0 */
10038 guint32 index;
10039
10040 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stps);
10041
10042 if (G_LIKELY (index > 0 && index <= n_samples)) {
10043 index -= 1;
10044 samples[index].keyframe = TRUE;
10045 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
10046 /* and exit if we have enough samples */
10047 if (G_UNLIKELY (index >= n)) {
10048 i++;
10049 break;
10050 }
10051 }
10052 }
10053 /* save state */
10054 stream->stps_index = i;
10055 }
10056 }
10057 } else {
10058 /* no stss, all samples are keyframes */
10059 stream->all_keyframe = TRUE;
10060 GST_DEBUG_OBJECT (qtdemux, "setting all keyframes");
10061 }
10062 }
10063
10064 ctts:
10065 /* composition time to sample */
10066 if (stream->ctts_present == TRUE) {
10067 guint32 n_composition_times;
10068 guint32 ctts_count;
10069 gint32 ctts_soffset;
10070
10071 /* Fill in the pts_offsets */
10072 cur = first;
10073 n_composition_times = stream->n_composition_times;
10074
10075 for (i = stream->ctts_index; i < n_composition_times; i++) {
10076 if (stream->ctts_sample_index >= stream->ctts_count
10077 || !stream->ctts_sample_index) {
10078 stream->ctts_count =
10079 gst_byte_reader_get_uint32_be_unchecked (&stream->ctts);
10080 stream->ctts_soffset =
10081 gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
10082 stream->ctts_sample_index = 0;
10083 }
10084
10085 ctts_count = stream->ctts_count;
10086 ctts_soffset = stream->ctts_soffset;
10087
10088 /* FIXME: Set offset to 0 for "no decode samples". This needs
10089 * to be handled in a codec specific manner ideally. */
10090 if (ctts_soffset == G_MININT32)
10091 ctts_soffset = 0;
10092
10093 for (j = stream->ctts_sample_index; j < ctts_count; j++) {
10094 cur->pts_offset = ctts_soffset;
10095 cur++;
10096
10097 if (G_UNLIKELY (cur > last)) {
10098 /* save state */
10099 stream->ctts_sample_index = j + 1;
10100 goto done;
10101 }
10102 }
10103 stream->ctts_sample_index = 0;
10104 stream->ctts_index++;
10105 }
10106 }
10107 done:
10108 stream->stbl_index = n;
10109 /* if index has been completely parsed, free data that is no-longer needed */
10110 if (n + 1 == stream->n_samples) {
10111 gst_qtdemux_stbl_free (stream);
10112 GST_DEBUG_OBJECT (qtdemux, "parsed all available samples;");
10113 if (qtdemux->pullbased) {
10114 GST_DEBUG_OBJECT (qtdemux, "checking for more samples");
10115 while (n + 1 == stream->n_samples)
10116 if (qtdemux_add_fragmented_samples (qtdemux) != GST_FLOW_OK)
10117 break;
10118 }
10119 }
10120 GST_OBJECT_UNLOCK (qtdemux);
10121
10122 return TRUE;
10123
10124 /* SUCCESS */
10125 already_parsed:
10126 {
10127 GST_LOG_OBJECT (qtdemux,
10128 "Tried to parse up to sample %u but this sample has already been parsed",
10129 n);
10130 /* if fragmented, there may be more */
10131 if (qtdemux->fragmented && n == stream->stbl_index)
10132 goto done;
10133 GST_OBJECT_UNLOCK (qtdemux);
10134 return TRUE;
10135 }
10136 /* ERRORS */
10137 out_of_samples:
10138 {
10139 GST_LOG_OBJECT (qtdemux,
10140 "Tried to parse up to sample %u but there are only %u samples", n + 1,
10141 stream->n_samples);
10142 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
10143 (_("This file is corrupt and cannot be played.")), (NULL));
10144 return FALSE;
10145 }
10146 corrupt_file:
10147 {
10148 GST_OBJECT_UNLOCK (qtdemux);
10149 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
10150 (_("This file is corrupt and cannot be played.")), (NULL));
10151 return FALSE;
10152 }
10153 }
10154
10155 /* collect all segment info for @stream.
10156 */
10157 static gboolean
qtdemux_parse_segments(GstQTDemux * qtdemux,QtDemuxStream * stream,GNode * trak)10158 qtdemux_parse_segments (GstQTDemux * qtdemux, QtDemuxStream * stream,
10159 GNode * trak)
10160 {
10161 GNode *edts;
10162 /* accept edts if they contain gaps at start and there is only
10163 * one media segment */
10164 gboolean allow_pushbased_edts = TRUE;
10165 gint media_segments_count = 0;
10166
10167 /* parse and prepare segment info from the edit list */
10168 GST_DEBUG_OBJECT (qtdemux, "looking for edit list container");
10169 stream->n_segments = 0;
10170 stream->segments = NULL;
10171 if ((edts = qtdemux_tree_get_child_by_type (trak, FOURCC_edts))) {
10172 GNode *elst;
10173 gint n_segments;
10174 gint segment_number, entry_size;
10175 guint64 time;
10176 GstClockTime stime;
10177 const guint8 *buffer;
10178 guint8 version;
10179 guint32 size;
10180
10181 GST_DEBUG_OBJECT (qtdemux, "looking for edit list");
10182 if (!(elst = qtdemux_tree_get_child_by_type (edts, FOURCC_elst)))
10183 goto done;
10184
10185 buffer = elst->data;
10186
10187 size = QT_UINT32 (buffer);
10188 /* version, flags, n_segments */
10189 if (size < 16) {
10190 GST_WARNING_OBJECT (qtdemux, "Invalid edit list");
10191 goto done;
10192 }
10193 version = QT_UINT8 (buffer + 8);
10194 entry_size = (version == 1) ? 20 : 12;
10195
10196 n_segments = QT_UINT32 (buffer + 12);
10197
10198 if (n_segments > 100000 || size < 16 + n_segments * entry_size) {
10199 GST_WARNING_OBJECT (qtdemux, "Invalid edit list");
10200 goto done;
10201 }
10202
10203 /* we might allocate a bit too much, at least allocate 1 segment */
10204 stream->segments = g_new (QtDemuxSegment, MAX (n_segments, 1));
10205
10206 /* segments always start from 0 */
10207 time = 0;
10208 stime = 0;
10209 buffer += 16;
10210 for (segment_number = 0; segment_number < n_segments; segment_number++) {
10211 guint64 duration;
10212 guint64 media_time;
10213 gboolean empty_edit = FALSE;
10214 QtDemuxSegment *segment;
10215 guint32 rate_int;
10216 GstClockTime media_start = GST_CLOCK_TIME_NONE;
10217
10218 if (version == 1) {
10219 media_time = QT_UINT64 (buffer + 8);
10220 duration = QT_UINT64 (buffer);
10221 if (media_time == G_MAXUINT64)
10222 empty_edit = TRUE;
10223 } else {
10224 media_time = QT_UINT32 (buffer + 4);
10225 duration = QT_UINT32 (buffer);
10226 if (media_time == G_MAXUINT32)
10227 empty_edit = TRUE;
10228 }
10229
10230 if (!empty_edit)
10231 media_start = QTSTREAMTIME_TO_GSTTIME (stream, media_time);
10232
10233 segment = &stream->segments[segment_number];
10234
10235 /* time and duration expressed in global timescale */
10236 segment->time = stime;
10237 if (duration != 0 || empty_edit) {
10238 /* edge case: empty edits with duration=zero are treated here.
10239 * (files should not have these anyway). */
10240
10241 /* add non scaled values so we don't cause roundoff errors */
10242 time += duration;
10243 stime = QTTIME_TO_GSTTIME (qtdemux, time);
10244 segment->duration = stime - segment->time;
10245 } else {
10246 /* zero duration does not imply media_start == media_stop
10247 * but, only specify media_start. The edit ends with the track. */
10248 stime = segment->duration = GST_CLOCK_TIME_NONE;
10249 /* Don't allow more edits after this one. */
10250 n_segments = segment_number + 1;
10251 }
10252 segment->stop_time = stime;
10253
10254 segment->trak_media_start = media_time;
10255 /* media_time expressed in stream timescale */
10256 if (!empty_edit) {
10257 segment->media_start = media_start;
10258 segment->media_stop = GST_CLOCK_TIME_IS_VALID (segment->duration)
10259 ? segment->media_start + segment->duration : GST_CLOCK_TIME_NONE;
10260 media_segments_count++;
10261 } else {
10262 segment->media_start = GST_CLOCK_TIME_NONE;
10263 segment->media_stop = GST_CLOCK_TIME_NONE;
10264 }
10265 rate_int = QT_UINT32 (buffer + ((version == 1) ? 16 : 8));
10266
10267 if (rate_int <= 1) {
10268 /* 0 is not allowed, some programs write 1 instead of the floating point
10269 * value */
10270 GST_WARNING_OBJECT (qtdemux, "found suspicious rate %" G_GUINT32_FORMAT,
10271 rate_int);
10272 segment->rate = 1;
10273 } else {
10274 segment->rate = rate_int / 65536.0;
10275 }
10276
10277 GST_DEBUG_OBJECT (qtdemux, "created segment %d time %" GST_TIME_FORMAT
10278 ", duration %" GST_TIME_FORMAT ", media_start %" GST_TIME_FORMAT
10279 " (%" G_GUINT64_FORMAT ") , media_stop %" GST_TIME_FORMAT
10280 " stop_time %" GST_TIME_FORMAT " rate %g, (%d) timescale %u",
10281 segment_number, GST_TIME_ARGS (segment->time),
10282 GST_TIME_ARGS (segment->duration),
10283 GST_TIME_ARGS (segment->media_start), media_time,
10284 GST_TIME_ARGS (segment->media_stop),
10285 GST_TIME_ARGS (segment->stop_time), segment->rate, rate_int,
10286 stream->timescale);
10287 if (segment->stop_time > qtdemux->segment.stop &&
10288 !qtdemux->upstream_format_is_time) {
10289 GST_WARNING_OBJECT (qtdemux, "Segment %d "
10290 " extends to %" GST_TIME_FORMAT
10291 " past the end of the declared movie duration %" GST_TIME_FORMAT
10292 " movie segment will be extended", segment_number,
10293 GST_TIME_ARGS (segment->stop_time),
10294 GST_TIME_ARGS (qtdemux->segment.stop));
10295 qtdemux->segment.stop = qtdemux->segment.duration = segment->stop_time;
10296 }
10297
10298 buffer += entry_size;
10299 }
10300 GST_DEBUG_OBJECT (qtdemux, "found %d segments", n_segments);
10301 stream->n_segments = n_segments;
10302 if (media_segments_count != 1)
10303 allow_pushbased_edts = FALSE;
10304 }
10305 done:
10306
10307 /* push based does not handle segments, so act accordingly here,
10308 * and warn if applicable */
10309 if (!qtdemux->pullbased && !allow_pushbased_edts) {
10310 GST_WARNING_OBJECT (qtdemux, "streaming; discarding edit list segments");
10311 /* remove and use default one below, we stream like it anyway */
10312 g_free (stream->segments);
10313 stream->segments = NULL;
10314 stream->n_segments = 0;
10315 }
10316
10317 /* no segments, create one to play the complete trak */
10318 if (stream->n_segments == 0) {
10319 GstClockTime stream_duration =
10320 QTSTREAMTIME_TO_GSTTIME (stream, stream->duration);
10321
10322 if (stream->segments == NULL)
10323 stream->segments = g_new (QtDemuxSegment, 1);
10324
10325 /* represent unknown our way */
10326 if (stream_duration == 0)
10327 stream_duration = GST_CLOCK_TIME_NONE;
10328
10329 stream->segments[0].time = 0;
10330 stream->segments[0].stop_time = stream_duration;
10331 stream->segments[0].duration = stream_duration;
10332 stream->segments[0].media_start = 0;
10333 stream->segments[0].media_stop = stream_duration;
10334 stream->segments[0].rate = 1.0;
10335 stream->segments[0].trak_media_start = 0;
10336
10337 GST_DEBUG_OBJECT (qtdemux, "created dummy segment %" GST_TIME_FORMAT,
10338 GST_TIME_ARGS (stream_duration));
10339 stream->n_segments = 1;
10340 stream->dummy_segment = TRUE;
10341 }
10342 GST_DEBUG_OBJECT (qtdemux, "using %d segments", stream->n_segments);
10343
10344 return TRUE;
10345 }
10346
10347 /*
10348 * Parses the stsd atom of a svq3 trak looking for
10349 * the SMI and gama atoms.
10350 */
10351 static void
qtdemux_parse_svq3_stsd_data(GstQTDemux * qtdemux,const guint8 * stsd_entry_data,const guint8 ** gamma,GstBuffer ** seqh)10352 qtdemux_parse_svq3_stsd_data (GstQTDemux * qtdemux,
10353 const guint8 * stsd_entry_data, const guint8 ** gamma, GstBuffer ** seqh)
10354 {
10355 const guint8 *_gamma = NULL;
10356 GstBuffer *_seqh = NULL;
10357 const guint8 *stsd_data = stsd_entry_data;
10358 guint32 length = QT_UINT32 (stsd_data);
10359 guint16 version;
10360
10361 if (length < 32) {
10362 GST_WARNING_OBJECT (qtdemux, "stsd too short");
10363 goto end;
10364 }
10365
10366 stsd_data += 16;
10367 length -= 16;
10368 version = QT_UINT16 (stsd_data);
10369 if (version == 3) {
10370 if (length >= 70) {
10371 length -= 70;
10372 stsd_data += 70;
10373 while (length > 8) {
10374 guint32 fourcc, size;
10375 const guint8 *data;
10376 size = QT_UINT32 (stsd_data);
10377 fourcc = QT_FOURCC (stsd_data + 4);
10378 data = stsd_data + 8;
10379
10380 if (size == 0) {
10381 GST_WARNING_OBJECT (qtdemux, "Atom of size 0 found, aborting "
10382 "svq3 atom parsing");
10383 goto end;
10384 }
10385
10386 switch (fourcc) {
10387 case FOURCC_gama:{
10388 if (size == 12) {
10389 _gamma = data;
10390 } else {
10391 GST_WARNING_OBJECT (qtdemux, "Unexpected size %" G_GUINT32_FORMAT
10392 " for gama atom, expected 12", size);
10393 }
10394 break;
10395 }
10396 case FOURCC_SMI_:{
10397 if (size > 16 && QT_FOURCC (data) == FOURCC_SEQH) {
10398 guint32 seqh_size;
10399 if (_seqh != NULL) {
10400 GST_WARNING_OBJECT (qtdemux, "Unexpected second SEQH SMI atom "
10401 " found, ignoring");
10402 } else {
10403 seqh_size = QT_UINT32 (data + 4);
10404 if (seqh_size > 0) {
10405 _seqh = gst_buffer_new_and_alloc (seqh_size);
10406 gst_buffer_fill (_seqh, 0, data + 8, seqh_size);
10407 }
10408 }
10409 }
10410 break;
10411 }
10412 default:{
10413 GST_WARNING_OBJECT (qtdemux, "Unhandled atom %" GST_FOURCC_FORMAT
10414 " in SVQ3 entry in stsd atom", GST_FOURCC_ARGS (fourcc));
10415 }
10416 }
10417
10418 if (size <= length) {
10419 length -= size;
10420 stsd_data += size;
10421 }
10422 }
10423 } else {
10424 GST_WARNING_OBJECT (qtdemux, "SVQ3 entry too short in stsd atom");
10425 }
10426 } else {
10427 GST_WARNING_OBJECT (qtdemux, "Unexpected version for SVQ3 entry %"
10428 G_GUINT16_FORMAT, version);
10429 goto end;
10430 }
10431
10432 end:
10433 if (gamma) {
10434 *gamma = _gamma;
10435 }
10436 if (seqh) {
10437 *seqh = _seqh;
10438 } else if (_seqh) {
10439 gst_buffer_unref (_seqh);
10440 }
10441 }
10442
10443 static gchar *
qtdemux_get_rtsp_uri_from_hndl(GstQTDemux * qtdemux,GNode * minf)10444 qtdemux_get_rtsp_uri_from_hndl (GstQTDemux * qtdemux, GNode * minf)
10445 {
10446 GNode *dinf;
10447 GstByteReader dref;
10448 gchar *uri = NULL;
10449
10450 /*
10451 * Get 'dinf', to get its child 'dref', that might contain a 'hndl'
10452 * atom that might contain a 'data' atom with the rtsp uri.
10453 * This case was reported in bug #597497, some info about
10454 * the hndl atom can be found in TN1195
10455 */
10456 dinf = qtdemux_tree_get_child_by_type (minf, FOURCC_dinf);
10457 GST_DEBUG_OBJECT (qtdemux, "Trying to obtain rtsp URI for stream trak");
10458
10459 if (dinf) {
10460 guint32 dref_num_entries = 0;
10461 if (qtdemux_tree_get_child_by_type_full (dinf, FOURCC_dref, &dref) &&
10462 gst_byte_reader_skip (&dref, 4) &&
10463 gst_byte_reader_get_uint32_be (&dref, &dref_num_entries)) {
10464 gint i;
10465
10466 /* search dref entries for hndl atom */
10467 for (i = 0; i < dref_num_entries; i++) {
10468 guint32 size = 0, type;
10469 guint8 string_len = 0;
10470 if (gst_byte_reader_get_uint32_be (&dref, &size) &&
10471 qt_atom_parser_get_fourcc (&dref, &type)) {
10472 if (type == FOURCC_hndl) {
10473 GST_DEBUG_OBJECT (qtdemux, "Found hndl atom");
10474
10475 /* skip data reference handle bytes and the
10476 * following pascal string and some extra 4
10477 * bytes I have no idea what are */
10478 if (!gst_byte_reader_skip (&dref, 4) ||
10479 !gst_byte_reader_get_uint8 (&dref, &string_len) ||
10480 !gst_byte_reader_skip (&dref, string_len + 4)) {
10481 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl atom");
10482 break;
10483 }
10484
10485 /* iterate over the atoms to find the data atom */
10486 while (gst_byte_reader_get_remaining (&dref) >= 8) {
10487 guint32 atom_size;
10488 guint32 atom_type;
10489
10490 if (gst_byte_reader_get_uint32_be (&dref, &atom_size) &&
10491 qt_atom_parser_get_fourcc (&dref, &atom_type)) {
10492 if (atom_type == FOURCC_data) {
10493 const guint8 *uri_aux = NULL;
10494
10495 /* found the data atom that might contain the rtsp uri */
10496 GST_DEBUG_OBJECT (qtdemux, "Found data atom inside "
10497 "hndl atom, interpreting it as an URI");
10498 if (gst_byte_reader_peek_data (&dref, atom_size - 8,
10499 &uri_aux)) {
10500 if (g_strstr_len ((gchar *) uri_aux, 7, "rtsp://") != NULL)
10501 uri = g_strndup ((gchar *) uri_aux, atom_size - 8);
10502 else
10503 GST_WARNING_OBJECT (qtdemux, "Data atom in hndl atom "
10504 "didn't contain a rtsp address");
10505 } else {
10506 GST_WARNING_OBJECT (qtdemux, "Failed to get the data "
10507 "atom contents");
10508 }
10509 break;
10510 }
10511 /* skipping to the next entry */
10512 if (!gst_byte_reader_skip (&dref, atom_size - 8))
10513 break;
10514 } else {
10515 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl child "
10516 "atom header");
10517 break;
10518 }
10519 }
10520 break;
10521 }
10522 /* skip to the next entry */
10523 if (!gst_byte_reader_skip (&dref, size - 8))
10524 break;
10525 } else {
10526 GST_WARNING_OBJECT (qtdemux, "Error parsing dref atom");
10527 }
10528 }
10529 GST_DEBUG_OBJECT (qtdemux, "Finished parsing dref atom");
10530 }
10531 }
10532 return uri;
10533 }
10534
10535 #define AMR_NB_ALL_MODES 0x81ff
10536 #define AMR_WB_ALL_MODES 0x83ff
10537 static guint
qtdemux_parse_amr_bitrate(GstBuffer * buf,gboolean wb)10538 qtdemux_parse_amr_bitrate (GstBuffer * buf, gboolean wb)
10539 {
10540 /* The 'damr' atom is of the form:
10541 *
10542 * | vendor | decoder_ver | mode_set | mode_change_period | frames/sample |
10543 * 32 b 8 b 16 b 8 b 8 b
10544 *
10545 * The highest set bit of the first 7 (AMR-NB) or 8 (AMR-WB) bits of mode_set
10546 * represents the highest mode used in the stream (and thus the maximum
10547 * bitrate), with a couple of special cases as seen below.
10548 */
10549
10550 /* Map of frame type ID -> bitrate */
10551 static const guint nb_bitrates[] = {
10552 4750, 5150, 5900, 6700, 7400, 7950, 10200, 12200
10553 };
10554 static const guint wb_bitrates[] = {
10555 6600, 8850, 12650, 14250, 15850, 18250, 19850, 23050, 23850
10556 };
10557 GstMapInfo map;
10558 gsize max_mode;
10559 guint16 mode_set;
10560
10561 gst_buffer_map (buf, &map, GST_MAP_READ);
10562
10563 if (map.size != 0x11) {
10564 GST_DEBUG ("Atom should have size 0x11, not %" G_GSIZE_FORMAT, map.size);
10565 goto bad_data;
10566 }
10567
10568 if (QT_FOURCC (map.data + 4) != FOURCC_damr) {
10569 GST_DEBUG ("Unknown atom in %" GST_FOURCC_FORMAT,
10570 GST_FOURCC_ARGS (QT_UINT32 (map.data + 4)));
10571 goto bad_data;
10572 }
10573
10574 mode_set = QT_UINT16 (map.data + 13);
10575
10576 if (mode_set == (wb ? AMR_WB_ALL_MODES : AMR_NB_ALL_MODES))
10577 max_mode = 7 + (wb ? 1 : 0);
10578 else
10579 /* AMR-NB modes fo from 0-7, and AMR-WB modes go from 0-8 */
10580 max_mode = g_bit_nth_msf ((gulong) mode_set & (wb ? 0x1ff : 0xff), -1);
10581
10582 if (max_mode == -1) {
10583 GST_DEBUG ("No mode indication was found (mode set) = %x",
10584 (guint) mode_set);
10585 goto bad_data;
10586 }
10587
10588 gst_buffer_unmap (buf, &map);
10589 return wb ? wb_bitrates[max_mode] : nb_bitrates[max_mode];
10590
10591 bad_data:
10592 gst_buffer_unmap (buf, &map);
10593 return 0;
10594 }
10595
10596 static gboolean
qtdemux_parse_transformation_matrix(GstQTDemux * qtdemux,GstByteReader * reader,guint32 * matrix,const gchar * atom)10597 qtdemux_parse_transformation_matrix (GstQTDemux * qtdemux,
10598 GstByteReader * reader, guint32 * matrix, const gchar * atom)
10599 {
10600 /*
10601 * 9 values of 32 bits (fixed point 16.16, except 2 5 and 8 that are 2.30)
10602 * [0 1 2]
10603 * [3 4 5]
10604 * [6 7 8]
10605 */
10606
10607 if (gst_byte_reader_get_remaining (reader) < 36)
10608 return FALSE;
10609
10610 matrix[0] = gst_byte_reader_get_uint32_be_unchecked (reader);
10611 matrix[1] = gst_byte_reader_get_uint32_be_unchecked (reader);
10612 matrix[2] = gst_byte_reader_get_uint32_be_unchecked (reader);
10613 matrix[3] = gst_byte_reader_get_uint32_be_unchecked (reader);
10614 matrix[4] = gst_byte_reader_get_uint32_be_unchecked (reader);
10615 matrix[5] = gst_byte_reader_get_uint32_be_unchecked (reader);
10616 matrix[6] = gst_byte_reader_get_uint32_be_unchecked (reader);
10617 matrix[7] = gst_byte_reader_get_uint32_be_unchecked (reader);
10618 matrix[8] = gst_byte_reader_get_uint32_be_unchecked (reader);
10619
10620 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix from atom %s", atom);
10621 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[0] >> 16,
10622 matrix[0] & 0xFFFF, matrix[1] >> 16, matrix[1] & 0xFF, matrix[2] >> 16,
10623 matrix[2] & 0xFF);
10624 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[3] >> 16,
10625 matrix[3] & 0xFFFF, matrix[4] >> 16, matrix[4] & 0xFF, matrix[5] >> 16,
10626 matrix[5] & 0xFF);
10627 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[6] >> 16,
10628 matrix[6] & 0xFFFF, matrix[7] >> 16, matrix[7] & 0xFF, matrix[8] >> 16,
10629 matrix[8] & 0xFF);
10630
10631 return TRUE;
10632 }
10633
10634 static void
qtdemux_inspect_transformation_matrix(GstQTDemux * qtdemux,QtDemuxStream * stream,guint32 * matrix,GstTagList ** taglist)10635 qtdemux_inspect_transformation_matrix (GstQTDemux * qtdemux,
10636 QtDemuxStream * stream, guint32 * matrix, GstTagList ** taglist)
10637 {
10638
10639 /* [a b c]
10640 * [d e f]
10641 * [g h i]
10642 *
10643 * This macro will only compare value abdegh, it expects cfi to have already
10644 * been checked
10645 */
10646 #define QTCHECK_MATRIX(m,a,b,d,e) ((m)[0] == (a << 16) && (m)[1] == (b << 16) && \
10647 (m)[3] == (d << 16) && (m)[4] == (e << 16))
10648
10649 /* only handle the cases where the last column has standard values */
10650 if (matrix[2] == 0 && matrix[5] == 0 && matrix[8] == 1 << 30) {
10651 const gchar *rotation_tag = NULL;
10652
10653 /* no rotation needed */
10654 if (QTCHECK_MATRIX (matrix, 1, 0, 0, 1)) {
10655 /* NOP */
10656 } else if (QTCHECK_MATRIX (matrix, 0, 1, G_MAXUINT16, 0)) {
10657 rotation_tag = "rotate-90";
10658 } else if (QTCHECK_MATRIX (matrix, G_MAXUINT16, 0, 0, G_MAXUINT16)) {
10659 rotation_tag = "rotate-180";
10660 } else if (QTCHECK_MATRIX (matrix, 0, G_MAXUINT16, 1, 0)) {
10661 rotation_tag = "rotate-270";
10662 } else {
10663 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
10664 }
10665
10666 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix rotation %s",
10667 GST_STR_NULL (rotation_tag));
10668 if (rotation_tag != NULL) {
10669 if (*taglist == NULL)
10670 *taglist = gst_tag_list_new_empty ();
10671 gst_tag_list_add (*taglist, GST_TAG_MERGE_REPLACE,
10672 GST_TAG_IMAGE_ORIENTATION, rotation_tag, NULL);
10673 #ifdef OHOS_EXT_FUNC
10674 // ohos.ext.func.0032
10675 GstMessage *msg_video_rotation = gst_message_new_video_rotation (GST_OBJECT (qtdemux), rotation_tag);
10676 if (msg_video_rotation != NULL) {
10677 gst_element_post_message (GST_ELEMENT (qtdemux), msg_video_rotation);
10678 }
10679 #endif
10680 }
10681 } else {
10682 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
10683 }
10684 }
10685
10686 static gboolean
qtdemux_parse_protection_aavd(GstQTDemux * qtdemux,QtDemuxStream * stream,GNode * container,guint32 * original_fmt)10687 qtdemux_parse_protection_aavd (GstQTDemux * qtdemux,
10688 QtDemuxStream * stream, GNode * container, guint32 * original_fmt)
10689 {
10690 GNode *adrm;
10691 guint32 adrm_size;
10692 GstBuffer *adrm_buf = NULL;
10693 QtDemuxAavdEncryptionInfo *info;
10694
10695 adrm = qtdemux_tree_get_child_by_type (container, FOURCC_adrm);
10696 if (G_UNLIKELY (!adrm)) {
10697 GST_ERROR_OBJECT (qtdemux, "aavd box does not contain mandatory adrm box");
10698 return FALSE;
10699 }
10700 adrm_size = QT_UINT32 (adrm->data);
10701 adrm_buf = gst_buffer_new_memdup (adrm->data, adrm_size);
10702
10703 stream->protection_scheme_type = FOURCC_aavd;
10704
10705 if (!stream->protection_scheme_info)
10706 stream->protection_scheme_info = g_new0 (QtDemuxAavdEncryptionInfo, 1);
10707
10708 info = (QtDemuxAavdEncryptionInfo *) stream->protection_scheme_info;
10709
10710 if (info->default_properties)
10711 gst_structure_free (info->default_properties);
10712 info->default_properties = gst_structure_new ("application/x-aavd",
10713 "encrypted", G_TYPE_BOOLEAN, TRUE,
10714 "adrm", GST_TYPE_BUFFER, adrm_buf, NULL);
10715 gst_buffer_unref (adrm_buf);
10716
10717 *original_fmt = FOURCC_mp4a;
10718 return TRUE;
10719 }
10720
10721 /* Parses the boxes defined in ISO/IEC 14496-12 that enable support for
10722 * protected streams (sinf, frma, schm and schi); if the protection scheme is
10723 * Common Encryption (cenc), the function will also parse the tenc box (defined
10724 * in ISO/IEC 23001-7). @container points to the node that contains these boxes
10725 * (typically an enc[v|a|t|s] sample entry); the function will set
10726 * @original_fmt to the fourcc of the original unencrypted stream format.
10727 * Returns TRUE if successful; FALSE otherwise. */
10728 static gboolean
qtdemux_parse_protection_scheme_info(GstQTDemux * qtdemux,QtDemuxStream * stream,GNode * container,guint32 * original_fmt)10729 qtdemux_parse_protection_scheme_info (GstQTDemux * qtdemux,
10730 QtDemuxStream * stream, GNode * container, guint32 * original_fmt)
10731 {
10732 GNode *sinf;
10733 GNode *frma;
10734 GNode *schm;
10735 GNode *schi;
10736 QtDemuxCencSampleSetInfo *info;
10737 GNode *tenc;
10738 const guint8 *tenc_data;
10739
10740 g_return_val_if_fail (qtdemux != NULL, FALSE);
10741 g_return_val_if_fail (stream != NULL, FALSE);
10742 g_return_val_if_fail (container != NULL, FALSE);
10743 g_return_val_if_fail (original_fmt != NULL, FALSE);
10744
10745 sinf = qtdemux_tree_get_child_by_type (container, FOURCC_sinf);
10746 if (G_UNLIKELY (!sinf)) {
10747 if (stream->protection_scheme_type == FOURCC_cenc
10748 || stream->protection_scheme_type == FOURCC_cbcs) {
10749 GST_ERROR_OBJECT (qtdemux, "sinf box does not contain schi box, which is "
10750 "mandatory for Common Encryption");
10751 return FALSE;
10752 }
10753 return TRUE;
10754 }
10755
10756 frma = qtdemux_tree_get_child_by_type (sinf, FOURCC_frma);
10757 if (G_UNLIKELY (!frma)) {
10758 GST_ERROR_OBJECT (qtdemux, "sinf box does not contain mandatory frma box");
10759 return FALSE;
10760 }
10761
10762 *original_fmt = QT_FOURCC ((const guint8 *) frma->data + 8);
10763 GST_DEBUG_OBJECT (qtdemux, "original stream format: '%" GST_FOURCC_FORMAT "'",
10764 GST_FOURCC_ARGS (*original_fmt));
10765
10766 schm = qtdemux_tree_get_child_by_type (sinf, FOURCC_schm);
10767 if (!schm) {
10768 GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schm box");
10769 return FALSE;
10770 }
10771 stream->protection_scheme_type = QT_FOURCC ((const guint8 *) schm->data + 12);
10772 stream->protection_scheme_version =
10773 QT_UINT32 ((const guint8 *) schm->data + 16);
10774
10775 GST_DEBUG_OBJECT (qtdemux,
10776 "protection_scheme_type: %" GST_FOURCC_FORMAT ", "
10777 "protection_scheme_version: %#010x",
10778 GST_FOURCC_ARGS (stream->protection_scheme_type),
10779 stream->protection_scheme_version);
10780
10781 schi = qtdemux_tree_get_child_by_type (sinf, FOURCC_schi);
10782 if (!schi) {
10783 GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schi box");
10784 return FALSE;
10785 }
10786 if (stream->protection_scheme_type != FOURCC_cenc &&
10787 stream->protection_scheme_type != FOURCC_piff &&
10788 stream->protection_scheme_type != FOURCC_cbcs) {
10789 GST_ERROR_OBJECT (qtdemux,
10790 "Invalid protection_scheme_type: %" GST_FOURCC_FORMAT,
10791 GST_FOURCC_ARGS (stream->protection_scheme_type));
10792 return FALSE;
10793 }
10794
10795 if (G_UNLIKELY (!stream->protection_scheme_info))
10796 stream->protection_scheme_info =
10797 g_malloc0 (sizeof (QtDemuxCencSampleSetInfo));
10798
10799 info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
10800
10801 if (stream->protection_scheme_type == FOURCC_cenc
10802 || stream->protection_scheme_type == FOURCC_cbcs) {
10803 guint8 is_encrypted;
10804 guint8 iv_size;
10805 guint8 constant_iv_size = 0;
10806 const guint8 *default_kid;
10807 guint8 crypt_byte_block = 0;
10808 guint8 skip_byte_block = 0;
10809 const guint8 *constant_iv = NULL;
10810
10811 tenc = qtdemux_tree_get_child_by_type (schi, FOURCC_tenc);
10812 if (!tenc) {
10813 GST_ERROR_OBJECT (qtdemux, "schi box does not contain tenc box, "
10814 "which is mandatory for Common Encryption");
10815 return FALSE;
10816 }
10817 tenc_data = (const guint8 *) tenc->data + 12;
10818 is_encrypted = QT_UINT8 (tenc_data + 2);
10819 iv_size = QT_UINT8 (tenc_data + 3);
10820 default_kid = (tenc_data + 4);
10821 if (stream->protection_scheme_type == FOURCC_cbcs) {
10822 guint8 possible_pattern_info;
10823 if (iv_size == 0) {
10824 constant_iv_size = QT_UINT8 (tenc_data + 20);
10825 if (constant_iv_size != 8 && constant_iv_size != 16) {
10826 GST_ERROR_OBJECT (qtdemux,
10827 "constant IV size should be 8 or 16, not %hhu", constant_iv_size);
10828 return FALSE;
10829 }
10830 constant_iv = (tenc_data + 21);
10831 }
10832 possible_pattern_info = QT_UINT8 (tenc_data + 1);
10833 crypt_byte_block = (possible_pattern_info >> 4) & 0x0f;
10834 skip_byte_block = possible_pattern_info & 0x0f;
10835 }
10836 qtdemux_update_default_sample_cenc_settings (qtdemux, info,
10837 is_encrypted, stream->protection_scheme_type, iv_size, default_kid,
10838 crypt_byte_block, skip_byte_block, constant_iv_size, constant_iv);
10839 } else if (stream->protection_scheme_type == FOURCC_piff) {
10840 GstByteReader br;
10841 static const guint8 piff_track_encryption_uuid[] = {
10842 0x89, 0x74, 0xdb, 0xce, 0x7b, 0xe7, 0x4c, 0x51,
10843 0x84, 0xf9, 0x71, 0x48, 0xf9, 0x88, 0x25, 0x54
10844 };
10845
10846 tenc = qtdemux_tree_get_child_by_type (schi, FOURCC_uuid);
10847 if (!tenc) {
10848 GST_ERROR_OBJECT (qtdemux, "schi box does not contain tenc box, "
10849 "which is mandatory for Common Encryption");
10850 return FALSE;
10851 }
10852
10853 tenc_data = (const guint8 *) tenc->data + 8;
10854 if (memcmp (tenc_data, piff_track_encryption_uuid, 16) != 0) {
10855 gchar *box_uuid = qtdemux_uuid_bytes_to_string (tenc_data);
10856 GST_ERROR_OBJECT (qtdemux,
10857 "Unsupported track encryption box with uuid: %s", box_uuid);
10858 g_free (box_uuid);
10859 return FALSE;
10860 }
10861 tenc_data = (const guint8 *) tenc->data + 16 + 12;
10862 gst_byte_reader_init (&br, tenc_data, 20);
10863 if (!qtdemux_update_default_piff_encryption_settings (qtdemux, info, &br)) {
10864 GST_ERROR_OBJECT (qtdemux, "PIFF track box parsing error");
10865 return FALSE;
10866 }
10867 stream->protection_scheme_type = FOURCC_cenc;
10868 }
10869
10870 return TRUE;
10871 }
10872
10873 static gint
qtdemux_track_id_compare_func(QtDemuxStream ** stream1,QtDemuxStream ** stream2)10874 qtdemux_track_id_compare_func (QtDemuxStream ** stream1,
10875 QtDemuxStream ** stream2)
10876 {
10877 return (gint) (*stream1)->track_id - (gint) (*stream2)->track_id;
10878 }
10879
10880 static gboolean
qtdemux_parse_stereo_svmi_atom(GstQTDemux * qtdemux,QtDemuxStream * stream,GNode * stbl)10881 qtdemux_parse_stereo_svmi_atom (GstQTDemux * qtdemux, QtDemuxStream * stream,
10882 GNode * stbl)
10883 {
10884 GNode *svmi;
10885
10886 /*parse svmi header if existing */
10887 svmi = qtdemux_tree_get_child_by_type (stbl, FOURCC_svmi);
10888 if (svmi) {
10889 guint len = QT_UINT32 ((guint8 *) svmi->data);
10890 guint32 version = QT_UINT32 ((guint8 *) svmi->data + 8);
10891 if (!version) {
10892 GstVideoMultiviewMode mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
10893 GstVideoMultiviewFlags flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
10894 guint8 frame_type, frame_layout;
10895 guint32 stereo_mono_change_count;
10896
10897 if (len < 18)
10898 return FALSE;
10899
10900 /* MPEG-A stereo video */
10901 if (qtdemux->major_brand == FOURCC_ss02)
10902 flags |= GST_VIDEO_MULTIVIEW_FLAGS_MIXED_MONO;
10903
10904 frame_type = QT_UINT8 ((guint8 *) svmi->data + 12);
10905 frame_layout = QT_UINT8 ((guint8 *) svmi->data + 13) & 0x01;
10906 stereo_mono_change_count = QT_UINT32 ((guint8 *) svmi->data + 14);
10907
10908 switch (frame_type) {
10909 case 0:
10910 mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
10911 break;
10912 case 1:
10913 mode = GST_VIDEO_MULTIVIEW_MODE_ROW_INTERLEAVED;
10914 break;
10915 case 2:
10916 mode = GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME;
10917 break;
10918 case 3:
10919 /* mode 3 is primary/secondary view sequence, ie
10920 * left/right views in separate tracks. See section 7.2
10921 * of ISO/IEC 23000-11:2009 */
10922 /* In the future this might be supported using related
10923 * streams, like an enhancement track - if files like this
10924 * ever exist */
10925 GST_FIXME_OBJECT (qtdemux,
10926 "Implement stereo video in separate streams");
10927 }
10928
10929 if ((frame_layout & 0x1) == 0)
10930 flags |= GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
10931
10932 GST_LOG_OBJECT (qtdemux,
10933 "StereoVideo: composition type: %u, is_left_first: %u",
10934 frame_type, frame_layout);
10935
10936 if (stereo_mono_change_count > 1) {
10937 GST_FIXME_OBJECT (qtdemux,
10938 "Mixed-mono flags are not yet supported in qtdemux.");
10939 }
10940
10941 stream->multiview_mode = mode;
10942 stream->multiview_flags = flags;
10943 }
10944 }
10945
10946 return TRUE;
10947 }
10948
10949 /* parse the traks.
10950 * With each track we associate a new QtDemuxStream that contains all the info
10951 * about the trak.
10952 * traks that do not decode to something (like strm traks) will not have a pad.
10953 */
10954 static gboolean
qtdemux_parse_trak(GstQTDemux * qtdemux,GNode * trak)10955 qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
10956 {
10957 GstByteReader tkhd;
10958 int offset;
10959 GNode *mdia;
10960 GNode *mdhd;
10961 GNode *hdlr;
10962 GNode *minf;
10963 GNode *stbl;
10964 GNode *stsd;
10965 GNode *mp4a;
10966 GNode *mp4v;
10967 GNode *esds;
10968 GNode *tref;
10969 GNode *udta;
10970
10971 QtDemuxStream *stream = NULL;
10972 const guint8 *stsd_data;
10973 const guint8 *stsd_entry_data;
10974 guint remaining_stsd_len;
10975 guint stsd_entry_count;
10976 guint stsd_index;
10977 guint16 lang_code; /* quicktime lang code or packed iso code */
10978 guint32 version;
10979 guint32 tkhd_flags = 0;
10980 guint8 tkhd_version = 0;
10981 guint32 w = 0, h = 0;
10982 guint value_size, stsd_len, len;
10983 guint32 track_id;
10984 guint32 dummy;
10985
10986 GST_DEBUG_OBJECT (qtdemux, "parse_trak");
10987
10988 if (!qtdemux_tree_get_child_by_type_full (trak, FOURCC_tkhd, &tkhd)
10989 || !gst_byte_reader_get_uint8 (&tkhd, &tkhd_version)
10990 || !gst_byte_reader_get_uint24_be (&tkhd, &tkhd_flags))
10991 goto corrupt_file;
10992
10993 /* pick between 64 or 32 bits */
10994 value_size = tkhd_version == 1 ? 8 : 4;
10995 if (!gst_byte_reader_skip (&tkhd, value_size * 2) ||
10996 !gst_byte_reader_get_uint32_be (&tkhd, &track_id))
10997 goto corrupt_file;
10998
10999 /* Check if current moov has duplicated track_id */
11000 if (qtdemux_find_stream (qtdemux, track_id))
11001 goto existing_stream;
11002
11003 stream = _create_stream (qtdemux, track_id);
11004 stream->stream_tags = gst_tag_list_make_writable (stream->stream_tags);
11005
11006 /* need defaults for fragments */
11007 qtdemux_parse_trex (qtdemux, stream, &dummy, &dummy, &dummy);
11008
11009 if ((tkhd_flags & 1) == 0)
11010 stream->disabled = TRUE;
11011
11012 GST_LOG_OBJECT (qtdemux, "track[tkhd] version/flags/id: 0x%02x/%06x/%u",
11013 tkhd_version, tkhd_flags, stream->track_id);
11014
11015 if (!(mdia = qtdemux_tree_get_child_by_type (trak, FOURCC_mdia)))
11016 goto corrupt_file;
11017
11018 if (!(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mdhd))) {
11019 /* be nice for some crooked mjp2 files that use mhdr for mdhd */
11020 if (qtdemux->major_brand != FOURCC_mjp2 ||
11021 !(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mhdr)))
11022 goto corrupt_file;
11023 }
11024
11025 len = QT_UINT32 ((guint8 *) mdhd->data);
11026 version = QT_UINT32 ((guint8 *) mdhd->data + 8);
11027 GST_LOG_OBJECT (qtdemux, "track version/flags: %08x", version);
11028 if (version == 0x01000000) {
11029 if (len < 42)
11030 goto corrupt_file;
11031 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 28);
11032 stream->duration = QT_UINT64 ((guint8 *) mdhd->data + 32);
11033 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 40);
11034 } else {
11035 if (len < 30)
11036 goto corrupt_file;
11037 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 20);
11038 stream->duration = QT_UINT32 ((guint8 *) mdhd->data + 24);
11039 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 28);
11040 }
11041
11042 if (lang_code < 0x400) {
11043 qtdemux_lang_map_qt_code_to_iso (stream->lang_id, lang_code);
11044 } else if (lang_code == 0x7fff) {
11045 stream->lang_id[0] = 0; /* unspecified */
11046 } else {
11047 stream->lang_id[0] = 0x60 + ((lang_code >> 10) & 0x1F);
11048 stream->lang_id[1] = 0x60 + ((lang_code >> 5) & 0x1F);
11049 stream->lang_id[2] = 0x60 + (lang_code & 0x1F);
11050 stream->lang_id[3] = 0;
11051 }
11052
11053 GST_LOG_OBJECT (qtdemux, "track timescale: %" G_GUINT32_FORMAT,
11054 stream->timescale);
11055 GST_LOG_OBJECT (qtdemux, "track duration: %" G_GUINT64_FORMAT,
11056 stream->duration);
11057 GST_LOG_OBJECT (qtdemux, "track language code/id: 0x%04x/%s",
11058 lang_code, stream->lang_id);
11059
11060 if (G_UNLIKELY (stream->timescale == 0 || qtdemux->timescale == 0))
11061 goto corrupt_file;
11062
11063 if ((tref = qtdemux_tree_get_child_by_type (trak, FOURCC_tref))) {
11064 /* chapters track reference */
11065 GNode *chap = qtdemux_tree_get_child_by_type (tref, FOURCC_chap);
11066 if (chap) {
11067 gsize length = GST_READ_UINT32_BE (chap->data);
11068 if (qtdemux->chapters_track_id)
11069 GST_FIXME_OBJECT (qtdemux, "Multiple CHAP tracks");
11070
11071 if (length >= 12) {
11072 qtdemux->chapters_track_id =
11073 GST_READ_UINT32_BE ((gint8 *) chap->data + 8);
11074 }
11075 }
11076 }
11077
11078 /* fragmented files may have bogus duration in moov */
11079 if (!qtdemux->fragmented &&
11080 qtdemux->duration != G_MAXINT64 && stream->duration != G_MAXINT32) {
11081 guint64 tdur1, tdur2;
11082
11083 /* don't overflow */
11084 tdur1 = stream->timescale * (guint64) qtdemux->duration;
11085 tdur2 = qtdemux->timescale * (guint64) stream->duration;
11086
11087 /* HACK:
11088 * some of those trailers, nowadays, have prologue images that are
11089 * themselves video tracks as well. I haven't really found a way to
11090 * identify those yet, except for just looking at their duration. */
11091 if (tdur1 != 0 && (tdur2 * 10 / tdur1) < 2) {
11092 GST_WARNING_OBJECT (qtdemux,
11093 "Track shorter than 20%% (%" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT
11094 " vs. %" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT ") of the stream "
11095 "found, assuming preview image or something; skipping track",
11096 stream->duration, stream->timescale, qtdemux->duration,
11097 qtdemux->timescale);
11098 gst_qtdemux_stream_unref (stream);
11099 return TRUE;
11100 }
11101 }
11102
11103 if (!(hdlr = qtdemux_tree_get_child_by_type (mdia, FOURCC_hdlr)))
11104 goto corrupt_file;
11105
11106 GST_LOG_OBJECT (qtdemux, "track type: %" GST_FOURCC_FORMAT,
11107 GST_FOURCC_ARGS (QT_FOURCC ((guint8 *) hdlr->data + 12)));
11108
11109 len = QT_UINT32 ((guint8 *) hdlr->data);
11110 if (len >= 20)
11111 stream->subtype = QT_FOURCC ((guint8 *) hdlr->data + 16);
11112 GST_LOG_OBJECT (qtdemux, "track subtype: %" GST_FOURCC_FORMAT,
11113 GST_FOURCC_ARGS (stream->subtype));
11114
11115 if (!(minf = qtdemux_tree_get_child_by_type (mdia, FOURCC_minf)))
11116 goto corrupt_file;
11117
11118 if (!(stbl = qtdemux_tree_get_child_by_type (minf, FOURCC_stbl)))
11119 goto corrupt_file;
11120
11121 /* Parse out svmi (and later st3d/sv3d) atoms */
11122 if (!qtdemux_parse_stereo_svmi_atom (qtdemux, stream, stbl))
11123 goto corrupt_file;
11124
11125 /* parse rest of tkhd */
11126 if (stream->subtype == FOURCC_vide) {
11127 guint32 matrix[9];
11128
11129 /* version 1 uses some 64-bit ints */
11130 if (!gst_byte_reader_skip (&tkhd, 20 + value_size))
11131 goto corrupt_file;
11132
11133 if (!qtdemux_parse_transformation_matrix (qtdemux, &tkhd, matrix, "tkhd"))
11134 goto corrupt_file;
11135
11136 if (!gst_byte_reader_get_uint32_be (&tkhd, &w)
11137 || !gst_byte_reader_get_uint32_be (&tkhd, &h))
11138 goto corrupt_file;
11139
11140 qtdemux_inspect_transformation_matrix (qtdemux, stream, matrix,
11141 &stream->stream_tags);
11142 }
11143
11144 /* parse stsd */
11145 if (!(stsd = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsd)))
11146 goto corrupt_file;
11147 stsd_data = (const guint8 *) stsd->data;
11148
11149 /* stsd should at least have one entry */
11150 stsd_len = QT_UINT32 (stsd_data);
11151 if (stsd_len < 24) {
11152 /* .. but skip stream with empty stsd produced by some Vivotek cameras */
11153 if (stream->subtype == FOURCC_vivo) {
11154 gst_qtdemux_stream_unref (stream);
11155 return TRUE;
11156 } else {
11157 goto corrupt_file;
11158 }
11159 }
11160
11161 stream->stsd_entries_length = stsd_entry_count = QT_UINT32 (stsd_data + 12);
11162 /* each stsd entry must contain at least 8 bytes */
11163 if (stream->stsd_entries_length == 0
11164 || stream->stsd_entries_length > stsd_len / 8) {
11165 stream->stsd_entries_length = 0;
11166 goto corrupt_file;
11167 }
11168 stream->stsd_entries = g_new0 (QtDemuxStreamStsdEntry, stsd_entry_count);
11169 GST_LOG_OBJECT (qtdemux, "stsd len: %d", stsd_len);
11170 GST_LOG_OBJECT (qtdemux, "stsd entry count: %u", stsd_entry_count);
11171
11172 stsd_entry_data = stsd_data + 16;
11173 remaining_stsd_len = stsd_len - 16;
11174 for (stsd_index = 0; stsd_index < stsd_entry_count; stsd_index++) {
11175 guint32 fourcc;
11176 gchar *codec = NULL;
11177 QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[stsd_index];
11178
11179 /* and that entry should fit within stsd */
11180 len = QT_UINT32 (stsd_entry_data);
11181 if (len > remaining_stsd_len)
11182 goto corrupt_file;
11183
11184 entry->fourcc = fourcc = QT_FOURCC (stsd_entry_data + 4);
11185 GST_LOG_OBJECT (qtdemux, "stsd type: %" GST_FOURCC_FORMAT,
11186 GST_FOURCC_ARGS (entry->fourcc));
11187 GST_LOG_OBJECT (qtdemux, "stsd type len: %d", len);
11188
11189 if ((fourcc == FOURCC_drms) || (fourcc == FOURCC_drmi))
11190 goto error_encrypted;
11191
11192 if (fourcc == FOURCC_aavd) {
11193 if (stream->subtype != FOURCC_soun) {
11194 GST_ERROR_OBJECT (qtdemux,
11195 "Unexpeced stsd type 'aavd' outside 'soun' track");
11196 } else {
11197 /* encrypted audio with sound sample description v0 */
11198 GNode *enc = qtdemux_tree_get_child_by_type (stsd, fourcc);
11199 stream->protected = TRUE;
11200 if (!qtdemux_parse_protection_aavd (qtdemux, stream, enc, &fourcc))
11201 GST_ERROR_OBJECT (qtdemux, "Failed to parse protection scheme info");
11202 }
11203 }
11204
11205 if (fourcc == FOURCC_encv || fourcc == FOURCC_enca) {
11206 /* FIXME this looks wrong, there might be multiple children
11207 * with the same type */
11208 GNode *enc = qtdemux_tree_get_child_by_type (stsd, fourcc);
11209 stream->protected = TRUE;
11210 if (!qtdemux_parse_protection_scheme_info (qtdemux, stream, enc, &fourcc))
11211 GST_ERROR_OBJECT (qtdemux, "Failed to parse protection scheme info");
11212 }
11213
11214 if (stream->subtype == FOURCC_vide) {
11215 GNode *colr;
11216 GNode *fiel;
11217 GNode *pasp;
11218 gboolean gray;
11219 gint depth, palette_size, palette_count;
11220 guint32 *palette_data = NULL;
11221
11222 entry->sampled = TRUE;
11223
11224 stream->display_width = w >> 16;
11225 stream->display_height = h >> 16;
11226
11227 offset = 16;
11228 if (len < 86) /* TODO verify */
11229 goto corrupt_file;
11230
11231 entry->width = QT_UINT16 (stsd_entry_data + offset + 16);
11232 entry->height = QT_UINT16 (stsd_entry_data + offset + 18);
11233 entry->fps_n = 0; /* this is filled in later */
11234 entry->fps_d = 0; /* this is filled in later */
11235 entry->bits_per_sample = QT_UINT16 (stsd_entry_data + offset + 66);
11236 entry->color_table_id = QT_UINT16 (stsd_entry_data + offset + 68);
11237
11238 /* if color_table_id is 0, ctab atom must follow; however some files
11239 * produced by TMPEGEnc have color_table_id = 0 and no ctab atom, so
11240 * if color table is not present we'll correct the value */
11241 if (entry->color_table_id == 0 &&
11242 (len < 90
11243 || QT_FOURCC (stsd_entry_data + offset + 70) != FOURCC_ctab)) {
11244 entry->color_table_id = -1;
11245 }
11246
11247 GST_LOG_OBJECT (qtdemux, "width %d, height %d, bps %d, color table id %d",
11248 entry->width, entry->height, entry->bits_per_sample,
11249 entry->color_table_id);
11250
11251 depth = entry->bits_per_sample;
11252
11253 /* more than 32 bits means grayscale */
11254 gray = (depth > 32);
11255 /* low 32 bits specify the depth */
11256 depth &= 0x1F;
11257
11258 /* different number of palette entries is determined by depth. */
11259 palette_count = 0;
11260 if ((depth == 1) || (depth == 2) || (depth == 4) || (depth == 8))
11261 palette_count = (1 << depth);
11262 palette_size = palette_count * 4;
11263
11264 if (entry->color_table_id) {
11265 switch (palette_count) {
11266 case 0:
11267 break;
11268 case 2:
11269 palette_data = g_memdup2 (ff_qt_default_palette_2, palette_size);
11270 break;
11271 case 4:
11272 palette_data = g_memdup2 (ff_qt_default_palette_4, palette_size);
11273 break;
11274 case 16:
11275 if (gray)
11276 palette_data =
11277 g_memdup2 (ff_qt_grayscale_palette_16, palette_size);
11278 else
11279 palette_data = g_memdup2 (ff_qt_default_palette_16, palette_size);
11280 break;
11281 case 256:
11282 if (gray)
11283 palette_data =
11284 g_memdup2 (ff_qt_grayscale_palette_256, palette_size);
11285 else
11286 palette_data =
11287 g_memdup2 (ff_qt_default_palette_256, palette_size);
11288 break;
11289 default:
11290 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
11291 (_("The video in this file might not play correctly.")),
11292 ("unsupported palette depth %d", depth));
11293 break;
11294 }
11295 } else {
11296 gint i, j, start, end;
11297
11298 if (len < 94)
11299 goto corrupt_file;
11300
11301 /* read table */
11302 start = QT_UINT32 (stsd_entry_data + offset + 70);
11303 palette_count = QT_UINT16 (stsd_entry_data + offset + 74);
11304 end = QT_UINT16 (stsd_entry_data + offset + 76);
11305
11306 GST_LOG_OBJECT (qtdemux, "start %d, end %d, palette_count %d",
11307 start, end, palette_count);
11308
11309 if (end > 255)
11310 end = 255;
11311 if (start > end)
11312 start = end;
11313
11314 if (len < 94 + (end - start) * 8)
11315 goto corrupt_file;
11316
11317 /* palette is always the same size */
11318 palette_data = g_malloc0 (256 * 4);
11319 palette_size = 256 * 4;
11320
11321 for (j = 0, i = start; i <= end; j++, i++) {
11322 guint32 a, r, g, b;
11323
11324 a = QT_UINT16 (stsd_entry_data + offset + 78 + (j * 8));
11325 r = QT_UINT16 (stsd_entry_data + offset + 80 + (j * 8));
11326 g = QT_UINT16 (stsd_entry_data + offset + 82 + (j * 8));
11327 b = QT_UINT16 (stsd_entry_data + offset + 84 + (j * 8));
11328
11329 palette_data[i] = ((a & 0xff00) << 16) | ((r & 0xff00) << 8) |
11330 (g & 0xff00) | (b >> 8);
11331 }
11332 }
11333
11334 if (entry->caps)
11335 gst_caps_unref (entry->caps);
11336
11337 entry->caps =
11338 qtdemux_video_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
11339 &codec);
11340 if (G_UNLIKELY (!entry->caps)) {
11341 g_free (palette_data);
11342 goto unknown_stream;
11343 }
11344
11345 if (codec) {
11346 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11347 GST_TAG_VIDEO_CODEC, codec, NULL);
11348 g_free (codec);
11349 codec = NULL;
11350 }
11351
11352 if (palette_data) {
11353 GstStructure *s;
11354
11355 if (entry->rgb8_palette)
11356 gst_memory_unref (entry->rgb8_palette);
11357 entry->rgb8_palette = gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY,
11358 palette_data, palette_size, 0, palette_size, palette_data, g_free);
11359
11360 s = gst_caps_get_structure (entry->caps, 0);
11361
11362 /* non-raw video has a palette_data property. raw video has the palette as
11363 * an extra plane that we append to the output buffers before we push
11364 * them*/
11365 if (!gst_structure_has_name (s, "video/x-raw")) {
11366 GstBuffer *palette;
11367
11368 palette = gst_buffer_new ();
11369 gst_buffer_append_memory (palette, entry->rgb8_palette);
11370 entry->rgb8_palette = NULL;
11371
11372 gst_caps_set_simple (entry->caps, "palette_data",
11373 GST_TYPE_BUFFER, palette, NULL);
11374 gst_buffer_unref (palette);
11375 }
11376 } else if (palette_count != 0) {
11377 GST_ELEMENT_WARNING (qtdemux, STREAM, NOT_IMPLEMENTED,
11378 (NULL), ("Unsupported palette depth %d", depth));
11379 }
11380
11381 GST_LOG_OBJECT (qtdemux, "frame count: %u",
11382 QT_UINT16 (stsd_entry_data + offset + 32));
11383
11384 esds = NULL;
11385 pasp = NULL;
11386 colr = NULL;
11387 fiel = NULL;
11388 /* pick 'the' stsd child */
11389 mp4v = qtdemux_tree_get_child_by_index (stsd, stsd_index);
11390 // We should skip parsing the stsd for non-protected streams if
11391 // the entry doesn't match the fourcc, since they don't change
11392 // format. However, for protected streams we can have partial
11393 // encryption, where parts of the stream are encrypted and parts
11394 // not. For both parts of such streams, we should ensure the
11395 // esds overrides are parsed for both from the stsd.
11396 if (QTDEMUX_TREE_NODE_FOURCC (mp4v) != fourcc) {
11397 if (stream->protected && QTDEMUX_TREE_NODE_FOURCC (mp4v) != FOURCC_encv)
11398 mp4v = NULL;
11399 else if (!stream->protected)
11400 mp4v = NULL;
11401 }
11402
11403 if (mp4v) {
11404 esds = qtdemux_tree_get_child_by_type (mp4v, FOURCC_esds);
11405 pasp = qtdemux_tree_get_child_by_type (mp4v, FOURCC_pasp);
11406 colr = qtdemux_tree_get_child_by_type (mp4v, FOURCC_colr);
11407 fiel = qtdemux_tree_get_child_by_type (mp4v, FOURCC_fiel);
11408 }
11409
11410 if (pasp) {
11411 const guint8 *pasp_data = (const guint8 *) pasp->data;
11412 gint len = QT_UINT32 (pasp_data);
11413
11414 if (len == 16) {
11415 CUR_STREAM (stream)->par_w = QT_UINT32 (pasp_data + 8);
11416 CUR_STREAM (stream)->par_h = QT_UINT32 (pasp_data + 12);
11417 } else {
11418 CUR_STREAM (stream)->par_w = 0;
11419 CUR_STREAM (stream)->par_h = 0;
11420 }
11421 } else {
11422 CUR_STREAM (stream)->par_w = 0;
11423 CUR_STREAM (stream)->par_h = 0;
11424 }
11425
11426 if (fiel) {
11427 const guint8 *fiel_data = (const guint8 *) fiel->data;
11428 gint len = QT_UINT32 (fiel_data);
11429
11430 if (len == 10) {
11431 CUR_STREAM (stream)->interlace_mode = GST_READ_UINT8 (fiel_data + 8);
11432 CUR_STREAM (stream)->field_order = GST_READ_UINT8 (fiel_data + 9);
11433 }
11434 }
11435
11436 if (colr) {
11437 const guint8 *colr_data = (const guint8 *) colr->data;
11438 gint len = QT_UINT32 (colr_data);
11439
11440 if (len == 19 || len == 18) {
11441 guint32 color_type = GST_READ_UINT32_LE (colr_data + 8);
11442
11443 if (color_type == FOURCC_nclx || color_type == FOURCC_nclc) {
11444 guint16 primaries = GST_READ_UINT16_BE (colr_data + 12);
11445 guint16 transfer_function = GST_READ_UINT16_BE (colr_data + 14);
11446 guint16 matrix = GST_READ_UINT16_BE (colr_data + 16);
11447 gboolean full_range = len == 19 ? colr_data[17] >> 7 : FALSE;
11448
11449 CUR_STREAM (stream)->colorimetry.primaries =
11450 gst_video_color_primaries_from_iso (primaries);
11451 CUR_STREAM (stream)->colorimetry.transfer =
11452 gst_video_transfer_function_from_iso (transfer_function);
11453 CUR_STREAM (stream)->colorimetry.matrix =
11454 gst_video_color_matrix_from_iso (matrix);
11455 CUR_STREAM (stream)->colorimetry.range =
11456 full_range ? GST_VIDEO_COLOR_RANGE_0_255 :
11457 GST_VIDEO_COLOR_RANGE_16_235;
11458 } else {
11459 GST_DEBUG_OBJECT (qtdemux, "Unsupported color type");
11460 }
11461 } else {
11462 GST_WARNING_OBJECT (qtdemux, "Invalid colr atom size");
11463 }
11464 }
11465
11466 if (esds) {
11467 gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
11468 stream->stream_tags);
11469 } else {
11470 switch (fourcc) {
11471 case FOURCC_H264:
11472 case FOURCC_avc1:
11473 case FOURCC_avc3:
11474 {
11475 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
11476 const guint8 *avc_data = stsd_entry_data + 0x56;
11477
11478 /* find avcC */
11479 while (len >= 0x8) {
11480 gint size;
11481
11482 if (QT_UINT32 (avc_data) <= len)
11483 size = QT_UINT32 (avc_data) - 0x8;
11484 else
11485 size = len - 0x8;
11486
11487 if (size < 1)
11488 /* No real data, so break out */
11489 break;
11490
11491 switch (QT_FOURCC (avc_data + 0x4)) {
11492 case FOURCC_avcC:
11493 {
11494 /* parse, if found */
11495 GstBuffer *buf;
11496
11497 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
11498
11499 /* First 4 bytes are the length of the atom, the next 4 bytes
11500 * are the fourcc, the next 1 byte is the version, and the
11501 * subsequent bytes are profile_tier_level structure like data. */
11502 gst_codec_utils_h264_caps_set_level_and_profile (entry->caps,
11503 avc_data + 8 + 1, size - 1);
11504 buf = gst_buffer_new_and_alloc (size);
11505 gst_buffer_fill (buf, 0, avc_data + 0x8, size);
11506 gst_caps_set_simple (entry->caps,
11507 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11508 gst_buffer_unref (buf);
11509
11510 break;
11511 }
11512 case FOURCC_strf:
11513 {
11514 GstBuffer *buf;
11515
11516 GST_DEBUG_OBJECT (qtdemux, "found strf codec_data in stsd");
11517
11518 /* First 4 bytes are the length of the atom, the next 4 bytes
11519 * are the fourcc, next 40 bytes are BITMAPINFOHEADER,
11520 * next 1 byte is the version, and the
11521 * subsequent bytes are sequence parameter set like data. */
11522
11523 size -= 40; /* we'll be skipping BITMAPINFOHEADER */
11524 if (size > 1) {
11525 gst_codec_utils_h264_caps_set_level_and_profile
11526 (entry->caps, avc_data + 8 + 40 + 1, size - 1);
11527
11528 buf = gst_buffer_new_and_alloc (size);
11529 gst_buffer_fill (buf, 0, avc_data + 8 + 40, size);
11530 gst_caps_set_simple (entry->caps,
11531 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11532 gst_buffer_unref (buf);
11533 }
11534 break;
11535 }
11536 case FOURCC_btrt:
11537 {
11538 guint avg_bitrate, max_bitrate;
11539
11540 /* bufferSizeDB, maxBitrate and avgBitrate - 4 bytes each */
11541 if (size < 12)
11542 break;
11543
11544 max_bitrate = QT_UINT32 (avc_data + 0xc);
11545 avg_bitrate = QT_UINT32 (avc_data + 0x10);
11546
11547 if (!max_bitrate && !avg_bitrate)
11548 break;
11549
11550 /* Some muxers seem to swap the average and maximum bitrates
11551 * (I'm looking at you, YouTube), so we swap for sanity. */
11552 if (max_bitrate > 0 && max_bitrate < avg_bitrate) {
11553 guint temp = avg_bitrate;
11554
11555 avg_bitrate = max_bitrate;
11556 max_bitrate = temp;
11557 }
11558
11559 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
11560 gst_tag_list_add (stream->stream_tags,
11561 GST_TAG_MERGE_REPLACE, GST_TAG_MAXIMUM_BITRATE,
11562 max_bitrate, NULL);
11563 }
11564 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
11565 gst_tag_list_add (stream->stream_tags,
11566 GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE, avg_bitrate,
11567 NULL);
11568 }
11569
11570 break;
11571 }
11572
11573 default:
11574 break;
11575 }
11576
11577 len -= size + 8;
11578 avc_data += size + 8;
11579 }
11580
11581 break;
11582 }
11583 case FOURCC_H265:
11584 case FOURCC_hvc1:
11585 case FOURCC_hev1:
11586 case FOURCC_dvh1:
11587 case FOURCC_dvhe:
11588 {
11589 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
11590 const guint8 *hevc_data = stsd_entry_data + 0x56;
11591
11592 /* find hevc */
11593 while (len >= 0x8) {
11594 gint size;
11595
11596 if (QT_UINT32 (hevc_data) <= len)
11597 size = QT_UINT32 (hevc_data) - 0x8;
11598 else
11599 size = len - 0x8;
11600
11601 if (size < 1)
11602 /* No real data, so break out */
11603 break;
11604
11605 switch (QT_FOURCC (hevc_data + 0x4)) {
11606 case FOURCC_hvcC:
11607 {
11608 /* parse, if found */
11609 GstBuffer *buf;
11610
11611 GST_DEBUG_OBJECT (qtdemux, "found hvcC codec_data in stsd");
11612
11613 /* First 4 bytes are the length of the atom, the next 4 bytes
11614 * are the fourcc, the next 1 byte is the version, and the
11615 * subsequent bytes are sequence parameter set like data. */
11616 gst_codec_utils_h265_caps_set_level_tier_and_profile
11617 (entry->caps, hevc_data + 8 + 1, size - 1);
11618
11619 buf = gst_buffer_new_and_alloc (size);
11620 gst_buffer_fill (buf, 0, hevc_data + 0x8, size);
11621 gst_caps_set_simple (entry->caps,
11622 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11623 gst_buffer_unref (buf);
11624 break;
11625 }
11626 default:
11627 break;
11628 }
11629 len -= size + 8;
11630 hevc_data += size + 8;
11631 }
11632 break;
11633 }
11634 case FOURCC_mp4v:
11635 case FOURCC_MP4V:
11636 case FOURCC_fmp4:
11637 case FOURCC_FMP4:
11638 case FOURCC_xvid:
11639 case FOURCC_XVID:
11640 {
11641 GNode *glbl;
11642
11643 GST_DEBUG_OBJECT (qtdemux, "found %" GST_FOURCC_FORMAT,
11644 GST_FOURCC_ARGS (fourcc));
11645
11646 /* codec data might be in glbl extension atom */
11647 glbl = mp4v ?
11648 qtdemux_tree_get_child_by_type (mp4v, FOURCC_glbl) : NULL;
11649 if (glbl) {
11650 guint8 *data;
11651 GstBuffer *buf;
11652 gint len;
11653
11654 GST_DEBUG_OBJECT (qtdemux, "found glbl data in stsd");
11655 data = glbl->data;
11656 len = QT_UINT32 (data);
11657 if (len > 0x8) {
11658 len -= 0x8;
11659 buf = gst_buffer_new_and_alloc (len);
11660 gst_buffer_fill (buf, 0, data + 8, len);
11661 gst_caps_set_simple (entry->caps,
11662 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11663 gst_buffer_unref (buf);
11664 }
11665 }
11666 break;
11667 }
11668 case FOURCC_mjp2:
11669 {
11670 /* see annex I of the jpeg2000 spec */
11671 GNode *jp2h, *ihdr, *colr, *mjp2, *field, *prefix, *cmap, *cdef;
11672 const guint8 *data;
11673 const gchar *colorspace = NULL;
11674 gint ncomp = 0;
11675 guint32 ncomp_map = 0;
11676 gint32 *comp_map = NULL;
11677 guint32 nchan_def = 0;
11678 gint32 *chan_def = NULL;
11679
11680 GST_DEBUG_OBJECT (qtdemux, "found mjp2");
11681 /* some required atoms */
11682 mjp2 = qtdemux_tree_get_child_by_index (stsd, stsd_index);
11683 if (!mjp2)
11684 break;
11685 jp2h = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2h);
11686 if (!jp2h)
11687 break;
11688
11689 /* number of components; redundant with info in codestream, but useful
11690 to a muxer */
11691 ihdr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_ihdr);
11692 if (!ihdr || QT_UINT32 (ihdr->data) != 22)
11693 break;
11694 ncomp = QT_UINT16 (((guint8 *) ihdr->data) + 16);
11695
11696 colr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_colr);
11697 if (!colr)
11698 break;
11699 GST_DEBUG_OBJECT (qtdemux, "found colr");
11700 /* extract colour space info */
11701 if (QT_UINT8 ((guint8 *) colr->data + 8) == 1) {
11702 switch (QT_UINT32 ((guint8 *) colr->data + 11)) {
11703 case 16:
11704 colorspace = "sRGB";
11705 break;
11706 case 17:
11707 colorspace = "GRAY";
11708 break;
11709 case 18:
11710 colorspace = "sYUV";
11711 break;
11712 default:
11713 colorspace = NULL;
11714 break;
11715 }
11716 }
11717 if (!colorspace)
11718 /* colr is required, and only values 16, 17, and 18 are specified,
11719 so error if we have no colorspace */
11720 break;
11721
11722 /* extract component mapping */
11723 cmap = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cmap);
11724 if (cmap) {
11725 guint32 cmap_len = 0;
11726 int i;
11727 cmap_len = QT_UINT32 (cmap->data);
11728 if (cmap_len >= 8) {
11729 /* normal box, subtract off header */
11730 cmap_len -= 8;
11731 /* cmap: { u16 cmp; u8 mtyp; u8 pcol; }* */
11732 if (cmap_len % 4 == 0) {
11733 ncomp_map = (cmap_len / 4);
11734 comp_map = g_new0 (gint32, ncomp_map);
11735 for (i = 0; i < ncomp_map; i++) {
11736 guint16 cmp;
11737 guint8 mtyp, pcol;
11738 cmp = QT_UINT16 (((guint8 *) cmap->data) + 8 + i * 4);
11739 mtyp = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 2);
11740 pcol = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 3);
11741 comp_map[i] = (mtyp << 24) | (pcol << 16) | cmp;
11742 }
11743 }
11744 }
11745 }
11746 /* extract channel definitions */
11747 cdef = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cdef);
11748 if (cdef) {
11749 guint32 cdef_len = 0;
11750 int i;
11751 cdef_len = QT_UINT32 (cdef->data);
11752 if (cdef_len >= 10) {
11753 /* normal box, subtract off header and len */
11754 cdef_len -= 10;
11755 /* cdef: u16 n; { u16 cn; u16 typ; u16 asoc; }* */
11756 if (cdef_len % 6 == 0) {
11757 nchan_def = (cdef_len / 6);
11758 chan_def = g_new0 (gint32, nchan_def);
11759 for (i = 0; i < nchan_def; i++)
11760 chan_def[i] = -1;
11761 for (i = 0; i < nchan_def; i++) {
11762 guint16 cn, typ, asoc;
11763 cn = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6);
11764 typ = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 2);
11765 asoc = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 4);
11766 if (cn < nchan_def) {
11767 switch (typ) {
11768 case 0:
11769 chan_def[cn] = asoc;
11770 break;
11771 case 1:
11772 chan_def[cn] = 0; /* alpha */
11773 break;
11774 default:
11775 chan_def[cn] = -typ;
11776 }
11777 }
11778 }
11779 }
11780 }
11781 }
11782
11783 gst_caps_set_simple (entry->caps,
11784 "num-components", G_TYPE_INT, ncomp, NULL);
11785 gst_caps_set_simple (entry->caps,
11786 "colorspace", G_TYPE_STRING, colorspace, NULL);
11787
11788 if (comp_map) {
11789 GValue arr = { 0, };
11790 GValue elt = { 0, };
11791 int i;
11792 g_value_init (&arr, GST_TYPE_ARRAY);
11793 g_value_init (&elt, G_TYPE_INT);
11794 for (i = 0; i < ncomp_map; i++) {
11795 g_value_set_int (&elt, comp_map[i]);
11796 gst_value_array_append_value (&arr, &elt);
11797 }
11798 gst_structure_set_value (gst_caps_get_structure (entry->caps, 0),
11799 "component-map", &arr);
11800 g_value_unset (&elt);
11801 g_value_unset (&arr);
11802 g_free (comp_map);
11803 }
11804
11805 if (chan_def) {
11806 GValue arr = { 0, };
11807 GValue elt = { 0, };
11808 int i;
11809 g_value_init (&arr, GST_TYPE_ARRAY);
11810 g_value_init (&elt, G_TYPE_INT);
11811 for (i = 0; i < nchan_def; i++) {
11812 g_value_set_int (&elt, chan_def[i]);
11813 gst_value_array_append_value (&arr, &elt);
11814 }
11815 gst_structure_set_value (gst_caps_get_structure (entry->caps, 0),
11816 "channel-definitions", &arr);
11817 g_value_unset (&elt);
11818 g_value_unset (&arr);
11819 g_free (chan_def);
11820 }
11821
11822 /* some optional atoms */
11823 field = qtdemux_tree_get_child_by_type (mjp2, FOURCC_fiel);
11824 prefix = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2x);
11825
11826 /* indicate possible fields in caps */
11827 if (field) {
11828 data = (guint8 *) field->data + 8;
11829 if (*data != 1)
11830 gst_caps_set_simple (entry->caps, "fields", G_TYPE_INT,
11831 (gint) * data, NULL);
11832 }
11833 /* add codec_data if provided */
11834 if (prefix) {
11835 GstBuffer *buf;
11836 gint len;
11837
11838 GST_DEBUG_OBJECT (qtdemux, "found prefix data in stsd");
11839 data = prefix->data;
11840 len = QT_UINT32 (data);
11841 if (len > 0x8) {
11842 len -= 0x8;
11843 buf = gst_buffer_new_and_alloc (len);
11844 gst_buffer_fill (buf, 0, data + 8, len);
11845 gst_caps_set_simple (entry->caps,
11846 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11847 gst_buffer_unref (buf);
11848 }
11849 }
11850 break;
11851 }
11852 case FOURCC_SVQ3:
11853 case FOURCC_VP31:
11854 {
11855 GstBuffer *buf;
11856 GstBuffer *seqh = NULL;
11857 const guint8 *gamma_data = NULL;
11858 gint len = QT_UINT32 (stsd_data); /* FIXME review - why put the whole stsd in codec data? */
11859
11860 qtdemux_parse_svq3_stsd_data (qtdemux, stsd_entry_data, &gamma_data,
11861 &seqh);
11862 if (gamma_data) {
11863 gst_caps_set_simple (entry->caps, "applied-gamma", G_TYPE_DOUBLE,
11864 QT_FP32 (gamma_data), NULL);
11865 }
11866 if (seqh) {
11867 /* sorry for the bad name, but we don't know what this is, other
11868 * than its own fourcc */
11869 gst_caps_set_simple (entry->caps, "seqh", GST_TYPE_BUFFER, seqh,
11870 NULL);
11871 gst_buffer_unref (seqh);
11872 }
11873
11874 GST_DEBUG_OBJECT (qtdemux, "found codec_data in stsd");
11875 buf = gst_buffer_new_and_alloc (len);
11876 gst_buffer_fill (buf, 0, stsd_data, len);
11877 gst_caps_set_simple (entry->caps,
11878 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11879 gst_buffer_unref (buf);
11880 break;
11881 }
11882 case FOURCC_jpeg:
11883 {
11884 /* https://developer.apple.com/standards/qtff-2001.pdf,
11885 * page 92, "Video Sample Description", under table 3.1 */
11886 GstByteReader br;
11887
11888 const gint compressor_offset =
11889 16 + 4 + 4 * 3 + 2 * 2 + 2 * 4 + 4 + 2;
11890 const gint min_size = compressor_offset + 32 + 2 + 2;
11891 GNode *jpeg;
11892 guint32 len;
11893 guint16 color_table_id = 0;
11894 gboolean ok;
11895
11896 GST_DEBUG_OBJECT (qtdemux, "found jpeg");
11897
11898 /* recover information on interlaced/progressive */
11899 jpeg = qtdemux_tree_get_child_by_type (stsd, FOURCC_jpeg);
11900 if (!jpeg)
11901 break;
11902
11903 len = QT_UINT32 (jpeg->data);
11904 GST_DEBUG_OBJECT (qtdemux, "Found jpeg: len %u, need %d", len,
11905 min_size);
11906 if (len >= min_size) {
11907 gst_byte_reader_init (&br, jpeg->data, len);
11908
11909 gst_byte_reader_skip (&br, compressor_offset + 32 + 2);
11910 gst_byte_reader_get_uint16_le (&br, &color_table_id);
11911 if (color_table_id != 0) {
11912 /* the spec says there can be concatenated chunks in the data, and we want
11913 * to find one called field. Walk through them. */
11914 gint offset = min_size;
11915 while (offset + 8 < len) {
11916 guint32 size = 0, tag;
11917 ok = gst_byte_reader_get_uint32_le (&br, &size);
11918 ok &= gst_byte_reader_get_uint32_le (&br, &tag);
11919 if (!ok || size < 8) {
11920 GST_WARNING_OBJECT (qtdemux,
11921 "Failed to walk optional chunk list");
11922 break;
11923 }
11924 GST_DEBUG_OBJECT (qtdemux,
11925 "Found optional %4.4s chunk, size %u",
11926 (const char *) &tag, size);
11927 if (tag == FOURCC_fiel) {
11928 guint8 n_fields = 0, ordering = 0;
11929 gst_byte_reader_get_uint8 (&br, &n_fields);
11930 gst_byte_reader_get_uint8 (&br, &ordering);
11931 if (n_fields == 1 || n_fields == 2) {
11932 GST_DEBUG_OBJECT (qtdemux,
11933 "Found fiel tag with %u fields, ordering %u",
11934 n_fields, ordering);
11935 if (n_fields == 2)
11936 gst_caps_set_simple (CUR_STREAM (stream)->caps,
11937 "interlace-mode", G_TYPE_STRING, "interleaved",
11938 NULL);
11939 } else {
11940 GST_WARNING_OBJECT (qtdemux,
11941 "Found fiel tag with invalid fields (%u)", n_fields);
11942 }
11943 }
11944 offset += size;
11945 }
11946 } else {
11947 GST_DEBUG_OBJECT (qtdemux,
11948 "Color table ID is 0, not trying to get interlacedness");
11949 }
11950 } else {
11951 GST_WARNING_OBJECT (qtdemux,
11952 "Length of jpeg chunk is too small, not trying to get interlacedness");
11953 }
11954
11955 break;
11956 }
11957 case FOURCC_rle_:
11958 case FOURCC_WRLE:
11959 {
11960 gst_caps_set_simple (entry->caps,
11961 "depth", G_TYPE_INT, QT_UINT16 (stsd_entry_data + offset + 66),
11962 NULL);
11963 break;
11964 }
11965 case FOURCC_XiTh:
11966 {
11967 GNode *xith, *xdxt;
11968
11969 GST_DEBUG_OBJECT (qtdemux, "found XiTh");
11970 xith = qtdemux_tree_get_child_by_index (stsd, stsd_index);
11971 if (!xith)
11972 break;
11973
11974 xdxt = qtdemux_tree_get_child_by_type (xith, FOURCC_XdxT);
11975 if (!xdxt)
11976 break;
11977
11978 GST_DEBUG_OBJECT (qtdemux, "found XdxT node");
11979 /* collect the headers and store them in a stream list so that we can
11980 * send them out first */
11981 qtdemux_parse_theora_extension (qtdemux, stream, xdxt);
11982 break;
11983 }
11984 case FOURCC_ovc1:
11985 {
11986 GNode *ovc1;
11987 guint8 *ovc1_data;
11988 guint ovc1_len;
11989 GstBuffer *buf;
11990
11991 GST_DEBUG_OBJECT (qtdemux, "parse ovc1 header");
11992 ovc1 = qtdemux_tree_get_child_by_index (stsd, stsd_index);
11993 if (!ovc1)
11994 break;
11995 ovc1_data = ovc1->data;
11996 ovc1_len = QT_UINT32 (ovc1_data);
11997 if (ovc1_len <= 198) {
11998 GST_WARNING_OBJECT (qtdemux, "Too small ovc1 header, skipping");
11999 break;
12000 }
12001 buf = gst_buffer_new_and_alloc (ovc1_len - 198);
12002 gst_buffer_fill (buf, 0, ovc1_data + 198, ovc1_len - 198);
12003 gst_caps_set_simple (entry->caps,
12004 "codec_data", GST_TYPE_BUFFER, buf, NULL);
12005 gst_buffer_unref (buf);
12006 break;
12007 }
12008 case FOURCC_vc_1:
12009 {
12010 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
12011 const guint8 *vc1_data = stsd_entry_data + 0x56;
12012
12013 /* find dvc1 */
12014 while (len >= 8) {
12015 gint size;
12016
12017 if (QT_UINT32 (vc1_data) <= len)
12018 size = QT_UINT32 (vc1_data) - 8;
12019 else
12020 size = len - 8;
12021
12022 if (size < 1)
12023 /* No real data, so break out */
12024 break;
12025
12026 switch (QT_FOURCC (vc1_data + 0x4)) {
12027 case GST_MAKE_FOURCC ('d', 'v', 'c', '1'):
12028 {
12029 GstBuffer *buf;
12030
12031 GST_DEBUG_OBJECT (qtdemux, "found dvc1 codec_data in stsd");
12032 buf = gst_buffer_new_and_alloc (size);
12033 gst_buffer_fill (buf, 0, vc1_data + 8, size);
12034 gst_caps_set_simple (entry->caps,
12035 "codec_data", GST_TYPE_BUFFER, buf, NULL);
12036 gst_buffer_unref (buf);
12037 break;
12038 }
12039 default:
12040 break;
12041 }
12042 len -= size + 8;
12043 vc1_data += size + 8;
12044 }
12045 break;
12046 }
12047 case FOURCC_av01:
12048 {
12049 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
12050 const guint8 *av1_data = stsd_entry_data + 0x56;
12051
12052 /* find av1C */
12053 while (len >= 0x8) {
12054 gint size;
12055
12056 if (QT_UINT32 (av1_data) <= len)
12057 size = QT_UINT32 (av1_data) - 0x8;
12058 else
12059 size = len - 0x8;
12060
12061 if (size < 1)
12062 /* No real data, so break out */
12063 break;
12064
12065 switch (QT_FOURCC (av1_data + 0x4)) {
12066 case FOURCC_av1C:
12067 {
12068 /* parse, if found */
12069 GstBuffer *buf;
12070 guint8 pres_delay_field;
12071
12072 GST_DEBUG_OBJECT (qtdemux,
12073 "found av1C codec_data in stsd of size %d", size);
12074
12075 /* not enough data, just ignore and hope for the best */
12076 if (size < 5)
12077 break;
12078
12079 /* Content is:
12080 * 4 bytes: atom length
12081 * 4 bytes: fourcc
12082 * 1 byte: version
12083 * 3 bytes: flags
12084 * 3 bits: reserved
12085 * 1 bits: initial_presentation_delay_present
12086 * 4 bits: initial_presentation_delay (if present else reserved
12087 * rest: OBUs.
12088 */
12089
12090 if (av1_data[9] != 0) {
12091 GST_WARNING ("Unknown version %d of av1C box", av1_data[9]);
12092 break;
12093 }
12094
12095 /* We skip initial_presentation_delay* for now */
12096 pres_delay_field = *(av1_data + 12);
12097 if (pres_delay_field & (1 << 5)) {
12098 gst_caps_set_simple (entry->caps,
12099 "presentation-delay", G_TYPE_INT,
12100 (gint) (pres_delay_field & 0x0F) + 1, NULL);
12101 }
12102 if (size > 5) {
12103 buf = gst_buffer_new_and_alloc (size - 5);
12104 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_HEADER);
12105 gst_buffer_fill (buf, 0, av1_data + 13, size - 5);
12106 gst_caps_set_simple (entry->caps,
12107 "codec_data", GST_TYPE_BUFFER, buf, NULL);
12108 gst_buffer_unref (buf);
12109 }
12110 break;
12111 }
12112 default:
12113 break;
12114 }
12115
12116 len -= size + 8;
12117 av1_data += size + 8;
12118 }
12119
12120 break;
12121 }
12122
12123 /* TODO: Need to parse vpcC for VP8 codec too.
12124 * Note that VPCodecConfigurationBox (vpcC) is defined for
12125 * vp08, vp09, and vp10 fourcc. */
12126 case FOURCC_vp09:
12127 {
12128 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
12129 const guint8 *vpcc_data = stsd_entry_data + 0x56;
12130
12131 /* find vpcC */
12132 while (len >= 0x8) {
12133 gint size;
12134
12135 if (QT_UINT32 (vpcc_data) <= len)
12136 size = QT_UINT32 (vpcc_data) - 0x8;
12137 else
12138 size = len - 0x8;
12139
12140 if (size < 1)
12141 /* No real data, so break out */
12142 break;
12143
12144 switch (QT_FOURCC (vpcc_data + 0x4)) {
12145 case FOURCC_vpcC:
12146 {
12147 const gchar *profile_str = NULL;
12148 const gchar *chroma_format_str = NULL;
12149 guint8 profile;
12150 guint8 bitdepth;
12151 guint8 chroma_format;
12152 GstVideoColorimetry cinfo;
12153
12154 /* parse, if found */
12155 GST_DEBUG_OBJECT (qtdemux,
12156 "found vp codec_data in stsd of size %d", size);
12157
12158 /* the meaning of "size" is length of the atom body, excluding
12159 * atom length and fourcc fields */
12160 if (size < 12)
12161 break;
12162
12163 /* Content is:
12164 * 4 bytes: atom length
12165 * 4 bytes: fourcc
12166 * 1 byte: version
12167 * 3 bytes: flags
12168 * 1 byte: profile
12169 * 1 byte: level
12170 * 4 bits: bitDepth
12171 * 3 bits: chromaSubsampling
12172 * 1 bit: videoFullRangeFlag
12173 * 1 byte: colourPrimaries
12174 * 1 byte: transferCharacteristics
12175 * 1 byte: matrixCoefficients
12176 * 2 bytes: codecIntializationDataSize (should be zero for vp8 and vp9)
12177 * rest: codecIntializationData (not used for vp8 and vp9)
12178 */
12179
12180 if (vpcc_data[8] != 1) {
12181 GST_WARNING_OBJECT (qtdemux,
12182 "unknown vpcC version %d", vpcc_data[8]);
12183 break;
12184 }
12185
12186 profile = vpcc_data[12];
12187 switch (profile) {
12188 case 0:
12189 profile_str = "0";
12190 break;
12191 case 1:
12192 profile_str = "1";
12193 break;
12194 case 2:
12195 profile_str = "2";
12196 break;
12197 case 3:
12198 profile_str = "3";
12199 break;
12200 default:
12201 break;
12202 }
12203
12204 if (profile_str) {
12205 gst_caps_set_simple (entry->caps,
12206 "profile", G_TYPE_STRING, profile_str, NULL);
12207 }
12208
12209 /* skip level, the VP9 spec v0.6 defines only one level atm,
12210 * but webm spec define various ones. Add level to caps
12211 * if we really need it then */
12212
12213 bitdepth = (vpcc_data[14] & 0xf0) >> 4;
12214 if (bitdepth == 8 || bitdepth == 10 || bitdepth == 12) {
12215 gst_caps_set_simple (entry->caps,
12216 "bit-depth-luma", G_TYPE_UINT, bitdepth,
12217 "bit-depth-chroma", G_TYPE_UINT, bitdepth, NULL);
12218 }
12219
12220 chroma_format = (vpcc_data[14] & 0xe) >> 1;
12221 switch (chroma_format) {
12222 case 0:
12223 case 1:
12224 chroma_format_str = "4:2:0";
12225 break;
12226 case 2:
12227 chroma_format_str = "4:2:2";
12228 break;
12229 case 3:
12230 chroma_format_str = "4:4:4";
12231 break;
12232 default:
12233 break;
12234 }
12235
12236 if (chroma_format_str) {
12237 gst_caps_set_simple (entry->caps,
12238 "chroma-format", G_TYPE_STRING, chroma_format_str,
12239 NULL);
12240 }
12241
12242 if ((vpcc_data[14] & 0x1) != 0)
12243 cinfo.range = GST_VIDEO_COLOR_RANGE_0_255;
12244 else
12245 cinfo.range = GST_VIDEO_COLOR_RANGE_16_235;
12246 cinfo.primaries =
12247 gst_video_color_primaries_from_iso (vpcc_data[15]);
12248 cinfo.transfer =
12249 gst_video_transfer_function_from_iso (vpcc_data[16]);
12250 cinfo.matrix =
12251 gst_video_color_matrix_from_iso (vpcc_data[17]);
12252
12253 if (cinfo.primaries != GST_VIDEO_COLOR_PRIMARIES_UNKNOWN &&
12254 cinfo.transfer != GST_VIDEO_TRANSFER_UNKNOWN &&
12255 cinfo.matrix != GST_VIDEO_COLOR_MATRIX_UNKNOWN) {
12256 /* set this only if all values are known, otherwise this
12257 * might overwrite valid ones parsed from other color box */
12258 CUR_STREAM (stream)->colorimetry = cinfo;
12259 }
12260 break;
12261 }
12262 default:
12263 break;
12264 }
12265
12266 len -= size + 8;
12267 vpcc_data += size + 8;
12268 }
12269
12270 break;
12271 }
12272 default:
12273 break;
12274 }
12275 }
12276
12277 GST_INFO_OBJECT (qtdemux,
12278 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
12279 GST_FOURCC_ARGS (fourcc), entry->caps);
12280
12281 } else if (stream->subtype == FOURCC_soun) {
12282 GNode *wave;
12283 int version, samplesize;
12284 guint16 compression_id;
12285 gboolean amrwb = FALSE;
12286
12287 offset = 16;
12288 /* sample description entry (16) + sound sample description v0 (20) */
12289 if (len < 36)
12290 goto corrupt_file;
12291
12292 version = QT_UINT32 (stsd_entry_data + offset);
12293 entry->n_channels = QT_UINT16 (stsd_entry_data + offset + 8);
12294 samplesize = QT_UINT16 (stsd_entry_data + offset + 10);
12295 compression_id = QT_UINT16 (stsd_entry_data + offset + 12);
12296 entry->rate = QT_FP32 (stsd_entry_data + offset + 16);
12297
12298 GST_LOG_OBJECT (qtdemux, "version/rev: %08x", version);
12299 GST_LOG_OBJECT (qtdemux, "vendor: %08x",
12300 QT_UINT32 (stsd_entry_data + offset + 4));
12301 GST_LOG_OBJECT (qtdemux, "n_channels: %d", entry->n_channels);
12302 GST_LOG_OBJECT (qtdemux, "sample_size: %d", samplesize);
12303 GST_LOG_OBJECT (qtdemux, "compression_id: %d", compression_id);
12304 GST_LOG_OBJECT (qtdemux, "packet size: %d",
12305 QT_UINT16 (stsd_entry_data + offset + 14));
12306 GST_LOG_OBJECT (qtdemux, "sample rate: %g", entry->rate);
12307
12308 if (compression_id == 0xfffe)
12309 entry->sampled = TRUE;
12310
12311 /* first assume uncompressed audio */
12312 entry->bytes_per_sample = samplesize / 8;
12313 entry->samples_per_frame = entry->n_channels;
12314 entry->bytes_per_frame = entry->n_channels * entry->bytes_per_sample;
12315 entry->samples_per_packet = entry->samples_per_frame;
12316 entry->bytes_per_packet = entry->bytes_per_sample;
12317
12318 offset = 36;
12319
12320 if (version == 0x00010000) {
12321 /* sample description entry (16) + sound sample description v1 (20+16) */
12322 if (len < 52)
12323 goto corrupt_file;
12324
12325 /* take information from here over the normal sample description */
12326 entry->samples_per_packet = QT_UINT32 (stsd_entry_data + offset);
12327 entry->bytes_per_packet = QT_UINT32 (stsd_entry_data + offset + 4);
12328 entry->bytes_per_frame = QT_UINT32 (stsd_entry_data + offset + 8);
12329 entry->bytes_per_sample = QT_UINT32 (stsd_entry_data + offset + 12);
12330
12331 GST_LOG_OBJECT (qtdemux, "Sound sample description Version 1");
12332 GST_LOG_OBJECT (qtdemux, "samples/packet: %d",
12333 entry->samples_per_packet);
12334 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
12335 entry->bytes_per_packet);
12336 GST_LOG_OBJECT (qtdemux, "bytes/frame: %d",
12337 entry->bytes_per_frame);
12338 GST_LOG_OBJECT (qtdemux, "bytes/sample: %d",
12339 entry->bytes_per_sample);
12340
12341 if (!entry->sampled && entry->bytes_per_packet) {
12342 entry->samples_per_frame = (entry->bytes_per_frame /
12343 entry->bytes_per_packet) * entry->samples_per_packet;
12344 GST_LOG_OBJECT (qtdemux, "samples/frame: %d",
12345 entry->samples_per_frame);
12346 }
12347 } else if (version == 0x00020000) {
12348 /* sample description entry (16) + sound sample description v2 (56) */
12349 if (len < 72)
12350 goto corrupt_file;
12351
12352 /* take information from here over the normal sample description */
12353 entry->rate = GST_READ_DOUBLE_BE (stsd_entry_data + offset + 4);
12354 entry->n_channels = QT_UINT32 (stsd_entry_data + offset + 12);
12355 entry->samples_per_frame = entry->n_channels;
12356 entry->bytes_per_sample = QT_UINT32 (stsd_entry_data + offset + 20) / 8;
12357 entry->bytes_per_packet = QT_UINT32 (stsd_entry_data + offset + 28);
12358 entry->samples_per_packet = QT_UINT32 (stsd_entry_data + offset + 32);
12359 entry->bytes_per_frame = entry->bytes_per_sample * entry->n_channels;
12360
12361 GST_LOG_OBJECT (qtdemux, "Sound sample description Version 2");
12362 GST_LOG_OBJECT (qtdemux, "sample rate: %g", entry->rate);
12363 GST_LOG_OBJECT (qtdemux, "n_channels: %d", entry->n_channels);
12364 GST_LOG_OBJECT (qtdemux, "bits/channel: %d",
12365 entry->bytes_per_sample * 8);
12366 GST_LOG_OBJECT (qtdemux, "format flags: %X",
12367 QT_UINT32 (stsd_entry_data + offset + 24));
12368 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
12369 entry->bytes_per_packet);
12370 GST_LOG_OBJECT (qtdemux, "LPCM frames/packet: %d",
12371 entry->samples_per_packet);
12372 } else if (version != 0x00000) {
12373 GST_WARNING_OBJECT (qtdemux, "unknown audio STSD version %08x",
12374 version);
12375 }
12376
12377 switch (fourcc) {
12378 /* Yes, these have to be hard-coded */
12379 case FOURCC_MAC6:
12380 {
12381 entry->samples_per_packet = 6;
12382 entry->bytes_per_packet = 1;
12383 entry->bytes_per_frame = 1 * entry->n_channels;
12384 entry->bytes_per_sample = 1;
12385 entry->samples_per_frame = 6 * entry->n_channels;
12386 break;
12387 }
12388 case FOURCC_MAC3:
12389 {
12390 entry->samples_per_packet = 3;
12391 entry->bytes_per_packet = 1;
12392 entry->bytes_per_frame = 1 * entry->n_channels;
12393 entry->bytes_per_sample = 1;
12394 entry->samples_per_frame = 3 * entry->n_channels;
12395 break;
12396 }
12397 case FOURCC_ima4:
12398 {
12399 entry->samples_per_packet = 64;
12400 entry->bytes_per_packet = 34;
12401 entry->bytes_per_frame = 34 * entry->n_channels;
12402 entry->bytes_per_sample = 2;
12403 entry->samples_per_frame = 64 * entry->n_channels;
12404 break;
12405 }
12406 case FOURCC_ulaw:
12407 case FOURCC_alaw:
12408 {
12409 entry->samples_per_packet = 1;
12410 entry->bytes_per_packet = 1;
12411 entry->bytes_per_frame = 1 * entry->n_channels;
12412 entry->bytes_per_sample = 1;
12413 entry->samples_per_frame = 1 * entry->n_channels;
12414 break;
12415 }
12416 case FOURCC_agsm:
12417 {
12418 entry->samples_per_packet = 160;
12419 entry->bytes_per_packet = 33;
12420 entry->bytes_per_frame = 33 * entry->n_channels;
12421 entry->bytes_per_sample = 2;
12422 entry->samples_per_frame = 160 * entry->n_channels;
12423 break;
12424 }
12425 /* fix up any invalid header information from above */
12426 case FOURCC_twos:
12427 case FOURCC_sowt:
12428 case FOURCC_raw_:
12429 case FOURCC_lpcm:
12430 /* Sometimes these are set to 0 in the sound sample descriptions so
12431 * let's try to infer useful values from the other information we
12432 * have available */
12433 if (entry->bytes_per_sample == 0)
12434 entry->bytes_per_sample =
12435 entry->bytes_per_frame / entry->n_channels;
12436 if (entry->bytes_per_sample == 0)
12437 entry->bytes_per_sample = samplesize / 8;
12438
12439 if (entry->bytes_per_frame == 0)
12440 entry->bytes_per_frame =
12441 entry->bytes_per_sample * entry->n_channels;
12442
12443 if (entry->bytes_per_packet == 0)
12444 entry->bytes_per_packet = entry->bytes_per_sample;
12445
12446 if (entry->samples_per_frame == 0)
12447 entry->samples_per_frame = entry->n_channels;
12448
12449 if (entry->samples_per_packet == 0)
12450 entry->samples_per_packet = entry->samples_per_frame;
12451
12452 break;
12453 case FOURCC_in24:
12454 case FOURCC_in32:
12455 case FOURCC_fl32:
12456 case FOURCC_fl64:
12457 case FOURCC_s16l:{
12458 switch (fourcc) {
12459 case FOURCC_in24:
12460 entry->bytes_per_sample = 3;
12461 break;
12462 case FOURCC_in32:
12463 case FOURCC_fl32:
12464 entry->bytes_per_sample = 4;
12465 break;
12466 case FOURCC_fl64:
12467 entry->bytes_per_sample = 8;
12468 break;
12469 case FOURCC_s16l:
12470 entry->bytes_per_sample = 2;
12471 break;
12472 default:
12473 g_assert_not_reached ();
12474 break;
12475 }
12476 entry->samples_per_frame = entry->n_channels;
12477 entry->bytes_per_frame = entry->n_channels * entry->bytes_per_sample;
12478 entry->samples_per_packet = entry->samples_per_frame;
12479 entry->bytes_per_packet = entry->bytes_per_sample;
12480 break;
12481 }
12482 default:
12483 break;
12484 }
12485
12486 if (entry->caps)
12487 gst_caps_unref (entry->caps);
12488
12489 entry->caps = qtdemux_audio_caps (qtdemux, stream, entry, fourcc,
12490 stsd_entry_data + 32, len - 16, &codec);
12491
12492 switch (fourcc) {
12493 case FOURCC_in24:
12494 case FOURCC_in32:
12495 case FOURCC_fl32:
12496 case FOURCC_fl64:
12497 {
12498 GNode *enda;
12499 GNode *fmt;
12500
12501 fmt = qtdemux_tree_get_child_by_type (stsd, fourcc);
12502
12503 enda = qtdemux_tree_get_child_by_type (fmt, FOURCC_enda);
12504 if (!enda) {
12505 wave = qtdemux_tree_get_child_by_type (fmt, FOURCC_wave);
12506 if (wave)
12507 enda = qtdemux_tree_get_child_by_type (wave, FOURCC_enda);
12508 }
12509 if (enda) {
12510 int enda_value = QT_UINT16 ((guint8 *) enda->data + 8);
12511 const gchar *format_str;
12512
12513 switch (fourcc) {
12514 case FOURCC_in24:
12515 format_str = (enda_value) ? "S24LE" : "S24BE";
12516 break;
12517 case FOURCC_in32:
12518 format_str = (enda_value) ? "S32LE" : "S32BE";
12519 break;
12520 case FOURCC_fl32:
12521 format_str = (enda_value) ? "F32LE" : "F32BE";
12522 break;
12523 case FOURCC_fl64:
12524 format_str = (enda_value) ? "F64LE" : "F64BE";
12525 break;
12526 default:
12527 g_assert_not_reached ();
12528 break;
12529 }
12530 gst_caps_set_simple (entry->caps,
12531 "format", G_TYPE_STRING, format_str, NULL);
12532 }
12533 break;
12534 }
12535 case FOURCC_owma:
12536 {
12537 const guint8 *owma_data;
12538 const gchar *codec_name = NULL;
12539 guint owma_len;
12540 GstBuffer *buf;
12541 gint version = 1;
12542 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
12543 /* FIXME this should also be gst_riff_strf_auds,
12544 * but the latter one is actually missing bits-per-sample :( */
12545 typedef struct
12546 {
12547 gint16 wFormatTag;
12548 gint16 nChannels;
12549 gint32 nSamplesPerSec;
12550 gint32 nAvgBytesPerSec;
12551 gint16 nBlockAlign;
12552 gint16 wBitsPerSample;
12553 gint16 cbSize;
12554 } WAVEFORMATEX;
12555 WAVEFORMATEX *wfex;
12556
12557 GST_DEBUG_OBJECT (qtdemux, "parse owma");
12558 owma_data = stsd_entry_data;
12559 owma_len = QT_UINT32 (owma_data);
12560 if (owma_len <= 54) {
12561 GST_WARNING_OBJECT (qtdemux, "Too small owma header, skipping");
12562 break;
12563 }
12564 wfex = (WAVEFORMATEX *) (owma_data + 36);
12565 buf = gst_buffer_new_and_alloc (owma_len - 54);
12566 gst_buffer_fill (buf, 0, owma_data + 54, owma_len - 54);
12567 if (wfex->wFormatTag == 0x0161) {
12568 codec_name = "Windows Media Audio";
12569 version = 2;
12570 } else if (wfex->wFormatTag == 0x0162) {
12571 codec_name = "Windows Media Audio 9 Pro";
12572 version = 3;
12573 } else if (wfex->wFormatTag == 0x0163) {
12574 codec_name = "Windows Media Audio 9 Lossless";
12575 /* is that correct? gstffmpegcodecmap.c is missing it, but
12576 * fluendo codec seems to support it */
12577 version = 4;
12578 }
12579
12580 gst_caps_set_simple (entry->caps,
12581 "codec_data", GST_TYPE_BUFFER, buf,
12582 "wmaversion", G_TYPE_INT, version,
12583 "block_align", G_TYPE_INT,
12584 GST_READ_UINT16_LE (&wfex->nBlockAlign), "bitrate", G_TYPE_INT,
12585 GST_READ_UINT32_LE (&wfex->nAvgBytesPerSec), "width", G_TYPE_INT,
12586 GST_READ_UINT16_LE (&wfex->wBitsPerSample), "depth", G_TYPE_INT,
12587 GST_READ_UINT16_LE (&wfex->wBitsPerSample), NULL);
12588 gst_buffer_unref (buf);
12589
12590 if (codec_name) {
12591 g_free (codec);
12592 codec = g_strdup (codec_name);
12593 }
12594 break;
12595 }
12596 case FOURCC_wma_:
12597 {
12598 gint len = QT_UINT32 (stsd_entry_data) - offset;
12599 const guint8 *wfex_data = stsd_entry_data + offset;
12600 const gchar *codec_name = NULL;
12601 gint version = 1;
12602 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
12603 /* FIXME this should also be gst_riff_strf_auds,
12604 * but the latter one is actually missing bits-per-sample :( */
12605 typedef struct
12606 {
12607 gint16 wFormatTag;
12608 gint16 nChannels;
12609 gint32 nSamplesPerSec;
12610 gint32 nAvgBytesPerSec;
12611 gint16 nBlockAlign;
12612 gint16 wBitsPerSample;
12613 gint16 cbSize;
12614 } WAVEFORMATEX;
12615 WAVEFORMATEX wfex;
12616
12617 /* FIXME: unify with similar wavformatex parsing code above */
12618 GST_DEBUG_OBJECT (qtdemux, "parse wma, looking for wfex");
12619
12620 /* find wfex */
12621 while (len >= 8) {
12622 gint size;
12623
12624 if (QT_UINT32 (wfex_data) <= len)
12625 size = QT_UINT32 (wfex_data) - 8;
12626 else
12627 size = len - 8;
12628
12629 if (size < 1)
12630 /* No real data, so break out */
12631 break;
12632
12633 switch (QT_FOURCC (wfex_data + 4)) {
12634 case GST_MAKE_FOURCC ('w', 'f', 'e', 'x'):
12635 {
12636 GST_DEBUG_OBJECT (qtdemux, "found wfex in stsd");
12637
12638 if (size < 8 + 18)
12639 break;
12640
12641 wfex.wFormatTag = GST_READ_UINT16_LE (wfex_data + 8 + 0);
12642 wfex.nChannels = GST_READ_UINT16_LE (wfex_data + 8 + 2);
12643 wfex.nSamplesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 4);
12644 wfex.nAvgBytesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 8);
12645 wfex.nBlockAlign = GST_READ_UINT16_LE (wfex_data + 8 + 12);
12646 wfex.wBitsPerSample = GST_READ_UINT16_LE (wfex_data + 8 + 14);
12647 wfex.cbSize = GST_READ_UINT16_LE (wfex_data + 8 + 16);
12648
12649 GST_LOG_OBJECT (qtdemux, "Found wfex box in stsd:");
12650 GST_LOG_OBJECT (qtdemux, "FormatTag = 0x%04x, Channels = %u, "
12651 "SamplesPerSec = %u, AvgBytesPerSec = %u, BlockAlign = %u, "
12652 "BitsPerSample = %u, Size = %u", wfex.wFormatTag,
12653 wfex.nChannels, wfex.nSamplesPerSec, wfex.nAvgBytesPerSec,
12654 wfex.nBlockAlign, wfex.wBitsPerSample, wfex.cbSize);
12655
12656 if (wfex.wFormatTag == 0x0161) {
12657 codec_name = "Windows Media Audio";
12658 version = 2;
12659 } else if (wfex.wFormatTag == 0x0162) {
12660 codec_name = "Windows Media Audio 9 Pro";
12661 version = 3;
12662 } else if (wfex.wFormatTag == 0x0163) {
12663 codec_name = "Windows Media Audio 9 Lossless";
12664 /* is that correct? gstffmpegcodecmap.c is missing it, but
12665 * fluendo codec seems to support it */
12666 version = 4;
12667 }
12668
12669 gst_caps_set_simple (entry->caps,
12670 "wmaversion", G_TYPE_INT, version,
12671 "block_align", G_TYPE_INT, wfex.nBlockAlign,
12672 "bitrate", G_TYPE_INT, wfex.nAvgBytesPerSec,
12673 "width", G_TYPE_INT, wfex.wBitsPerSample,
12674 "depth", G_TYPE_INT, wfex.wBitsPerSample, NULL);
12675
12676 if (size > wfex.cbSize) {
12677 GstBuffer *buf;
12678
12679 buf = gst_buffer_new_and_alloc (size - wfex.cbSize);
12680 gst_buffer_fill (buf, 0, wfex_data + 8 + wfex.cbSize,
12681 size - wfex.cbSize);
12682 gst_caps_set_simple (entry->caps,
12683 "codec_data", GST_TYPE_BUFFER, buf, NULL);
12684 gst_buffer_unref (buf);
12685 } else {
12686 GST_WARNING_OBJECT (qtdemux, "no codec data");
12687 }
12688
12689 if (codec_name) {
12690 g_free (codec);
12691 codec = g_strdup (codec_name);
12692 }
12693 break;
12694 }
12695 default:
12696 break;
12697 }
12698 len -= size + 8;
12699 wfex_data += size + 8;
12700 }
12701 break;
12702 }
12703 case FOURCC_opus:
12704 {
12705 const guint8 *dops_data;
12706 guint8 *channel_mapping = NULL;
12707 guint32 rate;
12708 guint8 channels;
12709 guint8 channel_mapping_family;
12710 guint8 stream_count;
12711 guint8 coupled_count;
12712 guint8 i;
12713
12714 version = GST_READ_UINT16_BE (stsd_entry_data + 16);
12715 if (version == 1)
12716 dops_data = stsd_entry_data + 51;
12717 else
12718 dops_data = stsd_entry_data + 35;
12719
12720 channels = GST_READ_UINT8 (dops_data + 10);
12721 rate = GST_READ_UINT32_LE (dops_data + 13);
12722 channel_mapping_family = GST_READ_UINT8 (dops_data + 19);
12723 stream_count = GST_READ_UINT8 (dops_data + 20);
12724 coupled_count = GST_READ_UINT8 (dops_data + 21);
12725
12726 if (channels > 0) {
12727 channel_mapping = g_malloc (channels * sizeof (guint8));
12728 for (i = 0; i < channels; i++)
12729 channel_mapping[i] = GST_READ_UINT8 (dops_data + i + 22);
12730 }
12731
12732 entry->caps = gst_codec_utils_opus_create_caps (rate, channels,
12733 channel_mapping_family, stream_count, coupled_count,
12734 channel_mapping);
12735 g_free (channel_mapping);
12736 break;
12737 }
12738 default:
12739 break;
12740 }
12741
12742 if (codec) {
12743 GstStructure *s;
12744 gint bitrate = 0;
12745
12746 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12747 GST_TAG_AUDIO_CODEC, codec, NULL);
12748 g_free (codec);
12749 codec = NULL;
12750
12751 /* some bitrate info may have ended up in caps */
12752 s = gst_caps_get_structure (entry->caps, 0);
12753 gst_structure_get_int (s, "bitrate", &bitrate);
12754 if (bitrate > 0)
12755 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12756 GST_TAG_BITRATE, bitrate, NULL);
12757 }
12758
12759 esds = NULL;
12760 mp4a = qtdemux_tree_get_child_by_index (stsd, stsd_index);
12761 if (QTDEMUX_TREE_NODE_FOURCC (mp4a) != fourcc) {
12762 if (stream->protected) {
12763 if (QTDEMUX_TREE_NODE_FOURCC (mp4a) == FOURCC_aavd) {
12764 esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
12765 }
12766 if (QTDEMUX_TREE_NODE_FOURCC (mp4a) != FOURCC_enca) {
12767 mp4a = NULL;
12768 }
12769 } else {
12770 mp4a = NULL;
12771 }
12772 }
12773
12774 wave = NULL;
12775 if (mp4a) {
12776 wave = qtdemux_tree_get_child_by_type (mp4a, FOURCC_wave);
12777 if (wave)
12778 esds = qtdemux_tree_get_child_by_type (wave, FOURCC_esds);
12779 if (!esds)
12780 esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
12781 }
12782
12783
12784 /* If the fourcc's bottom 16 bits gives 'sm', then the top
12785 16 bits is a byte-swapped wave-style codec identifier,
12786 and we can find a WAVE header internally to a 'wave' atom here.
12787 This can more clearly be thought of as 'ms' as the top 16 bits, and a
12788 codec id as the bottom 16 bits - but byte-swapped to store in QT (which
12789 is big-endian).
12790 */
12791 if ((fourcc & 0xffff) == (('s' << 8) | 'm')) {
12792 if (len < offset + 20) {
12793 GST_WARNING_OBJECT (qtdemux, "No wave atom in MS-style audio");
12794 } else {
12795 guint32 datalen = QT_UINT32 (stsd_entry_data + offset + 16);
12796 const guint8 *data = stsd_entry_data + offset + 16;
12797 GNode *wavenode;
12798 GNode *waveheadernode;
12799
12800 wavenode = g_node_new ((guint8 *) data);
12801 if (qtdemux_parse_node (qtdemux, wavenode, data, datalen)) {
12802 const guint8 *waveheader;
12803 guint32 headerlen;
12804
12805 waveheadernode = qtdemux_tree_get_child_by_type (wavenode, fourcc);
12806 if (waveheadernode) {
12807 waveheader = (const guint8 *) waveheadernode->data;
12808 headerlen = QT_UINT32 (waveheader);
12809
12810 if (headerlen > 8) {
12811 gst_riff_strf_auds *header = NULL;
12812 GstBuffer *headerbuf;
12813 GstBuffer *extra;
12814
12815 waveheader += 8;
12816 headerlen -= 8;
12817
12818 headerbuf = gst_buffer_new_and_alloc (headerlen);
12819 gst_buffer_fill (headerbuf, 0, waveheader, headerlen);
12820
12821 if (gst_riff_parse_strf_auds (GST_ELEMENT_CAST (qtdemux),
12822 headerbuf, &header, &extra)) {
12823 gst_caps_unref (entry->caps);
12824 /* FIXME: Need to do something with the channel reorder map */
12825 entry->caps =
12826 gst_riff_create_audio_caps (header->format, NULL, header,
12827 extra, NULL, NULL, NULL);
12828
12829 if (extra)
12830 gst_buffer_unref (extra);
12831 g_free (header);
12832 }
12833 }
12834 } else
12835 GST_DEBUG ("Didn't find waveheadernode for this codec");
12836 }
12837 g_node_destroy (wavenode);
12838 }
12839 } else if (esds) {
12840 gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
12841 stream->stream_tags);
12842 } else {
12843 switch (fourcc) {
12844 #if 0
12845 /* FIXME: what is in the chunk? */
12846 case FOURCC_QDMC:
12847 {
12848 gint len = QT_UINT32 (stsd_data);
12849
12850 /* seems to be always = 116 = 0x74 */
12851 break;
12852 }
12853 #endif
12854 case FOURCC_QDM2:
12855 {
12856 gint len = QT_UINT32 (stsd_entry_data);
12857
12858 if (len > 0x3C) {
12859 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x3C);
12860
12861 gst_buffer_fill (buf, 0, stsd_entry_data + 0x3C, len - 0x3C);
12862 gst_caps_set_simple (entry->caps,
12863 "codec_data", GST_TYPE_BUFFER, buf, NULL);
12864 gst_buffer_unref (buf);
12865 }
12866 gst_caps_set_simple (entry->caps,
12867 "samplesize", G_TYPE_INT, samplesize, NULL);
12868 break;
12869 }
12870 case FOURCC_alac:
12871 {
12872 GNode *alac, *wave = NULL;
12873
12874 /* apparently, m4a has this atom appended directly in the stsd entry,
12875 * while mov has it in a wave atom */
12876 alac = qtdemux_tree_get_child_by_type (stsd, FOURCC_alac);
12877 if (alac) {
12878 /* alac now refers to stsd entry atom */
12879 wave = qtdemux_tree_get_child_by_type (alac, FOURCC_wave);
12880 if (wave)
12881 alac = qtdemux_tree_get_child_by_type (wave, FOURCC_alac);
12882 else
12883 alac = qtdemux_tree_get_child_by_type (alac, FOURCC_alac);
12884 }
12885 if (alac) {
12886 const guint8 *alac_data = alac->data;
12887 gint len = QT_UINT32 (alac->data);
12888 GstBuffer *buf;
12889
12890 if (len < 36) {
12891 GST_DEBUG_OBJECT (qtdemux,
12892 "discarding alac atom with unexpected len %d", len);
12893 } else {
12894 /* codec-data contains alac atom size and prefix,
12895 * ffmpeg likes it that way, not quite gst-ish though ...*/
12896 buf = gst_buffer_new_and_alloc (len);
12897 gst_buffer_fill (buf, 0, alac->data, len);
12898 gst_caps_set_simple (entry->caps,
12899 "codec_data", GST_TYPE_BUFFER, buf, NULL);
12900 gst_buffer_unref (buf);
12901
12902 entry->bytes_per_frame = QT_UINT32 (alac_data + 12);
12903 entry->n_channels = QT_UINT8 (alac_data + 21);
12904 entry->rate = QT_UINT32 (alac_data + 32);
12905 samplesize = QT_UINT8 (alac_data + 16 + 1);
12906 }
12907 }
12908 gst_caps_set_simple (entry->caps,
12909 "samplesize", G_TYPE_INT, samplesize, NULL);
12910 break;
12911 }
12912 case FOURCC_fLaC:
12913 {
12914 /* The codingname of the sample entry is 'fLaC' */
12915 GNode *flac = qtdemux_tree_get_child_by_type (stsd, FOURCC_fLaC);
12916
12917 if (flac) {
12918 /* The 'dfLa' box is added to the sample entry to convey
12919 initializing information for the decoder. */
12920 const GNode *dfla =
12921 qtdemux_tree_get_child_by_type (flac, FOURCC_dfLa);
12922
12923 if (dfla) {
12924 const guint32 len = QT_UINT32 (dfla->data);
12925
12926 /* Must contain at least dfLa box header (12),
12927 * METADATA_BLOCK_HEADER (4), METADATA_BLOCK_STREAMINFO (34) */
12928 if (len < 50) {
12929 GST_DEBUG_OBJECT (qtdemux,
12930 "discarding dfla atom with unexpected len %d", len);
12931 } else {
12932 /* skip dfLa header to get the METADATA_BLOCKs */
12933 const guint8 *metadata_blocks = (guint8 *) dfla->data + 12;
12934 const guint32 metadata_blocks_len = len - 12;
12935
12936 gchar *stream_marker = g_strdup ("fLaC");
12937 GstBuffer *block = gst_buffer_new_wrapped (stream_marker,
12938 strlen (stream_marker));
12939
12940 guint32 index = 0;
12941 guint32 remainder = 0;
12942 guint32 block_size = 0;
12943 gboolean is_last = FALSE;
12944
12945 GValue array = G_VALUE_INIT;
12946 GValue value = G_VALUE_INIT;
12947
12948 g_value_init (&array, GST_TYPE_ARRAY);
12949 g_value_init (&value, GST_TYPE_BUFFER);
12950
12951 gst_value_set_buffer (&value, block);
12952 gst_value_array_append_value (&array, &value);
12953 g_value_reset (&value);
12954
12955 gst_buffer_unref (block);
12956
12957 /* check there's at least one METADATA_BLOCK_HEADER's worth
12958 * of data, and we haven't already finished parsing */
12959 while (!is_last && ((index + 3) < metadata_blocks_len)) {
12960 remainder = metadata_blocks_len - index;
12961
12962 /* add the METADATA_BLOCK_HEADER size to the signalled size */
12963 block_size = 4 +
12964 (metadata_blocks[index + 1] << 16) +
12965 (metadata_blocks[index + 2] << 8) +
12966 metadata_blocks[index + 3];
12967
12968 /* be careful not to read off end of box */
12969 if (block_size > remainder) {
12970 break;
12971 }
12972
12973 is_last = metadata_blocks[index] >> 7;
12974
12975 block = gst_buffer_new_and_alloc (block_size);
12976
12977 gst_buffer_fill (block, 0, &metadata_blocks[index],
12978 block_size);
12979
12980 gst_value_set_buffer (&value, block);
12981 gst_value_array_append_value (&array, &value);
12982 g_value_reset (&value);
12983
12984 gst_buffer_unref (block);
12985
12986 index += block_size;
12987 }
12988
12989 /* only append the metadata if we successfully read all of it */
12990 if (is_last) {
12991 gst_structure_set_value (gst_caps_get_structure (CUR_STREAM
12992 (stream)->caps, 0), "streamheader", &array);
12993 } else {
12994 GST_WARNING_OBJECT (qtdemux,
12995 "discarding all METADATA_BLOCKs due to invalid "
12996 "block_size %d at idx %d, rem %d", block_size, index,
12997 remainder);
12998 }
12999
13000 g_value_unset (&value);
13001 g_value_unset (&array);
13002
13003 /* The sample rate obtained from the stsd may not be accurate
13004 * since it cannot represent rates greater than 65535Hz, so
13005 * override that value with the sample rate from the
13006 * METADATA_BLOCK_STREAMINFO block */
13007 CUR_STREAM (stream)->rate =
13008 (QT_UINT32 (metadata_blocks + 14) >> 12) & 0xFFFFF;
13009 }
13010 }
13011 }
13012 break;
13013 }
13014 case FOURCC_sawb:
13015 /* Fallthrough! */
13016 amrwb = TRUE;
13017 case FOURCC_samr:
13018 {
13019 gint len = QT_UINT32 (stsd_entry_data);
13020
13021 if (len > 0x24) {
13022 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x24);
13023 guint bitrate;
13024
13025 gst_buffer_fill (buf, 0, stsd_entry_data + 0x24, len - 0x24);
13026
13027 /* If we have enough data, let's try to get the 'damr' atom. See
13028 * the 3GPP container spec (26.244) for more details. */
13029 if ((len - 0x34) > 8 &&
13030 (bitrate = qtdemux_parse_amr_bitrate (buf, amrwb))) {
13031 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
13032 GST_TAG_MAXIMUM_BITRATE, bitrate, NULL);
13033 }
13034
13035 gst_caps_set_simple (entry->caps,
13036 "codec_data", GST_TYPE_BUFFER, buf, NULL);
13037 gst_buffer_unref (buf);
13038 }
13039 break;
13040 }
13041 case FOURCC_mp4a:
13042 {
13043 /* mp4a atom withtout ESDS; Attempt to build codec data from atom */
13044 gint len = QT_UINT32 (stsd_entry_data);
13045 guint16 sound_version = 0;
13046 /* FIXME: Can this be determined somehow? There doesn't seem to be
13047 * anything in mp4a atom that specifis compression */
13048 gint profile = 2;
13049 guint16 channels = entry->n_channels;
13050 guint32 time_scale = (guint32) entry->rate;
13051 gint sample_rate_index = -1;
13052
13053 if (len >= 34) {
13054 sound_version = QT_UINT16 (stsd_entry_data + 16);
13055
13056 if (sound_version == 1) {
13057 channels = QT_UINT16 (stsd_entry_data + 24);
13058 time_scale = QT_UINT32 (stsd_entry_data + 30);
13059 } else {
13060 GST_FIXME_OBJECT (qtdemux, "Unhandled mp4a atom version %d",
13061 sound_version);
13062 }
13063 } else {
13064 GST_DEBUG_OBJECT (qtdemux, "Too small stsd entry data len %d",
13065 len);
13066 }
13067
13068 sample_rate_index =
13069 gst_codec_utils_aac_get_index_from_sample_rate (time_scale);
13070 if (sample_rate_index >= 0 && channels > 0) {
13071 guint8 codec_data[2];
13072 GstBuffer *buf;
13073
13074 /* build AAC codec data */
13075 codec_data[0] = profile << 3;
13076 codec_data[0] |= ((sample_rate_index >> 1) & 0x7);
13077 codec_data[1] = (sample_rate_index & 0x01) << 7;
13078 codec_data[1] |= (channels & 0xF) << 3;
13079
13080 buf = gst_buffer_new_and_alloc (2);
13081 gst_buffer_fill (buf, 0, codec_data, 2);
13082 gst_caps_set_simple (entry->caps,
13083 "codec_data", GST_TYPE_BUFFER, buf, NULL);
13084 gst_buffer_unref (buf);
13085 }
13086 break;
13087 }
13088 case FOURCC_lpcm:
13089 case FOURCC_in24:
13090 case FOURCC_in32:
13091 case FOURCC_fl32:
13092 case FOURCC_fl64:
13093 case FOURCC_s16l:
13094 /* Fully handled elsewhere */
13095 break;
13096 default:
13097 GST_INFO_OBJECT (qtdemux,
13098 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
13099 break;
13100 }
13101 }
13102 GST_INFO_OBJECT (qtdemux,
13103 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
13104 GST_FOURCC_ARGS (fourcc), entry->caps);
13105
13106 } else if (stream->subtype == FOURCC_strm) {
13107 if (fourcc == FOURCC_rtsp) {
13108 stream->redirect_uri = qtdemux_get_rtsp_uri_from_hndl (qtdemux, minf);
13109 } else {
13110 GST_INFO_OBJECT (qtdemux, "unhandled stream type %" GST_FOURCC_FORMAT,
13111 GST_FOURCC_ARGS (fourcc));
13112 goto unknown_stream;
13113 }
13114 entry->sampled = TRUE;
13115 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
13116 || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt
13117 || stream->subtype == FOURCC_clcp || stream->subtype == FOURCC_wvtt) {
13118
13119 entry->sampled = TRUE;
13120 entry->sparse = TRUE;
13121
13122 entry->caps =
13123 qtdemux_sub_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
13124 &codec);
13125 if (codec) {
13126 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
13127 GST_TAG_SUBTITLE_CODEC, codec, NULL);
13128 g_free (codec);
13129 codec = NULL;
13130 }
13131
13132 /* hunt for sort-of codec data */
13133 switch (fourcc) {
13134 case FOURCC_mp4s:
13135 {
13136 GNode *mp4s = NULL;
13137 GNode *esds = NULL;
13138
13139 /* look for palette in a stsd->mp4s->esds sub-atom */
13140 mp4s = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4s);
13141 if (mp4s)
13142 esds = qtdemux_tree_get_child_by_type (mp4s, FOURCC_esds);
13143 if (esds == NULL) {
13144 /* Invalid STSD */
13145 GST_LOG_OBJECT (qtdemux, "Skipping invalid stsd: no esds child");
13146 break;
13147 }
13148
13149 gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
13150 stream->stream_tags);
13151 break;
13152 }
13153 default:
13154 GST_INFO_OBJECT (qtdemux,
13155 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
13156 break;
13157 }
13158 GST_INFO_OBJECT (qtdemux,
13159 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
13160 GST_FOURCC_ARGS (fourcc), entry->caps);
13161 } else {
13162 /* everything in 1 sample */
13163 entry->sampled = TRUE;
13164
13165 entry->caps =
13166 qtdemux_generic_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
13167 &codec);
13168
13169 if (entry->caps == NULL)
13170 goto unknown_stream;
13171
13172 if (codec) {
13173 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
13174 GST_TAG_SUBTITLE_CODEC, codec, NULL);
13175 g_free (codec);
13176 codec = NULL;
13177 }
13178 }
13179
13180 /* promote to sampled format */
13181 if (entry->fourcc == FOURCC_samr) {
13182 /* force mono 8000 Hz for AMR */
13183 entry->sampled = TRUE;
13184 entry->n_channels = 1;
13185 entry->rate = 8000;
13186 } else if (entry->fourcc == FOURCC_sawb) {
13187 /* force mono 16000 Hz for AMR-WB */
13188 entry->sampled = TRUE;
13189 entry->n_channels = 1;
13190 entry->rate = 16000;
13191 } else if (entry->fourcc == FOURCC_mp4a) {
13192 entry->sampled = TRUE;
13193 }
13194
13195
13196 stsd_entry_data += len;
13197 remaining_stsd_len -= len;
13198
13199 }
13200
13201 /* collect sample information */
13202 if (!qtdemux_stbl_init (qtdemux, stream, stbl))
13203 goto samples_failed;
13204
13205 if (qtdemux->fragmented) {
13206 guint64 offset;
13207
13208 /* need all moov samples as basis; probably not many if any at all */
13209 /* prevent moof parsing taking of at this time */
13210 offset = qtdemux->moof_offset;
13211 qtdemux->moof_offset = 0;
13212 if (stream->n_samples &&
13213 !qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
13214 qtdemux->moof_offset = offset;
13215 goto samples_failed;
13216 }
13217 qtdemux->moof_offset = offset;
13218 /* movie duration more reliable in this case (e.g. mehd) */
13219 if (qtdemux->segment.duration &&
13220 GST_CLOCK_TIME_IS_VALID (qtdemux->segment.duration))
13221 stream->duration =
13222 GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->segment.duration);
13223 }
13224
13225 /* configure segments */
13226 if (!qtdemux_parse_segments (qtdemux, stream, trak))
13227 goto segments_failed;
13228
13229 /* add some language tag, if useful */
13230 if (stream->lang_id[0] != '\0' && strcmp (stream->lang_id, "unk") &&
13231 strcmp (stream->lang_id, "und")) {
13232 const gchar *lang_code;
13233
13234 /* convert ISO 639-2 code to ISO 639-1 */
13235 lang_code = gst_tag_get_language_code (stream->lang_id);
13236 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
13237 GST_TAG_LANGUAGE_CODE, (lang_code) ? lang_code : stream->lang_id, NULL);
13238 }
13239
13240 /* Check for UDTA tags */
13241 if ((udta = qtdemux_tree_get_child_by_type (trak, FOURCC_udta))) {
13242 qtdemux_parse_udta (qtdemux, stream->stream_tags, udta);
13243 }
13244
13245 /* Insert and sort new stream in track-id order.
13246 * This will help in comparing old/new streams during stream update check */
13247 g_ptr_array_add (qtdemux->active_streams, stream);
13248 g_ptr_array_sort (qtdemux->active_streams,
13249 (GCompareFunc) qtdemux_track_id_compare_func);
13250 GST_DEBUG_OBJECT (qtdemux, "n_streams is now %d",
13251 QTDEMUX_N_STREAMS (qtdemux));
13252
13253 return TRUE;
13254
13255 /* ERRORS */
13256 corrupt_file:
13257 {
13258 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
13259 (_("This file is corrupt and cannot be played.")), (NULL));
13260 if (stream)
13261 gst_qtdemux_stream_unref (stream);
13262 return FALSE;
13263 }
13264 error_encrypted:
13265 {
13266 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT, (NULL), (NULL));
13267 gst_qtdemux_stream_unref (stream);
13268 return FALSE;
13269 }
13270 samples_failed:
13271 segments_failed:
13272 {
13273 /* we posted an error already */
13274 /* free stbl sub-atoms */
13275 gst_qtdemux_stbl_free (stream);
13276 gst_qtdemux_stream_unref (stream);
13277 return FALSE;
13278 }
13279 existing_stream:
13280 {
13281 GST_INFO_OBJECT (qtdemux, "stream with track id %i already exists",
13282 track_id);
13283 return TRUE;
13284 }
13285 unknown_stream:
13286 {
13287 GST_INFO_OBJECT (qtdemux, "unknown subtype %" GST_FOURCC_FORMAT,
13288 GST_FOURCC_ARGS (stream->subtype));
13289 gst_qtdemux_stream_unref (stream);
13290 return TRUE;
13291 }
13292 }
13293
13294 /* If we can estimate the overall bitrate, and don't have information about the
13295 * stream bitrate for exactly one stream, this guesses the stream bitrate as
13296 * the overall bitrate minus the sum of the bitrates of all other streams. This
13297 * should be useful for the common case where we have one audio and one video
13298 * stream and can estimate the bitrate of one, but not the other. */
13299 static void
gst_qtdemux_guess_bitrate(GstQTDemux * qtdemux)13300 gst_qtdemux_guess_bitrate (GstQTDemux * qtdemux)
13301 {
13302 QtDemuxStream *stream = NULL;
13303 gint64 size, sys_bitrate, sum_bitrate = 0;
13304 GstClockTime duration;
13305 guint bitrate;
13306 gint i;
13307
13308 if (qtdemux->fragmented)
13309 return;
13310
13311 GST_DEBUG_OBJECT (qtdemux, "Looking for streams with unknown bitrate");
13312
13313 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &size)
13314 || size <= 0) {
13315 GST_DEBUG_OBJECT (qtdemux,
13316 "Size in bytes of the stream not known - bailing");
13317 return;
13318 }
13319
13320 /* Subtract the header size */
13321 GST_DEBUG_OBJECT (qtdemux, "Total size %" G_GINT64_FORMAT ", header size %u",
13322 size, qtdemux->header_size);
13323
13324 if (size < qtdemux->header_size)
13325 return;
13326
13327 size = size - qtdemux->header_size;
13328
13329 if (!gst_qtdemux_get_duration (qtdemux, &duration)) {
13330 GST_DEBUG_OBJECT (qtdemux, "Stream duration not known - bailing");
13331 return;
13332 }
13333
13334 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13335 QtDemuxStream *str = QTDEMUX_NTH_STREAM (qtdemux, i);
13336 switch (str->subtype) {
13337 case FOURCC_soun:
13338 case FOURCC_vide:
13339 GST_DEBUG_OBJECT (qtdemux, "checking bitrate for %" GST_PTR_FORMAT,
13340 CUR_STREAM (str)->caps);
13341 /* retrieve bitrate, prefer avg then max */
13342 bitrate = 0;
13343 if (str->stream_tags) {
13344 if (gst_tag_list_get_uint (str->stream_tags,
13345 GST_TAG_MAXIMUM_BITRATE, &bitrate))
13346 GST_DEBUG_OBJECT (qtdemux, "max-bitrate: %u", bitrate);
13347 if (gst_tag_list_get_uint (str->stream_tags,
13348 GST_TAG_NOMINAL_BITRATE, &bitrate))
13349 GST_DEBUG_OBJECT (qtdemux, "nominal-bitrate: %u", bitrate);
13350 if (gst_tag_list_get_uint (str->stream_tags,
13351 GST_TAG_BITRATE, &bitrate))
13352 GST_DEBUG_OBJECT (qtdemux, "bitrate: %u", bitrate);
13353 }
13354 if (bitrate)
13355 sum_bitrate += bitrate;
13356 else {
13357 if (stream) {
13358 GST_DEBUG_OBJECT (qtdemux,
13359 ">1 stream with unknown bitrate - bailing");
13360 return;
13361 } else
13362 stream = str;
13363 }
13364
13365 default:
13366 /* For other subtypes, we assume no significant impact on bitrate */
13367 break;
13368 }
13369 }
13370
13371 if (!stream) {
13372 GST_DEBUG_OBJECT (qtdemux, "All stream bitrates are known");
13373 return;
13374 }
13375
13376 sys_bitrate = gst_util_uint64_scale (size, GST_SECOND * 8, duration);
13377
13378 if (sys_bitrate < sum_bitrate) {
13379 /* This can happen, since sum_bitrate might be derived from maximum
13380 * bitrates and not average bitrates */
13381 GST_DEBUG_OBJECT (qtdemux,
13382 "System bitrate less than sum bitrate - bailing");
13383 return;
13384 }
13385
13386 bitrate = sys_bitrate - sum_bitrate;
13387 GST_DEBUG_OBJECT (qtdemux, "System bitrate = %" G_GINT64_FORMAT
13388 ", Stream bitrate = %u", sys_bitrate, bitrate);
13389
13390 if (!stream->stream_tags)
13391 stream->stream_tags = gst_tag_list_new_empty ();
13392 else
13393 stream->stream_tags = gst_tag_list_make_writable (stream->stream_tags);
13394
13395 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
13396 GST_TAG_BITRATE, bitrate, NULL);
13397 }
13398
13399 static GstFlowReturn
qtdemux_prepare_streams(GstQTDemux * qtdemux)13400 qtdemux_prepare_streams (GstQTDemux * qtdemux)
13401 {
13402 GstFlowReturn ret = GST_FLOW_OK;
13403 gint i;
13404
13405 GST_DEBUG_OBJECT (qtdemux, "prepare %u streams", QTDEMUX_N_STREAMS (qtdemux));
13406
13407 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13408 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
13409 guint32 sample_num = 0;
13410
13411 GST_DEBUG_OBJECT (qtdemux, "track-id %u, fourcc %" GST_FOURCC_FORMAT,
13412 stream->track_id, GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
13413
13414 if (qtdemux->fragmented && qtdemux->pullbased) {
13415 /* need all moov samples first */
13416 GST_OBJECT_LOCK (qtdemux);
13417 while (stream->n_samples == 0)
13418 if ((ret = qtdemux_add_fragmented_samples (qtdemux)) != GST_FLOW_OK)
13419 break;
13420 GST_OBJECT_UNLOCK (qtdemux);
13421 } else {
13422 /* discard any stray moof */
13423 qtdemux->moof_offset = 0;
13424 }
13425
13426 /* prepare braking */
13427 if (ret != GST_FLOW_ERROR)
13428 ret = GST_FLOW_OK;
13429
13430 /* in pull mode, we should have parsed some sample info by now;
13431 * and quite some code will not handle no samples.
13432 * in push mode, we'll just have to deal with it */
13433 if (G_UNLIKELY (qtdemux->pullbased && !stream->n_samples)) {
13434 GST_DEBUG_OBJECT (qtdemux, "no samples for stream; discarding");
13435 g_ptr_array_remove_index (qtdemux->active_streams, i);
13436 i--;
13437 continue;
13438 } else if (stream->track_id == qtdemux->chapters_track_id &&
13439 (stream->subtype == FOURCC_text || stream->subtype == FOURCC_sbtl)) {
13440 /* TODO - parse chapters track and expose it as GstToc; For now just ignore it
13441 so that it doesn't look like a subtitle track */
13442 g_ptr_array_remove_index (qtdemux->active_streams, i);
13443 i--;
13444 continue;
13445 }
13446
13447 /* parse the initial sample for use in setting the frame rate cap */
13448 while (sample_num == 0 && sample_num < stream->n_samples) {
13449 if (!qtdemux_parse_samples (qtdemux, stream, sample_num))
13450 break;
13451 ++sample_num;
13452 }
13453 }
13454
13455 return ret;
13456 }
13457
13458 static gboolean
_stream_equal_func(const QtDemuxStream * stream,const gchar * stream_id)13459 _stream_equal_func (const QtDemuxStream * stream, const gchar * stream_id)
13460 {
13461 return g_strcmp0 (stream->stream_id, stream_id) == 0;
13462 }
13463
13464 static gboolean
qtdemux_is_streams_update(GstQTDemux * qtdemux)13465 qtdemux_is_streams_update (GstQTDemux * qtdemux)
13466 {
13467 gint i;
13468
13469 /* Different length, updated */
13470 if (QTDEMUX_N_STREAMS (qtdemux) != qtdemux->old_streams->len)
13471 return TRUE;
13472
13473 /* streams in list are sorted in track-id order */
13474 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13475 /* Different stream-id, updated */
13476 if (g_strcmp0 (QTDEMUX_NTH_STREAM (qtdemux, i)->stream_id,
13477 QTDEMUX_NTH_OLD_STREAM (qtdemux, i)->stream_id))
13478 return TRUE;
13479 }
13480
13481 return FALSE;
13482 }
13483
13484 static gboolean
qtdemux_reuse_and_configure_stream(GstQTDemux * qtdemux,QtDemuxStream * oldstream,QtDemuxStream * newstream)13485 qtdemux_reuse_and_configure_stream (GstQTDemux * qtdemux,
13486 QtDemuxStream * oldstream, QtDemuxStream * newstream)
13487 {
13488 /* Connect old stream's srcpad to new stream */
13489 newstream->pad = oldstream->pad;
13490 oldstream->pad = NULL;
13491
13492 /* unset new_stream to prevent stream-start event, unless we are EOS in which
13493 * case we need to force one through */
13494 newstream->new_stream = GST_PAD_IS_EOS (newstream->pad);
13495
13496 return gst_qtdemux_configure_stream (qtdemux, newstream);
13497 }
13498
13499 static gboolean
qtdemux_update_streams(GstQTDemux * qtdemux)13500 qtdemux_update_streams (GstQTDemux * qtdemux)
13501 {
13502 gint i;
13503 g_assert (qtdemux->streams_aware);
13504
13505 /* At below, figure out which stream in active_streams has identical stream-id
13506 * with that of in old_streams. If there is matching stream-id,
13507 * corresponding newstream will not be exposed again,
13508 * but demux will reuse srcpad of matched old stream
13509 *
13510 * active_streams : newly created streams from the latest moov
13511 * old_streams : existing streams (belong to previous moov)
13512 */
13513
13514 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13515 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
13516 QtDemuxStream *oldstream = NULL;
13517 guint target;
13518
13519 GST_DEBUG_OBJECT (qtdemux, "track-id %u, fourcc %" GST_FOURCC_FORMAT,
13520 stream->track_id, GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
13521
13522 if (g_ptr_array_find_with_equal_func (qtdemux->old_streams,
13523 stream->stream_id, (GEqualFunc) _stream_equal_func, &target)) {
13524 oldstream = QTDEMUX_NTH_OLD_STREAM (qtdemux, target);
13525
13526 /* null pad stream cannot be reused */
13527 if (oldstream->pad == NULL)
13528 oldstream = NULL;
13529 }
13530
13531 if (oldstream) {
13532 GST_DEBUG_OBJECT (qtdemux, "Reuse track-id %d", oldstream->track_id);
13533
13534 if (!qtdemux_reuse_and_configure_stream (qtdemux, oldstream, stream))
13535 return FALSE;
13536
13537 /* we don't need to preserve order of old streams */
13538 g_ptr_array_remove_fast (qtdemux->old_streams, oldstream);
13539 } else {
13540 GstTagList *list;
13541
13542 /* now we have all info and can expose */
13543 list = stream->stream_tags;
13544 stream->stream_tags = NULL;
13545 if (!gst_qtdemux_add_stream (qtdemux, stream, list))
13546 return FALSE;
13547 }
13548 }
13549
13550 return TRUE;
13551 }
13552
13553 /* Must be called with expose lock */
13554 static GstFlowReturn
qtdemux_expose_streams(GstQTDemux * qtdemux)13555 qtdemux_expose_streams (GstQTDemux * qtdemux)
13556 {
13557 gint i;
13558
13559 GST_DEBUG_OBJECT (qtdemux, "exposing streams");
13560
13561 if (!qtdemux_is_streams_update (qtdemux)) {
13562 GST_DEBUG_OBJECT (qtdemux, "Reuse all streams");
13563 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13564 QtDemuxStream *new_stream = QTDEMUX_NTH_STREAM (qtdemux, i);
13565 QtDemuxStream *old_stream = QTDEMUX_NTH_OLD_STREAM (qtdemux, i);
13566 if (!qtdemux_reuse_and_configure_stream (qtdemux, old_stream, new_stream))
13567 return GST_FLOW_ERROR;
13568 }
13569
13570 g_ptr_array_set_size (qtdemux->old_streams, 0);
13571 qtdemux->need_segment = TRUE;
13572
13573 return GST_FLOW_OK;
13574 }
13575
13576 if (qtdemux->streams_aware) {
13577 if (!qtdemux_update_streams (qtdemux))
13578 return GST_FLOW_ERROR;
13579 } else {
13580 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13581 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
13582 GstTagList *list;
13583
13584 /* now we have all info and can expose */
13585 list = stream->stream_tags;
13586 stream->stream_tags = NULL;
13587 if (!gst_qtdemux_add_stream (qtdemux, stream, list))
13588 return GST_FLOW_ERROR;
13589
13590 }
13591 }
13592
13593 gst_qtdemux_guess_bitrate (qtdemux);
13594
13595 gst_element_no_more_pads (GST_ELEMENT_CAST (qtdemux));
13596
13597 /* If we have still old_streams, it's no more used stream */
13598 for (i = 0; i < qtdemux->old_streams->len; i++) {
13599 QtDemuxStream *stream = QTDEMUX_NTH_OLD_STREAM (qtdemux, i);
13600
13601 if (stream->pad) {
13602 GstEvent *event;
13603
13604 event = gst_event_new_eos ();
13605 if (qtdemux->segment_seqnum)
13606 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
13607
13608 gst_pad_push_event (stream->pad, event);
13609 }
13610 }
13611
13612 g_ptr_array_set_size (qtdemux->old_streams, 0);
13613
13614 /* check if we should post a redirect in case there is a single trak
13615 * and it is a redirecting trak */
13616 if (QTDEMUX_N_STREAMS (qtdemux) == 1 &&
13617 QTDEMUX_NTH_STREAM (qtdemux, 0)->redirect_uri != NULL) {
13618 GstMessage *m;
13619
13620 GST_INFO_OBJECT (qtdemux, "Issuing a redirect due to a single track with "
13621 "an external content");
13622 m = gst_message_new_element (GST_OBJECT_CAST (qtdemux),
13623 gst_structure_new ("redirect",
13624 "new-location", G_TYPE_STRING,
13625 QTDEMUX_NTH_STREAM (qtdemux, 0)->redirect_uri, NULL));
13626 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), m);
13627 g_free (qtdemux->redirect_location);
13628 qtdemux->redirect_location =
13629 g_strdup (QTDEMUX_NTH_STREAM (qtdemux, 0)->redirect_uri);
13630 }
13631
13632 g_ptr_array_foreach (qtdemux->active_streams,
13633 (GFunc) qtdemux_do_allocation, qtdemux);
13634
13635 qtdemux->need_segment = TRUE;
13636
13637 qtdemux->exposed = TRUE;
13638 return GST_FLOW_OK;
13639 }
13640
13641 typedef struct
13642 {
13643 GstStructure *structure; /* helper for sort function */
13644 gchar *location;
13645 guint min_req_bitrate;
13646 guint min_req_qt_version;
13647 } GstQtReference;
13648
13649 static gint
qtdemux_redirects_sort_func(gconstpointer a,gconstpointer b)13650 qtdemux_redirects_sort_func (gconstpointer a, gconstpointer b)
13651 {
13652 GstQtReference *ref_a = (GstQtReference *) a;
13653 GstQtReference *ref_b = (GstQtReference *) b;
13654
13655 if (ref_b->min_req_qt_version != ref_a->min_req_qt_version)
13656 return ref_b->min_req_qt_version - ref_a->min_req_qt_version;
13657
13658 /* known bitrates go before unknown; higher bitrates go first */
13659 return ref_b->min_req_bitrate - ref_a->min_req_bitrate;
13660 }
13661
13662 /* sort the redirects and post a message for the application.
13663 */
13664 static void
qtdemux_process_redirects(GstQTDemux * qtdemux,GList * references)13665 qtdemux_process_redirects (GstQTDemux * qtdemux, GList * references)
13666 {
13667 GstQtReference *best;
13668 GstStructure *s;
13669 GstMessage *msg;
13670 GValue list_val = { 0, };
13671 GList *l;
13672
13673 g_assert (references != NULL);
13674
13675 references = g_list_sort (references, qtdemux_redirects_sort_func);
13676
13677 best = (GstQtReference *) references->data;
13678
13679 g_value_init (&list_val, GST_TYPE_LIST);
13680
13681 for (l = references; l != NULL; l = l->next) {
13682 GstQtReference *ref = (GstQtReference *) l->data;
13683 GValue struct_val = { 0, };
13684
13685 ref->structure = gst_structure_new ("redirect",
13686 "new-location", G_TYPE_STRING, ref->location, NULL);
13687
13688 if (ref->min_req_bitrate > 0) {
13689 gst_structure_set (ref->structure, "minimum-bitrate", G_TYPE_INT,
13690 ref->min_req_bitrate, NULL);
13691 }
13692
13693 g_value_init (&struct_val, GST_TYPE_STRUCTURE);
13694 g_value_set_boxed (&struct_val, ref->structure);
13695 gst_value_list_append_value (&list_val, &struct_val);
13696 g_value_unset (&struct_val);
13697 /* don't free anything here yet, since we need best->structure below */
13698 }
13699
13700 g_assert (best != NULL);
13701 s = gst_structure_copy (best->structure);
13702
13703 if (g_list_length (references) > 1) {
13704 gst_structure_set_value (s, "locations", &list_val);
13705 }
13706
13707 g_value_unset (&list_val);
13708
13709 for (l = references; l != NULL; l = l->next) {
13710 GstQtReference *ref = (GstQtReference *) l->data;
13711
13712 gst_structure_free (ref->structure);
13713 g_free (ref->location);
13714 g_free (ref);
13715 }
13716 g_list_free (references);
13717
13718 GST_INFO_OBJECT (qtdemux, "posting redirect message: %" GST_PTR_FORMAT, s);
13719 g_free (qtdemux->redirect_location);
13720 qtdemux->redirect_location =
13721 g_strdup (gst_structure_get_string (s, "new-location"));
13722 msg = gst_message_new_element (GST_OBJECT_CAST (qtdemux), s);
13723 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
13724 }
13725
13726 /* look for redirect nodes, collect all redirect information and
13727 * process it.
13728 */
13729 static gboolean
qtdemux_parse_redirects(GstQTDemux * qtdemux)13730 qtdemux_parse_redirects (GstQTDemux * qtdemux)
13731 {
13732 GNode *rmra, *rmda, *rdrf;
13733
13734 rmra = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_rmra);
13735 if (rmra) {
13736 GList *redirects = NULL;
13737
13738 rmda = qtdemux_tree_get_child_by_type (rmra, FOURCC_rmda);
13739 while (rmda) {
13740 GstQtReference ref = { NULL, NULL, 0, 0 };
13741 GNode *rmdr, *rmvc;
13742
13743 if ((rmdr = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmdr))) {
13744 ref.min_req_bitrate = QT_UINT32 ((guint8 *) rmdr->data + 12);
13745 GST_LOG_OBJECT (qtdemux, "data rate atom, required bitrate = %u",
13746 ref.min_req_bitrate);
13747 }
13748
13749 if ((rmvc = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmvc))) {
13750 guint32 package = QT_FOURCC ((guint8 *) rmvc->data + 12);
13751 guint version = QT_UINT32 ((guint8 *) rmvc->data + 16);
13752
13753 #ifndef GST_DISABLE_GST_DEBUG
13754 guint bitmask = QT_UINT32 ((guint8 *) rmvc->data + 20);
13755 #endif
13756 guint check_type = QT_UINT16 ((guint8 *) rmvc->data + 24);
13757
13758 GST_LOG_OBJECT (qtdemux,
13759 "version check atom [%" GST_FOURCC_FORMAT "], version=0x%08x"
13760 ", mask=%08x, check_type=%u", GST_FOURCC_ARGS (package), version,
13761 bitmask, check_type);
13762 if (package == FOURCC_qtim && check_type == 0) {
13763 ref.min_req_qt_version = version;
13764 }
13765 }
13766
13767 rdrf = qtdemux_tree_get_child_by_type (rmda, FOURCC_rdrf);
13768 if (rdrf) {
13769 guint32 ref_type;
13770 guint8 *ref_data;
13771 guint ref_len;
13772
13773 ref_len = QT_UINT32 ((guint8 *) rdrf->data);
13774 if (ref_len > 20) {
13775 ref_type = QT_FOURCC ((guint8 *) rdrf->data + 12);
13776 ref_data = (guint8 *) rdrf->data + 20;
13777 if (ref_type == FOURCC_alis) {
13778 guint record_len, record_version, fn_len;
13779
13780 if (ref_len > 70) {
13781 /* MacOSX alias record, google for alias-layout.txt */
13782 record_len = QT_UINT16 (ref_data + 4);
13783 record_version = QT_UINT16 (ref_data + 4 + 2);
13784 fn_len = QT_UINT8 (ref_data + 50);
13785 if (record_len > 50 && record_version == 2 && fn_len > 0) {
13786 ref.location = g_strndup ((gchar *) ref_data + 51, fn_len);
13787 }
13788 } else {
13789 GST_WARNING_OBJECT (qtdemux, "Invalid rdrf/alis size (%u < 70)",
13790 ref_len);
13791 }
13792 } else if (ref_type == FOURCC_url_) {
13793 ref.location = g_strndup ((gchar *) ref_data, ref_len - 8);
13794 } else {
13795 GST_DEBUG_OBJECT (qtdemux,
13796 "unknown rdrf reference type %" GST_FOURCC_FORMAT,
13797 GST_FOURCC_ARGS (ref_type));
13798 }
13799 if (ref.location != NULL) {
13800 GST_INFO_OBJECT (qtdemux, "New location: %s", ref.location);
13801 redirects =
13802 g_list_prepend (redirects, g_memdup2 (&ref, sizeof (ref)));
13803 } else {
13804 GST_WARNING_OBJECT (qtdemux,
13805 "Failed to extract redirect location from rdrf atom");
13806 }
13807 } else {
13808 GST_WARNING_OBJECT (qtdemux, "Invalid rdrf size (%u < 20)", ref_len);
13809 }
13810 }
13811
13812 /* look for others */
13813 rmda = qtdemux_tree_get_sibling_by_type (rmda, FOURCC_rmda);
13814 }
13815
13816 if (redirects != NULL) {
13817 qtdemux_process_redirects (qtdemux, redirects);
13818 }
13819 }
13820 return TRUE;
13821 }
13822
13823 static GstTagList *
qtdemux_add_container_format(GstQTDemux * qtdemux,GstTagList * tags)13824 qtdemux_add_container_format (GstQTDemux * qtdemux, GstTagList * tags)
13825 {
13826 const gchar *fmt;
13827
13828 if (tags == NULL) {
13829 tags = gst_tag_list_new_empty ();
13830 gst_tag_list_set_scope (tags, GST_TAG_SCOPE_GLOBAL);
13831 }
13832
13833 if (qtdemux->major_brand == FOURCC_mjp2)
13834 fmt = "Motion JPEG 2000";
13835 else if ((qtdemux->major_brand & 0xffff) == FOURCC_3g__)
13836 fmt = "3GP";
13837 else if (qtdemux->major_brand == FOURCC_qt__)
13838 fmt = "Quicktime";
13839 else if (qtdemux->fragmented)
13840 fmt = "ISO fMP4";
13841 else
13842 fmt = "ISO MP4/M4A";
13843
13844 GST_LOG_OBJECT (qtdemux, "mapped %" GST_FOURCC_FORMAT " to '%s'",
13845 GST_FOURCC_ARGS (qtdemux->major_brand), fmt);
13846
13847 gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_CONTAINER_FORMAT,
13848 fmt, NULL);
13849
13850 return tags;
13851 }
13852
13853 /* we have read the complete moov node now.
13854 * This function parses all of the relevant info, creates the traks and
13855 * prepares all data structures for playback
13856 */
13857 static gboolean
qtdemux_parse_tree(GstQTDemux * qtdemux)13858 qtdemux_parse_tree (GstQTDemux * qtdemux)
13859 {
13860 GNode *mvhd;
13861 GNode *trak;
13862 GNode *udta;
13863 GNode *mvex;
13864 GNode *pssh;
13865 guint64 creation_time;
13866 GstDateTime *datetime = NULL;
13867 gint version;
13868
13869 /* make sure we have a usable taglist */
13870 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
13871
13872 mvhd = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvhd);
13873 if (mvhd == NULL) {
13874 GST_LOG_OBJECT (qtdemux, "No mvhd node found, looking for redirects.");
13875 return qtdemux_parse_redirects (qtdemux);
13876 }
13877
13878 version = QT_UINT8 ((guint8 *) mvhd->data + 8);
13879 if (version == 1) {
13880 creation_time = QT_UINT64 ((guint8 *) mvhd->data + 12);
13881 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 28);
13882 qtdemux->duration = QT_UINT64 ((guint8 *) mvhd->data + 32);
13883 } else if (version == 0) {
13884 creation_time = QT_UINT32 ((guint8 *) mvhd->data + 12);
13885 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 20);
13886 qtdemux->duration = QT_UINT32 ((guint8 *) mvhd->data + 24);
13887 } else {
13888 GST_WARNING_OBJECT (qtdemux, "Unhandled mvhd version %d", version);
13889 return FALSE;
13890 }
13891
13892 /* Moving qt creation time (secs since 1904) to unix time */
13893 if (creation_time != 0) {
13894 /* Try to use epoch first as it should be faster and more commonly found */
13895 if (creation_time >= QTDEMUX_SECONDS_FROM_1904_TO_1970) {
13896 gint64 now_s;
13897
13898 creation_time -= QTDEMUX_SECONDS_FROM_1904_TO_1970;
13899 /* some data cleansing sanity */
13900 now_s = g_get_real_time () / G_USEC_PER_SEC;
13901 if (now_s + 24 * 3600 < creation_time) {
13902 GST_DEBUG_OBJECT (qtdemux, "discarding bogus future creation time");
13903 } else {
13904 datetime = gst_date_time_new_from_unix_epoch_utc (creation_time);
13905 }
13906 } else {
13907 GDateTime *base_dt = g_date_time_new_utc (1904, 1, 1, 0, 0, 0);
13908 GDateTime *dt, *dt_local;
13909
13910 dt = g_date_time_add_seconds (base_dt, creation_time);
13911 dt_local = g_date_time_to_local (dt);
13912 datetime = gst_date_time_new_from_g_date_time (dt_local);
13913
13914 g_date_time_unref (base_dt);
13915 g_date_time_unref (dt);
13916 }
13917 }
13918 if (datetime) {
13919 /* Use KEEP as explicit tags should have a higher priority than mvhd tag */
13920 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_KEEP, GST_TAG_DATE_TIME,
13921 datetime, NULL);
13922 gst_date_time_unref (datetime);
13923 }
13924
13925 GST_INFO_OBJECT (qtdemux, "timescale: %u", qtdemux->timescale);
13926 GST_INFO_OBJECT (qtdemux, "duration: %" G_GUINT64_FORMAT, qtdemux->duration);
13927
13928 /* check for fragmented file and get some (default) data */
13929 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
13930 if (mvex) {
13931 GNode *mehd;
13932 GstByteReader mehd_data;
13933
13934 /* let track parsing or anyone know weird stuff might happen ... */
13935 qtdemux->fragmented = TRUE;
13936
13937 /* compensate for total duration */
13938 mehd = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_mehd, &mehd_data);
13939 if (mehd)
13940 qtdemux_parse_mehd (qtdemux, &mehd_data);
13941 }
13942
13943 /* Update the movie segment duration, unless it was directly given to us
13944 * by upstream. Otherwise let it as is, as we don't want to mangle the
13945 * duration provided by upstream that may come e.g. from a MPD file. */
13946 if (!qtdemux->upstream_format_is_time) {
13947 GstClockTime duration;
13948 /* set duration in the segment info */
13949 gst_qtdemux_get_duration (qtdemux, &duration);
13950 qtdemux->segment.duration = duration;
13951 /* also do not exceed duration; stop is set that way post seek anyway,
13952 * and segment activation falls back to duration,
13953 * whereas loop only checks stop, so let's align this here as well */
13954 qtdemux->segment.stop = duration;
13955 }
13956
13957 /* parse all traks */
13958 trak = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_trak);
13959 while (trak) {
13960 qtdemux_parse_trak (qtdemux, trak);
13961 /* iterate all siblings */
13962 trak = qtdemux_tree_get_sibling_by_type (trak, FOURCC_trak);
13963 }
13964
13965 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
13966
13967 /* find tags */
13968 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_udta);
13969 if (udta) {
13970 qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
13971 } else {
13972 GST_LOG_OBJECT (qtdemux, "No udta node found.");
13973 }
13974
13975 /* maybe also some tags in meta box */
13976 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_meta);
13977 if (udta) {
13978 GST_DEBUG_OBJECT (qtdemux, "Parsing meta box for tags.");
13979 qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
13980 } else {
13981 GST_LOG_OBJECT (qtdemux, "No meta node found.");
13982 }
13983
13984 /* parse any protection system info */
13985 pssh = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_pssh);
13986 while (pssh) {
13987 GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
13988 qtdemux_parse_pssh (qtdemux, pssh);
13989 pssh = qtdemux_tree_get_sibling_by_type (pssh, FOURCC_pssh);
13990 }
13991
13992 qtdemux->tag_list = qtdemux_add_container_format (qtdemux, qtdemux->tag_list);
13993
13994 return TRUE;
13995 }
13996
13997 /* taken from ffmpeg */
13998 static int
read_descr_size(guint8 * ptr,guint8 * end,guint8 ** end_out)13999 read_descr_size (guint8 * ptr, guint8 * end, guint8 ** end_out)
14000 {
14001 int count = 4;
14002 int len = 0;
14003
14004 while (count--) {
14005 int c;
14006
14007 if (ptr >= end)
14008 return -1;
14009
14010 c = *ptr++;
14011 len = (len << 7) | (c & 0x7f);
14012 if (!(c & 0x80))
14013 break;
14014 }
14015 *end_out = ptr;
14016 return len;
14017 }
14018
14019 static GList *
parse_xiph_stream_headers(GstQTDemux * qtdemux,gpointer codec_data,gsize codec_data_size)14020 parse_xiph_stream_headers (GstQTDemux * qtdemux, gpointer codec_data,
14021 gsize codec_data_size)
14022 {
14023 GList *list = NULL;
14024 guint8 *p = codec_data;
14025 gint i, offset, num_packets;
14026 guint *length, last;
14027
14028 GST_MEMDUMP_OBJECT (qtdemux, "xiph codec data", codec_data, codec_data_size);
14029
14030 if (codec_data == NULL || codec_data_size == 0)
14031 goto error;
14032
14033 /* start of the stream and vorbis audio or theora video, need to
14034 * send the codec_priv data as first three packets */
14035 num_packets = p[0] + 1;
14036 GST_DEBUG_OBJECT (qtdemux,
14037 "%u stream headers, total length=%" G_GSIZE_FORMAT " bytes",
14038 (guint) num_packets, codec_data_size);
14039
14040 /* Let's put some limits, Don't think there even is a xiph codec
14041 * with more than 3-4 headers */
14042 if (G_UNLIKELY (num_packets > 16)) {
14043 GST_WARNING_OBJECT (qtdemux,
14044 "Unlikely number of xiph headers, most likely not valid");
14045 goto error;
14046 }
14047
14048 length = g_alloca (num_packets * sizeof (guint));
14049 last = 0;
14050 offset = 1;
14051
14052 /* first packets, read length values */
14053 for (i = 0; i < num_packets - 1; i++) {
14054 length[i] = 0;
14055 while (offset < codec_data_size) {
14056 length[i] += p[offset];
14057 if (p[offset++] != 0xff)
14058 break;
14059 }
14060 last += length[i];
14061 }
14062 if (offset + last > codec_data_size)
14063 goto error;
14064
14065 /* last packet is the remaining size */
14066 length[i] = codec_data_size - offset - last;
14067
14068 for (i = 0; i < num_packets; i++) {
14069 GstBuffer *hdr;
14070
14071 GST_DEBUG_OBJECT (qtdemux, "buffer %d: %u bytes", i, (guint) length[i]);
14072
14073 if (offset + length[i] > codec_data_size)
14074 goto error;
14075
14076 hdr = gst_buffer_new_memdup (p + offset, length[i]);
14077 list = g_list_append (list, hdr);
14078
14079 offset += length[i];
14080 }
14081
14082 return list;
14083
14084 /* ERRORS */
14085 error:
14086 {
14087 if (list != NULL)
14088 g_list_free_full (list, (GDestroyNotify) gst_buffer_unref);
14089 return NULL;
14090 }
14091
14092 }
14093
14094 /* this can change the codec originally present in @list */
14095 static void
gst_qtdemux_handle_esds(GstQTDemux * qtdemux,QtDemuxStream * stream,QtDemuxStreamStsdEntry * entry,GNode * esds,GstTagList * list)14096 gst_qtdemux_handle_esds (GstQTDemux * qtdemux, QtDemuxStream * stream,
14097 QtDemuxStreamStsdEntry * entry, GNode * esds, GstTagList * list)
14098 {
14099 int len = QT_UINT32 (esds->data);
14100 guint8 *ptr = esds->data;
14101 guint8 *end = ptr + len;
14102 int tag;
14103 guint8 *data_ptr = NULL;
14104 int data_len = 0;
14105 guint8 object_type_id = 0;
14106 guint8 stream_type = 0;
14107 const char *codec_name = NULL;
14108 GstCaps *caps = NULL;
14109
14110 GST_MEMDUMP_OBJECT (qtdemux, "esds", ptr, len);
14111 ptr += 8;
14112 GST_DEBUG_OBJECT (qtdemux, "version/flags = %08x", QT_UINT32 (ptr));
14113 ptr += 4;
14114 while (ptr + 1 < end) {
14115 tag = QT_UINT8 (ptr);
14116 GST_DEBUG_OBJECT (qtdemux, "tag = %02x", tag);
14117 ptr++;
14118 len = read_descr_size (ptr, end, &ptr);
14119 GST_DEBUG_OBJECT (qtdemux, "len = %d", len);
14120
14121 /* Check the stated amount of data is available for reading */
14122 if (len < 0 || ptr + len > end)
14123 break;
14124
14125 switch (tag) {
14126 case ES_DESCRIPTOR_TAG:
14127 GST_DEBUG_OBJECT (qtdemux, "ID 0x%04x", QT_UINT16 (ptr));
14128 GST_DEBUG_OBJECT (qtdemux, "priority 0x%04x", QT_UINT8 (ptr + 2));
14129 ptr += 3;
14130 break;
14131 case DECODER_CONFIG_DESC_TAG:{
14132 guint max_bitrate, avg_bitrate;
14133
14134 object_type_id = QT_UINT8 (ptr);
14135 stream_type = QT_UINT8 (ptr + 1) >> 2;
14136 max_bitrate = QT_UINT32 (ptr + 5);
14137 avg_bitrate = QT_UINT32 (ptr + 9);
14138 GST_DEBUG_OBJECT (qtdemux, "object_type_id %02x", object_type_id);
14139 GST_DEBUG_OBJECT (qtdemux, "stream_type %02x", stream_type);
14140 GST_DEBUG_OBJECT (qtdemux, "buffer_size_db %02x", QT_UINT24 (ptr + 2));
14141 GST_DEBUG_OBJECT (qtdemux, "max bitrate %u", max_bitrate);
14142 GST_DEBUG_OBJECT (qtdemux, "avg bitrate %u", avg_bitrate);
14143 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
14144 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
14145 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
14146 }
14147 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
14148 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
14149 avg_bitrate, NULL);
14150 }
14151 ptr += 13;
14152 break;
14153 }
14154 case DECODER_SPECIFIC_INFO_TAG:
14155 GST_MEMDUMP_OBJECT (qtdemux, "data", ptr, len);
14156 if (object_type_id == 0xe0 && len == 0x40) {
14157 guint8 *data;
14158 GstStructure *s;
14159 guint32 clut[16];
14160 gint i;
14161
14162 GST_DEBUG_OBJECT (qtdemux,
14163 "Have VOBSUB palette. Creating palette event");
14164 /* move to decConfigDescr data and read palette */
14165 data = ptr;
14166 for (i = 0; i < 16; i++) {
14167 clut[i] = QT_UINT32 (data);
14168 data += 4;
14169 }
14170
14171 s = gst_structure_new ("application/x-gst-dvd", "event",
14172 G_TYPE_STRING, "dvd-spu-clut-change",
14173 "clut00", G_TYPE_INT, clut[0], "clut01", G_TYPE_INT, clut[1],
14174 "clut02", G_TYPE_INT, clut[2], "clut03", G_TYPE_INT, clut[3],
14175 "clut04", G_TYPE_INT, clut[4], "clut05", G_TYPE_INT, clut[5],
14176 "clut06", G_TYPE_INT, clut[6], "clut07", G_TYPE_INT, clut[7],
14177 "clut08", G_TYPE_INT, clut[8], "clut09", G_TYPE_INT, clut[9],
14178 "clut10", G_TYPE_INT, clut[10], "clut11", G_TYPE_INT, clut[11],
14179 "clut12", G_TYPE_INT, clut[12], "clut13", G_TYPE_INT, clut[13],
14180 "clut14", G_TYPE_INT, clut[14], "clut15", G_TYPE_INT, clut[15],
14181 NULL);
14182
14183 /* store event and trigger custom processing */
14184 stream->pending_event =
14185 gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s);
14186 } else {
14187 /* Generic codec_data handler puts it on the caps */
14188 data_ptr = ptr;
14189 data_len = len;
14190 }
14191
14192 ptr += len;
14193 break;
14194 case SL_CONFIG_DESC_TAG:
14195 GST_DEBUG_OBJECT (qtdemux, "data %02x", QT_UINT8 (ptr));
14196 ptr += 1;
14197 break;
14198 default:
14199 GST_DEBUG_OBJECT (qtdemux, "Unknown/unhandled descriptor tag %02x",
14200 tag);
14201 GST_MEMDUMP_OBJECT (qtdemux, "descriptor data", ptr, len);
14202 ptr += len;
14203 break;
14204 }
14205 }
14206
14207 /* object_type_id in the esds atom in mp4a and mp4v tells us which codec is
14208 * in use, and should also be used to override some other parameters for some
14209 * codecs. */
14210 switch (object_type_id) {
14211 case 0x20: /* MPEG-4 */
14212 /* 4 bytes for the visual_object_sequence_start_code and 1 byte for the
14213 * profile_and_level_indication */
14214 if (data_ptr != NULL && data_len >= 5 &&
14215 GST_READ_UINT32_BE (data_ptr) == 0x000001b0) {
14216 gst_codec_utils_mpeg4video_caps_set_level_and_profile (entry->caps,
14217 data_ptr + 4, data_len - 4);
14218 }
14219 break; /* Nothing special needed here */
14220 case 0x21: /* H.264 */
14221 codec_name = "H.264 / AVC";
14222 caps = gst_caps_new_simple ("video/x-h264",
14223 "stream-format", G_TYPE_STRING, "avc",
14224 "alignment", G_TYPE_STRING, "au", NULL);
14225 break;
14226 case 0x40: /* AAC (any) */
14227 case 0x66: /* AAC Main */
14228 case 0x67: /* AAC LC */
14229 case 0x68: /* AAC SSR */
14230 /* Override channels and rate based on the codec_data, as it's often
14231 * wrong. */
14232 /* Only do so for basic setup without HE-AAC extension */
14233 #ifdef OHOS_OPT_COMPAT
14234 /*
14235 * ohos.opt.compat.0030
14236 * sampling rate is get wrong, in special code flow
14237 */
14238 if (data_ptr && data_len >= 2) {
14239 #else
14240 if (data_ptr && data_len == 2) {
14241 #endif
14242 guint channels, rate;
14243
14244 channels = gst_codec_utils_aac_get_channels (data_ptr, data_len);
14245 if (channels > 0)
14246 entry->n_channels = channels;
14247
14248 rate = gst_codec_utils_aac_get_sample_rate (data_ptr, data_len);
14249 if (rate > 0)
14250 entry->rate = rate;
14251 }
14252
14253 /* Set level and profile if possible */
14254 if (data_ptr != NULL && data_len >= 2) {
14255 gst_codec_utils_aac_caps_set_level_and_profile (entry->caps,
14256 data_ptr, data_len);
14257 } else {
14258 const gchar *profile_str = NULL;
14259 GstBuffer *buffer;
14260 GstMapInfo map;
14261 guint8 *codec_data;
14262 gint rate_idx, profile;
14263
14264 /* No codec_data, let's invent something.
14265 * FIXME: This is wrong for SBR! */
14266
14267 GST_WARNING_OBJECT (qtdemux, "No codec_data for AAC available");
14268
14269 buffer = gst_buffer_new_and_alloc (2);
14270 gst_buffer_map (buffer, &map, GST_MAP_WRITE);
14271 codec_data = map.data;
14272
14273 rate_idx =
14274 gst_codec_utils_aac_get_index_from_sample_rate (CUR_STREAM
14275 (stream)->rate);
14276
14277 switch (object_type_id) {
14278 case 0x66:
14279 profile_str = "main";
14280 profile = 0;
14281 break;
14282 case 0x67:
14283 profile_str = "lc";
14284 profile = 1;
14285 break;
14286 case 0x68:
14287 profile_str = "ssr";
14288 profile = 2;
14289 break;
14290 default:
14291 profile = 3;
14292 break;
14293 }
14294
14295 codec_data[0] = ((profile + 1) << 3) | ((rate_idx & 0xE) >> 1);
14296 codec_data[1] =
14297 ((rate_idx & 0x1) << 7) | (CUR_STREAM (stream)->n_channels << 3);
14298
14299 gst_buffer_unmap (buffer, &map);
14300 gst_caps_set_simple (CUR_STREAM (stream)->caps, "codec_data",
14301 GST_TYPE_BUFFER, buffer, NULL);
14302 gst_buffer_unref (buffer);
14303
14304 if (profile_str) {
14305 gst_caps_set_simple (CUR_STREAM (stream)->caps, "profile",
14306 G_TYPE_STRING, profile_str, NULL);
14307 }
14308 }
14309 break;
14310 case 0x60: /* MPEG-2, various profiles */
14311 case 0x61:
14312 case 0x62:
14313 case 0x63:
14314 case 0x64:
14315 case 0x65:
14316 codec_name = "MPEG-2 video";
14317 caps = gst_caps_new_simple ("video/mpeg",
14318 "mpegversion", G_TYPE_INT, 2,
14319 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14320 break;
14321 case 0x69: /* MPEG-2 BC audio */
14322 case 0x6B: /* MPEG-1 audio */
14323 caps = gst_caps_new_simple ("audio/mpeg",
14324 "mpegversion", G_TYPE_INT, 1, NULL);
14325 codec_name = "MPEG-1 audio";
14326 break;
14327 case 0x6A: /* MPEG-1 */
14328 codec_name = "MPEG-1 video";
14329 caps = gst_caps_new_simple ("video/mpeg",
14330 "mpegversion", G_TYPE_INT, 1,
14331 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14332 break;
14333 case 0x6C: /* MJPEG */
14334 caps =
14335 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
14336 NULL);
14337 codec_name = "Motion-JPEG";
14338 break;
14339 case 0x6D: /* PNG */
14340 caps =
14341 gst_caps_new_simple ("image/png", "parsed", G_TYPE_BOOLEAN, TRUE,
14342 NULL);
14343 codec_name = "PNG still images";
14344 break;
14345 case 0x6E: /* JPEG2000 */
14346 codec_name = "JPEG-2000";
14347 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
14348 break;
14349 case 0xA4: /* Dirac */
14350 codec_name = "Dirac";
14351 caps = gst_caps_new_empty_simple ("video/x-dirac");
14352 break;
14353 case 0xA5: /* AC3 */
14354 codec_name = "AC-3 audio";
14355 caps = gst_caps_new_simple ("audio/x-ac3",
14356 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14357 break;
14358 case 0xA9: /* AC3 */
14359 codec_name = "DTS audio";
14360 caps = gst_caps_new_simple ("audio/x-dts",
14361 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14362 break;
14363 case 0xDD:
14364 if (stream_type == 0x05 && data_ptr) {
14365 GList *headers =
14366 parse_xiph_stream_headers (qtdemux, data_ptr, data_len);
14367 if (headers) {
14368 GList *tmp;
14369 GValue arr_val = G_VALUE_INIT;
14370 GValue buf_val = G_VALUE_INIT;
14371 GstStructure *s;
14372
14373 /* Let's assume it's vorbis if it's an audio stream of type 0xdd and we have codec data that extracts properly */
14374 codec_name = "Vorbis";
14375 caps = gst_caps_new_empty_simple ("audio/x-vorbis");
14376 #ifdef OHOS_OPT_COMPAT
14377 // ohos.opt.compat.0031. adapter for avdec_vorbis
14378 GstBuffer *codec_data = gst_buffer_new_allocate (NULL, data_len, NULL);
14379 if (codec_data != NULL) {
14380 gst_buffer_fill (codec_data, 0, data_ptr, data_len);
14381 gst_caps_set_simple (caps, "codec_data", GST_TYPE_BUFFER, codec_data, NULL);
14382 gst_buffer_unref (codec_data);
14383 } else {
14384 GST_ERROR_OBJECT (qtdemux, "gst_buffer_new_wrapped failed");
14385 }
14386 #endif
14387 g_value_init (&arr_val, GST_TYPE_ARRAY);
14388 g_value_init (&buf_val, GST_TYPE_BUFFER);
14389 for (tmp = headers; tmp; tmp = tmp->next) {
14390 g_value_set_boxed (&buf_val, (GstBuffer *) tmp->data);
14391 gst_value_array_append_value (&arr_val, &buf_val);
14392 }
14393 s = gst_caps_get_structure (caps, 0);
14394 gst_structure_take_value (s, "streamheader", &arr_val);
14395 g_value_unset (&buf_val);
14396 g_list_free (headers);
14397
14398 data_ptr = NULL;
14399 data_len = 0;
14400 }
14401 }
14402 break;
14403 case 0xE1: /* QCELP */
14404 /* QCELP, the codec_data is a riff tag (little endian) with
14405 * 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). */
14406 caps = gst_caps_new_empty_simple ("audio/qcelp");
14407 codec_name = "QCELP";
14408 break;
14409 default:
14410 break;
14411 }
14412
14413 /* If we have a replacement caps, then change our caps for this stream */
14414 if (caps) {
14415 gst_caps_unref (entry->caps);
14416 entry->caps = caps;
14417 }
14418
14419 if (codec_name && list)
14420 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
14421 GST_TAG_AUDIO_CODEC, codec_name, NULL);
14422
14423 /* Add the codec_data attribute to caps, if we have it */
14424 if (data_ptr) {
14425 GstBuffer *buffer;
14426
14427 buffer = gst_buffer_new_and_alloc (data_len);
14428 gst_buffer_fill (buffer, 0, data_ptr, data_len);
14429
14430 GST_DEBUG_OBJECT (qtdemux, "setting codec_data from esds");
14431 GST_MEMDUMP_OBJECT (qtdemux, "codec_data from esds", data_ptr, data_len);
14432
14433 gst_caps_set_simple (entry->caps, "codec_data", GST_TYPE_BUFFER,
14434 buffer, NULL);
14435 gst_buffer_unref (buffer);
14436 }
14437
14438 }
14439
14440 static inline GstCaps *
14441 _get_unknown_codec_name (const gchar * type, guint32 fourcc)
14442 {
14443 GstCaps *caps;
14444 guint i;
14445 char *s, fourstr[5];
14446
14447 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
14448 for (i = 0; i < 4; i++) {
14449 if (!g_ascii_isalnum (fourstr[i]))
14450 fourstr[i] = '_';
14451 }
14452 s = g_strdup_printf ("%s/x-gst-fourcc-%s", type, g_strstrip (fourstr));
14453 caps = gst_caps_new_empty_simple (s);
14454 g_free (s);
14455 return caps;
14456 }
14457
14458 #define _codec(name) \
14459 do { \
14460 if (codec_name) { \
14461 *codec_name = g_strdup (name); \
14462 } \
14463 } while (0)
14464
14465 static GstCaps *
14466 qtdemux_video_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
14467 QtDemuxStreamStsdEntry * entry, guint32 fourcc,
14468 const guint8 * stsd_entry_data, gchar ** codec_name)
14469 {
14470 GstCaps *caps = NULL;
14471 GstVideoFormat format = GST_VIDEO_FORMAT_UNKNOWN;
14472
14473 switch (fourcc) {
14474 case FOURCC_png:
14475 _codec ("PNG still images");
14476 caps = gst_caps_new_empty_simple ("image/png");
14477 break;
14478 case FOURCC_jpeg:
14479 _codec ("JPEG still images");
14480 caps =
14481 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
14482 NULL);
14483 break;
14484 case GST_MAKE_FOURCC ('m', 'j', 'p', 'a'):
14485 case GST_MAKE_FOURCC ('A', 'V', 'D', 'J'):
14486 case GST_MAKE_FOURCC ('M', 'J', 'P', 'G'):
14487 case GST_MAKE_FOURCC ('d', 'm', 'b', '1'):
14488 _codec ("Motion-JPEG");
14489 caps =
14490 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
14491 NULL);
14492 break;
14493 case GST_MAKE_FOURCC ('m', 'j', 'p', 'b'):
14494 _codec ("Motion-JPEG format B");
14495 caps = gst_caps_new_empty_simple ("video/x-mjpeg-b");
14496 break;
14497 case FOURCC_mjp2:
14498 _codec ("JPEG-2000");
14499 /* override to what it should be according to spec, avoid palette_data */
14500 entry->bits_per_sample = 24;
14501 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
14502 break;
14503 case FOURCC_SVQ3:
14504 _codec ("Sorensen video v.3");
14505 caps = gst_caps_new_simple ("video/x-svq",
14506 "svqversion", G_TYPE_INT, 3, NULL);
14507 break;
14508 case GST_MAKE_FOURCC ('s', 'v', 'q', 'i'):
14509 case GST_MAKE_FOURCC ('S', 'V', 'Q', '1'):
14510 _codec ("Sorensen video v.1");
14511 caps = gst_caps_new_simple ("video/x-svq",
14512 "svqversion", G_TYPE_INT, 1, NULL);
14513 break;
14514 case GST_MAKE_FOURCC ('W', 'R', 'A', 'W'):
14515 caps = gst_caps_new_empty_simple ("video/x-raw");
14516 gst_caps_set_simple (caps, "format", G_TYPE_STRING, "RGB8P", NULL);
14517 _codec ("Windows Raw RGB");
14518 stream->alignment = 32;
14519 break;
14520 case FOURCC_raw_:
14521 {
14522 guint16 bps;
14523
14524 bps = QT_UINT16 (stsd_entry_data + 82);
14525 switch (bps) {
14526 case 15:
14527 format = GST_VIDEO_FORMAT_RGB15;
14528 break;
14529 case 16:
14530 format = GST_VIDEO_FORMAT_RGB16;
14531 break;
14532 case 24:
14533 format = GST_VIDEO_FORMAT_RGB;
14534 break;
14535 case 32:
14536 format = GST_VIDEO_FORMAT_ARGB;
14537 break;
14538 default:
14539 /* unknown */
14540 break;
14541 }
14542 break;
14543 }
14544 case GST_MAKE_FOURCC ('y', 'v', '1', '2'):
14545 format = GST_VIDEO_FORMAT_I420;
14546 break;
14547 case GST_MAKE_FOURCC ('y', 'u', 'v', '2'):
14548 case GST_MAKE_FOURCC ('Y', 'u', 'v', '2'):
14549 format = GST_VIDEO_FORMAT_I420;
14550 break;
14551 case FOURCC_2vuy:
14552 case GST_MAKE_FOURCC ('2', 'V', 'u', 'y'):
14553 format = GST_VIDEO_FORMAT_UYVY;
14554 break;
14555 case GST_MAKE_FOURCC ('v', '3', '0', '8'):
14556 format = GST_VIDEO_FORMAT_v308;
14557 break;
14558 case GST_MAKE_FOURCC ('v', '2', '1', '6'):
14559 format = GST_VIDEO_FORMAT_v216;
14560 break;
14561 case FOURCC_v210:
14562 format = GST_VIDEO_FORMAT_v210;
14563 break;
14564 case GST_MAKE_FOURCC ('r', '2', '1', '0'):
14565 format = GST_VIDEO_FORMAT_r210;
14566 break;
14567 /* Packed YUV 4:4:4 10 bit in 32 bits, complex
14568 case GST_MAKE_FOURCC ('v', '4', '1', '0'):
14569 format = GST_VIDEO_FORMAT_v410;
14570 break;
14571 */
14572 /* Packed YUV 4:4:4:4 8 bit in 32 bits
14573 * but different order than AYUV
14574 case GST_MAKE_FOURCC ('v', '4', '0', '8'):
14575 format = GST_VIDEO_FORMAT_v408;
14576 break;
14577 */
14578 case GST_MAKE_FOURCC ('m', 'p', 'e', 'g'):
14579 case GST_MAKE_FOURCC ('m', 'p', 'g', '1'):
14580 _codec ("MPEG-1 video");
14581 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
14582 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14583 break;
14584 case GST_MAKE_FOURCC ('h', 'd', 'v', '1'): /* HDV 720p30 */
14585 case GST_MAKE_FOURCC ('h', 'd', 'v', '2'): /* HDV 1080i60 */
14586 case GST_MAKE_FOURCC ('h', 'd', 'v', '3'): /* HDV 1080i50 */
14587 case GST_MAKE_FOURCC ('h', 'd', 'v', '4'): /* HDV 720p24 */
14588 case GST_MAKE_FOURCC ('h', 'd', 'v', '5'): /* HDV 720p25 */
14589 case GST_MAKE_FOURCC ('h', 'd', 'v', '6'): /* HDV 1080p24 */
14590 case GST_MAKE_FOURCC ('h', 'd', 'v', '7'): /* HDV 1080p25 */
14591 case GST_MAKE_FOURCC ('h', 'd', 'v', '8'): /* HDV 1080p30 */
14592 case GST_MAKE_FOURCC ('h', 'd', 'v', '9'): /* HDV 720p60 */
14593 case GST_MAKE_FOURCC ('h', 'd', 'v', 'a'): /* HDV 720p50 */
14594 case GST_MAKE_FOURCC ('m', 'x', '5', 'n'): /* MPEG2 IMX NTSC 525/60 50mb/s produced by FCP */
14595 case GST_MAKE_FOURCC ('m', 'x', '5', 'p'): /* MPEG2 IMX PAL 625/60 50mb/s produced by FCP */
14596 case GST_MAKE_FOURCC ('m', 'x', '4', 'n'): /* MPEG2 IMX NTSC 525/60 40mb/s produced by FCP */
14597 case GST_MAKE_FOURCC ('m', 'x', '4', 'p'): /* MPEG2 IMX PAL 625/60 40mb/s produced by FCP */
14598 case GST_MAKE_FOURCC ('m', 'x', '3', 'n'): /* MPEG2 IMX NTSC 525/60 30mb/s produced by FCP */
14599 case GST_MAKE_FOURCC ('m', 'x', '3', 'p'): /* MPEG2 IMX PAL 625/50 30mb/s produced by FCP */
14600 case GST_MAKE_FOURCC ('x', 'd', 'v', '1'): /* XDCAM HD 720p30 35Mb/s */
14601 case GST_MAKE_FOURCC ('x', 'd', 'v', '2'): /* XDCAM HD 1080i60 35Mb/s */
14602 case GST_MAKE_FOURCC ('x', 'd', 'v', '3'): /* XDCAM HD 1080i50 35Mb/s */
14603 case GST_MAKE_FOURCC ('x', 'd', 'v', '4'): /* XDCAM HD 720p24 35Mb/s */
14604 case GST_MAKE_FOURCC ('x', 'd', 'v', '5'): /* XDCAM HD 720p25 35Mb/s */
14605 case GST_MAKE_FOURCC ('x', 'd', 'v', '6'): /* XDCAM HD 1080p24 35Mb/s */
14606 case GST_MAKE_FOURCC ('x', 'd', 'v', '7'): /* XDCAM HD 1080p25 35Mb/s */
14607 case GST_MAKE_FOURCC ('x', 'd', 'v', '8'): /* XDCAM HD 1080p30 35Mb/s */
14608 case GST_MAKE_FOURCC ('x', 'd', 'v', '9'): /* XDCAM HD 720p60 35Mb/s */
14609 case GST_MAKE_FOURCC ('x', 'd', 'v', 'a'): /* XDCAM HD 720p50 35Mb/s */
14610 case GST_MAKE_FOURCC ('x', 'd', 'v', 'b'): /* XDCAM EX 1080i60 50Mb/s CBR */
14611 case GST_MAKE_FOURCC ('x', 'd', 'v', 'c'): /* XDCAM EX 1080i50 50Mb/s CBR */
14612 case GST_MAKE_FOURCC ('x', 'd', 'v', 'd'): /* XDCAM HD 1080p24 50Mb/s CBR */
14613 case GST_MAKE_FOURCC ('x', 'd', 'v', 'e'): /* XDCAM HD 1080p25 50Mb/s CBR */
14614 case GST_MAKE_FOURCC ('x', 'd', 'v', 'f'): /* XDCAM HD 1080p30 50Mb/s CBR */
14615 case GST_MAKE_FOURCC ('x', 'd', '5', '1'): /* XDCAM HD422 720p30 50Mb/s CBR */
14616 case GST_MAKE_FOURCC ('x', 'd', '5', '4'): /* XDCAM HD422 720p24 50Mb/s CBR */
14617 case GST_MAKE_FOURCC ('x', 'd', '5', '5'): /* XDCAM HD422 720p25 50Mb/s CBR */
14618 case GST_MAKE_FOURCC ('x', 'd', '5', '9'): /* XDCAM HD422 720p60 50Mb/s CBR */
14619 case GST_MAKE_FOURCC ('x', 'd', '5', 'a'): /* XDCAM HD422 720p50 50Mb/s CBR */
14620 case GST_MAKE_FOURCC ('x', 'd', '5', 'b'): /* XDCAM HD422 1080i50 50Mb/s CBR */
14621 case GST_MAKE_FOURCC ('x', 'd', '5', 'c'): /* XDCAM HD422 1080i50 50Mb/s CBR */
14622 case GST_MAKE_FOURCC ('x', 'd', '5', 'd'): /* XDCAM HD422 1080p24 50Mb/s CBR */
14623 case GST_MAKE_FOURCC ('x', 'd', '5', 'e'): /* XDCAM HD422 1080p25 50Mb/s CBR */
14624 case GST_MAKE_FOURCC ('x', 'd', '5', 'f'): /* XDCAM HD422 1080p30 50Mb/s CBR */
14625 case GST_MAKE_FOURCC ('x', 'd', 'h', 'd'): /* XDCAM HD 540p */
14626 case GST_MAKE_FOURCC ('x', 'd', 'h', '2'): /* XDCAM HD422 540p */
14627 case GST_MAKE_FOURCC ('A', 'V', 'm', 'p'): /* AVID IMX PAL */
14628 case GST_MAKE_FOURCC ('m', 'p', 'g', '2'): /* AVID IMX PAL */
14629 case GST_MAKE_FOURCC ('m', 'p', '2', 'v'): /* AVID IMX PAL */
14630 case GST_MAKE_FOURCC ('m', '2', 'v', '1'):
14631 _codec ("MPEG-2 video");
14632 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 2,
14633 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14634 break;
14635 case GST_MAKE_FOURCC ('g', 'i', 'f', ' '):
14636 _codec ("GIF still images");
14637 caps = gst_caps_new_empty_simple ("image/gif");
14638 break;
14639 case FOURCC_h263:
14640 case GST_MAKE_FOURCC ('H', '2', '6', '3'):
14641 case FOURCC_s263:
14642 case GST_MAKE_FOURCC ('U', '2', '6', '3'):
14643 _codec ("H.263");
14644 /* ffmpeg uses the height/width props, don't know why */
14645 caps = gst_caps_new_simple ("video/x-h263",
14646 "variant", G_TYPE_STRING, "itu", NULL);
14647 break;
14648 case FOURCC_mp4v:
14649 case FOURCC_MP4V:
14650 _codec ("MPEG-4 video");
14651 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
14652 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14653 break;
14654 case GST_MAKE_FOURCC ('3', 'i', 'v', 'd'):
14655 case GST_MAKE_FOURCC ('3', 'I', 'V', 'D'):
14656 _codec ("Microsoft MPEG-4 4.3"); /* FIXME? */
14657 caps = gst_caps_new_simple ("video/x-msmpeg",
14658 "msmpegversion", G_TYPE_INT, 43, NULL);
14659 break;
14660 case GST_MAKE_FOURCC ('D', 'I', 'V', '3'):
14661 _codec ("DivX 3");
14662 caps = gst_caps_new_simple ("video/x-divx",
14663 "divxversion", G_TYPE_INT, 3, NULL);
14664 break;
14665 case GST_MAKE_FOURCC ('D', 'I', 'V', 'X'):
14666 case GST_MAKE_FOURCC ('d', 'i', 'v', 'x'):
14667 _codec ("DivX 4");
14668 caps = gst_caps_new_simple ("video/x-divx",
14669 "divxversion", G_TYPE_INT, 4, NULL);
14670 break;
14671 case GST_MAKE_FOURCC ('D', 'X', '5', '0'):
14672 _codec ("DivX 5");
14673 caps = gst_caps_new_simple ("video/x-divx",
14674 "divxversion", G_TYPE_INT, 5, NULL);
14675 break;
14676
14677 case GST_MAKE_FOURCC ('F', 'F', 'V', '1'):
14678 _codec ("FFV1");
14679 caps = gst_caps_new_simple ("video/x-ffv",
14680 "ffvversion", G_TYPE_INT, 1, NULL);
14681 break;
14682
14683 case GST_MAKE_FOURCC ('3', 'I', 'V', '1'):
14684 case GST_MAKE_FOURCC ('3', 'I', 'V', '2'):
14685 case FOURCC_XVID:
14686 case FOURCC_xvid:
14687 case FOURCC_FMP4:
14688 case FOURCC_fmp4:
14689 case GST_MAKE_FOURCC ('U', 'M', 'P', '4'):
14690 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
14691 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14692 _codec ("MPEG-4");
14693 break;
14694
14695 case GST_MAKE_FOURCC ('c', 'v', 'i', 'd'):
14696 _codec ("Cinepak");
14697 caps = gst_caps_new_empty_simple ("video/x-cinepak");
14698 break;
14699 case GST_MAKE_FOURCC ('q', 'd', 'r', 'w'):
14700 _codec ("Apple QuickDraw");
14701 caps = gst_caps_new_empty_simple ("video/x-qdrw");
14702 break;
14703 case GST_MAKE_FOURCC ('r', 'p', 'z', 'a'):
14704 _codec ("Apple video");
14705 caps = gst_caps_new_empty_simple ("video/x-apple-video");
14706 break;
14707 case FOURCC_H264:
14708 case FOURCC_avc1:
14709 case FOURCC_dva1:
14710 _codec ("H.264 / AVC");
14711 caps = gst_caps_new_simple ("video/x-h264",
14712 "stream-format", G_TYPE_STRING, "avc",
14713 "alignment", G_TYPE_STRING, "au", NULL);
14714 break;
14715 case FOURCC_avc3:
14716 case FOURCC_dvav:
14717 _codec ("H.264 / AVC");
14718 caps = gst_caps_new_simple ("video/x-h264",
14719 "stream-format", G_TYPE_STRING, "avc3",
14720 "alignment", G_TYPE_STRING, "au", NULL);
14721 break;
14722 case FOURCC_H265:
14723 case FOURCC_hvc1:
14724 case FOURCC_dvh1:
14725 _codec ("H.265 / HEVC");
14726 caps = gst_caps_new_simple ("video/x-h265",
14727 "stream-format", G_TYPE_STRING, "hvc1",
14728 "alignment", G_TYPE_STRING, "au", NULL);
14729 break;
14730 case FOURCC_hev1:
14731 case FOURCC_dvhe:
14732 _codec ("H.265 / HEVC");
14733 caps = gst_caps_new_simple ("video/x-h265",
14734 "stream-format", G_TYPE_STRING, "hev1",
14735 "alignment", G_TYPE_STRING, "au", NULL);
14736 break;
14737 case FOURCC_rle_:
14738 _codec ("Run-length encoding");
14739 caps = gst_caps_new_simple ("video/x-rle",
14740 "layout", G_TYPE_STRING, "quicktime", NULL);
14741 break;
14742 case FOURCC_WRLE:
14743 _codec ("Run-length encoding");
14744 caps = gst_caps_new_simple ("video/x-rle",
14745 "layout", G_TYPE_STRING, "microsoft", NULL);
14746 break;
14747 case GST_MAKE_FOURCC ('I', 'V', '3', '2'):
14748 case GST_MAKE_FOURCC ('i', 'v', '3', '2'):
14749 _codec ("Indeo Video 3");
14750 caps = gst_caps_new_simple ("video/x-indeo",
14751 "indeoversion", G_TYPE_INT, 3, NULL);
14752 break;
14753 case GST_MAKE_FOURCC ('I', 'V', '4', '1'):
14754 case GST_MAKE_FOURCC ('i', 'v', '4', '1'):
14755 _codec ("Intel Video 4");
14756 caps = gst_caps_new_simple ("video/x-indeo",
14757 "indeoversion", G_TYPE_INT, 4, NULL);
14758 break;
14759 case FOURCC_dvcp:
14760 case FOURCC_dvc_:
14761 case GST_MAKE_FOURCC ('d', 'v', 's', 'd'):
14762 case GST_MAKE_FOURCC ('D', 'V', 'S', 'D'):
14763 case GST_MAKE_FOURCC ('d', 'v', 'c', 's'):
14764 case GST_MAKE_FOURCC ('D', 'V', 'C', 'S'):
14765 case GST_MAKE_FOURCC ('d', 'v', '2', '5'):
14766 case GST_MAKE_FOURCC ('d', 'v', 'p', 'p'):
14767 _codec ("DV Video");
14768 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 25,
14769 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14770 break;
14771 case FOURCC_dv5n: /* DVCPRO50 NTSC */
14772 case FOURCC_dv5p: /* DVCPRO50 PAL */
14773 _codec ("DVCPro50 Video");
14774 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 50,
14775 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14776 break;
14777 case GST_MAKE_FOURCC ('d', 'v', 'h', '5'): /* DVCPRO HD 50i produced by FCP */
14778 case GST_MAKE_FOURCC ('d', 'v', 'h', '6'): /* DVCPRO HD 60i produced by FCP */
14779 _codec ("DVCProHD Video");
14780 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 100,
14781 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14782 break;
14783 case GST_MAKE_FOURCC ('s', 'm', 'c', ' '):
14784 _codec ("Apple Graphics (SMC)");
14785 caps = gst_caps_new_empty_simple ("video/x-smc");
14786 break;
14787 case GST_MAKE_FOURCC ('V', 'P', '3', '1'):
14788 _codec ("VP3");
14789 caps = gst_caps_new_empty_simple ("video/x-vp3");
14790 break;
14791 case GST_MAKE_FOURCC ('V', 'P', '6', 'F'):
14792 _codec ("VP6 Flash");
14793 caps = gst_caps_new_empty_simple ("video/x-vp6-flash");
14794 break;
14795 case FOURCC_XiTh:
14796 _codec ("Theora");
14797 caps = gst_caps_new_empty_simple ("video/x-theora");
14798 /* theora uses one byte of padding in the data stream because it does not
14799 * allow 0 sized packets while theora does */
14800 entry->padding = 1;
14801 break;
14802 case FOURCC_drac:
14803 _codec ("Dirac");
14804 caps = gst_caps_new_empty_simple ("video/x-dirac");
14805 break;
14806 case GST_MAKE_FOURCC ('t', 'i', 'f', 'f'):
14807 _codec ("TIFF still images");
14808 caps = gst_caps_new_empty_simple ("image/tiff");
14809 break;
14810 case GST_MAKE_FOURCC ('i', 'c', 'o', 'd'):
14811 _codec ("Apple Intermediate Codec");
14812 caps = gst_caps_from_string ("video/x-apple-intermediate-codec");
14813 break;
14814 case GST_MAKE_FOURCC ('A', 'V', 'd', 'n'):
14815 _codec ("AVID DNxHD");
14816 caps = gst_caps_from_string ("video/x-dnxhd");
14817 break;
14818 case FOURCC_VP80:
14819 case FOURCC_vp08:
14820 _codec ("On2 VP8");
14821 caps = gst_caps_from_string ("video/x-vp8");
14822 break;
14823 case FOURCC_vp09:
14824 _codec ("Google VP9");
14825 caps = gst_caps_from_string ("video/x-vp9");
14826 break;
14827 case FOURCC_apcs:
14828 _codec ("Apple ProRes LT");
14829 caps =
14830 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "lt",
14831 NULL);
14832 break;
14833 case FOURCC_apch:
14834 _codec ("Apple ProRes HQ");
14835 caps =
14836 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "hq",
14837 NULL);
14838 break;
14839 case FOURCC_apcn:
14840 _codec ("Apple ProRes");
14841 caps =
14842 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14843 "standard", NULL);
14844 break;
14845 case FOURCC_apco:
14846 _codec ("Apple ProRes Proxy");
14847 caps =
14848 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14849 "proxy", NULL);
14850 break;
14851 case FOURCC_ap4h:
14852 _codec ("Apple ProRes 4444");
14853 caps =
14854 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14855 "4444", NULL);
14856
14857 /* 24 bits per sample = an alpha channel is coded but image is always opaque */
14858 if (entry->bits_per_sample > 0) {
14859 gst_caps_set_simple (caps, "depth", G_TYPE_INT, entry->bits_per_sample,
14860 NULL);
14861 }
14862 break;
14863 case FOURCC_ap4x:
14864 _codec ("Apple ProRes 4444 XQ");
14865 caps =
14866 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14867 "4444xq", NULL);
14868
14869 /* 24 bits per sample = an alpha channel is coded but image is always opaque */
14870 if (entry->bits_per_sample > 0) {
14871 gst_caps_set_simple (caps, "depth", G_TYPE_INT, entry->bits_per_sample,
14872 NULL);
14873 }
14874 break;
14875 case FOURCC_cfhd:
14876 _codec ("GoPro CineForm");
14877 caps = gst_caps_from_string ("video/x-cineform");
14878 break;
14879 case FOURCC_vc_1:
14880 case FOURCC_ovc1:
14881 _codec ("VC-1");
14882 caps = gst_caps_new_simple ("video/x-wmv",
14883 "wmvversion", G_TYPE_INT, 3, "format", G_TYPE_STRING, "WVC1", NULL);
14884 break;
14885 case FOURCC_av01:
14886 _codec ("AV1");
14887 caps = gst_caps_new_empty_simple ("video/x-av1");
14888 break;
14889 case GST_MAKE_FOURCC ('k', 'p', 'c', 'd'):
14890 default:
14891 {
14892 caps = _get_unknown_codec_name ("video", fourcc);
14893 break;
14894 }
14895 }
14896
14897 if (format != GST_VIDEO_FORMAT_UNKNOWN) {
14898 GstVideoInfo info;
14899
14900 gst_video_info_init (&info);
14901 gst_video_info_set_format (&info, format, entry->width, entry->height);
14902
14903 caps = gst_video_info_to_caps (&info);
14904 *codec_name = gst_pb_utils_get_codec_description (caps);
14905
14906 /* enable clipping for raw video streams */
14907 stream->need_clip = TRUE;
14908 stream->alignment = 32;
14909 }
14910
14911 return caps;
14912 }
14913
14914 static guint
14915 round_up_pow2 (guint n)
14916 {
14917 n = n - 1;
14918 n = n | (n >> 1);
14919 n = n | (n >> 2);
14920 n = n | (n >> 4);
14921 n = n | (n >> 8);
14922 n = n | (n >> 16);
14923 return n + 1;
14924 }
14925
14926 static GstCaps *
14927 qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
14928 QtDemuxStreamStsdEntry * entry, guint32 fourcc, const guint8 * data,
14929 int len, gchar ** codec_name)
14930 {
14931 GstCaps *caps;
14932 const GstStructure *s;
14933 const gchar *name;
14934 gint endian = 0;
14935 GstAudioFormat format = 0;
14936 gint depth;
14937
14938 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
14939
14940 depth = entry->bytes_per_packet * 8;
14941
14942 switch (fourcc) {
14943 case GST_MAKE_FOURCC ('N', 'O', 'N', 'E'):
14944 case FOURCC_raw_:
14945 /* 8-bit audio is unsigned */
14946 if (depth == 8)
14947 format = GST_AUDIO_FORMAT_U8;
14948 /* otherwise it's signed and big-endian just like 'twos' */
14949 case FOURCC_twos:
14950 endian = G_BIG_ENDIAN;
14951 /* fall-through */
14952 case FOURCC_sowt:
14953 {
14954 gchar *str;
14955
14956 if (!endian)
14957 endian = G_LITTLE_ENDIAN;
14958
14959 if (!format)
14960 format = gst_audio_format_build_integer (TRUE, endian, depth, depth);
14961
14962 str = g_strdup_printf ("Raw %d-bit PCM audio", depth);
14963 _codec (str);
14964 g_free (str);
14965
14966 caps = gst_caps_new_simple ("audio/x-raw",
14967 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
14968 "layout", G_TYPE_STRING, "interleaved", NULL);
14969 stream->alignment = GST_ROUND_UP_8 (depth);
14970 stream->alignment = round_up_pow2 (stream->alignment);
14971 break;
14972 }
14973 case FOURCC_fl64:
14974 _codec ("Raw 64-bit floating-point audio");
14975 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
14976 * endian later */
14977 caps = gst_caps_new_simple ("audio/x-raw",
14978 "format", G_TYPE_STRING, "F64BE",
14979 "layout", G_TYPE_STRING, "interleaved", NULL);
14980 stream->alignment = 8;
14981 break;
14982 case FOURCC_fl32:
14983 _codec ("Raw 32-bit floating-point audio");
14984 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
14985 * endian later */
14986 caps = gst_caps_new_simple ("audio/x-raw",
14987 "format", G_TYPE_STRING, "F32BE",
14988 "layout", G_TYPE_STRING, "interleaved", NULL);
14989 stream->alignment = 4;
14990 break;
14991 case FOURCC_in24:
14992 _codec ("Raw 24-bit PCM audio");
14993 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
14994 * endian later */
14995 caps = gst_caps_new_simple ("audio/x-raw",
14996 "format", G_TYPE_STRING, "S24BE",
14997 "layout", G_TYPE_STRING, "interleaved", NULL);
14998 stream->alignment = 4;
14999 break;
15000 case FOURCC_in32:
15001 _codec ("Raw 32-bit PCM audio");
15002 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
15003 * endian later */
15004 caps = gst_caps_new_simple ("audio/x-raw",
15005 "format", G_TYPE_STRING, "S32BE",
15006 "layout", G_TYPE_STRING, "interleaved", NULL);
15007 stream->alignment = 4;
15008 break;
15009 case FOURCC_s16l:
15010 _codec ("Raw 16-bit PCM audio");
15011 caps = gst_caps_new_simple ("audio/x-raw",
15012 "format", G_TYPE_STRING, "S16LE",
15013 "layout", G_TYPE_STRING, "interleaved", NULL);
15014 stream->alignment = 2;
15015 break;
15016 case FOURCC_ulaw:
15017 _codec ("Mu-law audio");
15018 caps = gst_caps_new_empty_simple ("audio/x-mulaw");
15019 break;
15020 case FOURCC_alaw:
15021 _codec ("A-law audio");
15022 caps = gst_caps_new_empty_simple ("audio/x-alaw");
15023 break;
15024 case 0x0200736d:
15025 case 0x6d730002:
15026 _codec ("Microsoft ADPCM");
15027 /* Microsoft ADPCM-ACM code 2 */
15028 caps = gst_caps_new_simple ("audio/x-adpcm",
15029 "layout", G_TYPE_STRING, "microsoft", NULL);
15030 break;
15031 case 0x1100736d:
15032 case 0x6d730011:
15033 _codec ("DVI/IMA ADPCM");
15034 caps = gst_caps_new_simple ("audio/x-adpcm",
15035 "layout", G_TYPE_STRING, "dvi", NULL);
15036 break;
15037 case 0x1700736d:
15038 case 0x6d730017:
15039 _codec ("DVI/Intel IMA ADPCM");
15040 /* FIXME DVI/Intel IMA ADPCM/ACM code 17 */
15041 caps = gst_caps_new_simple ("audio/x-adpcm",
15042 "layout", G_TYPE_STRING, "quicktime", NULL);
15043 break;
15044 case 0x5500736d:
15045 case 0x6d730055:
15046 /* MPEG layer 3, CBR only (pre QT4.1) */
15047 case FOURCC__mp3:
15048 case FOURCC_mp3_:
15049 _codec ("MPEG-1 layer 3");
15050 /* MPEG layer 3, CBR & VBR (QT4.1 and later) */
15051 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 3,
15052 "mpegversion", G_TYPE_INT, 1, NULL);
15053 break;
15054 case GST_MAKE_FOURCC ('.', 'm', 'p', '2'):
15055 _codec ("MPEG-1 layer 2");
15056 /* MPEG layer 2 */
15057 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 2,
15058 "mpegversion", G_TYPE_INT, 1, NULL);
15059 break;
15060 case 0x20736d:
15061 case GST_MAKE_FOURCC ('e', 'c', '-', '3'):
15062 _codec ("EAC-3 audio");
15063 caps = gst_caps_new_simple ("audio/x-eac3",
15064 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
15065 entry->sampled = TRUE;
15066 break;
15067 case GST_MAKE_FOURCC ('s', 'a', 'c', '3'): // Nero Recode
15068 case FOURCC_ac_3:
15069 _codec ("AC-3 audio");
15070 caps = gst_caps_new_simple ("audio/x-ac3",
15071 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
15072 entry->sampled = TRUE;
15073 break;
15074 case GST_MAKE_FOURCC ('d', 't', 's', 'c'):
15075 case GST_MAKE_FOURCC ('D', 'T', 'S', ' '):
15076 _codec ("DTS audio");
15077 caps = gst_caps_new_simple ("audio/x-dts",
15078 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
15079 entry->sampled = TRUE;
15080 break;
15081 case GST_MAKE_FOURCC ('d', 't', 's', 'h'): // DTS-HD
15082 case GST_MAKE_FOURCC ('d', 't', 's', 'l'): // DTS-HD Lossless
15083 _codec ("DTS-HD audio");
15084 caps = gst_caps_new_simple ("audio/x-dts",
15085 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
15086 entry->sampled = TRUE;
15087 break;
15088 case FOURCC_MAC3:
15089 _codec ("MACE-3");
15090 caps = gst_caps_new_simple ("audio/x-mace",
15091 "maceversion", G_TYPE_INT, 3, NULL);
15092 break;
15093 case FOURCC_MAC6:
15094 _codec ("MACE-6");
15095 caps = gst_caps_new_simple ("audio/x-mace",
15096 "maceversion", G_TYPE_INT, 6, NULL);
15097 break;
15098 case GST_MAKE_FOURCC ('O', 'g', 'g', 'V'):
15099 /* ogg/vorbis */
15100 caps = gst_caps_new_empty_simple ("application/ogg");
15101 break;
15102 case GST_MAKE_FOURCC ('d', 'v', 'c', 'a'):
15103 _codec ("DV audio");
15104 caps = gst_caps_new_empty_simple ("audio/x-dv");
15105 break;
15106 case FOURCC_mp4a:
15107 _codec ("MPEG-4 AAC audio");
15108 caps = gst_caps_new_simple ("audio/mpeg",
15109 "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE,
15110 "stream-format", G_TYPE_STRING, "raw", NULL);
15111 break;
15112 case GST_MAKE_FOURCC ('Q', 'D', 'M', 'C'):
15113 _codec ("QDesign Music");
15114 caps = gst_caps_new_empty_simple ("audio/x-qdm");
15115 break;
15116 case FOURCC_QDM2:
15117 _codec ("QDesign Music v.2");
15118 /* FIXME: QDesign music version 2 (no constant) */
15119 if (FALSE && data) {
15120 caps = gst_caps_new_simple ("audio/x-qdm2",
15121 "framesize", G_TYPE_INT, QT_UINT32 (data + 52),
15122 "bitrate", G_TYPE_INT, QT_UINT32 (data + 40),
15123 "blocksize", G_TYPE_INT, QT_UINT32 (data + 44), NULL);
15124 } else {
15125 caps = gst_caps_new_empty_simple ("audio/x-qdm2");
15126 }
15127 break;
15128 case FOURCC_agsm:
15129 _codec ("GSM audio");
15130 caps = gst_caps_new_empty_simple ("audio/x-gsm");
15131 break;
15132 case FOURCC_samr:
15133 _codec ("AMR audio");
15134 caps = gst_caps_new_empty_simple ("audio/AMR");
15135 break;
15136 case FOURCC_sawb:
15137 _codec ("AMR-WB audio");
15138 caps = gst_caps_new_empty_simple ("audio/AMR-WB");
15139 break;
15140 case FOURCC_ima4:
15141 _codec ("Quicktime IMA ADPCM");
15142 caps = gst_caps_new_simple ("audio/x-adpcm",
15143 "layout", G_TYPE_STRING, "quicktime", NULL);
15144 break;
15145 case FOURCC_alac:
15146 _codec ("Apple lossless audio");
15147 caps = gst_caps_new_empty_simple ("audio/x-alac");
15148 break;
15149 case FOURCC_fLaC:
15150 _codec ("Free Lossless Audio Codec");
15151 caps = gst_caps_new_simple ("audio/x-flac",
15152 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
15153 break;
15154 case GST_MAKE_FOURCC ('Q', 'c', 'l', 'p'):
15155 _codec ("QualComm PureVoice");
15156 caps = gst_caps_from_string ("audio/qcelp");
15157 break;
15158 case FOURCC_wma_:
15159 case FOURCC_owma:
15160 _codec ("WMA");
15161 caps = gst_caps_new_empty_simple ("audio/x-wma");
15162 break;
15163 case FOURCC_opus:
15164 _codec ("Opus");
15165 caps = gst_caps_new_empty_simple ("audio/x-opus");
15166 break;
15167 case FOURCC_lpcm:
15168 {
15169 guint32 flags = 0;
15170 guint32 depth = 0;
15171 guint32 width = 0;
15172 GstAudioFormat format;
15173 enum
15174 {
15175 FLAG_IS_FLOAT = 0x1,
15176 FLAG_IS_BIG_ENDIAN = 0x2,
15177 FLAG_IS_SIGNED = 0x4,
15178 FLAG_IS_PACKED = 0x8,
15179 FLAG_IS_ALIGNED_HIGH = 0x10,
15180 FLAG_IS_NON_INTERLEAVED = 0x20
15181 };
15182 _codec ("Raw LPCM audio");
15183
15184 if (data && len >= 36) {
15185 depth = QT_UINT32 (data + 24);
15186 flags = QT_UINT32 (data + 28);
15187 width = QT_UINT32 (data + 32) * 8 / entry->n_channels;
15188 }
15189 if ((flags & FLAG_IS_FLOAT) == 0) {
15190 if (depth == 0)
15191 depth = 16;
15192 if (width == 0)
15193 width = 16;
15194 if ((flags & FLAG_IS_ALIGNED_HIGH))
15195 depth = width;
15196
15197 format = gst_audio_format_build_integer ((flags & FLAG_IS_SIGNED) ?
15198 TRUE : FALSE, (flags & FLAG_IS_BIG_ENDIAN) ?
15199 G_BIG_ENDIAN : G_LITTLE_ENDIAN, width, depth);
15200 caps = gst_caps_new_simple ("audio/x-raw",
15201 "format", G_TYPE_STRING,
15202 format !=
15203 GST_AUDIO_FORMAT_UNKNOWN ? gst_audio_format_to_string (format) :
15204 "UNKNOWN", "layout", G_TYPE_STRING,
15205 (flags & FLAG_IS_NON_INTERLEAVED) ? "non-interleaved" :
15206 "interleaved", NULL);
15207 stream->alignment = GST_ROUND_UP_8 (depth);
15208 stream->alignment = round_up_pow2 (stream->alignment);
15209 } else {
15210 if (width == 0)
15211 width = 32;
15212 if (width == 64) {
15213 if (flags & FLAG_IS_BIG_ENDIAN)
15214 format = GST_AUDIO_FORMAT_F64BE;
15215 else
15216 format = GST_AUDIO_FORMAT_F64LE;
15217 } else {
15218 if (flags & FLAG_IS_BIG_ENDIAN)
15219 format = GST_AUDIO_FORMAT_F32BE;
15220 else
15221 format = GST_AUDIO_FORMAT_F32LE;
15222 }
15223 caps = gst_caps_new_simple ("audio/x-raw",
15224 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
15225 "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
15226 "non-interleaved" : "interleaved", NULL);
15227 stream->alignment = width / 8;
15228 }
15229 break;
15230 }
15231 case GST_MAKE_FOURCC ('a', 'c', '-', '4'):
15232 {
15233 _codec ("AC4");
15234 caps = gst_caps_new_empty_simple ("audio/x-ac4");
15235 break;
15236 }
15237 case GST_MAKE_FOURCC ('q', 't', 'v', 'r'):
15238 /* ? */
15239 default:
15240 {
15241 caps = _get_unknown_codec_name ("audio", fourcc);
15242 break;
15243 }
15244 }
15245
15246 if (caps) {
15247 GstCaps *templ_caps =
15248 gst_static_pad_template_get_caps (&gst_qtdemux_audiosrc_template);
15249 GstCaps *intersection = gst_caps_intersect (caps, templ_caps);
15250 gst_caps_unref (caps);
15251 gst_caps_unref (templ_caps);
15252 caps = intersection;
15253 }
15254
15255 /* enable clipping for raw audio streams */
15256 s = gst_caps_get_structure (caps, 0);
15257 name = gst_structure_get_name (s);
15258 if (g_str_has_prefix (name, "audio/x-raw")) {
15259 stream->need_clip = TRUE;
15260 stream->min_buffer_size = 1024 * entry->bytes_per_frame;
15261 stream->max_buffer_size = 4096 * entry->bytes_per_frame;
15262 GST_DEBUG ("setting min/max buffer sizes to %d/%d", stream->min_buffer_size,
15263 stream->max_buffer_size);
15264 }
15265 return caps;
15266 }
15267
15268 static GstCaps *
15269 qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
15270 QtDemuxStreamStsdEntry * entry, guint32 fourcc,
15271 const guint8 * stsd_entry_data, gchar ** codec_name)
15272 {
15273 GstCaps *caps;
15274
15275 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
15276
15277 switch (fourcc) {
15278 case FOURCC_mp4s:
15279 _codec ("DVD subtitle");
15280 caps = gst_caps_new_empty_simple ("subpicture/x-dvd");
15281 stream->process_func = gst_qtdemux_process_buffer_dvd;
15282 break;
15283 case FOURCC_text:
15284 _codec ("Quicktime timed text");
15285 goto text;
15286 case FOURCC_tx3g:
15287 _codec ("3GPP timed text");
15288 text:
15289 caps = gst_caps_new_simple ("text/x-raw", "format", G_TYPE_STRING,
15290 "utf8", NULL);
15291 /* actual text piece needs to be extracted */
15292 stream->process_func = gst_qtdemux_process_buffer_text;
15293 break;
15294 case FOURCC_stpp:
15295 _codec ("XML subtitles");
15296 caps = gst_caps_new_empty_simple ("application/ttml+xml");
15297 break;
15298 case FOURCC_wvtt:
15299 {
15300 GstBuffer *buffer;
15301 const gchar *buf = "WEBVTT\n\n";
15302
15303 _codec ("WebVTT subtitles");
15304 caps = gst_caps_new_empty_simple ("application/x-subtitle-vtt");
15305 stream->process_func = gst_qtdemux_process_buffer_wvtt;
15306
15307 /* FIXME: Parse the vttC atom and get the entire WEBVTT header */
15308 buffer = gst_buffer_new_and_alloc (8);
15309 gst_buffer_fill (buffer, 0, buf, 8);
15310 stream->buffers = g_slist_append (stream->buffers, buffer);
15311
15312 break;
15313 }
15314 case FOURCC_c608:
15315 _codec ("CEA 608 Closed Caption");
15316 caps =
15317 gst_caps_new_simple ("closedcaption/x-cea-608", "format",
15318 G_TYPE_STRING, "s334-1a", NULL);
15319 stream->process_func = gst_qtdemux_process_buffer_clcp;
15320 stream->need_split = TRUE;
15321 break;
15322 case FOURCC_c708:
15323 _codec ("CEA 708 Closed Caption");
15324 caps =
15325 gst_caps_new_simple ("closedcaption/x-cea-708", "format",
15326 G_TYPE_STRING, "cdp", NULL);
15327 stream->process_func = gst_qtdemux_process_buffer_clcp;
15328 break;
15329
15330 default:
15331 {
15332 caps = _get_unknown_codec_name ("text", fourcc);
15333 break;
15334 }
15335 }
15336 return caps;
15337 }
15338
15339 static GstCaps *
15340 qtdemux_generic_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
15341 QtDemuxStreamStsdEntry * entry, guint32 fourcc,
15342 const guint8 * stsd_entry_data, gchar ** codec_name)
15343 {
15344 GstCaps *caps;
15345
15346 switch (fourcc) {
15347 case FOURCC_m1v:
15348 _codec ("MPEG 1 video");
15349 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
15350 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
15351 break;
15352 default:
15353 caps = NULL;
15354 break;
15355 }
15356 return caps;
15357 }
15358
15359 static void
15360 gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux,
15361 const gchar * system_id)
15362 {
15363 gint i;
15364
15365 if (!qtdemux->protection_system_ids)
15366 qtdemux->protection_system_ids =
15367 g_ptr_array_new_with_free_func ((GDestroyNotify) g_free);
15368 /* Check whether we already have an entry for this system ID. */
15369 for (i = 0; i < qtdemux->protection_system_ids->len; ++i) {
15370 const gchar *id = g_ptr_array_index (qtdemux->protection_system_ids, i);
15371 if (g_ascii_strcasecmp (system_id, id) == 0) {
15372 return;
15373 }
15374 }
15375 GST_DEBUG_OBJECT (qtdemux, "Adding cenc protection system ID %s", system_id);
15376 g_ptr_array_add (qtdemux->protection_system_ids, g_ascii_strdown (system_id,
15377 -1));
15378 }
15379