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 /* max. size considered 'sane' for non-mdat atoms */
86 #define QTDEMUX_MAX_ATOM_SIZE (32*1024*1024)
87
88 /* if the sample index is larger than this, something is likely wrong */
89 #define QTDEMUX_MAX_SAMPLE_INDEX_SIZE (200*1024*1024)
90
91 /* For converting qt creation times to unix epoch times */
92 #define QTDEMUX_SECONDS_PER_DAY (60 * 60 * 24)
93 #define QTDEMUX_LEAP_YEARS_FROM_1904_TO_1970 17
94 #define QTDEMUX_SECONDS_FROM_1904_TO_1970 (((1970 - 1904) * (guint64) 365 + \
95 QTDEMUX_LEAP_YEARS_FROM_1904_TO_1970) * QTDEMUX_SECONDS_PER_DAY)
96
97 #define QTDEMUX_TREE_NODE_FOURCC(n) (QT_FOURCC(((guint8 *) (n)->data) + 4))
98
99 #define STREAM_IS_EOS(s) ((s)->time_position == GST_CLOCK_TIME_NONE)
100
101 #define ABSDIFF(x, y) ( (x) > (y) ? ((x) - (y)) : ((y) - (x)) )
102
103 #define QTDEMUX_STREAM(s) ((QtDemuxStream *)(s))
104 #define QTDEMUX_N_STREAMS(demux) ((demux)->active_streams->len)
105 #define QTDEMUX_NTH_STREAM(demux,idx) \
106 QTDEMUX_STREAM(g_ptr_array_index((demux)->active_streams,idx))
107 #define QTDEMUX_NTH_OLD_STREAM(demux,idx) \
108 QTDEMUX_STREAM(g_ptr_array_index((demux)->old_streams,idx))
109
110 #define CUR_STREAM(s) (&((s)->stsd_entries[(s)->cur_stsd_entry_index]))
111
112 GST_DEBUG_CATEGORY (qtdemux_debug);
113 #define GST_CAT_DEFAULT qtdemux_debug
114
115 typedef struct _QtDemuxCencSampleSetInfo QtDemuxCencSampleSetInfo;
116 typedef struct _QtDemuxAavdEncryptionInfo QtDemuxAavdEncryptionInfo;
117
118 /* Macros for converting to/from timescale */
119 #define QTSTREAMTIME_TO_GSTTIME(stream, value) (gst_util_uint64_scale((value), GST_SECOND, (stream)->timescale))
120 #define GSTTIME_TO_QTSTREAMTIME(stream, value) (gst_util_uint64_scale((value), (stream)->timescale, GST_SECOND))
121
122 #define QTTIME_TO_GSTTIME(qtdemux, value) (gst_util_uint64_scale((value), GST_SECOND, (qtdemux)->timescale))
123 #define GSTTIME_TO_QTTIME(qtdemux, value) (gst_util_uint64_scale((value), (qtdemux)->timescale, GST_SECOND))
124
125 /* timestamp is the DTS */
126 #define QTSAMPLE_DTS(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp))
127 /* timestamp + offset + cslg_shift is the outgoing PTS */
128 #define QTSAMPLE_PTS(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp + (stream)->cslg_shift + (sample)->pts_offset))
129 /* timestamp + offset is the PTS used for internal seek calculations */
130 #define QTSAMPLE_PTS_NO_CSLG(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp + (sample)->pts_offset))
131 /* timestamp + duration - dts is the duration */
132 #define QTSAMPLE_DUR_DTS(stream, sample, dts) (QTSTREAMTIME_TO_GSTTIME ((stream), (sample)->timestamp + (sample)->duration) - (dts))
133
134 #define QTSAMPLE_KEYFRAME(stream,sample) ((stream)->all_keyframe || (sample)->keyframe)
135
136 #define QTDEMUX_EXPOSE_GET_LOCK(demux) (&((demux)->expose_lock))
137 #define QTDEMUX_EXPOSE_LOCK(demux) G_STMT_START { \
138 GST_TRACE("Locking from thread %p", g_thread_self()); \
139 g_mutex_lock (QTDEMUX_EXPOSE_GET_LOCK (demux)); \
140 GST_TRACE("Locked from thread %p", g_thread_self()); \
141 } G_STMT_END
142
143 #define QTDEMUX_EXPOSE_UNLOCK(demux) G_STMT_START { \
144 GST_TRACE("Unlocking from thread %p", g_thread_self()); \
145 g_mutex_unlock (QTDEMUX_EXPOSE_GET_LOCK (demux)); \
146 } G_STMT_END
147
148 /*
149 * Quicktime has tracks and segments. A track is a continuous piece of
150 * multimedia content. The track is not always played from start to finish but
151 * instead, pieces of the track are 'cut out' and played in sequence. This is
152 * what the segments do.
153 *
154 * Inside the track we have keyframes (K) and delta frames. The track has its
155 * own timing, which starts from 0 and extends to end. The position in the track
156 * is called the media_time.
157 *
158 * The segments now describe the pieces that should be played from this track
159 * and are basically tuples of media_time/duration/rate entries. We can have
160 * multiple segments and they are all played after one another. An example:
161 *
162 * segment 1: media_time: 1 second, duration: 1 second, rate 1
163 * segment 2: media_time: 3 second, duration: 2 second, rate 2
164 *
165 * To correctly play back this track, one must play: 1 second of media starting
166 * from media_time 1 followed by 2 seconds of media starting from media_time 3
167 * at a rate of 2.
168 *
169 * Each of the segments will be played at a specific time, the first segment at
170 * time 0, the second one after the duration of the first one, etc.. Note that
171 * the time in resulting playback is not identical to the media_time of the
172 * track anymore.
173 *
174 * Visually, assuming the track has 4 second of media_time:
175 *
176 * (a) (b) (c) (d)
177 * .-----------------------------------------------------------.
178 * track: | K.....K.........K........K.......K.......K...........K... |
179 * '-----------------------------------------------------------'
180 * 0 1 2 3 4
181 * .------------^ ^ .----------^ ^
182 * / .-------------' / .------------------'
183 * / / .-----' /
184 * .--------------. .--------------.
185 * | segment 1 | | segment 2 |
186 * '--------------' '--------------'
187 *
188 * The challenge here is to cut out the right pieces of the track for each of
189 * the playback segments. This fortunately can easily be done with the SEGMENT
190 * events of GStreamer.
191 *
192 * For playback of segment 1, we need to provide the decoder with the keyframe
193 * (a), in the above figure, but we must instruct it only to output the decoded
194 * data between second 1 and 2. We do this with a SEGMENT event for 1 to 2, time
195 * position set to the time of the segment: 0.
196 *
197 * We then proceed to push data from keyframe (a) to frame (b). The decoder
198 * decodes but clips all before media_time 1.
199 *
200 * After finishing a segment, we push out a new SEGMENT event with the clipping
201 * boundaries of the new data.
202 *
203 * This is a good usecase for the GStreamer accumulated SEGMENT events.
204 */
205
206 struct _QtDemuxSegment
207 {
208 /* global time and duration, all gst time */
209 GstClockTime time;
210 GstClockTime stop_time;
211 GstClockTime duration;
212 /* media time of trak, all gst time */
213 GstClockTime media_start;
214 GstClockTime media_stop;
215 gdouble rate;
216 /* Media start time in trak timescale units */
217 guint32 trak_media_start;
218 };
219
220 #define QTSEGMENT_IS_EMPTY(s) ((s)->media_start == GST_CLOCK_TIME_NONE)
221
222 /* Used with fragmented MP4 files (mfra atom) */
223 struct _QtDemuxRandomAccessEntry
224 {
225 GstClockTime ts;
226 guint64 moof_offset;
227 };
228
229
230 /* Contains properties and cryptographic info for a set of samples from a
231 * track protected using Common Encryption (cenc) */
232 struct _QtDemuxCencSampleSetInfo
233 {
234 GstStructure *default_properties;
235
236 /* @crypto_info holds one GstStructure per sample */
237 GPtrArray *crypto_info;
238 };
239
240 struct _QtDemuxAavdEncryptionInfo
241 {
242 GstStructure *default_properties;
243 };
244
245 static const gchar *
qt_demux_state_string(enum QtDemuxState state)246 qt_demux_state_string (enum QtDemuxState state)
247 {
248 switch (state) {
249 case QTDEMUX_STATE_INITIAL:
250 return "<INITIAL>";
251 case QTDEMUX_STATE_HEADER:
252 return "<HEADER>";
253 case QTDEMUX_STATE_MOVIE:
254 return "<MOVIE>";
255 case QTDEMUX_STATE_BUFFER_MDAT:
256 return "<BUFFER_MDAT>";
257 default:
258 return "<UNKNOWN>";
259 }
260 }
261
262 static GstFlowReturn qtdemux_add_fragmented_samples (GstQTDemux * qtdemux);
263
264 static void gst_qtdemux_check_send_pending_segment (GstQTDemux * demux);
265
266 static GstStaticPadTemplate gst_qtdemux_sink_template =
267 GST_STATIC_PAD_TEMPLATE ("sink",
268 GST_PAD_SINK,
269 GST_PAD_ALWAYS,
270 GST_STATIC_CAPS ("video/quicktime; video/mj2; audio/x-m4a; "
271 "application/x-3gp")
272 );
273
274 static GstStaticPadTemplate gst_qtdemux_videosrc_template =
275 GST_STATIC_PAD_TEMPLATE ("video_%u",
276 GST_PAD_SRC,
277 GST_PAD_SOMETIMES,
278 GST_STATIC_CAPS_ANY);
279
280 static GstStaticPadTemplate gst_qtdemux_audiosrc_template =
281 GST_STATIC_PAD_TEMPLATE ("audio_%u",
282 GST_PAD_SRC,
283 GST_PAD_SOMETIMES,
284 GST_STATIC_CAPS_ANY);
285
286 static GstStaticPadTemplate gst_qtdemux_subsrc_template =
287 GST_STATIC_PAD_TEMPLATE ("subtitle_%u",
288 GST_PAD_SRC,
289 GST_PAD_SOMETIMES,
290 GST_STATIC_CAPS_ANY);
291
292 #define gst_qtdemux_parent_class parent_class
293 G_DEFINE_TYPE (GstQTDemux, gst_qtdemux, GST_TYPE_ELEMENT);
294 GST_ELEMENT_REGISTER_DEFINE_WITH_CODE (qtdemux, "qtdemux",
295 GST_RANK_PRIMARY, GST_TYPE_QTDEMUX, isomp4_element_init (plugin));
296
297 static void gst_qtdemux_dispose (GObject * object);
298 static void gst_qtdemux_finalize (GObject * object);
299
300 static guint32
301 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
302 GstClockTime media_time);
303 static guint32
304 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
305 QtDemuxStream * str, gint64 media_offset);
306
307 #if 0
308 static void gst_qtdemux_set_index (GstElement * element, GstIndex * index);
309 static GstIndex *gst_qtdemux_get_index (GstElement * element);
310 #endif
311 static GstStateChangeReturn gst_qtdemux_change_state (GstElement * element,
312 GstStateChange transition);
313 static void gst_qtdemux_set_context (GstElement * element,
314 GstContext * context);
315 static gboolean qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent);
316 static gboolean qtdemux_sink_activate_mode (GstPad * sinkpad,
317 GstObject * parent, GstPadMode mode, gboolean active);
318
319 static void gst_qtdemux_loop (GstPad * pad);
320 static GstFlowReturn gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent,
321 GstBuffer * inbuf);
322 static gboolean gst_qtdemux_handle_sink_event (GstPad * pad, GstObject * parent,
323 GstEvent * event);
324 static gboolean gst_qtdemux_handle_sink_query (GstPad * pad, GstObject * parent,
325 GstQuery * query);
326 static gboolean gst_qtdemux_setcaps (GstQTDemux * qtdemux, GstCaps * caps);
327 static gboolean gst_qtdemux_configure_stream (GstQTDemux * qtdemux,
328 QtDemuxStream * stream);
329 static void gst_qtdemux_stream_check_and_change_stsd_index (GstQTDemux * demux,
330 QtDemuxStream * stream);
331 static GstFlowReturn gst_qtdemux_process_adapter (GstQTDemux * demux,
332 gboolean force);
333
334 static void gst_qtdemux_check_seekability (GstQTDemux * demux);
335
336 static gboolean qtdemux_parse_moov (GstQTDemux * qtdemux,
337 const guint8 * buffer, guint length);
338 static gboolean qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node,
339 const guint8 * buffer, guint length);
340 static gboolean qtdemux_parse_tree (GstQTDemux * qtdemux);
341
342 static void gst_qtdemux_handle_esds (GstQTDemux * qtdemux,
343 QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, GNode * esds,
344 GstTagList * list);
345 static GstCaps *qtdemux_video_caps (GstQTDemux * qtdemux,
346 QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, guint32 fourcc,
347 const guint8 * stsd_entry_data, gchar ** codec_name);
348 static GstCaps *qtdemux_audio_caps (GstQTDemux * qtdemux,
349 QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, guint32 fourcc,
350 const guint8 * data, int len, gchar ** codec_name);
351 static GstCaps *qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
352 QtDemuxStreamStsdEntry * entry, guint32 fourcc, const guint8 * data,
353 gchar ** codec_name);
354 static GstCaps *qtdemux_generic_caps (GstQTDemux * qtdemux,
355 QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, guint32 fourcc,
356 const guint8 * stsd_entry_data, gchar ** codec_name);
357
358 static gboolean qtdemux_parse_samples (GstQTDemux * qtdemux,
359 QtDemuxStream * stream, guint32 n);
360 static GstFlowReturn qtdemux_expose_streams (GstQTDemux * qtdemux);
361 static QtDemuxStream *gst_qtdemux_stream_ref (QtDemuxStream * stream);
362 static void gst_qtdemux_stream_unref (QtDemuxStream * stream);
363 static void gst_qtdemux_stream_clear (QtDemuxStream * stream);
364 static GstFlowReturn qtdemux_prepare_streams (GstQTDemux * qtdemux);
365 static void qtdemux_do_allocation (QtDemuxStream * stream,
366 GstQTDemux * qtdemux);
367 static gboolean gst_qtdemux_activate_segment (GstQTDemux * qtdemux,
368 QtDemuxStream * stream, guint32 seg_idx, GstClockTime offset);
369 static gboolean gst_qtdemux_stream_update_segment (GstQTDemux * qtdemux,
370 QtDemuxStream * stream, gint seg_idx, GstClockTime offset,
371 GstClockTime * _start, GstClockTime * _stop);
372 static void gst_qtdemux_send_gap_for_segment (GstQTDemux * demux,
373 QtDemuxStream * stream, gint segment_index, GstClockTime pos);
374
375 static gboolean qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux);
376 static void check_update_duration (GstQTDemux * qtdemux, GstClockTime duration);
377
378 static gchar *qtdemux_uuid_bytes_to_string (gconstpointer uuid_bytes);
379
380 static GstStructure *qtdemux_get_cenc_sample_properties (GstQTDemux * qtdemux,
381 QtDemuxStream * stream, guint sample_index);
382 static void gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux,
383 const gchar * id);
384 static void qtdemux_gst_structure_free (GstStructure * gststructure);
385 static void gst_qtdemux_reset (GstQTDemux * qtdemux, gboolean hard);
386
387 static void
gst_qtdemux_class_init(GstQTDemuxClass * klass)388 gst_qtdemux_class_init (GstQTDemuxClass * klass)
389 {
390 GObjectClass *gobject_class;
391 GstElementClass *gstelement_class;
392
393 gobject_class = (GObjectClass *) klass;
394 gstelement_class = (GstElementClass *) klass;
395
396 parent_class = g_type_class_peek_parent (klass);
397
398 gobject_class->dispose = gst_qtdemux_dispose;
399 gobject_class->finalize = gst_qtdemux_finalize;
400
401 gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_qtdemux_change_state);
402 #if 0
403 gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_qtdemux_set_index);
404 gstelement_class->get_index = GST_DEBUG_FUNCPTR (gst_qtdemux_get_index);
405 #endif
406 gstelement_class->set_context = GST_DEBUG_FUNCPTR (gst_qtdemux_set_context);
407
408 gst_tag_register_musicbrainz_tags ();
409
410 gst_element_class_add_static_pad_template (gstelement_class,
411 &gst_qtdemux_sink_template);
412 gst_element_class_add_static_pad_template (gstelement_class,
413 &gst_qtdemux_videosrc_template);
414 gst_element_class_add_static_pad_template (gstelement_class,
415 &gst_qtdemux_audiosrc_template);
416 gst_element_class_add_static_pad_template (gstelement_class,
417 &gst_qtdemux_subsrc_template);
418 gst_element_class_set_static_metadata (gstelement_class, "QuickTime demuxer",
419 "Codec/Demuxer",
420 "Demultiplex a QuickTime file into audio and video streams",
421 "David Schleef <ds@schleef.org>, Wim Taymans <wim@fluendo.com>");
422
423 GST_DEBUG_CATEGORY_INIT (qtdemux_debug, "qtdemux", 0, "qtdemux plugin");
424 gst_riff_init ();
425 }
426
427 static void
gst_qtdemux_init(GstQTDemux * qtdemux)428 gst_qtdemux_init (GstQTDemux * qtdemux)
429 {
430 qtdemux->sinkpad =
431 gst_pad_new_from_static_template (&gst_qtdemux_sink_template, "sink");
432 gst_pad_set_activate_function (qtdemux->sinkpad, qtdemux_sink_activate);
433 gst_pad_set_activatemode_function (qtdemux->sinkpad,
434 qtdemux_sink_activate_mode);
435 gst_pad_set_chain_function (qtdemux->sinkpad, gst_qtdemux_chain);
436 gst_pad_set_event_function (qtdemux->sinkpad, gst_qtdemux_handle_sink_event);
437 gst_pad_set_query_function (qtdemux->sinkpad, gst_qtdemux_handle_sink_query);
438 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), qtdemux->sinkpad);
439
440 qtdemux->adapter = gst_adapter_new ();
441 g_queue_init (&qtdemux->protection_event_queue);
442 qtdemux->flowcombiner = gst_flow_combiner_new ();
443 g_mutex_init (&qtdemux->expose_lock);
444
445 qtdemux->active_streams = g_ptr_array_new_with_free_func
446 ((GDestroyNotify) gst_qtdemux_stream_unref);
447 qtdemux->old_streams = g_ptr_array_new_with_free_func
448 ((GDestroyNotify) gst_qtdemux_stream_unref);
449
450 GST_OBJECT_FLAG_SET (qtdemux, GST_ELEMENT_FLAG_INDEXABLE);
451
452 gst_qtdemux_reset (qtdemux, TRUE);
453 }
454
455 static void
gst_qtdemux_finalize(GObject * object)456 gst_qtdemux_finalize (GObject * object)
457 {
458 GstQTDemux *qtdemux = GST_QTDEMUX (object);
459
460 g_free (qtdemux->redirect_location);
461
462 G_OBJECT_CLASS (parent_class)->finalize (object);
463 }
464
465 static void
gst_qtdemux_dispose(GObject * object)466 gst_qtdemux_dispose (GObject * object)
467 {
468 GstQTDemux *qtdemux = GST_QTDEMUX (object);
469
470 if (qtdemux->adapter) {
471 g_object_unref (G_OBJECT (qtdemux->adapter));
472 qtdemux->adapter = NULL;
473 }
474 gst_tag_list_unref (qtdemux->tag_list);
475 gst_flow_combiner_free (qtdemux->flowcombiner);
476 g_queue_foreach (&qtdemux->protection_event_queue, (GFunc) gst_event_unref,
477 NULL);
478 g_queue_clear (&qtdemux->protection_event_queue);
479
480 g_free (qtdemux->cenc_aux_info_sizes);
481 qtdemux->cenc_aux_info_sizes = NULL;
482 g_mutex_clear (&qtdemux->expose_lock);
483
484 g_ptr_array_free (qtdemux->active_streams, TRUE);
485 g_ptr_array_free (qtdemux->old_streams, TRUE);
486
487 G_OBJECT_CLASS (parent_class)->dispose (object);
488 }
489
490 static void
gst_qtdemux_post_no_playable_stream_error(GstQTDemux * qtdemux)491 gst_qtdemux_post_no_playable_stream_error (GstQTDemux * qtdemux)
492 {
493 if (qtdemux->redirect_location) {
494 GST_ELEMENT_ERROR_WITH_DETAILS (qtdemux, STREAM, DEMUX,
495 (_("This file contains no playable streams.")),
496 ("no known streams found, a redirect message has been posted"),
497 ("redirect-location", G_TYPE_STRING, qtdemux->redirect_location, NULL));
498 } else {
499 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
500 (_("This file contains no playable streams.")),
501 ("no known streams found"));
502 }
503 }
504
505 static GstBuffer *
_gst_buffer_new_wrapped(gpointer mem,gsize size,GFreeFunc free_func)506 _gst_buffer_new_wrapped (gpointer mem, gsize size, GFreeFunc free_func)
507 {
508 return gst_buffer_new_wrapped_full (free_func ? 0 : GST_MEMORY_FLAG_READONLY,
509 mem, size, 0, size, mem, free_func);
510 }
511
512 static GstFlowReturn
gst_qtdemux_pull_atom(GstQTDemux * qtdemux,guint64 offset,guint64 size,GstBuffer ** buf)513 gst_qtdemux_pull_atom (GstQTDemux * qtdemux, guint64 offset, guint64 size,
514 GstBuffer ** buf)
515 {
516 GstFlowReturn flow;
517 GstMapInfo map;
518 gsize bsize;
519
520 if (G_UNLIKELY (size == 0)) {
521 GstFlowReturn ret;
522 GstBuffer *tmp = NULL;
523
524 ret = gst_qtdemux_pull_atom (qtdemux, offset, sizeof (guint32), &tmp);
525 if (ret != GST_FLOW_OK)
526 return ret;
527
528 gst_buffer_map (tmp, &map, GST_MAP_READ);
529 size = QT_UINT32 (map.data);
530 GST_DEBUG_OBJECT (qtdemux, "size 0x%08" G_GINT64_MODIFIER "x", size);
531
532 gst_buffer_unmap (tmp, &map);
533 gst_buffer_unref (tmp);
534 }
535
536 /* Sanity check: catch bogus sizes (fuzzed/broken files) */
537 if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
538 if (qtdemux->state != QTDEMUX_STATE_MOVIE && qtdemux->got_moov) {
539 /* we're pulling header but already got most interesting bits,
540 * so never mind the rest (e.g. tags) (that much) */
541 GST_WARNING_OBJECT (qtdemux, "atom has bogus size %" G_GUINT64_FORMAT,
542 size);
543 return GST_FLOW_EOS;
544 } else {
545 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
546 (_("This file is invalid and cannot be played.")),
547 ("atom has bogus size %" G_GUINT64_FORMAT, size));
548 return GST_FLOW_ERROR;
549 }
550 }
551
552 flow = gst_pad_pull_range (qtdemux->sinkpad, offset, size, buf);
553
554 if (G_UNLIKELY (flow != GST_FLOW_OK))
555 return flow;
556
557 bsize = gst_buffer_get_size (*buf);
558 /* Catch short reads - we don't want any partial atoms */
559 if (G_UNLIKELY (bsize < size)) {
560 GST_WARNING_OBJECT (qtdemux,
561 "short read: %" G_GSIZE_FORMAT " < %" G_GUINT64_FORMAT, bsize, size);
562 gst_buffer_unref (*buf);
563 *buf = NULL;
564 return GST_FLOW_EOS;
565 }
566
567 return flow;
568 }
569
570 #if 1
571 static gboolean
gst_qtdemux_src_convert(GstQTDemux * qtdemux,GstPad * pad,GstFormat src_format,gint64 src_value,GstFormat dest_format,gint64 * dest_value)572 gst_qtdemux_src_convert (GstQTDemux * qtdemux, GstPad * pad,
573 GstFormat src_format, gint64 src_value, GstFormat dest_format,
574 gint64 * dest_value)
575 {
576 gboolean res = TRUE;
577 QtDemuxStream *stream = gst_pad_get_element_private (pad);
578 gint32 index;
579
580 if (stream->subtype != FOURCC_vide) {
581 res = FALSE;
582 goto done;
583 }
584
585 switch (src_format) {
586 case GST_FORMAT_TIME:
587 switch (dest_format) {
588 case GST_FORMAT_BYTES:{
589 index = gst_qtdemux_find_index_linear (qtdemux, stream, src_value);
590 if (-1 == index) {
591 res = FALSE;
592 goto done;
593 }
594
595 *dest_value = stream->samples[index].offset;
596
597 GST_DEBUG_OBJECT (qtdemux, "Format Conversion Time->Offset :%"
598 GST_TIME_FORMAT "->%" G_GUINT64_FORMAT,
599 GST_TIME_ARGS (src_value), *dest_value);
600 break;
601 }
602 default:
603 res = FALSE;
604 break;
605 }
606 break;
607 case GST_FORMAT_BYTES:
608 switch (dest_format) {
609 case GST_FORMAT_TIME:{
610 index =
611 gst_qtdemux_find_index_for_given_media_offset_linear (qtdemux,
612 stream, src_value);
613
614 if (-1 == index) {
615 res = FALSE;
616 goto done;
617 }
618
619 *dest_value =
620 QTSTREAMTIME_TO_GSTTIME (stream,
621 stream->samples[index].timestamp);
622 GST_DEBUG_OBJECT (qtdemux,
623 "Format Conversion Offset->Time :%" G_GUINT64_FORMAT "->%"
624 GST_TIME_FORMAT, src_value, GST_TIME_ARGS (*dest_value));
625 break;
626 }
627 default:
628 res = FALSE;
629 break;
630 }
631 break;
632 default:
633 res = FALSE;
634 break;
635 }
636
637 done:
638 return res;
639 }
640 #endif
641
642 static gboolean
gst_qtdemux_get_duration(GstQTDemux * qtdemux,GstClockTime * duration)643 gst_qtdemux_get_duration (GstQTDemux * qtdemux, GstClockTime * duration)
644 {
645 gboolean res = FALSE;
646
647 *duration = GST_CLOCK_TIME_NONE;
648
649 if (qtdemux->duration != 0 &&
650 qtdemux->duration != G_MAXINT64 && qtdemux->timescale != 0) {
651 *duration = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
652 res = TRUE;
653 } else {
654 *duration = GST_CLOCK_TIME_NONE;
655 }
656
657 return res;
658 }
659
660 static gboolean
gst_qtdemux_handle_src_query(GstPad * pad,GstObject * parent,GstQuery * query)661 gst_qtdemux_handle_src_query (GstPad * pad, GstObject * parent,
662 GstQuery * query)
663 {
664 gboolean res = FALSE;
665 GstQTDemux *qtdemux = GST_QTDEMUX (parent);
666
667 GST_LOG_OBJECT (pad, "%s query", GST_QUERY_TYPE_NAME (query));
668
669 switch (GST_QUERY_TYPE (query)) {
670 case GST_QUERY_POSITION:{
671 GstFormat fmt;
672
673 gst_query_parse_position (query, &fmt, NULL);
674 if (fmt == GST_FORMAT_TIME
675 && GST_CLOCK_TIME_IS_VALID (qtdemux->segment.position)) {
676 gst_query_set_position (query, GST_FORMAT_TIME,
677 qtdemux->segment.position);
678 res = TRUE;
679 }
680 }
681 break;
682 case GST_QUERY_DURATION:{
683 GstFormat fmt;
684
685 gst_query_parse_duration (query, &fmt, NULL);
686 if (fmt == GST_FORMAT_TIME) {
687 /* First try to query upstream */
688 res = gst_pad_query_default (pad, parent, query);
689 if (!res) {
690 GstClockTime duration;
691 if (gst_qtdemux_get_duration (qtdemux, &duration) && duration > 0) {
692 gst_query_set_duration (query, GST_FORMAT_TIME, duration);
693 res = TRUE;
694 }
695 }
696 }
697 break;
698 }
699 case GST_QUERY_CONVERT:{
700 GstFormat src_fmt, dest_fmt;
701 gint64 src_value, dest_value = 0;
702
703 gst_query_parse_convert (query, &src_fmt, &src_value, &dest_fmt, NULL);
704
705 res = gst_qtdemux_src_convert (qtdemux, pad,
706 src_fmt, src_value, dest_fmt, &dest_value);
707 if (res)
708 gst_query_set_convert (query, src_fmt, src_value, dest_fmt, dest_value);
709
710 break;
711 }
712 case GST_QUERY_FORMATS:
713 gst_query_set_formats (query, 2, GST_FORMAT_TIME, GST_FORMAT_BYTES);
714 res = TRUE;
715 break;
716 case GST_QUERY_SEEKING:{
717 GstFormat fmt;
718 gboolean seekable;
719
720 gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
721
722 if (fmt == GST_FORMAT_BYTES) {
723 /* We always refuse BYTES seeks from downstream */
724 break;
725 }
726
727 /* try upstream first */
728 res = gst_pad_query_default (pad, parent, query);
729
730 if (!res) {
731 gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
732 if (fmt == GST_FORMAT_TIME) {
733 GstClockTime duration;
734
735 gst_qtdemux_get_duration (qtdemux, &duration);
736 seekable = TRUE;
737 if (!qtdemux->pullbased) {
738 GstQuery *q;
739
740 /* we might be able with help from upstream */
741 seekable = FALSE;
742 q = gst_query_new_seeking (GST_FORMAT_BYTES);
743 if (gst_pad_peer_query (qtdemux->sinkpad, q)) {
744 gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL);
745 GST_LOG_OBJECT (qtdemux, "upstream BYTE seekable %d", seekable);
746 }
747 gst_query_unref (q);
748 }
749 gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0, duration);
750 res = TRUE;
751 }
752 }
753 break;
754 }
755 case GST_QUERY_SEGMENT:
756 {
757 GstFormat format;
758 gint64 start, stop;
759
760 format = qtdemux->segment.format;
761
762 start =
763 gst_segment_to_stream_time (&qtdemux->segment, format,
764 qtdemux->segment.start);
765 if ((stop = qtdemux->segment.stop) == -1)
766 stop = qtdemux->segment.duration;
767 else
768 stop = gst_segment_to_stream_time (&qtdemux->segment, format, stop);
769
770 gst_query_set_segment (query, qtdemux->segment.rate, format, start, stop);
771 res = TRUE;
772 break;
773 }
774 default:
775 res = gst_pad_query_default (pad, parent, query);
776 break;
777 }
778
779 return res;
780 }
781
782 static void
gst_qtdemux_push_tags(GstQTDemux * qtdemux,QtDemuxStream * stream)783 gst_qtdemux_push_tags (GstQTDemux * qtdemux, QtDemuxStream * stream)
784 {
785 if (G_LIKELY (stream->pad)) {
786 GST_DEBUG_OBJECT (qtdemux, "Checking pad %s:%s for tags",
787 GST_DEBUG_PAD_NAME (stream->pad));
788
789 if (!gst_tag_list_is_empty (stream->stream_tags)) {
790 GST_DEBUG_OBJECT (qtdemux, "Sending tags %" GST_PTR_FORMAT,
791 stream->stream_tags);
792 gst_pad_push_event (stream->pad,
793 gst_event_new_tag (gst_tag_list_ref (stream->stream_tags)));
794 }
795
796 if (G_UNLIKELY (stream->send_global_tags)) {
797 GST_DEBUG_OBJECT (qtdemux, "Sending global tags %" GST_PTR_FORMAT,
798 qtdemux->tag_list);
799 gst_pad_push_event (stream->pad,
800 gst_event_new_tag (gst_tag_list_ref (qtdemux->tag_list)));
801 stream->send_global_tags = FALSE;
802 }
803 }
804 }
805
806 /* push event on all source pads; takes ownership of the event */
807 static void
gst_qtdemux_push_event(GstQTDemux * qtdemux,GstEvent * event)808 gst_qtdemux_push_event (GstQTDemux * qtdemux, GstEvent * event)
809 {
810 gboolean has_valid_stream = FALSE;
811 GstEventType etype = GST_EVENT_TYPE (event);
812 guint i;
813
814 GST_DEBUG_OBJECT (qtdemux, "pushing %s event on all source pads",
815 GST_EVENT_TYPE_NAME (event));
816
817 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
818 GstPad *pad;
819 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
820 GST_DEBUG_OBJECT (qtdemux, "pushing on track-id %u", stream->track_id);
821
822 if ((pad = stream->pad)) {
823 has_valid_stream = TRUE;
824
825 if (etype == GST_EVENT_EOS) {
826 /* let's not send twice */
827 if (stream->sent_eos)
828 continue;
829 stream->sent_eos = TRUE;
830 }
831
832 gst_pad_push_event (pad, gst_event_ref (event));
833 }
834 }
835
836 gst_event_unref (event);
837
838 /* if it is EOS and there are no pads, post an error */
839 if (!has_valid_stream && etype == GST_EVENT_EOS) {
840 gst_qtdemux_post_no_playable_stream_error (qtdemux);
841 }
842 }
843
844 typedef struct
845 {
846 guint64 media_time;
847 } FindData;
848
849 static gint
find_func(QtDemuxSample * s1,gint64 * media_time,gpointer user_data)850 find_func (QtDemuxSample * s1, gint64 * media_time, gpointer user_data)
851 {
852 if ((gint64) s1->timestamp > *media_time)
853 return 1;
854 if ((gint64) s1->timestamp == *media_time)
855 return 0;
856
857 return -1;
858 }
859
860 /* find the index of the sample that includes the data for @media_time using a
861 * binary search. Only to be called in optimized cases of linear search below.
862 *
863 * Returns the index of the sample with the corresponding *DTS*.
864 */
865 static guint32
gst_qtdemux_find_index(GstQTDemux * qtdemux,QtDemuxStream * str,guint64 media_time)866 gst_qtdemux_find_index (GstQTDemux * qtdemux, QtDemuxStream * str,
867 guint64 media_time)
868 {
869 QtDemuxSample *result;
870 guint32 index;
871
872 /* convert media_time to mov format */
873 media_time =
874 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
875
876 result = gst_util_array_binary_search (str->samples, str->stbl_index + 1,
877 sizeof (QtDemuxSample), (GCompareDataFunc) find_func,
878 GST_SEARCH_MODE_BEFORE, &media_time, NULL);
879
880 if (G_LIKELY (result))
881 index = result - str->samples;
882 else
883 index = 0;
884
885 return index;
886 }
887
888
889
890 /* find the index of the sample that includes the data for @media_offset using a
891 * linear search
892 *
893 * Returns the index of the sample.
894 */
895 static guint32
gst_qtdemux_find_index_for_given_media_offset_linear(GstQTDemux * qtdemux,QtDemuxStream * str,gint64 media_offset)896 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
897 QtDemuxStream * str, gint64 media_offset)
898 {
899 QtDemuxSample *result = str->samples;
900 guint32 index = 0;
901
902 if (result == NULL || str->n_samples == 0)
903 return -1;
904
905 if (media_offset == result->offset)
906 return index;
907
908 result++;
909 while (index < str->n_samples - 1) {
910 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
911 goto parse_failed;
912
913 if (media_offset < result->offset)
914 break;
915
916 index++;
917 result++;
918 }
919 return index;
920
921 /* ERRORS */
922 parse_failed:
923 {
924 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
925 return -1;
926 }
927 }
928
929 /* find the index of the sample that includes the data for @media_time using a
930 * linear search, and keeping in mind that not all samples may have been parsed
931 * yet. If possible, it will delegate to binary search.
932 *
933 * Returns the index of the sample.
934 */
935 static guint32
gst_qtdemux_find_index_linear(GstQTDemux * qtdemux,QtDemuxStream * str,GstClockTime media_time)936 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
937 GstClockTime media_time)
938 {
939 guint32 index = 0;
940 guint64 mov_time;
941 QtDemuxSample *sample;
942
943 /* convert media_time to mov format */
944 mov_time =
945 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
946
947 sample = str->samples;
948 if (mov_time == sample->timestamp + sample->pts_offset)
949 return index;
950
951 /* use faster search if requested time in already parsed range */
952 sample = str->samples + str->stbl_index;
953 if (str->stbl_index >= 0 && mov_time <= sample->timestamp) {
954 index = gst_qtdemux_find_index (qtdemux, str, media_time);
955 sample = str->samples + index;
956 } else {
957 while (index < str->n_samples - 1) {
958 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
959 goto parse_failed;
960
961 sample = str->samples + index + 1;
962 if (mov_time < sample->timestamp) {
963 sample = str->samples + index;
964 break;
965 }
966
967 index++;
968 }
969 }
970
971 /* sample->timestamp is now <= media_time, need to find the corresponding
972 * PTS now by looking backwards */
973 while (index > 0 && sample->timestamp + sample->pts_offset > mov_time) {
974 index--;
975 sample = str->samples + index;
976 }
977
978 return index;
979
980 /* ERRORS */
981 parse_failed:
982 {
983 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
984 return -1;
985 }
986 }
987
988 /* find the index of the keyframe needed to decode the sample at @index
989 * of stream @str, or of a subsequent keyframe (depending on @next)
990 *
991 * Returns the index of the keyframe.
992 */
993 static guint32
gst_qtdemux_find_keyframe(GstQTDemux * qtdemux,QtDemuxStream * str,guint32 index,gboolean next)994 gst_qtdemux_find_keyframe (GstQTDemux * qtdemux, QtDemuxStream * str,
995 guint32 index, gboolean next)
996 {
997 guint32 new_index = index;
998
999 if (index >= str->n_samples) {
1000 new_index = str->n_samples;
1001 goto beach;
1002 }
1003
1004 /* all keyframes, return index */
1005 if (str->all_keyframe) {
1006 new_index = index;
1007 goto beach;
1008 }
1009
1010 /* else search until we have a keyframe */
1011 while (new_index < str->n_samples) {
1012 if (next && !qtdemux_parse_samples (qtdemux, str, new_index))
1013 goto parse_failed;
1014
1015 if (str->samples[new_index].keyframe)
1016 break;
1017
1018 if (new_index == 0)
1019 break;
1020
1021 if (next)
1022 new_index++;
1023 else
1024 new_index--;
1025 }
1026
1027 if (new_index == str->n_samples) {
1028 GST_DEBUG_OBJECT (qtdemux, "no next keyframe");
1029 new_index = -1;
1030 }
1031
1032 beach:
1033 GST_DEBUG_OBJECT (qtdemux, "searching for keyframe index %s index %u "
1034 "gave %u", next ? "after" : "before", index, new_index);
1035
1036 return new_index;
1037
1038 /* ERRORS */
1039 parse_failed:
1040 {
1041 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", new_index);
1042 return -1;
1043 }
1044 }
1045
1046 /* find the segment for @time_position for @stream
1047 *
1048 * Returns the index of the segment containing @time_position.
1049 * Returns the last segment and sets the @eos variable to TRUE
1050 * if the time is beyond the end. @eos may be NULL
1051 */
1052 static guint32
gst_qtdemux_find_segment(GstQTDemux * qtdemux,QtDemuxStream * stream,GstClockTime time_position)1053 gst_qtdemux_find_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
1054 GstClockTime time_position)
1055 {
1056 gint i;
1057 guint32 seg_idx;
1058
1059 GST_LOG_OBJECT (stream->pad, "finding segment for %" GST_TIME_FORMAT,
1060 GST_TIME_ARGS (time_position));
1061
1062 seg_idx = -1;
1063 for (i = 0; i < stream->n_segments; i++) {
1064 QtDemuxSegment *segment = &stream->segments[i];
1065
1066 GST_LOG_OBJECT (stream->pad,
1067 "looking at segment %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT,
1068 GST_TIME_ARGS (segment->time), GST_TIME_ARGS (segment->stop_time));
1069
1070 /* For the last segment we include stop_time in the last segment */
1071 if (i < stream->n_segments - 1) {
1072 if (segment->time <= time_position && time_position < segment->stop_time) {
1073 GST_LOG_OBJECT (stream->pad, "segment %d matches", i);
1074 seg_idx = i;
1075 break;
1076 }
1077 } else {
1078 /* Last segment always matches */
1079 seg_idx = i;
1080 break;
1081 }
1082 }
1083 return seg_idx;
1084 }
1085
1086 /* move the stream @str to the sample position @index.
1087 *
1088 * Updates @str->sample_index and marks discontinuity if needed.
1089 */
1090 static void
gst_qtdemux_move_stream(GstQTDemux * qtdemux,QtDemuxStream * str,guint32 index)1091 gst_qtdemux_move_stream (GstQTDemux * qtdemux, QtDemuxStream * str,
1092 guint32 index)
1093 {
1094 /* no change needed */
1095 if (index == str->sample_index)
1096 return;
1097
1098 GST_DEBUG_OBJECT (qtdemux, "moving to sample %u of %u", index,
1099 str->n_samples);
1100
1101 /* position changed, we have a discont */
1102 str->sample_index = index;
1103 str->offset_in_sample = 0;
1104 /* Each time we move in the stream we store the position where we are
1105 * starting from */
1106 str->from_sample = index;
1107 str->discont = TRUE;
1108 }
1109
1110 #ifdef OHOS_OPT_COMPAT
1111 /* ohos.opt.compat.0055 */
gst_qtdemux_get_all_tracks_minimum_duration(GstQTDemux * qtdemux)1112 static gint64 gst_qtdemux_get_all_tracks_minimum_duration(GstQTDemux * qtdemux)
1113 {
1114 guint64 min_duration = G_MAXUINT64;
1115 for (guint i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
1116 QtDemuxStream *str = QTDEMUX_NTH_STREAM (qtdemux, i);
1117 if (str->duration < min_duration) {
1118 min_duration = str->duration;
1119 }
1120 }
1121 return min_duration;
1122 }
1123 #endif
1124
1125 static void
gst_qtdemux_adjust_seek(GstQTDemux * qtdemux,gint64 desired_time,gboolean use_sparse,gboolean next,gint64 * key_time,gint64 * key_offset)1126 gst_qtdemux_adjust_seek (GstQTDemux * qtdemux, gint64 desired_time,
1127 gboolean use_sparse, gboolean next, gint64 * key_time, gint64 * key_offset)
1128 {
1129 guint64 min_offset;
1130 #ifdef OHOS_OPT_COMPAT
1131 /* ohos.opt.compat.0055 */
1132 guint64 max_time = 0;
1133 guint64 min_duration = gst_qtdemux_get_all_tracks_minimum_duration(qtdemux);
1134 #endif
1135 gint64 min_byte_offset = -1;
1136 guint i;
1137
1138 min_offset = desired_time;
1139
1140 /* for each stream, find the index of the sample in the segment
1141 * and move back to the previous keyframe. */
1142 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
1143 QtDemuxStream *str;
1144 guint32 index, kindex;
1145 guint32 seg_idx;
1146 GstClockTime media_start;
1147 GstClockTime media_time;
1148 GstClockTime seg_time;
1149 QtDemuxSegment *seg;
1150 gboolean empty_segment = FALSE;
1151
1152 str = QTDEMUX_NTH_STREAM (qtdemux, i);
1153
1154 if (CUR_STREAM (str)->sparse && !use_sparse)
1155 continue;
1156
1157 seg_idx = gst_qtdemux_find_segment (qtdemux, str, desired_time);
1158 GST_DEBUG_OBJECT (qtdemux, "align segment %d", seg_idx);
1159
1160 /* get segment and time in the segment */
1161 seg = &str->segments[seg_idx];
1162 seg_time = (desired_time - seg->time) * seg->rate;
1163
1164 while (QTSEGMENT_IS_EMPTY (seg)) {
1165 seg_time = 0;
1166 empty_segment = TRUE;
1167 GST_DEBUG_OBJECT (str->pad, "Segment %d is empty, moving to next one",
1168 seg_idx);
1169 seg_idx++;
1170 if (seg_idx == str->n_segments)
1171 break;
1172 seg = &str->segments[seg_idx];
1173 }
1174
1175 if (seg_idx == str->n_segments) {
1176 /* FIXME track shouldn't have the last segment as empty, but if it
1177 * happens we better handle it */
1178 continue;
1179 }
1180
1181 /* get the media time in the segment */
1182 media_start = seg->media_start + seg_time;
1183
1184 /* get the index of the sample with media time */
1185 index = gst_qtdemux_find_index_linear (qtdemux, str, media_start);
1186 GST_DEBUG_OBJECT (qtdemux, "sample for %" GST_TIME_FORMAT " at %u"
1187 " at offset %" G_GUINT64_FORMAT " (empty segment: %d)",
1188 GST_TIME_ARGS (media_start), index, str->samples[index].offset,
1189 empty_segment);
1190
1191 /* shift to next frame if we are looking for next keyframe */
1192 if (next && QTSAMPLE_PTS_NO_CSLG (str, &str->samples[index]) < media_start
1193 && index < str->stbl_index)
1194 index++;
1195
1196 if (!empty_segment) {
1197 /* find previous keyframe */
1198 kindex = gst_qtdemux_find_keyframe (qtdemux, str, index, next);
1199
1200 /* we will settle for one before if none found after */
1201 if (next && kindex == -1)
1202 kindex = gst_qtdemux_find_keyframe (qtdemux, str, index, FALSE);
1203
1204 /* Update the requested time whenever a keyframe was found, to make it
1205 * accurate and avoid having the first buffer fall outside of the segment
1206 */
1207 if (kindex != -1) {
1208 index = kindex;
1209
1210 /* get timestamp of keyframe */
1211 media_time = QTSAMPLE_PTS_NO_CSLG (str, &str->samples[kindex]);
1212 GST_DEBUG_OBJECT (qtdemux,
1213 "keyframe at %u with time %" GST_TIME_FORMAT " at offset %"
1214 G_GUINT64_FORMAT, kindex, GST_TIME_ARGS (media_time),
1215 str->samples[kindex].offset);
1216 #ifdef OHOS_OPT_COMPAT
1217 /**
1218 * ohos.opt.compat.0055
1219 * when video stream and audio stream are different duration(edge. video duration is 01:50,
1220 * audio duration is 0:35), it will lead seek done offset has a huge gap with seek offset.
1221 * Thus, return a timestamp closest to the seek offset.
1222 */
1223 GST_DEBUG_OBJECT (qtdemux,
1224 "min_duration %" GST_TIME_FORMAT " desired_time %" GST_TIME_FORMAT " next %d max_time %" GST_TIME_FORMAT "",
1225 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME(str, min_duration)),
1226 GST_TIME_ARGS (desired_time), next, GST_TIME_ARGS (max_time));
1227 /**
1228 * diffent: compared with the original logic, forward seek may miss video key frames
1229 * forward seek, find all tracks the biggest key frames time
1230 */
1231 if ((min_duration < desired_time) && (!next && (max_time > media_time))) {
1232 continue;
1233 }
1234 max_time = media_time;
1235 #endif
1236 /* keyframes in the segment get a chance to change the
1237 * desired_offset. keyframes out of the segment are
1238 * ignored. */
1239 if (media_time >= seg->media_start) {
1240 GstClockTime seg_time;
1241
1242 /* this keyframe is inside the segment, convert back to
1243 * segment time */
1244 seg_time = (media_time - seg->media_start) + seg->time;
1245 if ((!next && (seg_time < min_offset)) ||
1246 (next && (seg_time > min_offset)))
1247 min_offset = seg_time;
1248 }
1249 }
1250 }
1251
1252 if (min_byte_offset < 0 || str->samples[index].offset < min_byte_offset)
1253 min_byte_offset = str->samples[index].offset;
1254 }
1255
1256 if (key_time)
1257 *key_time = min_offset;
1258 if (key_offset)
1259 *key_offset = min_byte_offset;
1260 }
1261
1262 static gboolean
gst_qtdemux_convert_seek(GstPad * pad,GstFormat * format,GstSeekType cur_type,gint64 * cur,GstSeekType stop_type,gint64 * stop)1263 gst_qtdemux_convert_seek (GstPad * pad, GstFormat * format,
1264 GstSeekType cur_type, gint64 * cur, GstSeekType stop_type, gint64 * stop)
1265 {
1266 gboolean res;
1267
1268 g_return_val_if_fail (format != NULL, FALSE);
1269 g_return_val_if_fail (cur != NULL, FALSE);
1270 g_return_val_if_fail (stop != NULL, FALSE);
1271
1272 if (*format == GST_FORMAT_TIME)
1273 return TRUE;
1274
1275 res = TRUE;
1276 if (cur_type != GST_SEEK_TYPE_NONE)
1277 res = gst_pad_query_convert (pad, *format, *cur, GST_FORMAT_TIME, cur);
1278 if (res && stop_type != GST_SEEK_TYPE_NONE)
1279 res = gst_pad_query_convert (pad, *format, *stop, GST_FORMAT_TIME, stop);
1280
1281 if (res)
1282 *format = GST_FORMAT_TIME;
1283
1284 return res;
1285 }
1286
1287 /* perform seek in push based mode:
1288 find BYTE position to move to based on time and delegate to upstream
1289 */
1290 static gboolean
gst_qtdemux_do_push_seek(GstQTDemux * qtdemux,GstPad * pad,GstEvent * event)1291 gst_qtdemux_do_push_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1292 {
1293 gdouble rate;
1294 GstFormat format;
1295 GstSeekFlags flags;
1296 GstSeekType cur_type, stop_type;
1297 gint64 cur, stop, key_cur;
1298 gboolean res;
1299 gint64 byte_cur;
1300 gint64 original_stop;
1301 guint32 seqnum;
1302
1303 GST_DEBUG_OBJECT (qtdemux, "doing push-based seek");
1304
1305 gst_event_parse_seek (event, &rate, &format, &flags,
1306 &cur_type, &cur, &stop_type, &stop);
1307 seqnum = gst_event_get_seqnum (event);
1308
1309 /* Directly send the instant-rate-change event here before taking the
1310 * stream-lock so that it can be applied as soon as possible */
1311 if (flags & GST_SEEK_FLAG_INSTANT_RATE_CHANGE) {
1312 GstEvent *ev;
1313
1314 /* instant rate change only supported if direction does not change. All
1315 * other requirements are already checked before creating the seek event
1316 * but let's double-check here to be sure */
1317 if ((qtdemux->segment.rate > 0 && rate < 0) ||
1318 (qtdemux->segment.rate < 0 && rate > 0) ||
1319 cur_type != GST_SEEK_TYPE_NONE ||
1320 stop_type != GST_SEEK_TYPE_NONE || (flags & GST_SEEK_FLAG_FLUSH)) {
1321 GST_ERROR_OBJECT (qtdemux,
1322 "Instant rate change seeks only supported in the "
1323 "same direction, without flushing and position change");
1324 return FALSE;
1325 }
1326
1327 ev = gst_event_new_instant_rate_change (rate / qtdemux->segment.rate,
1328 (GstSegmentFlags) flags);
1329 gst_event_set_seqnum (ev, seqnum);
1330 gst_qtdemux_push_event (qtdemux, ev);
1331 return TRUE;
1332 }
1333
1334 /* only forward streaming and seeking is possible */
1335 if (rate <= 0)
1336 goto unsupported_seek;
1337
1338 /* convert to TIME if needed and possible */
1339 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1340 stop_type, &stop))
1341 goto no_format;
1342
1343 /* Upstream seek in bytes will have undefined stop, but qtdemux stores
1344 * the original stop position to use when upstream pushes the new segment
1345 * for this seek */
1346 original_stop = stop;
1347 stop = -1;
1348
1349 /* find reasonable corresponding BYTE position,
1350 * also try to mind about keyframes, since we can not go back a bit for them
1351 * later on */
1352 /* determining @next here based on SNAP_BEFORE/SNAP_AFTER should
1353 * mostly just work, but let's not yet boldly go there ... */
1354 gst_qtdemux_adjust_seek (qtdemux, cur, FALSE, FALSE, &key_cur, &byte_cur);
1355
1356 if (byte_cur == -1)
1357 goto abort_seek;
1358
1359 GST_DEBUG_OBJECT (qtdemux, "Pushing BYTE seek rate %g, "
1360 "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, byte_cur,
1361 stop);
1362
1363 GST_OBJECT_LOCK (qtdemux);
1364 qtdemux->seek_offset = byte_cur;
1365 if (!(flags & GST_SEEK_FLAG_KEY_UNIT)) {
1366 qtdemux->push_seek_start = cur;
1367 } else {
1368 qtdemux->push_seek_start = key_cur;
1369 }
1370
1371 if (stop_type == GST_SEEK_TYPE_NONE) {
1372 qtdemux->push_seek_stop = qtdemux->segment.stop;
1373 } else {
1374 qtdemux->push_seek_stop = original_stop;
1375 }
1376 GST_OBJECT_UNLOCK (qtdemux);
1377
1378 qtdemux->segment_seqnum = seqnum;
1379 /* BYTE seek event */
1380 event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type, byte_cur,
1381 stop_type, stop);
1382 gst_event_set_seqnum (event, seqnum);
1383 res = gst_pad_push_event (qtdemux->sinkpad, event);
1384
1385 return res;
1386
1387 /* ERRORS */
1388 abort_seek:
1389 {
1390 GST_DEBUG_OBJECT (qtdemux, "could not determine byte position to seek to, "
1391 "seek aborted.");
1392 return FALSE;
1393 }
1394 unsupported_seek:
1395 {
1396 GST_DEBUG_OBJECT (qtdemux, "unsupported seek, seek aborted.");
1397 return FALSE;
1398 }
1399 no_format:
1400 {
1401 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1402 return FALSE;
1403 }
1404 }
1405
1406 /* perform the seek.
1407 *
1408 * We set all segment_indexes in the streams to unknown and
1409 * adjust the time_position to the desired position. this is enough
1410 * to trigger a segment switch in the streaming thread to start
1411 * streaming from the desired position.
1412 *
1413 * Keyframe seeking is a little more complicated when dealing with
1414 * segments. Ideally we want to move to the previous keyframe in
1415 * the segment but there might not be a keyframe in the segment. In
1416 * fact, none of the segments could contain a keyframe. We take a
1417 * practical approach: seek to the previous keyframe in the segment,
1418 * if there is none, seek to the beginning of the segment.
1419 *
1420 * Called with STREAM_LOCK
1421 */
1422 static gboolean
gst_qtdemux_perform_seek(GstQTDemux * qtdemux,GstSegment * segment,guint32 seqnum,GstSeekFlags flags)1423 gst_qtdemux_perform_seek (GstQTDemux * qtdemux, GstSegment * segment,
1424 guint32 seqnum, GstSeekFlags flags)
1425 {
1426 gint64 desired_offset;
1427 guint i;
1428
1429 desired_offset = segment->position;
1430
1431 GST_DEBUG_OBJECT (qtdemux, "seeking to %" GST_TIME_FORMAT,
1432 GST_TIME_ARGS (desired_offset));
1433
1434 /* may not have enough fragmented info to do this adjustment,
1435 * and we can't scan (and probably should not) at this time with
1436 * possibly flushing upstream */
1437 if ((flags & GST_SEEK_FLAG_KEY_UNIT) && !qtdemux->fragmented) {
1438 gint64 min_offset;
1439 gboolean next, before, after;
1440
1441 before = ! !(flags & GST_SEEK_FLAG_SNAP_BEFORE);
1442 after = ! !(flags & GST_SEEK_FLAG_SNAP_AFTER);
1443 next = after && !before;
1444 if (segment->rate < 0)
1445 next = !next;
1446
1447 gst_qtdemux_adjust_seek (qtdemux, desired_offset, TRUE, next, &min_offset,
1448 NULL);
1449 GST_DEBUG_OBJECT (qtdemux, "keyframe seek, align to %"
1450 GST_TIME_FORMAT, GST_TIME_ARGS (min_offset));
1451 desired_offset = min_offset;
1452 }
1453
1454 /* and set all streams to the final position */
1455 GST_OBJECT_LOCK (qtdemux);
1456 gst_flow_combiner_reset (qtdemux->flowcombiner);
1457 GST_OBJECT_UNLOCK (qtdemux);
1458 qtdemux->segment_seqnum = seqnum;
1459 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
1460 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
1461
1462 stream->time_position = desired_offset;
1463 stream->accumulated_base = 0;
1464 stream->sample_index = -1;
1465 stream->offset_in_sample = 0;
1466 stream->segment_index = -1;
1467 stream->sent_eos = FALSE;
1468 stream->last_keyframe_dts = GST_CLOCK_TIME_NONE;
1469
1470 if (segment->flags & GST_SEEK_FLAG_FLUSH)
1471 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
1472 }
1473 segment->position = desired_offset;
1474 if (segment->rate >= 0) {
1475 segment->start = desired_offset;
1476 /* We need to update time as we update start in that direction */
1477 segment->time = desired_offset;
1478
1479 /* we stop at the end */
1480 if (segment->stop == -1)
1481 segment->stop = segment->duration;
1482 } else {
1483 segment->stop = desired_offset;
1484 }
1485
1486 if (qtdemux->fragmented)
1487 qtdemux->fragmented_seek_pending = TRUE;
1488
1489 return TRUE;
1490 }
1491
1492 /* do a seek in pull based mode */
1493 static gboolean
gst_qtdemux_do_seek(GstQTDemux * qtdemux,GstPad * pad,GstEvent * event)1494 gst_qtdemux_do_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1495 {
1496 gdouble rate = 1.0;
1497 GstFormat format;
1498 GstSeekFlags flags;
1499 GstSeekType cur_type, stop_type;
1500 gint64 cur, stop;
1501 gboolean flush, instant_rate_change;
1502 gboolean update;
1503 GstSegment seeksegment;
1504 guint32 seqnum = GST_SEQNUM_INVALID;
1505 GstEvent *flush_event;
1506 gboolean ret;
1507
1508 GST_DEBUG_OBJECT (qtdemux, "doing seek with event");
1509
1510 gst_event_parse_seek (event, &rate, &format, &flags,
1511 &cur_type, &cur, &stop_type, &stop);
1512 seqnum = gst_event_get_seqnum (event);
1513
1514 /* we have to have a format as the segment format. Try to convert
1515 * if not. */
1516 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1517 stop_type, &stop))
1518 goto no_format;
1519
1520 GST_DEBUG_OBJECT (qtdemux, "seek format %s", gst_format_get_name (format));
1521
1522 flush = ! !(flags & GST_SEEK_FLAG_FLUSH);
1523 instant_rate_change = ! !(flags & GST_SEEK_FLAG_INSTANT_RATE_CHANGE);
1524
1525 /* Directly send the instant-rate-change event here before taking the
1526 * stream-lock so that it can be applied as soon as possible */
1527 if (instant_rate_change) {
1528 GstEvent *ev;
1529
1530 /* instant rate change only supported if direction does not change. All
1531 * other requirements are already checked before creating the seek event
1532 * but let's double-check here to be sure */
1533 if ((qtdemux->segment.rate > 0 && rate < 0) ||
1534 (qtdemux->segment.rate < 0 && rate > 0) ||
1535 cur_type != GST_SEEK_TYPE_NONE ||
1536 stop_type != GST_SEEK_TYPE_NONE || flush) {
1537 GST_ERROR_OBJECT (qtdemux,
1538 "Instant rate change seeks only supported in the "
1539 "same direction, without flushing and position change");
1540 return FALSE;
1541 }
1542
1543 ev = gst_event_new_instant_rate_change (rate / qtdemux->segment.rate,
1544 (GstSegmentFlags) flags);
1545 gst_event_set_seqnum (ev, seqnum);
1546 gst_qtdemux_push_event (qtdemux, ev);
1547 return TRUE;
1548 }
1549
1550 /* stop streaming, either by flushing or by pausing the task */
1551 if (flush) {
1552 flush_event = gst_event_new_flush_start ();
1553 if (seqnum != GST_SEQNUM_INVALID)
1554 gst_event_set_seqnum (flush_event, seqnum);
1555 /* unlock upstream pull_range */
1556 gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event));
1557 /* make sure out loop function exits */
1558 gst_qtdemux_push_event (qtdemux, flush_event);
1559 } else {
1560 /* non flushing seek, pause the task */
1561 gst_pad_pause_task (qtdemux->sinkpad);
1562 }
1563
1564 /* wait for streaming to finish */
1565 GST_PAD_STREAM_LOCK (qtdemux->sinkpad);
1566
1567 /* copy segment, we need this because we still need the old
1568 * segment when we close the current segment. */
1569 memcpy (&seeksegment, &qtdemux->segment, sizeof (GstSegment));
1570
1571 /* configure the segment with the seek variables */
1572 GST_DEBUG_OBJECT (qtdemux, "configuring seek");
1573 if (!gst_segment_do_seek (&seeksegment, rate, format, flags,
1574 cur_type, cur, stop_type, stop, &update)) {
1575 ret = FALSE;
1576 GST_ERROR_OBJECT (qtdemux, "inconsistent seek values, doing nothing");
1577 } else {
1578 /* now do the seek */
1579 ret = gst_qtdemux_perform_seek (qtdemux, &seeksegment, seqnum, flags);
1580 }
1581
1582 /* prepare for streaming again */
1583 if (flush) {
1584 flush_event = gst_event_new_flush_stop (TRUE);
1585 if (seqnum != GST_SEQNUM_INVALID)
1586 gst_event_set_seqnum (flush_event, seqnum);
1587
1588 gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event));
1589 gst_qtdemux_push_event (qtdemux, flush_event);
1590 }
1591
1592 /* commit the new segment */
1593 memcpy (&qtdemux->segment, &seeksegment, sizeof (GstSegment));
1594
1595 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
1596 GstMessage *msg = gst_message_new_segment_start (GST_OBJECT_CAST (qtdemux),
1597 qtdemux->segment.format, qtdemux->segment.position);
1598 if (seqnum != GST_SEQNUM_INVALID)
1599 gst_message_set_seqnum (msg, seqnum);
1600 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
1601 }
1602
1603 /* restart streaming, NEWSEGMENT will be sent from the streaming thread. */
1604 gst_pad_start_task (qtdemux->sinkpad, (GstTaskFunction) gst_qtdemux_loop,
1605 qtdemux->sinkpad, NULL);
1606
1607 GST_PAD_STREAM_UNLOCK (qtdemux->sinkpad);
1608
1609 return ret;
1610
1611 /* ERRORS */
1612 no_format:
1613 {
1614 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1615 return FALSE;
1616 }
1617 }
1618
1619 static gboolean
qtdemux_ensure_index(GstQTDemux * qtdemux)1620 qtdemux_ensure_index (GstQTDemux * qtdemux)
1621 {
1622 guint i;
1623
1624 GST_DEBUG_OBJECT (qtdemux, "collecting all metadata for all streams");
1625
1626 /* Build complete index */
1627 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
1628 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
1629
1630 if (!qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
1631 GST_LOG_OBJECT (qtdemux,
1632 "Building complete index of track-id %u for seeking failed!",
1633 stream->track_id);
1634 return FALSE;
1635 }
1636 }
1637
1638 return TRUE;
1639 }
1640
1641 static gboolean
gst_qtdemux_handle_src_event(GstPad * pad,GstObject * parent,GstEvent * event)1642 gst_qtdemux_handle_src_event (GstPad * pad, GstObject * parent,
1643 GstEvent * event)
1644 {
1645 gboolean res = TRUE;
1646 GstQTDemux *qtdemux = GST_QTDEMUX (parent);
1647
1648 switch (GST_EVENT_TYPE (event)) {
1649 case GST_EVENT_RECONFIGURE:
1650 GST_OBJECT_LOCK (qtdemux);
1651 gst_flow_combiner_reset (qtdemux->flowcombiner);
1652 GST_OBJECT_UNLOCK (qtdemux);
1653 res = gst_pad_event_default (pad, parent, event);
1654 break;
1655 case GST_EVENT_SEEK:
1656 {
1657 GstSeekFlags flags = 0;
1658 GstFormat seek_format;
1659 gboolean instant_rate_change;
1660
1661 #ifndef GST_DISABLE_GST_DEBUG
1662 GstClockTime ts = gst_util_get_timestamp ();
1663 #endif
1664 guint32 seqnum = gst_event_get_seqnum (event);
1665
1666 qtdemux->received_seek = TRUE;
1667
1668 gst_event_parse_seek (event, NULL, &seek_format, &flags, NULL, NULL, NULL,
1669 NULL);
1670 instant_rate_change = ! !(flags & GST_SEEK_FLAG_INSTANT_RATE_CHANGE);
1671
1672 if (seqnum == qtdemux->segment_seqnum) {
1673 GST_LOG_OBJECT (pad,
1674 "Drop duplicated SEEK event seqnum %" G_GUINT32_FORMAT, seqnum);
1675 gst_event_unref (event);
1676 return TRUE;
1677 }
1678
1679 if (qtdemux->upstream_format_is_time && qtdemux->fragmented) {
1680 /* seek should be handled by upstream, we might need to re-download fragments */
1681 GST_DEBUG_OBJECT (qtdemux,
1682 "let upstream handle seek for fragmented playback");
1683 goto upstream;
1684 }
1685
1686 if (seek_format == GST_FORMAT_BYTES) {
1687 GST_DEBUG_OBJECT (pad, "Rejecting seek request in bytes format");
1688 gst_event_unref (event);
1689 return FALSE;
1690 }
1691
1692 gst_event_parse_seek_trickmode_interval (event,
1693 &qtdemux->trickmode_interval);
1694
1695 /* Build complete index for seeking;
1696 * if not a fragmented file at least and we're really doing a seek,
1697 * not just an instant-rate-change */
1698 if (!qtdemux->fragmented && !instant_rate_change) {
1699 if (!qtdemux_ensure_index (qtdemux))
1700 goto index_failed;
1701 }
1702 #ifndef GST_DISABLE_GST_DEBUG
1703 ts = gst_util_get_timestamp () - ts;
1704 GST_INFO_OBJECT (qtdemux,
1705 "Time taken to parse index %" GST_TIME_FORMAT, GST_TIME_ARGS (ts));
1706 #endif
1707 if (qtdemux->pullbased) {
1708 res = gst_qtdemux_do_seek (qtdemux, pad, event);
1709 } else if (gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (event))) {
1710 GST_DEBUG_OBJECT (qtdemux, "Upstream successfully seeked");
1711 res = TRUE;
1712 } else if (qtdemux->state == QTDEMUX_STATE_MOVIE
1713 && QTDEMUX_N_STREAMS (qtdemux)
1714 && !qtdemux->fragmented) {
1715 res = gst_qtdemux_do_push_seek (qtdemux, pad, event);
1716 } else {
1717 GST_DEBUG_OBJECT (qtdemux,
1718 "ignoring seek in push mode in current state");
1719 res = FALSE;
1720 }
1721 gst_event_unref (event);
1722 }
1723 break;
1724 default:
1725 upstream:
1726 res = gst_pad_event_default (pad, parent, event);
1727 break;
1728 }
1729
1730 done:
1731 return res;
1732
1733 /* ERRORS */
1734 index_failed:
1735 {
1736 GST_ERROR_OBJECT (qtdemux, "Index failed");
1737 gst_event_unref (event);
1738 res = FALSE;
1739 goto done;
1740 }
1741 }
1742
1743 /* Find, for each track, the first sample in coding order that has a file offset >= @byte_pos.
1744 *
1745 * If @fw is false, the coding order is explored backwards.
1746 *
1747 * If @set is true, each stream will be moved to its matched sample, or EOS if no matching
1748 * sample is found for that track.
1749 *
1750 * The stream and sample index of the sample with the minimum offset in the direction explored
1751 * (see @fw) is returned in the output parameters @_stream and @_index respectively.
1752 *
1753 * @_time is set to the QTSAMPLE_PTS of the matched sample with the minimum QTSAMPLE_PTS in the
1754 * direction explored, which may not always match the QTSAMPLE_PTS of the sample returned in
1755 * @_stream and @_index. */
1756 static void
gst_qtdemux_find_sample(GstQTDemux * qtdemux,gint64 byte_pos,gboolean fw,gboolean set,QtDemuxStream ** _stream,gint * _index,gint64 * _time)1757 gst_qtdemux_find_sample (GstQTDemux * qtdemux, gint64 byte_pos, gboolean fw,
1758 gboolean set, QtDemuxStream ** _stream, gint * _index, gint64 * _time)
1759 {
1760 gint i, index;
1761 gint64 time, min_time;
1762 QtDemuxStream *stream;
1763 gint iter;
1764
1765 min_time = -1;
1766 stream = NULL;
1767 index = -1;
1768
1769 for (iter = 0; iter < QTDEMUX_N_STREAMS (qtdemux); iter++) {
1770 QtDemuxStream *str;
1771 gint inc;
1772 gboolean set_sample;
1773
1774 str = QTDEMUX_NTH_STREAM (qtdemux, iter);
1775 set_sample = !set;
1776
1777 if (fw) {
1778 i = 0;
1779 inc = 1;
1780 } else {
1781 i = str->n_samples - 1;
1782 inc = -1;
1783 }
1784
1785 for (; (i >= 0) && (i < str->n_samples); i += inc) {
1786 if (str->samples[i].size == 0)
1787 continue;
1788
1789 if (fw && (str->samples[i].offset < byte_pos))
1790 continue;
1791
1792 if (!fw && (str->samples[i].offset + str->samples[i].size > byte_pos))
1793 continue;
1794
1795 /* move stream to first available sample */
1796 if (set) {
1797 gst_qtdemux_move_stream (qtdemux, str, i);
1798 set_sample = TRUE;
1799 }
1800
1801 /* avoid index from sparse streams since they might be far away */
1802 if (!CUR_STREAM (str)->sparse) {
1803 /* determine min/max time */
1804 time = QTSAMPLE_PTS (str, &str->samples[i]);
1805 if (min_time == -1 || (!fw && time > min_time) ||
1806 (fw && time < min_time)) {
1807 min_time = time;
1808 }
1809
1810 /* determine stream with leading sample, to get its position */
1811 if (!stream ||
1812 (fw && (str->samples[i].offset < stream->samples[index].offset)) ||
1813 (!fw && (str->samples[i].offset > stream->samples[index].offset))) {
1814 stream = str;
1815 index = i;
1816 }
1817 }
1818 break;
1819 }
1820
1821 /* no sample for this stream, mark eos */
1822 if (!set_sample)
1823 gst_qtdemux_move_stream (qtdemux, str, str->n_samples);
1824 }
1825
1826 if (_time)
1827 *_time = min_time;
1828 if (_stream)
1829 *_stream = stream;
1830 if (_index)
1831 *_index = index;
1832 }
1833
1834 /* Copied from mpegtsbase code */
1835 /* FIXME: replace this function when we add new util function for stream-id creation */
1836 static gchar *
_get_upstream_id(GstQTDemux * demux)1837 _get_upstream_id (GstQTDemux * demux)
1838 {
1839 gchar *upstream_id = gst_pad_get_stream_id (demux->sinkpad);
1840
1841 if (!upstream_id) {
1842 /* Try to create one from the upstream URI, else use a randome number */
1843 GstQuery *query;
1844 gchar *uri = NULL;
1845
1846 /* Try to generate one from the URI query and
1847 * if it fails take a random number instead */
1848 query = gst_query_new_uri ();
1849 if (gst_element_query (GST_ELEMENT_CAST (demux), query)) {
1850 gst_query_parse_uri (query, &uri);
1851 }
1852
1853 if (uri) {
1854 GChecksum *cs;
1855
1856 /* And then generate an SHA256 sum of the URI */
1857 cs = g_checksum_new (G_CHECKSUM_SHA256);
1858 g_checksum_update (cs, (const guchar *) uri, strlen (uri));
1859 g_free (uri);
1860 upstream_id = g_strdup (g_checksum_get_string (cs));
1861 g_checksum_free (cs);
1862 } else {
1863 /* Just get some random number if the URI query fails */
1864 GST_FIXME_OBJECT (demux, "Creating random stream-id, consider "
1865 "implementing a deterministic way of creating a stream-id");
1866 upstream_id =
1867 g_strdup_printf ("%08x%08x%08x%08x", g_random_int (), g_random_int (),
1868 g_random_int (), g_random_int ());
1869 }
1870
1871 gst_query_unref (query);
1872 }
1873 return upstream_id;
1874 }
1875
1876 static QtDemuxStream *
_create_stream(GstQTDemux * demux,guint32 track_id)1877 _create_stream (GstQTDemux * demux, guint32 track_id)
1878 {
1879 QtDemuxStream *stream;
1880 gchar *upstream_id;
1881
1882 stream = g_new0 (QtDemuxStream, 1);
1883 stream->demux = demux;
1884 stream->track_id = track_id;
1885 upstream_id = _get_upstream_id (demux);
1886 stream->stream_id = g_strdup_printf ("%s/%03u", upstream_id, track_id);
1887 g_free (upstream_id);
1888 /* new streams always need a discont */
1889 stream->discont = TRUE;
1890 /* we enable clipping for raw audio/video streams */
1891 stream->need_clip = FALSE;
1892 stream->process_func = NULL;
1893 stream->segment_index = -1;
1894 stream->time_position = 0;
1895 stream->sample_index = -1;
1896 stream->offset_in_sample = 0;
1897 stream->new_stream = TRUE;
1898 stream->multiview_mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
1899 stream->multiview_flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
1900 stream->protected = FALSE;
1901 stream->protection_scheme_type = 0;
1902 stream->protection_scheme_version = 0;
1903 stream->protection_scheme_info = NULL;
1904 stream->n_samples_moof = 0;
1905 stream->duration_moof = 0;
1906 stream->duration_last_moof = 0;
1907 stream->alignment = 1;
1908 stream->stream_tags = gst_tag_list_new_empty ();
1909 gst_tag_list_set_scope (stream->stream_tags, GST_TAG_SCOPE_STREAM);
1910 g_queue_init (&stream->protection_scheme_event_queue);
1911 stream->ref_count = 1;
1912 /* consistent default for push based mode */
1913 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
1914 #ifdef OHOS_OPT_PERFORMANCE // ohos.opt.performance.0001: demux push first audio/video frame
1915 stream->has_push_first_frame = FALSE;
1916 #endif
1917 return stream;
1918 }
1919
1920 static gboolean
gst_qtdemux_setcaps(GstQTDemux * demux,GstCaps * caps)1921 gst_qtdemux_setcaps (GstQTDemux * demux, GstCaps * caps)
1922 {
1923 GstStructure *structure;
1924 const gchar *variant;
1925 const GstCaps *mediacaps = NULL;
1926
1927 GST_DEBUG_OBJECT (demux, "Sink set caps: %" GST_PTR_FORMAT, caps);
1928
1929 structure = gst_caps_get_structure (caps, 0);
1930 variant = gst_structure_get_string (structure, "variant");
1931
1932 if (variant && strcmp (variant, "mss-fragmented") == 0) {
1933 QtDemuxStream *stream;
1934 const GValue *value;
1935
1936 demux->fragmented = TRUE;
1937 demux->mss_mode = TRUE;
1938
1939 if (QTDEMUX_N_STREAMS (demux) > 1) {
1940 /* can't do this, we can only renegotiate for another mss format */
1941 return FALSE;
1942 }
1943
1944 value = gst_structure_get_value (structure, "media-caps");
1945 /* create stream */
1946 if (value) {
1947 const GValue *timescale_v;
1948
1949 /* TODO update when stream changes during playback */
1950
1951 if (QTDEMUX_N_STREAMS (demux) == 0) {
1952 stream = _create_stream (demux, 1);
1953 g_ptr_array_add (demux->active_streams, stream);
1954 /* mss has no stsd/stsd entry, use id 0 as default */
1955 stream->stsd_entries_length = 1;
1956 stream->stsd_sample_description_id = stream->cur_stsd_entry_index = 0;
1957 stream->stsd_entries = g_new0 (QtDemuxStreamStsdEntry, 1);
1958 } else {
1959 stream = QTDEMUX_NTH_STREAM (demux, 0);
1960 }
1961
1962 timescale_v = gst_structure_get_value (structure, "timescale");
1963 if (timescale_v) {
1964 stream->timescale = g_value_get_uint64 (timescale_v);
1965 } else {
1966 /* default mss timescale */
1967 stream->timescale = 10000000;
1968 }
1969 demux->timescale = stream->timescale;
1970
1971 mediacaps = gst_value_get_caps (value);
1972 if (!CUR_STREAM (stream)->caps
1973 || !gst_caps_is_equal_fixed (mediacaps, CUR_STREAM (stream)->caps)) {
1974 GST_DEBUG_OBJECT (demux, "We have a new caps %" GST_PTR_FORMAT,
1975 mediacaps);
1976 stream->new_caps = TRUE;
1977 }
1978 gst_caps_replace (&CUR_STREAM (stream)->caps, (GstCaps *) mediacaps);
1979 structure = gst_caps_get_structure (mediacaps, 0);
1980 if (g_str_has_prefix (gst_structure_get_name (structure), "video")) {
1981 stream->subtype = FOURCC_vide;
1982
1983 gst_structure_get_int (structure, "width", &CUR_STREAM (stream)->width);
1984 gst_structure_get_int (structure, "height",
1985 &CUR_STREAM (stream)->height);
1986 gst_structure_get_fraction (structure, "framerate",
1987 &CUR_STREAM (stream)->fps_n, &CUR_STREAM (stream)->fps_d);
1988 } else if (g_str_has_prefix (gst_structure_get_name (structure), "audio")) {
1989 gint rate = 0;
1990 stream->subtype = FOURCC_soun;
1991 gst_structure_get_int (structure, "channels",
1992 &CUR_STREAM (stream)->n_channels);
1993 gst_structure_get_int (structure, "rate", &rate);
1994 CUR_STREAM (stream)->rate = rate;
1995 } else if (gst_structure_has_name (structure, "application/x-cenc")) {
1996 if (gst_structure_has_field (structure, "original-media-type")) {
1997 const gchar *media_type =
1998 gst_structure_get_string (structure, "original-media-type");
1999 if (g_str_has_prefix (media_type, "video")) {
2000 stream->subtype = FOURCC_vide;
2001 } else if (g_str_has_prefix (media_type, "audio")) {
2002 stream->subtype = FOURCC_soun;
2003 }
2004 }
2005 }
2006 }
2007 gst_caps_replace (&demux->media_caps, (GstCaps *) mediacaps);
2008 } else {
2009 demux->mss_mode = FALSE;
2010 }
2011
2012 return TRUE;
2013 }
2014
2015 static void
gst_qtdemux_reset(GstQTDemux * qtdemux,gboolean hard)2016 gst_qtdemux_reset (GstQTDemux * qtdemux, gboolean hard)
2017 {
2018 gint i;
2019
2020 GST_DEBUG_OBJECT (qtdemux, "Resetting demux");
2021 gst_pad_stop_task (qtdemux->sinkpad);
2022
2023 if (hard || qtdemux->upstream_format_is_time) {
2024 qtdemux->state = QTDEMUX_STATE_INITIAL;
2025 qtdemux->neededbytes = 16;
2026 qtdemux->todrop = 0;
2027 qtdemux->pullbased = FALSE;
2028 g_clear_pointer (&qtdemux->redirect_location, g_free);
2029 qtdemux->first_mdat = -1;
2030 qtdemux->header_size = 0;
2031 qtdemux->mdatoffset = -1;
2032 qtdemux->restoredata_offset = -1;
2033 if (qtdemux->mdatbuffer)
2034 gst_buffer_unref (qtdemux->mdatbuffer);
2035 if (qtdemux->restoredata_buffer)
2036 gst_buffer_unref (qtdemux->restoredata_buffer);
2037 qtdemux->mdatbuffer = NULL;
2038 qtdemux->restoredata_buffer = NULL;
2039 qtdemux->mdatleft = 0;
2040 qtdemux->mdatsize = 0;
2041 if (qtdemux->comp_brands)
2042 gst_buffer_unref (qtdemux->comp_brands);
2043 qtdemux->comp_brands = NULL;
2044 qtdemux->last_moov_offset = -1;
2045 if (qtdemux->moov_node_compressed) {
2046 g_node_destroy (qtdemux->moov_node_compressed);
2047 if (qtdemux->moov_node)
2048 g_free (qtdemux->moov_node->data);
2049 }
2050 qtdemux->moov_node_compressed = NULL;
2051 if (qtdemux->moov_node)
2052 g_node_destroy (qtdemux->moov_node);
2053 qtdemux->moov_node = NULL;
2054 if (qtdemux->tag_list)
2055 gst_mini_object_unref (GST_MINI_OBJECT_CAST (qtdemux->tag_list));
2056 qtdemux->tag_list = gst_tag_list_new_empty ();
2057 gst_tag_list_set_scope (qtdemux->tag_list, GST_TAG_SCOPE_GLOBAL);
2058 #if 0
2059 if (qtdemux->element_index)
2060 gst_object_unref (qtdemux->element_index);
2061 qtdemux->element_index = NULL;
2062 #endif
2063 qtdemux->major_brand = 0;
2064 qtdemux->upstream_format_is_time = FALSE;
2065 qtdemux->upstream_seekable = FALSE;
2066 qtdemux->upstream_size = 0;
2067
2068 qtdemux->fragment_start = -1;
2069 qtdemux->fragment_start_offset = -1;
2070 qtdemux->duration = 0;
2071 qtdemux->moof_offset = 0;
2072 qtdemux->chapters_track_id = 0;
2073 qtdemux->have_group_id = FALSE;
2074 qtdemux->group_id = G_MAXUINT;
2075
2076 g_queue_foreach (&qtdemux->protection_event_queue, (GFunc) gst_event_unref,
2077 NULL);
2078 g_queue_clear (&qtdemux->protection_event_queue);
2079
2080 qtdemux->received_seek = FALSE;
2081 qtdemux->first_moof_already_parsed = FALSE;
2082 }
2083 qtdemux->offset = 0;
2084 gst_adapter_clear (qtdemux->adapter);
2085 gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
2086 qtdemux->need_segment = TRUE;
2087
2088 if (hard) {
2089 qtdemux->segment_seqnum = GST_SEQNUM_INVALID;
2090 qtdemux->trickmode_interval = 0;
2091 g_ptr_array_set_size (qtdemux->active_streams, 0);
2092 g_ptr_array_set_size (qtdemux->old_streams, 0);
2093 qtdemux->n_video_streams = 0;
2094 qtdemux->n_audio_streams = 0;
2095 qtdemux->n_sub_streams = 0;
2096 qtdemux->exposed = FALSE;
2097 qtdemux->fragmented = FALSE;
2098 qtdemux->mss_mode = FALSE;
2099 gst_caps_replace (&qtdemux->media_caps, NULL);
2100 qtdemux->timescale = 0;
2101 qtdemux->got_moov = FALSE;
2102 qtdemux->cenc_aux_info_offset = 0;
2103 qtdemux->cenc_aux_info_sizes = NULL;
2104 qtdemux->cenc_aux_sample_count = 0;
2105 if (qtdemux->protection_system_ids) {
2106 g_ptr_array_free (qtdemux->protection_system_ids, TRUE);
2107 qtdemux->protection_system_ids = NULL;
2108 }
2109 qtdemux->streams_aware = GST_OBJECT_PARENT (qtdemux)
2110 && GST_OBJECT_FLAG_IS_SET (GST_OBJECT_PARENT (qtdemux),
2111 GST_BIN_FLAG_STREAMS_AWARE);
2112
2113 if (qtdemux->preferred_protection_system_id) {
2114 g_free (qtdemux->preferred_protection_system_id);
2115 qtdemux->preferred_protection_system_id = NULL;
2116 }
2117 } else if (qtdemux->mss_mode) {
2118 gst_flow_combiner_reset (qtdemux->flowcombiner);
2119 g_ptr_array_foreach (qtdemux->active_streams,
2120 (GFunc) gst_qtdemux_stream_clear, NULL);
2121 } else {
2122 gst_flow_combiner_reset (qtdemux->flowcombiner);
2123 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
2124 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
2125 stream->sent_eos = FALSE;
2126 stream->time_position = 0;
2127 stream->accumulated_base = 0;
2128 stream->last_keyframe_dts = GST_CLOCK_TIME_NONE;
2129 }
2130 }
2131 }
2132
2133
2134 /* Maps the @segment to the qt edts internal segments and pushes
2135 * the corresponding segment event.
2136 *
2137 * If it ends up being at a empty segment, a gap will be pushed and the next
2138 * edts segment will be activated in sequence.
2139 *
2140 * To be used in push-mode only */
2141 static void
gst_qtdemux_map_and_push_segments(GstQTDemux * qtdemux,GstSegment * segment)2142 gst_qtdemux_map_and_push_segments (GstQTDemux * qtdemux, GstSegment * segment)
2143 {
2144 gint i, iter;
2145
2146 for (iter = 0; iter < QTDEMUX_N_STREAMS (qtdemux); iter++) {
2147 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, iter);
2148
2149 stream->time_position = segment->start;
2150
2151 /* in push mode we should be guaranteed that we will have empty segments
2152 * at the beginning and then one segment after, other scenarios are not
2153 * supported and are discarded when parsing the edts */
2154 for (i = 0; i < stream->n_segments; i++) {
2155 if (stream->segments[i].stop_time > segment->start) {
2156 /* push the empty segment and move to the next one */
2157 gst_qtdemux_activate_segment (qtdemux, stream, i,
2158 stream->time_position);
2159 if (QTSEGMENT_IS_EMPTY (&stream->segments[i])) {
2160 gst_qtdemux_send_gap_for_segment (qtdemux, stream, i,
2161 stream->time_position);
2162
2163 /* accumulate previous segments */
2164 if (GST_CLOCK_TIME_IS_VALID (stream->segment.stop))
2165 stream->accumulated_base +=
2166 (stream->segment.stop -
2167 stream->segment.start) / ABS (stream->segment.rate);
2168 continue;
2169 }
2170
2171 g_assert (i == stream->n_segments - 1);
2172 }
2173 }
2174 }
2175 }
2176
2177 static void
gst_qtdemux_stream_concat(GstQTDemux * qtdemux,GPtrArray * dest,GPtrArray * src)2178 gst_qtdemux_stream_concat (GstQTDemux * qtdemux, GPtrArray * dest,
2179 GPtrArray * src)
2180 {
2181 guint i;
2182 guint len;
2183
2184 len = src->len;
2185
2186 if (len == 0)
2187 return;
2188
2189 for (i = 0; i < len; i++) {
2190 QtDemuxStream *stream = g_ptr_array_index (src, i);
2191
2192 #ifndef GST_DISABLE_GST_DEBUG
2193 GST_DEBUG_OBJECT (qtdemux, "Move stream %p (stream-id %s) to %p",
2194 stream, GST_STR_NULL (stream->stream_id), dest);
2195 #endif
2196 g_ptr_array_add (dest, gst_qtdemux_stream_ref (stream));
2197 }
2198
2199 g_ptr_array_set_size (src, 0);
2200 }
2201
2202 static gboolean
gst_qtdemux_handle_sink_event(GstPad * sinkpad,GstObject * parent,GstEvent * event)2203 gst_qtdemux_handle_sink_event (GstPad * sinkpad, GstObject * parent,
2204 GstEvent * event)
2205 {
2206 GstQTDemux *demux = GST_QTDEMUX (parent);
2207 gboolean res = TRUE;
2208
2209 GST_LOG_OBJECT (demux, "handling %s event", GST_EVENT_TYPE_NAME (event));
2210
2211 switch (GST_EVENT_TYPE (event)) {
2212 case GST_EVENT_SEGMENT:
2213 {
2214 gint64 offset = 0;
2215 QtDemuxStream *stream;
2216 gint idx;
2217 GstSegment segment;
2218
2219 /* some debug output */
2220 gst_event_copy_segment (event, &segment);
2221 GST_DEBUG_OBJECT (demux, "received newsegment %" GST_SEGMENT_FORMAT,
2222 &segment);
2223
2224 if (segment.format == GST_FORMAT_TIME) {
2225 demux->upstream_format_is_time = TRUE;
2226 demux->segment_seqnum = gst_event_get_seqnum (event);
2227 } else {
2228 GST_DEBUG_OBJECT (demux, "Not storing upstream newsegment, "
2229 "not in time format");
2230
2231 /* chain will send initial newsegment after pads have been added */
2232 if (demux->state != QTDEMUX_STATE_MOVIE || !QTDEMUX_N_STREAMS (demux)) {
2233 GST_DEBUG_OBJECT (demux, "still starting, eating event");
2234 goto exit;
2235 }
2236 }
2237
2238 /* check if this matches a time seek we received previously
2239 * FIXME for backwards compatibility reasons we use the
2240 * seek_offset here to compare. In the future we might want to
2241 * change this to use the seqnum as it uniquely should identify
2242 * the segment that corresponds to the seek. */
2243 GST_DEBUG_OBJECT (demux, "Stored seek offset: %" G_GINT64_FORMAT
2244 ", received segment offset %" G_GINT64_FORMAT,
2245 demux->seek_offset, segment.start);
2246 if (segment.format == GST_FORMAT_BYTES
2247 && demux->seek_offset == segment.start) {
2248 GST_OBJECT_LOCK (demux);
2249 offset = segment.start;
2250
2251 segment.format = GST_FORMAT_TIME;
2252 segment.start = demux->push_seek_start;
2253 segment.stop = demux->push_seek_stop;
2254 GST_DEBUG_OBJECT (demux, "Replaced segment with stored seek "
2255 "segment %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT,
2256 GST_TIME_ARGS (segment.start), GST_TIME_ARGS (segment.stop));
2257 GST_OBJECT_UNLOCK (demux);
2258 }
2259
2260 /* we only expect a BYTE segment, e.g. following a seek */
2261 if (segment.format == GST_FORMAT_BYTES) {
2262 if (GST_CLOCK_TIME_IS_VALID (segment.start)) {
2263 offset = segment.start;
2264
2265 gst_qtdemux_find_sample (demux, segment.start, TRUE, FALSE, NULL,
2266 NULL, (gint64 *) & segment.start);
2267 if ((gint64) segment.start < 0)
2268 segment.start = 0;
2269 }
2270 if (GST_CLOCK_TIME_IS_VALID (segment.stop)) {
2271 gst_qtdemux_find_sample (demux, segment.stop, FALSE, FALSE, NULL,
2272 NULL, (gint64 *) & segment.stop);
2273 /* keyframe seeking should already arrange for start >= stop,
2274 * but make sure in other rare cases */
2275 segment.stop = MAX (segment.stop, segment.start);
2276 }
2277 } else if (segment.format == GST_FORMAT_TIME) {
2278 /* push all data on the adapter before starting this
2279 * new segment */
2280 gst_qtdemux_process_adapter (demux, TRUE);
2281 } else {
2282 GST_DEBUG_OBJECT (demux, "unsupported segment format, ignoring");
2283 goto exit;
2284 }
2285
2286 /* We shouldn't modify upstream driven TIME FORMAT segment */
2287 if (!demux->upstream_format_is_time) {
2288 /* accept upstream's notion of segment and distribute along */
2289 segment.format = GST_FORMAT_TIME;
2290 segment.position = segment.time = segment.start;
2291 segment.duration = demux->segment.duration;
2292 segment.base = gst_segment_to_running_time (&demux->segment,
2293 GST_FORMAT_TIME, demux->segment.position);
2294 }
2295
2296 gst_segment_copy_into (&segment, &demux->segment);
2297 GST_DEBUG_OBJECT (demux, "Pushing newseg %" GST_SEGMENT_FORMAT, &segment);
2298
2299 /* map segment to internal qt segments and push on each stream */
2300 if (QTDEMUX_N_STREAMS (demux)) {
2301 demux->need_segment = TRUE;
2302 gst_qtdemux_check_send_pending_segment (demux);
2303 }
2304
2305 /* clear leftover in current segment, if any */
2306 gst_adapter_clear (demux->adapter);
2307
2308 /* set up streaming thread */
2309 demux->offset = offset;
2310 if (demux->upstream_format_is_time) {
2311 GST_DEBUG_OBJECT (demux, "Upstream is driving in time format, "
2312 "set values to restart reading from a new atom");
2313 demux->neededbytes = 16;
2314 demux->todrop = 0;
2315 } else {
2316 gst_qtdemux_find_sample (demux, offset, TRUE, TRUE, &stream, &idx,
2317 NULL);
2318 if (stream) {
2319 demux->todrop = stream->samples[idx].offset - offset;
2320 demux->neededbytes = demux->todrop + stream->samples[idx].size;
2321 } else {
2322 /* set up for EOS */
2323 demux->neededbytes = -1;
2324 demux->todrop = 0;
2325 }
2326 }
2327 exit:
2328 gst_event_unref (event);
2329 res = TRUE;
2330 goto drop;
2331 }
2332 case GST_EVENT_FLUSH_START:
2333 {
2334 if (gst_event_get_seqnum (event) == demux->offset_seek_seqnum) {
2335 gst_event_unref (event);
2336 goto drop;
2337 }
2338 QTDEMUX_EXPOSE_LOCK (demux);
2339 res = gst_pad_event_default (demux->sinkpad, parent, event);
2340 QTDEMUX_EXPOSE_UNLOCK (demux);
2341 goto drop;
2342 }
2343 case GST_EVENT_FLUSH_STOP:
2344 {
2345 guint64 dur;
2346
2347 dur = demux->segment.duration;
2348 gst_qtdemux_reset (demux, FALSE);
2349 demux->segment.duration = dur;
2350
2351 if (gst_event_get_seqnum (event) == demux->offset_seek_seqnum) {
2352 gst_event_unref (event);
2353 goto drop;
2354 }
2355 break;
2356 }
2357 case GST_EVENT_EOS:
2358 /* If we are in push mode, and get an EOS before we've seen any streams,
2359 * then error out - we have nowhere to send the EOS */
2360 if (!demux->pullbased) {
2361 gint i;
2362 gboolean has_valid_stream = FALSE;
2363 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
2364 if (QTDEMUX_NTH_STREAM (demux, i)->pad != NULL) {
2365 has_valid_stream = TRUE;
2366 break;
2367 }
2368 }
2369 if (!has_valid_stream)
2370 gst_qtdemux_post_no_playable_stream_error (demux);
2371 else {
2372 GST_DEBUG_OBJECT (demux, "Data still available after EOS: %u",
2373 (guint) gst_adapter_available (demux->adapter));
2374 if (gst_qtdemux_process_adapter (demux, TRUE) != GST_FLOW_OK) {
2375 res = FALSE;
2376 }
2377 }
2378 }
2379 break;
2380 case GST_EVENT_CAPS:{
2381 GstCaps *caps = NULL;
2382
2383 gst_event_parse_caps (event, &caps);
2384 gst_qtdemux_setcaps (demux, caps);
2385 res = TRUE;
2386 gst_event_unref (event);
2387 goto drop;
2388 }
2389 case GST_EVENT_PROTECTION:
2390 {
2391 const gchar *system_id = NULL;
2392
2393 gst_event_parse_protection (event, &system_id, NULL, NULL);
2394 GST_DEBUG_OBJECT (demux, "Received protection event for system ID %s",
2395 system_id);
2396 gst_qtdemux_append_protection_system_id (demux, system_id);
2397 /* save the event for later, for source pads that have not been created */
2398 g_queue_push_tail (&demux->protection_event_queue, gst_event_ref (event));
2399 /* send it to all pads that already exist */
2400 gst_qtdemux_push_event (demux, event);
2401 res = TRUE;
2402 goto drop;
2403 }
2404 case GST_EVENT_STREAM_START:
2405 {
2406 res = TRUE;
2407 gst_event_unref (event);
2408
2409 /* Drain all the buffers */
2410 gst_qtdemux_process_adapter (demux, TRUE);
2411 gst_qtdemux_reset (demux, FALSE);
2412 /* We expect new moov box after new stream-start event */
2413 if (demux->exposed) {
2414 gst_qtdemux_stream_concat (demux,
2415 demux->old_streams, demux->active_streams);
2416 }
2417
2418 goto drop;
2419 }
2420 default:
2421 break;
2422 }
2423
2424 res = gst_pad_event_default (demux->sinkpad, parent, event) & res;
2425
2426 drop:
2427 return res;
2428 }
2429
2430 static gboolean
gst_qtdemux_handle_sink_query(GstPad * pad,GstObject * parent,GstQuery * query)2431 gst_qtdemux_handle_sink_query (GstPad * pad, GstObject * parent,
2432 GstQuery * query)
2433 {
2434 GstQTDemux *demux = GST_QTDEMUX (parent);
2435 gboolean res = FALSE;
2436
2437 switch (GST_QUERY_TYPE (query)) {
2438 case GST_QUERY_BITRATE:
2439 {
2440 GstClockTime duration;
2441
2442 /* populate demux->upstream_size if not done yet */
2443 gst_qtdemux_check_seekability (demux);
2444
2445 if (demux->upstream_size != -1
2446 && gst_qtdemux_get_duration (demux, &duration)) {
2447 guint bitrate =
2448 gst_util_uint64_scale (8 * demux->upstream_size, GST_SECOND,
2449 duration);
2450
2451 GST_LOG_OBJECT (demux, "bitrate query byte length: %" G_GUINT64_FORMAT
2452 " duration %" GST_TIME_FORMAT " resulting a bitrate of %u",
2453 demux->upstream_size, GST_TIME_ARGS (duration), bitrate);
2454
2455 /* TODO: better results based on ranges/index tables */
2456 gst_query_set_bitrate (query, bitrate);
2457 res = TRUE;
2458 }
2459 break;
2460 }
2461 default:
2462 res = gst_pad_query_default (pad, (GstObject *) demux, query);
2463 break;
2464 }
2465
2466 return res;
2467 }
2468
2469
2470 #if 0
2471 static void
2472 gst_qtdemux_set_index (GstElement * element, GstIndex * index)
2473 {
2474 GstQTDemux *demux = GST_QTDEMUX (element);
2475
2476 GST_OBJECT_LOCK (demux);
2477 if (demux->element_index)
2478 gst_object_unref (demux->element_index);
2479 if (index) {
2480 demux->element_index = gst_object_ref (index);
2481 } else {
2482 demux->element_index = NULL;
2483 }
2484 GST_OBJECT_UNLOCK (demux);
2485 /* object lock might be taken again */
2486 if (index)
2487 gst_index_get_writer_id (index, GST_OBJECT (element), &demux->index_id);
2488 GST_DEBUG_OBJECT (demux, "Set index %" GST_PTR_FORMAT "for writer id %d",
2489 demux->element_index, demux->index_id);
2490 }
2491
2492 static GstIndex *
2493 gst_qtdemux_get_index (GstElement * element)
2494 {
2495 GstIndex *result = NULL;
2496 GstQTDemux *demux = GST_QTDEMUX (element);
2497
2498 GST_OBJECT_LOCK (demux);
2499 if (demux->element_index)
2500 result = gst_object_ref (demux->element_index);
2501 GST_OBJECT_UNLOCK (demux);
2502
2503 GST_DEBUG_OBJECT (demux, "Returning index %" GST_PTR_FORMAT, result);
2504
2505 return result;
2506 }
2507 #endif
2508
2509 static void
gst_qtdemux_stbl_free(QtDemuxStream * stream)2510 gst_qtdemux_stbl_free (QtDemuxStream * stream)
2511 {
2512 g_free ((gpointer) stream->stco.data);
2513 stream->stco.data = NULL;
2514 g_free ((gpointer) stream->stsz.data);
2515 stream->stsz.data = NULL;
2516 g_free ((gpointer) stream->stsc.data);
2517 stream->stsc.data = NULL;
2518 g_free ((gpointer) stream->stts.data);
2519 stream->stts.data = NULL;
2520 g_free ((gpointer) stream->stss.data);
2521 stream->stss.data = NULL;
2522 g_free ((gpointer) stream->stps.data);
2523 stream->stps.data = NULL;
2524 g_free ((gpointer) stream->ctts.data);
2525 stream->ctts.data = NULL;
2526 }
2527
2528 static void
gst_qtdemux_stream_flush_segments_data(QtDemuxStream * stream)2529 gst_qtdemux_stream_flush_segments_data (QtDemuxStream * stream)
2530 {
2531 g_free (stream->segments);
2532 stream->segments = NULL;
2533 stream->segment_index = -1;
2534 stream->accumulated_base = 0;
2535 }
2536
2537 static void
gst_qtdemux_stream_flush_samples_data(QtDemuxStream * stream)2538 gst_qtdemux_stream_flush_samples_data (QtDemuxStream * stream)
2539 {
2540 g_free (stream->samples);
2541 stream->samples = NULL;
2542 gst_qtdemux_stbl_free (stream);
2543
2544 /* fragments */
2545 g_free (stream->ra_entries);
2546 stream->ra_entries = NULL;
2547 stream->n_ra_entries = 0;
2548
2549 stream->sample_index = -1;
2550 stream->stbl_index = -1;
2551 stream->n_samples = 0;
2552 stream->time_position = 0;
2553
2554 stream->n_samples_moof = 0;
2555 stream->duration_moof = 0;
2556 stream->duration_last_moof = 0;
2557 }
2558
2559 static void
gst_qtdemux_stream_clear(QtDemuxStream * stream)2560 gst_qtdemux_stream_clear (QtDemuxStream * stream)
2561 {
2562 gint i;
2563 if (stream->allocator)
2564 gst_object_unref (stream->allocator);
2565 while (stream->buffers) {
2566 gst_buffer_unref (GST_BUFFER_CAST (stream->buffers->data));
2567 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
2568 }
2569 for (i = 0; i < stream->stsd_entries_length; i++) {
2570 QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[i];
2571 if (entry->rgb8_palette) {
2572 gst_memory_unref (entry->rgb8_palette);
2573 entry->rgb8_palette = NULL;
2574 }
2575 entry->sparse = FALSE;
2576 }
2577
2578 if (stream->stream_tags)
2579 gst_tag_list_unref (stream->stream_tags);
2580
2581 stream->stream_tags = gst_tag_list_new_empty ();
2582 gst_tag_list_set_scope (stream->stream_tags, GST_TAG_SCOPE_STREAM);
2583 g_free (stream->redirect_uri);
2584 stream->redirect_uri = NULL;
2585 stream->sent_eos = FALSE;
2586 stream->protected = FALSE;
2587 #ifdef OHOS_OPT_PERFORMANCE // ohos.opt.performance.0001: demux push first audio/video frame
2588 stream->has_push_first_frame = FALSE;
2589 #endif
2590 if (stream->protection_scheme_info) {
2591 if (stream->protection_scheme_type == FOURCC_cenc
2592 || stream->protection_scheme_type == FOURCC_cbcs) {
2593 QtDemuxCencSampleSetInfo *info =
2594 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
2595 if (info->default_properties)
2596 gst_structure_free (info->default_properties);
2597 if (info->crypto_info)
2598 g_ptr_array_free (info->crypto_info, TRUE);
2599 }
2600 if (stream->protection_scheme_type == FOURCC_aavd) {
2601 QtDemuxAavdEncryptionInfo *info =
2602 (QtDemuxAavdEncryptionInfo *) stream->protection_scheme_info;
2603 if (info->default_properties)
2604 gst_structure_free (info->default_properties);
2605 }
2606 g_free (stream->protection_scheme_info);
2607 stream->protection_scheme_info = NULL;
2608 }
2609 stream->protection_scheme_type = 0;
2610 stream->protection_scheme_version = 0;
2611 g_queue_foreach (&stream->protection_scheme_event_queue,
2612 (GFunc) gst_event_unref, NULL);
2613 g_queue_clear (&stream->protection_scheme_event_queue);
2614 gst_qtdemux_stream_flush_segments_data (stream);
2615 gst_qtdemux_stream_flush_samples_data (stream);
2616 }
2617
2618 static void
gst_qtdemux_stream_reset(QtDemuxStream * stream)2619 gst_qtdemux_stream_reset (QtDemuxStream * stream)
2620 {
2621 gint i;
2622 gst_qtdemux_stream_clear (stream);
2623 for (i = 0; i < stream->stsd_entries_length; i++) {
2624 QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[i];
2625 if (entry->caps) {
2626 gst_caps_unref (entry->caps);
2627 entry->caps = NULL;
2628 }
2629 }
2630 g_free (stream->stsd_entries);
2631 stream->stsd_entries = NULL;
2632 stream->stsd_entries_length = 0;
2633 }
2634
2635 static QtDemuxStream *
gst_qtdemux_stream_ref(QtDemuxStream * stream)2636 gst_qtdemux_stream_ref (QtDemuxStream * stream)
2637 {
2638 g_atomic_int_add (&stream->ref_count, 1);
2639
2640 return stream;
2641 }
2642
2643 static void
gst_qtdemux_stream_unref(QtDemuxStream * stream)2644 gst_qtdemux_stream_unref (QtDemuxStream * stream)
2645 {
2646 if (g_atomic_int_dec_and_test (&stream->ref_count)) {
2647 gst_qtdemux_stream_reset (stream);
2648 gst_tag_list_unref (stream->stream_tags);
2649 if (stream->pad) {
2650 GstQTDemux *demux = stream->demux;
2651 gst_element_remove_pad (GST_ELEMENT_CAST (demux), stream->pad);
2652 GST_OBJECT_LOCK (demux);
2653 gst_flow_combiner_remove_pad (demux->flowcombiner, stream->pad);
2654 GST_OBJECT_UNLOCK (demux);
2655 }
2656 g_free (stream->stream_id);
2657 g_free (stream);
2658 }
2659 }
2660
2661 static GstStateChangeReturn
gst_qtdemux_change_state(GstElement * element,GstStateChange transition)2662 gst_qtdemux_change_state (GstElement * element, GstStateChange transition)
2663 {
2664 GstQTDemux *qtdemux = GST_QTDEMUX (element);
2665 GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
2666
2667 switch (transition) {
2668 case GST_STATE_CHANGE_READY_TO_PAUSED:
2669 gst_qtdemux_reset (qtdemux, TRUE);
2670 break;
2671 default:
2672 break;
2673 }
2674
2675 result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
2676
2677 switch (transition) {
2678 case GST_STATE_CHANGE_PAUSED_TO_READY:{
2679 gst_qtdemux_reset (qtdemux, TRUE);
2680 break;
2681 }
2682 default:
2683 break;
2684 }
2685
2686 return result;
2687 }
2688
2689 static void
gst_qtdemux_set_context(GstElement * element,GstContext * context)2690 gst_qtdemux_set_context (GstElement * element, GstContext * context)
2691 {
2692 GstQTDemux *qtdemux = GST_QTDEMUX (element);
2693
2694 g_return_if_fail (GST_IS_CONTEXT (context));
2695
2696 if (gst_context_has_context_type (context,
2697 "drm-preferred-decryption-system-id")) {
2698 const GstStructure *s;
2699
2700 s = gst_context_get_structure (context);
2701 g_free (qtdemux->preferred_protection_system_id);
2702 qtdemux->preferred_protection_system_id =
2703 g_strdup (gst_structure_get_string (s, "decryption-system-id"));
2704 GST_DEBUG_OBJECT (element, "set preferred decryption system to %s",
2705 qtdemux->preferred_protection_system_id);
2706 }
2707
2708 GST_ELEMENT_CLASS (parent_class)->set_context (element, context);
2709 }
2710
2711 static void
qtdemux_parse_ftyp(GstQTDemux * qtdemux,const guint8 * buffer,gint length)2712 qtdemux_parse_ftyp (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2713 {
2714 /* counts as header data */
2715 qtdemux->header_size += length;
2716
2717 /* only consider at least a sufficiently complete ftyp atom */
2718 if (length >= 20) {
2719 GstBuffer *buf;
2720
2721 qtdemux->major_brand = QT_FOURCC (buffer + 8);
2722 GST_DEBUG_OBJECT (qtdemux, "major brand: %" GST_FOURCC_FORMAT,
2723 GST_FOURCC_ARGS (qtdemux->major_brand));
2724 if (qtdemux->comp_brands)
2725 gst_buffer_unref (qtdemux->comp_brands);
2726 buf = qtdemux->comp_brands = gst_buffer_new_and_alloc (length - 16);
2727 gst_buffer_fill (buf, 0, buffer + 16, length - 16);
2728 }
2729 }
2730
2731 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)2732 qtdemux_update_default_sample_cenc_settings (GstQTDemux * qtdemux,
2733 QtDemuxCencSampleSetInfo * info, guint32 is_encrypted,
2734 guint32 protection_scheme_type, guint8 iv_size, const guint8 * kid,
2735 guint crypt_byte_block, guint skip_byte_block, guint8 constant_iv_size,
2736 const guint8 * constant_iv)
2737 {
2738 GstBuffer *kid_buf = gst_buffer_new_allocate (NULL, 16, NULL);
2739 gst_buffer_fill (kid_buf, 0, kid, 16);
2740 if (info->default_properties)
2741 gst_structure_free (info->default_properties);
2742 info->default_properties =
2743 gst_structure_new ("application/x-cenc",
2744 "iv_size", G_TYPE_UINT, iv_size,
2745 "encrypted", G_TYPE_BOOLEAN, (is_encrypted == 1),
2746 "kid", GST_TYPE_BUFFER, kid_buf, NULL);
2747 GST_DEBUG_OBJECT (qtdemux, "default sample properties: "
2748 "is_encrypted=%u, iv_size=%u", is_encrypted, iv_size);
2749 gst_buffer_unref (kid_buf);
2750 if (protection_scheme_type == FOURCC_cbcs) {
2751 if (crypt_byte_block != 0 || skip_byte_block != 0) {
2752 gst_structure_set (info->default_properties, "crypt_byte_block",
2753 G_TYPE_UINT, crypt_byte_block, "skip_byte_block", G_TYPE_UINT,
2754 skip_byte_block, NULL);
2755 }
2756 if (constant_iv != NULL) {
2757 GstBuffer *constant_iv_buf =
2758 gst_buffer_new_allocate (NULL, constant_iv_size, NULL);
2759 gst_buffer_fill (constant_iv_buf, 0, constant_iv, constant_iv_size);
2760 gst_structure_set (info->default_properties, "constant_iv_size",
2761 G_TYPE_UINT, constant_iv_size, "iv", GST_TYPE_BUFFER, constant_iv_buf,
2762 NULL);
2763 gst_buffer_unref (constant_iv_buf);
2764 }
2765 gst_structure_set (info->default_properties, "cipher-mode",
2766 G_TYPE_STRING, "cbcs", NULL);
2767 } else {
2768 gst_structure_set (info->default_properties, "cipher-mode",
2769 G_TYPE_STRING, "cenc", NULL);
2770 }
2771 }
2772
2773 static gboolean
qtdemux_update_default_piff_encryption_settings(GstQTDemux * qtdemux,QtDemuxCencSampleSetInfo * info,GstByteReader * br)2774 qtdemux_update_default_piff_encryption_settings (GstQTDemux * qtdemux,
2775 QtDemuxCencSampleSetInfo * info, GstByteReader * br)
2776 {
2777 guint32 algorithm_id = 0;
2778 const guint8 *kid;
2779 gboolean is_encrypted = TRUE;
2780 guint8 iv_size = 8;
2781
2782 if (!gst_byte_reader_get_uint24_le (br, &algorithm_id)) {
2783 GST_ERROR_OBJECT (qtdemux, "Error getting box's algorithm ID field");
2784 return FALSE;
2785 }
2786
2787 algorithm_id >>= 8;
2788 if (algorithm_id == 0) {
2789 is_encrypted = FALSE;
2790 } else if (algorithm_id == 1) {
2791 GST_DEBUG_OBJECT (qtdemux, "AES 128-bits CTR encrypted stream");
2792 } else if (algorithm_id == 2) {
2793 GST_DEBUG_OBJECT (qtdemux, "AES 128-bits CBC encrypted stream");
2794 }
2795
2796 if (!gst_byte_reader_get_uint8 (br, &iv_size))
2797 return FALSE;
2798
2799 if (!gst_byte_reader_get_data (br, 16, &kid))
2800 return FALSE;
2801
2802 qtdemux_update_default_sample_cenc_settings (qtdemux, info,
2803 is_encrypted, FOURCC_cenc, iv_size, kid, 0, 0, 0, NULL);
2804 gst_structure_set (info->default_properties, "piff_algorithm_id",
2805 G_TYPE_UINT, algorithm_id, NULL);
2806 return TRUE;
2807 }
2808
2809
2810 static void
qtdemux_parse_piff(GstQTDemux * qtdemux,const guint8 * buffer,gint length,guint offset)2811 qtdemux_parse_piff (GstQTDemux * qtdemux, const guint8 * buffer, gint length,
2812 guint offset)
2813 {
2814 GstByteReader br;
2815 guint8 version;
2816 guint32 flags = 0;
2817 guint i;
2818 guint iv_size = 8;
2819 QtDemuxStream *stream;
2820 GstStructure *structure;
2821 QtDemuxCencSampleSetInfo *ss_info = NULL;
2822 const gchar *system_id;
2823 gboolean uses_sub_sample_encryption = FALSE;
2824 guint32 sample_count;
2825
2826 if (QTDEMUX_N_STREAMS (qtdemux) == 0)
2827 return;
2828
2829 stream = QTDEMUX_NTH_STREAM (qtdemux, 0);
2830
2831 structure = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
2832 if (!gst_structure_has_name (structure, "application/x-cenc")) {
2833 GST_WARNING_OBJECT (qtdemux,
2834 "Attempting PIFF box parsing on an unencrypted stream.");
2835 return;
2836 }
2837
2838 gst_structure_get (structure, GST_PROTECTION_SYSTEM_ID_CAPS_FIELD,
2839 G_TYPE_STRING, &system_id, NULL);
2840 gst_qtdemux_append_protection_system_id (qtdemux, system_id);
2841
2842 stream->protected = TRUE;
2843 stream->protection_scheme_type = FOURCC_cenc;
2844
2845 if (!stream->protection_scheme_info)
2846 stream->protection_scheme_info = g_new0 (QtDemuxCencSampleSetInfo, 1);
2847
2848 ss_info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
2849 if (!ss_info->default_properties) {
2850 ss_info->default_properties =
2851 gst_structure_new ("application/x-cenc",
2852 "iv_size", G_TYPE_UINT, iv_size, "encrypted", G_TYPE_BOOLEAN, TRUE,
2853 NULL);
2854
2855 }
2856
2857 if (ss_info->crypto_info) {
2858 GST_LOG_OBJECT (qtdemux, "unreffing existing crypto_info");
2859 g_ptr_array_free (ss_info->crypto_info, TRUE);
2860 ss_info->crypto_info = NULL;
2861 }
2862
2863 /* skip UUID */
2864 gst_byte_reader_init (&br, buffer + offset + 16, length - offset - 16);
2865
2866 if (!gst_byte_reader_get_uint8 (&br, &version)) {
2867 GST_ERROR_OBJECT (qtdemux, "Error getting box's version field");
2868 return;
2869 }
2870
2871 if (!gst_byte_reader_get_uint24_be (&br, &flags)) {
2872 GST_ERROR_OBJECT (qtdemux, "Error getting box's flags field");
2873 return;
2874 }
2875
2876 if ((flags & 0x000001)) {
2877 if (!qtdemux_update_default_piff_encryption_settings (qtdemux, ss_info,
2878 &br))
2879 return;
2880 } else if ((flags & 0x000002)) {
2881 uses_sub_sample_encryption = TRUE;
2882 }
2883
2884 if (!gst_structure_get_uint (ss_info->default_properties, "iv_size",
2885 &iv_size)) {
2886 GST_ERROR_OBJECT (qtdemux, "Error getting encryption IV size field");
2887 return;
2888 }
2889
2890 if (!gst_byte_reader_get_uint32_be (&br, &sample_count)) {
2891 GST_ERROR_OBJECT (qtdemux, "Error getting box's sample count field");
2892 return;
2893 }
2894
2895 ss_info->crypto_info =
2896 g_ptr_array_new_full (sample_count,
2897 (GDestroyNotify) qtdemux_gst_structure_free);
2898
2899 for (i = 0; i < sample_count; ++i) {
2900 GstStructure *properties;
2901 guint8 *data;
2902 GstBuffer *buf;
2903
2904 properties = qtdemux_get_cenc_sample_properties (qtdemux, stream, i);
2905 if (properties == NULL) {
2906 GST_ERROR_OBJECT (qtdemux, "failed to get properties for sample %u", i);
2907 qtdemux->cenc_aux_sample_count = i;
2908 return;
2909 }
2910
2911 if (!gst_byte_reader_dup_data (&br, iv_size, &data)) {
2912 GST_ERROR_OBJECT (qtdemux, "IV data not present for sample %u", i);
2913 gst_structure_free (properties);
2914 qtdemux->cenc_aux_sample_count = i;
2915 return;
2916 }
2917 buf = gst_buffer_new_wrapped (data, iv_size);
2918 gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL);
2919 gst_buffer_unref (buf);
2920
2921 if (uses_sub_sample_encryption) {
2922 guint16 n_subsamples;
2923 const GValue *kid_buf_value;
2924
2925 if (!gst_byte_reader_get_uint16_be (&br, &n_subsamples)
2926 || n_subsamples == 0) {
2927 GST_ERROR_OBJECT (qtdemux,
2928 "failed to get subsample count for sample %u", i);
2929 gst_structure_free (properties);
2930 qtdemux->cenc_aux_sample_count = i;
2931 return;
2932 }
2933 GST_LOG_OBJECT (qtdemux, "subsample count: %u", n_subsamples);
2934 if (!gst_byte_reader_dup_data (&br, n_subsamples * 6, &data)) {
2935 GST_ERROR_OBJECT (qtdemux, "failed to get subsample data for sample %u",
2936 i);
2937 gst_structure_free (properties);
2938 qtdemux->cenc_aux_sample_count = i;
2939 return;
2940 }
2941 buf = gst_buffer_new_wrapped (data, n_subsamples * 6);
2942
2943 kid_buf_value =
2944 gst_structure_get_value (ss_info->default_properties, "kid");
2945
2946 gst_structure_set (properties,
2947 "subsample_count", G_TYPE_UINT, n_subsamples,
2948 "subsamples", GST_TYPE_BUFFER, buf, NULL);
2949 gst_structure_set_value (properties, "kid", kid_buf_value);
2950 gst_buffer_unref (buf);
2951 } else {
2952 gst_structure_set (properties, "subsample_count", G_TYPE_UINT, 0, NULL);
2953 }
2954
2955 g_ptr_array_add (ss_info->crypto_info, properties);
2956 }
2957
2958 qtdemux->cenc_aux_sample_count = sample_count;
2959 }
2960
2961 static void
qtdemux_parse_uuid(GstQTDemux * qtdemux,const guint8 * buffer,gint length)2962 qtdemux_parse_uuid (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2963 {
2964 static const guint8 xmp_uuid[] = { 0xBE, 0x7A, 0xCF, 0xCB,
2965 0x97, 0xA9, 0x42, 0xE8,
2966 0x9C, 0x71, 0x99, 0x94,
2967 0x91, 0xE3, 0xAF, 0xAC
2968 };
2969 static const guint8 playready_uuid[] = {
2970 0xd0, 0x8a, 0x4f, 0x18, 0x10, 0xf3, 0x4a, 0x82,
2971 0xb6, 0xc8, 0x32, 0xd8, 0xab, 0xa1, 0x83, 0xd3
2972 };
2973
2974 static const guint8 piff_sample_encryption_uuid[] = {
2975 0xa2, 0x39, 0x4f, 0x52, 0x5a, 0x9b, 0x4f, 0x14,
2976 0xa2, 0x44, 0x6c, 0x42, 0x7c, 0x64, 0x8d, 0xf4
2977 };
2978
2979 guint offset;
2980
2981 /* counts as header data */
2982 qtdemux->header_size += length;
2983
2984 offset = (QT_UINT32 (buffer) == 0) ? 16 : 8;
2985
2986 if (length <= offset + 16) {
2987 GST_DEBUG_OBJECT (qtdemux, "uuid atom is too short, skipping");
2988 return;
2989 }
2990
2991 if (memcmp (buffer + offset, xmp_uuid, 16) == 0) {
2992 GstBuffer *buf;
2993 GstTagList *taglist;
2994
2995 buf = _gst_buffer_new_wrapped ((guint8 *) buffer + offset + 16,
2996 length - offset - 16, NULL);
2997 taglist = gst_tag_list_from_xmp_buffer (buf);
2998 gst_buffer_unref (buf);
2999
3000 /* make sure we have a usable taglist */
3001 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
3002
3003 qtdemux_handle_xmp_taglist (qtdemux, qtdemux->tag_list, taglist);
3004
3005 } else if (memcmp (buffer + offset, playready_uuid, 16) == 0) {
3006 int len;
3007 const gunichar2 *s_utf16;
3008 char *contents;
3009
3010 len = GST_READ_UINT16_LE (buffer + offset + 0x30);
3011 s_utf16 = (const gunichar2 *) (buffer + offset + 0x32);
3012 contents = g_utf16_to_utf8 (s_utf16, len / 2, NULL, NULL, NULL);
3013 GST_ERROR_OBJECT (qtdemux, "contents: %s", contents);
3014
3015 g_free (contents);
3016
3017 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT,
3018 (_("Cannot play stream because it is encrypted with PlayReady DRM.")),
3019 (NULL));
3020 } else if (memcmp (buffer + offset, piff_sample_encryption_uuid, 16) == 0) {
3021 qtdemux_parse_piff (qtdemux, buffer, length, offset);
3022 } else {
3023 GST_DEBUG_OBJECT (qtdemux, "Ignoring unknown uuid: %08x-%08x-%08x-%08x",
3024 GST_READ_UINT32_LE (buffer + offset),
3025 GST_READ_UINT32_LE (buffer + offset + 4),
3026 GST_READ_UINT32_LE (buffer + offset + 8),
3027 GST_READ_UINT32_LE (buffer + offset + 12));
3028 }
3029 }
3030
3031 static void
qtdemux_parse_sidx(GstQTDemux * qtdemux,const guint8 * buffer,gint length)3032 qtdemux_parse_sidx (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
3033 {
3034 GstSidxParser sidx_parser;
3035 GstIsoffParserResult res;
3036 guint consumed;
3037
3038 gst_isoff_qt_sidx_parser_init (&sidx_parser);
3039
3040 res =
3041 gst_isoff_qt_sidx_parser_add_data (&sidx_parser, buffer, length,
3042 &consumed);
3043 GST_DEBUG_OBJECT (qtdemux, "sidx parse result: %d", res);
3044 if (res == GST_ISOFF_QT_PARSER_DONE) {
3045 check_update_duration (qtdemux, sidx_parser.cumulative_pts);
3046 }
3047 gst_isoff_qt_sidx_parser_clear (&sidx_parser);
3048 }
3049
3050 /* caller verifies at least 8 bytes in buf */
3051 static void
extract_initial_length_and_fourcc(const guint8 * data,guint size,guint64 * plength,guint32 * pfourcc)3052 extract_initial_length_and_fourcc (const guint8 * data, guint size,
3053 guint64 * plength, guint32 * pfourcc)
3054 {
3055 guint64 length;
3056 guint32 fourcc;
3057
3058 length = QT_UINT32 (data);
3059 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
3060 fourcc = QT_FOURCC (data + 4);
3061 GST_DEBUG ("atom type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
3062
3063 if (length == 0) {
3064 length = G_MAXUINT64;
3065 } else if (length == 1 && size >= 16) {
3066 /* this means we have an extended size, which is the 64 bit value of
3067 * the next 8 bytes */
3068 length = QT_UINT64 (data + 8);
3069 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
3070 }
3071
3072 if (plength)
3073 *plength = length;
3074 if (pfourcc)
3075 *pfourcc = fourcc;
3076 }
3077
3078 static gboolean
qtdemux_parse_mehd(GstQTDemux * qtdemux,GstByteReader * br)3079 qtdemux_parse_mehd (GstQTDemux * qtdemux, GstByteReader * br)
3080 {
3081 guint32 version = 0;
3082 GstClockTime duration = 0;
3083
3084 if (!gst_byte_reader_get_uint32_be (br, &version))
3085 goto failed;
3086
3087 version >>= 24;
3088 if (version == 1) {
3089 if (!gst_byte_reader_get_uint64_be (br, &duration))
3090 goto failed;
3091 } else {
3092 guint32 dur = 0;
3093
3094 if (!gst_byte_reader_get_uint32_be (br, &dur))
3095 goto failed;
3096 duration = dur;
3097 }
3098
3099 GST_INFO_OBJECT (qtdemux, "mehd duration: %" G_GUINT64_FORMAT, duration);
3100 qtdemux->duration = duration;
3101
3102 return TRUE;
3103
3104 failed:
3105 {
3106 GST_DEBUG_OBJECT (qtdemux, "parsing mehd failed");
3107 return FALSE;
3108 }
3109 }
3110
3111 static gboolean
qtdemux_parse_trex(GstQTDemux * qtdemux,QtDemuxStream * stream,guint32 * ds_duration,guint32 * ds_size,guint32 * ds_flags)3112 qtdemux_parse_trex (GstQTDemux * qtdemux, QtDemuxStream * stream,
3113 guint32 * ds_duration, guint32 * ds_size, guint32 * ds_flags)
3114 {
3115 if (!stream->parsed_trex && qtdemux->moov_node) {
3116 GNode *mvex, *trex;
3117 GstByteReader trex_data;
3118
3119 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
3120 if (mvex) {
3121 trex = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_trex,
3122 &trex_data);
3123 while (trex) {
3124 guint32 id = 0, sdi = 0, dur = 0, size = 0, flags = 0;
3125
3126 /* skip version/flags */
3127 if (!gst_byte_reader_skip (&trex_data, 4))
3128 goto next;
3129 if (!gst_byte_reader_get_uint32_be (&trex_data, &id))
3130 goto next;
3131 if (id != stream->track_id)
3132 goto next;
3133 if (!gst_byte_reader_get_uint32_be (&trex_data, &sdi))
3134 goto next;
3135 if (!gst_byte_reader_get_uint32_be (&trex_data, &dur))
3136 goto next;
3137 if (!gst_byte_reader_get_uint32_be (&trex_data, &size))
3138 goto next;
3139 if (!gst_byte_reader_get_uint32_be (&trex_data, &flags))
3140 goto next;
3141
3142 GST_DEBUG_OBJECT (qtdemux, "fragment defaults for stream %d; "
3143 "duration %d, size %d, flags 0x%x", stream->track_id,
3144 dur, size, flags);
3145
3146 stream->parsed_trex = TRUE;
3147 stream->def_sample_description_index = sdi;
3148 stream->def_sample_duration = dur;
3149 stream->def_sample_size = size;
3150 stream->def_sample_flags = flags;
3151
3152 next:
3153 /* iterate all siblings */
3154 trex = qtdemux_tree_get_sibling_by_type_full (trex, FOURCC_trex,
3155 &trex_data);
3156 }
3157 }
3158 }
3159
3160 *ds_duration = stream->def_sample_duration;
3161 *ds_size = stream->def_sample_size;
3162 *ds_flags = stream->def_sample_flags;
3163
3164 /* even then, above values are better than random ... */
3165 if (G_UNLIKELY (!stream->parsed_trex)) {
3166 GST_WARNING_OBJECT (qtdemux,
3167 "failed to find fragment defaults for stream %d", stream->track_id);
3168 return FALSE;
3169 }
3170
3171 return TRUE;
3172 }
3173
3174 /* This method should be called whenever a more accurate duration might
3175 * have been found. It will update all relevant variables if/where needed
3176 */
3177 static void
check_update_duration(GstQTDemux * qtdemux,GstClockTime duration)3178 check_update_duration (GstQTDemux * qtdemux, GstClockTime duration)
3179 {
3180 guint i;
3181 guint64 movdur;
3182 GstClockTime prevdur;
3183
3184 movdur = GSTTIME_TO_QTTIME (qtdemux, duration);
3185
3186 if (movdur > qtdemux->duration) {
3187 prevdur = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
3188 GST_DEBUG_OBJECT (qtdemux,
3189 "Updating total duration to %" GST_TIME_FORMAT " was %" GST_TIME_FORMAT,
3190 GST_TIME_ARGS (duration), GST_TIME_ARGS (prevdur));
3191 qtdemux->duration = movdur;
3192 GST_DEBUG_OBJECT (qtdemux,
3193 "qtdemux->segment.duration: %" GST_TIME_FORMAT " .stop: %"
3194 GST_TIME_FORMAT, GST_TIME_ARGS (qtdemux->segment.duration),
3195 GST_TIME_ARGS (qtdemux->segment.stop));
3196 if (qtdemux->segment.duration == prevdur) {
3197 /* If the current segment has duration/stop identical to previous duration
3198 * update them also (because they were set at that point in time with
3199 * the wrong duration */
3200 /* We convert the value *from* the timescale version to avoid rounding errors */
3201 GstClockTime fixeddur = QTTIME_TO_GSTTIME (qtdemux, movdur);
3202 GST_DEBUG_OBJECT (qtdemux, "Updated segment.duration and segment.stop");
3203 qtdemux->segment.duration = fixeddur;
3204 qtdemux->segment.stop = fixeddur;
3205 }
3206 }
3207
3208 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
3209 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
3210
3211 movdur = GSTTIME_TO_QTSTREAMTIME (stream, duration);
3212 if (movdur > stream->duration) {
3213 GST_DEBUG_OBJECT (qtdemux,
3214 "Updating stream #%d duration to %" GST_TIME_FORMAT, i,
3215 GST_TIME_ARGS (duration));
3216 stream->duration = movdur;
3217 /* internal duration tracking state has been updated above, so */
3218 /* preserve an open-ended dummy segment rather than repeatedly updating
3219 * it and spamming downstream accordingly with segment events */
3220 /* also mangle the edit list end time when fragmented with a single edit
3221 * list that may only cover any non-fragmented data */
3222 if ((stream->dummy_segment ||
3223 (qtdemux->fragmented && stream->n_segments == 1)) &&
3224 GST_CLOCK_TIME_IS_VALID (stream->segments[0].duration)) {
3225 /* Update all dummy values to new duration */
3226 stream->segments[0].stop_time = duration;
3227 stream->segments[0].duration = duration;
3228 stream->segments[0].media_stop = duration;
3229
3230 /* let downstream know we possibly have a new stop time */
3231 if (stream->segment_index != -1) {
3232 GstClockTime pos;
3233
3234 if (qtdemux->segment.rate >= 0) {
3235 pos = stream->segment.start;
3236 } else {
3237 pos = stream->segment.stop;
3238 }
3239
3240 gst_qtdemux_stream_update_segment (qtdemux, stream,
3241 stream->segment_index, pos, NULL, NULL);
3242 }
3243 }
3244 }
3245 }
3246 }
3247
3248 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)3249 qtdemux_parse_trun (GstQTDemux * qtdemux, GstByteReader * trun,
3250 QtDemuxStream * stream, guint32 d_sample_duration, guint32 d_sample_size,
3251 guint32 d_sample_flags, gint64 moof_offset, gint64 moof_length,
3252 gint64 * base_offset, gint64 * running_offset, gint64 decode_ts,
3253 gboolean has_tfdt)
3254 {
3255 GstClockTime gst_ts = GST_CLOCK_TIME_NONE;
3256 guint64 timestamp;
3257 gint32 data_offset = 0;
3258 guint8 version;
3259 guint32 flags = 0, first_flags = 0, samples_count = 0;
3260 gint i;
3261 guint8 *data;
3262 guint entry_size, dur_offset, size_offset, flags_offset = 0, ct_offset = 0;
3263 QtDemuxSample *sample;
3264 gboolean ismv = FALSE;
3265 gint64 initial_offset;
3266 gint32 min_ct = 0;
3267
3268 GST_LOG_OBJECT (qtdemux, "parsing trun track-id %d; "
3269 "default dur %d, size %d, flags 0x%x, base offset %" G_GINT64_FORMAT ", "
3270 "decode ts %" G_GINT64_FORMAT, stream->track_id, d_sample_duration,
3271 d_sample_size, d_sample_flags, *base_offset, decode_ts);
3272
3273 if (stream->pending_seek && moof_offset < stream->pending_seek->moof_offset) {
3274 GST_INFO_OBJECT (stream->pad, "skipping trun before seek target fragment");
3275 return TRUE;
3276 }
3277
3278 /* presence of stss or not can't really tell us much,
3279 * and flags and so on tend to be marginally reliable in these files */
3280 if (stream->subtype == FOURCC_soun) {
3281 GST_DEBUG_OBJECT (qtdemux,
3282 "sound track in fragmented file; marking all keyframes");
3283 stream->all_keyframe = TRUE;
3284 }
3285
3286 if (!gst_byte_reader_get_uint8 (trun, &version) ||
3287 !gst_byte_reader_get_uint24_be (trun, &flags))
3288 goto fail;
3289
3290 if (!gst_byte_reader_get_uint32_be (trun, &samples_count))
3291 goto fail;
3292
3293 if (flags & TR_DATA_OFFSET) {
3294 /* note this is really signed */
3295 if (!gst_byte_reader_get_int32_be (trun, &data_offset))
3296 goto fail;
3297 GST_LOG_OBJECT (qtdemux, "trun data offset %d", data_offset);
3298 /* default base offset = first byte of moof */
3299 if (*base_offset == -1) {
3300 GST_LOG_OBJECT (qtdemux, "base_offset at moof");
3301 *base_offset = moof_offset;
3302 }
3303 *running_offset = *base_offset + data_offset;
3304 } else {
3305 /* if no offset at all, that would mean data starts at moof start,
3306 * which is a bit wrong and is ismv crappy way, so compensate
3307 * assuming data is in mdat following moof */
3308 if (*base_offset == -1) {
3309 *base_offset = moof_offset + moof_length + 8;
3310 GST_LOG_OBJECT (qtdemux, "base_offset assumed in mdat after moof");
3311 ismv = TRUE;
3312 }
3313 if (*running_offset == -1)
3314 *running_offset = *base_offset;
3315 }
3316
3317 GST_LOG_OBJECT (qtdemux, "running offset now %" G_GINT64_FORMAT,
3318 *running_offset);
3319 GST_LOG_OBJECT (qtdemux, "trun offset %d, flags 0x%x, entries %d",
3320 data_offset, flags, samples_count);
3321
3322 if (flags & TR_FIRST_SAMPLE_FLAGS) {
3323 if (G_UNLIKELY (flags & TR_SAMPLE_FLAGS)) {
3324 GST_DEBUG_OBJECT (qtdemux,
3325 "invalid flags; SAMPLE and FIRST_SAMPLE present, discarding latter");
3326 flags ^= TR_FIRST_SAMPLE_FLAGS;
3327 } else {
3328 if (!gst_byte_reader_get_uint32_be (trun, &first_flags))
3329 goto fail;
3330 GST_LOG_OBJECT (qtdemux, "first flags: 0x%x", first_flags);
3331 }
3332 }
3333
3334 /* FIXME ? spec says other bits should also be checked to determine
3335 * entry size (and prefix size for that matter) */
3336 entry_size = 0;
3337 dur_offset = size_offset = 0;
3338 if (flags & TR_SAMPLE_DURATION) {
3339 GST_LOG_OBJECT (qtdemux, "entry duration present");
3340 dur_offset = entry_size;
3341 entry_size += 4;
3342 }
3343 if (flags & TR_SAMPLE_SIZE) {
3344 GST_LOG_OBJECT (qtdemux, "entry size present");
3345 size_offset = entry_size;
3346 entry_size += 4;
3347 }
3348 if (flags & TR_SAMPLE_FLAGS) {
3349 GST_LOG_OBJECT (qtdemux, "entry flags present");
3350 flags_offset = entry_size;
3351 entry_size += 4;
3352 }
3353 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
3354 GST_LOG_OBJECT (qtdemux, "entry ct offset present");
3355 ct_offset = entry_size;
3356 entry_size += 4;
3357 }
3358
3359 if (!qt_atom_parser_has_chunks (trun, samples_count, entry_size))
3360 goto fail;
3361 data = (guint8 *) gst_byte_reader_peek_data_unchecked (trun);
3362
3363 if (stream->n_samples + samples_count >=
3364 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample))
3365 goto index_too_big;
3366
3367 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
3368 stream->n_samples + samples_count, (guint) sizeof (QtDemuxSample),
3369 (stream->n_samples + samples_count) *
3370 sizeof (QtDemuxSample) / (1024.0 * 1024.0));
3371
3372 /* create a new array of samples if it's the first sample parsed */
3373 if (stream->n_samples == 0) {
3374 g_assert (stream->samples == NULL);
3375 stream->samples = g_try_new0 (QtDemuxSample, samples_count);
3376 /* or try to reallocate it with space enough to insert the new samples */
3377 } else
3378 stream->samples = g_try_renew (QtDemuxSample, stream->samples,
3379 stream->n_samples + samples_count);
3380 if (stream->samples == NULL)
3381 goto out_of_memory;
3382
3383 if (qtdemux->fragment_start != -1) {
3384 timestamp = GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->fragment_start);
3385 qtdemux->fragment_start = -1;
3386 } else {
3387 if (stream->n_samples == 0) {
3388 if (decode_ts > 0) {
3389 timestamp = decode_ts;
3390 } else if (stream->pending_seek != NULL) {
3391 /* if we don't have a timestamp from a tfdt box, we'll use the one
3392 * from the mfra seek table */
3393 GST_INFO_OBJECT (stream->pad, "pending seek ts = %" GST_TIME_FORMAT,
3394 GST_TIME_ARGS (stream->pending_seek->ts));
3395
3396 /* FIXME: this is not fully correct, the timestamp refers to the random
3397 * access sample refered to in the tfra entry, which may not necessarily
3398 * be the first sample in the tfrag/trun (but hopefully/usually is) */
3399 timestamp = GSTTIME_TO_QTSTREAMTIME (stream, stream->pending_seek->ts);
3400 } else {
3401 timestamp = 0;
3402 }
3403
3404 gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
3405 GST_INFO_OBJECT (stream->pad, "first sample ts %" GST_TIME_FORMAT,
3406 GST_TIME_ARGS (gst_ts));
3407 } else {
3408 /* subsequent fragments extend stream */
3409 timestamp =
3410 stream->samples[stream->n_samples - 1].timestamp +
3411 stream->samples[stream->n_samples - 1].duration;
3412
3413 /* If this is a GST_FORMAT_BYTES stream and there's a significant
3414 * difference (1 sec.) between decode_ts and timestamp, prefer the
3415 * former */
3416 if (has_tfdt && !qtdemux->upstream_format_is_time
3417 && ABSDIFF (decode_ts, timestamp) >
3418 MAX (stream->duration_last_moof / 2,
3419 GSTTIME_TO_QTSTREAMTIME (stream, GST_SECOND))) {
3420 GST_INFO_OBJECT (qtdemux,
3421 "decode_ts (%" GST_TIME_FORMAT ") and timestamp (%" GST_TIME_FORMAT
3422 ") are significantly different (more than %" GST_TIME_FORMAT
3423 "), using decode_ts",
3424 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, decode_ts)),
3425 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, timestamp)),
3426 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream,
3427 MAX (stream->duration_last_moof / 2,
3428 GSTTIME_TO_QTSTREAMTIME (stream, GST_SECOND)))));
3429 timestamp = decode_ts;
3430 }
3431
3432 gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
3433 GST_INFO_OBJECT (qtdemux, "first sample ts %" GST_TIME_FORMAT
3434 " (extends previous samples)", GST_TIME_ARGS (gst_ts));
3435 }
3436 }
3437
3438 initial_offset = *running_offset;
3439
3440 sample = stream->samples + stream->n_samples;
3441 for (i = 0; i < samples_count; i++) {
3442 guint32 dur, size, sflags;
3443 gint32 ct;
3444
3445 /* first read sample data */
3446 if (flags & TR_SAMPLE_DURATION) {
3447 dur = QT_UINT32 (data + dur_offset);
3448 } else {
3449 dur = d_sample_duration;
3450 }
3451 if (flags & TR_SAMPLE_SIZE) {
3452 size = QT_UINT32 (data + size_offset);
3453 } else {
3454 size = d_sample_size;
3455 }
3456 if (flags & TR_FIRST_SAMPLE_FLAGS) {
3457 if (i == 0) {
3458 sflags = first_flags;
3459 } else {
3460 sflags = d_sample_flags;
3461 }
3462 } else if (flags & TR_SAMPLE_FLAGS) {
3463 sflags = QT_UINT32 (data + flags_offset);
3464 } else {
3465 sflags = d_sample_flags;
3466 }
3467
3468 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
3469 /* Read offsets as signed numbers regardless of trun version as very
3470 * high offsets are unlikely and there are files out there that use
3471 * version=0 truns with negative offsets */
3472 ct = QT_UINT32 (data + ct_offset);
3473
3474 /* FIXME: Set offset to 0 for "no decode samples". This needs
3475 * to be handled in a codec specific manner ideally. */
3476 if (ct == G_MININT32)
3477 ct = 0;
3478 } else {
3479 ct = 0;
3480 }
3481 data += entry_size;
3482
3483 /* fill the sample information */
3484 sample->offset = *running_offset;
3485 sample->pts_offset = ct;
3486 sample->size = size;
3487 sample->timestamp = timestamp;
3488 sample->duration = dur;
3489 /* sample-is-difference-sample */
3490 /* ismv seems to use 0x40 for keyframe, 0xc0 for non-keyframe,
3491 * now idea how it relates to bitfield other than massive LE/BE confusion */
3492 sample->keyframe = ismv ? ((sflags & 0xff) == 0x40) : !(sflags & 0x10000);
3493 *running_offset += size;
3494 timestamp += dur;
3495 stream->duration_moof += dur;
3496 sample++;
3497
3498 if (ct < min_ct)
3499 min_ct = ct;
3500 }
3501
3502 /* Shift PTS/DTS to allow for negative composition offsets while keeping
3503 * A/V sync in place. This is similar to the code handling ctts/cslg in the
3504 * non-fragmented case.
3505 */
3506 if (min_ct < 0)
3507 stream->cslg_shift = -min_ct;
3508 else
3509 stream->cslg_shift = 0;
3510
3511 GST_DEBUG_OBJECT (qtdemux, "Using clsg_shift %" G_GUINT64_FORMAT,
3512 stream->cslg_shift);
3513
3514 /* Update total duration if needed */
3515 check_update_duration (qtdemux, QTSTREAMTIME_TO_GSTTIME (stream, timestamp));
3516
3517 /* Pre-emptively figure out size of mdat based on trun information.
3518 * If the [mdat] atom is effectivelly read, it will be replaced by the actual
3519 * size, else we will still be able to use this when dealing with gap'ed
3520 * input */
3521 qtdemux->mdatleft = *running_offset - initial_offset;
3522 qtdemux->mdatoffset = initial_offset;
3523 qtdemux->mdatsize = qtdemux->mdatleft;
3524
3525 stream->n_samples += samples_count;
3526 stream->n_samples_moof += samples_count;
3527
3528 if (stream->pending_seek != NULL)
3529 stream->pending_seek = NULL;
3530
3531 return TRUE;
3532
3533 fail:
3534 {
3535 GST_WARNING_OBJECT (qtdemux, "failed to parse trun");
3536 return FALSE;
3537 }
3538 out_of_memory:
3539 {
3540 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
3541 stream->n_samples);
3542 return FALSE;
3543 }
3544 index_too_big:
3545 {
3546 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
3547 "be larger than %uMB (broken file?)", stream->n_samples,
3548 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
3549 return FALSE;
3550 }
3551 }
3552
3553 /* find stream with @id */
3554 static inline QtDemuxStream *
qtdemux_find_stream(GstQTDemux * qtdemux,guint32 id)3555 qtdemux_find_stream (GstQTDemux * qtdemux, guint32 id)
3556 {
3557 QtDemuxStream *stream;
3558 gint i;
3559
3560 /* check */
3561 if (G_UNLIKELY (!id)) {
3562 GST_DEBUG_OBJECT (qtdemux, "invalid track id 0");
3563 return NULL;
3564 }
3565
3566 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
3567 stream = QTDEMUX_NTH_STREAM (qtdemux, i);
3568 if (stream->track_id == id)
3569 return stream;
3570 }
3571 if (qtdemux->mss_mode) {
3572 /* mss should have only 1 stream anyway */
3573 return QTDEMUX_NTH_STREAM (qtdemux, 0);
3574 }
3575
3576 return NULL;
3577 }
3578
3579 static gboolean
qtdemux_parse_mfhd(GstQTDemux * qtdemux,GstByteReader * mfhd,guint32 * fragment_number)3580 qtdemux_parse_mfhd (GstQTDemux * qtdemux, GstByteReader * mfhd,
3581 guint32 * fragment_number)
3582 {
3583 if (!gst_byte_reader_skip (mfhd, 4))
3584 goto fail;
3585 if (!gst_byte_reader_get_uint32_be (mfhd, fragment_number))
3586 goto fail;
3587 return TRUE;
3588 fail:
3589 {
3590 GST_WARNING_OBJECT (qtdemux, "Failed to parse mfhd atom");
3591 return FALSE;
3592 }
3593 }
3594
3595 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)3596 qtdemux_parse_tfhd (GstQTDemux * qtdemux, GstByteReader * tfhd,
3597 QtDemuxStream ** stream, guint32 * default_sample_duration,
3598 guint32 * default_sample_size, guint32 * default_sample_flags,
3599 gint64 * base_offset)
3600 {
3601 guint32 flags = 0;
3602 guint32 track_id = 0;
3603
3604 if (!gst_byte_reader_skip (tfhd, 1) ||
3605 !gst_byte_reader_get_uint24_be (tfhd, &flags))
3606 goto invalid_track;
3607
3608 if (!gst_byte_reader_get_uint32_be (tfhd, &track_id))
3609 goto invalid_track;
3610
3611 *stream = qtdemux_find_stream (qtdemux, track_id);
3612 if (G_UNLIKELY (!*stream))
3613 goto unknown_stream;
3614
3615 if (flags & TF_DEFAULT_BASE_IS_MOOF)
3616 *base_offset = qtdemux->moof_offset;
3617
3618 if (flags & TF_BASE_DATA_OFFSET)
3619 if (!gst_byte_reader_get_uint64_be (tfhd, (guint64 *) base_offset))
3620 goto invalid_track;
3621
3622 /* obtain stream defaults */
3623 qtdemux_parse_trex (qtdemux, *stream,
3624 default_sample_duration, default_sample_size, default_sample_flags);
3625
3626 (*stream)->stsd_sample_description_id =
3627 (*stream)->def_sample_description_index - 1;
3628
3629 if (flags & TF_SAMPLE_DESCRIPTION_INDEX) {
3630 guint32 sample_description_index;
3631 if (!gst_byte_reader_get_uint32_be (tfhd, &sample_description_index))
3632 goto invalid_track;
3633 (*stream)->stsd_sample_description_id = sample_description_index - 1;
3634 }
3635
3636 if (qtdemux->mss_mode) {
3637 /* mss has no stsd entry */
3638 (*stream)->stsd_sample_description_id = 0;
3639 }
3640
3641 if (flags & TF_DEFAULT_SAMPLE_DURATION)
3642 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_duration))
3643 goto invalid_track;
3644
3645 if (flags & TF_DEFAULT_SAMPLE_SIZE)
3646 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_size))
3647 goto invalid_track;
3648
3649 if (flags & TF_DEFAULT_SAMPLE_FLAGS)
3650 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_flags))
3651 goto invalid_track;
3652
3653 return TRUE;
3654
3655 invalid_track:
3656 {
3657 GST_WARNING_OBJECT (qtdemux, "invalid track fragment header");
3658 return FALSE;
3659 }
3660 unknown_stream:
3661 {
3662 GST_DEBUG_OBJECT (qtdemux, "unknown stream (%u) in tfhd", track_id);
3663 return TRUE;
3664 }
3665 }
3666
3667 static gboolean
qtdemux_parse_tfdt(GstQTDemux * qtdemux,GstByteReader * br,guint64 * decode_time)3668 qtdemux_parse_tfdt (GstQTDemux * qtdemux, GstByteReader * br,
3669 guint64 * decode_time)
3670 {
3671 guint32 version = 0;
3672
3673 if (!gst_byte_reader_get_uint32_be (br, &version))
3674 return FALSE;
3675
3676 version >>= 24;
3677 if (version == 1) {
3678 if (!gst_byte_reader_get_uint64_be (br, decode_time))
3679 goto failed;
3680 } else {
3681 guint32 dec_time = 0;
3682 if (!gst_byte_reader_get_uint32_be (br, &dec_time))
3683 goto failed;
3684 *decode_time = dec_time;
3685 }
3686
3687 GST_INFO_OBJECT (qtdemux, "Track fragment decode time: %" G_GUINT64_FORMAT,
3688 *decode_time);
3689
3690 return TRUE;
3691
3692 failed:
3693 {
3694 GST_DEBUG_OBJECT (qtdemux, "parsing tfdt failed");
3695 return FALSE;
3696 }
3697 }
3698
3699 /* Returns a pointer to a GstStructure containing the properties of
3700 * the stream sample identified by @sample_index. The caller must unref
3701 * the returned object after use. Returns NULL if unsuccessful. */
3702 static GstStructure *
qtdemux_get_cenc_sample_properties(GstQTDemux * qtdemux,QtDemuxStream * stream,guint sample_index)3703 qtdemux_get_cenc_sample_properties (GstQTDemux * qtdemux,
3704 QtDemuxStream * stream, guint sample_index)
3705 {
3706 QtDemuxCencSampleSetInfo *info = NULL;
3707
3708 g_return_val_if_fail (stream != NULL, NULL);
3709 g_return_val_if_fail (stream->protected, NULL);
3710 g_return_val_if_fail (stream->protection_scheme_info != NULL, NULL);
3711
3712 info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
3713
3714 /* Currently, cenc properties for groups of samples are not supported, so
3715 * simply return a copy of the default sample properties */
3716 return gst_structure_copy (info->default_properties);
3717 }
3718
3719 /* Parses the sizes of sample auxiliary information contained within a stream,
3720 * as given in a saiz box. Returns array of sample_count guint8 size values,
3721 * or NULL on failure */
3722 static guint8 *
qtdemux_parse_saiz(GstQTDemux * qtdemux,QtDemuxStream * stream,GstByteReader * br,guint32 * sample_count)3723 qtdemux_parse_saiz (GstQTDemux * qtdemux, QtDemuxStream * stream,
3724 GstByteReader * br, guint32 * sample_count)
3725 {
3726 guint32 flags = 0;
3727 guint8 *info_sizes;
3728 guint8 default_info_size;
3729
3730 g_return_val_if_fail (qtdemux != NULL, NULL);
3731 g_return_val_if_fail (stream != NULL, NULL);
3732 g_return_val_if_fail (br != NULL, NULL);
3733 g_return_val_if_fail (sample_count != NULL, NULL);
3734
3735 if (!gst_byte_reader_get_uint32_be (br, &flags))
3736 return NULL;
3737
3738 if (flags & 0x1) {
3739 /* aux_info_type and aux_info_type_parameter are ignored */
3740 if (!gst_byte_reader_skip (br, 8))
3741 return NULL;
3742 }
3743
3744 if (!gst_byte_reader_get_uint8 (br, &default_info_size))
3745 return NULL;
3746 GST_DEBUG_OBJECT (qtdemux, "default_info_size: %u", default_info_size);
3747
3748 if (!gst_byte_reader_get_uint32_be (br, sample_count))
3749 return NULL;
3750 GST_DEBUG_OBJECT (qtdemux, "sample_count: %u", *sample_count);
3751
3752
3753 if (default_info_size == 0) {
3754 if (!gst_byte_reader_dup_data (br, *sample_count, &info_sizes)) {
3755 return NULL;
3756 }
3757 } else {
3758 info_sizes = g_new (guint8, *sample_count);
3759 memset (info_sizes, default_info_size, *sample_count);
3760 }
3761
3762 return info_sizes;
3763 }
3764
3765 /* Parses the offset of sample auxiliary information contained within a stream,
3766 * as given in a saio box. Returns TRUE if successful; FALSE otherwise. */
3767 static gboolean
qtdemux_parse_saio(GstQTDemux * qtdemux,QtDemuxStream * stream,GstByteReader * br,guint32 * info_type,guint32 * info_type_parameter,guint64 * offset)3768 qtdemux_parse_saio (GstQTDemux * qtdemux, QtDemuxStream * stream,
3769 GstByteReader * br, guint32 * info_type, guint32 * info_type_parameter,
3770 guint64 * offset)
3771 {
3772 guint8 version = 0;
3773 guint32 flags = 0;
3774 guint32 aux_info_type = 0;
3775 guint32 aux_info_type_parameter = 0;
3776 guint32 entry_count;
3777 guint32 off_32;
3778 guint64 off_64;
3779 const guint8 *aux_info_type_data = NULL;
3780
3781 g_return_val_if_fail (qtdemux != NULL, FALSE);
3782 g_return_val_if_fail (stream != NULL, FALSE);
3783 g_return_val_if_fail (br != NULL, FALSE);
3784 g_return_val_if_fail (offset != NULL, FALSE);
3785
3786 if (!gst_byte_reader_get_uint8 (br, &version))
3787 return FALSE;
3788
3789 if (!gst_byte_reader_get_uint24_be (br, &flags))
3790 return FALSE;
3791
3792 if (flags & 0x1) {
3793
3794 if (!gst_byte_reader_get_data (br, 4, &aux_info_type_data))
3795 return FALSE;
3796 aux_info_type = QT_FOURCC (aux_info_type_data);
3797
3798 if (!gst_byte_reader_get_uint32_be (br, &aux_info_type_parameter))
3799 return FALSE;
3800 } else if (stream->protected) {
3801 aux_info_type = stream->protection_scheme_type;
3802 } else {
3803 aux_info_type = CUR_STREAM (stream)->fourcc;
3804 }
3805
3806 if (info_type)
3807 *info_type = aux_info_type;
3808 if (info_type_parameter)
3809 *info_type_parameter = aux_info_type_parameter;
3810
3811 GST_DEBUG_OBJECT (qtdemux, "aux_info_type: '%" GST_FOURCC_FORMAT "', "
3812 "aux_info_type_parameter: %#06x",
3813 GST_FOURCC_ARGS (aux_info_type), aux_info_type_parameter);
3814
3815 if (!gst_byte_reader_get_uint32_be (br, &entry_count))
3816 return FALSE;
3817
3818 if (entry_count != 1) {
3819 GST_ERROR_OBJECT (qtdemux, "multiple offsets are not supported");
3820 return FALSE;
3821 }
3822
3823 if (version == 0) {
3824 if (!gst_byte_reader_get_uint32_be (br, &off_32))
3825 return FALSE;
3826 *offset = (guint64) off_32;
3827 } else {
3828 if (!gst_byte_reader_get_uint64_be (br, &off_64))
3829 return FALSE;
3830 *offset = off_64;
3831 }
3832
3833 GST_DEBUG_OBJECT (qtdemux, "offset: %" G_GUINT64_FORMAT, *offset);
3834 return TRUE;
3835 }
3836
3837 static void
qtdemux_gst_structure_free(GstStructure * gststructure)3838 qtdemux_gst_structure_free (GstStructure * gststructure)
3839 {
3840 if (gststructure) {
3841 gst_structure_free (gststructure);
3842 }
3843 }
3844
3845 /* Parses auxiliary information relating to samples protected using
3846 * Common Encryption (cenc); the format of this information
3847 * is defined in ISO/IEC 23001-7. Returns TRUE if successful; FALSE
3848 * otherwise. */
3849 static gboolean
qtdemux_parse_cenc_aux_info(GstQTDemux * qtdemux,QtDemuxStream * stream,GstByteReader * br,guint8 * info_sizes,guint32 sample_count)3850 qtdemux_parse_cenc_aux_info (GstQTDemux * qtdemux, QtDemuxStream * stream,
3851 GstByteReader * br, guint8 * info_sizes, guint32 sample_count)
3852 {
3853 QtDemuxCencSampleSetInfo *ss_info = NULL;
3854 guint8 size;
3855 gint i;
3856 GPtrArray *old_crypto_info = NULL;
3857 guint old_entries = 0;
3858
3859 g_return_val_if_fail (qtdemux != NULL, FALSE);
3860 g_return_val_if_fail (stream != NULL, FALSE);
3861 g_return_val_if_fail (br != NULL, FALSE);
3862 g_return_val_if_fail (stream->protected, FALSE);
3863 g_return_val_if_fail (stream->protection_scheme_info != NULL, FALSE);
3864
3865 ss_info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
3866
3867 if (ss_info->crypto_info) {
3868 old_crypto_info = ss_info->crypto_info;
3869 /* Count number of non-null entries remaining at the tail end */
3870 for (i = old_crypto_info->len - 1; i >= 0; i--) {
3871 if (g_ptr_array_index (old_crypto_info, i) == NULL)
3872 break;
3873 old_entries++;
3874 }
3875 }
3876
3877 ss_info->crypto_info =
3878 g_ptr_array_new_full (sample_count + old_entries,
3879 (GDestroyNotify) qtdemux_gst_structure_free);
3880
3881 /* We preserve old entries because we parse the next moof in advance
3882 * of consuming all samples from the previous moof, and otherwise
3883 * we'd discard the corresponding crypto info for the samples
3884 * from the previous fragment. */
3885 if (old_entries) {
3886 GST_DEBUG_OBJECT (qtdemux, "Preserving %d old crypto info entries",
3887 old_entries);
3888 for (i = old_crypto_info->len - old_entries; i < old_crypto_info->len; i++) {
3889 g_ptr_array_add (ss_info->crypto_info, g_ptr_array_index (old_crypto_info,
3890 i));
3891 g_ptr_array_index (old_crypto_info, i) = NULL;
3892 }
3893 }
3894
3895 if (old_crypto_info) {
3896 /* Everything now belongs to the new array */
3897 g_ptr_array_free (old_crypto_info, TRUE);
3898 }
3899
3900 for (i = 0; i < sample_count; ++i) {
3901 GstStructure *properties;
3902 guint16 n_subsamples = 0;
3903 guint8 *data;
3904 guint iv_size;
3905 GstBuffer *buf;
3906 gboolean could_read_iv;
3907
3908 properties = qtdemux_get_cenc_sample_properties (qtdemux, stream, i);
3909 if (properties == NULL) {
3910 GST_ERROR_OBJECT (qtdemux, "failed to get properties for sample %u", i);
3911 return FALSE;
3912 }
3913 if (!gst_structure_get_uint (properties, "iv_size", &iv_size)) {
3914 GST_ERROR_OBJECT (qtdemux, "failed to get iv_size for sample %u", i);
3915 gst_structure_free (properties);
3916 return FALSE;
3917 }
3918 could_read_iv =
3919 iv_size > 0 ? gst_byte_reader_dup_data (br, iv_size, &data) : FALSE;
3920 if (could_read_iv) {
3921 buf = gst_buffer_new_wrapped (data, iv_size);
3922 gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL);
3923 gst_buffer_unref (buf);
3924 } else if (stream->protection_scheme_type == FOURCC_cbcs) {
3925 const GValue *constant_iv_size_value =
3926 gst_structure_get_value (properties, "constant_iv_size");
3927 const GValue *constant_iv_value =
3928 gst_structure_get_value (properties, "iv");
3929 if (constant_iv_size_value == NULL || constant_iv_value == NULL) {
3930 GST_ERROR_OBJECT (qtdemux, "failed to get constant_iv");
3931 gst_structure_free (properties);
3932 return FALSE;
3933 }
3934 gst_structure_set_value (properties, "iv_size", constant_iv_size_value);
3935 gst_structure_remove_field (properties, "constant_iv_size");
3936 } else if (stream->protection_scheme_type == FOURCC_cenc) {
3937 GST_ERROR_OBJECT (qtdemux, "failed to get IV for sample %u", i);
3938 gst_structure_free (properties);
3939 return FALSE;
3940 }
3941 size = info_sizes[i];
3942 if (size > iv_size) {
3943 if (!gst_byte_reader_get_uint16_be (br, &n_subsamples)
3944 || !(n_subsamples > 0)) {
3945 gst_structure_free (properties);
3946 GST_ERROR_OBJECT (qtdemux,
3947 "failed to get subsample count for sample %u", i);
3948 return FALSE;
3949 }
3950 GST_LOG_OBJECT (qtdemux, "subsample count: %u", n_subsamples);
3951 if (!gst_byte_reader_dup_data (br, n_subsamples * 6, &data)) {
3952 GST_ERROR_OBJECT (qtdemux, "failed to get subsample data for sample %u",
3953 i);
3954 gst_structure_free (properties);
3955 return FALSE;
3956 }
3957 buf = gst_buffer_new_wrapped (data, n_subsamples * 6);
3958 if (!buf) {
3959 gst_structure_free (properties);
3960 return FALSE;
3961 }
3962 gst_structure_set (properties,
3963 "subsample_count", G_TYPE_UINT, n_subsamples,
3964 "subsamples", GST_TYPE_BUFFER, buf, NULL);
3965 gst_buffer_unref (buf);
3966 } else {
3967 gst_structure_set (properties, "subsample_count", G_TYPE_UINT, 0, NULL);
3968 }
3969 g_ptr_array_add (ss_info->crypto_info, properties);
3970 }
3971 return TRUE;
3972 }
3973
3974 /* Converts a UUID in raw byte form to a string representation, as defined in
3975 * RFC 4122. The caller takes ownership of the returned string and is
3976 * responsible for freeing it after use. */
3977 static gchar *
qtdemux_uuid_bytes_to_string(gconstpointer uuid_bytes)3978 qtdemux_uuid_bytes_to_string (gconstpointer uuid_bytes)
3979 {
3980 const guint8 *uuid = (const guint8 *) uuid_bytes;
3981
3982 return g_strdup_printf ("%02x%02x%02x%02x-%02x%02x-%02x%02x-"
3983 "%02x%02x-%02x%02x%02x%02x%02x%02x",
3984 uuid[0], uuid[1], uuid[2], uuid[3],
3985 uuid[4], uuid[5], uuid[6], uuid[7],
3986 uuid[8], uuid[9], uuid[10], uuid[11],
3987 uuid[12], uuid[13], uuid[14], uuid[15]);
3988 }
3989
3990 /* Parses a Protection System Specific Header box (pssh), as defined in the
3991 * Common Encryption (cenc) standard (ISO/IEC 23001-7), which contains
3992 * information needed by a specific content protection system in order to
3993 * decrypt cenc-protected tracks. Returns TRUE if successful; FALSE
3994 * otherwise. */
3995 static gboolean
qtdemux_parse_pssh(GstQTDemux * qtdemux,GNode * node)3996 qtdemux_parse_pssh (GstQTDemux * qtdemux, GNode * node)
3997 {
3998 gchar *sysid_string;
3999 guint32 pssh_size = QT_UINT32 (node->data);
4000 GstBuffer *pssh = NULL;
4001 GstEvent *event = NULL;
4002 guint32 parent_box_type;
4003 gint i;
4004
4005 if (G_UNLIKELY (pssh_size < 32U)) {
4006 GST_ERROR_OBJECT (qtdemux, "invalid box size");
4007 return FALSE;
4008 }
4009
4010 sysid_string =
4011 qtdemux_uuid_bytes_to_string ((const guint8 *) node->data + 12);
4012
4013 gst_qtdemux_append_protection_system_id (qtdemux, sysid_string);
4014
4015 pssh = gst_buffer_new_memdup (node->data, pssh_size);
4016 GST_LOG_OBJECT (qtdemux, "cenc pssh size: %" G_GSIZE_FORMAT,
4017 gst_buffer_get_size (pssh));
4018
4019 parent_box_type = QT_FOURCC ((const guint8 *) node->parent->data + 4);
4020
4021 /* Push an event containing the pssh box onto the queues of all streams. */
4022 event = gst_event_new_protection (sysid_string, pssh,
4023 (parent_box_type == FOURCC_moov) ? "isobmff/moov" : "isobmff/moof");
4024 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
4025 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
4026 GST_TRACE_OBJECT (qtdemux,
4027 "adding protection event for stream %s and system %s",
4028 stream->stream_id, sysid_string);
4029 g_queue_push_tail (&stream->protection_scheme_event_queue,
4030 gst_event_ref (event));
4031 }
4032 g_free (sysid_string);
4033 gst_event_unref (event);
4034 gst_buffer_unref (pssh);
4035 return TRUE;
4036 }
4037
4038 static gboolean
qtdemux_parse_moof(GstQTDemux * qtdemux,const guint8 * buffer,guint length,guint64 moof_offset,QtDemuxStream * stream)4039 qtdemux_parse_moof (GstQTDemux * qtdemux, const guint8 * buffer, guint length,
4040 guint64 moof_offset, QtDemuxStream * stream)
4041 {
4042 GNode *moof_node, *traf_node, *tfhd_node, *trun_node, *tfdt_node, *mfhd_node;
4043 GNode *uuid_node;
4044 GstByteReader mfhd_data, trun_data, tfhd_data, tfdt_data;
4045 GNode *saiz_node, *saio_node, *pssh_node;
4046 GstByteReader saiz_data, saio_data;
4047 guint32 ds_size = 0, ds_duration = 0, ds_flags = 0;
4048 gint64 base_offset, running_offset;
4049 guint32 frag_num;
4050 GstClockTime min_dts = GST_CLOCK_TIME_NONE;
4051
4052 /* NOTE @stream ignored */
4053
4054 moof_node = g_node_new ((guint8 *) buffer);
4055 qtdemux_parse_node (qtdemux, moof_node, buffer, length);
4056 qtdemux_node_dump (qtdemux, moof_node);
4057
4058 /* Get fragment number from mfhd and check it's valid */
4059 mfhd_node =
4060 qtdemux_tree_get_child_by_type_full (moof_node, FOURCC_mfhd, &mfhd_data);
4061 if (mfhd_node == NULL)
4062 goto missing_mfhd;
4063 if (!qtdemux_parse_mfhd (qtdemux, &mfhd_data, &frag_num))
4064 goto fail;
4065 GST_DEBUG_OBJECT (qtdemux, "Fragment #%d", frag_num);
4066
4067 /* unknown base_offset to start with */
4068 base_offset = running_offset = -1;
4069 traf_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_traf);
4070 while (traf_node) {
4071 guint64 decode_time = 0;
4072
4073 /* Fragment Header node */
4074 tfhd_node =
4075 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfhd,
4076 &tfhd_data);
4077 if (!tfhd_node)
4078 goto missing_tfhd;
4079 if (!qtdemux_parse_tfhd (qtdemux, &tfhd_data, &stream, &ds_duration,
4080 &ds_size, &ds_flags, &base_offset))
4081 goto missing_tfhd;
4082
4083 /* The following code assumes at most a single set of sample auxiliary
4084 * data in the fragment (consisting of a saiz box and a corresponding saio
4085 * box); in theory, however, there could be multiple sets of sample
4086 * auxiliary data in a fragment. */
4087 saiz_node =
4088 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saiz,
4089 &saiz_data);
4090 if (saiz_node) {
4091 guint32 info_type = 0;
4092 guint64 offset = 0;
4093 guint32 info_type_parameter = 0;
4094
4095 g_free (qtdemux->cenc_aux_info_sizes);
4096
4097 qtdemux->cenc_aux_info_sizes =
4098 qtdemux_parse_saiz (qtdemux, stream, &saiz_data,
4099 &qtdemux->cenc_aux_sample_count);
4100 if (qtdemux->cenc_aux_info_sizes == NULL) {
4101 GST_ERROR_OBJECT (qtdemux, "failed to parse saiz box");
4102 goto fail;
4103 }
4104 saio_node =
4105 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saio,
4106 &saio_data);
4107 if (!saio_node) {
4108 GST_ERROR_OBJECT (qtdemux, "saiz box without a corresponding saio box");
4109 g_free (qtdemux->cenc_aux_info_sizes);
4110 qtdemux->cenc_aux_info_sizes = NULL;
4111 goto fail;
4112 }
4113
4114 if (G_UNLIKELY (!qtdemux_parse_saio (qtdemux, stream, &saio_data,
4115 &info_type, &info_type_parameter, &offset))) {
4116 GST_ERROR_OBJECT (qtdemux, "failed to parse saio box");
4117 g_free (qtdemux->cenc_aux_info_sizes);
4118 qtdemux->cenc_aux_info_sizes = NULL;
4119 goto fail;
4120 }
4121 if (base_offset > -1 && base_offset > qtdemux->moof_offset)
4122 offset += (guint64) (base_offset - qtdemux->moof_offset);
4123 if ((info_type == FOURCC_cenc || info_type == FOURCC_cbcs)
4124 && info_type_parameter == 0U) {
4125 GstByteReader br;
4126 if (offset > length) {
4127 GST_DEBUG_OBJECT (qtdemux, "cenc auxiliary info stored out of moof");
4128 qtdemux->cenc_aux_info_offset = offset;
4129 } else {
4130 gst_byte_reader_init (&br, buffer + offset, length - offset);
4131 if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
4132 qtdemux->cenc_aux_info_sizes,
4133 qtdemux->cenc_aux_sample_count)) {
4134 GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
4135 g_free (qtdemux->cenc_aux_info_sizes);
4136 qtdemux->cenc_aux_info_sizes = NULL;
4137 goto fail;
4138 }
4139 }
4140 }
4141 }
4142
4143 tfdt_node =
4144 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfdt,
4145 &tfdt_data);
4146 if (tfdt_node) {
4147 /* We'll use decode_time to interpolate timestamps
4148 * in case the input timestamps are missing */
4149 qtdemux_parse_tfdt (qtdemux, &tfdt_data, &decode_time);
4150
4151 GST_DEBUG_OBJECT (qtdemux, "decode time %" G_GINT64_FORMAT
4152 " (%" GST_TIME_FORMAT ")", decode_time,
4153 GST_TIME_ARGS (stream ? QTSTREAMTIME_TO_GSTTIME (stream,
4154 decode_time) : GST_CLOCK_TIME_NONE));
4155
4156 /* Discard the fragment buffer timestamp info to avoid using it.
4157 * Rely on tfdt instead as it is more accurate than the timestamp
4158 * that is fetched from a manifest/playlist and is usually
4159 * less accurate. */
4160 qtdemux->fragment_start = -1;
4161 }
4162
4163 if (G_UNLIKELY (!stream)) {
4164 /* we lost track of offset, we'll need to regain it,
4165 * but can delay complaining until later or avoid doing so altogether */
4166 base_offset = -2;
4167 goto next;
4168 }
4169 if (G_UNLIKELY (base_offset < -1))
4170 goto lost_offset;
4171
4172 min_dts = MIN (min_dts, QTSTREAMTIME_TO_GSTTIME (stream, decode_time));
4173
4174 if (!qtdemux->pullbased) {
4175 /* Sample tables can grow enough to be problematic if the system memory
4176 * is very low (e.g. embedded devices) and the videos very long
4177 * (~8 MiB/hour for 25-30 fps video + typical AAC audio frames).
4178 * Fortunately, we can easily discard them for each new fragment when
4179 * we know qtdemux will not receive seeks outside of the current fragment.
4180 * adaptivedemux honors this assumption.
4181 * This optimization is also useful for applications that use qtdemux as
4182 * a push-based simple demuxer, like Media Source Extensions. */
4183 gst_qtdemux_stream_flush_samples_data (stream);
4184 }
4185
4186 /* initialise moof sample data */
4187 stream->n_samples_moof = 0;
4188 stream->duration_last_moof = stream->duration_moof;
4189 stream->duration_moof = 0;
4190
4191 /* Track Run node */
4192 trun_node =
4193 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_trun,
4194 &trun_data);
4195 while (trun_node) {
4196 qtdemux_parse_trun (qtdemux, &trun_data, stream,
4197 ds_duration, ds_size, ds_flags, moof_offset, length, &base_offset,
4198 &running_offset, decode_time, (tfdt_node != NULL));
4199 /* iterate all siblings */
4200 trun_node = qtdemux_tree_get_sibling_by_type_full (trun_node, FOURCC_trun,
4201 &trun_data);
4202 /* don't use tfdt for subsequent trun as it only refers to the first */
4203 tfdt_node = NULL;
4204 }
4205
4206 uuid_node = qtdemux_tree_get_child_by_type (traf_node, FOURCC_uuid);
4207 if (uuid_node) {
4208 guint8 *uuid_buffer = (guint8 *) uuid_node->data;
4209 guint32 box_length = QT_UINT32 (uuid_buffer);
4210
4211 qtdemux_parse_uuid (qtdemux, uuid_buffer, box_length);
4212 }
4213
4214 /* if no new base_offset provided for next traf,
4215 * base is end of current traf */
4216 base_offset = running_offset;
4217 running_offset = -1;
4218
4219 if (stream->n_samples_moof && stream->duration_moof)
4220 stream->new_caps = TRUE;
4221
4222 next:
4223 /* iterate all siblings */
4224 traf_node = qtdemux_tree_get_sibling_by_type (traf_node, FOURCC_traf);
4225 }
4226
4227 /* parse any protection system info */
4228 pssh_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_pssh);
4229 while (pssh_node) {
4230 GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
4231 qtdemux_parse_pssh (qtdemux, pssh_node);
4232 pssh_node = qtdemux_tree_get_sibling_by_type (pssh_node, FOURCC_pssh);
4233 }
4234
4235 if (!qtdemux->upstream_format_is_time && !qtdemux->first_moof_already_parsed
4236 && !qtdemux->received_seek && GST_CLOCK_TIME_IS_VALID (min_dts)
4237 && min_dts != 0) {
4238 /* Unless the user has explicitly requested another seek, perform an
4239 * internal seek to the time specified in the tfdt.
4240 *
4241 * This way if the user opens a file where the first tfdt is 1 hour
4242 * into the presentation, they will not have to wait 1 hour for run
4243 * time to catch up and actual playback to start. */
4244 gint i;
4245
4246 GST_DEBUG_OBJECT (qtdemux, "First fragment has a non-zero tfdt, "
4247 "performing an internal seek to %" GST_TIME_FORMAT,
4248 GST_TIME_ARGS (min_dts));
4249
4250 qtdemux->segment.start = min_dts;
4251 qtdemux->segment.time = qtdemux->segment.position = min_dts;
4252
4253 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
4254 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
4255 stream->time_position = min_dts;
4256 }
4257
4258 /* Before this code was run a segment was already sent when the moov was
4259 * parsed... which is OK -- some apps (mostly tests) expect a segment to
4260 * be emitted after a moov, and we can emit a second segment anyway for
4261 * special cases like this. */
4262 qtdemux->need_segment = TRUE;
4263 }
4264
4265 qtdemux->first_moof_already_parsed = TRUE;
4266
4267 g_node_destroy (moof_node);
4268 return TRUE;
4269
4270 missing_tfhd:
4271 {
4272 GST_DEBUG_OBJECT (qtdemux, "missing tfhd box");
4273 goto fail;
4274 }
4275 missing_mfhd:
4276 {
4277 GST_DEBUG_OBJECT (qtdemux, "Missing mfhd box");
4278 goto fail;
4279 }
4280 lost_offset:
4281 {
4282 GST_DEBUG_OBJECT (qtdemux, "lost offset");
4283 goto fail;
4284 }
4285 fail:
4286 {
4287 g_node_destroy (moof_node);
4288 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4289 (_("This file is corrupt and cannot be played.")), (NULL));
4290 return FALSE;
4291 }
4292 }
4293
4294 #if 0
4295 /* might be used if some day we actually use mfra & co
4296 * for random access to fragments,
4297 * but that will require quite some modifications and much less relying
4298 * on a sample array */
4299 #endif
4300
4301 static gboolean
qtdemux_parse_tfra(GstQTDemux * qtdemux,GNode * tfra_node)4302 qtdemux_parse_tfra (GstQTDemux * qtdemux, GNode * tfra_node)
4303 {
4304 QtDemuxStream *stream;
4305 guint32 ver_flags, track_id, len, num_entries, i;
4306 guint value_size, traf_size, trun_size, sample_size;
4307 guint64 time = 0, moof_offset = 0;
4308 #if 0
4309 GstBuffer *buf = NULL;
4310 GstFlowReturn ret;
4311 #endif
4312 GstByteReader tfra;
4313
4314 gst_byte_reader_init (&tfra, tfra_node->data, QT_UINT32 (tfra_node->data));
4315
4316 if (!gst_byte_reader_skip (&tfra, 8))
4317 return FALSE;
4318
4319 if (!gst_byte_reader_get_uint32_be (&tfra, &ver_flags))
4320 return FALSE;
4321
4322 if (!gst_byte_reader_get_uint32_be (&tfra, &track_id)
4323 || !gst_byte_reader_get_uint32_be (&tfra, &len)
4324 || !gst_byte_reader_get_uint32_be (&tfra, &num_entries))
4325 return FALSE;
4326
4327 GST_DEBUG_OBJECT (qtdemux, "parsing tfra box for track id %u", track_id);
4328
4329 stream = qtdemux_find_stream (qtdemux, track_id);
4330 if (stream == NULL)
4331 goto unknown_trackid;
4332
4333 value_size = ((ver_flags >> 24) == 1) ? sizeof (guint64) : sizeof (guint32);
4334 sample_size = (len & 3) + 1;
4335 trun_size = ((len & 12) >> 2) + 1;
4336 traf_size = ((len & 48) >> 4) + 1;
4337
4338 GST_DEBUG_OBJECT (qtdemux, "%u entries, sizes: value %u, traf %u, trun %u, "
4339 "sample %u", num_entries, value_size, traf_size, trun_size, sample_size);
4340
4341 if (num_entries == 0)
4342 goto no_samples;
4343
4344 if (!qt_atom_parser_has_chunks (&tfra, num_entries,
4345 value_size + value_size + traf_size + trun_size + sample_size))
4346 goto corrupt_file;
4347
4348 g_free (stream->ra_entries);
4349 stream->ra_entries = g_new (QtDemuxRandomAccessEntry, num_entries);
4350 stream->n_ra_entries = num_entries;
4351
4352 for (i = 0; i < num_entries; i++) {
4353 qt_atom_parser_get_offset (&tfra, value_size, &time);
4354 qt_atom_parser_get_offset (&tfra, value_size, &moof_offset);
4355 qt_atom_parser_get_uint_with_size_unchecked (&tfra, traf_size);
4356 qt_atom_parser_get_uint_with_size_unchecked (&tfra, trun_size);
4357 qt_atom_parser_get_uint_with_size_unchecked (&tfra, sample_size);
4358
4359 time = QTSTREAMTIME_TO_GSTTIME (stream, time);
4360
4361 GST_LOG_OBJECT (qtdemux, "fragment time: %" GST_TIME_FORMAT ", "
4362 " moof_offset: %" G_GUINT64_FORMAT, GST_TIME_ARGS (time), moof_offset);
4363
4364 stream->ra_entries[i].ts = time;
4365 stream->ra_entries[i].moof_offset = moof_offset;
4366
4367 /* don't want to go through the entire file and read all moofs at startup */
4368 #if 0
4369 ret = gst_qtdemux_pull_atom (qtdemux, moof_offset, 0, &buf);
4370 if (ret != GST_FLOW_OK)
4371 goto corrupt_file;
4372 qtdemux_parse_moof (qtdemux, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf),
4373 moof_offset, stream);
4374 gst_buffer_unref (buf);
4375 #endif
4376 }
4377
4378 check_update_duration (qtdemux, time);
4379
4380 return TRUE;
4381
4382 /* ERRORS */
4383 unknown_trackid:
4384 {
4385 GST_WARNING_OBJECT (qtdemux, "Couldn't find stream for track %u", track_id);
4386 return FALSE;
4387 }
4388 corrupt_file:
4389 {
4390 GST_WARNING_OBJECT (qtdemux, "broken traf box, ignoring");
4391 return FALSE;
4392 }
4393 no_samples:
4394 {
4395 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
4396 return FALSE;
4397 }
4398 }
4399
4400 static gboolean
qtdemux_pull_mfro_mfra(GstQTDemux * qtdemux)4401 qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux)
4402 {
4403 GstMapInfo mfro_map = GST_MAP_INFO_INIT;
4404 GstMapInfo mfra_map = GST_MAP_INFO_INIT;
4405 GstBuffer *mfro = NULL, *mfra = NULL;
4406 GstFlowReturn flow;
4407 gboolean ret = FALSE;
4408 GNode *mfra_node, *tfra_node;
4409 guint64 mfra_offset = 0;
4410 guint32 fourcc, mfra_size;
4411 gint64 len;
4412
4413 /* query upstream size in bytes */
4414 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &len))
4415 goto size_query_failed;
4416
4417 /* mfro box should be at the very end of the file */
4418 flow = gst_qtdemux_pull_atom (qtdemux, len - 16, 16, &mfro);
4419 if (flow != GST_FLOW_OK)
4420 goto exit;
4421
4422 gst_buffer_map (mfro, &mfro_map, GST_MAP_READ);
4423
4424 fourcc = QT_FOURCC (mfro_map.data + 4);
4425 if (fourcc != FOURCC_mfro)
4426 goto exit;
4427
4428 GST_INFO_OBJECT (qtdemux, "Found mfro box");
4429 if (mfro_map.size < 16)
4430 goto invalid_mfro_size;
4431
4432 mfra_size = QT_UINT32 (mfro_map.data + 12);
4433 if (mfra_size >= len)
4434 goto invalid_mfra_size;
4435
4436 mfra_offset = len - mfra_size;
4437
4438 GST_INFO_OBJECT (qtdemux, "mfra offset: %" G_GUINT64_FORMAT ", size %u",
4439 mfra_offset, mfra_size);
4440
4441 /* now get and parse mfra box */
4442 flow = gst_qtdemux_pull_atom (qtdemux, mfra_offset, mfra_size, &mfra);
4443 if (flow != GST_FLOW_OK)
4444 goto broken_file;
4445
4446 gst_buffer_map (mfra, &mfra_map, GST_MAP_READ);
4447
4448 mfra_node = g_node_new ((guint8 *) mfra_map.data);
4449 qtdemux_parse_node (qtdemux, mfra_node, mfra_map.data, mfra_map.size);
4450
4451 tfra_node = qtdemux_tree_get_child_by_type (mfra_node, FOURCC_tfra);
4452
4453 while (tfra_node) {
4454 qtdemux_parse_tfra (qtdemux, tfra_node);
4455 /* iterate all siblings */
4456 tfra_node = qtdemux_tree_get_sibling_by_type (tfra_node, FOURCC_tfra);
4457 }
4458 g_node_destroy (mfra_node);
4459
4460 GST_INFO_OBJECT (qtdemux, "parsed movie fragment random access box (mfra)");
4461 ret = TRUE;
4462
4463 exit:
4464
4465 if (mfro) {
4466 if (mfro_map.memory != NULL)
4467 gst_buffer_unmap (mfro, &mfro_map);
4468 gst_buffer_unref (mfro);
4469 }
4470 if (mfra) {
4471 if (mfra_map.memory != NULL)
4472 gst_buffer_unmap (mfra, &mfra_map);
4473 gst_buffer_unref (mfra);
4474 }
4475 return ret;
4476
4477 /* ERRORS */
4478 size_query_failed:
4479 {
4480 GST_WARNING_OBJECT (qtdemux, "could not query upstream size");
4481 goto exit;
4482 }
4483 invalid_mfro_size:
4484 {
4485 GST_WARNING_OBJECT (qtdemux, "mfro size is too small");
4486 goto exit;
4487 }
4488 invalid_mfra_size:
4489 {
4490 GST_WARNING_OBJECT (qtdemux, "mfra_size in mfro box is invalid");
4491 goto exit;
4492 }
4493 broken_file:
4494 {
4495 GST_WARNING_OBJECT (qtdemux, "bogus mfra offset or size, broken file");
4496 goto exit;
4497 }
4498 }
4499
4500 static guint64
add_offset(guint64 offset,guint64 advance)4501 add_offset (guint64 offset, guint64 advance)
4502 {
4503 /* Avoid 64-bit overflow by clamping */
4504 if (offset > G_MAXUINT64 - advance)
4505 return G_MAXUINT64;
4506 return offset + advance;
4507 }
4508
4509 static GstFlowReturn
gst_qtdemux_loop_state_header(GstQTDemux * qtdemux)4510 gst_qtdemux_loop_state_header (GstQTDemux * qtdemux)
4511 {
4512 guint64 length = 0;
4513 guint32 fourcc = 0;
4514 GstBuffer *buf = NULL;
4515 GstFlowReturn ret = GST_FLOW_OK;
4516 guint64 cur_offset = qtdemux->offset;
4517 GstMapInfo map;
4518
4519 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, 16, &buf);
4520 if (G_UNLIKELY (ret != GST_FLOW_OK))
4521 goto beach;
4522 gst_buffer_map (buf, &map, GST_MAP_READ);
4523 if (G_LIKELY (map.size >= 8))
4524 extract_initial_length_and_fourcc (map.data, map.size, &length, &fourcc);
4525 gst_buffer_unmap (buf, &map);
4526 gst_buffer_unref (buf);
4527
4528 /* maybe we already got most we needed, so only consider this eof */
4529 if (G_UNLIKELY (length == 0)) {
4530 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
4531 (_("Invalid atom size.")),
4532 ("Header atom '%" GST_FOURCC_FORMAT "' has empty length",
4533 GST_FOURCC_ARGS (fourcc)));
4534 ret = GST_FLOW_EOS;
4535 goto beach;
4536 }
4537
4538 switch (fourcc) {
4539 case FOURCC_moof:
4540 /* record for later parsing when needed */
4541 if (!qtdemux->moof_offset) {
4542 qtdemux->moof_offset = qtdemux->offset;
4543 }
4544 if (qtdemux_pull_mfro_mfra (qtdemux)) {
4545 /* FIXME */
4546 } else {
4547 qtdemux->offset += length; /* skip moof and keep going */
4548 }
4549 if (qtdemux->got_moov) {
4550 GST_INFO_OBJECT (qtdemux, "moof header, got moov, done with headers");
4551 ret = GST_FLOW_EOS;
4552 goto beach;
4553 }
4554 break;
4555 case FOURCC_mdat:
4556 case FOURCC_free:
4557 case FOURCC_skip:
4558 case FOURCC_wide:
4559 case FOURCC_PICT:
4560 case FOURCC_pnot:
4561 {
4562 GST_LOG_OBJECT (qtdemux,
4563 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
4564 GST_FOURCC_ARGS (fourcc), cur_offset);
4565 qtdemux->offset = add_offset (qtdemux->offset, length);
4566 break;
4567 }
4568 case FOURCC_moov:
4569 {
4570 GstBuffer *moov = NULL;
4571
4572 if (qtdemux->got_moov) {
4573 GST_DEBUG_OBJECT (qtdemux, "Skipping moov atom as we have one already");
4574 qtdemux->offset = add_offset (qtdemux->offset, length);
4575 goto beach;
4576 }
4577
4578 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, length, &moov);
4579 if (ret != GST_FLOW_OK)
4580 goto beach;
4581 gst_buffer_map (moov, &map, GST_MAP_READ);
4582
4583 if (length != map.size) {
4584 /* Some files have a 'moov' atom at the end of the file which contains
4585 * a terminal 'free' atom where the body of the atom is missing.
4586 * Check for, and permit, this special case.
4587 */
4588 if (map.size >= 8) {
4589 guint8 *final_data = map.data + (map.size - 8);
4590 guint32 final_length = QT_UINT32 (final_data);
4591 guint32 final_fourcc = QT_FOURCC (final_data + 4);
4592
4593 if (final_fourcc == FOURCC_free
4594 && map.size + final_length - 8 == length) {
4595 /* Ok, we've found that special case. Allocate a new buffer with
4596 * that free atom actually present. */
4597 GstBuffer *newmoov = gst_buffer_new_and_alloc (length);
4598 gst_buffer_fill (newmoov, 0, map.data, map.size);
4599 gst_buffer_memset (newmoov, map.size, 0, final_length - 8);
4600 gst_buffer_unmap (moov, &map);
4601 gst_buffer_unref (moov);
4602 moov = newmoov;
4603 gst_buffer_map (moov, &map, GST_MAP_READ);
4604 }
4605 }
4606 }
4607
4608 if (length != map.size) {
4609 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4610 (_("This file is incomplete and cannot be played.")),
4611 ("We got less than expected (received %" G_GSIZE_FORMAT
4612 ", wanted %u, offset %" G_GUINT64_FORMAT ")", map.size,
4613 (guint) length, cur_offset));
4614 gst_buffer_unmap (moov, &map);
4615 gst_buffer_unref (moov);
4616 ret = GST_FLOW_ERROR;
4617 goto beach;
4618 }
4619 qtdemux->offset += length;
4620
4621 qtdemux_parse_moov (qtdemux, map.data, length);
4622 qtdemux_node_dump (qtdemux, qtdemux->moov_node);
4623
4624 qtdemux_parse_tree (qtdemux);
4625 if (qtdemux->moov_node_compressed) {
4626 g_node_destroy (qtdemux->moov_node_compressed);
4627 g_free (qtdemux->moov_node->data);
4628 }
4629 qtdemux->moov_node_compressed = NULL;
4630 g_node_destroy (qtdemux->moov_node);
4631 qtdemux->moov_node = NULL;
4632 gst_buffer_unmap (moov, &map);
4633 gst_buffer_unref (moov);
4634 qtdemux->got_moov = TRUE;
4635
4636 break;
4637 }
4638 case FOURCC_ftyp:
4639 {
4640 GstBuffer *ftyp = NULL;
4641
4642 /* extract major brand; might come in handy for ISO vs QT issues */
4643 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &ftyp);
4644 if (ret != GST_FLOW_OK)
4645 goto beach;
4646 qtdemux->offset += length;
4647 gst_buffer_map (ftyp, &map, GST_MAP_READ);
4648 qtdemux_parse_ftyp (qtdemux, map.data, map.size);
4649 gst_buffer_unmap (ftyp, &map);
4650 gst_buffer_unref (ftyp);
4651 break;
4652 }
4653 case FOURCC_uuid:
4654 {
4655 GstBuffer *uuid = NULL;
4656
4657 /* uuid are extension atoms */
4658 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &uuid);
4659 if (ret != GST_FLOW_OK)
4660 goto beach;
4661 qtdemux->offset += length;
4662 gst_buffer_map (uuid, &map, GST_MAP_READ);
4663 qtdemux_parse_uuid (qtdemux, map.data, map.size);
4664 gst_buffer_unmap (uuid, &map);
4665 gst_buffer_unref (uuid);
4666 break;
4667 }
4668 case FOURCC_sidx:
4669 {
4670 GstBuffer *sidx = NULL;
4671 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &sidx);
4672 if (ret != GST_FLOW_OK)
4673 goto beach;
4674 qtdemux->offset += length;
4675 gst_buffer_map (sidx, &map, GST_MAP_READ);
4676 qtdemux_parse_sidx (qtdemux, map.data, map.size);
4677 gst_buffer_unmap (sidx, &map);
4678 gst_buffer_unref (sidx);
4679 break;
4680 }
4681 default:
4682 {
4683 GstBuffer *unknown = NULL;
4684
4685 GST_LOG_OBJECT (qtdemux,
4686 "unknown %08x '%" GST_FOURCC_FORMAT "' of size %" G_GUINT64_FORMAT
4687 " at %" G_GUINT64_FORMAT, fourcc, GST_FOURCC_ARGS (fourcc), length,
4688 cur_offset);
4689 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &unknown);
4690 if (ret != GST_FLOW_OK)
4691 goto beach;
4692 gst_buffer_map (unknown, &map, GST_MAP_READ);
4693 GST_MEMDUMP ("Unknown tag", map.data, map.size);
4694 gst_buffer_unmap (unknown, &map);
4695 gst_buffer_unref (unknown);
4696 qtdemux->offset += length;
4697 break;
4698 }
4699 }
4700
4701 beach:
4702 if (ret == GST_FLOW_EOS && (qtdemux->got_moov || qtdemux->media_caps)) {
4703 /* digested all data, show what we have */
4704 qtdemux_prepare_streams (qtdemux);
4705 QTDEMUX_EXPOSE_LOCK (qtdemux);
4706 ret = qtdemux_expose_streams (qtdemux);
4707 QTDEMUX_EXPOSE_UNLOCK (qtdemux);
4708
4709 qtdemux->state = QTDEMUX_STATE_MOVIE;
4710 GST_DEBUG_OBJECT (qtdemux, "switching state to STATE_MOVIE (%d)",
4711 qtdemux->state);
4712 return ret;
4713 }
4714 return ret;
4715 }
4716
4717 /* Seeks to the previous keyframe of the indexed stream and
4718 * aligns other streams with respect to the keyframe timestamp
4719 * of indexed stream. Only called in case of Reverse Playback
4720 */
4721 static GstFlowReturn
gst_qtdemux_seek_to_previous_keyframe(GstQTDemux * qtdemux)4722 gst_qtdemux_seek_to_previous_keyframe (GstQTDemux * qtdemux)
4723 {
4724 guint32 seg_idx = 0, k_index = 0;
4725 guint32 ref_seg_idx, ref_k_index;
4726 GstClockTime k_pos = 0, last_stop = 0;
4727 QtDemuxSegment *seg = NULL;
4728 QtDemuxStream *ref_str = NULL;
4729 guint64 seg_media_start_mov; /* segment media start time in mov format */
4730 guint64 target_ts;
4731 gint i;
4732
4733 /* Now we choose an arbitrary stream, get the previous keyframe timestamp
4734 * and finally align all the other streams on that timestamp with their
4735 * respective keyframes */
4736 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
4737 QtDemuxStream *str = QTDEMUX_NTH_STREAM (qtdemux, i);
4738
4739 /* No candidate yet, take the first stream */
4740 if (!ref_str) {
4741 ref_str = str;
4742 continue;
4743 }
4744
4745 /* So that stream has a segment, we prefer video streams */
4746 if (str->subtype == FOURCC_vide) {
4747 ref_str = str;
4748 break;
4749 }
4750 }
4751
4752 if (G_UNLIKELY (!ref_str)) {
4753 GST_DEBUG_OBJECT (qtdemux, "couldn't find any stream");
4754 goto eos;
4755 }
4756
4757 if (G_UNLIKELY (!ref_str->from_sample)) {
4758 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of the file");
4759 goto eos;
4760 }
4761
4762 /* So that stream has been playing from from_sample to to_sample. We will
4763 * get the timestamp of the previous sample and search for a keyframe before
4764 * that. For audio streams we do an arbitrary jump in the past (10 samples) */
4765 if (ref_str->subtype == FOURCC_vide) {
4766 k_index = gst_qtdemux_find_keyframe (qtdemux, ref_str,
4767 ref_str->from_sample - 1, FALSE);
4768 } else {
4769 if (ref_str->from_sample >= 10)
4770 k_index = ref_str->from_sample - 10;
4771 else
4772 k_index = 0;
4773 }
4774
4775 target_ts =
4776 ref_str->samples[k_index].timestamp +
4777 ref_str->samples[k_index].pts_offset;
4778
4779 /* get current segment for that stream */
4780 seg = &ref_str->segments[ref_str->segment_index];
4781 /* Use segment start in original timescale for comparisons */
4782 seg_media_start_mov = seg->trak_media_start;
4783
4784 GST_LOG_OBJECT (qtdemux, "keyframe index %u ts %" G_GUINT64_FORMAT
4785 " seg start %" G_GUINT64_FORMAT " %" GST_TIME_FORMAT,
4786 k_index, target_ts, seg_media_start_mov,
4787 GST_TIME_ARGS (seg->media_start));
4788
4789 /* Crawl back through segments to find the one containing this I frame */
4790 while (target_ts < seg_media_start_mov) {
4791 GST_DEBUG_OBJECT (qtdemux,
4792 "keyframe position (sample %u) is out of segment %u " " target %"
4793 G_GUINT64_FORMAT " seg start %" G_GUINT64_FORMAT, k_index,
4794 ref_str->segment_index, target_ts, seg_media_start_mov);
4795
4796 if (G_UNLIKELY (!ref_str->segment_index)) {
4797 /* Reached first segment, let's consider it's EOS */
4798 goto eos;
4799 }
4800 ref_str->segment_index--;
4801 seg = &ref_str->segments[ref_str->segment_index];
4802 /* Use segment start in original timescale for comparisons */
4803 seg_media_start_mov = seg->trak_media_start;
4804 }
4805 /* Calculate time position of the keyframe and where we should stop */
4806 k_pos =
4807 QTSTREAMTIME_TO_GSTTIME (ref_str,
4808 target_ts - seg->trak_media_start) + seg->time;
4809 last_stop =
4810 QTSTREAMTIME_TO_GSTTIME (ref_str,
4811 ref_str->samples[ref_str->from_sample].timestamp -
4812 seg->trak_media_start) + seg->time;
4813
4814 GST_DEBUG_OBJECT (qtdemux, "preferred stream played from sample %u, "
4815 "now going to sample %u (pts %" GST_TIME_FORMAT ")", ref_str->from_sample,
4816 k_index, GST_TIME_ARGS (k_pos));
4817
4818 /* Set last_stop with the keyframe timestamp we pushed of that stream */
4819 qtdemux->segment.position = last_stop;
4820 GST_DEBUG_OBJECT (qtdemux, "last_stop now is %" GST_TIME_FORMAT,
4821 GST_TIME_ARGS (last_stop));
4822
4823 if (G_UNLIKELY (last_stop < qtdemux->segment.start)) {
4824 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of segment");
4825 goto eos;
4826 }
4827
4828 ref_seg_idx = ref_str->segment_index;
4829 ref_k_index = k_index;
4830
4831 /* Align them all on this */
4832 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
4833 guint32 index = 0;
4834 GstClockTime seg_time = 0;
4835 QtDemuxStream *str = QTDEMUX_NTH_STREAM (qtdemux, i);
4836
4837 /* aligning reference stream again might lead to backing up to yet another
4838 * keyframe (due to timestamp rounding issues),
4839 * potentially putting more load on downstream; so let's try to avoid */
4840 if (str == ref_str) {
4841 seg_idx = ref_seg_idx;
4842 seg = &str->segments[seg_idx];
4843 k_index = ref_k_index;
4844 GST_DEBUG_OBJECT (qtdemux, "reference track-id %u segment %d, "
4845 "sample at index %d", str->track_id, ref_str->segment_index, k_index);
4846 } else {
4847 seg_idx = gst_qtdemux_find_segment (qtdemux, str, k_pos);
4848 GST_DEBUG_OBJECT (qtdemux,
4849 "track-id %u align segment %d for keyframe pos %" GST_TIME_FORMAT,
4850 str->track_id, seg_idx, GST_TIME_ARGS (k_pos));
4851
4852 /* get segment and time in the segment */
4853 seg = &str->segments[seg_idx];
4854 seg_time = k_pos - seg->time;
4855
4856 /* get the media time in the segment.
4857 * No adjustment for empty "filler" segments */
4858 if (seg->media_start != GST_CLOCK_TIME_NONE)
4859 seg_time += seg->media_start;
4860
4861 /* get the index of the sample with media time */
4862 index = gst_qtdemux_find_index_linear (qtdemux, str, seg_time);
4863 GST_DEBUG_OBJECT (qtdemux,
4864 "track-id %u sample for %" GST_TIME_FORMAT " at %u", str->track_id,
4865 GST_TIME_ARGS (seg_time), index);
4866
4867 /* find previous keyframe */
4868 k_index = gst_qtdemux_find_keyframe (qtdemux, str, index, FALSE);
4869 }
4870
4871 /* Remember until where we want to go */
4872 str->to_sample = str->from_sample - 1;
4873 /* Define our time position */
4874 target_ts =
4875 str->samples[k_index].timestamp + str->samples[k_index].pts_offset;
4876 str->time_position = QTSTREAMTIME_TO_GSTTIME (str, target_ts) + seg->time;
4877 if (seg->media_start != GST_CLOCK_TIME_NONE)
4878 str->time_position -= seg->media_start;
4879
4880 /* Now seek back in time */
4881 gst_qtdemux_move_stream (qtdemux, str, k_index);
4882 GST_DEBUG_OBJECT (qtdemux, "track-id %u keyframe at %u, time position %"
4883 GST_TIME_FORMAT " playing from sample %u to %u", str->track_id, k_index,
4884 GST_TIME_ARGS (str->time_position), str->from_sample, str->to_sample);
4885 }
4886
4887 return GST_FLOW_OK;
4888
4889 eos:
4890 return GST_FLOW_EOS;
4891 }
4892
4893 /*
4894 * Gets the current qt segment start, stop and position for the
4895 * given time offset. This is used in update_segment()
4896 */
4897 static void
gst_qtdemux_stream_segment_get_boundaries(GstQTDemux * qtdemux,QtDemuxStream * stream,GstClockTime offset,GstClockTime * _start,GstClockTime * _stop,GstClockTime * _time)4898 gst_qtdemux_stream_segment_get_boundaries (GstQTDemux * qtdemux,
4899 QtDemuxStream * stream, GstClockTime offset,
4900 GstClockTime * _start, GstClockTime * _stop, GstClockTime * _time)
4901 {
4902 GstClockTime seg_time;
4903 GstClockTime start, stop, time;
4904 QtDemuxSegment *segment;
4905
4906 segment = &stream->segments[stream->segment_index];
4907
4908 /* get time in this segment */
4909 seg_time = (offset - segment->time) * segment->rate;
4910
4911 GST_LOG_OBJECT (stream->pad, "seg_time %" GST_TIME_FORMAT,
4912 GST_TIME_ARGS (seg_time));
4913
4914 if (G_UNLIKELY (seg_time > segment->duration)) {
4915 GST_LOG_OBJECT (stream->pad,
4916 "seg_time > segment->duration %" GST_TIME_FORMAT,
4917 GST_TIME_ARGS (segment->duration));
4918 seg_time = segment->duration;
4919 }
4920
4921 /* qtdemux->segment.stop is in outside-time-realm, whereas
4922 * segment->media_stop is in track-time-realm.
4923 *
4924 * In order to compare the two, we need to bring segment.stop
4925 * into the track-time-realm
4926 *
4927 * FIXME - does this comment still hold? Don't see any conversion here */
4928
4929 stop = qtdemux->segment.stop;
4930 if (stop == GST_CLOCK_TIME_NONE)
4931 stop = qtdemux->segment.duration;
4932 if (stop == GST_CLOCK_TIME_NONE)
4933 stop = segment->media_stop;
4934 else
4935 stop =
4936 MIN (segment->media_stop, stop - segment->time + segment->media_start);
4937
4938 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
4939 start = segment->time + seg_time;
4940 time = offset;
4941 stop = start - seg_time + segment->duration;
4942 } else if (qtdemux->segment.rate >= 0) {
4943 start = MIN (segment->media_start + seg_time, stop);
4944 time = offset;
4945 } else {
4946 if (segment->media_start >= qtdemux->segment.start) {
4947 time = segment->time;
4948 } else {
4949 time = segment->time + (qtdemux->segment.start - segment->media_start);
4950 }
4951
4952 start = MAX (segment->media_start, qtdemux->segment.start);
4953 stop = MIN (segment->media_start + seg_time, stop);
4954 }
4955
4956 *_start = start;
4957 *_stop = stop;
4958 *_time = time;
4959 }
4960
4961 /*
4962 * Updates the qt segment used for the stream and pushes a new segment event
4963 * downstream on this stream's pad.
4964 */
4965 static gboolean
gst_qtdemux_stream_update_segment(GstQTDemux * qtdemux,QtDemuxStream * stream,gint seg_idx,GstClockTime offset,GstClockTime * _start,GstClockTime * _stop)4966 gst_qtdemux_stream_update_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
4967 gint seg_idx, GstClockTime offset, GstClockTime * _start,
4968 GstClockTime * _stop)
4969 {
4970 QtDemuxSegment *segment;
4971 GstClockTime start = 0, stop = GST_CLOCK_TIME_NONE, time = 0;
4972 gdouble rate;
4973 GstEvent *event;
4974
4975 /* update the current segment */
4976 stream->segment_index = seg_idx;
4977
4978 /* get the segment */
4979 segment = &stream->segments[seg_idx];
4980
4981 if (G_UNLIKELY (offset < segment->time)) {
4982 GST_WARNING_OBJECT (stream->pad, "offset < segment->time %" GST_TIME_FORMAT,
4983 GST_TIME_ARGS (segment->time));
4984 return FALSE;
4985 }
4986
4987 /* segment lies beyond total indicated duration */
4988 if (G_UNLIKELY (qtdemux->segment.duration != GST_CLOCK_TIME_NONE &&
4989 segment->time > qtdemux->segment.duration)) {
4990 GST_WARNING_OBJECT (stream->pad, "file duration %" GST_TIME_FORMAT
4991 " < segment->time %" GST_TIME_FORMAT,
4992 GST_TIME_ARGS (qtdemux->segment.duration),
4993 GST_TIME_ARGS (segment->time));
4994 return FALSE;
4995 }
4996
4997 gst_qtdemux_stream_segment_get_boundaries (qtdemux, stream, offset,
4998 &start, &stop, &time);
4999
5000 GST_DEBUG_OBJECT (stream->pad, "new segment %d from %" GST_TIME_FORMAT
5001 " to %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT, seg_idx,
5002 GST_TIME_ARGS (start), GST_TIME_ARGS (stop), GST_TIME_ARGS (time));
5003
5004 /* combine global rate with that of the segment */
5005 rate = segment->rate * qtdemux->segment.rate;
5006
5007 /* Copy flags from main segment */
5008 stream->segment.flags = qtdemux->segment.flags;
5009
5010 /* update the segment values used for clipping */
5011 stream->segment.offset = qtdemux->segment.offset;
5012 stream->segment.base = qtdemux->segment.base + stream->accumulated_base;
5013 stream->segment.applied_rate = qtdemux->segment.applied_rate;
5014 stream->segment.rate = rate;
5015 stream->segment.start = start + QTSTREAMTIME_TO_GSTTIME (stream,
5016 stream->cslg_shift);
5017 if (stop != -1)
5018 stream->segment.stop = stop + QTSTREAMTIME_TO_GSTTIME (stream,
5019 stream->cslg_shift);
5020 else
5021 stream->segment.stop = stop;
5022 stream->segment.time = time;
5023 stream->segment.position = stream->segment.start;
5024
5025 GST_DEBUG_OBJECT (stream->pad, "New segment: %" GST_SEGMENT_FORMAT,
5026 &stream->segment);
5027
5028 /* now prepare and send the segment */
5029 if (stream->pad) {
5030 event = gst_event_new_segment (&stream->segment);
5031 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID) {
5032 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
5033 }
5034 gst_pad_push_event (stream->pad, event);
5035 /* assume we can send more data now */
5036 GST_PAD_LAST_FLOW_RETURN (stream->pad) = GST_FLOW_OK;
5037 /* clear to send tags on this pad now */
5038 gst_qtdemux_push_tags (qtdemux, stream);
5039 }
5040
5041 if (_start)
5042 *_start = start;
5043 if (_stop)
5044 *_stop = stop;
5045
5046 return TRUE;
5047 }
5048
5049 /* activate the given segment number @seg_idx of @stream at time @offset.
5050 * @offset is an absolute global position over all the segments.
5051 *
5052 * This will push out a NEWSEGMENT event with the right values and
5053 * position the stream index to the first decodable sample before
5054 * @offset.
5055 */
5056 static gboolean
gst_qtdemux_activate_segment(GstQTDemux * qtdemux,QtDemuxStream * stream,guint32 seg_idx,GstClockTime offset)5057 gst_qtdemux_activate_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
5058 guint32 seg_idx, GstClockTime offset)
5059 {
5060 QtDemuxSegment *segment;
5061 guint32 index, kf_index;
5062 GstClockTime start = 0, stop = GST_CLOCK_TIME_NONE;
5063
5064 GST_LOG_OBJECT (stream->pad, "activate segment %d, offset %" GST_TIME_FORMAT,
5065 seg_idx, GST_TIME_ARGS (offset));
5066
5067 if (!gst_qtdemux_stream_update_segment (qtdemux, stream, seg_idx, offset,
5068 &start, &stop))
5069 return FALSE;
5070
5071 segment = &stream->segments[stream->segment_index];
5072
5073 /* in the fragmented case, we pick a fragment that starts before our
5074 * desired position and rely on downstream to wait for a keyframe
5075 * (FIXME: doesn't seem to work so well with ismv and wmv, as no parser; the
5076 * tfra entries tells us which trun/sample the key unit is in, but we don't
5077 * make use of this additional information at the moment) */
5078 if (qtdemux->fragmented && !qtdemux->fragmented_seek_pending) {
5079 stream->to_sample = G_MAXUINT32;
5080 return TRUE;
5081 } else {
5082 /* well, it will be taken care of below */
5083 qtdemux->fragmented_seek_pending = FALSE;
5084 /* FIXME ideally the do_fragmented_seek can be done right here,
5085 * rather than at loop level
5086 * (which might even allow handling edit lists in a fragmented file) */
5087 }
5088
5089 /* We don't need to look for a sample in push-based */
5090 if (!qtdemux->pullbased)
5091 return TRUE;
5092
5093 /* and move to the keyframe before the indicated media time of the
5094 * segment */
5095 if (G_LIKELY (!QTSEGMENT_IS_EMPTY (segment))) {
5096 if (qtdemux->segment.rate >= 0) {
5097 index = gst_qtdemux_find_index_linear (qtdemux, stream, start);
5098 stream->to_sample = G_MAXUINT32;
5099 GST_DEBUG_OBJECT (stream->pad,
5100 "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
5101 GST_TIME_FORMAT, GST_TIME_ARGS (start), index,
5102 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
5103 } else {
5104 index = gst_qtdemux_find_index_linear (qtdemux, stream, stop);
5105 stream->to_sample = index;
5106 GST_DEBUG_OBJECT (stream->pad,
5107 "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
5108 GST_TIME_FORMAT, GST_TIME_ARGS (stop), index,
5109 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
5110 }
5111 } else {
5112 GST_DEBUG_OBJECT (stream->pad, "No need to look for keyframe, "
5113 "this is an empty segment");
5114 return TRUE;
5115 }
5116
5117 /* gst_qtdemux_parse_sample () called from gst_qtdemux_find_index_linear ()
5118 * encountered an error and printed a message so we return appropriately */
5119 if (index == -1)
5120 return FALSE;
5121
5122 /* we're at the right spot */
5123 if (index == stream->sample_index) {
5124 GST_DEBUG_OBJECT (stream->pad, "we are at the right index");
5125 return TRUE;
5126 }
5127
5128 /* find keyframe of the target index */
5129 kf_index = gst_qtdemux_find_keyframe (qtdemux, stream, index, FALSE);
5130
5131 /* go back two frames to provide lead-in for non-raw audio decoders */
5132 if (stream->subtype == FOURCC_soun && !stream->need_clip) {
5133 guint32 lead_in = 2;
5134 guint32 old_index = kf_index;
5135 GstStructure *s = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
5136
5137 if (gst_structure_has_name (s, "audio/mpeg")) {
5138 gint mpegversion;
5139 if (gst_structure_get_int (s, "mpegversion", &mpegversion)
5140 && mpegversion == 1) {
5141 /* mp3 could need up to 30 frames of lead-in per mpegaudioparse */
5142 lead_in = 30;
5143 }
5144 }
5145
5146 kf_index = MAX (kf_index, lead_in) - lead_in;
5147 if (qtdemux_parse_samples (qtdemux, stream, kf_index)) {
5148 GST_DEBUG_OBJECT (stream->pad,
5149 "Moving backwards %u frames to ensure sufficient sound lead-in",
5150 old_index - kf_index);
5151 } else {
5152 kf_index = old_index;
5153 }
5154 }
5155
5156 /* if we move forwards, we don't have to go back to the previous
5157 * keyframe since we already sent that. We can also just jump to
5158 * the keyframe right before the target index if there is one. */
5159 if (index > stream->sample_index) {
5160 /* moving forwards check if we move past a keyframe */
5161 if (kf_index > stream->sample_index) {
5162 GST_DEBUG_OBJECT (stream->pad,
5163 "moving forwards to keyframe at %u "
5164 "(pts %" GST_TIME_FORMAT " dts %" GST_TIME_FORMAT " )",
5165 kf_index,
5166 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[kf_index])),
5167 GST_TIME_ARGS (QTSAMPLE_DTS (stream, &stream->samples[kf_index])));
5168 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
5169 } else {
5170 GST_DEBUG_OBJECT (stream->pad,
5171 "moving forwards, keyframe at %u "
5172 "(pts %" GST_TIME_FORMAT " dts %" GST_TIME_FORMAT " ) already sent",
5173 kf_index,
5174 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[kf_index])),
5175 GST_TIME_ARGS (QTSAMPLE_DTS (stream, &stream->samples[kf_index])));
5176 }
5177 } else {
5178 GST_DEBUG_OBJECT (stream->pad,
5179 "moving backwards to %sframe at %u "
5180 "(pts %" GST_TIME_FORMAT " dts %" GST_TIME_FORMAT " )",
5181 (stream->subtype == FOURCC_soun) ? "audio " : "key", kf_index,
5182 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[kf_index])),
5183 GST_TIME_ARGS (QTSAMPLE_DTS (stream, &stream->samples[kf_index])));
5184 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
5185 }
5186
5187 return TRUE;
5188 }
5189
5190 /* prepare to get the current sample of @stream, getting essential values.
5191 *
5192 * This function will also prepare and send the segment when needed.
5193 *
5194 * Return FALSE if the stream is EOS.
5195 *
5196 * PULL-BASED
5197 */
5198 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)5199 gst_qtdemux_prepare_current_sample (GstQTDemux * qtdemux,
5200 QtDemuxStream * stream, gboolean * empty, guint64 * offset, guint * size,
5201 GstClockTime * dts, GstClockTime * pts, GstClockTime * duration,
5202 gboolean * keyframe)
5203 {
5204 QtDemuxSample *sample;
5205 GstClockTime time_position;
5206 guint32 seg_idx;
5207
5208 g_return_val_if_fail (stream != NULL, FALSE);
5209
5210 time_position = stream->time_position;
5211 if (G_UNLIKELY (time_position == GST_CLOCK_TIME_NONE))
5212 goto eos;
5213
5214 seg_idx = stream->segment_index;
5215 if (G_UNLIKELY (seg_idx == -1)) {
5216 /* find segment corresponding to time_position if we are looking
5217 * for a segment. */
5218 seg_idx = gst_qtdemux_find_segment (qtdemux, stream, time_position);
5219 }
5220
5221 /* different segment, activate it, sample_index will be set. */
5222 if (G_UNLIKELY (stream->segment_index != seg_idx))
5223 gst_qtdemux_activate_segment (qtdemux, stream, seg_idx, time_position);
5224
5225 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (&stream->
5226 segments[stream->segment_index]))) {
5227 QtDemuxSegment *seg = &stream->segments[stream->segment_index];
5228
5229 GST_LOG_OBJECT (qtdemux, "Empty segment activated,"
5230 " prepare empty sample");
5231
5232 *empty = TRUE;
5233 *pts = *dts = time_position;
5234 *duration = seg->duration - (time_position - seg->time);
5235
5236 return TRUE;
5237 }
5238
5239 *empty = FALSE;
5240
5241 if (stream->sample_index == -1)
5242 stream->sample_index = 0;
5243
5244 GST_LOG_OBJECT (qtdemux, "segment active, index = %u of %u",
5245 stream->sample_index, stream->n_samples);
5246
5247 if (G_UNLIKELY (stream->sample_index >= stream->n_samples)) {
5248 if (!qtdemux->fragmented)
5249 goto eos;
5250
5251 GST_INFO_OBJECT (qtdemux, "out of samples, trying to add more");
5252 do {
5253 GstFlowReturn flow;
5254
5255 GST_OBJECT_LOCK (qtdemux);
5256 flow = qtdemux_add_fragmented_samples (qtdemux);
5257 GST_OBJECT_UNLOCK (qtdemux);
5258
5259 if (flow != GST_FLOW_OK)
5260 goto eos;
5261 }
5262 while (stream->sample_index >= stream->n_samples);
5263 }
5264
5265 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
5266 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
5267 stream->sample_index);
5268 return FALSE;
5269 }
5270
5271 /* now get the info for the sample we're at */
5272 sample = &stream->samples[stream->sample_index];
5273
5274 *dts = QTSAMPLE_DTS (stream, sample);
5275 *pts = QTSAMPLE_PTS (stream, sample);
5276 *offset = sample->offset;
5277 *size = sample->size;
5278 *duration = QTSAMPLE_DUR_DTS (stream, sample, *dts);
5279 *keyframe = QTSAMPLE_KEYFRAME (stream, sample);
5280
5281 return TRUE;
5282
5283 /* special cases */
5284 eos:
5285 {
5286 stream->time_position = GST_CLOCK_TIME_NONE;
5287 return FALSE;
5288 }
5289 }
5290
5291 /* move to the next sample in @stream.
5292 *
5293 * Moves to the next segment when needed.
5294 */
5295 static void
gst_qtdemux_advance_sample(GstQTDemux * qtdemux,QtDemuxStream * stream)5296 gst_qtdemux_advance_sample (GstQTDemux * qtdemux, QtDemuxStream * stream)
5297 {
5298 QtDemuxSample *sample;
5299 QtDemuxSegment *segment;
5300
5301 /* get current segment */
5302 segment = &stream->segments[stream->segment_index];
5303
5304 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
5305 GST_DEBUG_OBJECT (qtdemux, "Empty segment, no samples to advance");
5306 goto next_segment;
5307 }
5308
5309 if (G_UNLIKELY (stream->sample_index >= stream->to_sample)) {
5310 /* Mark the stream as EOS */
5311 GST_DEBUG_OBJECT (qtdemux,
5312 "reached max allowed sample %u, mark EOS", stream->to_sample);
5313 stream->time_position = GST_CLOCK_TIME_NONE;
5314 return;
5315 }
5316
5317 /* move to next sample */
5318 stream->sample_index++;
5319 stream->offset_in_sample = 0;
5320
5321 GST_TRACE_OBJECT (qtdemux, "advance to sample %u/%u", stream->sample_index,
5322 stream->n_samples);
5323
5324 /* reached the last sample, we need the next segment */
5325 if (G_UNLIKELY (stream->sample_index >= stream->n_samples))
5326 goto next_segment;
5327
5328 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
5329 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
5330 stream->sample_index);
5331 return;
5332 }
5333
5334 /* get next sample */
5335 sample = &stream->samples[stream->sample_index];
5336
5337 GST_TRACE_OBJECT (qtdemux, "sample dts %" GST_TIME_FORMAT " media_stop: %"
5338 GST_TIME_FORMAT, GST_TIME_ARGS (QTSAMPLE_DTS (stream, sample)),
5339 GST_TIME_ARGS (segment->media_stop));
5340
5341 /* see if we are past the segment */
5342 if (G_UNLIKELY (QTSAMPLE_DTS (stream, sample) >= segment->media_stop))
5343 goto next_segment;
5344
5345 if (QTSAMPLE_DTS (stream, sample) >= segment->media_start) {
5346 /* inside the segment, update time_position, looks very familiar to
5347 * GStreamer segments, doesn't it? */
5348 stream->time_position =
5349 QTSAMPLE_DTS (stream, sample) - segment->media_start + segment->time;
5350 } else {
5351 /* not yet in segment, time does not yet increment. This means
5352 * that we are still prerolling keyframes to the decoder so it can
5353 * decode the first sample of the segment. */
5354 stream->time_position = segment->time;
5355 }
5356 return;
5357
5358 /* move to the next segment */
5359 next_segment:
5360 {
5361 GST_DEBUG_OBJECT (qtdemux, "segment %d ended ", stream->segment_index);
5362
5363 if (stream->segment_index == stream->n_segments - 1) {
5364 /* are we at the end of the last segment, we're EOS */
5365 stream->time_position = GST_CLOCK_TIME_NONE;
5366 } else {
5367 /* else we're only at the end of the current segment */
5368 stream->time_position = segment->stop_time;
5369 }
5370 /* make sure we select a new segment */
5371
5372 /* accumulate previous segments */
5373 if (GST_CLOCK_TIME_IS_VALID (stream->segment.stop))
5374 stream->accumulated_base +=
5375 (stream->segment.stop -
5376 stream->segment.start) / ABS (stream->segment.rate);
5377
5378 stream->segment_index = -1;
5379 }
5380 }
5381
5382 static void
gst_qtdemux_sync_streams(GstQTDemux * demux)5383 gst_qtdemux_sync_streams (GstQTDemux * demux)
5384 {
5385 gint i;
5386
5387 if (QTDEMUX_N_STREAMS (demux) <= 1)
5388 return;
5389
5390 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
5391 QtDemuxStream *stream;
5392 GstClockTime end_time;
5393
5394 stream = QTDEMUX_NTH_STREAM (demux, i);
5395
5396 if (!stream->pad)
5397 continue;
5398
5399 /* TODO advance time on subtitle streams here, if any some day */
5400
5401 /* some clips/trailers may have unbalanced streams at the end,
5402 * so send EOS on shorter stream to prevent stalling others */
5403
5404 /* do not mess with EOS if SEGMENT seeking */
5405 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT)
5406 continue;
5407
5408 if (demux->pullbased) {
5409 /* loop mode is sample time based */
5410 if (!STREAM_IS_EOS (stream))
5411 continue;
5412 } else {
5413 /* push mode is byte position based */
5414 if (stream->n_samples &&
5415 stream->samples[stream->n_samples - 1].offset >= demux->offset)
5416 continue;
5417 }
5418
5419 if (stream->sent_eos)
5420 continue;
5421
5422 /* only act if some gap */
5423 end_time = stream->segments[stream->n_segments - 1].stop_time;
5424 GST_LOG_OBJECT (demux, "current position: %" GST_TIME_FORMAT
5425 ", stream end: %" GST_TIME_FORMAT,
5426 GST_TIME_ARGS (demux->segment.position), GST_TIME_ARGS (end_time));
5427 if (GST_CLOCK_TIME_IS_VALID (end_time)
5428 && (end_time + 2 * GST_SECOND < demux->segment.position)) {
5429 GstEvent *event;
5430
5431 GST_DEBUG_OBJECT (demux, "sending EOS for stream %s",
5432 GST_PAD_NAME (stream->pad));
5433 stream->sent_eos = TRUE;
5434 event = gst_event_new_eos ();
5435 if (demux->segment_seqnum != GST_SEQNUM_INVALID)
5436 gst_event_set_seqnum (event, demux->segment_seqnum);
5437 gst_pad_push_event (stream->pad, event);
5438 }
5439 }
5440 }
5441
5442 /* EOS and NOT_LINKED need to be combined. This means that we return:
5443 *
5444 * GST_FLOW_NOT_LINKED: when all pads NOT_LINKED.
5445 * GST_FLOW_EOS: when all pads EOS or NOT_LINKED.
5446 */
5447 static GstFlowReturn
gst_qtdemux_combine_flows(GstQTDemux * demux,QtDemuxStream * stream,GstFlowReturn ret)5448 gst_qtdemux_combine_flows (GstQTDemux * demux, QtDemuxStream * stream,
5449 GstFlowReturn ret)
5450 {
5451 GST_LOG_OBJECT (demux, "flow return: %s", gst_flow_get_name (ret));
5452
5453 if (stream->pad)
5454 ret = gst_flow_combiner_update_pad_flow (demux->flowcombiner, stream->pad,
5455 ret);
5456 else
5457 ret = gst_flow_combiner_update_flow (demux->flowcombiner, ret);
5458
5459 GST_LOG_OBJECT (demux, "combined flow return: %s", gst_flow_get_name (ret));
5460 return ret;
5461 }
5462
5463 /* the input buffer metadata must be writable. Returns NULL when the buffer is
5464 * completely clipped
5465 *
5466 * Should be used only with raw buffers */
5467 static GstBuffer *
gst_qtdemux_clip_buffer(GstQTDemux * qtdemux,QtDemuxStream * stream,GstBuffer * buf)5468 gst_qtdemux_clip_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
5469 GstBuffer * buf)
5470 {
5471 guint64 start, stop, cstart, cstop, diff;
5472 GstClockTime pts, duration;
5473 gsize size, osize;
5474 gint num_rate, denom_rate;
5475 gint frame_size;
5476 gboolean clip_data;
5477 guint offset;
5478
5479 osize = size = gst_buffer_get_size (buf);
5480 offset = 0;
5481
5482 /* depending on the type, setup the clip parameters */
5483 if (stream->subtype == FOURCC_soun) {
5484 frame_size = CUR_STREAM (stream)->bytes_per_frame;
5485 num_rate = GST_SECOND;
5486 denom_rate = (gint) CUR_STREAM (stream)->rate;
5487 clip_data = TRUE;
5488 } else if (stream->subtype == FOURCC_vide) {
5489 frame_size = size;
5490 num_rate = CUR_STREAM (stream)->fps_n;
5491 denom_rate = CUR_STREAM (stream)->fps_d;
5492 clip_data = FALSE;
5493 } else
5494 goto wrong_type;
5495
5496 if (frame_size <= 0)
5497 goto bad_frame_size;
5498
5499 /* we can only clip if we have a valid pts */
5500 pts = GST_BUFFER_PTS (buf);
5501 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (pts)))
5502 goto no_pts;
5503
5504 duration = GST_BUFFER_DURATION (buf);
5505
5506 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (duration))) {
5507 duration =
5508 gst_util_uint64_scale_int (size / frame_size, num_rate, denom_rate);
5509 }
5510
5511 start = pts;
5512 stop = start + duration;
5513
5514 if (G_UNLIKELY (!gst_segment_clip (&stream->segment,
5515 GST_FORMAT_TIME, start, stop, &cstart, &cstop)))
5516 goto clipped;
5517
5518 /* see if some clipping happened */
5519 diff = cstart - start;
5520 if (diff > 0) {
5521 pts += diff;
5522 duration -= diff;
5523
5524 if (clip_data) {
5525 /* bring clipped time to samples and to bytes */
5526 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
5527 diff *= frame_size;
5528
5529 GST_DEBUG_OBJECT (qtdemux,
5530 "clipping start to %" GST_TIME_FORMAT " %"
5531 G_GUINT64_FORMAT " bytes", GST_TIME_ARGS (cstart), diff);
5532
5533 offset = diff;
5534 size -= diff;
5535 }
5536 }
5537 diff = stop - cstop;
5538 if (diff > 0) {
5539 duration -= diff;
5540
5541 if (clip_data) {
5542 /* bring clipped time to samples and then to bytes */
5543 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
5544 diff *= frame_size;
5545 GST_DEBUG_OBJECT (qtdemux,
5546 "clipping stop to %" GST_TIME_FORMAT " %" G_GUINT64_FORMAT
5547 " bytes", GST_TIME_ARGS (cstop), diff);
5548 size -= diff;
5549 }
5550 }
5551
5552 if (offset != 0 || size != osize)
5553 gst_buffer_resize (buf, offset, size);
5554
5555 GST_BUFFER_DTS (buf) = GST_CLOCK_TIME_NONE;
5556 GST_BUFFER_PTS (buf) = pts;
5557 GST_BUFFER_DURATION (buf) = duration;
5558
5559 return buf;
5560
5561 /* dropped buffer */
5562 wrong_type:
5563 {
5564 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
5565 return buf;
5566 }
5567 bad_frame_size:
5568 {
5569 GST_DEBUG_OBJECT (qtdemux, "bad frame size");
5570 return buf;
5571 }
5572 no_pts:
5573 {
5574 GST_DEBUG_OBJECT (qtdemux, "no pts on buffer");
5575 return buf;
5576 }
5577 clipped:
5578 {
5579 GST_DEBUG_OBJECT (qtdemux, "clipped buffer");
5580 gst_buffer_unref (buf);
5581 return NULL;
5582 }
5583 }
5584
5585 static GstBuffer *
gst_qtdemux_align_buffer(GstQTDemux * demux,GstBuffer * buffer,gsize alignment)5586 gst_qtdemux_align_buffer (GstQTDemux * demux,
5587 GstBuffer * buffer, gsize alignment)
5588 {
5589 GstMapInfo map;
5590
5591 gst_buffer_map (buffer, &map, GST_MAP_READ);
5592
5593 if (map.size < sizeof (guintptr)) {
5594 gst_buffer_unmap (buffer, &map);
5595 return buffer;
5596 }
5597
5598 if (((guintptr) map.data) & (alignment - 1)) {
5599 GstBuffer *new_buffer;
5600 GstAllocationParams params = { 0, alignment - 1, 0, 0, };
5601
5602 new_buffer = gst_buffer_new_allocate (NULL,
5603 gst_buffer_get_size (buffer), ¶ms);
5604
5605 /* Copy data "by hand", so ensure alignment is kept: */
5606 gst_buffer_fill (new_buffer, 0, map.data, map.size);
5607
5608 gst_buffer_copy_into (new_buffer, buffer, GST_BUFFER_COPY_METADATA, 0, -1);
5609 GST_DEBUG_OBJECT (demux,
5610 "We want output aligned on %" G_GSIZE_FORMAT ", reallocated",
5611 alignment);
5612
5613 gst_buffer_unmap (buffer, &map);
5614 gst_buffer_unref (buffer);
5615
5616 return new_buffer;
5617 }
5618
5619 gst_buffer_unmap (buffer, &map);
5620 return buffer;
5621 }
5622
5623 static guint8 *
convert_to_s334_1a(const guint8 * ccpair,guint8 ccpair_size,guint field,gsize * res)5624 convert_to_s334_1a (const guint8 * ccpair, guint8 ccpair_size, guint field,
5625 gsize * res)
5626 {
5627 guint8 *storage;
5628 gsize i;
5629
5630 /* We are converting from pairs to triplets */
5631 *res = ccpair_size / 2 * 3;
5632 storage = g_malloc (*res);
5633 for (i = 0; i * 2 < ccpair_size; i += 1) {
5634 /* FIXME: Use line offset 0 as we simply can't know here */
5635 if (field == 1)
5636 storage[i * 3] = 0x80 | 0x00;
5637 else
5638 storage[i * 3] = 0x00 | 0x00;
5639 storage[i * 3 + 1] = ccpair[i * 2];
5640 storage[i * 3 + 2] = ccpair[i * 2 + 1];
5641 }
5642
5643 return storage;
5644 }
5645
5646 static guint8 *
extract_cc_from_data(QtDemuxStream * stream,const guint8 * data,gsize size,gsize * cclen)5647 extract_cc_from_data (QtDemuxStream * stream, const guint8 * data, gsize size,
5648 gsize * cclen)
5649 {
5650 guint8 *res = NULL;
5651 guint32 atom_length, fourcc;
5652 QtDemuxStreamStsdEntry *stsd_entry;
5653
5654 GST_MEMDUMP ("caption atom", data, size);
5655
5656 /* There might be multiple atoms */
5657
5658 *cclen = 0;
5659 if (size < 8)
5660 goto invalid_cdat;
5661 atom_length = QT_UINT32 (data);
5662 fourcc = QT_FOURCC (data + 4);
5663 if (G_UNLIKELY (atom_length > size || atom_length == 8))
5664 goto invalid_cdat;
5665
5666 GST_DEBUG_OBJECT (stream->pad, "here");
5667
5668 /* Check if we have something compatible */
5669 stsd_entry = CUR_STREAM (stream);
5670 switch (stsd_entry->fourcc) {
5671 case FOURCC_c608:{
5672 guint8 *cdat = NULL, *cdt2 = NULL;
5673 gsize cdat_size = 0, cdt2_size = 0;
5674 /* Should be cdat or cdt2 */
5675 if (fourcc != FOURCC_cdat && fourcc != FOURCC_cdt2) {
5676 GST_WARNING_OBJECT (stream->pad,
5677 "Unknown data atom (%" GST_FOURCC_FORMAT ") for CEA608",
5678 GST_FOURCC_ARGS (fourcc));
5679 goto invalid_cdat;
5680 }
5681
5682 /* Convert to S334-1 Annex A byte triplet */
5683 if (fourcc == FOURCC_cdat)
5684 cdat = convert_to_s334_1a (data + 8, atom_length - 8, 1, &cdat_size);
5685 else
5686 cdt2 = convert_to_s334_1a (data + 8, atom_length - 8, 2, &cdt2_size);
5687 GST_DEBUG_OBJECT (stream->pad, "size:%" G_GSIZE_FORMAT " atom_length:%u",
5688 size, atom_length);
5689
5690 /* Check for another atom ? */
5691 if (size > atom_length + 8) {
5692 guint32 new_atom_length = QT_UINT32 (data + atom_length);
5693 if (size >= atom_length + new_atom_length) {
5694 fourcc = QT_FOURCC (data + atom_length + 4);
5695 if (fourcc == FOURCC_cdat) {
5696 if (cdat == NULL)
5697 cdat =
5698 convert_to_s334_1a (data + atom_length + 8,
5699 new_atom_length - 8, 1, &cdat_size);
5700 else
5701 GST_WARNING_OBJECT (stream->pad,
5702 "Got multiple [cdat] atoms in a c608 sample. This is unsupported for now. Please file a bug");
5703 } else {
5704 if (cdt2 == NULL)
5705 cdt2 =
5706 convert_to_s334_1a (data + atom_length + 8,
5707 new_atom_length - 8, 2, &cdt2_size);
5708 else
5709 GST_WARNING_OBJECT (stream->pad,
5710 "Got multiple [cdt2] atoms in a c608 sample. This is unsupported for now. Please file a bug");
5711 }
5712 }
5713 }
5714
5715 *cclen = cdat_size + cdt2_size;
5716 res = g_malloc (*cclen);
5717 if (cdat_size)
5718 memcpy (res, cdat, cdat_size);
5719 if (cdt2_size)
5720 memcpy (res + cdat_size, cdt2, cdt2_size);
5721 g_free (cdat);
5722 g_free (cdt2);
5723 }
5724 break;
5725 case FOURCC_c708:
5726 if (fourcc != FOURCC_ccdp) {
5727 GST_WARNING_OBJECT (stream->pad,
5728 "Unknown data atom (%" GST_FOURCC_FORMAT ") for CEA708",
5729 GST_FOURCC_ARGS (fourcc));
5730 goto invalid_cdat;
5731 }
5732 *cclen = atom_length - 8;
5733 res = g_memdup2 (data + 8, *cclen);
5734 break;
5735 default:
5736 /* Keep this here in case other closed caption formats are added */
5737 g_assert_not_reached ();
5738 break;
5739 }
5740
5741 GST_MEMDUMP ("Output", res, *cclen);
5742 return res;
5743
5744 /* Errors */
5745 invalid_cdat:
5746 GST_WARNING ("[cdat] atom is too small or invalid");
5747 return NULL;
5748 }
5749
5750 /* Handle Closed Caption sample buffers.
5751 * The input buffer metadata must be writable,
5752 * but time/duration etc not yet set and need not be preserved */
5753 static GstBuffer *
gst_qtdemux_process_buffer_clcp(GstQTDemux * qtdemux,QtDemuxStream * stream,GstBuffer * buf)5754 gst_qtdemux_process_buffer_clcp (GstQTDemux * qtdemux, QtDemuxStream * stream,
5755 GstBuffer * buf)
5756 {
5757 GstBuffer *outbuf = NULL;
5758 GstMapInfo map;
5759 guint8 *cc;
5760 gsize cclen = 0;
5761
5762 gst_buffer_map (buf, &map, GST_MAP_READ);
5763
5764 /* empty buffer is sent to terminate previous subtitle */
5765 if (map.size <= 2) {
5766 gst_buffer_unmap (buf, &map);
5767 gst_buffer_unref (buf);
5768 return NULL;
5769 }
5770
5771 /* For closed caption, we need to extract the information from the
5772 * [cdat],[cdt2] or [ccdp] atom */
5773 cc = extract_cc_from_data (stream, map.data, map.size, &cclen);
5774 gst_buffer_unmap (buf, &map);
5775 if (cc) {
5776 outbuf = _gst_buffer_new_wrapped (cc, cclen, g_free);
5777 gst_buffer_copy_into (outbuf, buf, GST_BUFFER_COPY_METADATA, 0, -1);
5778 } else {
5779 /* Conversion failed or there's nothing */
5780 }
5781 gst_buffer_unref (buf);
5782
5783 return outbuf;
5784 }
5785
5786 /* DVD subpicture specific sample handling.
5787 * the input buffer metadata must be writable,
5788 * but time/duration etc not yet set and need not be preserved */
5789 static GstBuffer *
gst_qtdemux_process_buffer_dvd(GstQTDemux * qtdemux,QtDemuxStream * stream,GstBuffer * buf)5790 gst_qtdemux_process_buffer_dvd (GstQTDemux * qtdemux, QtDemuxStream * stream,
5791 GstBuffer * buf)
5792 {
5793 /* send a one time dvd clut event */
5794 if (stream->pending_event && stream->pad)
5795 gst_pad_push_event (stream->pad, stream->pending_event);
5796 stream->pending_event = NULL;
5797
5798 /* empty buffer is sent to terminate previous subtitle */
5799 if (gst_buffer_get_size (buf) <= 2) {
5800 gst_buffer_unref (buf);
5801 return NULL;
5802 }
5803
5804 /* That's all the processing needed for subpictures */
5805 return buf;
5806 }
5807
5808 /* Timed text formats
5809 * the input buffer metadata must be writable,
5810 * but time/duration etc not yet set and need not be preserved */
5811 static GstBuffer *
gst_qtdemux_process_buffer_text(GstQTDemux * qtdemux,QtDemuxStream * stream,GstBuffer * buf)5812 gst_qtdemux_process_buffer_text (GstQTDemux * qtdemux, QtDemuxStream * stream,
5813 GstBuffer * buf)
5814 {
5815 GstBuffer *outbuf = NULL;
5816 GstMapInfo map;
5817 guint nsize = 0;
5818 gchar *str;
5819
5820 /* not many cases for now */
5821 if (G_UNLIKELY (stream->subtype != FOURCC_text &&
5822 stream->subtype != FOURCC_sbtl)) {
5823 return buf;
5824 }
5825
5826 gst_buffer_map (buf, &map, GST_MAP_READ);
5827
5828 /* empty buffer is sent to terminate previous subtitle */
5829 if (map.size <= 2) {
5830 gst_buffer_unmap (buf, &map);
5831 gst_buffer_unref (buf);
5832 return NULL;
5833 }
5834
5835 nsize = GST_READ_UINT16_BE (map.data);
5836 nsize = MIN (nsize, map.size - 2);
5837
5838 GST_LOG_OBJECT (qtdemux, "3GPP timed text subtitle: %d/%" G_GSIZE_FORMAT "",
5839 nsize, map.size);
5840
5841 /* takes care of UTF-8 validation or UTF-16 recognition,
5842 * no other encoding expected */
5843 str = gst_tag_freeform_string_to_utf8 ((gchar *) map.data + 2, nsize, NULL);
5844 gst_buffer_unmap (buf, &map);
5845
5846 if (str) {
5847 outbuf = _gst_buffer_new_wrapped (str, strlen (str), g_free);
5848 gst_buffer_copy_into (outbuf, buf, GST_BUFFER_COPY_METADATA, 0, -1);
5849 } else {
5850 /* this should not really happen unless the subtitle is corrupted */
5851 }
5852 gst_buffer_unref (buf);
5853
5854 /* FIXME ? convert optional subsequent style info to markup */
5855
5856 return outbuf;
5857 }
5858
5859 /* WebVTT sample handling according to 14496-30 */
5860 static GstBuffer *
gst_qtdemux_process_buffer_wvtt(GstQTDemux * qtdemux,QtDemuxStream * stream,GstBuffer * buf)5861 gst_qtdemux_process_buffer_wvtt (GstQTDemux * qtdemux, QtDemuxStream * stream,
5862 GstBuffer * buf)
5863 {
5864 GstBuffer *outbuf = NULL;
5865 GstMapInfo map;
5866
5867 if (!gst_buffer_map (buf, &map, GST_MAP_READ)) {
5868 g_assert_not_reached (); /* The buffer must be mappable */
5869 }
5870
5871 if (qtdemux_webvtt_is_empty (qtdemux, map.data, map.size)) {
5872 GstEvent *gap = NULL;
5873 /* Push a gap event */
5874 stream->segment.position = GST_BUFFER_PTS (buf);
5875 gap =
5876 gst_event_new_gap (stream->segment.position, GST_BUFFER_DURATION (buf));
5877 gst_pad_push_event (stream->pad, gap);
5878
5879 if (GST_BUFFER_DURATION_IS_VALID (buf))
5880 stream->segment.position += GST_BUFFER_DURATION (buf);
5881 } else {
5882 outbuf =
5883 qtdemux_webvtt_decode (qtdemux, GST_BUFFER_PTS (buf),
5884 GST_BUFFER_DURATION (buf), map.data, map.size);
5885 gst_buffer_copy_into (outbuf, buf, GST_BUFFER_COPY_METADATA, 0, -1);
5886 }
5887
5888 gst_buffer_unmap (buf, &map);
5889 gst_buffer_unref (buf);
5890
5891 return outbuf;
5892 }
5893
5894 #ifdef OHOS_OPT_PERFORMANCE // ohos.opt.performance.0001: demux push first audio/video frame
5895 static void
kpi_log_demux_push_first_frame(GstQTDemux * qtdemux,QtDemuxStream * stream)5896 kpi_log_demux_push_first_frame (GstQTDemux *qtdemux, QtDemuxStream *stream)
5897 {
5898 if (stream->has_push_first_frame) {
5899 return;
5900 }
5901
5902 if (stream->subtype == FOURCC_vide && stream->on_keyframe) {
5903 stream->has_push_first_frame = TRUE;
5904 GST_WARNING_OBJECT(qtdemux, "KPI-TRACE: FIRST-VIDEO-FRAME demux push first video keyframe");
5905 } else if (stream->subtype == FOURCC_soun) {
5906 stream->has_push_first_frame = TRUE;
5907 GST_WARNING_OBJECT(qtdemux, "KPI-TRACE: demux push first audio frame");
5908 }
5909 }
5910 #endif
5911
5912 static GstFlowReturn
gst_qtdemux_push_buffer(GstQTDemux * qtdemux,QtDemuxStream * stream,GstBuffer * buf)5913 gst_qtdemux_push_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
5914 GstBuffer * buf)
5915 {
5916 GstFlowReturn ret = GST_FLOW_OK;
5917 GstClockTime pts, duration;
5918
5919 if (stream->need_clip)
5920 buf = gst_qtdemux_clip_buffer (qtdemux, stream, buf);
5921
5922 if (G_UNLIKELY (buf == NULL))
5923 goto exit;
5924
5925 if (G_UNLIKELY (stream->discont)) {
5926 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
5927 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
5928 stream->discont = FALSE;
5929 } else {
5930 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
5931 }
5932
5933 GST_LOG_OBJECT (qtdemux,
5934 "Pushing buffer with dts %" GST_TIME_FORMAT ", pts %" GST_TIME_FORMAT
5935 ", duration %" GST_TIME_FORMAT " on pad %s",
5936 GST_TIME_ARGS (GST_BUFFER_DTS (buf)),
5937 GST_TIME_ARGS (GST_BUFFER_PTS (buf)),
5938 GST_TIME_ARGS (GST_BUFFER_DURATION (buf)), GST_PAD_NAME (stream->pad));
5939
5940 if (stream->protected && stream->protection_scheme_type == FOURCC_aavd) {
5941 GstStructure *crypto_info;
5942 QtDemuxAavdEncryptionInfo *info =
5943 (QtDemuxAavdEncryptionInfo *) stream->protection_scheme_info;
5944
5945 crypto_info = gst_structure_copy (info->default_properties);
5946 if (!crypto_info || !gst_buffer_add_protection_meta (buf, crypto_info))
5947 GST_ERROR_OBJECT (qtdemux, "failed to attach aavd metadata to buffer");
5948 }
5949
5950 if (stream->protected && (stream->protection_scheme_type == FOURCC_cenc
5951 || stream->protection_scheme_type == FOURCC_cbcs)) {
5952 GstStructure *crypto_info;
5953 QtDemuxCencSampleSetInfo *info =
5954 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
5955 gint index;
5956 GstEvent *event;
5957
5958 while ((event = g_queue_pop_head (&stream->protection_scheme_event_queue))) {
5959 GST_TRACE_OBJECT (stream->pad, "pushing protection event: %"
5960 GST_PTR_FORMAT, event);
5961 gst_pad_push_event (stream->pad, event);
5962 }
5963
5964 if (info->crypto_info == NULL) {
5965 if (stream->protection_scheme_type == FOURCC_cbcs) {
5966 crypto_info = qtdemux_get_cenc_sample_properties (qtdemux, stream, 0);
5967 if (!crypto_info || !gst_buffer_add_protection_meta (buf, crypto_info)) {
5968 GST_ERROR_OBJECT (qtdemux,
5969 "failed to attach cbcs metadata to buffer");
5970 qtdemux_gst_structure_free (crypto_info);
5971 } else {
5972 GST_TRACE_OBJECT (qtdemux, "added cbcs protection metadata");
5973 }
5974 } else {
5975 GST_DEBUG_OBJECT (qtdemux,
5976 "cenc metadata hasn't been parsed yet, pushing buffer as if it wasn't encrypted");
5977 }
5978 } else {
5979 /* The end of the crypto_info array matches our n_samples position,
5980 * so count backward from there */
5981 index = stream->sample_index - stream->n_samples + info->crypto_info->len;
5982 if (G_LIKELY (index >= 0 && index < info->crypto_info->len)) {
5983 /* steal structure from array */
5984 crypto_info = g_ptr_array_index (info->crypto_info, index);
5985 g_ptr_array_index (info->crypto_info, index) = NULL;
5986 GST_LOG_OBJECT (qtdemux, "attaching cenc metadata [%u/%u]", index,
5987 info->crypto_info->len);
5988 if (!crypto_info || !gst_buffer_add_protection_meta (buf, crypto_info))
5989 GST_ERROR_OBJECT (qtdemux,
5990 "failed to attach cenc metadata to buffer");
5991 } else {
5992 GST_INFO_OBJECT (qtdemux, "No crypto info with index %d and sample %d",
5993 index, stream->sample_index);
5994 }
5995 }
5996 }
5997
5998 if (stream->alignment > 1)
5999 buf = gst_qtdemux_align_buffer (qtdemux, buf, stream->alignment);
6000
6001 pts = GST_BUFFER_PTS (buf);
6002 duration = GST_BUFFER_DURATION (buf);
6003
6004 #ifdef OHOS_OPT_PERFORMANCE // ohos.opt.performance.0001: add log for kpi
6005 kpi_log_demux_push_first_frame (qtdemux, stream);
6006 #endif
6007 ret = gst_pad_push (stream->pad, buf);
6008
6009 if (GST_CLOCK_TIME_IS_VALID (pts) && GST_CLOCK_TIME_IS_VALID (duration)) {
6010 /* mark position in stream, we'll need this to know when to send GAP event */
6011 stream->segment.position = pts + duration;
6012 }
6013
6014 exit:
6015
6016 return ret;
6017 }
6018
6019 static GstFlowReturn
gst_qtdemux_split_and_push_buffer(GstQTDemux * qtdemux,QtDemuxStream * stream,GstBuffer * buf)6020 gst_qtdemux_split_and_push_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
6021 GstBuffer * buf)
6022 {
6023 GstFlowReturn ret = GST_FLOW_OK;
6024
6025 if (stream->subtype == FOURCC_clcp
6026 && CUR_STREAM (stream)->fourcc == FOURCC_c608 && stream->need_split) {
6027 GstMapInfo map;
6028 guint n_output_buffers, n_field1 = 0, n_field2 = 0;
6029 guint n_triplets, i;
6030 guint field1_off = 0, field2_off = 0;
6031
6032 /* We have to split CEA608 buffers so that each outgoing buffer contains
6033 * one byte pair per field according to the framerate of the video track.
6034 *
6035 * If there is only a single byte pair per field we don't have to do
6036 * anything
6037 */
6038
6039 gst_buffer_map (buf, &map, GST_MAP_READ);
6040
6041 n_triplets = map.size / 3;
6042 for (i = 0; i < n_triplets; i++) {
6043 if (map.data[3 * i] & 0x80)
6044 n_field1++;
6045 else
6046 n_field2++;
6047 }
6048
6049 g_assert (n_field1 || n_field2);
6050
6051 /* If there's more than 1 frame we have to split, otherwise we can just
6052 * pass through */
6053 if (n_field1 > 1 || n_field2 > 1) {
6054 n_output_buffers =
6055 gst_util_uint64_scale (GST_BUFFER_DURATION (buf),
6056 CUR_STREAM (stream)->fps_n, GST_SECOND * CUR_STREAM (stream)->fps_d);
6057
6058 for (i = 0; i < n_output_buffers; i++) {
6059 GstBuffer *outbuf =
6060 gst_buffer_new_and_alloc ((n_field1 ? 3 : 0) + (n_field2 ? 3 : 0));
6061 GstMapInfo outmap;
6062 guint8 *outptr;
6063
6064 gst_buffer_map (outbuf, &outmap, GST_MAP_WRITE);
6065 outptr = outmap.data;
6066
6067 if (n_field1) {
6068 gboolean found = FALSE;
6069
6070 while (map.data + field1_off < map.data + map.size) {
6071 if (map.data[field1_off] & 0x80) {
6072 memcpy (outptr, &map.data[field1_off], 3);
6073 field1_off += 3;
6074 found = TRUE;
6075 break;
6076 }
6077 field1_off += 3;
6078 }
6079
6080 if (!found) {
6081 const guint8 empty[] = { 0x80, 0x80, 0x80 };
6082
6083 memcpy (outptr, empty, 3);
6084 }
6085
6086 outptr += 3;
6087 }
6088
6089 if (n_field2) {
6090 gboolean found = FALSE;
6091
6092 while (map.data + field2_off < map.data + map.size) {
6093 if ((map.data[field2_off] & 0x80) == 0) {
6094 memcpy (outptr, &map.data[field2_off], 3);
6095 field2_off += 3;
6096 found = TRUE;
6097 break;
6098 }
6099 field2_off += 3;
6100 }
6101
6102 if (!found) {
6103 const guint8 empty[] = { 0x00, 0x80, 0x80 };
6104
6105 memcpy (outptr, empty, 3);
6106 }
6107
6108 outptr += 3;
6109 }
6110
6111 gst_buffer_unmap (outbuf, &outmap);
6112
6113 GST_BUFFER_PTS (outbuf) =
6114 GST_BUFFER_PTS (buf) + gst_util_uint64_scale (i,
6115 GST_SECOND * CUR_STREAM (stream)->fps_d,
6116 CUR_STREAM (stream)->fps_n);
6117 GST_BUFFER_DURATION (outbuf) =
6118 gst_util_uint64_scale (GST_SECOND, CUR_STREAM (stream)->fps_d,
6119 CUR_STREAM (stream)->fps_n);
6120 GST_BUFFER_OFFSET (outbuf) = -1;
6121 GST_BUFFER_OFFSET_END (outbuf) = -1;
6122
6123 ret = gst_qtdemux_push_buffer (qtdemux, stream, outbuf);
6124
6125 if (ret != GST_FLOW_OK && ret != GST_FLOW_NOT_LINKED)
6126 break;
6127 }
6128 gst_buffer_unmap (buf, &map);
6129 gst_buffer_unref (buf);
6130 } else {
6131 gst_buffer_unmap (buf, &map);
6132 ret = gst_qtdemux_push_buffer (qtdemux, stream, buf);
6133 }
6134 } else {
6135 ret = gst_qtdemux_push_buffer (qtdemux, stream, buf);
6136 }
6137
6138 return ret;
6139 }
6140
6141 /* Sets a buffer's attributes properly and pushes it downstream.
6142 * Also checks for additional actions and custom processing that may
6143 * need to be done first.
6144 */
6145 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)6146 gst_qtdemux_decorate_and_push_buffer (GstQTDemux * qtdemux,
6147 QtDemuxStream * stream, GstBuffer * buf,
6148 GstClockTime dts, GstClockTime pts, GstClockTime duration,
6149 gboolean keyframe, GstClockTime position, guint64 byte_position)
6150 {
6151 GstFlowReturn ret = GST_FLOW_OK;
6152
6153 /* offset the timestamps according to the edit list */
6154
6155 if (G_UNLIKELY (CUR_STREAM (stream)->fourcc == FOURCC_rtsp)) {
6156 gchar *url;
6157 GstMapInfo map;
6158
6159 gst_buffer_map (buf, &map, GST_MAP_READ);
6160 url = g_strndup ((gchar *) map.data, map.size);
6161 gst_buffer_unmap (buf, &map);
6162 if (url != NULL && strlen (url) != 0) {
6163 /* we have RTSP redirect now */
6164 g_free (qtdemux->redirect_location);
6165 qtdemux->redirect_location = g_strdup (url);
6166 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
6167 gst_message_new_element (GST_OBJECT_CAST (qtdemux),
6168 gst_structure_new ("redirect",
6169 "new-location", G_TYPE_STRING, url, NULL)));
6170 } else {
6171 GST_WARNING_OBJECT (qtdemux, "Redirect URI of stream is empty, not "
6172 "posting");
6173 }
6174 g_free (url);
6175 }
6176
6177 /* position reporting */
6178 if (qtdemux->segment.rate >= 0) {
6179 qtdemux->segment.position = position;
6180 gst_qtdemux_sync_streams (qtdemux);
6181 }
6182
6183 if (G_UNLIKELY (!stream->pad)) {
6184 GST_DEBUG_OBJECT (qtdemux, "No output pad for stream, ignoring");
6185 gst_buffer_unref (buf);
6186 goto exit;
6187 }
6188
6189 /* send out pending buffers */
6190 while (stream->buffers) {
6191 GstBuffer *buffer = (GstBuffer *) stream->buffers->data;
6192
6193 if (G_UNLIKELY (stream->discont)) {
6194 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
6195 GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
6196 stream->discont = FALSE;
6197 } else {
6198 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
6199 }
6200
6201 if (stream->alignment > 1)
6202 buffer = gst_qtdemux_align_buffer (qtdemux, buffer, stream->alignment);
6203 gst_pad_push (stream->pad, buffer);
6204
6205 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
6206 }
6207
6208 /* we're going to modify the metadata */
6209 buf = gst_buffer_make_writable (buf);
6210
6211 GST_BUFFER_DTS (buf) = dts;
6212 GST_BUFFER_PTS (buf) = pts;
6213 GST_BUFFER_DURATION (buf) = duration;
6214 GST_BUFFER_OFFSET (buf) = -1;
6215 GST_BUFFER_OFFSET_END (buf) = -1;
6216
6217 if (G_UNLIKELY (stream->process_func))
6218 buf = stream->process_func (qtdemux, stream, buf);
6219
6220 if (!buf) {
6221 goto exit;
6222 }
6223
6224 if (!keyframe) {
6225 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
6226 stream->on_keyframe = FALSE;
6227 } else {
6228 stream->on_keyframe = TRUE;
6229 }
6230
6231 if (G_UNLIKELY (CUR_STREAM (stream)->rgb8_palette))
6232 gst_buffer_append_memory (buf,
6233 gst_memory_ref (CUR_STREAM (stream)->rgb8_palette));
6234
6235 if (G_UNLIKELY (CUR_STREAM (stream)->padding)) {
6236 gst_buffer_resize (buf, CUR_STREAM (stream)->padding, -1);
6237 }
6238 #if 0
6239 if (G_UNLIKELY (qtdemux->element_index)) {
6240 GstClockTime stream_time;
6241
6242 stream_time =
6243 gst_segment_to_stream_time (&stream->segment, GST_FORMAT_TIME,
6244 timestamp);
6245 if (GST_CLOCK_TIME_IS_VALID (stream_time)) {
6246 GST_LOG_OBJECT (qtdemux,
6247 "adding association %" GST_TIME_FORMAT "-> %"
6248 G_GUINT64_FORMAT, GST_TIME_ARGS (stream_time), byte_position);
6249 gst_index_add_association (qtdemux->element_index,
6250 qtdemux->index_id,
6251 keyframe ? GST_ASSOCIATION_FLAG_KEY_UNIT :
6252 GST_ASSOCIATION_FLAG_DELTA_UNIT, GST_FORMAT_TIME, stream_time,
6253 GST_FORMAT_BYTES, byte_position, NULL);
6254 }
6255 }
6256 #endif
6257
6258 ret = gst_qtdemux_split_and_push_buffer (qtdemux, stream, buf);
6259
6260 exit:
6261 return ret;
6262 }
6263
6264 static const QtDemuxRandomAccessEntry *
gst_qtdemux_stream_seek_fragment(GstQTDemux * qtdemux,QtDemuxStream * stream,GstClockTime pos,gboolean after)6265 gst_qtdemux_stream_seek_fragment (GstQTDemux * qtdemux, QtDemuxStream * stream,
6266 GstClockTime pos, gboolean after)
6267 {
6268 QtDemuxRandomAccessEntry *entries = stream->ra_entries;
6269 guint n_entries = stream->n_ra_entries;
6270 guint i;
6271
6272 /* we assume the table is sorted */
6273 for (i = 0; i < n_entries; ++i) {
6274 if (entries[i].ts > pos)
6275 break;
6276 }
6277
6278 /* FIXME: maybe save first moof_offset somewhere instead, but for now it's
6279 * probably okay to assume that the index lists the very first fragment */
6280 if (i == 0)
6281 return &entries[0];
6282
6283 if (after)
6284 return &entries[i];
6285 else
6286 return &entries[i - 1];
6287 }
6288
6289 static gboolean
gst_qtdemux_do_fragmented_seek(GstQTDemux * qtdemux)6290 gst_qtdemux_do_fragmented_seek (GstQTDemux * qtdemux)
6291 {
6292 const QtDemuxRandomAccessEntry *best_entry = NULL;
6293 gint i;
6294
6295 GST_OBJECT_LOCK (qtdemux);
6296
6297 g_assert (QTDEMUX_N_STREAMS (qtdemux) > 0);
6298
6299 /* first see if we can determine where to go to using mfra,
6300 * before we start clearing things */
6301 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
6302 const QtDemuxRandomAccessEntry *entry;
6303 QtDemuxStream *stream;
6304 gboolean is_audio_or_video;
6305
6306 stream = QTDEMUX_NTH_STREAM (qtdemux, i);
6307
6308 if (stream->ra_entries == NULL)
6309 continue;
6310
6311 if (stream->subtype == FOURCC_vide || stream->subtype == FOURCC_soun)
6312 is_audio_or_video = TRUE;
6313 else
6314 is_audio_or_video = FALSE;
6315
6316 entry =
6317 gst_qtdemux_stream_seek_fragment (qtdemux, stream,
6318 stream->time_position, !is_audio_or_video);
6319
6320 GST_INFO_OBJECT (stream->pad, "%" GST_TIME_FORMAT " at offset "
6321 "%" G_GUINT64_FORMAT, GST_TIME_ARGS (entry->ts), entry->moof_offset);
6322
6323 stream->pending_seek = entry;
6324
6325 /* decide position to jump to just based on audio/video tracks, not subs */
6326 if (!is_audio_or_video)
6327 continue;
6328
6329 if (best_entry == NULL || entry->moof_offset < best_entry->moof_offset)
6330 best_entry = entry;
6331 }
6332
6333 /* no luck, will handle seek otherwise */
6334 if (best_entry == NULL) {
6335 GST_OBJECT_UNLOCK (qtdemux);
6336 return FALSE;
6337 }
6338
6339 /* ok, now we can prepare for processing as of located moof */
6340 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
6341 QtDemuxStream *stream;
6342
6343 stream = QTDEMUX_NTH_STREAM (qtdemux, i);
6344
6345 g_free (stream->samples);
6346 stream->samples = NULL;
6347 stream->n_samples = 0;
6348 stream->stbl_index = -1; /* no samples have yet been parsed */
6349 stream->sample_index = -1;
6350
6351 if (stream->protection_scheme_info) {
6352 /* Clear out any old cenc crypto info entries as we'll move to a new moof */
6353 if (stream->protection_scheme_type == FOURCC_cenc
6354 || stream->protection_scheme_type == FOURCC_cbcs) {
6355 QtDemuxCencSampleSetInfo *info =
6356 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
6357 if (info->crypto_info) {
6358 g_ptr_array_free (info->crypto_info, TRUE);
6359 info->crypto_info = NULL;
6360 }
6361 }
6362 }
6363 }
6364
6365 GST_INFO_OBJECT (qtdemux, "seek to %" GST_TIME_FORMAT ", best fragment "
6366 "moof offset: %" G_GUINT64_FORMAT ", ts %" GST_TIME_FORMAT,
6367 GST_TIME_ARGS (QTDEMUX_NTH_STREAM (qtdemux, 0)->time_position),
6368 best_entry->moof_offset, GST_TIME_ARGS (best_entry->ts));
6369
6370 qtdemux->moof_offset = best_entry->moof_offset;
6371
6372 qtdemux_add_fragmented_samples (qtdemux);
6373
6374 GST_OBJECT_UNLOCK (qtdemux);
6375 return TRUE;
6376 }
6377
6378 static GstFlowReturn
gst_qtdemux_loop_state_movie(GstQTDemux * qtdemux)6379 gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux)
6380 {
6381 GstFlowReturn ret = GST_FLOW_OK;
6382 GstBuffer *buf = NULL;
6383 QtDemuxStream *stream, *target_stream = NULL;
6384 GstClockTime min_time;
6385 guint64 offset = 0;
6386 GstClockTime dts = GST_CLOCK_TIME_NONE;
6387 GstClockTime pts = GST_CLOCK_TIME_NONE;
6388 GstClockTime duration = 0;
6389 gboolean keyframe = FALSE;
6390 guint sample_size = 0;
6391 guint num_samples = 1;
6392 gboolean empty = 0;
6393 guint size;
6394 gint i;
6395
6396 if (qtdemux->fragmented_seek_pending) {
6397 GST_INFO_OBJECT (qtdemux, "pending fragmented seek");
6398 if (gst_qtdemux_do_fragmented_seek (qtdemux)) {
6399 GST_INFO_OBJECT (qtdemux, "fragmented seek done!");
6400 qtdemux->fragmented_seek_pending = FALSE;
6401 } else {
6402 GST_INFO_OBJECT (qtdemux, "fragmented seek still pending");
6403 }
6404 }
6405
6406 /* Figure out the next stream sample to output, min_time is expressed in
6407 * global time and runs over the edit list segments. */
6408 min_time = G_MAXUINT64;
6409 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
6410 GstClockTime position;
6411
6412 stream = QTDEMUX_NTH_STREAM (qtdemux, i);
6413 position = stream->time_position;
6414
6415 if (!GST_CLOCK_TIME_IS_VALID (position))
6416 continue;
6417
6418 if (stream->segment_index != -1) {
6419 QtDemuxSegment *segment = &stream->segments[stream->segment_index];
6420 position += segment->media_start;
6421 }
6422
6423 /* position of -1 is EOS */
6424 if (position < min_time) {
6425 min_time = position;
6426 target_stream = stream;
6427 }
6428 }
6429 /* all are EOS */
6430 if (G_UNLIKELY (target_stream == NULL)) {
6431 GST_DEBUG_OBJECT (qtdemux, "all streams are EOS");
6432 goto eos;
6433 }
6434
6435 /* check for segment end */
6436 if (G_UNLIKELY (qtdemux->segment.stop != -1
6437 && qtdemux->segment.rate >= 0
6438 && qtdemux->segment.stop <= min_time && target_stream->on_keyframe)) {
6439 GST_DEBUG_OBJECT (qtdemux, "we reached the end of our segment.");
6440 target_stream->time_position = GST_CLOCK_TIME_NONE;
6441 goto eos_stream;
6442 }
6443
6444 /* gap events for subtitle streams */
6445 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
6446 stream = QTDEMUX_NTH_STREAM (qtdemux, i);
6447 if (stream->pad) {
6448 GstClockTime gap_threshold;
6449
6450 /* Only send gap events on non-subtitle streams if lagging way behind. */
6451 if (stream->subtype == FOURCC_subp
6452 || stream->subtype == FOURCC_text || stream->subtype == FOURCC_sbtl ||
6453 stream->subtype == FOURCC_wvtt)
6454 gap_threshold = 1 * GST_SECOND;
6455 else
6456 gap_threshold = 3 * GST_SECOND;
6457
6458 /* send gap events until the stream catches up */
6459 /* gaps can only be sent after segment is activated (segment.stop is no longer -1) */
6460 while (GST_CLOCK_TIME_IS_VALID (stream->segment.stop) &&
6461 GST_CLOCK_TIME_IS_VALID (stream->segment.position) &&
6462 stream->segment.position + gap_threshold < min_time) {
6463 GstEvent *gap =
6464 gst_event_new_gap (stream->segment.position, gap_threshold);
6465 gst_pad_push_event (stream->pad, gap);
6466 stream->segment.position += gap_threshold;
6467 }
6468 }
6469 }
6470
6471 stream = target_stream;
6472 /* fetch info for the current sample of this stream */
6473 if (G_UNLIKELY (!gst_qtdemux_prepare_current_sample (qtdemux, stream, &empty,
6474 &offset, &sample_size, &dts, &pts, &duration, &keyframe)))
6475 goto eos_stream;
6476
6477 gst_qtdemux_stream_check_and_change_stsd_index (qtdemux, stream);
6478 if (stream->new_caps) {
6479 gst_qtdemux_configure_stream (qtdemux, stream);
6480 qtdemux_do_allocation (stream, qtdemux);
6481 }
6482
6483 /* If we're doing a keyframe-only trickmode, only push keyframes on video streams */
6484 if (G_UNLIKELY (qtdemux->segment.
6485 flags & GST_SEGMENT_FLAG_TRICKMODE_KEY_UNITS)) {
6486 if (stream->subtype == FOURCC_vide) {
6487 if (!keyframe) {
6488 GST_LOG_OBJECT (qtdemux, "Skipping non-keyframe on track-id %u",
6489 stream->track_id);
6490 goto next;
6491 } else if (qtdemux->trickmode_interval > 0) {
6492 GstClockTimeDiff interval;
6493
6494 if (qtdemux->segment.rate > 0)
6495 interval = stream->time_position - stream->last_keyframe_dts;
6496 else
6497 interval = stream->last_keyframe_dts - stream->time_position;
6498
6499 if (GST_CLOCK_TIME_IS_VALID (stream->last_keyframe_dts)
6500 && interval < qtdemux->trickmode_interval) {
6501 GST_LOG_OBJECT (qtdemux,
6502 "Skipping keyframe within interval on track-id %u",
6503 stream->track_id);
6504 goto next;
6505 } else {
6506 stream->last_keyframe_dts = stream->time_position;
6507 }
6508 }
6509 }
6510 }
6511
6512 GST_DEBUG_OBJECT (qtdemux,
6513 "pushing from track-id %u, empty %d offset %" G_GUINT64_FORMAT
6514 ", size %d, dts=%" GST_TIME_FORMAT ", pts=%" GST_TIME_FORMAT
6515 ", duration %" GST_TIME_FORMAT, stream->track_id, empty, offset,
6516 sample_size, GST_TIME_ARGS (dts), GST_TIME_ARGS (pts),
6517 GST_TIME_ARGS (duration));
6518
6519 if (G_UNLIKELY (empty)) {
6520 /* empty segment, push a gap if there's a second or more
6521 * difference and move to the next one */
6522 if ((pts + duration - stream->segment.position) >= GST_SECOND)
6523 gst_pad_push_event (stream->pad, gst_event_new_gap (pts, duration));
6524 stream->segment.position = pts + duration;
6525 goto next;
6526 }
6527
6528 /* hmm, empty sample, skip and move to next sample */
6529 if (G_UNLIKELY (sample_size <= 0))
6530 goto next;
6531
6532 /* last pushed sample was out of boundary, goto next sample */
6533 if (G_UNLIKELY (GST_PAD_LAST_FLOW_RETURN (stream->pad) == GST_FLOW_EOS))
6534 goto next;
6535
6536 if (stream->max_buffer_size != 0 && sample_size > stream->max_buffer_size) {
6537 GST_DEBUG_OBJECT (qtdemux,
6538 "size %d larger than stream max_buffer_size %d, trimming",
6539 sample_size, stream->max_buffer_size);
6540 size =
6541 MIN (sample_size - stream->offset_in_sample, stream->max_buffer_size);
6542 } else if (stream->min_buffer_size != 0 && stream->offset_in_sample == 0
6543 && sample_size < stream->min_buffer_size) {
6544 guint start_sample_index = stream->sample_index;
6545 guint accumulated_size = sample_size;
6546 guint64 expected_next_offset = offset + sample_size;
6547
6548 GST_DEBUG_OBJECT (qtdemux,
6549 "size %d smaller than stream min_buffer_size %d, combining with the next",
6550 sample_size, stream->min_buffer_size);
6551
6552 while (stream->sample_index < stream->to_sample
6553 && stream->sample_index + 1 < stream->n_samples) {
6554 const QtDemuxSample *next_sample;
6555
6556 /* Increment temporarily */
6557 stream->sample_index++;
6558
6559 /* Failed to parse sample so let's go back to the previous one that was
6560 * still successful */
6561 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
6562 stream->sample_index--;
6563 break;
6564 }
6565
6566 next_sample = &stream->samples[stream->sample_index];
6567
6568 /* Not contiguous with the previous sample so let's go back to the
6569 * previous one that was still successful */
6570 if (next_sample->offset != expected_next_offset) {
6571 stream->sample_index--;
6572 break;
6573 }
6574
6575 accumulated_size += next_sample->size;
6576 expected_next_offset += next_sample->size;
6577 if (accumulated_size >= stream->min_buffer_size)
6578 break;
6579 }
6580
6581 num_samples = stream->sample_index + 1 - start_sample_index;
6582 stream->sample_index = start_sample_index;
6583 GST_DEBUG_OBJECT (qtdemux, "Pulling %u samples of size %u at once",
6584 num_samples, accumulated_size);
6585 size = accumulated_size;
6586 } else {
6587 size = sample_size;
6588 }
6589
6590 if (qtdemux->cenc_aux_info_offset > 0) {
6591 GstMapInfo map;
6592 GstByteReader br;
6593 GstBuffer *aux_info = NULL;
6594
6595 /* pull the data stored before the sample */
6596 ret =
6597 gst_qtdemux_pull_atom (qtdemux, qtdemux->offset,
6598 offset + stream->offset_in_sample - qtdemux->offset, &aux_info);
6599 if (G_UNLIKELY (ret != GST_FLOW_OK))
6600 goto beach;
6601 gst_buffer_map (aux_info, &map, GST_MAP_READ);
6602 GST_DEBUG_OBJECT (qtdemux, "parsing cenc auxiliary info");
6603 gst_byte_reader_init (&br, map.data + 8, map.size);
6604 if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
6605 qtdemux->cenc_aux_info_sizes, qtdemux->cenc_aux_sample_count)) {
6606 GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
6607 gst_buffer_unmap (aux_info, &map);
6608 gst_buffer_unref (aux_info);
6609 ret = GST_FLOW_ERROR;
6610 goto beach;
6611 }
6612 gst_buffer_unmap (aux_info, &map);
6613 gst_buffer_unref (aux_info);
6614 }
6615
6616 GST_LOG_OBJECT (qtdemux, "reading %d bytes @ %" G_GUINT64_FORMAT, size,
6617 offset);
6618
6619 if (stream->use_allocator) {
6620 /* if we have a per-stream allocator, use it */
6621 buf = gst_buffer_new_allocate (stream->allocator, size, &stream->params);
6622 }
6623
6624 ret = gst_qtdemux_pull_atom (qtdemux, offset + stream->offset_in_sample,
6625 size, &buf);
6626 if (G_UNLIKELY (ret != GST_FLOW_OK))
6627 goto beach;
6628
6629 /* Update for both splitting and combining of samples */
6630 if (size != sample_size) {
6631 pts += gst_util_uint64_scale_int (GST_SECOND,
6632 stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame,
6633 stream->timescale);
6634 dts +=
6635 gst_util_uint64_scale_int (GST_SECOND,
6636 stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame,
6637 stream->timescale);
6638 duration =
6639 gst_util_uint64_scale_int (GST_SECOND,
6640 size / CUR_STREAM (stream)->bytes_per_frame, stream->timescale);
6641 }
6642
6643 ret = gst_qtdemux_decorate_and_push_buffer (qtdemux, stream, buf,
6644 dts, pts, duration, keyframe, min_time, offset);
6645
6646 if (size < sample_size) {
6647 QtDemuxSample *sample = &stream->samples[stream->sample_index];
6648 QtDemuxSegment *segment = &stream->segments[stream->segment_index];
6649
6650 GstClockTime time_position = QTSTREAMTIME_TO_GSTTIME (stream,
6651 sample->timestamp +
6652 stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame);
6653 if (time_position >= segment->media_start) {
6654 /* inside the segment, update time_position, looks very familiar to
6655 * GStreamer segments, doesn't it? */
6656 stream->time_position = (time_position - segment->media_start) +
6657 segment->time;
6658 } else {
6659 /* not yet in segment, time does not yet increment. This means
6660 * that we are still prerolling keyframes to the decoder so it can
6661 * decode the first sample of the segment. */
6662 stream->time_position = segment->time;
6663 }
6664 } else if (size > sample_size) {
6665 /* Increase to the last sample we already pulled so that advancing
6666 * below brings us to the next sample we need to pull */
6667 stream->sample_index += num_samples - 1;
6668 }
6669
6670 /* combine flows */
6671 GST_OBJECT_LOCK (qtdemux);
6672 ret = gst_qtdemux_combine_flows (qtdemux, stream, ret);
6673 GST_OBJECT_UNLOCK (qtdemux);
6674 /* ignore unlinked, we will not push on the pad anymore and we will EOS when
6675 * we have no more data for the pad to push */
6676 if (ret == GST_FLOW_EOS)
6677 ret = GST_FLOW_OK;
6678
6679 stream->offset_in_sample += size;
6680 if (stream->offset_in_sample >= sample_size) {
6681 gst_qtdemux_advance_sample (qtdemux, stream);
6682 }
6683 goto beach;
6684
6685 next:
6686 gst_qtdemux_advance_sample (qtdemux, stream);
6687
6688 beach:
6689 return ret;
6690
6691 /* special cases */
6692 eos:
6693 {
6694 GST_DEBUG_OBJECT (qtdemux, "No samples left for any streams - EOS");
6695 ret = GST_FLOW_EOS;
6696 goto beach;
6697 }
6698 eos_stream:
6699 {
6700 GST_DEBUG_OBJECT (qtdemux, "No samples left for stream");
6701 /* EOS will be raised if all are EOS */
6702 ret = GST_FLOW_OK;
6703 goto beach;
6704 }
6705 }
6706
6707 static void
gst_qtdemux_loop(GstPad * pad)6708 gst_qtdemux_loop (GstPad * pad)
6709 {
6710 GstQTDemux *qtdemux;
6711 guint64 cur_offset;
6712 GstFlowReturn ret;
6713
6714 qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
6715
6716 cur_offset = qtdemux->offset;
6717 GST_LOG_OBJECT (qtdemux, "loop at position %" G_GUINT64_FORMAT ", state %s",
6718 cur_offset, qt_demux_state_string (qtdemux->state));
6719
6720 switch (qtdemux->state) {
6721 case QTDEMUX_STATE_INITIAL:
6722 case QTDEMUX_STATE_HEADER:
6723 ret = gst_qtdemux_loop_state_header (qtdemux);
6724 break;
6725 case QTDEMUX_STATE_MOVIE:
6726 ret = gst_qtdemux_loop_state_movie (qtdemux);
6727 if (qtdemux->segment.rate < 0 && ret == GST_FLOW_EOS) {
6728 ret = gst_qtdemux_seek_to_previous_keyframe (qtdemux);
6729 }
6730 break;
6731 default:
6732 /* ouch */
6733 goto invalid_state;
6734 }
6735
6736 /* if something went wrong, pause */
6737 if (ret != GST_FLOW_OK)
6738 goto pause;
6739
6740 done:
6741 gst_object_unref (qtdemux);
6742 return;
6743
6744 /* ERRORS */
6745 invalid_state:
6746 {
6747 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
6748 (NULL), ("streaming stopped, invalid state"));
6749 gst_pad_pause_task (pad);
6750 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
6751 goto done;
6752 }
6753 pause:
6754 {
6755 const gchar *reason = gst_flow_get_name (ret);
6756
6757 GST_LOG_OBJECT (qtdemux, "pausing task, reason %s", reason);
6758
6759 gst_pad_pause_task (pad);
6760
6761 /* fatal errors need special actions */
6762 /* check EOS */
6763 if (ret == GST_FLOW_EOS) {
6764 if (QTDEMUX_N_STREAMS (qtdemux) == 0) {
6765 /* we have no streams, post an error */
6766 gst_qtdemux_post_no_playable_stream_error (qtdemux);
6767 }
6768 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
6769 gint64 stop;
6770
6771 if ((stop = qtdemux->segment.stop) == -1)
6772 stop = qtdemux->segment.duration;
6773
6774 if (qtdemux->segment.rate >= 0) {
6775 GstMessage *message;
6776 GstEvent *event;
6777
6778 GST_LOG_OBJECT (qtdemux, "Sending segment done, at end of segment");
6779 message = gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
6780 GST_FORMAT_TIME, stop);
6781 event = gst_event_new_segment_done (GST_FORMAT_TIME, stop);
6782 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID) {
6783 gst_message_set_seqnum (message, qtdemux->segment_seqnum);
6784 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
6785 }
6786 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), message);
6787 gst_qtdemux_push_event (qtdemux, event);
6788 } else {
6789 GstMessage *message;
6790 GstEvent *event;
6791
6792 /* For Reverse Playback */
6793 GST_LOG_OBJECT (qtdemux, "Sending segment done, at start of segment");
6794 message = gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
6795 GST_FORMAT_TIME, qtdemux->segment.start);
6796 event = gst_event_new_segment_done (GST_FORMAT_TIME,
6797 qtdemux->segment.start);
6798 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID) {
6799 gst_message_set_seqnum (message, qtdemux->segment_seqnum);
6800 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
6801 }
6802 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), message);
6803 gst_qtdemux_push_event (qtdemux, event);
6804 }
6805 } else {
6806 GstEvent *event;
6807
6808 GST_LOG_OBJECT (qtdemux, "Sending EOS at end of segment");
6809 event = gst_event_new_eos ();
6810 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID)
6811 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
6812 gst_qtdemux_push_event (qtdemux, event);
6813 }
6814 } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
6815 GST_ELEMENT_FLOW_ERROR (qtdemux, ret);
6816 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
6817 }
6818 goto done;
6819 }
6820 }
6821
6822 /*
6823 * has_next_entry
6824 *
6825 * Returns if there are samples to be played.
6826 */
6827 static gboolean
has_next_entry(GstQTDemux * demux)6828 has_next_entry (GstQTDemux * demux)
6829 {
6830 QtDemuxStream *stream;
6831 gint i;
6832
6833 GST_DEBUG_OBJECT (demux, "Checking if there are samples not played yet");
6834
6835 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
6836 stream = QTDEMUX_NTH_STREAM (demux, i);
6837
6838 if (stream->sample_index == -1) {
6839 stream->sample_index = 0;
6840 stream->offset_in_sample = 0;
6841 }
6842
6843 if (stream->sample_index >= stream->n_samples) {
6844 GST_LOG_OBJECT (demux, "track-id %u samples exhausted", stream->track_id);
6845 continue;
6846 }
6847 GST_DEBUG_OBJECT (demux, "Found a sample");
6848 return TRUE;
6849 }
6850
6851 GST_DEBUG_OBJECT (demux, "There wasn't any next sample");
6852 return FALSE;
6853 }
6854
6855 /*
6856 * next_entry_size
6857 *
6858 * Returns the size of the first entry at the current offset.
6859 * If -1, there are none (which means EOS or empty file).
6860 */
6861 static guint64
next_entry_size(GstQTDemux * demux)6862 next_entry_size (GstQTDemux * demux)
6863 {
6864 QtDemuxStream *stream, *target_stream = NULL;
6865 guint64 smalloffs = (guint64) - 1;
6866 QtDemuxSample *sample;
6867 gint i;
6868
6869 GST_LOG_OBJECT (demux, "Finding entry at offset %" G_GUINT64_FORMAT,
6870 demux->offset);
6871
6872 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
6873 stream = QTDEMUX_NTH_STREAM (demux, i);
6874
6875 if (stream->sample_index == -1) {
6876 stream->sample_index = 0;
6877 stream->offset_in_sample = 0;
6878 }
6879
6880 if (stream->sample_index >= stream->n_samples) {
6881 GST_LOG_OBJECT (demux, "track-id %u samples exhausted", stream->track_id);
6882 continue;
6883 }
6884
6885 if (!qtdemux_parse_samples (demux, stream, stream->sample_index)) {
6886 GST_LOG_OBJECT (demux, "Parsing of index %u from stbl atom failed!",
6887 stream->sample_index);
6888 return -1;
6889 }
6890
6891 sample = &stream->samples[stream->sample_index];
6892
6893 GST_LOG_OBJECT (demux,
6894 "Checking track-id %u (sample_index:%d / offset:%" G_GUINT64_FORMAT
6895 " / size:%" G_GUINT32_FORMAT ")", stream->track_id,
6896 stream->sample_index, sample->offset, sample->size);
6897
6898 if (((smalloffs == -1)
6899 || (sample->offset < smalloffs)) && (sample->size)) {
6900 smalloffs = sample->offset;
6901 target_stream = stream;
6902 }
6903 }
6904
6905 if (!target_stream)
6906 return -1;
6907
6908 GST_LOG_OBJECT (demux,
6909 "track-id %u offset %" G_GUINT64_FORMAT " demux->offset :%"
6910 G_GUINT64_FORMAT, target_stream->track_id, smalloffs, demux->offset);
6911
6912 stream = target_stream;
6913 sample = &stream->samples[stream->sample_index];
6914
6915 if (sample->offset >= demux->offset) {
6916 demux->todrop = sample->offset - demux->offset;
6917 return sample->size + demux->todrop;
6918 }
6919
6920 GST_DEBUG_OBJECT (demux,
6921 "There wasn't any entry at offset %" G_GUINT64_FORMAT, demux->offset);
6922 return -1;
6923 }
6924
6925 static void
gst_qtdemux_post_progress(GstQTDemux * demux,gint num,gint denom)6926 gst_qtdemux_post_progress (GstQTDemux * demux, gint num, gint denom)
6927 {
6928 gint perc = (gint) ((gdouble) num * 100.0 / (gdouble) denom);
6929
6930 gst_element_post_message (GST_ELEMENT_CAST (demux),
6931 gst_message_new_element (GST_OBJECT_CAST (demux),
6932 gst_structure_new ("progress", "percent", G_TYPE_INT, perc, NULL)));
6933 }
6934
6935 static gboolean
qtdemux_seek_offset(GstQTDemux * demux,guint64 offset)6936 qtdemux_seek_offset (GstQTDemux * demux, guint64 offset)
6937 {
6938 GstEvent *event;
6939 gboolean res = 0;
6940
6941 GST_DEBUG_OBJECT (demux, "Seeking to %" G_GUINT64_FORMAT, offset);
6942
6943 event =
6944 gst_event_new_seek (1.0, GST_FORMAT_BYTES,
6945 GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset,
6946 GST_SEEK_TYPE_NONE, -1);
6947
6948 /* store seqnum to drop flush events, they don't need to reach downstream */
6949 demux->offset_seek_seqnum = gst_event_get_seqnum (event);
6950 res = gst_pad_push_event (demux->sinkpad, event);
6951 demux->offset_seek_seqnum = GST_SEQNUM_INVALID;
6952
6953 return res;
6954 }
6955
6956 /* check for seekable upstream, above and beyond a mere query */
6957 static void
gst_qtdemux_check_seekability(GstQTDemux * demux)6958 gst_qtdemux_check_seekability (GstQTDemux * demux)
6959 {
6960 GstQuery *query;
6961 gboolean seekable = FALSE;
6962 gint64 start = -1, stop = -1;
6963
6964 if (demux->upstream_size)
6965 return;
6966
6967 if (demux->upstream_format_is_time)
6968 return;
6969
6970 query = gst_query_new_seeking (GST_FORMAT_BYTES);
6971 if (!gst_pad_peer_query (demux->sinkpad, query)) {
6972 GST_DEBUG_OBJECT (demux, "seeking query failed");
6973 goto done;
6974 }
6975
6976 gst_query_parse_seeking (query, NULL, &seekable, &start, &stop);
6977
6978 /* try harder to query upstream size if we didn't get it the first time */
6979 if (seekable && stop == -1) {
6980 GST_DEBUG_OBJECT (demux, "doing duration query to fix up unset stop");
6981 gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &stop);
6982 }
6983
6984 /* if upstream doesn't know the size, it's likely that it's not seekable in
6985 * practice even if it technically may be seekable */
6986 if (seekable && (start != 0 || stop <= start)) {
6987 GST_DEBUG_OBJECT (demux, "seekable but unknown start/stop -> disable");
6988 seekable = FALSE;
6989 }
6990
6991 done:
6992 gst_query_unref (query);
6993
6994 GST_DEBUG_OBJECT (demux, "seekable: %d (%" G_GUINT64_FORMAT " - %"
6995 G_GUINT64_FORMAT ")", seekable, start, stop);
6996 demux->upstream_seekable = seekable;
6997 demux->upstream_size = seekable ? stop : -1;
6998 }
6999
7000 static void
gst_qtdemux_drop_data(GstQTDemux * demux,gint bytes)7001 gst_qtdemux_drop_data (GstQTDemux * demux, gint bytes)
7002 {
7003 g_return_if_fail (bytes <= demux->todrop);
7004
7005 GST_LOG_OBJECT (demux, "Dropping %d bytes", bytes);
7006 gst_adapter_flush (demux->adapter, bytes);
7007 demux->neededbytes -= bytes;
7008 demux->offset += bytes;
7009 demux->todrop -= bytes;
7010 }
7011
7012 /* PUSH-MODE only: Send a segment, if not done already. */
7013 static void
gst_qtdemux_check_send_pending_segment(GstQTDemux * demux)7014 gst_qtdemux_check_send_pending_segment (GstQTDemux * demux)
7015 {
7016 if (G_UNLIKELY (demux->need_segment)) {
7017 gint i;
7018
7019 if (!demux->upstream_format_is_time) {
7020 gst_qtdemux_map_and_push_segments (demux, &demux->segment);
7021 } else {
7022 GstEvent *segment_event;
7023 segment_event = gst_event_new_segment (&demux->segment);
7024 if (demux->segment_seqnum != GST_SEQNUM_INVALID)
7025 gst_event_set_seqnum (segment_event, demux->segment_seqnum);
7026 gst_qtdemux_push_event (demux, segment_event);
7027 }
7028
7029 demux->need_segment = FALSE;
7030
7031 /* clear to send tags on all streams */
7032 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
7033 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (demux, i);
7034 gst_qtdemux_push_tags (demux, stream);
7035 if (CUR_STREAM (stream)->sparse) {
7036 GST_INFO_OBJECT (demux, "Sending gap event on stream %d", i);
7037 gst_pad_push_event (stream->pad,
7038 gst_event_new_gap (stream->segment.position, GST_CLOCK_TIME_NONE));
7039 }
7040 }
7041 }
7042 }
7043
7044 /* Used for push mode only. */
7045 static void
gst_qtdemux_send_gap_for_segment(GstQTDemux * demux,QtDemuxStream * stream,gint segment_index,GstClockTime pos)7046 gst_qtdemux_send_gap_for_segment (GstQTDemux * demux,
7047 QtDemuxStream * stream, gint segment_index, GstClockTime pos)
7048 {
7049 GstClockTime ts, dur;
7050
7051 ts = pos;
7052 dur =
7053 stream->segments[segment_index].duration - (pos -
7054 stream->segments[segment_index].time);
7055 stream->time_position += dur;
7056
7057 /* Only gaps with a duration of at least one second are propagated.
7058 * Same workaround as in pull mode.
7059 * (See 2e45926a96ec5298c6ef29bf912e5e6a06dc3e0e) */
7060 if (dur >= GST_SECOND) {
7061 GstEvent *gap;
7062 gap = gst_event_new_gap (ts, dur);
7063
7064 GST_DEBUG_OBJECT (stream->pad, "Pushing gap for empty "
7065 "segment: %" GST_PTR_FORMAT, gap);
7066 gst_pad_push_event (stream->pad, gap);
7067 }
7068 }
7069
7070 static GstFlowReturn
gst_qtdemux_chain(GstPad * sinkpad,GstObject * parent,GstBuffer * inbuf)7071 gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent, GstBuffer * inbuf)
7072 {
7073 GstQTDemux *demux;
7074
7075 demux = GST_QTDEMUX (parent);
7076
7077 GST_DEBUG_OBJECT (demux,
7078 "Received buffer pts:%" GST_TIME_FORMAT " dts:%" GST_TIME_FORMAT
7079 " offset:%" G_GUINT64_FORMAT " size:%" G_GSIZE_FORMAT " demux offset:%"
7080 G_GUINT64_FORMAT, GST_TIME_ARGS (GST_BUFFER_PTS (inbuf)),
7081 GST_TIME_ARGS (GST_BUFFER_DTS (inbuf)), GST_BUFFER_OFFSET (inbuf),
7082 gst_buffer_get_size (inbuf), demux->offset);
7083
7084 if (GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_DISCONT)) {
7085 gboolean is_gap_input = FALSE;
7086 gint i;
7087
7088 GST_DEBUG_OBJECT (demux, "Got DISCONT, marking all streams as DISCONT");
7089
7090 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
7091 QTDEMUX_NTH_STREAM (demux, i)->discont = TRUE;
7092 }
7093
7094 /* Check if we can land back on our feet in the case where upstream is
7095 * handling the seeking/pushing of samples with gaps in between (like
7096 * in the case of trick-mode DASH for example) */
7097 if (demux->upstream_format_is_time
7098 && GST_BUFFER_OFFSET (inbuf) != GST_BUFFER_OFFSET_NONE) {
7099 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
7100 guint32 res;
7101 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (demux, i);
7102 GST_LOG_OBJECT (demux,
7103 "track-id #%u , checking if offset %" G_GUINT64_FORMAT
7104 " is a sample start", stream->track_id, GST_BUFFER_OFFSET (inbuf));
7105 res =
7106 gst_qtdemux_find_index_for_given_media_offset_linear (demux,
7107 stream, GST_BUFFER_OFFSET (inbuf));
7108 if (res != -1) {
7109 QtDemuxSample *sample = &stream->samples[res];
7110 GST_LOG_OBJECT (demux,
7111 "Checking if sample %d from track-id %u is valid (offset:%"
7112 G_GUINT64_FORMAT " size:%" G_GUINT32_FORMAT ")", res,
7113 stream->track_id, sample->offset, sample->size);
7114 if (sample->offset == GST_BUFFER_OFFSET (inbuf)) {
7115 GST_LOG_OBJECT (demux,
7116 "new buffer corresponds to a valid sample : %" G_GUINT32_FORMAT,
7117 res);
7118 is_gap_input = TRUE;
7119 /* We can go back to standard playback mode */
7120 demux->state = QTDEMUX_STATE_MOVIE;
7121 /* Remember which sample this stream is at */
7122 stream->sample_index = res;
7123 /* Finally update all push-based values to the expected values */
7124 demux->neededbytes = stream->samples[res].size;
7125 demux->offset = GST_BUFFER_OFFSET (inbuf);
7126 demux->mdatleft =
7127 demux->mdatsize - demux->offset + demux->mdatoffset;
7128 demux->todrop = 0;
7129 }
7130 }
7131 }
7132 if (!is_gap_input) {
7133 GST_DEBUG_OBJECT (demux, "Resetting, actual DISCONT");
7134 /* Reset state if it's a real discont */
7135 demux->neededbytes = 16;
7136 demux->state = QTDEMUX_STATE_INITIAL;
7137 demux->offset = GST_BUFFER_OFFSET (inbuf);
7138 gst_adapter_clear (demux->adapter);
7139 }
7140 }
7141 /* Reverse fragmented playback, need to flush all we have before
7142 * consuming a new fragment.
7143 * The samples array have the timestamps calculated by accumulating the
7144 * durations but this won't work for reverse playback of fragments as
7145 * the timestamps of a subsequent fragment should be smaller than the
7146 * previously received one. */
7147 if (!is_gap_input && demux->fragmented && demux->segment.rate < 0) {
7148 gst_qtdemux_process_adapter (demux, TRUE);
7149 g_ptr_array_foreach (demux->active_streams,
7150 (GFunc) gst_qtdemux_stream_flush_samples_data, NULL);
7151 }
7152 }
7153
7154 gst_adapter_push (demux->adapter, inbuf);
7155
7156 GST_DEBUG_OBJECT (demux,
7157 "pushing in inbuf %p, neededbytes:%u, available:%" G_GSIZE_FORMAT, inbuf,
7158 demux->neededbytes, gst_adapter_available (demux->adapter));
7159
7160 return gst_qtdemux_process_adapter (demux, FALSE);
7161 }
7162
7163 static GstFlowReturn
gst_qtdemux_process_adapter(GstQTDemux * demux,gboolean force)7164 gst_qtdemux_process_adapter (GstQTDemux * demux, gboolean force)
7165 {
7166 GstFlowReturn ret = GST_FLOW_OK;
7167
7168 /* we never really mean to buffer that much */
7169 if (demux->neededbytes == -1) {
7170 goto eos;
7171 }
7172
7173 while (((gst_adapter_available (demux->adapter)) >= demux->neededbytes) &&
7174 (ret == GST_FLOW_OK || (ret == GST_FLOW_NOT_LINKED && force))) {
7175
7176 #ifndef GST_DISABLE_GST_DEBUG
7177 {
7178 guint64 discont_offset, distance_from_discont;
7179
7180 discont_offset = gst_adapter_offset_at_discont (demux->adapter);
7181 distance_from_discont =
7182 gst_adapter_distance_from_discont (demux->adapter);
7183
7184 GST_DEBUG_OBJECT (demux,
7185 "state:%s , demux->neededbytes:%d, demux->offset:%" G_GUINT64_FORMAT
7186 " adapter offset :%" G_GUINT64_FORMAT " (+ %" G_GUINT64_FORMAT
7187 " bytes)", qt_demux_state_string (demux->state), demux->neededbytes,
7188 demux->offset, discont_offset, distance_from_discont);
7189 }
7190 #endif
7191
7192 switch (demux->state) {
7193 case QTDEMUX_STATE_INITIAL:{
7194 const guint8 *data;
7195 guint32 fourcc;
7196 guint64 size;
7197
7198 gst_qtdemux_check_seekability (demux);
7199
7200 data = gst_adapter_map (demux->adapter, demux->neededbytes);
7201
7202 /* get fourcc/length, set neededbytes */
7203 extract_initial_length_and_fourcc ((guint8 *) data, demux->neededbytes,
7204 &size, &fourcc);
7205 gst_adapter_unmap (demux->adapter);
7206 data = NULL;
7207 GST_DEBUG_OBJECT (demux, "Peeking found [%" GST_FOURCC_FORMAT "] "
7208 "size: %" G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), size);
7209 if (size == 0) {
7210 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
7211 (_("This file is invalid and cannot be played.")),
7212 ("initial atom '%" GST_FOURCC_FORMAT "' has empty length",
7213 GST_FOURCC_ARGS (fourcc)));
7214 ret = GST_FLOW_ERROR;
7215 break;
7216 }
7217 if (fourcc == FOURCC_mdat) {
7218 gint next_entry = next_entry_size (demux);
7219 if (QTDEMUX_N_STREAMS (demux) > 0 && (next_entry != -1
7220 || !demux->fragmented)) {
7221 /* we have the headers, start playback */
7222 demux->state = QTDEMUX_STATE_MOVIE;
7223 demux->neededbytes = next_entry;
7224 demux->mdatleft = size;
7225 demux->mdatsize = demux->mdatleft;
7226 } else {
7227 /* no headers yet, try to get them */
7228 guint bs;
7229 gboolean res;
7230 guint64 old, target;
7231
7232 buffer_data:
7233 old = demux->offset;
7234 target = old + size;
7235
7236 /* try to jump over the atom with a seek */
7237 /* only bother if it seems worth doing so,
7238 * and avoids possible upstream/server problems */
7239 if (demux->upstream_seekable &&
7240 demux->upstream_size > 4 * (1 << 20)) {
7241 res = qtdemux_seek_offset (demux, target);
7242 } else {
7243 GST_DEBUG_OBJECT (demux, "skipping seek");
7244 res = FALSE;
7245 }
7246
7247 if (res) {
7248 GST_DEBUG_OBJECT (demux, "seek success");
7249 /* remember the offset fo the first mdat so we can seek back to it
7250 * after we have the headers */
7251 if (fourcc == FOURCC_mdat && demux->first_mdat == -1) {
7252 demux->first_mdat = old;
7253 GST_DEBUG_OBJECT (demux, "first mdat at %" G_GUINT64_FORMAT,
7254 demux->first_mdat);
7255 }
7256 /* seek worked, continue reading */
7257 demux->offset = target;
7258 demux->neededbytes = 16;
7259 demux->state = QTDEMUX_STATE_INITIAL;
7260 } else {
7261 /* seek failed, need to buffer */
7262 demux->offset = old;
7263 GST_DEBUG_OBJECT (demux, "seek failed/skipped");
7264 /* there may be multiple mdat (or alike) buffers */
7265 /* sanity check */
7266 if (demux->mdatbuffer)
7267 bs = gst_buffer_get_size (demux->mdatbuffer);
7268 else
7269 bs = 0;
7270 if (size + bs > 10 * (1 << 20))
7271 goto no_moov;
7272 demux->state = QTDEMUX_STATE_BUFFER_MDAT;
7273 demux->neededbytes = size;
7274 if (!demux->mdatbuffer)
7275 demux->mdatoffset = demux->offset;
7276 }
7277 }
7278 } else if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
7279 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
7280 (_("This file is invalid and cannot be played.")),
7281 ("atom %" GST_FOURCC_FORMAT " has bogus size %" G_GUINT64_FORMAT,
7282 GST_FOURCC_ARGS (fourcc), size));
7283 ret = GST_FLOW_ERROR;
7284 break;
7285 } else {
7286 /* this means we already started buffering and still no moov header,
7287 * let's continue buffering everything till we get moov */
7288 if (demux->mdatbuffer && !(fourcc == FOURCC_moov
7289 || fourcc == FOURCC_moof))
7290 goto buffer_data;
7291 demux->neededbytes = size;
7292 demux->state = QTDEMUX_STATE_HEADER;
7293 }
7294 break;
7295 }
7296 case QTDEMUX_STATE_HEADER:{
7297 const guint8 *data;
7298 guint32 fourcc;
7299
7300 GST_DEBUG_OBJECT (demux, "In header");
7301
7302 data = gst_adapter_map (demux->adapter, demux->neededbytes);
7303
7304 /* parse the header */
7305 extract_initial_length_and_fourcc (data, demux->neededbytes, NULL,
7306 &fourcc);
7307 if (fourcc == FOURCC_moov) {
7308 /* in usual fragmented setup we could try to scan for more
7309 * and end up at the the moov (after mdat) again */
7310 if (demux->got_moov && QTDEMUX_N_STREAMS (demux) > 0 &&
7311 (!demux->fragmented
7312 || demux->last_moov_offset == demux->offset)) {
7313 GST_DEBUG_OBJECT (demux,
7314 "Skipping moov atom as we have (this) one already");
7315 } else {
7316 GST_DEBUG_OBJECT (demux, "Parsing [moov]");
7317
7318 if (demux->got_moov && demux->fragmented) {
7319 GST_DEBUG_OBJECT (demux,
7320 "Got a second moov, clean up data from old one");
7321 if (demux->moov_node_compressed) {
7322 g_node_destroy (demux->moov_node_compressed);
7323 if (demux->moov_node)
7324 g_free (demux->moov_node->data);
7325 }
7326 demux->moov_node_compressed = NULL;
7327 if (demux->moov_node)
7328 g_node_destroy (demux->moov_node);
7329 demux->moov_node = NULL;
7330 }
7331
7332 demux->last_moov_offset = demux->offset;
7333
7334 /* Update streams with new moov */
7335 gst_qtdemux_stream_concat (demux,
7336 demux->old_streams, demux->active_streams);
7337
7338 qtdemux_parse_moov (demux, data, demux->neededbytes);
7339 qtdemux_node_dump (demux, demux->moov_node);
7340 qtdemux_parse_tree (demux);
7341 qtdemux_prepare_streams (demux);
7342 QTDEMUX_EXPOSE_LOCK (demux);
7343 qtdemux_expose_streams (demux);
7344 QTDEMUX_EXPOSE_UNLOCK (demux);
7345
7346 demux->got_moov = TRUE;
7347
7348 gst_qtdemux_check_send_pending_segment (demux);
7349
7350 if (demux->moov_node_compressed) {
7351 g_node_destroy (demux->moov_node_compressed);
7352 g_free (demux->moov_node->data);
7353 }
7354 demux->moov_node_compressed = NULL;
7355 g_node_destroy (demux->moov_node);
7356 demux->moov_node = NULL;
7357 GST_DEBUG_OBJECT (demux, "Finished parsing the header");
7358 }
7359 } else if (fourcc == FOURCC_moof) {
7360 if ((demux->got_moov || demux->media_caps) && demux->fragmented) {
7361 guint64 dist = 0;
7362 GstClockTime prev_pts;
7363 guint64 prev_offset;
7364 guint64 adapter_discont_offset, adapter_discont_dist;
7365
7366 GST_DEBUG_OBJECT (demux, "Parsing [moof]");
7367
7368 /*
7369 * The timestamp of the moof buffer is relevant as some scenarios
7370 * won't have the initial timestamp in the atoms. Whenever a new
7371 * buffer has started, we get that buffer's PTS and use it as a base
7372 * timestamp for the trun entries.
7373 *
7374 * To keep track of the current buffer timestamp and starting point
7375 * we use gst_adapter_prev_pts that gives us the PTS and the distance
7376 * from the beginning of the buffer, with the distance and demux->offset
7377 * we know if it is still the same buffer or not.
7378 */
7379 prev_pts = gst_adapter_prev_pts (demux->adapter, &dist);
7380 prev_offset = demux->offset - dist;
7381 if (demux->fragment_start_offset == -1
7382 || prev_offset > demux->fragment_start_offset) {
7383 demux->fragment_start_offset = prev_offset;
7384 demux->fragment_start = prev_pts;
7385 GST_DEBUG_OBJECT (demux,
7386 "New fragment start found at: %" G_GUINT64_FORMAT " : %"
7387 GST_TIME_FORMAT, demux->fragment_start_offset,
7388 GST_TIME_ARGS (demux->fragment_start));
7389 }
7390
7391 /* We can't use prev_offset() here because this would require
7392 * upstream to set consistent and correct offsets on all buffers
7393 * since the discont. Nothing ever did that in the past and we
7394 * would break backwards compatibility here then.
7395 * Instead take the offset we had at the last discont and count
7396 * the bytes from there. This works with old code as there would
7397 * be no discont between moov and moof, and also works with
7398 * adaptivedemux which correctly sets offset and will set the
7399 * DISCONT flag accordingly when needed.
7400 *
7401 * We also only do this for upstream TIME segments as otherwise
7402 * there are potential backwards compatibility problems with
7403 * seeking in PUSH mode and upstream providing inconsistent
7404 * timestamps. */
7405 adapter_discont_offset =
7406 gst_adapter_offset_at_discont (demux->adapter);
7407 adapter_discont_dist =
7408 gst_adapter_distance_from_discont (demux->adapter);
7409
7410 GST_DEBUG_OBJECT (demux,
7411 "demux offset %" G_GUINT64_FORMAT " adapter offset %"
7412 G_GUINT64_FORMAT " (+ %" G_GUINT64_FORMAT " bytes)",
7413 demux->offset, adapter_discont_offset, adapter_discont_dist);
7414
7415 if (demux->upstream_format_is_time) {
7416 demux->moof_offset = adapter_discont_offset;
7417 if (demux->moof_offset != GST_BUFFER_OFFSET_NONE)
7418 demux->moof_offset += adapter_discont_dist;
7419 if (demux->moof_offset == GST_BUFFER_OFFSET_NONE)
7420 demux->moof_offset = demux->offset;
7421 } else {
7422 demux->moof_offset = demux->offset;
7423 }
7424
7425 if (!qtdemux_parse_moof (demux, data, demux->neededbytes,
7426 demux->moof_offset, NULL)) {
7427 gst_adapter_unmap (demux->adapter);
7428 ret = GST_FLOW_ERROR;
7429 goto done;
7430 }
7431
7432 /* in MSS we need to expose the pads after the first moof as we won't get a moov */
7433 if (demux->mss_mode && !demux->exposed) {
7434 QTDEMUX_EXPOSE_LOCK (demux);
7435 qtdemux_expose_streams (demux);
7436 QTDEMUX_EXPOSE_UNLOCK (demux);
7437 }
7438
7439 gst_qtdemux_check_send_pending_segment (demux);
7440 } else {
7441 GST_DEBUG_OBJECT (demux, "Discarding [moof]");
7442 }
7443 } else if (fourcc == FOURCC_ftyp) {
7444 GST_DEBUG_OBJECT (demux, "Parsing [ftyp]");
7445 qtdemux_parse_ftyp (demux, data, demux->neededbytes);
7446 } else if (fourcc == FOURCC_uuid) {
7447 GST_DEBUG_OBJECT (demux, "Parsing [uuid]");
7448 qtdemux_parse_uuid (demux, data, demux->neededbytes);
7449 } else if (fourcc == FOURCC_sidx) {
7450 GST_DEBUG_OBJECT (demux, "Parsing [sidx]");
7451 qtdemux_parse_sidx (demux, data, demux->neededbytes);
7452 } else {
7453 switch (fourcc) {
7454 case FOURCC_styp:
7455 /* [styp] is like a [ftyp], but in fragment header. We ignore it for now
7456 * FALLTHROUGH */
7457 case FOURCC_skip:
7458 case FOURCC_free:
7459 /* [free] and [skip] are padding atoms */
7460 GST_DEBUG_OBJECT (demux,
7461 "Skipping fourcc while parsing header : %" GST_FOURCC_FORMAT,
7462 GST_FOURCC_ARGS (fourcc));
7463 break;
7464 default:
7465 GST_WARNING_OBJECT (demux,
7466 "Unknown fourcc while parsing header : %" GST_FOURCC_FORMAT,
7467 GST_FOURCC_ARGS (fourcc));
7468 /* Let's jump that one and go back to initial state */
7469 break;
7470 }
7471 }
7472 gst_adapter_unmap (demux->adapter);
7473 data = NULL;
7474
7475 if (demux->mdatbuffer && QTDEMUX_N_STREAMS (demux)) {
7476 gsize remaining_data_size = 0;
7477
7478 /* the mdat was before the header */
7479 GST_DEBUG_OBJECT (demux, "We have n_streams:%d and mdatbuffer:%p",
7480 QTDEMUX_N_STREAMS (demux), demux->mdatbuffer);
7481 /* restore our adapter/offset view of things with upstream;
7482 * put preceding buffered data ahead of current moov data.
7483 * This should also handle evil mdat, moov, mdat cases and alike */
7484 gst_adapter_flush (demux->adapter, demux->neededbytes);
7485
7486 /* Store any remaining data after the mdat for later usage */
7487 remaining_data_size = gst_adapter_available (demux->adapter);
7488 if (remaining_data_size > 0) {
7489 g_assert (demux->restoredata_buffer == NULL);
7490 demux->restoredata_buffer =
7491 gst_adapter_take_buffer (demux->adapter, remaining_data_size);
7492 demux->restoredata_offset = demux->offset + demux->neededbytes;
7493 GST_DEBUG_OBJECT (demux,
7494 "Stored %" G_GSIZE_FORMAT " post mdat bytes at offset %"
7495 G_GUINT64_FORMAT, remaining_data_size,
7496 demux->restoredata_offset);
7497 }
7498
7499 gst_adapter_push (demux->adapter, demux->mdatbuffer);
7500 demux->mdatbuffer = NULL;
7501 demux->offset = demux->mdatoffset;
7502 demux->neededbytes = next_entry_size (demux);
7503 demux->state = QTDEMUX_STATE_MOVIE;
7504 demux->mdatleft = gst_adapter_available (demux->adapter);
7505 demux->mdatsize = demux->mdatleft;
7506 } else {
7507 GST_DEBUG_OBJECT (demux, "Carrying on normally");
7508 gst_adapter_flush (demux->adapter, demux->neededbytes);
7509
7510 /* only go back to the mdat if there are samples to play */
7511 if (demux->got_moov && demux->first_mdat != -1
7512 && has_next_entry (demux)) {
7513 gboolean res;
7514
7515 /* we need to seek back */
7516 res = qtdemux_seek_offset (demux, demux->first_mdat);
7517 if (res) {
7518 demux->offset = demux->first_mdat;
7519 } else {
7520 GST_DEBUG_OBJECT (demux, "Seek back failed");
7521 }
7522 } else {
7523 demux->offset += demux->neededbytes;
7524 }
7525 demux->neededbytes = 16;
7526 demux->state = QTDEMUX_STATE_INITIAL;
7527 }
7528
7529 break;
7530 }
7531 case QTDEMUX_STATE_BUFFER_MDAT:{
7532 GstBuffer *buf;
7533 guint8 fourcc[4];
7534
7535 GST_DEBUG_OBJECT (demux, "Got our buffer at offset %" G_GUINT64_FORMAT,
7536 demux->offset);
7537 buf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
7538 gst_buffer_extract (buf, 0, fourcc, 4);
7539 GST_DEBUG_OBJECT (demux, "mdatbuffer starts with %" GST_FOURCC_FORMAT,
7540 GST_FOURCC_ARGS (QT_FOURCC (fourcc)));
7541 if (demux->mdatbuffer)
7542 demux->mdatbuffer = gst_buffer_append (demux->mdatbuffer, buf);
7543 else
7544 demux->mdatbuffer = buf;
7545 demux->offset += demux->neededbytes;
7546 demux->neededbytes = 16;
7547 demux->state = QTDEMUX_STATE_INITIAL;
7548 gst_qtdemux_post_progress (demux, 1, 1);
7549
7550 break;
7551 }
7552 case QTDEMUX_STATE_MOVIE:{
7553 QtDemuxStream *stream = NULL;
7554 QtDemuxSample *sample;
7555 GstClockTime dts, pts, duration;
7556 gboolean keyframe;
7557 gint i;
7558
7559 GST_DEBUG_OBJECT (demux,
7560 "BEGIN // in MOVIE for offset %" G_GUINT64_FORMAT, demux->offset);
7561
7562 if (demux->fragmented) {
7563 GST_DEBUG_OBJECT (demux, "mdat remaining %" G_GUINT64_FORMAT,
7564 demux->mdatleft);
7565 if (G_LIKELY (demux->todrop < demux->mdatleft)) {
7566 /* if needed data starts within this atom,
7567 * then it should not exceed this atom */
7568 if (G_UNLIKELY (demux->neededbytes > demux->mdatleft)) {
7569 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
7570 (_("This file is invalid and cannot be played.")),
7571 ("sample data crosses atom boundary"));
7572 ret = GST_FLOW_ERROR;
7573 break;
7574 }
7575 demux->mdatleft -= demux->neededbytes;
7576 } else {
7577 GST_DEBUG_OBJECT (demux, "data atom emptied; resuming atom scan");
7578 /* so we are dropping more than left in this atom */
7579 gst_qtdemux_drop_data (demux, demux->mdatleft);
7580 demux->mdatleft = 0;
7581
7582 /* need to resume atom parsing so we do not miss any other pieces */
7583 demux->state = QTDEMUX_STATE_INITIAL;
7584 demux->neededbytes = 16;
7585
7586 /* check if there was any stored post mdat data from previous buffers */
7587 if (demux->restoredata_buffer) {
7588 g_assert (gst_adapter_available (demux->adapter) == 0);
7589
7590 gst_adapter_push (demux->adapter, demux->restoredata_buffer);
7591 demux->restoredata_buffer = NULL;
7592 demux->offset = demux->restoredata_offset;
7593 }
7594
7595 break;
7596 }
7597 }
7598
7599 if (demux->todrop) {
7600 if (demux->cenc_aux_info_offset > 0) {
7601 GstByteReader br;
7602 const guint8 *data;
7603
7604 GST_DEBUG_OBJECT (demux, "parsing cenc auxiliary info");
7605 data = gst_adapter_map (demux->adapter, demux->todrop);
7606 gst_byte_reader_init (&br, data + 8, demux->todrop);
7607 if (!qtdemux_parse_cenc_aux_info (demux,
7608 QTDEMUX_NTH_STREAM (demux, 0), &br,
7609 demux->cenc_aux_info_sizes, demux->cenc_aux_sample_count)) {
7610 GST_ERROR_OBJECT (demux, "failed to parse cenc auxiliary info");
7611 ret = GST_FLOW_ERROR;
7612 gst_adapter_unmap (demux->adapter);
7613 g_free (demux->cenc_aux_info_sizes);
7614 demux->cenc_aux_info_sizes = NULL;
7615 goto done;
7616 }
7617 demux->cenc_aux_info_offset = 0;
7618 g_free (demux->cenc_aux_info_sizes);
7619 demux->cenc_aux_info_sizes = NULL;
7620 gst_adapter_unmap (demux->adapter);
7621 }
7622 gst_qtdemux_drop_data (demux, demux->todrop);
7623 }
7624
7625 /* first buffer? */
7626 /* initial newsegment sent here after having added pads,
7627 * possible others in sink_event */
7628 gst_qtdemux_check_send_pending_segment (demux);
7629
7630 /* Figure out which stream this packet belongs to */
7631 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
7632 stream = QTDEMUX_NTH_STREAM (demux, i);
7633 if (stream->sample_index >= stream->n_samples) {
7634 /* reset to be checked below G_UNLIKELY (stream == NULL) */
7635 stream = NULL;
7636 continue;
7637 }
7638 GST_LOG_OBJECT (demux,
7639 "Checking track-id %u (sample_index:%d / offset:%"
7640 G_GUINT64_FORMAT " / size:%d)", stream->track_id,
7641 stream->sample_index,
7642 stream->samples[stream->sample_index].offset,
7643 stream->samples[stream->sample_index].size);
7644
7645 if (stream->samples[stream->sample_index].offset == demux->offset)
7646 break;
7647 }
7648
7649 if (G_UNLIKELY (stream == NULL))
7650 goto unknown_stream;
7651
7652 gst_qtdemux_stream_check_and_change_stsd_index (demux, stream);
7653
7654 if (stream->new_caps) {
7655 gst_qtdemux_configure_stream (demux, stream);
7656 }
7657
7658 /* Put data in a buffer, set timestamps, caps, ... */
7659 sample = &stream->samples[stream->sample_index];
7660
7661 if (G_LIKELY (!(STREAM_IS_EOS (stream)))) {
7662 GST_DEBUG_OBJECT (demux, "stream : %" GST_FOURCC_FORMAT,
7663 GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
7664
7665 dts = QTSAMPLE_DTS (stream, sample);
7666 pts = QTSAMPLE_PTS (stream, sample);
7667 duration = QTSAMPLE_DUR_DTS (stream, sample, dts);
7668 keyframe = QTSAMPLE_KEYFRAME (stream, sample);
7669
7670 /* check for segment end */
7671 if (G_UNLIKELY (demux->segment.stop != -1
7672 && demux->segment.stop <= pts && stream->on_keyframe)
7673 && !(demux->upstream_format_is_time && demux->segment.rate < 0)) {
7674 GST_DEBUG_OBJECT (demux, "we reached the end of our segment.");
7675 stream->time_position = GST_CLOCK_TIME_NONE; /* this means EOS */
7676
7677 /* skip this data, stream is EOS */
7678 gst_adapter_flush (demux->adapter, demux->neededbytes);
7679 demux->offset += demux->neededbytes;
7680
7681 /* check if all streams are eos */
7682 ret = GST_FLOW_EOS;
7683 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
7684 if (!STREAM_IS_EOS (QTDEMUX_NTH_STREAM (demux, i))) {
7685 ret = GST_FLOW_OK;
7686 break;
7687 }
7688 }
7689 } else {
7690 GstBuffer *outbuf;
7691
7692 outbuf =
7693 gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
7694
7695 /* FIXME: should either be an assert or a plain check */
7696 g_return_val_if_fail (outbuf != NULL, GST_FLOW_ERROR);
7697
7698 ret = gst_qtdemux_decorate_and_push_buffer (demux, stream, outbuf,
7699 dts, pts, duration, keyframe, dts, demux->offset);
7700 }
7701
7702 /* combine flows */
7703 GST_OBJECT_LOCK (demux);
7704 ret = gst_qtdemux_combine_flows (demux, stream, ret);
7705 GST_OBJECT_UNLOCK (demux);
7706 } else {
7707 /* skip this data, stream is EOS */
7708 gst_adapter_flush (demux->adapter, demux->neededbytes);
7709 }
7710
7711 stream->sample_index++;
7712 stream->offset_in_sample = 0;
7713
7714 /* update current offset and figure out size of next buffer */
7715 GST_LOG_OBJECT (demux, "increasing offset %" G_GUINT64_FORMAT " by %u",
7716 demux->offset, demux->neededbytes);
7717 demux->offset += demux->neededbytes;
7718 GST_LOG_OBJECT (demux, "offset is now %" G_GUINT64_FORMAT,
7719 demux->offset);
7720
7721
7722 if (ret == GST_FLOW_EOS) {
7723 GST_DEBUG_OBJECT (demux, "All streams are EOS, signal upstream");
7724 demux->neededbytes = -1;
7725 goto eos;
7726 }
7727
7728 if ((demux->neededbytes = next_entry_size (demux)) == -1) {
7729 if (demux->fragmented) {
7730 GST_DEBUG_OBJECT (demux, "(temporarily) out of fragmented samples");
7731 /* there may be more to follow, only finish this atom */
7732 demux->todrop = demux->mdatleft;
7733 demux->neededbytes = demux->todrop;
7734 break;
7735 }
7736 goto eos;
7737 }
7738 if (ret != GST_FLOW_OK && ret != GST_FLOW_NOT_LINKED) {
7739 goto non_ok_unlinked_flow;
7740 }
7741 break;
7742 }
7743 default:
7744 goto invalid_state;
7745 }
7746 }
7747
7748 /* when buffering movie data, at least show user something is happening */
7749 if (ret == GST_FLOW_OK && demux->state == QTDEMUX_STATE_BUFFER_MDAT &&
7750 gst_adapter_available (demux->adapter) <= demux->neededbytes) {
7751 gst_qtdemux_post_progress (demux, gst_adapter_available (demux->adapter),
7752 demux->neededbytes);
7753 }
7754 done:
7755
7756 return ret;
7757
7758 /* ERRORS */
7759 non_ok_unlinked_flow:
7760 {
7761 GST_DEBUG_OBJECT (demux, "Stopping, combined return flow %s",
7762 gst_flow_get_name (ret));
7763 return ret;
7764 }
7765 unknown_stream:
7766 {
7767 GST_ELEMENT_ERROR (demux, STREAM, FAILED, (NULL), ("unknown stream found"));
7768 ret = GST_FLOW_ERROR;
7769 goto done;
7770 }
7771 eos:
7772 {
7773 GST_DEBUG_OBJECT (demux, "no next entry, EOS");
7774 ret = GST_FLOW_EOS;
7775 goto done;
7776 }
7777 invalid_state:
7778 {
7779 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
7780 (NULL), ("qtdemuxer invalid state %d", demux->state));
7781 ret = GST_FLOW_ERROR;
7782 goto done;
7783 }
7784 no_moov:
7785 {
7786 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
7787 (NULL), ("no 'moov' atom within the first 10 MB"));
7788 ret = GST_FLOW_ERROR;
7789 goto done;
7790 }
7791 }
7792
7793 static gboolean
qtdemux_sink_activate(GstPad * sinkpad,GstObject * parent)7794 qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent)
7795 {
7796 GstQuery *query;
7797 gboolean pull_mode;
7798
7799 query = gst_query_new_scheduling ();
7800
7801 if (!gst_pad_peer_query (sinkpad, query)) {
7802 gst_query_unref (query);
7803 goto activate_push;
7804 }
7805
7806 pull_mode = gst_query_has_scheduling_mode_with_flags (query,
7807 GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
7808 gst_query_unref (query);
7809
7810 if (!pull_mode)
7811 goto activate_push;
7812
7813 GST_DEBUG_OBJECT (sinkpad, "activating pull");
7814 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
7815
7816 activate_push:
7817 {
7818 GST_DEBUG_OBJECT (sinkpad, "activating push");
7819 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
7820 }
7821 }
7822
7823 static gboolean
qtdemux_sink_activate_mode(GstPad * sinkpad,GstObject * parent,GstPadMode mode,gboolean active)7824 qtdemux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
7825 GstPadMode mode, gboolean active)
7826 {
7827 gboolean res;
7828 GstQTDemux *demux = GST_QTDEMUX (parent);
7829
7830 switch (mode) {
7831 case GST_PAD_MODE_PUSH:
7832 demux->pullbased = FALSE;
7833 res = TRUE;
7834 break;
7835 case GST_PAD_MODE_PULL:
7836 if (active) {
7837 demux->pullbased = TRUE;
7838 res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_qtdemux_loop,
7839 sinkpad, NULL);
7840 } else {
7841 res = gst_pad_stop_task (sinkpad);
7842 }
7843 break;
7844 default:
7845 res = FALSE;
7846 break;
7847 }
7848 return res;
7849 }
7850
7851 #ifdef HAVE_ZLIB
7852 static void *
qtdemux_inflate(void * z_buffer,guint z_length,guint * length)7853 qtdemux_inflate (void *z_buffer, guint z_length, guint * length)
7854 {
7855 guint8 *buffer;
7856 z_stream z;
7857 int ret;
7858
7859 memset (&z, 0, sizeof (z));
7860 z.zalloc = NULL;
7861 z.zfree = NULL;
7862 z.opaque = NULL;
7863
7864 if ((ret = inflateInit (&z)) != Z_OK) {
7865 GST_ERROR ("inflateInit() returned %d", ret);
7866 return NULL;
7867 }
7868
7869 z.next_in = z_buffer;
7870 z.avail_in = z_length;
7871
7872 buffer = (guint8 *) g_malloc (*length);
7873 z.avail_out = *length;
7874 z.next_out = (Bytef *) buffer;
7875 do {
7876 ret = inflate (&z, Z_NO_FLUSH);
7877 if (ret == Z_STREAM_END) {
7878 break;
7879 } else if (ret != Z_OK) {
7880 GST_WARNING ("inflate() returned %d", ret);
7881 break;
7882 }
7883
7884 if (*length > G_MAXUINT - 4096 || *length > QTDEMUX_MAX_SAMPLE_INDEX_SIZE) {
7885 GST_WARNING ("too big decompressed data");
7886 ret = Z_MEM_ERROR;
7887 break;
7888 }
7889
7890 *length += 4096;
7891 buffer = (guint8 *) g_realloc (buffer, *length);
7892 z.next_out = (Bytef *) (buffer + z.total_out);
7893 z.avail_out += *length - z.total_out;
7894 } while (z.avail_in > 0);
7895
7896 if (ret != Z_STREAM_END) {
7897 g_free (buffer);
7898 buffer = NULL;
7899 *length = 0;
7900 } else {
7901 *length = z.total_out;
7902 }
7903
7904 inflateEnd (&z);
7905
7906 return buffer;
7907 }
7908 #endif /* HAVE_ZLIB */
7909
7910 static gboolean
qtdemux_parse_moov(GstQTDemux * qtdemux,const guint8 * buffer,guint length)7911 qtdemux_parse_moov (GstQTDemux * qtdemux, const guint8 * buffer, guint length)
7912 {
7913 GNode *cmov;
7914
7915 qtdemux->moov_node = g_node_new ((guint8 *) buffer);
7916
7917 /* counts as header data */
7918 qtdemux->header_size += length;
7919
7920 GST_DEBUG_OBJECT (qtdemux, "parsing 'moov' atom");
7921 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buffer, length);
7922
7923 cmov = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_cmov);
7924 if (cmov) {
7925 guint32 method;
7926 GNode *dcom;
7927 GNode *cmvd;
7928 guint32 dcom_len;
7929
7930 dcom = qtdemux_tree_get_child_by_type (cmov, FOURCC_dcom);
7931 cmvd = qtdemux_tree_get_child_by_type (cmov, FOURCC_cmvd);
7932 if (dcom == NULL || cmvd == NULL)
7933 goto invalid_compression;
7934
7935 dcom_len = QT_UINT32 (dcom->data);
7936 if (dcom_len < 12)
7937 goto invalid_compression;
7938
7939 method = QT_FOURCC ((guint8 *) dcom->data + 8);
7940 switch (method) {
7941 #ifdef HAVE_ZLIB
7942 case FOURCC_zlib:{
7943 guint uncompressed_length;
7944 guint compressed_length;
7945 guint8 *buf;
7946 guint32 cmvd_len;
7947
7948 cmvd_len = QT_UINT32 ((guint8 *) cmvd->data);
7949 if (cmvd_len < 12)
7950 goto invalid_compression;
7951
7952 uncompressed_length = QT_UINT32 ((guint8 *) cmvd->data + 8);
7953 compressed_length = cmvd_len - 12;
7954 GST_LOG ("length = %u", uncompressed_length);
7955
7956 buf =
7957 (guint8 *) qtdemux_inflate ((guint8 *) cmvd->data + 12,
7958 compressed_length, &uncompressed_length);
7959
7960 if (buf) {
7961 qtdemux->moov_node_compressed = qtdemux->moov_node;
7962 qtdemux->moov_node = g_node_new (buf);
7963
7964 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buf,
7965 uncompressed_length);
7966 }
7967 break;
7968 }
7969 #endif /* HAVE_ZLIB */
7970 default:
7971 GST_WARNING_OBJECT (qtdemux, "unknown or unhandled header compression "
7972 "type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (method));
7973 break;
7974 }
7975 }
7976 return TRUE;
7977
7978 /* ERRORS */
7979 invalid_compression:
7980 {
7981 GST_ERROR_OBJECT (qtdemux, "invalid compressed header");
7982 return FALSE;
7983 }
7984 }
7985
7986 static gboolean
qtdemux_parse_container(GstQTDemux * qtdemux,GNode * node,const guint8 * buf,const guint8 * end)7987 qtdemux_parse_container (GstQTDemux * qtdemux, GNode * node, const guint8 * buf,
7988 const guint8 * end)
7989 {
7990 while (G_UNLIKELY (buf < end)) {
7991 GNode *child;
7992 guint32 len;
7993
7994 if (G_UNLIKELY (buf + 4 > end)) {
7995 GST_LOG_OBJECT (qtdemux, "buffer overrun");
7996 break;
7997 }
7998 len = QT_UINT32 (buf);
7999 if (G_UNLIKELY (len == 0)) {
8000 GST_LOG_OBJECT (qtdemux, "empty container");
8001 break;
8002 }
8003 if (G_UNLIKELY (len < 8)) {
8004 GST_WARNING_OBJECT (qtdemux, "length too short (%d < 8)", len);
8005 break;
8006 }
8007 if (G_UNLIKELY (len > (end - buf))) {
8008 GST_WARNING_OBJECT (qtdemux, "length too long (%d > %d)", len,
8009 (gint) (end - buf));
8010 break;
8011 }
8012
8013 child = g_node_new ((guint8 *) buf);
8014 g_node_append (node, child);
8015 GST_LOG_OBJECT (qtdemux, "adding new node of len %d", len);
8016 qtdemux_parse_node (qtdemux, child, buf, len);
8017
8018 buf += len;
8019 }
8020 return TRUE;
8021 }
8022
8023 static gboolean
qtdemux_parse_theora_extension(GstQTDemux * qtdemux,QtDemuxStream * stream,GNode * xdxt)8024 qtdemux_parse_theora_extension (GstQTDemux * qtdemux, QtDemuxStream * stream,
8025 GNode * xdxt)
8026 {
8027 int len = QT_UINT32 (xdxt->data);
8028 guint8 *buf = xdxt->data;
8029 guint8 *end = buf + len;
8030 GstBuffer *buffer;
8031
8032 /* skip size and type */
8033 buf += 8;
8034 end -= 8;
8035
8036 while (buf < end) {
8037 gint size;
8038 guint32 type;
8039
8040 size = QT_UINT32 (buf);
8041 type = QT_FOURCC (buf + 4);
8042
8043 GST_LOG_OBJECT (qtdemux, "%p %p", buf, end);
8044
8045 if (buf + size > end || size <= 0)
8046 break;
8047
8048 buf += 8;
8049 size -= 8;
8050
8051 GST_WARNING_OBJECT (qtdemux, "have cookie %" GST_FOURCC_FORMAT,
8052 GST_FOURCC_ARGS (type));
8053
8054 switch (type) {
8055 case FOURCC_tCtH:
8056 buffer = gst_buffer_new_and_alloc (size);
8057 gst_buffer_fill (buffer, 0, buf, size);
8058 stream->buffers = g_slist_append (stream->buffers, buffer);
8059 GST_LOG_OBJECT (qtdemux, "parsing theora header");
8060 break;
8061 case FOURCC_tCt_:
8062 buffer = gst_buffer_new_and_alloc (size);
8063 gst_buffer_fill (buffer, 0, buf, size);
8064 stream->buffers = g_slist_append (stream->buffers, buffer);
8065 GST_LOG_OBJECT (qtdemux, "parsing theora comment");
8066 break;
8067 case FOURCC_tCtC:
8068 buffer = gst_buffer_new_and_alloc (size);
8069 gst_buffer_fill (buffer, 0, buf, size);
8070 stream->buffers = g_slist_append (stream->buffers, buffer);
8071 GST_LOG_OBJECT (qtdemux, "parsing theora codebook");
8072 break;
8073 default:
8074 GST_WARNING_OBJECT (qtdemux,
8075 "unknown theora cookie %" GST_FOURCC_FORMAT,
8076 GST_FOURCC_ARGS (type));
8077 break;
8078 }
8079 buf += size;
8080 }
8081 return TRUE;
8082 }
8083
8084 static gboolean
qtdemux_parse_node(GstQTDemux * qtdemux,GNode * node,const guint8 * buffer,guint length)8085 qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node, const guint8 * buffer,
8086 guint length)
8087 {
8088 guint32 fourcc = 0;
8089 guint32 node_length = 0;
8090 const QtNodeType *type;
8091 const guint8 *end;
8092
8093 GST_LOG_OBJECT (qtdemux, "qtdemux_parse buffer %p length %u", buffer, length);
8094
8095 if (G_UNLIKELY (length < 8))
8096 goto not_enough_data;
8097
8098 node_length = QT_UINT32 (buffer);
8099 fourcc = QT_FOURCC (buffer + 4);
8100
8101 /* ignore empty nodes */
8102 if (G_UNLIKELY (fourcc == 0 || node_length == 8))
8103 return TRUE;
8104
8105 type = qtdemux_type_get (fourcc);
8106
8107 end = buffer + length;
8108
8109 GST_LOG_OBJECT (qtdemux,
8110 "parsing '%" GST_FOURCC_FORMAT "', length=%u, name '%s'",
8111 GST_FOURCC_ARGS (fourcc), node_length, type->name);
8112
8113 if (node_length > length)
8114 goto broken_atom_size;
8115
8116 if (type->flags & QT_FLAG_CONTAINER) {
8117 qtdemux_parse_container (qtdemux, node, buffer + 8, end);
8118 } else {
8119 switch (fourcc) {
8120 case FOURCC_stsd:
8121 {
8122 if (node_length < 20) {
8123 GST_LOG_OBJECT (qtdemux, "skipping small stsd box");
8124 break;
8125 }
8126 GST_DEBUG_OBJECT (qtdemux,
8127 "parsing stsd (sample table, sample description) atom");
8128 /* Skip over 8 byte atom hdr + 1 byte version, 3 bytes flags, 4 byte num_entries */
8129 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
8130 break;
8131 }
8132 case FOURCC_mp4a:
8133 case FOURCC_alac:
8134 case FOURCC_fLaC:
8135 case FOURCC_aavd:
8136 {
8137 guint32 version;
8138 guint32 offset;
8139 guint min_size;
8140
8141 /* also read alac (or whatever) in stead of mp4a in the following,
8142 * since a similar layout is used in other cases as well */
8143 if (fourcc == FOURCC_mp4a)
8144 min_size = 20;
8145 else if (fourcc == FOURCC_fLaC)
8146 min_size = 86;
8147 else
8148 min_size = 40;
8149
8150 /* There are two things we might encounter here: a true mp4a atom, and
8151 an mp4a entry in an stsd atom. The latter is what we're interested
8152 in, and it looks like an atom, but isn't really one. The true mp4a
8153 atom is short, so we detect it based on length here. */
8154 if (length < min_size) {
8155 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
8156 GST_FOURCC_ARGS (fourcc));
8157 break;
8158 }
8159
8160 /* 'version' here is the sound sample description version. Types 0 and
8161 1 are documented in the QTFF reference, but type 2 is not: it's
8162 described in Apple header files instead (struct SoundDescriptionV2
8163 in Movies.h) */
8164 version = QT_UINT16 (buffer + 16);
8165
8166 GST_DEBUG_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT " version 0x%08x",
8167 GST_FOURCC_ARGS (fourcc), version);
8168
8169 /* parse any esds descriptors */
8170 switch (version) {
8171 case 0:
8172 offset = 0x24;
8173 break;
8174 case 1:
8175 offset = 0x34;
8176 break;
8177 case 2:
8178 offset = 0x48;
8179 break;
8180 default:
8181 GST_WARNING_OBJECT (qtdemux,
8182 "unhandled %" GST_FOURCC_FORMAT " version 0x%08x",
8183 GST_FOURCC_ARGS (fourcc), version);
8184 offset = 0;
8185 break;
8186 }
8187 if (offset)
8188 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
8189 break;
8190 }
8191 case FOURCC_mp4v:
8192 case FOURCC_MP4V:
8193 case FOURCC_fmp4:
8194 case FOURCC_FMP4:
8195 case FOURCC_apcs:
8196 case FOURCC_apch:
8197 case FOURCC_apcn:
8198 case FOURCC_apco:
8199 case FOURCC_ap4h:
8200 case FOURCC_xvid:
8201 case FOURCC_XVID:
8202 case FOURCC_H264:
8203 case FOURCC_avc1:
8204 case FOURCC_avc3:
8205 case FOURCC_H265:
8206 case FOURCC_hvc1:
8207 case FOURCC_hev1:
8208 case FOURCC_dvh1:
8209 case FOURCC_dvhe:
8210 case FOURCC_mjp2:
8211 case FOURCC_encv:
8212 {
8213 guint32 version;
8214 guint32 str_len;
8215
8216 /* codec_data is contained inside these atoms, which all have
8217 * the same format. */
8218 /* video sample description size is 86 bytes without extension.
8219 * node_length have to be bigger than 86 bytes because video sample
8220 * description can include extensions such as esds, fiel, glbl, etc. */
8221 if (node_length < 86) {
8222 GST_WARNING_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT
8223 " sample description length too short (%u < 86)",
8224 GST_FOURCC_ARGS (fourcc), node_length);
8225 break;
8226 }
8227
8228 GST_DEBUG_OBJECT (qtdemux, "parsing in %" GST_FOURCC_FORMAT,
8229 GST_FOURCC_ARGS (fourcc));
8230
8231 /* version (2 bytes) : this is set to 0, unless a compressor has changed
8232 * its data format.
8233 * revision level (2 bytes) : must be set to 0. */
8234 version = QT_UINT32 (buffer + 16);
8235 GST_DEBUG_OBJECT (qtdemux, "version %08x", version);
8236
8237 /* compressor name : PASCAL string and informative purposes
8238 * first byte : the number of bytes to be displayed.
8239 * it has to be less than 32 because it is reserved
8240 * space of 32 bytes total including itself. */
8241 str_len = QT_UINT8 (buffer + 50);
8242 if (str_len < 32)
8243 GST_DEBUG_OBJECT (qtdemux, "compressorname = %.*s", str_len,
8244 (char *) buffer + 51);
8245 else
8246 GST_WARNING_OBJECT (qtdemux,
8247 "compressorname length too big (%u > 31)", str_len);
8248
8249 GST_MEMDUMP_OBJECT (qtdemux, "video sample description", buffer,
8250 end - buffer);
8251 qtdemux_parse_container (qtdemux, node, buffer + 86, end);
8252 break;
8253 }
8254 case FOURCC_meta:
8255 {
8256 GST_DEBUG_OBJECT (qtdemux, "parsing meta atom");
8257
8258 /* You are reading this correctly. QTFF specifies that the
8259 * metadata atom is a short atom, whereas ISO BMFF specifies
8260 * it's a full atom. But since so many people are doing things
8261 * differently, we actually peek into the atom to see which
8262 * variant it is */
8263 if (length < 16) {
8264 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
8265 GST_FOURCC_ARGS (fourcc));
8266 break;
8267 }
8268 if (QT_FOURCC (buffer + 12) == FOURCC_hdlr) {
8269 /* Variant 1: What QTFF specifies. 'meta' is a short header which
8270 * starts with a 'hdlr' atom */
8271 qtdemux_parse_container (qtdemux, node, buffer + 8, end);
8272 } else if (QT_UINT32 (buffer + 8) == 0x00000000) {
8273 /* Variant 2: What ISO BMFF specifies. 'meta' is a _full_ atom
8274 * with version/flags both set to zero */
8275 qtdemux_parse_container (qtdemux, node, buffer + 12, end);
8276 } else
8277 GST_WARNING_OBJECT (qtdemux, "Unknown 'meta' atom format");
8278 break;
8279 }
8280 case FOURCC_mp4s:
8281 {
8282 GST_MEMDUMP_OBJECT (qtdemux, "mp4s", buffer, end - buffer);
8283 /* Skip 8 byte header, plus 8 byte version + flags + entry_count */
8284 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
8285 break;
8286 }
8287 case FOURCC_XiTh:
8288 {
8289 guint32 version;
8290 guint32 offset;
8291
8292 if (length < 16) {
8293 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
8294 GST_FOURCC_ARGS (fourcc));
8295 break;
8296 }
8297
8298 version = QT_UINT32 (buffer + 12);
8299 GST_DEBUG_OBJECT (qtdemux, "parsing XiTh atom version 0x%08x", version);
8300
8301 switch (version) {
8302 case 0x00000001:
8303 offset = 0x62;
8304 break;
8305 default:
8306 GST_DEBUG_OBJECT (qtdemux, "unknown version 0x%08x", version);
8307 offset = 0;
8308 break;
8309 }
8310 if (offset) {
8311 if (length < offset) {
8312 GST_WARNING_OBJECT (qtdemux,
8313 "skipping too small %" GST_FOURCC_FORMAT " box",
8314 GST_FOURCC_ARGS (fourcc));
8315 break;
8316 }
8317 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
8318 }
8319 break;
8320 }
8321 case FOURCC_in24:
8322 {
8323 qtdemux_parse_container (qtdemux, node, buffer + 0x34, end);
8324 break;
8325 }
8326 case FOURCC_uuid:
8327 {
8328 qtdemux_parse_uuid (qtdemux, buffer, end - buffer);
8329 break;
8330 }
8331 case FOURCC_enca:
8332 {
8333 qtdemux_parse_container (qtdemux, node, buffer + 36, end);
8334 break;
8335 }
8336 default:
8337 if (!strcmp (type->name, "unknown"))
8338 GST_MEMDUMP ("Unknown tag", buffer + 4, end - buffer - 4);
8339 break;
8340 }
8341 }
8342 GST_LOG_OBJECT (qtdemux, "parsed '%" GST_FOURCC_FORMAT "'",
8343 GST_FOURCC_ARGS (fourcc));
8344 return TRUE;
8345
8346 /* ERRORS */
8347 not_enough_data:
8348 {
8349 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8350 (_("This file is corrupt and cannot be played.")),
8351 ("Not enough data for an atom header, got only %u bytes", length));
8352 return FALSE;
8353 }
8354 broken_atom_size:
8355 {
8356 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8357 (_("This file is corrupt and cannot be played.")),
8358 ("Atom '%" GST_FOURCC_FORMAT "' has size of %u bytes, but we have only "
8359 "%u bytes available.", GST_FOURCC_ARGS (fourcc), node_length,
8360 length));
8361 return FALSE;
8362 }
8363 }
8364
8365 static void
qtdemux_do_allocation(QtDemuxStream * stream,GstQTDemux * qtdemux)8366 qtdemux_do_allocation (QtDemuxStream * stream, GstQTDemux * qtdemux)
8367 {
8368 /* FIXME: This can only reliably work if demuxers have a
8369 * separate streaming thread per srcpad. This should be
8370 * done in a demuxer base class, which integrates parts
8371 * of multiqueue
8372 *
8373 * https://bugzilla.gnome.org/show_bug.cgi?id=701856
8374 */
8375 #if 0
8376 GstQuery *query;
8377
8378 query = gst_query_new_allocation (stream->caps, FALSE);
8379
8380 if (!gst_pad_peer_query (stream->pad, query)) {
8381 /* not a problem, just debug a little */
8382 GST_DEBUG_OBJECT (qtdemux, "peer ALLOCATION query failed");
8383 }
8384
8385 if (stream->allocator)
8386 gst_object_unref (stream->allocator);
8387
8388 if (gst_query_get_n_allocation_params (query) > 0) {
8389 /* try the allocator */
8390 gst_query_parse_nth_allocation_param (query, 0, &stream->allocator,
8391 &stream->params);
8392 stream->use_allocator = TRUE;
8393 } else {
8394 stream->allocator = NULL;
8395 gst_allocation_params_init (&stream->params);
8396 stream->use_allocator = FALSE;
8397 }
8398 gst_query_unref (query);
8399 #endif
8400 }
8401
8402 static gboolean
pad_query(const GValue * item,GValue * value,gpointer user_data)8403 pad_query (const GValue * item, GValue * value, gpointer user_data)
8404 {
8405 GstPad *pad = g_value_get_object (item);
8406 GstQuery *query = user_data;
8407 gboolean res;
8408
8409 res = gst_pad_peer_query (pad, query);
8410
8411 if (res) {
8412 g_value_set_boolean (value, TRUE);
8413 return FALSE;
8414 }
8415
8416 GST_INFO_OBJECT (pad, "pad peer query failed");
8417 return TRUE;
8418 }
8419
8420 static gboolean
gst_qtdemux_run_query(GstElement * element,GstQuery * query,GstPadDirection direction)8421 gst_qtdemux_run_query (GstElement * element, GstQuery * query,
8422 GstPadDirection direction)
8423 {
8424 GstIterator *it;
8425 GstIteratorFoldFunction func = pad_query;
8426 GValue res = { 0, };
8427
8428 g_value_init (&res, G_TYPE_BOOLEAN);
8429 g_value_set_boolean (&res, FALSE);
8430
8431 /* Ask neighbor */
8432 if (direction == GST_PAD_SRC)
8433 it = gst_element_iterate_src_pads (element);
8434 else
8435 it = gst_element_iterate_sink_pads (element);
8436
8437 while (gst_iterator_fold (it, func, &res, query) == GST_ITERATOR_RESYNC)
8438 gst_iterator_resync (it);
8439
8440 gst_iterator_free (it);
8441
8442 return g_value_get_boolean (&res);
8443 }
8444
8445 static void
gst_qtdemux_request_protection_context(GstQTDemux * qtdemux,QtDemuxStream * stream)8446 gst_qtdemux_request_protection_context (GstQTDemux * qtdemux,
8447 QtDemuxStream * stream)
8448 {
8449 GstQuery *query;
8450 GstContext *ctxt;
8451 GstElement *element = GST_ELEMENT (qtdemux);
8452 GstStructure *st;
8453 gchar **filtered_sys_ids;
8454 GValue event_list = G_VALUE_INIT;
8455 GList *walk;
8456
8457 /* 1. Check if we already have the context. */
8458 if (qtdemux->preferred_protection_system_id != NULL) {
8459 GST_LOG_OBJECT (element,
8460 "already have the protection context, no need to request it again");
8461 return;
8462 }
8463
8464 g_ptr_array_add (qtdemux->protection_system_ids, NULL);
8465 filtered_sys_ids = gst_protection_filter_systems_by_available_decryptors (
8466 (const gchar **) qtdemux->protection_system_ids->pdata);
8467
8468 g_ptr_array_remove_index (qtdemux->protection_system_ids,
8469 qtdemux->protection_system_ids->len - 1);
8470 GST_TRACE_OBJECT (qtdemux, "detected %u protection systems, we have "
8471 "decryptors for %u of them, running context request",
8472 qtdemux->protection_system_ids->len,
8473 filtered_sys_ids ? g_strv_length (filtered_sys_ids) : 0);
8474
8475
8476 if (stream->protection_scheme_event_queue.length) {
8477 GST_TRACE_OBJECT (qtdemux, "using stream event queue, length %u",
8478 stream->protection_scheme_event_queue.length);
8479 walk = stream->protection_scheme_event_queue.tail;
8480 } else {
8481 GST_TRACE_OBJECT (qtdemux, "using demuxer event queue, length %u",
8482 qtdemux->protection_event_queue.length);
8483 walk = qtdemux->protection_event_queue.tail;
8484 }
8485
8486 g_value_init (&event_list, GST_TYPE_LIST);
8487 for (; walk; walk = g_list_previous (walk)) {
8488 GValue *event_value = g_new0 (GValue, 1);
8489 g_value_init (event_value, GST_TYPE_EVENT);
8490 g_value_set_boxed (event_value, walk->data);
8491 gst_value_list_append_and_take_value (&event_list, event_value);
8492 }
8493
8494 /* 2a) Query downstream with GST_QUERY_CONTEXT for the context and
8495 * check if downstream already has a context of the specific type
8496 * 2b) Query upstream as above.
8497 */
8498 query = gst_query_new_context ("drm-preferred-decryption-system-id");
8499 st = gst_query_writable_structure (query);
8500 gst_structure_set (st, "track-id", G_TYPE_UINT, stream->track_id,
8501 "available-stream-encryption-systems", G_TYPE_STRV, filtered_sys_ids,
8502 NULL);
8503 gst_structure_set_value (st, "stream-encryption-events", &event_list);
8504 if (gst_qtdemux_run_query (element, query, GST_PAD_SRC)) {
8505 gst_query_parse_context (query, &ctxt);
8506 GST_INFO_OBJECT (element, "found context (%p) in downstream query", ctxt);
8507 gst_element_set_context (element, ctxt);
8508 } else if (gst_qtdemux_run_query (element, query, GST_PAD_SINK)) {
8509 gst_query_parse_context (query, &ctxt);
8510 GST_INFO_OBJECT (element, "found context (%p) in upstream query", ctxt);
8511 gst_element_set_context (element, ctxt);
8512 } else {
8513 /* 3) Post a GST_MESSAGE_NEED_CONTEXT message on the bus with
8514 * the required context type and afterwards check if a
8515 * usable context was set now as in 1). The message could
8516 * be handled by the parent bins of the element and the
8517 * application.
8518 */
8519 GstMessage *msg;
8520
8521 GST_INFO_OBJECT (element, "posting need context message");
8522 msg = gst_message_new_need_context (GST_OBJECT_CAST (element),
8523 "drm-preferred-decryption-system-id");
8524 st = (GstStructure *) gst_message_get_structure (msg);
8525 gst_structure_set (st, "track-id", G_TYPE_UINT, stream->track_id,
8526 "available-stream-encryption-systems", G_TYPE_STRV, filtered_sys_ids,
8527 NULL);
8528
8529 gst_structure_set_value (st, "stream-encryption-events", &event_list);
8530 gst_element_post_message (element, msg);
8531 }
8532
8533 g_strfreev (filtered_sys_ids);
8534 g_value_unset (&event_list);
8535 gst_query_unref (query);
8536 }
8537
8538 static gboolean
gst_qtdemux_configure_protected_caps(GstQTDemux * qtdemux,QtDemuxStream * stream)8539 gst_qtdemux_configure_protected_caps (GstQTDemux * qtdemux,
8540 QtDemuxStream * stream)
8541 {
8542 GstStructure *s;
8543 const gchar *selected_system = NULL;
8544
8545 g_return_val_if_fail (qtdemux != NULL, FALSE);
8546 g_return_val_if_fail (stream != NULL, FALSE);
8547 g_return_val_if_fail (gst_caps_get_size (CUR_STREAM (stream)->caps) == 1,
8548 FALSE);
8549
8550 if (stream->protection_scheme_type == FOURCC_aavd) {
8551 s = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
8552 if (!gst_structure_has_name (s, "application/x-aavd")) {
8553 gst_structure_set (s,
8554 "original-media-type", G_TYPE_STRING, gst_structure_get_name (s),
8555 NULL);
8556 gst_structure_set_name (s, "application/x-aavd");
8557 }
8558 return TRUE;
8559 }
8560
8561 if (stream->protection_scheme_type != FOURCC_cenc
8562 && stream->protection_scheme_type != FOURCC_cbcs) {
8563 GST_ERROR_OBJECT (qtdemux,
8564 "unsupported protection scheme: %" GST_FOURCC_FORMAT,
8565 GST_FOURCC_ARGS (stream->protection_scheme_type));
8566 return FALSE;
8567 }
8568
8569 s = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
8570 if (!gst_structure_has_name (s, "application/x-cenc")) {
8571 gst_structure_set (s,
8572 "original-media-type", G_TYPE_STRING, gst_structure_get_name (s), NULL);
8573 gst_structure_set (s, "cipher-mode", G_TYPE_STRING,
8574 (stream->protection_scheme_type == FOURCC_cbcs) ? "cbcs" : "cenc",
8575 NULL);
8576 gst_structure_set_name (s, "application/x-cenc");
8577 }
8578
8579 if (qtdemux->protection_system_ids == NULL) {
8580 GST_DEBUG_OBJECT (qtdemux, "stream is protected using cenc, but no "
8581 "cenc protection system information has been found, not setting a "
8582 "protection system UUID");
8583 return TRUE;
8584 }
8585
8586 gst_qtdemux_request_protection_context (qtdemux, stream);
8587 if (qtdemux->preferred_protection_system_id != NULL) {
8588 const gchar *preferred_system_array[] =
8589 { qtdemux->preferred_protection_system_id, NULL };
8590
8591 selected_system = gst_protection_select_system (preferred_system_array);
8592
8593 if (selected_system) {
8594 GST_TRACE_OBJECT (qtdemux, "selected preferred system %s",
8595 qtdemux->preferred_protection_system_id);
8596 } else {
8597 GST_WARNING_OBJECT (qtdemux, "could not select preferred system %s "
8598 "because there is no available decryptor",
8599 qtdemux->preferred_protection_system_id);
8600 }
8601 }
8602
8603 if (!selected_system) {
8604 g_ptr_array_add (qtdemux->protection_system_ids, NULL);
8605 selected_system = gst_protection_select_system ((const gchar **)
8606 qtdemux->protection_system_ids->pdata);
8607 g_ptr_array_remove_index (qtdemux->protection_system_ids,
8608 qtdemux->protection_system_ids->len - 1);
8609 }
8610
8611 if (!selected_system) {
8612 GST_ERROR_OBJECT (qtdemux, "stream is protected, but no "
8613 "suitable decryptor element has been found");
8614 return FALSE;
8615 }
8616
8617 GST_DEBUG_OBJECT (qtdemux, "selected protection system is %s",
8618 selected_system);
8619
8620 gst_structure_set (s,
8621 GST_PROTECTION_SYSTEM_ID_CAPS_FIELD, G_TYPE_STRING, selected_system,
8622 NULL);
8623
8624 return TRUE;
8625 }
8626
8627 static gboolean
gst_qtdemux_guess_framerate(GstQTDemux * qtdemux,QtDemuxStream * stream)8628 gst_qtdemux_guess_framerate (GstQTDemux * qtdemux, QtDemuxStream * stream)
8629 {
8630 /* fps is calculated base on the duration of the average framerate since
8631 * qt does not have a fixed framerate. */
8632 gboolean fps_available = TRUE;
8633 guint32 first_duration = 0;
8634
8635 if (stream->n_samples > 0)
8636 first_duration = stream->samples[0].duration;
8637
8638 if ((stream->n_samples == 1 && first_duration == 0)
8639 || (qtdemux->fragmented && stream->n_samples_moof == 1)) {
8640 /* still frame */
8641 CUR_STREAM (stream)->fps_n = 0;
8642 CUR_STREAM (stream)->fps_d = 1;
8643 } else {
8644 if (stream->duration == 0 || stream->n_samples < 2) {
8645 CUR_STREAM (stream)->fps_n = stream->timescale;
8646 CUR_STREAM (stream)->fps_d = 1;
8647 fps_available = FALSE;
8648 } else {
8649 GstClockTime avg_duration;
8650 guint64 duration;
8651 guint32 n_samples;
8652
8653 /* duration and n_samples can be updated for fragmented format
8654 * so, framerate of fragmented format is calculated using data in a moof */
8655 if (qtdemux->fragmented && stream->n_samples_moof > 0
8656 && stream->duration_moof > 0) {
8657 n_samples = stream->n_samples_moof;
8658 duration = stream->duration_moof;
8659 } else {
8660 n_samples = stream->n_samples;
8661 duration = stream->duration;
8662 }
8663
8664 /* Calculate a framerate, ignoring the first sample which is sometimes truncated */
8665 /* stream->duration is guint64, timescale, n_samples are guint32 */
8666 avg_duration =
8667 gst_util_uint64_scale_round (duration -
8668 first_duration, GST_SECOND,
8669 (guint64) (stream->timescale) * (n_samples - 1));
8670
8671 GST_LOG_OBJECT (qtdemux,
8672 "Calculating avg sample duration based on stream (or moof) duration %"
8673 G_GUINT64_FORMAT
8674 " minus first sample %u, leaving %d samples gives %"
8675 GST_TIME_FORMAT, duration, first_duration,
8676 n_samples - 1, GST_TIME_ARGS (avg_duration));
8677 #ifdef OHOS_OPT_COMPAT
8678 /**
8679 * ohos.opt.compat.0038
8680 * Solve the problem of correct frame rate not passing forward
8681 */
8682 if (avg_duration == 0) {
8683 fps_available = FALSE;
8684 GST_ERROR_OBJECT (qtdemux, "Calculating avg duration abnormal");
8685 } else {
8686 gst_video_guess_framerate (avg_duration, &CUR_STREAM (stream)->fps_n, &CUR_STREAM (stream)->fps_d);
8687 GST_DEBUG_OBJECT (qtdemux, "Guess framerate fps_n %d fps_d %d",
8688 CUR_STREAM (stream)->fps_n, CUR_STREAM (stream)->fps_d);
8689 }
8690 #else
8691 fps_available =
8692 gst_video_guess_framerate (avg_duration,
8693 &CUR_STREAM (stream)->fps_n, &CUR_STREAM (stream)->fps_d);
8694 #endif
8695 GST_DEBUG_OBJECT (qtdemux,
8696 "Calculating framerate, timescale %u gave fps_n %d fps_d %d",
8697 stream->timescale, CUR_STREAM (stream)->fps_n,
8698 CUR_STREAM (stream)->fps_d);
8699 }
8700 }
8701
8702 return fps_available;
8703 }
8704
8705 static gboolean
gst_qtdemux_configure_stream(GstQTDemux * qtdemux,QtDemuxStream * stream)8706 gst_qtdemux_configure_stream (GstQTDemux * qtdemux, QtDemuxStream * stream)
8707 {
8708 if (stream->subtype == FOURCC_vide) {
8709 gboolean fps_available = gst_qtdemux_guess_framerate (qtdemux, stream);
8710
8711 if (CUR_STREAM (stream)->caps) {
8712 CUR_STREAM (stream)->caps =
8713 gst_caps_make_writable (CUR_STREAM (stream)->caps);
8714
8715 if (CUR_STREAM (stream)->width && CUR_STREAM (stream)->height)
8716 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8717 "width", G_TYPE_INT, CUR_STREAM (stream)->width,
8718 "height", G_TYPE_INT, CUR_STREAM (stream)->height, NULL);
8719
8720 /* set framerate if calculated framerate is reliable */
8721 if (fps_available) {
8722 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8723 "framerate", GST_TYPE_FRACTION, CUR_STREAM (stream)->fps_n,
8724 CUR_STREAM (stream)->fps_d, NULL);
8725 }
8726
8727 /* calculate pixel-aspect-ratio using display width and height */
8728 GST_DEBUG_OBJECT (qtdemux,
8729 "video size %dx%d, target display size %dx%d",
8730 CUR_STREAM (stream)->width, CUR_STREAM (stream)->height,
8731 stream->display_width, stream->display_height);
8732 /* qt file might have pasp atom */
8733 if (CUR_STREAM (stream)->par_w > 0 && CUR_STREAM (stream)->par_h > 0) {
8734 GST_DEBUG_OBJECT (qtdemux, "par %d:%d", CUR_STREAM (stream)->par_w,
8735 CUR_STREAM (stream)->par_h);
8736 gst_caps_set_simple (CUR_STREAM (stream)->caps, "pixel-aspect-ratio",
8737 GST_TYPE_FRACTION, CUR_STREAM (stream)->par_w,
8738 CUR_STREAM (stream)->par_h, NULL);
8739 } else if (stream->display_width > 0 && stream->display_height > 0
8740 && CUR_STREAM (stream)->width > 0
8741 && CUR_STREAM (stream)->height > 0) {
8742 gint n, d;
8743
8744 /* calculate the pixel aspect ratio using the display and pixel w/h */
8745 n = stream->display_width * CUR_STREAM (stream)->height;
8746 d = stream->display_height * CUR_STREAM (stream)->width;
8747 if (n == d)
8748 n = d = 1;
8749 GST_DEBUG_OBJECT (qtdemux, "setting PAR to %d/%d", n, d);
8750 CUR_STREAM (stream)->par_w = n;
8751 CUR_STREAM (stream)->par_h = d;
8752 gst_caps_set_simple (CUR_STREAM (stream)->caps, "pixel-aspect-ratio",
8753 GST_TYPE_FRACTION, CUR_STREAM (stream)->par_w,
8754 CUR_STREAM (stream)->par_h, NULL);
8755 }
8756
8757 if (CUR_STREAM (stream)->interlace_mode > 0) {
8758 if (CUR_STREAM (stream)->interlace_mode == 1) {
8759 gst_caps_set_simple (CUR_STREAM (stream)->caps, "interlace-mode",
8760 G_TYPE_STRING, "progressive", NULL);
8761 } else if (CUR_STREAM (stream)->interlace_mode == 2) {
8762 gst_caps_set_simple (CUR_STREAM (stream)->caps, "interlace-mode",
8763 G_TYPE_STRING, "interleaved", NULL);
8764 if (CUR_STREAM (stream)->field_order == 9) {
8765 gst_caps_set_simple (CUR_STREAM (stream)->caps, "field-order",
8766 G_TYPE_STRING, "top-field-first", NULL);
8767 } else if (CUR_STREAM (stream)->field_order == 14) {
8768 gst_caps_set_simple (CUR_STREAM (stream)->caps, "field-order",
8769 G_TYPE_STRING, "bottom-field-first", NULL);
8770 }
8771 }
8772 }
8773
8774 /* Create incomplete colorimetry here if needed */
8775 if (CUR_STREAM (stream)->colorimetry.range ||
8776 CUR_STREAM (stream)->colorimetry.matrix ||
8777 CUR_STREAM (stream)->colorimetry.transfer
8778 || CUR_STREAM (stream)->colorimetry.primaries) {
8779 gchar *colorimetry =
8780 gst_video_colorimetry_to_string (&CUR_STREAM (stream)->colorimetry);
8781 gst_caps_set_simple (CUR_STREAM (stream)->caps, "colorimetry",
8782 G_TYPE_STRING, colorimetry, NULL);
8783 g_free (colorimetry);
8784 }
8785
8786 if (stream->multiview_mode != GST_VIDEO_MULTIVIEW_MODE_NONE) {
8787 guint par_w = 1, par_h = 1;
8788
8789 if (CUR_STREAM (stream)->par_w > 0 && CUR_STREAM (stream)->par_h > 0) {
8790 par_w = CUR_STREAM (stream)->par_w;
8791 par_h = CUR_STREAM (stream)->par_h;
8792 }
8793
8794 if (gst_video_multiview_guess_half_aspect (stream->multiview_mode,
8795 CUR_STREAM (stream)->width, CUR_STREAM (stream)->height, par_w,
8796 par_h)) {
8797 stream->multiview_flags |= GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT;
8798 }
8799
8800 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8801 "multiview-mode", G_TYPE_STRING,
8802 gst_video_multiview_mode_to_caps_string (stream->multiview_mode),
8803 "multiview-flags", GST_TYPE_VIDEO_MULTIVIEW_FLAGSET,
8804 stream->multiview_flags, GST_FLAG_SET_MASK_EXACT, NULL);
8805 }
8806 }
8807 }
8808
8809 else if (stream->subtype == FOURCC_soun) {
8810 if (CUR_STREAM (stream)->caps) {
8811 CUR_STREAM (stream)->caps =
8812 gst_caps_make_writable (CUR_STREAM (stream)->caps);
8813 if (CUR_STREAM (stream)->rate > 0)
8814 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8815 "rate", G_TYPE_INT, (int) CUR_STREAM (stream)->rate, NULL);
8816 if (CUR_STREAM (stream)->n_channels > 0)
8817 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8818 "channels", G_TYPE_INT, CUR_STREAM (stream)->n_channels, NULL);
8819 if (CUR_STREAM (stream)->n_channels > 2) {
8820 /* FIXME: Need to parse the 'chan' atom to get channel layouts
8821 * correctly; this is just the minimum we can do - assume
8822 * we don't actually have any channel positions. */
8823 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8824 "channel-mask", GST_TYPE_BITMASK, G_GUINT64_CONSTANT (0), NULL);
8825 }
8826 }
8827 }
8828
8829 else if (stream->subtype == FOURCC_clcp && CUR_STREAM (stream)->caps) {
8830 const GstStructure *s;
8831 QtDemuxStream *fps_stream = NULL;
8832 gboolean fps_available = FALSE;
8833
8834 /* CEA608 closed caption tracks are a bit special in that each sample
8835 * can contain CCs for multiple frames, and CCs can be omitted and have to
8836 * be inferred from the duration of the sample then.
8837 *
8838 * As such we take the framerate from the (first) video track here for
8839 * CEA608 as there must be one CC byte pair for every video frame
8840 * according to the spec.
8841 *
8842 * For CEA708 all is fine and there is one sample per frame.
8843 */
8844
8845 s = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
8846 if (gst_structure_has_name (s, "closedcaption/x-cea-608")) {
8847 gint i;
8848
8849 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
8850 QtDemuxStream *tmp = QTDEMUX_NTH_STREAM (qtdemux, i);
8851
8852 if (tmp->subtype == FOURCC_vide) {
8853 fps_stream = tmp;
8854 break;
8855 }
8856 }
8857
8858 if (fps_stream) {
8859 fps_available = gst_qtdemux_guess_framerate (qtdemux, fps_stream);
8860 CUR_STREAM (stream)->fps_n = CUR_STREAM (fps_stream)->fps_n;
8861 CUR_STREAM (stream)->fps_d = CUR_STREAM (fps_stream)->fps_d;
8862 }
8863 } else {
8864 fps_available = gst_qtdemux_guess_framerate (qtdemux, stream);
8865 fps_stream = stream;
8866 }
8867
8868 CUR_STREAM (stream)->caps =
8869 gst_caps_make_writable (CUR_STREAM (stream)->caps);
8870
8871 /* set framerate if calculated framerate is reliable */
8872 if (fps_available) {
8873 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8874 "framerate", GST_TYPE_FRACTION, CUR_STREAM (stream)->fps_n,
8875 CUR_STREAM (stream)->fps_d, NULL);
8876 }
8877 }
8878
8879 if (stream->pad) {
8880 GstCaps *prev_caps = NULL;
8881
8882 GST_PAD_ELEMENT_PRIVATE (stream->pad) = stream;
8883 gst_pad_set_event_function (stream->pad, gst_qtdemux_handle_src_event);
8884 gst_pad_set_query_function (stream->pad, gst_qtdemux_handle_src_query);
8885 gst_pad_set_active (stream->pad, TRUE);
8886
8887 gst_pad_use_fixed_caps (stream->pad);
8888
8889 if (stream->protected) {
8890 if (!gst_qtdemux_configure_protected_caps (qtdemux, stream)) {
8891 GST_ERROR_OBJECT (qtdemux,
8892 "Failed to configure protected stream caps.");
8893 return FALSE;
8894 }
8895 }
8896
8897 GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT,
8898 CUR_STREAM (stream)->caps);
8899 if (stream->new_stream) {
8900 GstEvent *event;
8901 GstStreamFlags stream_flags = GST_STREAM_FLAG_NONE;
8902
8903 event =
8904 gst_pad_get_sticky_event (qtdemux->sinkpad, GST_EVENT_STREAM_START,
8905 0);
8906 if (event) {
8907 gst_event_parse_stream_flags (event, &stream_flags);
8908 if (gst_event_parse_group_id (event, &qtdemux->group_id))
8909 qtdemux->have_group_id = TRUE;
8910 else
8911 qtdemux->have_group_id = FALSE;
8912 gst_event_unref (event);
8913 } else if (!qtdemux->have_group_id) {
8914 qtdemux->have_group_id = TRUE;
8915 qtdemux->group_id = gst_util_group_id_next ();
8916 }
8917
8918 stream->new_stream = FALSE;
8919 event = gst_event_new_stream_start (stream->stream_id);
8920 if (qtdemux->have_group_id)
8921 gst_event_set_group_id (event, qtdemux->group_id);
8922 if (stream->disabled)
8923 stream_flags |= GST_STREAM_FLAG_UNSELECT;
8924 if (CUR_STREAM (stream)->sparse) {
8925 stream_flags |= GST_STREAM_FLAG_SPARSE;
8926 } else {
8927 stream_flags &= ~GST_STREAM_FLAG_SPARSE;
8928 }
8929 gst_event_set_stream_flags (event, stream_flags);
8930 gst_pad_push_event (stream->pad, event);
8931 }
8932
8933 prev_caps = gst_pad_get_current_caps (stream->pad);
8934
8935 if (CUR_STREAM (stream)->caps) {
8936 if (!prev_caps
8937 || !gst_caps_is_equal_fixed (prev_caps, CUR_STREAM (stream)->caps)) {
8938 GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT,
8939 CUR_STREAM (stream)->caps);
8940 gst_pad_set_caps (stream->pad, CUR_STREAM (stream)->caps);
8941 } else {
8942 GST_DEBUG_OBJECT (qtdemux, "ignore duplicated caps");
8943 }
8944 } else {
8945 GST_WARNING_OBJECT (qtdemux, "stream without caps");
8946 }
8947
8948 if (prev_caps)
8949 gst_caps_unref (prev_caps);
8950 stream->new_caps = FALSE;
8951 }
8952 return TRUE;
8953 }
8954
8955 static void
gst_qtdemux_stream_check_and_change_stsd_index(GstQTDemux * demux,QtDemuxStream * stream)8956 gst_qtdemux_stream_check_and_change_stsd_index (GstQTDemux * demux,
8957 QtDemuxStream * stream)
8958 {
8959 if (stream->cur_stsd_entry_index == stream->stsd_sample_description_id)
8960 return;
8961
8962 GST_DEBUG_OBJECT (stream->pad, "Changing stsd index from '%u' to '%u'",
8963 stream->cur_stsd_entry_index, stream->stsd_sample_description_id);
8964 if (G_UNLIKELY (stream->stsd_sample_description_id >=
8965 stream->stsd_entries_length)) {
8966 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
8967 (_("This file is invalid and cannot be played.")),
8968 ("New sample description id is out of bounds (%d >= %d)",
8969 stream->stsd_sample_description_id, stream->stsd_entries_length));
8970 } else {
8971 stream->cur_stsd_entry_index = stream->stsd_sample_description_id;
8972 stream->new_caps = TRUE;
8973 }
8974 }
8975
8976 static gboolean
gst_qtdemux_add_stream(GstQTDemux * qtdemux,QtDemuxStream * stream,GstTagList * list)8977 gst_qtdemux_add_stream (GstQTDemux * qtdemux,
8978 QtDemuxStream * stream, GstTagList * list)
8979 {
8980 gboolean ret = TRUE;
8981
8982 if (stream->subtype == FOURCC_vide) {
8983 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
8984
8985 stream->pad =
8986 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
8987 g_free (name);
8988
8989 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8990 gst_object_unref (stream->pad);
8991 stream->pad = NULL;
8992 ret = FALSE;
8993 goto done;
8994 }
8995
8996 qtdemux->n_video_streams++;
8997 } else if (stream->subtype == FOURCC_soun) {
8998 gchar *name = g_strdup_printf ("audio_%u", qtdemux->n_audio_streams);
8999
9000 stream->pad =
9001 gst_pad_new_from_static_template (&gst_qtdemux_audiosrc_template, name);
9002 g_free (name);
9003 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
9004 gst_object_unref (stream->pad);
9005 stream->pad = NULL;
9006 ret = FALSE;
9007 goto done;
9008 }
9009 qtdemux->n_audio_streams++;
9010 } else if (stream->subtype == FOURCC_strm) {
9011 GST_DEBUG_OBJECT (qtdemux, "stream type, not creating pad");
9012 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
9013 || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt
9014 || stream->subtype == FOURCC_clcp || stream->subtype == FOURCC_wvtt) {
9015 gchar *name = g_strdup_printf ("subtitle_%u", qtdemux->n_sub_streams);
9016
9017 stream->pad =
9018 gst_pad_new_from_static_template (&gst_qtdemux_subsrc_template, name);
9019 g_free (name);
9020 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
9021 gst_object_unref (stream->pad);
9022 stream->pad = NULL;
9023 ret = FALSE;
9024 goto done;
9025 }
9026 qtdemux->n_sub_streams++;
9027 } else if (CUR_STREAM (stream)->caps) {
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 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
9034 gst_object_unref (stream->pad);
9035 stream->pad = NULL;
9036 ret = FALSE;
9037 goto done;
9038 }
9039 qtdemux->n_video_streams++;
9040 } else {
9041 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
9042 goto done;
9043 }
9044
9045 if (stream->pad) {
9046 GList *l;
9047
9048 GST_DEBUG_OBJECT (qtdemux, "adding pad %s %p to qtdemux %p",
9049 GST_OBJECT_NAME (stream->pad), stream->pad, qtdemux);
9050 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
9051 GST_OBJECT_LOCK (qtdemux);
9052 gst_flow_combiner_add_pad (qtdemux->flowcombiner, stream->pad);
9053 GST_OBJECT_UNLOCK (qtdemux);
9054
9055 if (stream->stream_tags)
9056 gst_tag_list_unref (stream->stream_tags);
9057 stream->stream_tags = list;
9058 list = NULL;
9059 /* global tags go on each pad anyway */
9060 stream->send_global_tags = TRUE;
9061 /* send upstream GST_EVENT_PROTECTION events that were received before
9062 this source pad was created */
9063 for (l = qtdemux->protection_event_queue.head; l != NULL; l = l->next)
9064 gst_pad_push_event (stream->pad, gst_event_ref (l->data));
9065 }
9066 done:
9067 if (list)
9068 gst_tag_list_unref (list);
9069 return ret;
9070 }
9071
9072 /* find next atom with @fourcc starting at @offset */
9073 static GstFlowReturn
qtdemux_find_atom(GstQTDemux * qtdemux,guint64 * offset,guint64 * length,guint32 fourcc)9074 qtdemux_find_atom (GstQTDemux * qtdemux, guint64 * offset,
9075 guint64 * length, guint32 fourcc)
9076 {
9077 GstFlowReturn ret;
9078 guint32 lfourcc;
9079 GstBuffer *buf;
9080
9081 GST_LOG_OBJECT (qtdemux, "finding fourcc %" GST_FOURCC_FORMAT " at offset %"
9082 G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), *offset);
9083
9084 while (TRUE) {
9085 GstMapInfo map;
9086
9087 buf = NULL;
9088 ret = gst_pad_pull_range (qtdemux->sinkpad, *offset, 16, &buf);
9089 if (G_UNLIKELY (ret != GST_FLOW_OK))
9090 goto locate_failed;
9091 if (G_UNLIKELY (gst_buffer_get_size (buf) != 16)) {
9092 /* likely EOF */
9093 ret = GST_FLOW_EOS;
9094 gst_buffer_unref (buf);
9095 goto locate_failed;
9096 }
9097 gst_buffer_map (buf, &map, GST_MAP_READ);
9098 extract_initial_length_and_fourcc (map.data, 16, length, &lfourcc);
9099 gst_buffer_unmap (buf, &map);
9100 gst_buffer_unref (buf);
9101
9102 if (G_UNLIKELY (*length == 0)) {
9103 GST_DEBUG_OBJECT (qtdemux, "invalid length 0");
9104 ret = GST_FLOW_ERROR;
9105 goto locate_failed;
9106 }
9107
9108 if (lfourcc == fourcc) {
9109 GST_DEBUG_OBJECT (qtdemux, "found '%" GST_FOURCC_FORMAT " at offset %"
9110 G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), *offset);
9111 break;
9112 } else {
9113 GST_LOG_OBJECT (qtdemux,
9114 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
9115 GST_FOURCC_ARGS (lfourcc), *offset);
9116 if (*offset == G_MAXUINT64)
9117 goto locate_failed;
9118 *offset += *length;
9119 }
9120 }
9121
9122 return GST_FLOW_OK;
9123
9124 locate_failed:
9125 {
9126 /* might simply have had last one */
9127 GST_DEBUG_OBJECT (qtdemux, "fourcc not found");
9128 return ret;
9129 }
9130 }
9131
9132 /* should only do something in pull mode */
9133 /* call with OBJECT lock */
9134 static GstFlowReturn
qtdemux_add_fragmented_samples(GstQTDemux * qtdemux)9135 qtdemux_add_fragmented_samples (GstQTDemux * qtdemux)
9136 {
9137 guint64 length, offset;
9138 GstBuffer *buf = NULL;
9139 GstFlowReturn ret = GST_FLOW_OK;
9140 GstFlowReturn res = GST_FLOW_OK;
9141 GstMapInfo map;
9142
9143 offset = qtdemux->moof_offset;
9144 GST_DEBUG_OBJECT (qtdemux, "next moof at offset %" G_GUINT64_FORMAT, offset);
9145
9146 if (!offset) {
9147 GST_DEBUG_OBJECT (qtdemux, "no next moof");
9148 return GST_FLOW_EOS;
9149 }
9150
9151 /* best not do pull etc with lock held */
9152 GST_OBJECT_UNLOCK (qtdemux);
9153
9154 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
9155 if (ret != GST_FLOW_OK)
9156 goto flow_failed;
9157
9158 ret = gst_qtdemux_pull_atom (qtdemux, offset, length, &buf);
9159 if (G_UNLIKELY (ret != GST_FLOW_OK))
9160 goto flow_failed;
9161 gst_buffer_map (buf, &map, GST_MAP_READ);
9162 if (!qtdemux_parse_moof (qtdemux, map.data, map.size, offset, NULL)) {
9163 gst_buffer_unmap (buf, &map);
9164 gst_buffer_unref (buf);
9165 buf = NULL;
9166 goto parse_failed;
9167 }
9168
9169 gst_buffer_unmap (buf, &map);
9170 gst_buffer_unref (buf);
9171 buf = NULL;
9172
9173 offset += length;
9174 /* look for next moof */
9175 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
9176 if (G_UNLIKELY (ret != GST_FLOW_OK))
9177 goto flow_failed;
9178
9179 exit:
9180 GST_OBJECT_LOCK (qtdemux);
9181
9182 qtdemux->moof_offset = offset;
9183
9184 return res;
9185
9186 parse_failed:
9187 {
9188 GST_DEBUG_OBJECT (qtdemux, "failed to parse moof");
9189 offset = 0;
9190 res = GST_FLOW_ERROR;
9191 goto exit;
9192 }
9193 flow_failed:
9194 {
9195 /* maybe upstream temporarily flushing */
9196 if (ret != GST_FLOW_FLUSHING) {
9197 GST_DEBUG_OBJECT (qtdemux, "no next moof");
9198 offset = 0;
9199 } else {
9200 GST_DEBUG_OBJECT (qtdemux, "upstream WRONG_STATE");
9201 /* resume at current position next time */
9202 }
9203 res = ret;
9204 goto exit;
9205 }
9206 }
9207
9208 static void
qtdemux_merge_sample_table(GstQTDemux * qtdemux,QtDemuxStream * stream)9209 qtdemux_merge_sample_table (GstQTDemux * qtdemux, QtDemuxStream * stream)
9210 {
9211 guint i;
9212 guint32 num_chunks;
9213 gint32 stts_duration;
9214 GstByteWriter stsc, stts, stsz;
9215
9216 /* Each sample has a different size, which we don't support for merging */
9217 if (stream->sample_size == 0) {
9218 GST_DEBUG_OBJECT (qtdemux,
9219 "Not all samples have the same size, not merging");
9220 return;
9221 }
9222
9223 /* The stream has a ctts table, we don't support that */
9224 if (stream->ctts_present) {
9225 GST_DEBUG_OBJECT (qtdemux, "Have ctts, not merging");
9226 return;
9227 }
9228
9229 /* If there's a sync sample table also ignore this stream */
9230 if (stream->stps_present || stream->stss_present) {
9231 GST_DEBUG_OBJECT (qtdemux, "Have stss/stps, not merging");
9232 return;
9233 }
9234
9235 /* If chunks are considered samples already ignore this stream */
9236 if (stream->chunks_are_samples) {
9237 GST_DEBUG_OBJECT (qtdemux, "Chunks are samples, not merging");
9238 return;
9239 }
9240
9241 /* Require that all samples have the same duration */
9242 if (stream->n_sample_times > 1) {
9243 GST_DEBUG_OBJECT (qtdemux, "Not all samples have the same duration");
9244 return;
9245 }
9246
9247 /* Parse the stts to get the sample duration and number of samples */
9248 gst_byte_reader_skip_unchecked (&stream->stts, 4);
9249 stts_duration = gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
9250
9251 /* Parse the number of chunks from the stco manually because the
9252 * reader is already behind that */
9253 num_chunks = GST_READ_UINT32_BE (stream->stco.data + 4);
9254
9255 GST_DEBUG_OBJECT (qtdemux, "sample_duration %d, num_chunks %u", stts_duration,
9256 num_chunks);
9257
9258 /* Now parse stsc, convert chunks into single samples and generate a
9259 * new stsc, stts and stsz from this information */
9260 gst_byte_writer_init (&stsc);
9261 gst_byte_writer_init (&stts);
9262 gst_byte_writer_init (&stsz);
9263
9264 /* Note: we skip fourccs, size, version, flags and other fields of the new
9265 * atoms as the byte readers with them are already behind that position
9266 * anyway and only update the values of those inside the stream directly.
9267 */
9268 stream->n_sample_times = 0;
9269 stream->n_samples = 0;
9270 for (i = 0; i < stream->n_samples_per_chunk; i++) {
9271 guint j;
9272 guint32 first_chunk, last_chunk, samples_per_chunk, sample_description_id;
9273
9274 first_chunk = gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9275 samples_per_chunk = gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9276 sample_description_id =
9277 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9278
9279 if (i == stream->n_samples_per_chunk - 1) {
9280 /* +1 because first_chunk is 1-based */
9281 last_chunk = num_chunks + 1;
9282 } else {
9283 last_chunk = gst_byte_reader_peek_uint32_be_unchecked (&stream->stsc);
9284 }
9285
9286 GST_DEBUG_OBJECT (qtdemux,
9287 "Merging first_chunk: %u, last_chunk: %u, samples_per_chunk: %u, sample_description_id: %u",
9288 first_chunk, last_chunk, samples_per_chunk, sample_description_id);
9289
9290 gst_byte_writer_put_uint32_be (&stsc, first_chunk);
9291 /* One sample in this chunk */
9292 gst_byte_writer_put_uint32_be (&stsc, 1);
9293 gst_byte_writer_put_uint32_be (&stsc, sample_description_id);
9294
9295 /* For each chunk write a stts and stsz entry now */
9296 gst_byte_writer_put_uint32_be (&stts, last_chunk - first_chunk);
9297 gst_byte_writer_put_uint32_be (&stts, stts_duration * samples_per_chunk);
9298 for (j = first_chunk; j < last_chunk; j++) {
9299 gst_byte_writer_put_uint32_be (&stsz,
9300 stream->sample_size * samples_per_chunk);
9301 }
9302
9303 stream->n_sample_times += 1;
9304 stream->n_samples += last_chunk - first_chunk;
9305 }
9306
9307 g_assert_cmpint (stream->n_samples, ==, num_chunks);
9308
9309 GST_DEBUG_OBJECT (qtdemux, "Have %u samples and %u sample times",
9310 stream->n_samples, stream->n_sample_times);
9311
9312 /* We don't have a fixed sample size anymore */
9313 stream->sample_size = 0;
9314
9315 /* Free old data for the atoms */
9316 g_free ((gpointer) stream->stsz.data);
9317 stream->stsz.data = NULL;
9318 g_free ((gpointer) stream->stsc.data);
9319 stream->stsc.data = NULL;
9320 g_free ((gpointer) stream->stts.data);
9321 stream->stts.data = NULL;
9322
9323 /* Store new data and replace byte readers */
9324 stream->stsz.size = gst_byte_writer_get_size (&stsz);
9325 stream->stsz.data = gst_byte_writer_reset_and_get_data (&stsz);
9326 gst_byte_reader_init (&stream->stsz, stream->stsz.data, stream->stsz.size);
9327 stream->stts.size = gst_byte_writer_get_size (&stts);
9328 stream->stts.data = gst_byte_writer_reset_and_get_data (&stts);
9329 gst_byte_reader_init (&stream->stts, stream->stts.data, stream->stts.size);
9330 stream->stsc.size = gst_byte_writer_get_size (&stsc);
9331 stream->stsc.data = gst_byte_writer_reset_and_get_data (&stsc);
9332 gst_byte_reader_init (&stream->stsc, stream->stsc.data, stream->stsc.size);
9333 }
9334
9335 /* initialise bytereaders for stbl sub-atoms */
9336 static gboolean
qtdemux_stbl_init(GstQTDemux * qtdemux,QtDemuxStream * stream,GNode * stbl)9337 qtdemux_stbl_init (GstQTDemux * qtdemux, QtDemuxStream * stream, GNode * stbl)
9338 {
9339 stream->stbl_index = -1; /* no samples have yet been parsed */
9340 stream->sample_index = -1;
9341
9342 /* time-to-sample atom */
9343 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stts, &stream->stts))
9344 goto corrupt_file;
9345
9346 /* copy atom data into a new buffer for later use */
9347 stream->stts.data = g_memdup2 (stream->stts.data, stream->stts.size);
9348
9349 /* skip version + flags */
9350 if (!gst_byte_reader_skip (&stream->stts, 1 + 3) ||
9351 !gst_byte_reader_get_uint32_be (&stream->stts, &stream->n_sample_times))
9352 goto corrupt_file;
9353 GST_LOG_OBJECT (qtdemux, "%u timestamp blocks", stream->n_sample_times);
9354
9355 /* make sure there's enough data */
9356 if (!qt_atom_parser_has_chunks (&stream->stts, stream->n_sample_times, 8)) {
9357 stream->n_sample_times = gst_byte_reader_get_remaining (&stream->stts) / 8;
9358 GST_LOG_OBJECT (qtdemux, "overriding to %u timestamp blocks",
9359 stream->n_sample_times);
9360 if (!stream->n_sample_times)
9361 goto corrupt_file;
9362 }
9363
9364 /* sync sample atom */
9365 stream->stps_present = FALSE;
9366 if ((stream->stss_present =
9367 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stss,
9368 &stream->stss) ? TRUE : FALSE) == TRUE) {
9369 /* copy atom data into a new buffer for later use */
9370 stream->stss.data = g_memdup2 (stream->stss.data, stream->stss.size);
9371
9372 /* skip version + flags */
9373 if (!gst_byte_reader_skip (&stream->stss, 1 + 3) ||
9374 !gst_byte_reader_get_uint32_be (&stream->stss, &stream->n_sample_syncs))
9375 goto corrupt_file;
9376
9377 if (stream->n_sample_syncs) {
9378 /* make sure there's enough data */
9379 if (!qt_atom_parser_has_chunks (&stream->stss, stream->n_sample_syncs, 4))
9380 goto corrupt_file;
9381 }
9382
9383 /* partial sync sample atom */
9384 if ((stream->stps_present =
9385 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stps,
9386 &stream->stps) ? TRUE : FALSE) == TRUE) {
9387 /* copy atom data into a new buffer for later use */
9388 stream->stps.data = g_memdup2 (stream->stps.data, stream->stps.size);
9389
9390 /* skip version + flags */
9391 if (!gst_byte_reader_skip (&stream->stps, 1 + 3) ||
9392 !gst_byte_reader_get_uint32_be (&stream->stps,
9393 &stream->n_sample_partial_syncs))
9394 goto corrupt_file;
9395
9396 /* if there are no entries, the stss table contains the real
9397 * sync samples */
9398 if (stream->n_sample_partial_syncs) {
9399 /* make sure there's enough data */
9400 if (!qt_atom_parser_has_chunks (&stream->stps,
9401 stream->n_sample_partial_syncs, 4))
9402 goto corrupt_file;
9403 }
9404 }
9405 }
9406
9407 /* sample size */
9408 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsz, &stream->stsz))
9409 goto no_samples;
9410
9411 /* copy atom data into a new buffer for later use */
9412 stream->stsz.data = g_memdup2 (stream->stsz.data, stream->stsz.size);
9413
9414 /* skip version + flags */
9415 if (!gst_byte_reader_skip (&stream->stsz, 1 + 3) ||
9416 !gst_byte_reader_get_uint32_be (&stream->stsz, &stream->sample_size))
9417 goto corrupt_file;
9418
9419 if (!gst_byte_reader_get_uint32_be (&stream->stsz, &stream->n_samples))
9420 goto corrupt_file;
9421
9422 if (!stream->n_samples)
9423 goto no_samples;
9424
9425 /* sample-to-chunk atom */
9426 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsc, &stream->stsc))
9427 goto corrupt_file;
9428
9429 /* copy atom data into a new buffer for later use */
9430 stream->stsc.data = g_memdup2 (stream->stsc.data, stream->stsc.size);
9431
9432 /* skip version + flags */
9433 if (!gst_byte_reader_skip (&stream->stsc, 1 + 3) ||
9434 !gst_byte_reader_get_uint32_be (&stream->stsc,
9435 &stream->n_samples_per_chunk))
9436 goto corrupt_file;
9437
9438 GST_DEBUG_OBJECT (qtdemux, "n_samples_per_chunk %u",
9439 stream->n_samples_per_chunk);
9440
9441 /* make sure there's enough data */
9442 if (!qt_atom_parser_has_chunks (&stream->stsc, stream->n_samples_per_chunk,
9443 12))
9444 goto corrupt_file;
9445
9446
9447 /* chunk offset */
9448 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stco, &stream->stco))
9449 stream->co_size = sizeof (guint32);
9450 else if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_co64,
9451 &stream->stco))
9452 stream->co_size = sizeof (guint64);
9453 else
9454 goto corrupt_file;
9455
9456 /* copy atom data into a new buffer for later use */
9457 stream->stco.data = g_memdup2 (stream->stco.data, stream->stco.size);
9458
9459 /* skip version + flags */
9460 if (!gst_byte_reader_skip (&stream->stco, 1 + 3))
9461 goto corrupt_file;
9462
9463 /* chunks_are_samples == TRUE means treat chunks as samples */
9464 stream->chunks_are_samples = stream->sample_size
9465 && !CUR_STREAM (stream)->sampled;
9466 if (stream->chunks_are_samples) {
9467 /* treat chunks as samples */
9468 if (!gst_byte_reader_get_uint32_be (&stream->stco, &stream->n_samples))
9469 goto corrupt_file;
9470 } else {
9471 /* skip number of entries */
9472 if (!gst_byte_reader_skip (&stream->stco, 4))
9473 goto corrupt_file;
9474
9475 /* make sure there are enough data in the stsz atom */
9476 if (!stream->sample_size) {
9477 /* different sizes for each sample */
9478 if (!qt_atom_parser_has_chunks (&stream->stsz, stream->n_samples, 4))
9479 goto corrupt_file;
9480 }
9481 }
9482
9483 /* composition time-to-sample */
9484 if ((stream->ctts_present =
9485 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_ctts,
9486 &stream->ctts) ? TRUE : FALSE) == TRUE) {
9487 GstByteReader cslg = GST_BYTE_READER_INIT (NULL, 0);
9488 guint8 ctts_version;
9489 gboolean checked_ctts = FALSE;
9490
9491 /* copy atom data into a new buffer for later use */
9492 stream->ctts.data = g_memdup2 (stream->ctts.data, stream->ctts.size);
9493
9494 /* version 1 has signed offsets */
9495 if (!gst_byte_reader_get_uint8 (&stream->ctts, &ctts_version))
9496 goto corrupt_file;
9497
9498 /* flags */
9499 if (!gst_byte_reader_skip (&stream->ctts, 3)
9500 || !gst_byte_reader_get_uint32_be (&stream->ctts,
9501 &stream->n_composition_times))
9502 goto corrupt_file;
9503
9504 /* make sure there's enough data */
9505 if (!qt_atom_parser_has_chunks (&stream->ctts, stream->n_composition_times,
9506 4 + 4))
9507 goto corrupt_file;
9508
9509 /* This is optional, if missing we iterate the ctts */
9510 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_cslg, &cslg)) {
9511 guint8 cslg_version;
9512
9513 /* cslg version 1 has 64 bit fields */
9514 if (!gst_byte_reader_get_uint8 (&cslg, &cslg_version))
9515 goto corrupt_file;
9516
9517 /* skip flags */
9518 if (!gst_byte_reader_skip (&cslg, 3))
9519 goto corrupt_file;
9520
9521 if (cslg_version == 0) {
9522 gint32 composition_to_dts_shift;
9523
9524 if (!gst_byte_reader_get_int32_be (&cslg, &composition_to_dts_shift))
9525 goto corrupt_file;
9526
9527 stream->cslg_shift = MAX (0, composition_to_dts_shift);
9528 } else {
9529 gint64 composition_to_dts_shift;
9530
9531 if (!gst_byte_reader_get_int64_be (&cslg, &composition_to_dts_shift))
9532 goto corrupt_file;
9533
9534 stream->cslg_shift = MAX (0, composition_to_dts_shift);
9535 }
9536 } else {
9537 gint32 cslg_least = 0;
9538 guint num_entries, pos;
9539 gint i;
9540
9541 pos = gst_byte_reader_get_pos (&stream->ctts);
9542 num_entries = stream->n_composition_times;
9543
9544 checked_ctts = TRUE;
9545
9546 stream->cslg_shift = 0;
9547
9548 for (i = 0; i < num_entries; i++) {
9549 gint32 offset;
9550
9551 gst_byte_reader_skip_unchecked (&stream->ctts, 4);
9552 offset = gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
9553 /* HACK: if sample_offset is larger than 2 * duration, ignore the box.
9554 * slightly inaccurate PTS could be more usable than corrupted one */
9555 if (G_UNLIKELY ((ctts_version == 0 || offset != G_MININT32)
9556 && ABS (offset) / 2 > stream->duration)) {
9557 GST_WARNING_OBJECT (qtdemux,
9558 "Ignore corrupted ctts, sample_offset %" G_GINT32_FORMAT
9559 " larger than duration %" G_GUINT64_FORMAT, offset,
9560 stream->duration);
9561
9562 stream->cslg_shift = 0;
9563 stream->ctts_present = FALSE;
9564 goto done;
9565 }
9566
9567 /* Don't consider "no decode samples" with offset G_MININT32
9568 * for the DTS/PTS shift */
9569 if (offset != G_MININT32 && offset < cslg_least)
9570 cslg_least = offset;
9571 }
9572
9573 if (cslg_least < 0)
9574 stream->cslg_shift = -cslg_least;
9575 else
9576 stream->cslg_shift = 0;
9577
9578 /* reset the reader so we can generate sample table */
9579 gst_byte_reader_set_pos (&stream->ctts, pos);
9580 }
9581
9582 /* Check if ctts values are looking reasonable if that didn't happen above */
9583 if (!checked_ctts) {
9584 guint num_entries, pos;
9585 gint i;
9586
9587 pos = gst_byte_reader_get_pos (&stream->ctts);
9588 num_entries = stream->n_composition_times;
9589
9590 for (i = 0; i < num_entries; i++) {
9591 gint32 offset;
9592
9593 gst_byte_reader_skip_unchecked (&stream->ctts, 4);
9594 offset = gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
9595 /* HACK: if sample_offset is larger than 2 * duration, ignore the box.
9596 * slightly inaccurate PTS could be more usable than corrupted one */
9597 if (G_UNLIKELY ((ctts_version == 0 || offset != G_MININT32)
9598 && ABS (offset) / 2 > stream->duration)) {
9599 GST_WARNING_OBJECT (qtdemux,
9600 "Ignore corrupted ctts, sample_offset %" G_GINT32_FORMAT
9601 " larger than duration %" G_GUINT64_FORMAT, offset,
9602 stream->duration);
9603
9604 stream->cslg_shift = 0;
9605 stream->ctts_present = FALSE;
9606 goto done;
9607 }
9608 }
9609
9610 /* reset the reader so we can generate sample table */
9611 gst_byte_reader_set_pos (&stream->ctts, pos);
9612 }
9613 } else {
9614 /* Ensure the cslg_shift value is consistent so we can use it
9615 * unconditionally to produce TS and Segment */
9616 stream->cslg_shift = 0;
9617 }
9618
9619 GST_DEBUG_OBJECT (qtdemux, "Using clsg_shift %" G_GUINT64_FORMAT,
9620 stream->cslg_shift);
9621
9622 /* For raw audio streams especially we might want to merge the samples
9623 * to not output one audio sample per buffer. We're doing this here
9624 * before allocating the sample tables so that from this point onwards
9625 * the number of container samples are static */
9626 if (stream->min_buffer_size > 0) {
9627 qtdemux_merge_sample_table (qtdemux, stream);
9628 }
9629
9630 done:
9631 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
9632 stream->n_samples, (guint) sizeof (QtDemuxSample),
9633 stream->n_samples * sizeof (QtDemuxSample) / (1024.0 * 1024.0));
9634
9635 if (stream->n_samples >=
9636 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample)) {
9637 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
9638 "be larger than %uMB (broken file?)", stream->n_samples,
9639 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
9640 return FALSE;
9641 }
9642
9643 g_assert (stream->samples == NULL);
9644 stream->samples = g_try_new0 (QtDemuxSample, stream->n_samples);
9645 if (!stream->samples) {
9646 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
9647 stream->n_samples);
9648 return FALSE;
9649 }
9650
9651 return TRUE;
9652
9653 corrupt_file:
9654 {
9655 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
9656 (_("This file is corrupt and cannot be played.")), (NULL));
9657 return FALSE;
9658 }
9659 no_samples:
9660 {
9661 gst_qtdemux_stbl_free (stream);
9662 if (!qtdemux->fragmented) {
9663 /* not quite good */
9664 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
9665 return FALSE;
9666 } else {
9667 /* may pick up samples elsewhere */
9668 return TRUE;
9669 }
9670 }
9671 }
9672
9673 /* collect samples from the next sample to be parsed up to sample @n for @stream
9674 * by reading the info from @stbl
9675 *
9676 * This code can be executed from both the streaming thread and the seeking
9677 * thread so it takes the object lock to protect itself
9678 */
9679 static gboolean
qtdemux_parse_samples(GstQTDemux * qtdemux,QtDemuxStream * stream,guint32 n)9680 qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream, guint32 n)
9681 {
9682 gint i, j, k;
9683 QtDemuxSample *samples, *first, *cur, *last;
9684 guint32 n_samples_per_chunk;
9685 guint32 n_samples;
9686
9687 GST_LOG_OBJECT (qtdemux, "parsing samples for stream fourcc %"
9688 GST_FOURCC_FORMAT ", pad %s",
9689 GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc),
9690 stream->pad ? GST_PAD_NAME (stream->pad) : "(NULL)");
9691
9692 n_samples = stream->n_samples;
9693
9694 if (n >= n_samples)
9695 goto out_of_samples;
9696
9697 GST_OBJECT_LOCK (qtdemux);
9698 if (n <= stream->stbl_index)
9699 goto already_parsed;
9700
9701 GST_DEBUG_OBJECT (qtdemux, "parsing up to sample %u", n);
9702
9703 if (!stream->stsz.data) {
9704 /* so we already parsed and passed all the moov samples;
9705 * onto fragmented ones */
9706 g_assert (qtdemux->fragmented);
9707 goto done;
9708 }
9709
9710 /* pointer to the sample table */
9711 samples = stream->samples;
9712
9713 /* starts from -1, moves to the next sample index to parse */
9714 stream->stbl_index++;
9715
9716 /* keep track of the first and last sample to fill */
9717 first = &samples[stream->stbl_index];
9718 last = &samples[n];
9719
9720 if (!stream->chunks_are_samples) {
9721 /* set the sample sizes */
9722 if (stream->sample_size == 0) {
9723 /* different sizes for each sample */
9724 for (cur = first; cur <= last; cur++) {
9725 cur->size = gst_byte_reader_get_uint32_be_unchecked (&stream->stsz);
9726 GST_LOG_OBJECT (qtdemux, "sample %d has size %u",
9727 (guint) (cur - samples), cur->size);
9728 }
9729 } else {
9730 /* samples have the same size */
9731 GST_LOG_OBJECT (qtdemux, "all samples have size %u", stream->sample_size);
9732 for (cur = first; cur <= last; cur++)
9733 cur->size = stream->sample_size;
9734 }
9735 }
9736
9737 n_samples_per_chunk = stream->n_samples_per_chunk;
9738 cur = first;
9739
9740 for (i = stream->stsc_index; i < n_samples_per_chunk; i++) {
9741 guint32 last_chunk;
9742
9743 if (stream->stsc_chunk_index >= stream->last_chunk
9744 || stream->stsc_chunk_index < stream->first_chunk) {
9745 stream->first_chunk =
9746 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9747 stream->samples_per_chunk =
9748 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9749 /* starts from 1 */
9750 stream->stsd_sample_description_id =
9751 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc) - 1;
9752
9753 /* chunk numbers are counted from 1 it seems */
9754 if (G_UNLIKELY (stream->first_chunk == 0))
9755 goto corrupt_file;
9756
9757 --stream->first_chunk;
9758
9759 /* the last chunk of each entry is calculated by taking the first chunk
9760 * of the next entry; except if there is no next, where we fake it with
9761 * INT_MAX */
9762 if (G_UNLIKELY (i == (stream->n_samples_per_chunk - 1))) {
9763 stream->last_chunk = G_MAXUINT32;
9764 } else {
9765 stream->last_chunk =
9766 gst_byte_reader_peek_uint32_be_unchecked (&stream->stsc);
9767 if (G_UNLIKELY (stream->last_chunk == 0))
9768 goto corrupt_file;
9769
9770 --stream->last_chunk;
9771 }
9772
9773 GST_LOG_OBJECT (qtdemux,
9774 "entry %d has first_chunk %d, last_chunk %d, samples_per_chunk %d"
9775 "sample desc ID: %d", i, stream->first_chunk, stream->last_chunk,
9776 stream->samples_per_chunk, stream->stsd_sample_description_id);
9777
9778 if (G_UNLIKELY (stream->last_chunk < stream->first_chunk))
9779 goto corrupt_file;
9780
9781 if (stream->last_chunk != G_MAXUINT32) {
9782 if (!qt_atom_parser_peek_sub (&stream->stco,
9783 stream->first_chunk * stream->co_size,
9784 (stream->last_chunk - stream->first_chunk) * stream->co_size,
9785 &stream->co_chunk))
9786 goto corrupt_file;
9787
9788 } else {
9789 stream->co_chunk = stream->stco;
9790 if (!gst_byte_reader_skip (&stream->co_chunk,
9791 stream->first_chunk * stream->co_size))
9792 goto corrupt_file;
9793 }
9794
9795 stream->stsc_chunk_index = stream->first_chunk;
9796 }
9797
9798 last_chunk = stream->last_chunk;
9799
9800 if (stream->chunks_are_samples) {
9801 cur = &samples[stream->stsc_chunk_index];
9802
9803 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
9804 if (j > n) {
9805 /* save state */
9806 stream->stsc_chunk_index = j;
9807 goto done;
9808 }
9809
9810 cur->offset =
9811 qt_atom_parser_get_offset_unchecked (&stream->co_chunk,
9812 stream->co_size);
9813
9814 GST_LOG_OBJECT (qtdemux, "Created entry %d with offset "
9815 "%" G_GUINT64_FORMAT, j, cur->offset);
9816
9817 if (CUR_STREAM (stream)->samples_per_frame > 0 &&
9818 CUR_STREAM (stream)->bytes_per_frame > 0) {
9819 cur->size =
9820 (stream->samples_per_chunk * CUR_STREAM (stream)->n_channels) /
9821 CUR_STREAM (stream)->samples_per_frame *
9822 CUR_STREAM (stream)->bytes_per_frame;
9823 } else {
9824 cur->size = stream->samples_per_chunk;
9825 }
9826
9827 GST_DEBUG_OBJECT (qtdemux,
9828 "keyframe sample %d: timestamp %" GST_TIME_FORMAT ", size %u",
9829 j, GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream,
9830 stream->stco_sample_index)), cur->size);
9831
9832 cur->timestamp = stream->stco_sample_index;
9833 cur->duration = stream->samples_per_chunk;
9834 cur->keyframe = TRUE;
9835 cur++;
9836
9837 stream->stco_sample_index += stream->samples_per_chunk;
9838 }
9839 stream->stsc_chunk_index = j;
9840 } else {
9841 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
9842 guint32 samples_per_chunk;
9843 guint64 chunk_offset;
9844
9845 if (!stream->stsc_sample_index
9846 && !qt_atom_parser_get_offset (&stream->co_chunk, stream->co_size,
9847 &stream->chunk_offset))
9848 goto corrupt_file;
9849
9850 samples_per_chunk = stream->samples_per_chunk;
9851 chunk_offset = stream->chunk_offset;
9852
9853 for (k = stream->stsc_sample_index; k < samples_per_chunk; k++) {
9854 GST_LOG_OBJECT (qtdemux, "creating entry %d with offset %"
9855 G_GUINT64_FORMAT " and size %d",
9856 (guint) (cur - samples), chunk_offset, cur->size);
9857
9858 cur->offset = chunk_offset;
9859 chunk_offset += cur->size;
9860 cur++;
9861
9862 if (G_UNLIKELY (cur > last)) {
9863 /* save state */
9864 stream->stsc_sample_index = k + 1;
9865 stream->chunk_offset = chunk_offset;
9866 stream->stsc_chunk_index = j;
9867 goto done2;
9868 }
9869 }
9870 stream->stsc_sample_index = 0;
9871 }
9872 stream->stsc_chunk_index = j;
9873 }
9874 stream->stsc_index++;
9875 }
9876
9877 if (stream->chunks_are_samples)
9878 goto ctts;
9879 done2:
9880 {
9881 guint32 n_sample_times;
9882
9883 n_sample_times = stream->n_sample_times;
9884 cur = first;
9885
9886 for (i = stream->stts_index; i < n_sample_times; i++) {
9887 guint32 stts_samples;
9888 gint32 stts_duration;
9889 gint64 stts_time;
9890
9891 if (stream->stts_sample_index >= stream->stts_samples
9892 || !stream->stts_sample_index) {
9893
9894 stream->stts_samples =
9895 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
9896 stream->stts_duration =
9897 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
9898
9899 GST_LOG_OBJECT (qtdemux, "block %d, %u timestamps, duration %u",
9900 i, stream->stts_samples, stream->stts_duration);
9901
9902 stream->stts_sample_index = 0;
9903 }
9904
9905 stts_samples = stream->stts_samples;
9906 stts_duration = stream->stts_duration;
9907 stts_time = stream->stts_time;
9908
9909 for (j = stream->stts_sample_index; j < stts_samples; j++) {
9910 GST_DEBUG_OBJECT (qtdemux,
9911 "sample %d: index %d, timestamp %" GST_TIME_FORMAT,
9912 (guint) (cur - samples), j,
9913 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stts_time)));
9914
9915 cur->timestamp = stts_time;
9916 cur->duration = stts_duration;
9917
9918 /* avoid 32-bit wrap-around,
9919 * but still mind possible 'negative' duration */
9920 stts_time += (gint64) stts_duration;
9921 cur++;
9922
9923 if (G_UNLIKELY (cur > last)) {
9924 /* save values */
9925 stream->stts_time = stts_time;
9926 stream->stts_sample_index = j + 1;
9927 if (stream->stts_sample_index >= stream->stts_samples)
9928 stream->stts_index++;
9929 goto done3;
9930 }
9931 }
9932 stream->stts_sample_index = 0;
9933 stream->stts_time = stts_time;
9934 stream->stts_index++;
9935 }
9936 /* fill up empty timestamps with the last timestamp, this can happen when
9937 * the last samples do not decode and so we don't have timestamps for them.
9938 * We however look at the last timestamp to estimate the track length so we
9939 * need something in here. */
9940 for (; cur < last; cur++) {
9941 GST_DEBUG_OBJECT (qtdemux,
9942 "fill sample %d: timestamp %" GST_TIME_FORMAT,
9943 (guint) (cur - samples),
9944 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stream->stts_time)));
9945 cur->timestamp = stream->stts_time;
9946 cur->duration = -1;
9947 }
9948 }
9949 done3:
9950 {
9951 /* sample sync, can be NULL */
9952 if (stream->stss_present == TRUE) {
9953 guint32 n_sample_syncs;
9954
9955 n_sample_syncs = stream->n_sample_syncs;
9956
9957 if (!n_sample_syncs) {
9958 GST_DEBUG_OBJECT (qtdemux, "all samples are keyframes");
9959 stream->all_keyframe = TRUE;
9960 } else {
9961 for (i = stream->stss_index; i < n_sample_syncs; i++) {
9962 /* note that the first sample is index 1, not 0 */
9963 guint32 index;
9964
9965 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stss);
9966
9967 if (G_LIKELY (index > 0 && index <= n_samples)) {
9968 index -= 1;
9969 samples[index].keyframe = TRUE;
9970 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
9971 /* and exit if we have enough samples */
9972 if (G_UNLIKELY (index >= n)) {
9973 i++;
9974 break;
9975 }
9976 }
9977 }
9978 /* save state */
9979 stream->stss_index = i;
9980 }
9981
9982 /* stps marks partial sync frames like open GOP I-Frames */
9983 if (stream->stps_present == TRUE) {
9984 guint32 n_sample_partial_syncs;
9985
9986 n_sample_partial_syncs = stream->n_sample_partial_syncs;
9987
9988 /* if there are no entries, the stss table contains the real
9989 * sync samples */
9990 if (n_sample_partial_syncs) {
9991 for (i = stream->stps_index; i < n_sample_partial_syncs; i++) {
9992 /* note that the first sample is index 1, not 0 */
9993 guint32 index;
9994
9995 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stps);
9996
9997 if (G_LIKELY (index > 0 && index <= n_samples)) {
9998 index -= 1;
9999 samples[index].keyframe = TRUE;
10000 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
10001 /* and exit if we have enough samples */
10002 if (G_UNLIKELY (index >= n)) {
10003 i++;
10004 break;
10005 }
10006 }
10007 }
10008 /* save state */
10009 stream->stps_index = i;
10010 }
10011 }
10012 } else {
10013 /* no stss, all samples are keyframes */
10014 stream->all_keyframe = TRUE;
10015 GST_DEBUG_OBJECT (qtdemux, "setting all keyframes");
10016 }
10017 }
10018
10019 ctts:
10020 /* composition time to sample */
10021 if (stream->ctts_present == TRUE) {
10022 guint32 n_composition_times;
10023 guint32 ctts_count;
10024 gint32 ctts_soffset;
10025
10026 /* Fill in the pts_offsets */
10027 cur = first;
10028 n_composition_times = stream->n_composition_times;
10029
10030 for (i = stream->ctts_index; i < n_composition_times; i++) {
10031 if (stream->ctts_sample_index >= stream->ctts_count
10032 || !stream->ctts_sample_index) {
10033 stream->ctts_count =
10034 gst_byte_reader_get_uint32_be_unchecked (&stream->ctts);
10035 stream->ctts_soffset =
10036 gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
10037 stream->ctts_sample_index = 0;
10038 }
10039
10040 ctts_count = stream->ctts_count;
10041 ctts_soffset = stream->ctts_soffset;
10042
10043 /* FIXME: Set offset to 0 for "no decode samples". This needs
10044 * to be handled in a codec specific manner ideally. */
10045 if (ctts_soffset == G_MININT32)
10046 ctts_soffset = 0;
10047
10048 for (j = stream->ctts_sample_index; j < ctts_count; j++) {
10049 cur->pts_offset = ctts_soffset;
10050 cur++;
10051
10052 if (G_UNLIKELY (cur > last)) {
10053 /* save state */
10054 stream->ctts_sample_index = j + 1;
10055 goto done;
10056 }
10057 }
10058 stream->ctts_sample_index = 0;
10059 stream->ctts_index++;
10060 }
10061 }
10062 done:
10063 stream->stbl_index = n;
10064 /* if index has been completely parsed, free data that is no-longer needed */
10065 if (n + 1 == stream->n_samples) {
10066 gst_qtdemux_stbl_free (stream);
10067 GST_DEBUG_OBJECT (qtdemux, "parsed all available samples;");
10068 if (qtdemux->pullbased) {
10069 GST_DEBUG_OBJECT (qtdemux, "checking for more samples");
10070 while (n + 1 == stream->n_samples)
10071 if (qtdemux_add_fragmented_samples (qtdemux) != GST_FLOW_OK)
10072 break;
10073 }
10074 }
10075 GST_OBJECT_UNLOCK (qtdemux);
10076
10077 return TRUE;
10078
10079 /* SUCCESS */
10080 already_parsed:
10081 {
10082 GST_LOG_OBJECT (qtdemux,
10083 "Tried to parse up to sample %u but this sample has already been parsed",
10084 n);
10085 /* if fragmented, there may be more */
10086 if (qtdemux->fragmented && n == stream->stbl_index)
10087 goto done;
10088 GST_OBJECT_UNLOCK (qtdemux);
10089 return TRUE;
10090 }
10091 /* ERRORS */
10092 out_of_samples:
10093 {
10094 GST_LOG_OBJECT (qtdemux,
10095 "Tried to parse up to sample %u but there are only %u samples", n + 1,
10096 stream->n_samples);
10097 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
10098 (_("This file is corrupt and cannot be played.")), (NULL));
10099 return FALSE;
10100 }
10101 corrupt_file:
10102 {
10103 GST_OBJECT_UNLOCK (qtdemux);
10104 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
10105 (_("This file is corrupt and cannot be played.")), (NULL));
10106 return FALSE;
10107 }
10108 }
10109
10110 /* collect all segment info for @stream.
10111 */
10112 static gboolean
qtdemux_parse_segments(GstQTDemux * qtdemux,QtDemuxStream * stream,GNode * trak)10113 qtdemux_parse_segments (GstQTDemux * qtdemux, QtDemuxStream * stream,
10114 GNode * trak)
10115 {
10116 GNode *edts;
10117 /* accept edts if they contain gaps at start and there is only
10118 * one media segment */
10119 gboolean allow_pushbased_edts = TRUE;
10120 gint media_segments_count = 0;
10121
10122 /* parse and prepare segment info from the edit list */
10123 GST_DEBUG_OBJECT (qtdemux, "looking for edit list container");
10124 stream->n_segments = 0;
10125 stream->segments = NULL;
10126 if ((edts = qtdemux_tree_get_child_by_type (trak, FOURCC_edts))) {
10127 GNode *elst;
10128 gint n_segments;
10129 gint segment_number, entry_size;
10130 guint64 time;
10131 GstClockTime stime;
10132 const guint8 *buffer;
10133 guint8 version;
10134 guint32 size;
10135
10136 GST_DEBUG_OBJECT (qtdemux, "looking for edit list");
10137 if (!(elst = qtdemux_tree_get_child_by_type (edts, FOURCC_elst)))
10138 goto done;
10139
10140 buffer = elst->data;
10141
10142 size = QT_UINT32 (buffer);
10143 /* version, flags, n_segments */
10144 if (size < 16) {
10145 GST_WARNING_OBJECT (qtdemux, "Invalid edit list");
10146 goto done;
10147 }
10148 version = QT_UINT8 (buffer + 8);
10149 entry_size = (version == 1) ? 20 : 12;
10150
10151 n_segments = QT_UINT32 (buffer + 12);
10152
10153 if (n_segments > 100000 || size < 16 + n_segments * entry_size) {
10154 GST_WARNING_OBJECT (qtdemux, "Invalid edit list");
10155 goto done;
10156 }
10157
10158 /* we might allocate a bit too much, at least allocate 1 segment */
10159 stream->segments = g_new (QtDemuxSegment, MAX (n_segments, 1));
10160
10161 /* segments always start from 0 */
10162 time = 0;
10163 stime = 0;
10164 buffer += 16;
10165 for (segment_number = 0; segment_number < n_segments; segment_number++) {
10166 guint64 duration;
10167 guint64 media_time;
10168 gboolean empty_edit = FALSE;
10169 QtDemuxSegment *segment;
10170 guint32 rate_int;
10171 GstClockTime media_start = GST_CLOCK_TIME_NONE;
10172
10173 if (version == 1) {
10174 media_time = QT_UINT64 (buffer + 8);
10175 duration = QT_UINT64 (buffer);
10176 if (media_time == G_MAXUINT64)
10177 empty_edit = TRUE;
10178 } else {
10179 media_time = QT_UINT32 (buffer + 4);
10180 duration = QT_UINT32 (buffer);
10181 if (media_time == G_MAXUINT32)
10182 empty_edit = TRUE;
10183 }
10184
10185 if (!empty_edit)
10186 media_start = QTSTREAMTIME_TO_GSTTIME (stream, media_time);
10187
10188 segment = &stream->segments[segment_number];
10189
10190 /* time and duration expressed in global timescale */
10191 segment->time = stime;
10192 if (duration != 0 || empty_edit) {
10193 /* edge case: empty edits with duration=zero are treated here.
10194 * (files should not have these anyway). */
10195
10196 /* add non scaled values so we don't cause roundoff errors */
10197 time += duration;
10198 stime = QTTIME_TO_GSTTIME (qtdemux, time);
10199 segment->duration = stime - segment->time;
10200 } else {
10201 /* zero duration does not imply media_start == media_stop
10202 * but, only specify media_start. The edit ends with the track. */
10203 stime = segment->duration = GST_CLOCK_TIME_NONE;
10204 /* Don't allow more edits after this one. */
10205 n_segments = segment_number + 1;
10206 }
10207 segment->stop_time = stime;
10208
10209 segment->trak_media_start = media_time;
10210 /* media_time expressed in stream timescale */
10211 if (!empty_edit) {
10212 segment->media_start = media_start;
10213 segment->media_stop = GST_CLOCK_TIME_IS_VALID (segment->duration)
10214 ? segment->media_start + segment->duration : GST_CLOCK_TIME_NONE;
10215 media_segments_count++;
10216 } else {
10217 segment->media_start = GST_CLOCK_TIME_NONE;
10218 segment->media_stop = GST_CLOCK_TIME_NONE;
10219 }
10220 rate_int = QT_UINT32 (buffer + ((version == 1) ? 16 : 8));
10221
10222 if (rate_int <= 1) {
10223 /* 0 is not allowed, some programs write 1 instead of the floating point
10224 * value */
10225 GST_WARNING_OBJECT (qtdemux, "found suspicious rate %" G_GUINT32_FORMAT,
10226 rate_int);
10227 segment->rate = 1;
10228 } else {
10229 segment->rate = rate_int / 65536.0;
10230 }
10231
10232 GST_DEBUG_OBJECT (qtdemux, "created segment %d time %" GST_TIME_FORMAT
10233 ", duration %" GST_TIME_FORMAT ", media_start %" GST_TIME_FORMAT
10234 " (%" G_GUINT64_FORMAT ") , media_stop %" GST_TIME_FORMAT
10235 " stop_time %" GST_TIME_FORMAT " rate %g, (%d) timescale %u",
10236 segment_number, GST_TIME_ARGS (segment->time),
10237 GST_TIME_ARGS (segment->duration),
10238 GST_TIME_ARGS (segment->media_start), media_time,
10239 GST_TIME_ARGS (segment->media_stop),
10240 GST_TIME_ARGS (segment->stop_time), segment->rate, rate_int,
10241 stream->timescale);
10242 if (segment->stop_time > qtdemux->segment.stop &&
10243 !qtdemux->upstream_format_is_time) {
10244 GST_WARNING_OBJECT (qtdemux, "Segment %d "
10245 " extends to %" GST_TIME_FORMAT
10246 " past the end of the declared movie duration %" GST_TIME_FORMAT
10247 " movie segment will be extended", segment_number,
10248 GST_TIME_ARGS (segment->stop_time),
10249 GST_TIME_ARGS (qtdemux->segment.stop));
10250 qtdemux->segment.stop = qtdemux->segment.duration = segment->stop_time;
10251 }
10252
10253 buffer += entry_size;
10254 }
10255 GST_DEBUG_OBJECT (qtdemux, "found %d segments", n_segments);
10256 stream->n_segments = n_segments;
10257 if (media_segments_count != 1)
10258 allow_pushbased_edts = FALSE;
10259 }
10260 done:
10261
10262 /* push based does not handle segments, so act accordingly here,
10263 * and warn if applicable */
10264 if (!qtdemux->pullbased && !allow_pushbased_edts) {
10265 GST_WARNING_OBJECT (qtdemux, "streaming; discarding edit list segments");
10266 /* remove and use default one below, we stream like it anyway */
10267 g_free (stream->segments);
10268 stream->segments = NULL;
10269 stream->n_segments = 0;
10270 }
10271
10272 /* no segments, create one to play the complete trak */
10273 if (stream->n_segments == 0) {
10274 GstClockTime stream_duration =
10275 QTSTREAMTIME_TO_GSTTIME (stream, stream->duration);
10276
10277 if (stream->segments == NULL)
10278 stream->segments = g_new (QtDemuxSegment, 1);
10279
10280 /* represent unknown our way */
10281 if (stream_duration == 0)
10282 stream_duration = GST_CLOCK_TIME_NONE;
10283
10284 stream->segments[0].time = 0;
10285 stream->segments[0].stop_time = stream_duration;
10286 stream->segments[0].duration = stream_duration;
10287 stream->segments[0].media_start = 0;
10288 stream->segments[0].media_stop = stream_duration;
10289 stream->segments[0].rate = 1.0;
10290 stream->segments[0].trak_media_start = 0;
10291
10292 GST_DEBUG_OBJECT (qtdemux, "created dummy segment %" GST_TIME_FORMAT,
10293 GST_TIME_ARGS (stream_duration));
10294 stream->n_segments = 1;
10295 stream->dummy_segment = TRUE;
10296 }
10297 GST_DEBUG_OBJECT (qtdemux, "using %d segments", stream->n_segments);
10298
10299 return TRUE;
10300 }
10301
10302 /*
10303 * Parses the stsd atom of a svq3 trak looking for
10304 * the SMI and gama atoms.
10305 */
10306 static void
qtdemux_parse_svq3_stsd_data(GstQTDemux * qtdemux,const guint8 * stsd_entry_data,const guint8 ** gamma,GstBuffer ** seqh)10307 qtdemux_parse_svq3_stsd_data (GstQTDemux * qtdemux,
10308 const guint8 * stsd_entry_data, const guint8 ** gamma, GstBuffer ** seqh)
10309 {
10310 const guint8 *_gamma = NULL;
10311 GstBuffer *_seqh = NULL;
10312 const guint8 *stsd_data = stsd_entry_data;
10313 guint32 length = QT_UINT32 (stsd_data);
10314 guint16 version;
10315
10316 if (length < 32) {
10317 GST_WARNING_OBJECT (qtdemux, "stsd too short");
10318 goto end;
10319 }
10320
10321 stsd_data += 16;
10322 length -= 16;
10323 version = QT_UINT16 (stsd_data);
10324 if (version == 3) {
10325 if (length >= 70) {
10326 length -= 70;
10327 stsd_data += 70;
10328 while (length > 8) {
10329 guint32 fourcc, size;
10330 const guint8 *data;
10331 size = QT_UINT32 (stsd_data);
10332 fourcc = QT_FOURCC (stsd_data + 4);
10333 data = stsd_data + 8;
10334
10335 if (size == 0) {
10336 GST_WARNING_OBJECT (qtdemux, "Atom of size 0 found, aborting "
10337 "svq3 atom parsing");
10338 goto end;
10339 }
10340
10341 switch (fourcc) {
10342 case FOURCC_gama:{
10343 if (size == 12) {
10344 _gamma = data;
10345 } else {
10346 GST_WARNING_OBJECT (qtdemux, "Unexpected size %" G_GUINT32_FORMAT
10347 " for gama atom, expected 12", size);
10348 }
10349 break;
10350 }
10351 case FOURCC_SMI_:{
10352 if (size > 16 && QT_FOURCC (data) == FOURCC_SEQH) {
10353 guint32 seqh_size;
10354 if (_seqh != NULL) {
10355 GST_WARNING_OBJECT (qtdemux, "Unexpected second SEQH SMI atom "
10356 " found, ignoring");
10357 } else {
10358 seqh_size = QT_UINT32 (data + 4);
10359 if (seqh_size > 0) {
10360 _seqh = gst_buffer_new_and_alloc (seqh_size);
10361 gst_buffer_fill (_seqh, 0, data + 8, seqh_size);
10362 }
10363 }
10364 }
10365 break;
10366 }
10367 default:{
10368 GST_WARNING_OBJECT (qtdemux, "Unhandled atom %" GST_FOURCC_FORMAT
10369 " in SVQ3 entry in stsd atom", GST_FOURCC_ARGS (fourcc));
10370 }
10371 }
10372
10373 if (size <= length) {
10374 length -= size;
10375 stsd_data += size;
10376 }
10377 }
10378 } else {
10379 GST_WARNING_OBJECT (qtdemux, "SVQ3 entry too short in stsd atom");
10380 }
10381 } else {
10382 GST_WARNING_OBJECT (qtdemux, "Unexpected version for SVQ3 entry %"
10383 G_GUINT16_FORMAT, version);
10384 goto end;
10385 }
10386
10387 end:
10388 if (gamma) {
10389 *gamma = _gamma;
10390 }
10391 if (seqh) {
10392 *seqh = _seqh;
10393 } else if (_seqh) {
10394 gst_buffer_unref (_seqh);
10395 }
10396 }
10397
10398 static gchar *
qtdemux_get_rtsp_uri_from_hndl(GstQTDemux * qtdemux,GNode * minf)10399 qtdemux_get_rtsp_uri_from_hndl (GstQTDemux * qtdemux, GNode * minf)
10400 {
10401 GNode *dinf;
10402 GstByteReader dref;
10403 gchar *uri = NULL;
10404
10405 /*
10406 * Get 'dinf', to get its child 'dref', that might contain a 'hndl'
10407 * atom that might contain a 'data' atom with the rtsp uri.
10408 * This case was reported in bug #597497, some info about
10409 * the hndl atom can be found in TN1195
10410 */
10411 dinf = qtdemux_tree_get_child_by_type (minf, FOURCC_dinf);
10412 GST_DEBUG_OBJECT (qtdemux, "Trying to obtain rtsp URI for stream trak");
10413
10414 if (dinf) {
10415 guint32 dref_num_entries = 0;
10416 if (qtdemux_tree_get_child_by_type_full (dinf, FOURCC_dref, &dref) &&
10417 gst_byte_reader_skip (&dref, 4) &&
10418 gst_byte_reader_get_uint32_be (&dref, &dref_num_entries)) {
10419 gint i;
10420
10421 /* search dref entries for hndl atom */
10422 for (i = 0; i < dref_num_entries; i++) {
10423 guint32 size = 0, type;
10424 guint8 string_len = 0;
10425 if (gst_byte_reader_get_uint32_be (&dref, &size) &&
10426 qt_atom_parser_get_fourcc (&dref, &type)) {
10427 if (type == FOURCC_hndl) {
10428 GST_DEBUG_OBJECT (qtdemux, "Found hndl atom");
10429
10430 /* skip data reference handle bytes and the
10431 * following pascal string and some extra 4
10432 * bytes I have no idea what are */
10433 if (!gst_byte_reader_skip (&dref, 4) ||
10434 !gst_byte_reader_get_uint8 (&dref, &string_len) ||
10435 !gst_byte_reader_skip (&dref, string_len + 4)) {
10436 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl atom");
10437 break;
10438 }
10439
10440 /* iterate over the atoms to find the data atom */
10441 while (gst_byte_reader_get_remaining (&dref) >= 8) {
10442 guint32 atom_size;
10443 guint32 atom_type;
10444
10445 if (gst_byte_reader_get_uint32_be (&dref, &atom_size) &&
10446 qt_atom_parser_get_fourcc (&dref, &atom_type)) {
10447 if (atom_type == FOURCC_data) {
10448 const guint8 *uri_aux = NULL;
10449
10450 /* found the data atom that might contain the rtsp uri */
10451 GST_DEBUG_OBJECT (qtdemux, "Found data atom inside "
10452 "hndl atom, interpreting it as an URI");
10453 if (gst_byte_reader_peek_data (&dref, atom_size - 8,
10454 &uri_aux)) {
10455 if (g_strstr_len ((gchar *) uri_aux, 7, "rtsp://") != NULL)
10456 uri = g_strndup ((gchar *) uri_aux, atom_size - 8);
10457 else
10458 GST_WARNING_OBJECT (qtdemux, "Data atom in hndl atom "
10459 "didn't contain a rtsp address");
10460 } else {
10461 GST_WARNING_OBJECT (qtdemux, "Failed to get the data "
10462 "atom contents");
10463 }
10464 break;
10465 }
10466 /* skipping to the next entry */
10467 if (!gst_byte_reader_skip (&dref, atom_size - 8))
10468 break;
10469 } else {
10470 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl child "
10471 "atom header");
10472 break;
10473 }
10474 }
10475 break;
10476 }
10477 /* skip to the next entry */
10478 if (!gst_byte_reader_skip (&dref, size - 8))
10479 break;
10480 } else {
10481 GST_WARNING_OBJECT (qtdemux, "Error parsing dref atom");
10482 }
10483 }
10484 GST_DEBUG_OBJECT (qtdemux, "Finished parsing dref atom");
10485 }
10486 }
10487 return uri;
10488 }
10489
10490 #define AMR_NB_ALL_MODES 0x81ff
10491 #define AMR_WB_ALL_MODES 0x83ff
10492 static guint
qtdemux_parse_amr_bitrate(GstBuffer * buf,gboolean wb)10493 qtdemux_parse_amr_bitrate (GstBuffer * buf, gboolean wb)
10494 {
10495 /* The 'damr' atom is of the form:
10496 *
10497 * | vendor | decoder_ver | mode_set | mode_change_period | frames/sample |
10498 * 32 b 8 b 16 b 8 b 8 b
10499 *
10500 * The highest set bit of the first 7 (AMR-NB) or 8 (AMR-WB) bits of mode_set
10501 * represents the highest mode used in the stream (and thus the maximum
10502 * bitrate), with a couple of special cases as seen below.
10503 */
10504
10505 /* Map of frame type ID -> bitrate */
10506 static const guint nb_bitrates[] = {
10507 4750, 5150, 5900, 6700, 7400, 7950, 10200, 12200
10508 };
10509 static const guint wb_bitrates[] = {
10510 6600, 8850, 12650, 14250, 15850, 18250, 19850, 23050, 23850
10511 };
10512 GstMapInfo map;
10513 gsize max_mode;
10514 guint16 mode_set;
10515
10516 gst_buffer_map (buf, &map, GST_MAP_READ);
10517
10518 if (map.size != 0x11) {
10519 GST_DEBUG ("Atom should have size 0x11, not %" G_GSIZE_FORMAT, map.size);
10520 goto bad_data;
10521 }
10522
10523 if (QT_FOURCC (map.data + 4) != FOURCC_damr) {
10524 GST_DEBUG ("Unknown atom in %" GST_FOURCC_FORMAT,
10525 GST_FOURCC_ARGS (QT_UINT32 (map.data + 4)));
10526 goto bad_data;
10527 }
10528
10529 mode_set = QT_UINT16 (map.data + 13);
10530
10531 if (mode_set == (wb ? AMR_WB_ALL_MODES : AMR_NB_ALL_MODES))
10532 max_mode = 7 + (wb ? 1 : 0);
10533 else
10534 /* AMR-NB modes fo from 0-7, and AMR-WB modes go from 0-8 */
10535 max_mode = g_bit_nth_msf ((gulong) mode_set & (wb ? 0x1ff : 0xff), -1);
10536
10537 if (max_mode == -1) {
10538 GST_DEBUG ("No mode indication was found (mode set) = %x",
10539 (guint) mode_set);
10540 goto bad_data;
10541 }
10542
10543 gst_buffer_unmap (buf, &map);
10544 return wb ? wb_bitrates[max_mode] : nb_bitrates[max_mode];
10545
10546 bad_data:
10547 gst_buffer_unmap (buf, &map);
10548 return 0;
10549 }
10550
10551 static gboolean
qtdemux_parse_transformation_matrix(GstQTDemux * qtdemux,GstByteReader * reader,guint32 * matrix,const gchar * atom)10552 qtdemux_parse_transformation_matrix (GstQTDemux * qtdemux,
10553 GstByteReader * reader, guint32 * matrix, const gchar * atom)
10554 {
10555 /*
10556 * 9 values of 32 bits (fixed point 16.16, except 2 5 and 8 that are 2.30)
10557 * [0 1 2]
10558 * [3 4 5]
10559 * [6 7 8]
10560 */
10561
10562 if (gst_byte_reader_get_remaining (reader) < 36)
10563 return FALSE;
10564
10565 matrix[0] = gst_byte_reader_get_uint32_be_unchecked (reader);
10566 matrix[1] = gst_byte_reader_get_uint32_be_unchecked (reader);
10567 matrix[2] = gst_byte_reader_get_uint32_be_unchecked (reader);
10568 matrix[3] = gst_byte_reader_get_uint32_be_unchecked (reader);
10569 matrix[4] = gst_byte_reader_get_uint32_be_unchecked (reader);
10570 matrix[5] = gst_byte_reader_get_uint32_be_unchecked (reader);
10571 matrix[6] = gst_byte_reader_get_uint32_be_unchecked (reader);
10572 matrix[7] = gst_byte_reader_get_uint32_be_unchecked (reader);
10573 matrix[8] = gst_byte_reader_get_uint32_be_unchecked (reader);
10574
10575 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix from atom %s", atom);
10576 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[0] >> 16,
10577 matrix[0] & 0xFFFF, matrix[1] >> 16, matrix[1] & 0xFF, matrix[2] >> 16,
10578 matrix[2] & 0xFF);
10579 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[3] >> 16,
10580 matrix[3] & 0xFFFF, matrix[4] >> 16, matrix[4] & 0xFF, matrix[5] >> 16,
10581 matrix[5] & 0xFF);
10582 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[6] >> 16,
10583 matrix[6] & 0xFFFF, matrix[7] >> 16, matrix[7] & 0xFF, matrix[8] >> 16,
10584 matrix[8] & 0xFF);
10585
10586 return TRUE;
10587 }
10588
10589 static void
qtdemux_inspect_transformation_matrix(GstQTDemux * qtdemux,QtDemuxStream * stream,guint32 * matrix,GstTagList ** taglist)10590 qtdemux_inspect_transformation_matrix (GstQTDemux * qtdemux,
10591 QtDemuxStream * stream, guint32 * matrix, GstTagList ** taglist)
10592 {
10593
10594 /* [a b c]
10595 * [d e f]
10596 * [g h i]
10597 *
10598 * This macro will only compare value abdegh, it expects cfi to have already
10599 * been checked
10600 */
10601 #define QTCHECK_MATRIX(m,a,b,d,e) ((m)[0] == (a << 16) && (m)[1] == (b << 16) && \
10602 (m)[3] == (d << 16) && (m)[4] == (e << 16))
10603
10604 /* only handle the cases where the last column has standard values */
10605 if (matrix[2] == 0 && matrix[5] == 0 && matrix[8] == 1 << 30) {
10606 const gchar *rotation_tag = NULL;
10607
10608 /* no rotation needed */
10609 if (QTCHECK_MATRIX (matrix, 1, 0, 0, 1)) {
10610 /* NOP */
10611 } else if (QTCHECK_MATRIX (matrix, 0, 1, G_MAXUINT16, 0)) {
10612 rotation_tag = "rotate-90";
10613 } else if (QTCHECK_MATRIX (matrix, G_MAXUINT16, 0, 0, G_MAXUINT16)) {
10614 rotation_tag = "rotate-180";
10615 } else if (QTCHECK_MATRIX (matrix, 0, G_MAXUINT16, 1, 0)) {
10616 rotation_tag = "rotate-270";
10617 } else {
10618 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
10619 }
10620
10621 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix rotation %s",
10622 GST_STR_NULL (rotation_tag));
10623 if (rotation_tag != NULL) {
10624 if (*taglist == NULL)
10625 *taglist = gst_tag_list_new_empty ();
10626 gst_tag_list_add (*taglist, GST_TAG_MERGE_REPLACE,
10627 GST_TAG_IMAGE_ORIENTATION, rotation_tag, NULL);
10628 #ifdef OHOS_EXT_FUNC
10629 // ohos.ext.func.0032
10630 GstMessage *msg_video_rotation = gst_message_new_video_rotation (GST_OBJECT (qtdemux), rotation_tag);
10631 if (msg_video_rotation != NULL) {
10632 gst_element_post_message (GST_ELEMENT (qtdemux), msg_video_rotation);
10633 }
10634 #endif
10635 }
10636 } else {
10637 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
10638 }
10639 }
10640
10641 static gboolean
qtdemux_parse_protection_aavd(GstQTDemux * qtdemux,QtDemuxStream * stream,GNode * container,guint32 * original_fmt)10642 qtdemux_parse_protection_aavd (GstQTDemux * qtdemux,
10643 QtDemuxStream * stream, GNode * container, guint32 * original_fmt)
10644 {
10645 GNode *adrm;
10646 guint32 adrm_size;
10647 GstBuffer *adrm_buf = NULL;
10648 QtDemuxAavdEncryptionInfo *info;
10649
10650 adrm = qtdemux_tree_get_child_by_type (container, FOURCC_adrm);
10651 if (G_UNLIKELY (!adrm)) {
10652 GST_ERROR_OBJECT (qtdemux, "aavd box does not contain mandatory adrm box");
10653 return FALSE;
10654 }
10655 adrm_size = QT_UINT32 (adrm->data);
10656 adrm_buf = gst_buffer_new_memdup (adrm->data, adrm_size);
10657
10658 stream->protection_scheme_type = FOURCC_aavd;
10659
10660 if (!stream->protection_scheme_info)
10661 stream->protection_scheme_info = g_new0 (QtDemuxAavdEncryptionInfo, 1);
10662
10663 info = (QtDemuxAavdEncryptionInfo *) stream->protection_scheme_info;
10664
10665 if (info->default_properties)
10666 gst_structure_free (info->default_properties);
10667 info->default_properties = gst_structure_new ("application/x-aavd",
10668 "encrypted", G_TYPE_BOOLEAN, TRUE,
10669 "adrm", GST_TYPE_BUFFER, adrm_buf, NULL);
10670 gst_buffer_unref (adrm_buf);
10671
10672 *original_fmt = FOURCC_mp4a;
10673 return TRUE;
10674 }
10675
10676 /* Parses the boxes defined in ISO/IEC 14496-12 that enable support for
10677 * protected streams (sinf, frma, schm and schi); if the protection scheme is
10678 * Common Encryption (cenc), the function will also parse the tenc box (defined
10679 * in ISO/IEC 23001-7). @container points to the node that contains these boxes
10680 * (typically an enc[v|a|t|s] sample entry); the function will set
10681 * @original_fmt to the fourcc of the original unencrypted stream format.
10682 * Returns TRUE if successful; FALSE otherwise. */
10683 static gboolean
qtdemux_parse_protection_scheme_info(GstQTDemux * qtdemux,QtDemuxStream * stream,GNode * container,guint32 * original_fmt)10684 qtdemux_parse_protection_scheme_info (GstQTDemux * qtdemux,
10685 QtDemuxStream * stream, GNode * container, guint32 * original_fmt)
10686 {
10687 GNode *sinf;
10688 GNode *frma;
10689 GNode *schm;
10690 GNode *schi;
10691 QtDemuxCencSampleSetInfo *info;
10692 GNode *tenc;
10693 const guint8 *tenc_data;
10694
10695 g_return_val_if_fail (qtdemux != NULL, FALSE);
10696 g_return_val_if_fail (stream != NULL, FALSE);
10697 g_return_val_if_fail (container != NULL, FALSE);
10698 g_return_val_if_fail (original_fmt != NULL, FALSE);
10699
10700 sinf = qtdemux_tree_get_child_by_type (container, FOURCC_sinf);
10701 if (G_UNLIKELY (!sinf)) {
10702 if (stream->protection_scheme_type == FOURCC_cenc
10703 || stream->protection_scheme_type == FOURCC_cbcs) {
10704 GST_ERROR_OBJECT (qtdemux, "sinf box does not contain schi box, which is "
10705 "mandatory for Common Encryption");
10706 return FALSE;
10707 }
10708 return TRUE;
10709 }
10710
10711 frma = qtdemux_tree_get_child_by_type (sinf, FOURCC_frma);
10712 if (G_UNLIKELY (!frma)) {
10713 GST_ERROR_OBJECT (qtdemux, "sinf box does not contain mandatory frma box");
10714 return FALSE;
10715 }
10716
10717 *original_fmt = QT_FOURCC ((const guint8 *) frma->data + 8);
10718 GST_DEBUG_OBJECT (qtdemux, "original stream format: '%" GST_FOURCC_FORMAT "'",
10719 GST_FOURCC_ARGS (*original_fmt));
10720
10721 schm = qtdemux_tree_get_child_by_type (sinf, FOURCC_schm);
10722 if (!schm) {
10723 GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schm box");
10724 return FALSE;
10725 }
10726 stream->protection_scheme_type = QT_FOURCC ((const guint8 *) schm->data + 12);
10727 stream->protection_scheme_version =
10728 QT_UINT32 ((const guint8 *) schm->data + 16);
10729
10730 GST_DEBUG_OBJECT (qtdemux,
10731 "protection_scheme_type: %" GST_FOURCC_FORMAT ", "
10732 "protection_scheme_version: %#010x",
10733 GST_FOURCC_ARGS (stream->protection_scheme_type),
10734 stream->protection_scheme_version);
10735
10736 schi = qtdemux_tree_get_child_by_type (sinf, FOURCC_schi);
10737 if (!schi) {
10738 GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schi box");
10739 return FALSE;
10740 }
10741 if (stream->protection_scheme_type != FOURCC_cenc &&
10742 stream->protection_scheme_type != FOURCC_piff &&
10743 stream->protection_scheme_type != FOURCC_cbcs) {
10744 GST_ERROR_OBJECT (qtdemux,
10745 "Invalid protection_scheme_type: %" GST_FOURCC_FORMAT,
10746 GST_FOURCC_ARGS (stream->protection_scheme_type));
10747 return FALSE;
10748 }
10749
10750 if (G_UNLIKELY (!stream->protection_scheme_info))
10751 stream->protection_scheme_info =
10752 g_malloc0 (sizeof (QtDemuxCencSampleSetInfo));
10753
10754 info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
10755
10756 if (stream->protection_scheme_type == FOURCC_cenc
10757 || stream->protection_scheme_type == FOURCC_cbcs) {
10758 guint8 is_encrypted;
10759 guint8 iv_size;
10760 guint8 constant_iv_size = 0;
10761 const guint8 *default_kid;
10762 guint8 crypt_byte_block = 0;
10763 guint8 skip_byte_block = 0;
10764 const guint8 *constant_iv = NULL;
10765
10766 tenc = qtdemux_tree_get_child_by_type (schi, FOURCC_tenc);
10767 if (!tenc) {
10768 GST_ERROR_OBJECT (qtdemux, "schi box does not contain tenc box, "
10769 "which is mandatory for Common Encryption");
10770 return FALSE;
10771 }
10772 tenc_data = (const guint8 *) tenc->data + 12;
10773 is_encrypted = QT_UINT8 (tenc_data + 2);
10774 iv_size = QT_UINT8 (tenc_data + 3);
10775 default_kid = (tenc_data + 4);
10776 if (stream->protection_scheme_type == FOURCC_cbcs) {
10777 guint8 possible_pattern_info;
10778 if (iv_size == 0) {
10779 constant_iv_size = QT_UINT8 (tenc_data + 20);
10780 if (constant_iv_size != 8 && constant_iv_size != 16) {
10781 GST_ERROR_OBJECT (qtdemux,
10782 "constant IV size should be 8 or 16, not %hhu", constant_iv_size);
10783 return FALSE;
10784 }
10785 constant_iv = (tenc_data + 21);
10786 }
10787 possible_pattern_info = QT_UINT8 (tenc_data + 1);
10788 crypt_byte_block = (possible_pattern_info >> 4) & 0x0f;
10789 skip_byte_block = possible_pattern_info & 0x0f;
10790 }
10791 qtdemux_update_default_sample_cenc_settings (qtdemux, info,
10792 is_encrypted, stream->protection_scheme_type, iv_size, default_kid,
10793 crypt_byte_block, skip_byte_block, constant_iv_size, constant_iv);
10794 } else if (stream->protection_scheme_type == FOURCC_piff) {
10795 GstByteReader br;
10796 static const guint8 piff_track_encryption_uuid[] = {
10797 0x89, 0x74, 0xdb, 0xce, 0x7b, 0xe7, 0x4c, 0x51,
10798 0x84, 0xf9, 0x71, 0x48, 0xf9, 0x88, 0x25, 0x54
10799 };
10800
10801 tenc = qtdemux_tree_get_child_by_type (schi, FOURCC_uuid);
10802 if (!tenc) {
10803 GST_ERROR_OBJECT (qtdemux, "schi box does not contain tenc box, "
10804 "which is mandatory for Common Encryption");
10805 return FALSE;
10806 }
10807
10808 tenc_data = (const guint8 *) tenc->data + 8;
10809 if (memcmp (tenc_data, piff_track_encryption_uuid, 16) != 0) {
10810 gchar *box_uuid = qtdemux_uuid_bytes_to_string (tenc_data);
10811 GST_ERROR_OBJECT (qtdemux,
10812 "Unsupported track encryption box with uuid: %s", box_uuid);
10813 g_free (box_uuid);
10814 return FALSE;
10815 }
10816 tenc_data = (const guint8 *) tenc->data + 16 + 12;
10817 gst_byte_reader_init (&br, tenc_data, 20);
10818 if (!qtdemux_update_default_piff_encryption_settings (qtdemux, info, &br)) {
10819 GST_ERROR_OBJECT (qtdemux, "PIFF track box parsing error");
10820 return FALSE;
10821 }
10822 stream->protection_scheme_type = FOURCC_cenc;
10823 }
10824
10825 return TRUE;
10826 }
10827
10828 static gint
qtdemux_track_id_compare_func(QtDemuxStream ** stream1,QtDemuxStream ** stream2)10829 qtdemux_track_id_compare_func (QtDemuxStream ** stream1,
10830 QtDemuxStream ** stream2)
10831 {
10832 return (gint) (*stream1)->track_id - (gint) (*stream2)->track_id;
10833 }
10834
10835 static gboolean
qtdemux_parse_stereo_svmi_atom(GstQTDemux * qtdemux,QtDemuxStream * stream,GNode * stbl)10836 qtdemux_parse_stereo_svmi_atom (GstQTDemux * qtdemux, QtDemuxStream * stream,
10837 GNode * stbl)
10838 {
10839 GNode *svmi;
10840
10841 /*parse svmi header if existing */
10842 svmi = qtdemux_tree_get_child_by_type (stbl, FOURCC_svmi);
10843 if (svmi) {
10844 guint len = QT_UINT32 ((guint8 *) svmi->data);
10845 guint32 version = QT_UINT32 ((guint8 *) svmi->data + 8);
10846 if (!version) {
10847 GstVideoMultiviewMode mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
10848 GstVideoMultiviewFlags flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
10849 guint8 frame_type, frame_layout;
10850 guint32 stereo_mono_change_count;
10851
10852 if (len < 18)
10853 return FALSE;
10854
10855 /* MPEG-A stereo video */
10856 if (qtdemux->major_brand == FOURCC_ss02)
10857 flags |= GST_VIDEO_MULTIVIEW_FLAGS_MIXED_MONO;
10858
10859 frame_type = QT_UINT8 ((guint8 *) svmi->data + 12);
10860 frame_layout = QT_UINT8 ((guint8 *) svmi->data + 13) & 0x01;
10861 stereo_mono_change_count = QT_UINT32 ((guint8 *) svmi->data + 14);
10862
10863 switch (frame_type) {
10864 case 0:
10865 mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
10866 break;
10867 case 1:
10868 mode = GST_VIDEO_MULTIVIEW_MODE_ROW_INTERLEAVED;
10869 break;
10870 case 2:
10871 mode = GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME;
10872 break;
10873 case 3:
10874 /* mode 3 is primary/secondary view sequence, ie
10875 * left/right views in separate tracks. See section 7.2
10876 * of ISO/IEC 23000-11:2009 */
10877 /* In the future this might be supported using related
10878 * streams, like an enhancement track - if files like this
10879 * ever exist */
10880 GST_FIXME_OBJECT (qtdemux,
10881 "Implement stereo video in separate streams");
10882 }
10883
10884 if ((frame_layout & 0x1) == 0)
10885 flags |= GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
10886
10887 GST_LOG_OBJECT (qtdemux,
10888 "StereoVideo: composition type: %u, is_left_first: %u",
10889 frame_type, frame_layout);
10890
10891 if (stereo_mono_change_count > 1) {
10892 GST_FIXME_OBJECT (qtdemux,
10893 "Mixed-mono flags are not yet supported in qtdemux.");
10894 }
10895
10896 stream->multiview_mode = mode;
10897 stream->multiview_flags = flags;
10898 }
10899 }
10900
10901 return TRUE;
10902 }
10903
10904 /* parse the traks.
10905 * With each track we associate a new QtDemuxStream that contains all the info
10906 * about the trak.
10907 * traks that do not decode to something (like strm traks) will not have a pad.
10908 */
10909 static gboolean
qtdemux_parse_trak(GstQTDemux * qtdemux,GNode * trak)10910 qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
10911 {
10912 GstByteReader tkhd;
10913 int offset;
10914 GNode *mdia;
10915 GNode *mdhd;
10916 GNode *hdlr;
10917 GNode *minf;
10918 GNode *stbl;
10919 GNode *stsd;
10920 GNode *mp4a;
10921 GNode *mp4v;
10922 GNode *esds;
10923 GNode *tref;
10924 GNode *udta;
10925
10926 QtDemuxStream *stream = NULL;
10927 const guint8 *stsd_data;
10928 const guint8 *stsd_entry_data;
10929 guint remaining_stsd_len;
10930 guint stsd_entry_count;
10931 guint stsd_index;
10932 guint16 lang_code; /* quicktime lang code or packed iso code */
10933 guint32 version;
10934 guint32 tkhd_flags = 0;
10935 guint8 tkhd_version = 0;
10936 guint32 w = 0, h = 0;
10937 guint value_size, stsd_len, len;
10938 guint32 track_id;
10939 guint32 dummy;
10940
10941 GST_DEBUG_OBJECT (qtdemux, "parse_trak");
10942
10943 if (!qtdemux_tree_get_child_by_type_full (trak, FOURCC_tkhd, &tkhd)
10944 || !gst_byte_reader_get_uint8 (&tkhd, &tkhd_version)
10945 || !gst_byte_reader_get_uint24_be (&tkhd, &tkhd_flags))
10946 goto corrupt_file;
10947
10948 /* pick between 64 or 32 bits */
10949 value_size = tkhd_version == 1 ? 8 : 4;
10950 if (!gst_byte_reader_skip (&tkhd, value_size * 2) ||
10951 !gst_byte_reader_get_uint32_be (&tkhd, &track_id))
10952 goto corrupt_file;
10953
10954 /* Check if current moov has duplicated track_id */
10955 if (qtdemux_find_stream (qtdemux, track_id))
10956 goto existing_stream;
10957
10958 stream = _create_stream (qtdemux, track_id);
10959 stream->stream_tags = gst_tag_list_make_writable (stream->stream_tags);
10960
10961 /* need defaults for fragments */
10962 qtdemux_parse_trex (qtdemux, stream, &dummy, &dummy, &dummy);
10963
10964 if ((tkhd_flags & 1) == 0)
10965 stream->disabled = TRUE;
10966
10967 GST_LOG_OBJECT (qtdemux, "track[tkhd] version/flags/id: 0x%02x/%06x/%u",
10968 tkhd_version, tkhd_flags, stream->track_id);
10969
10970 if (!(mdia = qtdemux_tree_get_child_by_type (trak, FOURCC_mdia)))
10971 goto corrupt_file;
10972
10973 if (!(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mdhd))) {
10974 /* be nice for some crooked mjp2 files that use mhdr for mdhd */
10975 if (qtdemux->major_brand != FOURCC_mjp2 ||
10976 !(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mhdr)))
10977 goto corrupt_file;
10978 }
10979
10980 len = QT_UINT32 ((guint8 *) mdhd->data);
10981 version = QT_UINT32 ((guint8 *) mdhd->data + 8);
10982 GST_LOG_OBJECT (qtdemux, "track version/flags: %08x", version);
10983 if (version == 0x01000000) {
10984 if (len < 42)
10985 goto corrupt_file;
10986 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 28);
10987 stream->duration = QT_UINT64 ((guint8 *) mdhd->data + 32);
10988 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 40);
10989 } else {
10990 if (len < 30)
10991 goto corrupt_file;
10992 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 20);
10993 stream->duration = QT_UINT32 ((guint8 *) mdhd->data + 24);
10994 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 28);
10995 }
10996
10997 if (lang_code < 0x400) {
10998 qtdemux_lang_map_qt_code_to_iso (stream->lang_id, lang_code);
10999 } else if (lang_code == 0x7fff) {
11000 stream->lang_id[0] = 0; /* unspecified */
11001 } else {
11002 stream->lang_id[0] = 0x60 + ((lang_code >> 10) & 0x1F);
11003 stream->lang_id[1] = 0x60 + ((lang_code >> 5) & 0x1F);
11004 stream->lang_id[2] = 0x60 + (lang_code & 0x1F);
11005 stream->lang_id[3] = 0;
11006 }
11007
11008 GST_LOG_OBJECT (qtdemux, "track timescale: %" G_GUINT32_FORMAT,
11009 stream->timescale);
11010 GST_LOG_OBJECT (qtdemux, "track duration: %" G_GUINT64_FORMAT,
11011 stream->duration);
11012 GST_LOG_OBJECT (qtdemux, "track language code/id: 0x%04x/%s",
11013 lang_code, stream->lang_id);
11014
11015 if (G_UNLIKELY (stream->timescale == 0 || qtdemux->timescale == 0))
11016 goto corrupt_file;
11017
11018 if ((tref = qtdemux_tree_get_child_by_type (trak, FOURCC_tref))) {
11019 /* chapters track reference */
11020 GNode *chap = qtdemux_tree_get_child_by_type (tref, FOURCC_chap);
11021 if (chap) {
11022 gsize length = GST_READ_UINT32_BE (chap->data);
11023 if (qtdemux->chapters_track_id)
11024 GST_FIXME_OBJECT (qtdemux, "Multiple CHAP tracks");
11025
11026 if (length >= 12) {
11027 qtdemux->chapters_track_id =
11028 GST_READ_UINT32_BE ((gint8 *) chap->data + 8);
11029 }
11030 }
11031 }
11032
11033 /* fragmented files may have bogus duration in moov */
11034 if (!qtdemux->fragmented &&
11035 qtdemux->duration != G_MAXINT64 && stream->duration != G_MAXINT32) {
11036 guint64 tdur1, tdur2;
11037
11038 /* don't overflow */
11039 tdur1 = stream->timescale * (guint64) qtdemux->duration;
11040 tdur2 = qtdemux->timescale * (guint64) stream->duration;
11041
11042 /* HACK:
11043 * some of those trailers, nowadays, have prologue images that are
11044 * themselves video tracks as well. I haven't really found a way to
11045 * identify those yet, except for just looking at their duration. */
11046 if (tdur1 != 0 && (tdur2 * 10 / tdur1) < 2) {
11047 GST_WARNING_OBJECT (qtdemux,
11048 "Track shorter than 20%% (%" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT
11049 " vs. %" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT ") of the stream "
11050 "found, assuming preview image or something; skipping track",
11051 stream->duration, stream->timescale, qtdemux->duration,
11052 qtdemux->timescale);
11053 gst_qtdemux_stream_unref (stream);
11054 return TRUE;
11055 }
11056 }
11057
11058 if (!(hdlr = qtdemux_tree_get_child_by_type (mdia, FOURCC_hdlr)))
11059 goto corrupt_file;
11060
11061 GST_LOG_OBJECT (qtdemux, "track type: %" GST_FOURCC_FORMAT,
11062 GST_FOURCC_ARGS (QT_FOURCC ((guint8 *) hdlr->data + 12)));
11063
11064 len = QT_UINT32 ((guint8 *) hdlr->data);
11065 if (len >= 20)
11066 stream->subtype = QT_FOURCC ((guint8 *) hdlr->data + 16);
11067 GST_LOG_OBJECT (qtdemux, "track subtype: %" GST_FOURCC_FORMAT,
11068 GST_FOURCC_ARGS (stream->subtype));
11069
11070 if (!(minf = qtdemux_tree_get_child_by_type (mdia, FOURCC_minf)))
11071 goto corrupt_file;
11072
11073 if (!(stbl = qtdemux_tree_get_child_by_type (minf, FOURCC_stbl)))
11074 goto corrupt_file;
11075
11076 /* Parse out svmi (and later st3d/sv3d) atoms */
11077 if (!qtdemux_parse_stereo_svmi_atom (qtdemux, stream, stbl))
11078 goto corrupt_file;
11079
11080 /* parse rest of tkhd */
11081 if (stream->subtype == FOURCC_vide) {
11082 guint32 matrix[9];
11083
11084 /* version 1 uses some 64-bit ints */
11085 if (!gst_byte_reader_skip (&tkhd, 20 + value_size))
11086 goto corrupt_file;
11087
11088 if (!qtdemux_parse_transformation_matrix (qtdemux, &tkhd, matrix, "tkhd"))
11089 goto corrupt_file;
11090
11091 if (!gst_byte_reader_get_uint32_be (&tkhd, &w)
11092 || !gst_byte_reader_get_uint32_be (&tkhd, &h))
11093 goto corrupt_file;
11094
11095 qtdemux_inspect_transformation_matrix (qtdemux, stream, matrix,
11096 &stream->stream_tags);
11097 }
11098
11099 /* parse stsd */
11100 if (!(stsd = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsd)))
11101 goto corrupt_file;
11102 stsd_data = (const guint8 *) stsd->data;
11103
11104 /* stsd should at least have one entry */
11105 stsd_len = QT_UINT32 (stsd_data);
11106 if (stsd_len < 24) {
11107 /* .. but skip stream with empty stsd produced by some Vivotek cameras */
11108 if (stream->subtype == FOURCC_vivo) {
11109 gst_qtdemux_stream_unref (stream);
11110 return TRUE;
11111 } else {
11112 goto corrupt_file;
11113 }
11114 }
11115
11116 stream->stsd_entries_length = stsd_entry_count = QT_UINT32 (stsd_data + 12);
11117 /* each stsd entry must contain at least 8 bytes */
11118 if (stream->stsd_entries_length == 0
11119 || stream->stsd_entries_length > stsd_len / 8) {
11120 stream->stsd_entries_length = 0;
11121 goto corrupt_file;
11122 }
11123 stream->stsd_entries = g_new0 (QtDemuxStreamStsdEntry, stsd_entry_count);
11124 GST_LOG_OBJECT (qtdemux, "stsd len: %d", stsd_len);
11125 GST_LOG_OBJECT (qtdemux, "stsd entry count: %u", stsd_entry_count);
11126
11127 stsd_entry_data = stsd_data + 16;
11128 remaining_stsd_len = stsd_len - 16;
11129 for (stsd_index = 0; stsd_index < stsd_entry_count; stsd_index++) {
11130 guint32 fourcc;
11131 gchar *codec = NULL;
11132 QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[stsd_index];
11133
11134 /* and that entry should fit within stsd */
11135 len = QT_UINT32 (stsd_entry_data);
11136 if (len > remaining_stsd_len)
11137 goto corrupt_file;
11138
11139 entry->fourcc = fourcc = QT_FOURCC (stsd_entry_data + 4);
11140 GST_LOG_OBJECT (qtdemux, "stsd type: %" GST_FOURCC_FORMAT,
11141 GST_FOURCC_ARGS (entry->fourcc));
11142 GST_LOG_OBJECT (qtdemux, "stsd type len: %d", len);
11143
11144 if ((fourcc == FOURCC_drms) || (fourcc == FOURCC_drmi))
11145 goto error_encrypted;
11146
11147 if (fourcc == FOURCC_aavd) {
11148 if (stream->subtype != FOURCC_soun) {
11149 GST_ERROR_OBJECT (qtdemux,
11150 "Unexpeced stsd type 'aavd' outside 'soun' track");
11151 } else {
11152 /* encrypted audio with sound sample description v0 */
11153 GNode *enc = qtdemux_tree_get_child_by_type (stsd, fourcc);
11154 stream->protected = TRUE;
11155 if (!qtdemux_parse_protection_aavd (qtdemux, stream, enc, &fourcc))
11156 GST_ERROR_OBJECT (qtdemux, "Failed to parse protection scheme info");
11157 }
11158 }
11159
11160 if (fourcc == FOURCC_encv || fourcc == FOURCC_enca) {
11161 /* FIXME this looks wrong, there might be multiple children
11162 * with the same type */
11163 GNode *enc = qtdemux_tree_get_child_by_type (stsd, fourcc);
11164 stream->protected = TRUE;
11165 if (!qtdemux_parse_protection_scheme_info (qtdemux, stream, enc, &fourcc))
11166 GST_ERROR_OBJECT (qtdemux, "Failed to parse protection scheme info");
11167 }
11168
11169 if (stream->subtype == FOURCC_vide) {
11170 GNode *colr;
11171 GNode *fiel;
11172 GNode *pasp;
11173 gboolean gray;
11174 gint depth, palette_size, palette_count;
11175 guint32 *palette_data = NULL;
11176
11177 entry->sampled = TRUE;
11178
11179 stream->display_width = w >> 16;
11180 stream->display_height = h >> 16;
11181
11182 offset = 16;
11183 if (len < 86) /* TODO verify */
11184 goto corrupt_file;
11185
11186 entry->width = QT_UINT16 (stsd_entry_data + offset + 16);
11187 entry->height = QT_UINT16 (stsd_entry_data + offset + 18);
11188 entry->fps_n = 0; /* this is filled in later */
11189 entry->fps_d = 0; /* this is filled in later */
11190 entry->bits_per_sample = QT_UINT16 (stsd_entry_data + offset + 66);
11191 entry->color_table_id = QT_UINT16 (stsd_entry_data + offset + 68);
11192
11193 /* if color_table_id is 0, ctab atom must follow; however some files
11194 * produced by TMPEGEnc have color_table_id = 0 and no ctab atom, so
11195 * if color table is not present we'll correct the value */
11196 if (entry->color_table_id == 0 &&
11197 (len < 90
11198 || QT_FOURCC (stsd_entry_data + offset + 70) != FOURCC_ctab)) {
11199 entry->color_table_id = -1;
11200 }
11201
11202 GST_LOG_OBJECT (qtdemux, "width %d, height %d, bps %d, color table id %d",
11203 entry->width, entry->height, entry->bits_per_sample,
11204 entry->color_table_id);
11205
11206 depth = entry->bits_per_sample;
11207
11208 /* more than 32 bits means grayscale */
11209 gray = (depth > 32);
11210 /* low 32 bits specify the depth */
11211 depth &= 0x1F;
11212
11213 /* different number of palette entries is determined by depth. */
11214 palette_count = 0;
11215 if ((depth == 1) || (depth == 2) || (depth == 4) || (depth == 8))
11216 palette_count = (1 << depth);
11217 palette_size = palette_count * 4;
11218
11219 if (entry->color_table_id) {
11220 switch (palette_count) {
11221 case 0:
11222 break;
11223 case 2:
11224 palette_data = g_memdup2 (ff_qt_default_palette_2, palette_size);
11225 break;
11226 case 4:
11227 palette_data = g_memdup2 (ff_qt_default_palette_4, palette_size);
11228 break;
11229 case 16:
11230 if (gray)
11231 palette_data =
11232 g_memdup2 (ff_qt_grayscale_palette_16, palette_size);
11233 else
11234 palette_data = g_memdup2 (ff_qt_default_palette_16, palette_size);
11235 break;
11236 case 256:
11237 if (gray)
11238 palette_data =
11239 g_memdup2 (ff_qt_grayscale_palette_256, palette_size);
11240 else
11241 palette_data =
11242 g_memdup2 (ff_qt_default_palette_256, palette_size);
11243 break;
11244 default:
11245 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
11246 (_("The video in this file might not play correctly.")),
11247 ("unsupported palette depth %d", depth));
11248 break;
11249 }
11250 } else {
11251 gint i, j, start, end;
11252
11253 if (len < 94)
11254 goto corrupt_file;
11255
11256 /* read table */
11257 start = QT_UINT32 (stsd_entry_data + offset + 70);
11258 palette_count = QT_UINT16 (stsd_entry_data + offset + 74);
11259 end = QT_UINT16 (stsd_entry_data + offset + 76);
11260
11261 GST_LOG_OBJECT (qtdemux, "start %d, end %d, palette_count %d",
11262 start, end, palette_count);
11263
11264 if (end > 255)
11265 end = 255;
11266 if (start > end)
11267 start = end;
11268
11269 if (len < 94 + (end - start) * 8)
11270 goto corrupt_file;
11271
11272 /* palette is always the same size */
11273 palette_data = g_malloc0 (256 * 4);
11274 palette_size = 256 * 4;
11275
11276 for (j = 0, i = start; i <= end; j++, i++) {
11277 guint32 a, r, g, b;
11278
11279 a = QT_UINT16 (stsd_entry_data + offset + 78 + (j * 8));
11280 r = QT_UINT16 (stsd_entry_data + offset + 80 + (j * 8));
11281 g = QT_UINT16 (stsd_entry_data + offset + 82 + (j * 8));
11282 b = QT_UINT16 (stsd_entry_data + offset + 84 + (j * 8));
11283
11284 palette_data[i] = ((a & 0xff00) << 16) | ((r & 0xff00) << 8) |
11285 (g & 0xff00) | (b >> 8);
11286 }
11287 }
11288
11289 if (entry->caps)
11290 gst_caps_unref (entry->caps);
11291
11292 entry->caps =
11293 qtdemux_video_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
11294 &codec);
11295 if (G_UNLIKELY (!entry->caps)) {
11296 g_free (palette_data);
11297 goto unknown_stream;
11298 }
11299
11300 if (codec) {
11301 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11302 GST_TAG_VIDEO_CODEC, codec, NULL);
11303 g_free (codec);
11304 codec = NULL;
11305 }
11306
11307 if (palette_data) {
11308 GstStructure *s;
11309
11310 if (entry->rgb8_palette)
11311 gst_memory_unref (entry->rgb8_palette);
11312 entry->rgb8_palette = gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY,
11313 palette_data, palette_size, 0, palette_size, palette_data, g_free);
11314
11315 s = gst_caps_get_structure (entry->caps, 0);
11316
11317 /* non-raw video has a palette_data property. raw video has the palette as
11318 * an extra plane that we append to the output buffers before we push
11319 * them*/
11320 if (!gst_structure_has_name (s, "video/x-raw")) {
11321 GstBuffer *palette;
11322
11323 palette = gst_buffer_new ();
11324 gst_buffer_append_memory (palette, entry->rgb8_palette);
11325 entry->rgb8_palette = NULL;
11326
11327 gst_caps_set_simple (entry->caps, "palette_data",
11328 GST_TYPE_BUFFER, palette, NULL);
11329 gst_buffer_unref (palette);
11330 }
11331 } else if (palette_count != 0) {
11332 GST_ELEMENT_WARNING (qtdemux, STREAM, NOT_IMPLEMENTED,
11333 (NULL), ("Unsupported palette depth %d", depth));
11334 }
11335
11336 GST_LOG_OBJECT (qtdemux, "frame count: %u",
11337 QT_UINT16 (stsd_entry_data + offset + 32));
11338
11339 esds = NULL;
11340 pasp = NULL;
11341 colr = NULL;
11342 fiel = NULL;
11343 /* pick 'the' stsd child */
11344 mp4v = qtdemux_tree_get_child_by_index (stsd, stsd_index);
11345 // We should skip parsing the stsd for non-protected streams if
11346 // the entry doesn't match the fourcc, since they don't change
11347 // format. However, for protected streams we can have partial
11348 // encryption, where parts of the stream are encrypted and parts
11349 // not. For both parts of such streams, we should ensure the
11350 // esds overrides are parsed for both from the stsd.
11351 if (QTDEMUX_TREE_NODE_FOURCC (mp4v) != fourcc) {
11352 if (stream->protected && QTDEMUX_TREE_NODE_FOURCC (mp4v) != FOURCC_encv)
11353 mp4v = NULL;
11354 else if (!stream->protected)
11355 mp4v = NULL;
11356 }
11357
11358 if (mp4v) {
11359 esds = qtdemux_tree_get_child_by_type (mp4v, FOURCC_esds);
11360 pasp = qtdemux_tree_get_child_by_type (mp4v, FOURCC_pasp);
11361 colr = qtdemux_tree_get_child_by_type (mp4v, FOURCC_colr);
11362 fiel = qtdemux_tree_get_child_by_type (mp4v, FOURCC_fiel);
11363 }
11364
11365 if (pasp) {
11366 const guint8 *pasp_data = (const guint8 *) pasp->data;
11367 gint len = QT_UINT32 (pasp_data);
11368
11369 if (len == 16) {
11370 CUR_STREAM (stream)->par_w = QT_UINT32 (pasp_data + 8);
11371 CUR_STREAM (stream)->par_h = QT_UINT32 (pasp_data + 12);
11372 } else {
11373 CUR_STREAM (stream)->par_w = 0;
11374 CUR_STREAM (stream)->par_h = 0;
11375 }
11376 } else {
11377 CUR_STREAM (stream)->par_w = 0;
11378 CUR_STREAM (stream)->par_h = 0;
11379 }
11380
11381 if (fiel) {
11382 const guint8 *fiel_data = (const guint8 *) fiel->data;
11383 gint len = QT_UINT32 (fiel_data);
11384
11385 if (len == 10) {
11386 CUR_STREAM (stream)->interlace_mode = GST_READ_UINT8 (fiel_data + 8);
11387 CUR_STREAM (stream)->field_order = GST_READ_UINT8 (fiel_data + 9);
11388 }
11389 }
11390
11391 if (colr) {
11392 const guint8 *colr_data = (const guint8 *) colr->data;
11393 gint len = QT_UINT32 (colr_data);
11394
11395 if (len == 19 || len == 18) {
11396 guint32 color_type = GST_READ_UINT32_LE (colr_data + 8);
11397
11398 if (color_type == FOURCC_nclx || color_type == FOURCC_nclc) {
11399 guint16 primaries = GST_READ_UINT16_BE (colr_data + 12);
11400 guint16 transfer_function = GST_READ_UINT16_BE (colr_data + 14);
11401 guint16 matrix = GST_READ_UINT16_BE (colr_data + 16);
11402 gboolean full_range = len == 19 ? colr_data[17] >> 7 : FALSE;
11403
11404 CUR_STREAM (stream)->colorimetry.primaries =
11405 gst_video_color_primaries_from_iso (primaries);
11406 CUR_STREAM (stream)->colorimetry.transfer =
11407 gst_video_transfer_function_from_iso (transfer_function);
11408 CUR_STREAM (stream)->colorimetry.matrix =
11409 gst_video_color_matrix_from_iso (matrix);
11410 CUR_STREAM (stream)->colorimetry.range =
11411 full_range ? GST_VIDEO_COLOR_RANGE_0_255 :
11412 GST_VIDEO_COLOR_RANGE_16_235;
11413 } else {
11414 GST_DEBUG_OBJECT (qtdemux, "Unsupported color type");
11415 }
11416 } else {
11417 GST_WARNING_OBJECT (qtdemux, "Invalid colr atom size");
11418 }
11419 }
11420
11421 if (esds) {
11422 gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
11423 stream->stream_tags);
11424 } else {
11425 switch (fourcc) {
11426 case FOURCC_H264:
11427 case FOURCC_avc1:
11428 case FOURCC_avc3:
11429 {
11430 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
11431 const guint8 *avc_data = stsd_entry_data + 0x56;
11432
11433 /* find avcC */
11434 while (len >= 0x8) {
11435 gint size;
11436
11437 if (QT_UINT32 (avc_data) <= len)
11438 size = QT_UINT32 (avc_data) - 0x8;
11439 else
11440 size = len - 0x8;
11441
11442 if (size < 1)
11443 /* No real data, so break out */
11444 break;
11445
11446 switch (QT_FOURCC (avc_data + 0x4)) {
11447 case FOURCC_avcC:
11448 {
11449 /* parse, if found */
11450 GstBuffer *buf;
11451
11452 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
11453
11454 /* First 4 bytes are the length of the atom, the next 4 bytes
11455 * are the fourcc, the next 1 byte is the version, and the
11456 * subsequent bytes are profile_tier_level structure like data. */
11457 gst_codec_utils_h264_caps_set_level_and_profile (entry->caps,
11458 avc_data + 8 + 1, size - 1);
11459 buf = gst_buffer_new_and_alloc (size);
11460 gst_buffer_fill (buf, 0, avc_data + 0x8, size);
11461 gst_caps_set_simple (entry->caps,
11462 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11463 gst_buffer_unref (buf);
11464
11465 break;
11466 }
11467 case FOURCC_strf:
11468 {
11469 GstBuffer *buf;
11470
11471 GST_DEBUG_OBJECT (qtdemux, "found strf codec_data in stsd");
11472
11473 /* First 4 bytes are the length of the atom, the next 4 bytes
11474 * are the fourcc, next 40 bytes are BITMAPINFOHEADER,
11475 * next 1 byte is the version, and the
11476 * subsequent bytes are sequence parameter set like data. */
11477
11478 size -= 40; /* we'll be skipping BITMAPINFOHEADER */
11479 if (size > 1) {
11480 gst_codec_utils_h264_caps_set_level_and_profile
11481 (entry->caps, avc_data + 8 + 40 + 1, size - 1);
11482
11483 buf = gst_buffer_new_and_alloc (size);
11484 gst_buffer_fill (buf, 0, avc_data + 8 + 40, size);
11485 gst_caps_set_simple (entry->caps,
11486 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11487 gst_buffer_unref (buf);
11488 }
11489 break;
11490 }
11491 case FOURCC_btrt:
11492 {
11493 guint avg_bitrate, max_bitrate;
11494
11495 /* bufferSizeDB, maxBitrate and avgBitrate - 4 bytes each */
11496 if (size < 12)
11497 break;
11498
11499 max_bitrate = QT_UINT32 (avc_data + 0xc);
11500 avg_bitrate = QT_UINT32 (avc_data + 0x10);
11501
11502 if (!max_bitrate && !avg_bitrate)
11503 break;
11504
11505 /* Some muxers seem to swap the average and maximum bitrates
11506 * (I'm looking at you, YouTube), so we swap for sanity. */
11507 if (max_bitrate > 0 && max_bitrate < avg_bitrate) {
11508 guint temp = avg_bitrate;
11509
11510 avg_bitrate = max_bitrate;
11511 max_bitrate = temp;
11512 }
11513
11514 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
11515 gst_tag_list_add (stream->stream_tags,
11516 GST_TAG_MERGE_REPLACE, GST_TAG_MAXIMUM_BITRATE,
11517 max_bitrate, NULL);
11518 }
11519 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
11520 gst_tag_list_add (stream->stream_tags,
11521 GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE, avg_bitrate,
11522 NULL);
11523 }
11524
11525 break;
11526 }
11527
11528 default:
11529 break;
11530 }
11531
11532 len -= size + 8;
11533 avc_data += size + 8;
11534 }
11535
11536 break;
11537 }
11538 case FOURCC_H265:
11539 case FOURCC_hvc1:
11540 case FOURCC_hev1:
11541 case FOURCC_dvh1:
11542 case FOURCC_dvhe:
11543 {
11544 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
11545 const guint8 *hevc_data = stsd_entry_data + 0x56;
11546
11547 /* find hevc */
11548 while (len >= 0x8) {
11549 gint size;
11550
11551 if (QT_UINT32 (hevc_data) <= len)
11552 size = QT_UINT32 (hevc_data) - 0x8;
11553 else
11554 size = len - 0x8;
11555
11556 if (size < 1)
11557 /* No real data, so break out */
11558 break;
11559
11560 switch (QT_FOURCC (hevc_data + 0x4)) {
11561 case FOURCC_hvcC:
11562 {
11563 /* parse, if found */
11564 GstBuffer *buf;
11565
11566 GST_DEBUG_OBJECT (qtdemux, "found hvcC codec_data in stsd");
11567
11568 /* First 4 bytes are the length of the atom, the next 4 bytes
11569 * are the fourcc, the next 1 byte is the version, and the
11570 * subsequent bytes are sequence parameter set like data. */
11571 gst_codec_utils_h265_caps_set_level_tier_and_profile
11572 (entry->caps, hevc_data + 8 + 1, size - 1);
11573
11574 buf = gst_buffer_new_and_alloc (size);
11575 gst_buffer_fill (buf, 0, hevc_data + 0x8, size);
11576 gst_caps_set_simple (entry->caps,
11577 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11578 gst_buffer_unref (buf);
11579 break;
11580 }
11581 default:
11582 break;
11583 }
11584 len -= size + 8;
11585 hevc_data += size + 8;
11586 }
11587 break;
11588 }
11589 case FOURCC_mp4v:
11590 case FOURCC_MP4V:
11591 case FOURCC_fmp4:
11592 case FOURCC_FMP4:
11593 case FOURCC_xvid:
11594 case FOURCC_XVID:
11595 {
11596 GNode *glbl;
11597
11598 GST_DEBUG_OBJECT (qtdemux, "found %" GST_FOURCC_FORMAT,
11599 GST_FOURCC_ARGS (fourcc));
11600
11601 /* codec data might be in glbl extension atom */
11602 glbl = mp4v ?
11603 qtdemux_tree_get_child_by_type (mp4v, FOURCC_glbl) : NULL;
11604 if (glbl) {
11605 guint8 *data;
11606 GstBuffer *buf;
11607 gint len;
11608
11609 GST_DEBUG_OBJECT (qtdemux, "found glbl data in stsd");
11610 data = glbl->data;
11611 len = QT_UINT32 (data);
11612 if (len > 0x8) {
11613 len -= 0x8;
11614 buf = gst_buffer_new_and_alloc (len);
11615 gst_buffer_fill (buf, 0, data + 8, len);
11616 gst_caps_set_simple (entry->caps,
11617 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11618 gst_buffer_unref (buf);
11619 }
11620 }
11621 break;
11622 }
11623 case FOURCC_mjp2:
11624 {
11625 /* see annex I of the jpeg2000 spec */
11626 GNode *jp2h, *ihdr, *colr, *mjp2, *field, *prefix, *cmap, *cdef;
11627 const guint8 *data;
11628 const gchar *colorspace = NULL;
11629 gint ncomp = 0;
11630 guint32 ncomp_map = 0;
11631 gint32 *comp_map = NULL;
11632 guint32 nchan_def = 0;
11633 gint32 *chan_def = NULL;
11634
11635 GST_DEBUG_OBJECT (qtdemux, "found mjp2");
11636 /* some required atoms */
11637 mjp2 = qtdemux_tree_get_child_by_index (stsd, stsd_index);
11638 if (!mjp2)
11639 break;
11640 jp2h = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2h);
11641 if (!jp2h)
11642 break;
11643
11644 /* number of components; redundant with info in codestream, but useful
11645 to a muxer */
11646 ihdr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_ihdr);
11647 if (!ihdr || QT_UINT32 (ihdr->data) != 22)
11648 break;
11649 ncomp = QT_UINT16 (((guint8 *) ihdr->data) + 16);
11650
11651 colr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_colr);
11652 if (!colr)
11653 break;
11654 GST_DEBUG_OBJECT (qtdemux, "found colr");
11655 /* extract colour space info */
11656 if (QT_UINT8 ((guint8 *) colr->data + 8) == 1) {
11657 switch (QT_UINT32 ((guint8 *) colr->data + 11)) {
11658 case 16:
11659 colorspace = "sRGB";
11660 break;
11661 case 17:
11662 colorspace = "GRAY";
11663 break;
11664 case 18:
11665 colorspace = "sYUV";
11666 break;
11667 default:
11668 colorspace = NULL;
11669 break;
11670 }
11671 }
11672 if (!colorspace)
11673 /* colr is required, and only values 16, 17, and 18 are specified,
11674 so error if we have no colorspace */
11675 break;
11676
11677 /* extract component mapping */
11678 cmap = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cmap);
11679 if (cmap) {
11680 guint32 cmap_len = 0;
11681 int i;
11682 cmap_len = QT_UINT32 (cmap->data);
11683 if (cmap_len >= 8) {
11684 /* normal box, subtract off header */
11685 cmap_len -= 8;
11686 /* cmap: { u16 cmp; u8 mtyp; u8 pcol; }* */
11687 if (cmap_len % 4 == 0) {
11688 ncomp_map = (cmap_len / 4);
11689 comp_map = g_new0 (gint32, ncomp_map);
11690 for (i = 0; i < ncomp_map; i++) {
11691 guint16 cmp;
11692 guint8 mtyp, pcol;
11693 cmp = QT_UINT16 (((guint8 *) cmap->data) + 8 + i * 4);
11694 mtyp = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 2);
11695 pcol = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 3);
11696 comp_map[i] = (mtyp << 24) | (pcol << 16) | cmp;
11697 }
11698 }
11699 }
11700 }
11701 /* extract channel definitions */
11702 cdef = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cdef);
11703 if (cdef) {
11704 guint32 cdef_len = 0;
11705 int i;
11706 cdef_len = QT_UINT32 (cdef->data);
11707 if (cdef_len >= 10) {
11708 /* normal box, subtract off header and len */
11709 cdef_len -= 10;
11710 /* cdef: u16 n; { u16 cn; u16 typ; u16 asoc; }* */
11711 if (cdef_len % 6 == 0) {
11712 nchan_def = (cdef_len / 6);
11713 chan_def = g_new0 (gint32, nchan_def);
11714 for (i = 0; i < nchan_def; i++)
11715 chan_def[i] = -1;
11716 for (i = 0; i < nchan_def; i++) {
11717 guint16 cn, typ, asoc;
11718 cn = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6);
11719 typ = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 2);
11720 asoc = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 4);
11721 if (cn < nchan_def) {
11722 switch (typ) {
11723 case 0:
11724 chan_def[cn] = asoc;
11725 break;
11726 case 1:
11727 chan_def[cn] = 0; /* alpha */
11728 break;
11729 default:
11730 chan_def[cn] = -typ;
11731 }
11732 }
11733 }
11734 }
11735 }
11736 }
11737
11738 gst_caps_set_simple (entry->caps,
11739 "num-components", G_TYPE_INT, ncomp, NULL);
11740 gst_caps_set_simple (entry->caps,
11741 "colorspace", G_TYPE_STRING, colorspace, NULL);
11742
11743 if (comp_map) {
11744 GValue arr = { 0, };
11745 GValue elt = { 0, };
11746 int i;
11747 g_value_init (&arr, GST_TYPE_ARRAY);
11748 g_value_init (&elt, G_TYPE_INT);
11749 for (i = 0; i < ncomp_map; i++) {
11750 g_value_set_int (&elt, comp_map[i]);
11751 gst_value_array_append_value (&arr, &elt);
11752 }
11753 gst_structure_set_value (gst_caps_get_structure (entry->caps, 0),
11754 "component-map", &arr);
11755 g_value_unset (&elt);
11756 g_value_unset (&arr);
11757 g_free (comp_map);
11758 }
11759
11760 if (chan_def) {
11761 GValue arr = { 0, };
11762 GValue elt = { 0, };
11763 int i;
11764 g_value_init (&arr, GST_TYPE_ARRAY);
11765 g_value_init (&elt, G_TYPE_INT);
11766 for (i = 0; i < nchan_def; i++) {
11767 g_value_set_int (&elt, chan_def[i]);
11768 gst_value_array_append_value (&arr, &elt);
11769 }
11770 gst_structure_set_value (gst_caps_get_structure (entry->caps, 0),
11771 "channel-definitions", &arr);
11772 g_value_unset (&elt);
11773 g_value_unset (&arr);
11774 g_free (chan_def);
11775 }
11776
11777 /* some optional atoms */
11778 field = qtdemux_tree_get_child_by_type (mjp2, FOURCC_fiel);
11779 prefix = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2x);
11780
11781 /* indicate possible fields in caps */
11782 if (field) {
11783 data = (guint8 *) field->data + 8;
11784 if (*data != 1)
11785 gst_caps_set_simple (entry->caps, "fields", G_TYPE_INT,
11786 (gint) * data, NULL);
11787 }
11788 /* add codec_data if provided */
11789 if (prefix) {
11790 GstBuffer *buf;
11791 gint len;
11792
11793 GST_DEBUG_OBJECT (qtdemux, "found prefix data in stsd");
11794 data = prefix->data;
11795 len = QT_UINT32 (data);
11796 if (len > 0x8) {
11797 len -= 0x8;
11798 buf = gst_buffer_new_and_alloc (len);
11799 gst_buffer_fill (buf, 0, data + 8, len);
11800 gst_caps_set_simple (entry->caps,
11801 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11802 gst_buffer_unref (buf);
11803 }
11804 }
11805 break;
11806 }
11807 case FOURCC_SVQ3:
11808 case FOURCC_VP31:
11809 {
11810 GstBuffer *buf;
11811 GstBuffer *seqh = NULL;
11812 const guint8 *gamma_data = NULL;
11813 gint len = QT_UINT32 (stsd_data); /* FIXME review - why put the whole stsd in codec data? */
11814
11815 qtdemux_parse_svq3_stsd_data (qtdemux, stsd_entry_data, &gamma_data,
11816 &seqh);
11817 if (gamma_data) {
11818 gst_caps_set_simple (entry->caps, "applied-gamma", G_TYPE_DOUBLE,
11819 QT_FP32 (gamma_data), NULL);
11820 }
11821 if (seqh) {
11822 /* sorry for the bad name, but we don't know what this is, other
11823 * than its own fourcc */
11824 gst_caps_set_simple (entry->caps, "seqh", GST_TYPE_BUFFER, seqh,
11825 NULL);
11826 gst_buffer_unref (seqh);
11827 }
11828
11829 GST_DEBUG_OBJECT (qtdemux, "found codec_data in stsd");
11830 buf = gst_buffer_new_and_alloc (len);
11831 gst_buffer_fill (buf, 0, stsd_data, len);
11832 gst_caps_set_simple (entry->caps,
11833 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11834 gst_buffer_unref (buf);
11835 break;
11836 }
11837 case FOURCC_jpeg:
11838 {
11839 /* https://developer.apple.com/standards/qtff-2001.pdf,
11840 * page 92, "Video Sample Description", under table 3.1 */
11841 GstByteReader br;
11842
11843 const gint compressor_offset =
11844 16 + 4 + 4 * 3 + 2 * 2 + 2 * 4 + 4 + 2;
11845 const gint min_size = compressor_offset + 32 + 2 + 2;
11846 GNode *jpeg;
11847 guint32 len;
11848 guint16 color_table_id = 0;
11849 gboolean ok;
11850
11851 GST_DEBUG_OBJECT (qtdemux, "found jpeg");
11852
11853 /* recover information on interlaced/progressive */
11854 jpeg = qtdemux_tree_get_child_by_type (stsd, FOURCC_jpeg);
11855 if (!jpeg)
11856 break;
11857
11858 len = QT_UINT32 (jpeg->data);
11859 GST_DEBUG_OBJECT (qtdemux, "Found jpeg: len %u, need %d", len,
11860 min_size);
11861 if (len >= min_size) {
11862 gst_byte_reader_init (&br, jpeg->data, len);
11863
11864 gst_byte_reader_skip (&br, compressor_offset + 32 + 2);
11865 gst_byte_reader_get_uint16_le (&br, &color_table_id);
11866 if (color_table_id != 0) {
11867 /* the spec says there can be concatenated chunks in the data, and we want
11868 * to find one called field. Walk through them. */
11869 gint offset = min_size;
11870 while (offset + 8 < len) {
11871 guint32 size = 0, tag;
11872 ok = gst_byte_reader_get_uint32_le (&br, &size);
11873 ok &= gst_byte_reader_get_uint32_le (&br, &tag);
11874 if (!ok || size < 8) {
11875 GST_WARNING_OBJECT (qtdemux,
11876 "Failed to walk optional chunk list");
11877 break;
11878 }
11879 GST_DEBUG_OBJECT (qtdemux,
11880 "Found optional %4.4s chunk, size %u",
11881 (const char *) &tag, size);
11882 if (tag == FOURCC_fiel) {
11883 guint8 n_fields = 0, ordering = 0;
11884 gst_byte_reader_get_uint8 (&br, &n_fields);
11885 gst_byte_reader_get_uint8 (&br, &ordering);
11886 if (n_fields == 1 || n_fields == 2) {
11887 GST_DEBUG_OBJECT (qtdemux,
11888 "Found fiel tag with %u fields, ordering %u",
11889 n_fields, ordering);
11890 if (n_fields == 2)
11891 gst_caps_set_simple (CUR_STREAM (stream)->caps,
11892 "interlace-mode", G_TYPE_STRING, "interleaved",
11893 NULL);
11894 } else {
11895 GST_WARNING_OBJECT (qtdemux,
11896 "Found fiel tag with invalid fields (%u)", n_fields);
11897 }
11898 }
11899 offset += size;
11900 }
11901 } else {
11902 GST_DEBUG_OBJECT (qtdemux,
11903 "Color table ID is 0, not trying to get interlacedness");
11904 }
11905 } else {
11906 GST_WARNING_OBJECT (qtdemux,
11907 "Length of jpeg chunk is too small, not trying to get interlacedness");
11908 }
11909
11910 break;
11911 }
11912 case FOURCC_rle_:
11913 case FOURCC_WRLE:
11914 {
11915 gst_caps_set_simple (entry->caps,
11916 "depth", G_TYPE_INT, QT_UINT16 (stsd_entry_data + offset + 66),
11917 NULL);
11918 break;
11919 }
11920 case FOURCC_XiTh:
11921 {
11922 GNode *xith, *xdxt;
11923
11924 GST_DEBUG_OBJECT (qtdemux, "found XiTh");
11925 xith = qtdemux_tree_get_child_by_index (stsd, stsd_index);
11926 if (!xith)
11927 break;
11928
11929 xdxt = qtdemux_tree_get_child_by_type (xith, FOURCC_XdxT);
11930 if (!xdxt)
11931 break;
11932
11933 GST_DEBUG_OBJECT (qtdemux, "found XdxT node");
11934 /* collect the headers and store them in a stream list so that we can
11935 * send them out first */
11936 qtdemux_parse_theora_extension (qtdemux, stream, xdxt);
11937 break;
11938 }
11939 case FOURCC_ovc1:
11940 {
11941 GNode *ovc1;
11942 guint8 *ovc1_data;
11943 guint ovc1_len;
11944 GstBuffer *buf;
11945
11946 GST_DEBUG_OBJECT (qtdemux, "parse ovc1 header");
11947 ovc1 = qtdemux_tree_get_child_by_index (stsd, stsd_index);
11948 if (!ovc1)
11949 break;
11950 ovc1_data = ovc1->data;
11951 ovc1_len = QT_UINT32 (ovc1_data);
11952 if (ovc1_len <= 198) {
11953 GST_WARNING_OBJECT (qtdemux, "Too small ovc1 header, skipping");
11954 break;
11955 }
11956 buf = gst_buffer_new_and_alloc (ovc1_len - 198);
11957 gst_buffer_fill (buf, 0, ovc1_data + 198, ovc1_len - 198);
11958 gst_caps_set_simple (entry->caps,
11959 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11960 gst_buffer_unref (buf);
11961 break;
11962 }
11963 case FOURCC_vc_1:
11964 {
11965 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
11966 const guint8 *vc1_data = stsd_entry_data + 0x56;
11967
11968 /* find dvc1 */
11969 while (len >= 8) {
11970 gint size;
11971
11972 if (QT_UINT32 (vc1_data) <= len)
11973 size = QT_UINT32 (vc1_data) - 8;
11974 else
11975 size = len - 8;
11976
11977 if (size < 1)
11978 /* No real data, so break out */
11979 break;
11980
11981 switch (QT_FOURCC (vc1_data + 0x4)) {
11982 case GST_MAKE_FOURCC ('d', 'v', 'c', '1'):
11983 {
11984 GstBuffer *buf;
11985
11986 GST_DEBUG_OBJECT (qtdemux, "found dvc1 codec_data in stsd");
11987 buf = gst_buffer_new_and_alloc (size);
11988 gst_buffer_fill (buf, 0, vc1_data + 8, size);
11989 gst_caps_set_simple (entry->caps,
11990 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11991 gst_buffer_unref (buf);
11992 break;
11993 }
11994 default:
11995 break;
11996 }
11997 len -= size + 8;
11998 vc1_data += size + 8;
11999 }
12000 break;
12001 }
12002 case FOURCC_av01:
12003 {
12004 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
12005 const guint8 *av1_data = stsd_entry_data + 0x56;
12006
12007 /* find av1C */
12008 while (len >= 0x8) {
12009 gint size;
12010
12011 if (QT_UINT32 (av1_data) <= len)
12012 size = QT_UINT32 (av1_data) - 0x8;
12013 else
12014 size = len - 0x8;
12015
12016 if (size < 1)
12017 /* No real data, so break out */
12018 break;
12019
12020 switch (QT_FOURCC (av1_data + 0x4)) {
12021 case FOURCC_av1C:
12022 {
12023 /* parse, if found */
12024 GstBuffer *buf;
12025 guint8 pres_delay_field;
12026
12027 GST_DEBUG_OBJECT (qtdemux,
12028 "found av1C codec_data in stsd of size %d", size);
12029
12030 /* not enough data, just ignore and hope for the best */
12031 if (size < 5)
12032 break;
12033
12034 /* Content is:
12035 * 4 bytes: atom length
12036 * 4 bytes: fourcc
12037 * 1 byte: version
12038 * 3 bytes: flags
12039 * 3 bits: reserved
12040 * 1 bits: initial_presentation_delay_present
12041 * 4 bits: initial_presentation_delay (if present else reserved
12042 * rest: OBUs.
12043 */
12044
12045 if (av1_data[9] != 0) {
12046 GST_WARNING ("Unknown version %d of av1C box", av1_data[9]);
12047 break;
12048 }
12049
12050 /* We skip initial_presentation_delay* for now */
12051 pres_delay_field = *(av1_data + 12);
12052 if (pres_delay_field & (1 << 5)) {
12053 gst_caps_set_simple (entry->caps,
12054 "presentation-delay", G_TYPE_INT,
12055 (gint) (pres_delay_field & 0x0F) + 1, NULL);
12056 }
12057 if (size > 5) {
12058 buf = gst_buffer_new_and_alloc (size - 5);
12059 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_HEADER);
12060 gst_buffer_fill (buf, 0, av1_data + 13, size - 5);
12061 gst_caps_set_simple (entry->caps,
12062 "codec_data", GST_TYPE_BUFFER, buf, NULL);
12063 gst_buffer_unref (buf);
12064 }
12065 break;
12066 }
12067 default:
12068 break;
12069 }
12070
12071 len -= size + 8;
12072 av1_data += size + 8;
12073 }
12074
12075 break;
12076 }
12077
12078 /* TODO: Need to parse vpcC for VP8 codec too.
12079 * Note that VPCodecConfigurationBox (vpcC) is defined for
12080 * vp08, vp09, and vp10 fourcc. */
12081 case FOURCC_vp09:
12082 {
12083 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
12084 const guint8 *vpcc_data = stsd_entry_data + 0x56;
12085
12086 /* find vpcC */
12087 while (len >= 0x8) {
12088 gint size;
12089
12090 if (QT_UINT32 (vpcc_data) <= len)
12091 size = QT_UINT32 (vpcc_data) - 0x8;
12092 else
12093 size = len - 0x8;
12094
12095 if (size < 1)
12096 /* No real data, so break out */
12097 break;
12098
12099 switch (QT_FOURCC (vpcc_data + 0x4)) {
12100 case FOURCC_vpcC:
12101 {
12102 const gchar *profile_str = NULL;
12103 const gchar *chroma_format_str = NULL;
12104 guint8 profile;
12105 guint8 bitdepth;
12106 guint8 chroma_format;
12107 GstVideoColorimetry cinfo;
12108
12109 /* parse, if found */
12110 GST_DEBUG_OBJECT (qtdemux,
12111 "found vp codec_data in stsd of size %d", size);
12112
12113 /* the meaning of "size" is length of the atom body, excluding
12114 * atom length and fourcc fields */
12115 if (size < 12)
12116 break;
12117
12118 /* Content is:
12119 * 4 bytes: atom length
12120 * 4 bytes: fourcc
12121 * 1 byte: version
12122 * 3 bytes: flags
12123 * 1 byte: profile
12124 * 1 byte: level
12125 * 4 bits: bitDepth
12126 * 3 bits: chromaSubsampling
12127 * 1 bit: videoFullRangeFlag
12128 * 1 byte: colourPrimaries
12129 * 1 byte: transferCharacteristics
12130 * 1 byte: matrixCoefficients
12131 * 2 bytes: codecIntializationDataSize (should be zero for vp8 and vp9)
12132 * rest: codecIntializationData (not used for vp8 and vp9)
12133 */
12134
12135 if (vpcc_data[8] != 1) {
12136 GST_WARNING_OBJECT (qtdemux,
12137 "unknown vpcC version %d", vpcc_data[8]);
12138 break;
12139 }
12140
12141 profile = vpcc_data[12];
12142 switch (profile) {
12143 case 0:
12144 profile_str = "0";
12145 break;
12146 case 1:
12147 profile_str = "1";
12148 break;
12149 case 2:
12150 profile_str = "2";
12151 break;
12152 case 3:
12153 profile_str = "3";
12154 break;
12155 default:
12156 break;
12157 }
12158
12159 if (profile_str) {
12160 gst_caps_set_simple (entry->caps,
12161 "profile", G_TYPE_STRING, profile_str, NULL);
12162 }
12163
12164 /* skip level, the VP9 spec v0.6 defines only one level atm,
12165 * but webm spec define various ones. Add level to caps
12166 * if we really need it then */
12167
12168 bitdepth = (vpcc_data[14] & 0xf0) >> 4;
12169 if (bitdepth == 8 || bitdepth == 10 || bitdepth == 12) {
12170 gst_caps_set_simple (entry->caps,
12171 "bit-depth-luma", G_TYPE_UINT, bitdepth,
12172 "bit-depth-chroma", G_TYPE_UINT, bitdepth, NULL);
12173 }
12174
12175 chroma_format = (vpcc_data[14] & 0xe) >> 1;
12176 switch (chroma_format) {
12177 case 0:
12178 case 1:
12179 chroma_format_str = "4:2:0";
12180 break;
12181 case 2:
12182 chroma_format_str = "4:2:2";
12183 break;
12184 case 3:
12185 chroma_format_str = "4:4:4";
12186 break;
12187 default:
12188 break;
12189 }
12190
12191 if (chroma_format_str) {
12192 gst_caps_set_simple (entry->caps,
12193 "chroma-format", G_TYPE_STRING, chroma_format_str,
12194 NULL);
12195 }
12196
12197 if ((vpcc_data[14] & 0x1) != 0)
12198 cinfo.range = GST_VIDEO_COLOR_RANGE_0_255;
12199 else
12200 cinfo.range = GST_VIDEO_COLOR_RANGE_16_235;
12201 cinfo.primaries =
12202 gst_video_color_primaries_from_iso (vpcc_data[15]);
12203 cinfo.transfer =
12204 gst_video_transfer_function_from_iso (vpcc_data[16]);
12205 cinfo.matrix =
12206 gst_video_color_matrix_from_iso (vpcc_data[17]);
12207
12208 if (cinfo.primaries != GST_VIDEO_COLOR_PRIMARIES_UNKNOWN &&
12209 cinfo.transfer != GST_VIDEO_TRANSFER_UNKNOWN &&
12210 cinfo.matrix != GST_VIDEO_COLOR_MATRIX_UNKNOWN) {
12211 /* set this only if all values are known, otherwise this
12212 * might overwrite valid ones parsed from other color box */
12213 CUR_STREAM (stream)->colorimetry = cinfo;
12214 }
12215 break;
12216 }
12217 default:
12218 break;
12219 }
12220
12221 len -= size + 8;
12222 vpcc_data += size + 8;
12223 }
12224
12225 break;
12226 }
12227 default:
12228 break;
12229 }
12230 }
12231
12232 GST_INFO_OBJECT (qtdemux,
12233 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
12234 GST_FOURCC_ARGS (fourcc), entry->caps);
12235
12236 } else if (stream->subtype == FOURCC_soun) {
12237 GNode *wave;
12238 int version, samplesize;
12239 guint16 compression_id;
12240 gboolean amrwb = FALSE;
12241
12242 offset = 16;
12243 /* sample description entry (16) + sound sample description v0 (20) */
12244 if (len < 36)
12245 goto corrupt_file;
12246
12247 version = QT_UINT32 (stsd_entry_data + offset);
12248 entry->n_channels = QT_UINT16 (stsd_entry_data + offset + 8);
12249 samplesize = QT_UINT16 (stsd_entry_data + offset + 10);
12250 compression_id = QT_UINT16 (stsd_entry_data + offset + 12);
12251 entry->rate = QT_FP32 (stsd_entry_data + offset + 16);
12252
12253 GST_LOG_OBJECT (qtdemux, "version/rev: %08x", version);
12254 GST_LOG_OBJECT (qtdemux, "vendor: %08x",
12255 QT_UINT32 (stsd_entry_data + offset + 4));
12256 GST_LOG_OBJECT (qtdemux, "n_channels: %d", entry->n_channels);
12257 GST_LOG_OBJECT (qtdemux, "sample_size: %d", samplesize);
12258 GST_LOG_OBJECT (qtdemux, "compression_id: %d", compression_id);
12259 GST_LOG_OBJECT (qtdemux, "packet size: %d",
12260 QT_UINT16 (stsd_entry_data + offset + 14));
12261 GST_LOG_OBJECT (qtdemux, "sample rate: %g", entry->rate);
12262
12263 if (compression_id == 0xfffe)
12264 entry->sampled = TRUE;
12265
12266 /* first assume uncompressed audio */
12267 entry->bytes_per_sample = samplesize / 8;
12268 entry->samples_per_frame = entry->n_channels;
12269 entry->bytes_per_frame = entry->n_channels * entry->bytes_per_sample;
12270 entry->samples_per_packet = entry->samples_per_frame;
12271 entry->bytes_per_packet = entry->bytes_per_sample;
12272
12273 offset = 36;
12274
12275 if (version == 0x00010000) {
12276 /* sample description entry (16) + sound sample description v1 (20+16) */
12277 if (len < 52)
12278 goto corrupt_file;
12279
12280 /* take information from here over the normal sample description */
12281 entry->samples_per_packet = QT_UINT32 (stsd_entry_data + offset);
12282 entry->bytes_per_packet = QT_UINT32 (stsd_entry_data + offset + 4);
12283 entry->bytes_per_frame = QT_UINT32 (stsd_entry_data + offset + 8);
12284 entry->bytes_per_sample = QT_UINT32 (stsd_entry_data + offset + 12);
12285
12286 GST_LOG_OBJECT (qtdemux, "Sound sample description Version 1");
12287 GST_LOG_OBJECT (qtdemux, "samples/packet: %d",
12288 entry->samples_per_packet);
12289 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
12290 entry->bytes_per_packet);
12291 GST_LOG_OBJECT (qtdemux, "bytes/frame: %d",
12292 entry->bytes_per_frame);
12293 GST_LOG_OBJECT (qtdemux, "bytes/sample: %d",
12294 entry->bytes_per_sample);
12295
12296 if (!entry->sampled && entry->bytes_per_packet) {
12297 entry->samples_per_frame = (entry->bytes_per_frame /
12298 entry->bytes_per_packet) * entry->samples_per_packet;
12299 GST_LOG_OBJECT (qtdemux, "samples/frame: %d",
12300 entry->samples_per_frame);
12301 }
12302 } else if (version == 0x00020000) {
12303 /* sample description entry (16) + sound sample description v2 (56) */
12304 if (len < 72)
12305 goto corrupt_file;
12306
12307 /* take information from here over the normal sample description */
12308 entry->rate = GST_READ_DOUBLE_BE (stsd_entry_data + offset + 4);
12309 entry->n_channels = QT_UINT32 (stsd_entry_data + offset + 12);
12310 entry->samples_per_frame = entry->n_channels;
12311 entry->bytes_per_sample = QT_UINT32 (stsd_entry_data + offset + 20) / 8;
12312 entry->bytes_per_packet = QT_UINT32 (stsd_entry_data + offset + 28);
12313 entry->samples_per_packet = QT_UINT32 (stsd_entry_data + offset + 32);
12314 entry->bytes_per_frame = entry->bytes_per_sample * entry->n_channels;
12315
12316 GST_LOG_OBJECT (qtdemux, "Sound sample description Version 2");
12317 GST_LOG_OBJECT (qtdemux, "sample rate: %g", entry->rate);
12318 GST_LOG_OBJECT (qtdemux, "n_channels: %d", entry->n_channels);
12319 GST_LOG_OBJECT (qtdemux, "bits/channel: %d",
12320 entry->bytes_per_sample * 8);
12321 GST_LOG_OBJECT (qtdemux, "format flags: %X",
12322 QT_UINT32 (stsd_entry_data + offset + 24));
12323 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
12324 entry->bytes_per_packet);
12325 GST_LOG_OBJECT (qtdemux, "LPCM frames/packet: %d",
12326 entry->samples_per_packet);
12327 } else if (version != 0x00000) {
12328 GST_WARNING_OBJECT (qtdemux, "unknown audio STSD version %08x",
12329 version);
12330 }
12331
12332 switch (fourcc) {
12333 /* Yes, these have to be hard-coded */
12334 case FOURCC_MAC6:
12335 {
12336 entry->samples_per_packet = 6;
12337 entry->bytes_per_packet = 1;
12338 entry->bytes_per_frame = 1 * entry->n_channels;
12339 entry->bytes_per_sample = 1;
12340 entry->samples_per_frame = 6 * entry->n_channels;
12341 break;
12342 }
12343 case FOURCC_MAC3:
12344 {
12345 entry->samples_per_packet = 3;
12346 entry->bytes_per_packet = 1;
12347 entry->bytes_per_frame = 1 * entry->n_channels;
12348 entry->bytes_per_sample = 1;
12349 entry->samples_per_frame = 3 * entry->n_channels;
12350 break;
12351 }
12352 case FOURCC_ima4:
12353 {
12354 entry->samples_per_packet = 64;
12355 entry->bytes_per_packet = 34;
12356 entry->bytes_per_frame = 34 * entry->n_channels;
12357 entry->bytes_per_sample = 2;
12358 entry->samples_per_frame = 64 * entry->n_channels;
12359 break;
12360 }
12361 case FOURCC_ulaw:
12362 case FOURCC_alaw:
12363 {
12364 entry->samples_per_packet = 1;
12365 entry->bytes_per_packet = 1;
12366 entry->bytes_per_frame = 1 * entry->n_channels;
12367 entry->bytes_per_sample = 1;
12368 entry->samples_per_frame = 1 * entry->n_channels;
12369 break;
12370 }
12371 case FOURCC_agsm:
12372 {
12373 entry->samples_per_packet = 160;
12374 entry->bytes_per_packet = 33;
12375 entry->bytes_per_frame = 33 * entry->n_channels;
12376 entry->bytes_per_sample = 2;
12377 entry->samples_per_frame = 160 * entry->n_channels;
12378 break;
12379 }
12380 /* fix up any invalid header information from above */
12381 case FOURCC_twos:
12382 case FOURCC_sowt:
12383 case FOURCC_raw_:
12384 case FOURCC_lpcm:
12385 /* Sometimes these are set to 0 in the sound sample descriptions so
12386 * let's try to infer useful values from the other information we
12387 * have available */
12388 if (entry->bytes_per_sample == 0)
12389 entry->bytes_per_sample =
12390 entry->bytes_per_frame / entry->n_channels;
12391 if (entry->bytes_per_sample == 0)
12392 entry->bytes_per_sample = samplesize / 8;
12393
12394 if (entry->bytes_per_frame == 0)
12395 entry->bytes_per_frame =
12396 entry->bytes_per_sample * entry->n_channels;
12397
12398 if (entry->bytes_per_packet == 0)
12399 entry->bytes_per_packet = entry->bytes_per_sample;
12400
12401 if (entry->samples_per_frame == 0)
12402 entry->samples_per_frame = entry->n_channels;
12403
12404 if (entry->samples_per_packet == 0)
12405 entry->samples_per_packet = entry->samples_per_frame;
12406
12407 break;
12408 case FOURCC_in24:
12409 case FOURCC_in32:
12410 case FOURCC_fl32:
12411 case FOURCC_fl64:
12412 case FOURCC_s16l:{
12413 switch (fourcc) {
12414 case FOURCC_in24:
12415 entry->bytes_per_sample = 3;
12416 break;
12417 case FOURCC_in32:
12418 case FOURCC_fl32:
12419 entry->bytes_per_sample = 4;
12420 break;
12421 case FOURCC_fl64:
12422 entry->bytes_per_sample = 8;
12423 break;
12424 case FOURCC_s16l:
12425 entry->bytes_per_sample = 2;
12426 break;
12427 default:
12428 g_assert_not_reached ();
12429 break;
12430 }
12431 entry->samples_per_frame = entry->n_channels;
12432 entry->bytes_per_frame = entry->n_channels * entry->bytes_per_sample;
12433 entry->samples_per_packet = entry->samples_per_frame;
12434 entry->bytes_per_packet = entry->bytes_per_sample;
12435 break;
12436 }
12437 default:
12438 break;
12439 }
12440
12441 if (entry->caps)
12442 gst_caps_unref (entry->caps);
12443
12444 entry->caps = qtdemux_audio_caps (qtdemux, stream, entry, fourcc,
12445 stsd_entry_data + 32, len - 16, &codec);
12446
12447 switch (fourcc) {
12448 case FOURCC_in24:
12449 case FOURCC_in32:
12450 case FOURCC_fl32:
12451 case FOURCC_fl64:
12452 {
12453 GNode *enda;
12454 GNode *fmt;
12455
12456 fmt = qtdemux_tree_get_child_by_type (stsd, fourcc);
12457
12458 enda = qtdemux_tree_get_child_by_type (fmt, FOURCC_enda);
12459 if (!enda) {
12460 wave = qtdemux_tree_get_child_by_type (fmt, FOURCC_wave);
12461 if (wave)
12462 enda = qtdemux_tree_get_child_by_type (wave, FOURCC_enda);
12463 }
12464 if (enda) {
12465 int enda_value = QT_UINT16 ((guint8 *) enda->data + 8);
12466 const gchar *format_str;
12467
12468 switch (fourcc) {
12469 case FOURCC_in24:
12470 format_str = (enda_value) ? "S24LE" : "S24BE";
12471 break;
12472 case FOURCC_in32:
12473 format_str = (enda_value) ? "S32LE" : "S32BE";
12474 break;
12475 case FOURCC_fl32:
12476 format_str = (enda_value) ? "F32LE" : "F32BE";
12477 break;
12478 case FOURCC_fl64:
12479 format_str = (enda_value) ? "F64LE" : "F64BE";
12480 break;
12481 default:
12482 g_assert_not_reached ();
12483 break;
12484 }
12485 gst_caps_set_simple (entry->caps,
12486 "format", G_TYPE_STRING, format_str, NULL);
12487 }
12488 break;
12489 }
12490 case FOURCC_owma:
12491 {
12492 const guint8 *owma_data;
12493 const gchar *codec_name = NULL;
12494 guint owma_len;
12495 GstBuffer *buf;
12496 gint version = 1;
12497 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
12498 /* FIXME this should also be gst_riff_strf_auds,
12499 * but the latter one is actually missing bits-per-sample :( */
12500 typedef struct
12501 {
12502 gint16 wFormatTag;
12503 gint16 nChannels;
12504 gint32 nSamplesPerSec;
12505 gint32 nAvgBytesPerSec;
12506 gint16 nBlockAlign;
12507 gint16 wBitsPerSample;
12508 gint16 cbSize;
12509 } WAVEFORMATEX;
12510 WAVEFORMATEX *wfex;
12511
12512 GST_DEBUG_OBJECT (qtdemux, "parse owma");
12513 owma_data = stsd_entry_data;
12514 owma_len = QT_UINT32 (owma_data);
12515 if (owma_len <= 54) {
12516 GST_WARNING_OBJECT (qtdemux, "Too small owma header, skipping");
12517 break;
12518 }
12519 wfex = (WAVEFORMATEX *) (owma_data + 36);
12520 buf = gst_buffer_new_and_alloc (owma_len - 54);
12521 gst_buffer_fill (buf, 0, owma_data + 54, owma_len - 54);
12522 if (wfex->wFormatTag == 0x0161) {
12523 codec_name = "Windows Media Audio";
12524 version = 2;
12525 } else if (wfex->wFormatTag == 0x0162) {
12526 codec_name = "Windows Media Audio 9 Pro";
12527 version = 3;
12528 } else if (wfex->wFormatTag == 0x0163) {
12529 codec_name = "Windows Media Audio 9 Lossless";
12530 /* is that correct? gstffmpegcodecmap.c is missing it, but
12531 * fluendo codec seems to support it */
12532 version = 4;
12533 }
12534
12535 gst_caps_set_simple (entry->caps,
12536 "codec_data", GST_TYPE_BUFFER, buf,
12537 "wmaversion", G_TYPE_INT, version,
12538 "block_align", G_TYPE_INT,
12539 GST_READ_UINT16_LE (&wfex->nBlockAlign), "bitrate", G_TYPE_INT,
12540 GST_READ_UINT32_LE (&wfex->nAvgBytesPerSec), "width", G_TYPE_INT,
12541 GST_READ_UINT16_LE (&wfex->wBitsPerSample), "depth", G_TYPE_INT,
12542 GST_READ_UINT16_LE (&wfex->wBitsPerSample), NULL);
12543 gst_buffer_unref (buf);
12544
12545 if (codec_name) {
12546 g_free (codec);
12547 codec = g_strdup (codec_name);
12548 }
12549 break;
12550 }
12551 case FOURCC_wma_:
12552 {
12553 gint len = QT_UINT32 (stsd_entry_data) - offset;
12554 const guint8 *wfex_data = stsd_entry_data + offset;
12555 const gchar *codec_name = NULL;
12556 gint version = 1;
12557 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
12558 /* FIXME this should also be gst_riff_strf_auds,
12559 * but the latter one is actually missing bits-per-sample :( */
12560 typedef struct
12561 {
12562 gint16 wFormatTag;
12563 gint16 nChannels;
12564 gint32 nSamplesPerSec;
12565 gint32 nAvgBytesPerSec;
12566 gint16 nBlockAlign;
12567 gint16 wBitsPerSample;
12568 gint16 cbSize;
12569 } WAVEFORMATEX;
12570 WAVEFORMATEX wfex;
12571
12572 /* FIXME: unify with similar wavformatex parsing code above */
12573 GST_DEBUG_OBJECT (qtdemux, "parse wma, looking for wfex");
12574
12575 /* find wfex */
12576 while (len >= 8) {
12577 gint size;
12578
12579 if (QT_UINT32 (wfex_data) <= len)
12580 size = QT_UINT32 (wfex_data) - 8;
12581 else
12582 size = len - 8;
12583
12584 if (size < 1)
12585 /* No real data, so break out */
12586 break;
12587
12588 switch (QT_FOURCC (wfex_data + 4)) {
12589 case GST_MAKE_FOURCC ('w', 'f', 'e', 'x'):
12590 {
12591 GST_DEBUG_OBJECT (qtdemux, "found wfex in stsd");
12592
12593 if (size < 8 + 18)
12594 break;
12595
12596 wfex.wFormatTag = GST_READ_UINT16_LE (wfex_data + 8 + 0);
12597 wfex.nChannels = GST_READ_UINT16_LE (wfex_data + 8 + 2);
12598 wfex.nSamplesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 4);
12599 wfex.nAvgBytesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 8);
12600 wfex.nBlockAlign = GST_READ_UINT16_LE (wfex_data + 8 + 12);
12601 wfex.wBitsPerSample = GST_READ_UINT16_LE (wfex_data + 8 + 14);
12602 wfex.cbSize = GST_READ_UINT16_LE (wfex_data + 8 + 16);
12603
12604 GST_LOG_OBJECT (qtdemux, "Found wfex box in stsd:");
12605 GST_LOG_OBJECT (qtdemux, "FormatTag = 0x%04x, Channels = %u, "
12606 "SamplesPerSec = %u, AvgBytesPerSec = %u, BlockAlign = %u, "
12607 "BitsPerSample = %u, Size = %u", wfex.wFormatTag,
12608 wfex.nChannels, wfex.nSamplesPerSec, wfex.nAvgBytesPerSec,
12609 wfex.nBlockAlign, wfex.wBitsPerSample, wfex.cbSize);
12610
12611 if (wfex.wFormatTag == 0x0161) {
12612 codec_name = "Windows Media Audio";
12613 version = 2;
12614 } else if (wfex.wFormatTag == 0x0162) {
12615 codec_name = "Windows Media Audio 9 Pro";
12616 version = 3;
12617 } else if (wfex.wFormatTag == 0x0163) {
12618 codec_name = "Windows Media Audio 9 Lossless";
12619 /* is that correct? gstffmpegcodecmap.c is missing it, but
12620 * fluendo codec seems to support it */
12621 version = 4;
12622 }
12623
12624 gst_caps_set_simple (entry->caps,
12625 "wmaversion", G_TYPE_INT, version,
12626 "block_align", G_TYPE_INT, wfex.nBlockAlign,
12627 "bitrate", G_TYPE_INT, wfex.nAvgBytesPerSec,
12628 "width", G_TYPE_INT, wfex.wBitsPerSample,
12629 "depth", G_TYPE_INT, wfex.wBitsPerSample, NULL);
12630
12631 if (size > wfex.cbSize) {
12632 GstBuffer *buf;
12633
12634 buf = gst_buffer_new_and_alloc (size - wfex.cbSize);
12635 gst_buffer_fill (buf, 0, wfex_data + 8 + wfex.cbSize,
12636 size - wfex.cbSize);
12637 gst_caps_set_simple (entry->caps,
12638 "codec_data", GST_TYPE_BUFFER, buf, NULL);
12639 gst_buffer_unref (buf);
12640 } else {
12641 GST_WARNING_OBJECT (qtdemux, "no codec data");
12642 }
12643
12644 if (codec_name) {
12645 g_free (codec);
12646 codec = g_strdup (codec_name);
12647 }
12648 break;
12649 }
12650 default:
12651 break;
12652 }
12653 len -= size + 8;
12654 wfex_data += size + 8;
12655 }
12656 break;
12657 }
12658 case FOURCC_opus:
12659 {
12660 const guint8 *dops_data;
12661 guint8 *channel_mapping = NULL;
12662 guint32 rate;
12663 guint8 channels;
12664 guint8 channel_mapping_family;
12665 guint8 stream_count;
12666 guint8 coupled_count;
12667 guint8 i;
12668
12669 version = GST_READ_UINT16_BE (stsd_entry_data + 16);
12670 if (version == 1)
12671 dops_data = stsd_entry_data + 51;
12672 else
12673 dops_data = stsd_entry_data + 35;
12674
12675 channels = GST_READ_UINT8 (dops_data + 10);
12676 rate = GST_READ_UINT32_LE (dops_data + 13);
12677 channel_mapping_family = GST_READ_UINT8 (dops_data + 19);
12678 stream_count = GST_READ_UINT8 (dops_data + 20);
12679 coupled_count = GST_READ_UINT8 (dops_data + 21);
12680
12681 if (channels > 0) {
12682 channel_mapping = g_malloc (channels * sizeof (guint8));
12683 for (i = 0; i < channels; i++)
12684 channel_mapping[i] = GST_READ_UINT8 (dops_data + i + 22);
12685 }
12686
12687 entry->caps = gst_codec_utils_opus_create_caps (rate, channels,
12688 channel_mapping_family, stream_count, coupled_count,
12689 channel_mapping);
12690 g_free (channel_mapping);
12691 break;
12692 }
12693 default:
12694 break;
12695 }
12696
12697 if (codec) {
12698 GstStructure *s;
12699 gint bitrate = 0;
12700
12701 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12702 GST_TAG_AUDIO_CODEC, codec, NULL);
12703 g_free (codec);
12704 codec = NULL;
12705
12706 /* some bitrate info may have ended up in caps */
12707 s = gst_caps_get_structure (entry->caps, 0);
12708 gst_structure_get_int (s, "bitrate", &bitrate);
12709 if (bitrate > 0)
12710 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12711 GST_TAG_BITRATE, bitrate, NULL);
12712 }
12713
12714 esds = NULL;
12715 mp4a = qtdemux_tree_get_child_by_index (stsd, stsd_index);
12716 if (QTDEMUX_TREE_NODE_FOURCC (mp4a) != fourcc) {
12717 if (stream->protected) {
12718 if (QTDEMUX_TREE_NODE_FOURCC (mp4a) == FOURCC_aavd) {
12719 esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
12720 }
12721 if (QTDEMUX_TREE_NODE_FOURCC (mp4a) != FOURCC_enca) {
12722 mp4a = NULL;
12723 }
12724 } else {
12725 mp4a = NULL;
12726 }
12727 }
12728
12729 wave = NULL;
12730 if (mp4a) {
12731 wave = qtdemux_tree_get_child_by_type (mp4a, FOURCC_wave);
12732 if (wave)
12733 esds = qtdemux_tree_get_child_by_type (wave, FOURCC_esds);
12734 if (!esds)
12735 esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
12736 }
12737
12738
12739 /* If the fourcc's bottom 16 bits gives 'sm', then the top
12740 16 bits is a byte-swapped wave-style codec identifier,
12741 and we can find a WAVE header internally to a 'wave' atom here.
12742 This can more clearly be thought of as 'ms' as the top 16 bits, and a
12743 codec id as the bottom 16 bits - but byte-swapped to store in QT (which
12744 is big-endian).
12745 */
12746 if ((fourcc & 0xffff) == (('s' << 8) | 'm')) {
12747 if (len < offset + 20) {
12748 GST_WARNING_OBJECT (qtdemux, "No wave atom in MS-style audio");
12749 } else {
12750 guint32 datalen = QT_UINT32 (stsd_entry_data + offset + 16);
12751 const guint8 *data = stsd_entry_data + offset + 16;
12752 GNode *wavenode;
12753 GNode *waveheadernode;
12754
12755 wavenode = g_node_new ((guint8 *) data);
12756 if (qtdemux_parse_node (qtdemux, wavenode, data, datalen)) {
12757 const guint8 *waveheader;
12758 guint32 headerlen;
12759
12760 waveheadernode = qtdemux_tree_get_child_by_type (wavenode, fourcc);
12761 if (waveheadernode) {
12762 waveheader = (const guint8 *) waveheadernode->data;
12763 headerlen = QT_UINT32 (waveheader);
12764
12765 if (headerlen > 8) {
12766 gst_riff_strf_auds *header = NULL;
12767 GstBuffer *headerbuf;
12768 GstBuffer *extra;
12769
12770 waveheader += 8;
12771 headerlen -= 8;
12772
12773 headerbuf = gst_buffer_new_and_alloc (headerlen);
12774 gst_buffer_fill (headerbuf, 0, waveheader, headerlen);
12775
12776 if (gst_riff_parse_strf_auds (GST_ELEMENT_CAST (qtdemux),
12777 headerbuf, &header, &extra)) {
12778 gst_caps_unref (entry->caps);
12779 /* FIXME: Need to do something with the channel reorder map */
12780 entry->caps =
12781 gst_riff_create_audio_caps (header->format, NULL, header,
12782 extra, NULL, NULL, NULL);
12783
12784 if (extra)
12785 gst_buffer_unref (extra);
12786 g_free (header);
12787 }
12788 }
12789 } else
12790 GST_DEBUG ("Didn't find waveheadernode for this codec");
12791 }
12792 g_node_destroy (wavenode);
12793 }
12794 } else if (esds) {
12795 gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
12796 stream->stream_tags);
12797 } else {
12798 switch (fourcc) {
12799 #if 0
12800 /* FIXME: what is in the chunk? */
12801 case FOURCC_QDMC:
12802 {
12803 gint len = QT_UINT32 (stsd_data);
12804
12805 /* seems to be always = 116 = 0x74 */
12806 break;
12807 }
12808 #endif
12809 case FOURCC_QDM2:
12810 {
12811 gint len = QT_UINT32 (stsd_entry_data);
12812
12813 if (len > 0x3C) {
12814 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x3C);
12815
12816 gst_buffer_fill (buf, 0, stsd_entry_data + 0x3C, len - 0x3C);
12817 gst_caps_set_simple (entry->caps,
12818 "codec_data", GST_TYPE_BUFFER, buf, NULL);
12819 gst_buffer_unref (buf);
12820 }
12821 gst_caps_set_simple (entry->caps,
12822 "samplesize", G_TYPE_INT, samplesize, NULL);
12823 break;
12824 }
12825 case FOURCC_alac:
12826 {
12827 GNode *alac, *wave = NULL;
12828
12829 /* apparently, m4a has this atom appended directly in the stsd entry,
12830 * while mov has it in a wave atom */
12831 alac = qtdemux_tree_get_child_by_type (stsd, FOURCC_alac);
12832 if (alac) {
12833 /* alac now refers to stsd entry atom */
12834 wave = qtdemux_tree_get_child_by_type (alac, FOURCC_wave);
12835 if (wave)
12836 alac = qtdemux_tree_get_child_by_type (wave, FOURCC_alac);
12837 else
12838 alac = qtdemux_tree_get_child_by_type (alac, FOURCC_alac);
12839 }
12840 if (alac) {
12841 const guint8 *alac_data = alac->data;
12842 gint len = QT_UINT32 (alac->data);
12843 GstBuffer *buf;
12844
12845 if (len < 36) {
12846 GST_DEBUG_OBJECT (qtdemux,
12847 "discarding alac atom with unexpected len %d", len);
12848 } else {
12849 /* codec-data contains alac atom size and prefix,
12850 * ffmpeg likes it that way, not quite gst-ish though ...*/
12851 buf = gst_buffer_new_and_alloc (len);
12852 gst_buffer_fill (buf, 0, alac->data, len);
12853 gst_caps_set_simple (entry->caps,
12854 "codec_data", GST_TYPE_BUFFER, buf, NULL);
12855 gst_buffer_unref (buf);
12856
12857 entry->bytes_per_frame = QT_UINT32 (alac_data + 12);
12858 entry->n_channels = QT_UINT8 (alac_data + 21);
12859 entry->rate = QT_UINT32 (alac_data + 32);
12860 samplesize = QT_UINT8 (alac_data + 16 + 1);
12861 }
12862 }
12863 gst_caps_set_simple (entry->caps,
12864 "samplesize", G_TYPE_INT, samplesize, NULL);
12865 break;
12866 }
12867 case FOURCC_fLaC:
12868 {
12869 /* The codingname of the sample entry is 'fLaC' */
12870 GNode *flac = qtdemux_tree_get_child_by_type (stsd, FOURCC_fLaC);
12871
12872 if (flac) {
12873 /* The 'dfLa' box is added to the sample entry to convey
12874 initializing information for the decoder. */
12875 const GNode *dfla =
12876 qtdemux_tree_get_child_by_type (flac, FOURCC_dfLa);
12877
12878 if (dfla) {
12879 const guint32 len = QT_UINT32 (dfla->data);
12880
12881 /* Must contain at least dfLa box header (12),
12882 * METADATA_BLOCK_HEADER (4), METADATA_BLOCK_STREAMINFO (34) */
12883 if (len < 50) {
12884 GST_DEBUG_OBJECT (qtdemux,
12885 "discarding dfla atom with unexpected len %d", len);
12886 } else {
12887 /* skip dfLa header to get the METADATA_BLOCKs */
12888 const guint8 *metadata_blocks = (guint8 *) dfla->data + 12;
12889 const guint32 metadata_blocks_len = len - 12;
12890
12891 gchar *stream_marker = g_strdup ("fLaC");
12892 GstBuffer *block = gst_buffer_new_wrapped (stream_marker,
12893 strlen (stream_marker));
12894
12895 guint32 index = 0;
12896 guint32 remainder = 0;
12897 guint32 block_size = 0;
12898 gboolean is_last = FALSE;
12899
12900 GValue array = G_VALUE_INIT;
12901 GValue value = G_VALUE_INIT;
12902
12903 g_value_init (&array, GST_TYPE_ARRAY);
12904 g_value_init (&value, GST_TYPE_BUFFER);
12905
12906 gst_value_set_buffer (&value, block);
12907 gst_value_array_append_value (&array, &value);
12908 g_value_reset (&value);
12909
12910 gst_buffer_unref (block);
12911
12912 /* check there's at least one METADATA_BLOCK_HEADER's worth
12913 * of data, and we haven't already finished parsing */
12914 while (!is_last && ((index + 3) < metadata_blocks_len)) {
12915 remainder = metadata_blocks_len - index;
12916
12917 /* add the METADATA_BLOCK_HEADER size to the signalled size */
12918 block_size = 4 +
12919 (metadata_blocks[index + 1] << 16) +
12920 (metadata_blocks[index + 2] << 8) +
12921 metadata_blocks[index + 3];
12922
12923 /* be careful not to read off end of box */
12924 if (block_size > remainder) {
12925 break;
12926 }
12927
12928 is_last = metadata_blocks[index] >> 7;
12929
12930 block = gst_buffer_new_and_alloc (block_size);
12931
12932 gst_buffer_fill (block, 0, &metadata_blocks[index],
12933 block_size);
12934
12935 gst_value_set_buffer (&value, block);
12936 gst_value_array_append_value (&array, &value);
12937 g_value_reset (&value);
12938
12939 gst_buffer_unref (block);
12940
12941 index += block_size;
12942 }
12943
12944 /* only append the metadata if we successfully read all of it */
12945 if (is_last) {
12946 gst_structure_set_value (gst_caps_get_structure (CUR_STREAM
12947 (stream)->caps, 0), "streamheader", &array);
12948 } else {
12949 GST_WARNING_OBJECT (qtdemux,
12950 "discarding all METADATA_BLOCKs due to invalid "
12951 "block_size %d at idx %d, rem %d", block_size, index,
12952 remainder);
12953 }
12954
12955 g_value_unset (&value);
12956 g_value_unset (&array);
12957
12958 /* The sample rate obtained from the stsd may not be accurate
12959 * since it cannot represent rates greater than 65535Hz, so
12960 * override that value with the sample rate from the
12961 * METADATA_BLOCK_STREAMINFO block */
12962 CUR_STREAM (stream)->rate =
12963 (QT_UINT32 (metadata_blocks + 14) >> 12) & 0xFFFFF;
12964 }
12965 }
12966 }
12967 break;
12968 }
12969 case FOURCC_sawb:
12970 /* Fallthrough! */
12971 amrwb = TRUE;
12972 case FOURCC_samr:
12973 {
12974 gint len = QT_UINT32 (stsd_entry_data);
12975
12976 if (len > 0x24) {
12977 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x24);
12978 guint bitrate;
12979
12980 gst_buffer_fill (buf, 0, stsd_entry_data + 0x24, len - 0x24);
12981
12982 /* If we have enough data, let's try to get the 'damr' atom. See
12983 * the 3GPP container spec (26.244) for more details. */
12984 if ((len - 0x34) > 8 &&
12985 (bitrate = qtdemux_parse_amr_bitrate (buf, amrwb))) {
12986 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12987 GST_TAG_MAXIMUM_BITRATE, bitrate, NULL);
12988 }
12989
12990 gst_caps_set_simple (entry->caps,
12991 "codec_data", GST_TYPE_BUFFER, buf, NULL);
12992 gst_buffer_unref (buf);
12993 }
12994 break;
12995 }
12996 case FOURCC_mp4a:
12997 {
12998 /* mp4a atom withtout ESDS; Attempt to build codec data from atom */
12999 gint len = QT_UINT32 (stsd_entry_data);
13000 guint16 sound_version = 0;
13001 /* FIXME: Can this be determined somehow? There doesn't seem to be
13002 * anything in mp4a atom that specifis compression */
13003 gint profile = 2;
13004 guint16 channels = entry->n_channels;
13005 guint32 time_scale = (guint32) entry->rate;
13006 gint sample_rate_index = -1;
13007
13008 if (len >= 34) {
13009 sound_version = QT_UINT16 (stsd_entry_data + 16);
13010
13011 if (sound_version == 1) {
13012 channels = QT_UINT16 (stsd_entry_data + 24);
13013 time_scale = QT_UINT32 (stsd_entry_data + 30);
13014 } else {
13015 GST_FIXME_OBJECT (qtdemux, "Unhandled mp4a atom version %d",
13016 sound_version);
13017 }
13018 } else {
13019 GST_DEBUG_OBJECT (qtdemux, "Too small stsd entry data len %d",
13020 len);
13021 }
13022
13023 sample_rate_index =
13024 gst_codec_utils_aac_get_index_from_sample_rate (time_scale);
13025 if (sample_rate_index >= 0 && channels > 0) {
13026 guint8 codec_data[2];
13027 GstBuffer *buf;
13028
13029 /* build AAC codec data */
13030 codec_data[0] = profile << 3;
13031 codec_data[0] |= ((sample_rate_index >> 1) & 0x7);
13032 codec_data[1] = (sample_rate_index & 0x01) << 7;
13033 codec_data[1] |= (channels & 0xF) << 3;
13034
13035 buf = gst_buffer_new_and_alloc (2);
13036 gst_buffer_fill (buf, 0, codec_data, 2);
13037 gst_caps_set_simple (entry->caps,
13038 "codec_data", GST_TYPE_BUFFER, buf, NULL);
13039 gst_buffer_unref (buf);
13040 }
13041 break;
13042 }
13043 case FOURCC_lpcm:
13044 case FOURCC_in24:
13045 case FOURCC_in32:
13046 case FOURCC_fl32:
13047 case FOURCC_fl64:
13048 case FOURCC_s16l:
13049 /* Fully handled elsewhere */
13050 break;
13051 default:
13052 GST_INFO_OBJECT (qtdemux,
13053 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
13054 break;
13055 }
13056 }
13057 GST_INFO_OBJECT (qtdemux,
13058 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
13059 GST_FOURCC_ARGS (fourcc), entry->caps);
13060
13061 } else if (stream->subtype == FOURCC_strm) {
13062 if (fourcc == FOURCC_rtsp) {
13063 stream->redirect_uri = qtdemux_get_rtsp_uri_from_hndl (qtdemux, minf);
13064 } else {
13065 GST_INFO_OBJECT (qtdemux, "unhandled stream type %" GST_FOURCC_FORMAT,
13066 GST_FOURCC_ARGS (fourcc));
13067 goto unknown_stream;
13068 }
13069 entry->sampled = TRUE;
13070 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
13071 || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt
13072 || stream->subtype == FOURCC_clcp || stream->subtype == FOURCC_wvtt) {
13073
13074 entry->sampled = TRUE;
13075 entry->sparse = TRUE;
13076
13077 entry->caps =
13078 qtdemux_sub_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
13079 &codec);
13080 if (codec) {
13081 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
13082 GST_TAG_SUBTITLE_CODEC, codec, NULL);
13083 g_free (codec);
13084 codec = NULL;
13085 }
13086
13087 /* hunt for sort-of codec data */
13088 switch (fourcc) {
13089 case FOURCC_mp4s:
13090 {
13091 GNode *mp4s = NULL;
13092 GNode *esds = NULL;
13093
13094 /* look for palette in a stsd->mp4s->esds sub-atom */
13095 mp4s = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4s);
13096 if (mp4s)
13097 esds = qtdemux_tree_get_child_by_type (mp4s, FOURCC_esds);
13098 if (esds == NULL) {
13099 /* Invalid STSD */
13100 GST_LOG_OBJECT (qtdemux, "Skipping invalid stsd: no esds child");
13101 break;
13102 }
13103
13104 gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
13105 stream->stream_tags);
13106 break;
13107 }
13108 default:
13109 GST_INFO_OBJECT (qtdemux,
13110 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
13111 break;
13112 }
13113 GST_INFO_OBJECT (qtdemux,
13114 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
13115 GST_FOURCC_ARGS (fourcc), entry->caps);
13116 } else {
13117 /* everything in 1 sample */
13118 entry->sampled = TRUE;
13119
13120 entry->caps =
13121 qtdemux_generic_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
13122 &codec);
13123
13124 if (entry->caps == NULL)
13125 goto unknown_stream;
13126
13127 if (codec) {
13128 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
13129 GST_TAG_SUBTITLE_CODEC, codec, NULL);
13130 g_free (codec);
13131 codec = NULL;
13132 }
13133 }
13134
13135 /* promote to sampled format */
13136 if (entry->fourcc == FOURCC_samr) {
13137 /* force mono 8000 Hz for AMR */
13138 entry->sampled = TRUE;
13139 entry->n_channels = 1;
13140 entry->rate = 8000;
13141 } else if (entry->fourcc == FOURCC_sawb) {
13142 /* force mono 16000 Hz for AMR-WB */
13143 entry->sampled = TRUE;
13144 entry->n_channels = 1;
13145 entry->rate = 16000;
13146 } else if (entry->fourcc == FOURCC_mp4a) {
13147 entry->sampled = TRUE;
13148 }
13149
13150
13151 stsd_entry_data += len;
13152 remaining_stsd_len -= len;
13153
13154 }
13155
13156 /* collect sample information */
13157 if (!qtdemux_stbl_init (qtdemux, stream, stbl))
13158 goto samples_failed;
13159
13160 if (qtdemux->fragmented) {
13161 guint64 offset;
13162
13163 /* need all moov samples as basis; probably not many if any at all */
13164 /* prevent moof parsing taking of at this time */
13165 offset = qtdemux->moof_offset;
13166 qtdemux->moof_offset = 0;
13167 if (stream->n_samples &&
13168 !qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
13169 qtdemux->moof_offset = offset;
13170 goto samples_failed;
13171 }
13172 qtdemux->moof_offset = offset;
13173 /* movie duration more reliable in this case (e.g. mehd) */
13174 if (qtdemux->segment.duration &&
13175 GST_CLOCK_TIME_IS_VALID (qtdemux->segment.duration))
13176 stream->duration =
13177 GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->segment.duration);
13178 }
13179
13180 /* configure segments */
13181 if (!qtdemux_parse_segments (qtdemux, stream, trak))
13182 goto segments_failed;
13183
13184 /* add some language tag, if useful */
13185 if (stream->lang_id[0] != '\0' && strcmp (stream->lang_id, "unk") &&
13186 strcmp (stream->lang_id, "und")) {
13187 const gchar *lang_code;
13188
13189 /* convert ISO 639-2 code to ISO 639-1 */
13190 lang_code = gst_tag_get_language_code (stream->lang_id);
13191 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
13192 GST_TAG_LANGUAGE_CODE, (lang_code) ? lang_code : stream->lang_id, NULL);
13193 }
13194
13195 /* Check for UDTA tags */
13196 if ((udta = qtdemux_tree_get_child_by_type (trak, FOURCC_udta))) {
13197 qtdemux_parse_udta (qtdemux, stream->stream_tags, udta);
13198 }
13199
13200 /* Insert and sort new stream in track-id order.
13201 * This will help in comparing old/new streams during stream update check */
13202 g_ptr_array_add (qtdemux->active_streams, stream);
13203 g_ptr_array_sort (qtdemux->active_streams,
13204 (GCompareFunc) qtdemux_track_id_compare_func);
13205 GST_DEBUG_OBJECT (qtdemux, "n_streams is now %d",
13206 QTDEMUX_N_STREAMS (qtdemux));
13207
13208 return TRUE;
13209
13210 /* ERRORS */
13211 corrupt_file:
13212 {
13213 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
13214 (_("This file is corrupt and cannot be played.")), (NULL));
13215 if (stream)
13216 gst_qtdemux_stream_unref (stream);
13217 return FALSE;
13218 }
13219 error_encrypted:
13220 {
13221 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT, (NULL), (NULL));
13222 gst_qtdemux_stream_unref (stream);
13223 return FALSE;
13224 }
13225 samples_failed:
13226 segments_failed:
13227 {
13228 /* we posted an error already */
13229 /* free stbl sub-atoms */
13230 gst_qtdemux_stbl_free (stream);
13231 gst_qtdemux_stream_unref (stream);
13232 return FALSE;
13233 }
13234 existing_stream:
13235 {
13236 GST_INFO_OBJECT (qtdemux, "stream with track id %i already exists",
13237 track_id);
13238 return TRUE;
13239 }
13240 unknown_stream:
13241 {
13242 GST_INFO_OBJECT (qtdemux, "unknown subtype %" GST_FOURCC_FORMAT,
13243 GST_FOURCC_ARGS (stream->subtype));
13244 gst_qtdemux_stream_unref (stream);
13245 return TRUE;
13246 }
13247 }
13248
13249 /* If we can estimate the overall bitrate, and don't have information about the
13250 * stream bitrate for exactly one stream, this guesses the stream bitrate as
13251 * the overall bitrate minus the sum of the bitrates of all other streams. This
13252 * should be useful for the common case where we have one audio and one video
13253 * stream and can estimate the bitrate of one, but not the other. */
13254 static void
gst_qtdemux_guess_bitrate(GstQTDemux * qtdemux)13255 gst_qtdemux_guess_bitrate (GstQTDemux * qtdemux)
13256 {
13257 QtDemuxStream *stream = NULL;
13258 gint64 size, sys_bitrate, sum_bitrate = 0;
13259 GstClockTime duration;
13260 guint bitrate;
13261 gint i;
13262
13263 if (qtdemux->fragmented)
13264 return;
13265
13266 GST_DEBUG_OBJECT (qtdemux, "Looking for streams with unknown bitrate");
13267
13268 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &size)
13269 || size <= 0) {
13270 GST_DEBUG_OBJECT (qtdemux,
13271 "Size in bytes of the stream not known - bailing");
13272 return;
13273 }
13274
13275 /* Subtract the header size */
13276 GST_DEBUG_OBJECT (qtdemux, "Total size %" G_GINT64_FORMAT ", header size %u",
13277 size, qtdemux->header_size);
13278
13279 if (size < qtdemux->header_size)
13280 return;
13281
13282 size = size - qtdemux->header_size;
13283
13284 if (!gst_qtdemux_get_duration (qtdemux, &duration)) {
13285 GST_DEBUG_OBJECT (qtdemux, "Stream duration not known - bailing");
13286 return;
13287 }
13288
13289 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13290 QtDemuxStream *str = QTDEMUX_NTH_STREAM (qtdemux, i);
13291 switch (str->subtype) {
13292 case FOURCC_soun:
13293 case FOURCC_vide:
13294 GST_DEBUG_OBJECT (qtdemux, "checking bitrate for %" GST_PTR_FORMAT,
13295 CUR_STREAM (str)->caps);
13296 /* retrieve bitrate, prefer avg then max */
13297 bitrate = 0;
13298 if (str->stream_tags) {
13299 if (gst_tag_list_get_uint (str->stream_tags,
13300 GST_TAG_MAXIMUM_BITRATE, &bitrate))
13301 GST_DEBUG_OBJECT (qtdemux, "max-bitrate: %u", bitrate);
13302 if (gst_tag_list_get_uint (str->stream_tags,
13303 GST_TAG_NOMINAL_BITRATE, &bitrate))
13304 GST_DEBUG_OBJECT (qtdemux, "nominal-bitrate: %u", bitrate);
13305 if (gst_tag_list_get_uint (str->stream_tags,
13306 GST_TAG_BITRATE, &bitrate))
13307 GST_DEBUG_OBJECT (qtdemux, "bitrate: %u", bitrate);
13308 }
13309 if (bitrate)
13310 sum_bitrate += bitrate;
13311 else {
13312 if (stream) {
13313 GST_DEBUG_OBJECT (qtdemux,
13314 ">1 stream with unknown bitrate - bailing");
13315 return;
13316 } else
13317 stream = str;
13318 }
13319
13320 default:
13321 /* For other subtypes, we assume no significant impact on bitrate */
13322 break;
13323 }
13324 }
13325
13326 if (!stream) {
13327 GST_DEBUG_OBJECT (qtdemux, "All stream bitrates are known");
13328 return;
13329 }
13330
13331 sys_bitrate = gst_util_uint64_scale (size, GST_SECOND * 8, duration);
13332
13333 if (sys_bitrate < sum_bitrate) {
13334 /* This can happen, since sum_bitrate might be derived from maximum
13335 * bitrates and not average bitrates */
13336 GST_DEBUG_OBJECT (qtdemux,
13337 "System bitrate less than sum bitrate - bailing");
13338 return;
13339 }
13340
13341 bitrate = sys_bitrate - sum_bitrate;
13342 GST_DEBUG_OBJECT (qtdemux, "System bitrate = %" G_GINT64_FORMAT
13343 ", Stream bitrate = %u", sys_bitrate, bitrate);
13344
13345 if (!stream->stream_tags)
13346 stream->stream_tags = gst_tag_list_new_empty ();
13347 else
13348 stream->stream_tags = gst_tag_list_make_writable (stream->stream_tags);
13349
13350 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
13351 GST_TAG_BITRATE, bitrate, NULL);
13352 }
13353
13354 static GstFlowReturn
qtdemux_prepare_streams(GstQTDemux * qtdemux)13355 qtdemux_prepare_streams (GstQTDemux * qtdemux)
13356 {
13357 GstFlowReturn ret = GST_FLOW_OK;
13358 gint i;
13359
13360 GST_DEBUG_OBJECT (qtdemux, "prepare %u streams", QTDEMUX_N_STREAMS (qtdemux));
13361
13362 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13363 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
13364 guint32 sample_num = 0;
13365
13366 GST_DEBUG_OBJECT (qtdemux, "track-id %u, fourcc %" GST_FOURCC_FORMAT,
13367 stream->track_id, GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
13368
13369 if (qtdemux->fragmented && qtdemux->pullbased) {
13370 /* need all moov samples first */
13371 GST_OBJECT_LOCK (qtdemux);
13372 while (stream->n_samples == 0)
13373 if ((ret = qtdemux_add_fragmented_samples (qtdemux)) != GST_FLOW_OK)
13374 break;
13375 GST_OBJECT_UNLOCK (qtdemux);
13376 } else {
13377 /* discard any stray moof */
13378 qtdemux->moof_offset = 0;
13379 }
13380
13381 /* prepare braking */
13382 if (ret != GST_FLOW_ERROR)
13383 ret = GST_FLOW_OK;
13384
13385 /* in pull mode, we should have parsed some sample info by now;
13386 * and quite some code will not handle no samples.
13387 * in push mode, we'll just have to deal with it */
13388 if (G_UNLIKELY (qtdemux->pullbased && !stream->n_samples)) {
13389 GST_DEBUG_OBJECT (qtdemux, "no samples for stream; discarding");
13390 g_ptr_array_remove_index (qtdemux->active_streams, i);
13391 i--;
13392 continue;
13393 } else if (stream->track_id == qtdemux->chapters_track_id &&
13394 (stream->subtype == FOURCC_text || stream->subtype == FOURCC_sbtl)) {
13395 /* TODO - parse chapters track and expose it as GstToc; For now just ignore it
13396 so that it doesn't look like a subtitle track */
13397 g_ptr_array_remove_index (qtdemux->active_streams, i);
13398 i--;
13399 continue;
13400 }
13401
13402 /* parse the initial sample for use in setting the frame rate cap */
13403 while (sample_num == 0 && sample_num < stream->n_samples) {
13404 if (!qtdemux_parse_samples (qtdemux, stream, sample_num))
13405 break;
13406 ++sample_num;
13407 }
13408 }
13409
13410 return ret;
13411 }
13412
13413 static gboolean
_stream_equal_func(const QtDemuxStream * stream,const gchar * stream_id)13414 _stream_equal_func (const QtDemuxStream * stream, const gchar * stream_id)
13415 {
13416 return g_strcmp0 (stream->stream_id, stream_id) == 0;
13417 }
13418
13419 static gboolean
qtdemux_is_streams_update(GstQTDemux * qtdemux)13420 qtdemux_is_streams_update (GstQTDemux * qtdemux)
13421 {
13422 gint i;
13423
13424 /* Different length, updated */
13425 if (QTDEMUX_N_STREAMS (qtdemux) != qtdemux->old_streams->len)
13426 return TRUE;
13427
13428 /* streams in list are sorted in track-id order */
13429 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13430 /* Different stream-id, updated */
13431 if (g_strcmp0 (QTDEMUX_NTH_STREAM (qtdemux, i)->stream_id,
13432 QTDEMUX_NTH_OLD_STREAM (qtdemux, i)->stream_id))
13433 return TRUE;
13434 }
13435
13436 return FALSE;
13437 }
13438
13439 static gboolean
qtdemux_reuse_and_configure_stream(GstQTDemux * qtdemux,QtDemuxStream * oldstream,QtDemuxStream * newstream)13440 qtdemux_reuse_and_configure_stream (GstQTDemux * qtdemux,
13441 QtDemuxStream * oldstream, QtDemuxStream * newstream)
13442 {
13443 /* Connect old stream's srcpad to new stream */
13444 newstream->pad = oldstream->pad;
13445 oldstream->pad = NULL;
13446
13447 /* unset new_stream to prevent stream-start event, unless we are EOS in which
13448 * case we need to force one through */
13449 newstream->new_stream = GST_PAD_IS_EOS (newstream->pad);
13450
13451 return gst_qtdemux_configure_stream (qtdemux, newstream);
13452 }
13453
13454 static gboolean
qtdemux_update_streams(GstQTDemux * qtdemux)13455 qtdemux_update_streams (GstQTDemux * qtdemux)
13456 {
13457 gint i;
13458 g_assert (qtdemux->streams_aware);
13459
13460 /* At below, figure out which stream in active_streams has identical stream-id
13461 * with that of in old_streams. If there is matching stream-id,
13462 * corresponding newstream will not be exposed again,
13463 * but demux will reuse srcpad of matched old stream
13464 *
13465 * active_streams : newly created streams from the latest moov
13466 * old_streams : existing streams (belong to previous moov)
13467 */
13468
13469 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13470 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
13471 QtDemuxStream *oldstream = NULL;
13472 guint target;
13473
13474 GST_DEBUG_OBJECT (qtdemux, "track-id %u, fourcc %" GST_FOURCC_FORMAT,
13475 stream->track_id, GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
13476
13477 if (g_ptr_array_find_with_equal_func (qtdemux->old_streams,
13478 stream->stream_id, (GEqualFunc) _stream_equal_func, &target)) {
13479 oldstream = QTDEMUX_NTH_OLD_STREAM (qtdemux, target);
13480
13481 /* null pad stream cannot be reused */
13482 if (oldstream->pad == NULL)
13483 oldstream = NULL;
13484 }
13485
13486 if (oldstream) {
13487 GST_DEBUG_OBJECT (qtdemux, "Reuse track-id %d", oldstream->track_id);
13488
13489 if (!qtdemux_reuse_and_configure_stream (qtdemux, oldstream, stream))
13490 return FALSE;
13491
13492 /* we don't need to preserve order of old streams */
13493 g_ptr_array_remove_fast (qtdemux->old_streams, oldstream);
13494 } else {
13495 GstTagList *list;
13496
13497 /* now we have all info and can expose */
13498 list = stream->stream_tags;
13499 stream->stream_tags = NULL;
13500 if (!gst_qtdemux_add_stream (qtdemux, stream, list))
13501 return FALSE;
13502 }
13503 }
13504
13505 return TRUE;
13506 }
13507
13508 /* Must be called with expose lock */
13509 static GstFlowReturn
qtdemux_expose_streams(GstQTDemux * qtdemux)13510 qtdemux_expose_streams (GstQTDemux * qtdemux)
13511 {
13512 gint i;
13513
13514 GST_DEBUG_OBJECT (qtdemux, "exposing streams");
13515
13516 if (!qtdemux_is_streams_update (qtdemux)) {
13517 GST_DEBUG_OBJECT (qtdemux, "Reuse all streams");
13518 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13519 QtDemuxStream *new_stream = QTDEMUX_NTH_STREAM (qtdemux, i);
13520 QtDemuxStream *old_stream = QTDEMUX_NTH_OLD_STREAM (qtdemux, i);
13521 if (!qtdemux_reuse_and_configure_stream (qtdemux, old_stream, new_stream))
13522 return GST_FLOW_ERROR;
13523 }
13524
13525 g_ptr_array_set_size (qtdemux->old_streams, 0);
13526 qtdemux->need_segment = TRUE;
13527
13528 return GST_FLOW_OK;
13529 }
13530
13531 if (qtdemux->streams_aware) {
13532 if (!qtdemux_update_streams (qtdemux))
13533 return GST_FLOW_ERROR;
13534 } else {
13535 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13536 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
13537 GstTagList *list;
13538
13539 /* now we have all info and can expose */
13540 list = stream->stream_tags;
13541 stream->stream_tags = NULL;
13542 if (!gst_qtdemux_add_stream (qtdemux, stream, list))
13543 return GST_FLOW_ERROR;
13544
13545 }
13546 }
13547
13548 gst_qtdemux_guess_bitrate (qtdemux);
13549
13550 gst_element_no_more_pads (GST_ELEMENT_CAST (qtdemux));
13551
13552 /* If we have still old_streams, it's no more used stream */
13553 for (i = 0; i < qtdemux->old_streams->len; i++) {
13554 QtDemuxStream *stream = QTDEMUX_NTH_OLD_STREAM (qtdemux, i);
13555
13556 if (stream->pad) {
13557 GstEvent *event;
13558
13559 event = gst_event_new_eos ();
13560 if (qtdemux->segment_seqnum)
13561 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
13562
13563 gst_pad_push_event (stream->pad, event);
13564 }
13565 }
13566
13567 g_ptr_array_set_size (qtdemux->old_streams, 0);
13568
13569 /* check if we should post a redirect in case there is a single trak
13570 * and it is a redirecting trak */
13571 if (QTDEMUX_N_STREAMS (qtdemux) == 1 &&
13572 QTDEMUX_NTH_STREAM (qtdemux, 0)->redirect_uri != NULL) {
13573 GstMessage *m;
13574
13575 GST_INFO_OBJECT (qtdemux, "Issuing a redirect due to a single track with "
13576 "an external content");
13577 m = gst_message_new_element (GST_OBJECT_CAST (qtdemux),
13578 gst_structure_new ("redirect",
13579 "new-location", G_TYPE_STRING,
13580 QTDEMUX_NTH_STREAM (qtdemux, 0)->redirect_uri, NULL));
13581 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), m);
13582 g_free (qtdemux->redirect_location);
13583 qtdemux->redirect_location =
13584 g_strdup (QTDEMUX_NTH_STREAM (qtdemux, 0)->redirect_uri);
13585 }
13586
13587 g_ptr_array_foreach (qtdemux->active_streams,
13588 (GFunc) qtdemux_do_allocation, qtdemux);
13589
13590 qtdemux->need_segment = TRUE;
13591
13592 qtdemux->exposed = TRUE;
13593 return GST_FLOW_OK;
13594 }
13595
13596 typedef struct
13597 {
13598 GstStructure *structure; /* helper for sort function */
13599 gchar *location;
13600 guint min_req_bitrate;
13601 guint min_req_qt_version;
13602 } GstQtReference;
13603
13604 static gint
qtdemux_redirects_sort_func(gconstpointer a,gconstpointer b)13605 qtdemux_redirects_sort_func (gconstpointer a, gconstpointer b)
13606 {
13607 GstQtReference *ref_a = (GstQtReference *) a;
13608 GstQtReference *ref_b = (GstQtReference *) b;
13609
13610 if (ref_b->min_req_qt_version != ref_a->min_req_qt_version)
13611 return ref_b->min_req_qt_version - ref_a->min_req_qt_version;
13612
13613 /* known bitrates go before unknown; higher bitrates go first */
13614 return ref_b->min_req_bitrate - ref_a->min_req_bitrate;
13615 }
13616
13617 /* sort the redirects and post a message for the application.
13618 */
13619 static void
qtdemux_process_redirects(GstQTDemux * qtdemux,GList * references)13620 qtdemux_process_redirects (GstQTDemux * qtdemux, GList * references)
13621 {
13622 GstQtReference *best;
13623 GstStructure *s;
13624 GstMessage *msg;
13625 GValue list_val = { 0, };
13626 GList *l;
13627
13628 g_assert (references != NULL);
13629
13630 references = g_list_sort (references, qtdemux_redirects_sort_func);
13631
13632 best = (GstQtReference *) references->data;
13633
13634 g_value_init (&list_val, GST_TYPE_LIST);
13635
13636 for (l = references; l != NULL; l = l->next) {
13637 GstQtReference *ref = (GstQtReference *) l->data;
13638 GValue struct_val = { 0, };
13639
13640 ref->structure = gst_structure_new ("redirect",
13641 "new-location", G_TYPE_STRING, ref->location, NULL);
13642
13643 if (ref->min_req_bitrate > 0) {
13644 gst_structure_set (ref->structure, "minimum-bitrate", G_TYPE_INT,
13645 ref->min_req_bitrate, NULL);
13646 }
13647
13648 g_value_init (&struct_val, GST_TYPE_STRUCTURE);
13649 g_value_set_boxed (&struct_val, ref->structure);
13650 gst_value_list_append_value (&list_val, &struct_val);
13651 g_value_unset (&struct_val);
13652 /* don't free anything here yet, since we need best->structure below */
13653 }
13654
13655 g_assert (best != NULL);
13656 s = gst_structure_copy (best->structure);
13657
13658 if (g_list_length (references) > 1) {
13659 gst_structure_set_value (s, "locations", &list_val);
13660 }
13661
13662 g_value_unset (&list_val);
13663
13664 for (l = references; l != NULL; l = l->next) {
13665 GstQtReference *ref = (GstQtReference *) l->data;
13666
13667 gst_structure_free (ref->structure);
13668 g_free (ref->location);
13669 g_free (ref);
13670 }
13671 g_list_free (references);
13672
13673 GST_INFO_OBJECT (qtdemux, "posting redirect message: %" GST_PTR_FORMAT, s);
13674 g_free (qtdemux->redirect_location);
13675 qtdemux->redirect_location =
13676 g_strdup (gst_structure_get_string (s, "new-location"));
13677 msg = gst_message_new_element (GST_OBJECT_CAST (qtdemux), s);
13678 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
13679 }
13680
13681 /* look for redirect nodes, collect all redirect information and
13682 * process it.
13683 */
13684 static gboolean
qtdemux_parse_redirects(GstQTDemux * qtdemux)13685 qtdemux_parse_redirects (GstQTDemux * qtdemux)
13686 {
13687 GNode *rmra, *rmda, *rdrf;
13688
13689 rmra = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_rmra);
13690 if (rmra) {
13691 GList *redirects = NULL;
13692
13693 rmda = qtdemux_tree_get_child_by_type (rmra, FOURCC_rmda);
13694 while (rmda) {
13695 GstQtReference ref = { NULL, NULL, 0, 0 };
13696 GNode *rmdr, *rmvc;
13697
13698 if ((rmdr = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmdr))) {
13699 ref.min_req_bitrate = QT_UINT32 ((guint8 *) rmdr->data + 12);
13700 GST_LOG_OBJECT (qtdemux, "data rate atom, required bitrate = %u",
13701 ref.min_req_bitrate);
13702 }
13703
13704 if ((rmvc = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmvc))) {
13705 guint32 package = QT_FOURCC ((guint8 *) rmvc->data + 12);
13706 guint version = QT_UINT32 ((guint8 *) rmvc->data + 16);
13707
13708 #ifndef GST_DISABLE_GST_DEBUG
13709 guint bitmask = QT_UINT32 ((guint8 *) rmvc->data + 20);
13710 #endif
13711 guint check_type = QT_UINT16 ((guint8 *) rmvc->data + 24);
13712
13713 GST_LOG_OBJECT (qtdemux,
13714 "version check atom [%" GST_FOURCC_FORMAT "], version=0x%08x"
13715 ", mask=%08x, check_type=%u", GST_FOURCC_ARGS (package), version,
13716 bitmask, check_type);
13717 if (package == FOURCC_qtim && check_type == 0) {
13718 ref.min_req_qt_version = version;
13719 }
13720 }
13721
13722 rdrf = qtdemux_tree_get_child_by_type (rmda, FOURCC_rdrf);
13723 if (rdrf) {
13724 guint32 ref_type;
13725 guint8 *ref_data;
13726 guint ref_len;
13727
13728 ref_len = QT_UINT32 ((guint8 *) rdrf->data);
13729 if (ref_len > 20) {
13730 ref_type = QT_FOURCC ((guint8 *) rdrf->data + 12);
13731 ref_data = (guint8 *) rdrf->data + 20;
13732 if (ref_type == FOURCC_alis) {
13733 guint record_len, record_version, fn_len;
13734
13735 if (ref_len > 70) {
13736 /* MacOSX alias record, google for alias-layout.txt */
13737 record_len = QT_UINT16 (ref_data + 4);
13738 record_version = QT_UINT16 (ref_data + 4 + 2);
13739 fn_len = QT_UINT8 (ref_data + 50);
13740 if (record_len > 50 && record_version == 2 && fn_len > 0) {
13741 ref.location = g_strndup ((gchar *) ref_data + 51, fn_len);
13742 }
13743 } else {
13744 GST_WARNING_OBJECT (qtdemux, "Invalid rdrf/alis size (%u < 70)",
13745 ref_len);
13746 }
13747 } else if (ref_type == FOURCC_url_) {
13748 ref.location = g_strndup ((gchar *) ref_data, ref_len - 8);
13749 } else {
13750 GST_DEBUG_OBJECT (qtdemux,
13751 "unknown rdrf reference type %" GST_FOURCC_FORMAT,
13752 GST_FOURCC_ARGS (ref_type));
13753 }
13754 if (ref.location != NULL) {
13755 GST_INFO_OBJECT (qtdemux, "New location: %s", ref.location);
13756 redirects =
13757 g_list_prepend (redirects, g_memdup2 (&ref, sizeof (ref)));
13758 } else {
13759 GST_WARNING_OBJECT (qtdemux,
13760 "Failed to extract redirect location from rdrf atom");
13761 }
13762 } else {
13763 GST_WARNING_OBJECT (qtdemux, "Invalid rdrf size (%u < 20)", ref_len);
13764 }
13765 }
13766
13767 /* look for others */
13768 rmda = qtdemux_tree_get_sibling_by_type (rmda, FOURCC_rmda);
13769 }
13770
13771 if (redirects != NULL) {
13772 qtdemux_process_redirects (qtdemux, redirects);
13773 }
13774 }
13775 return TRUE;
13776 }
13777
13778 static GstTagList *
qtdemux_add_container_format(GstQTDemux * qtdemux,GstTagList * tags)13779 qtdemux_add_container_format (GstQTDemux * qtdemux, GstTagList * tags)
13780 {
13781 const gchar *fmt;
13782
13783 if (tags == NULL) {
13784 tags = gst_tag_list_new_empty ();
13785 gst_tag_list_set_scope (tags, GST_TAG_SCOPE_GLOBAL);
13786 }
13787
13788 if (qtdemux->major_brand == FOURCC_mjp2)
13789 fmt = "Motion JPEG 2000";
13790 else if ((qtdemux->major_brand & 0xffff) == FOURCC_3g__)
13791 fmt = "3GP";
13792 else if (qtdemux->major_brand == FOURCC_qt__)
13793 fmt = "Quicktime";
13794 else if (qtdemux->fragmented)
13795 fmt = "ISO fMP4";
13796 else
13797 fmt = "ISO MP4/M4A";
13798
13799 GST_LOG_OBJECT (qtdemux, "mapped %" GST_FOURCC_FORMAT " to '%s'",
13800 GST_FOURCC_ARGS (qtdemux->major_brand), fmt);
13801
13802 gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_CONTAINER_FORMAT,
13803 fmt, NULL);
13804
13805 return tags;
13806 }
13807
13808 /* we have read the complete moov node now.
13809 * This function parses all of the relevant info, creates the traks and
13810 * prepares all data structures for playback
13811 */
13812 static gboolean
qtdemux_parse_tree(GstQTDemux * qtdemux)13813 qtdemux_parse_tree (GstQTDemux * qtdemux)
13814 {
13815 GNode *mvhd;
13816 GNode *trak;
13817 GNode *udta;
13818 GNode *mvex;
13819 GNode *pssh;
13820 guint64 creation_time;
13821 GstDateTime *datetime = NULL;
13822 gint version;
13823
13824 /* make sure we have a usable taglist */
13825 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
13826
13827 mvhd = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvhd);
13828 if (mvhd == NULL) {
13829 GST_LOG_OBJECT (qtdemux, "No mvhd node found, looking for redirects.");
13830 return qtdemux_parse_redirects (qtdemux);
13831 }
13832
13833 version = QT_UINT8 ((guint8 *) mvhd->data + 8);
13834 if (version == 1) {
13835 creation_time = QT_UINT64 ((guint8 *) mvhd->data + 12);
13836 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 28);
13837 qtdemux->duration = QT_UINT64 ((guint8 *) mvhd->data + 32);
13838 } else if (version == 0) {
13839 creation_time = QT_UINT32 ((guint8 *) mvhd->data + 12);
13840 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 20);
13841 qtdemux->duration = QT_UINT32 ((guint8 *) mvhd->data + 24);
13842 } else {
13843 GST_WARNING_OBJECT (qtdemux, "Unhandled mvhd version %d", version);
13844 return FALSE;
13845 }
13846
13847 /* Moving qt creation time (secs since 1904) to unix time */
13848 if (creation_time != 0) {
13849 /* Try to use epoch first as it should be faster and more commonly found */
13850 if (creation_time >= QTDEMUX_SECONDS_FROM_1904_TO_1970) {
13851 gint64 now_s;
13852
13853 creation_time -= QTDEMUX_SECONDS_FROM_1904_TO_1970;
13854 /* some data cleansing sanity */
13855 now_s = g_get_real_time () / G_USEC_PER_SEC;
13856 if (now_s + 24 * 3600 < creation_time) {
13857 GST_DEBUG_OBJECT (qtdemux, "discarding bogus future creation time");
13858 } else {
13859 datetime = gst_date_time_new_from_unix_epoch_utc (creation_time);
13860 }
13861 } else {
13862 GDateTime *base_dt = g_date_time_new_utc (1904, 1, 1, 0, 0, 0);
13863 GDateTime *dt, *dt_local;
13864
13865 dt = g_date_time_add_seconds (base_dt, creation_time);
13866 dt_local = g_date_time_to_local (dt);
13867 datetime = gst_date_time_new_from_g_date_time (dt_local);
13868
13869 g_date_time_unref (base_dt);
13870 g_date_time_unref (dt);
13871 }
13872 }
13873 if (datetime) {
13874 /* Use KEEP as explicit tags should have a higher priority than mvhd tag */
13875 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_KEEP, GST_TAG_DATE_TIME,
13876 datetime, NULL);
13877 gst_date_time_unref (datetime);
13878 }
13879
13880 GST_INFO_OBJECT (qtdemux, "timescale: %u", qtdemux->timescale);
13881 GST_INFO_OBJECT (qtdemux, "duration: %" G_GUINT64_FORMAT, qtdemux->duration);
13882
13883 /* check for fragmented file and get some (default) data */
13884 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
13885 if (mvex) {
13886 GNode *mehd;
13887 GstByteReader mehd_data;
13888
13889 /* let track parsing or anyone know weird stuff might happen ... */
13890 qtdemux->fragmented = TRUE;
13891
13892 /* compensate for total duration */
13893 mehd = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_mehd, &mehd_data);
13894 if (mehd)
13895 qtdemux_parse_mehd (qtdemux, &mehd_data);
13896 }
13897
13898 /* Update the movie segment duration, unless it was directly given to us
13899 * by upstream. Otherwise let it as is, as we don't want to mangle the
13900 * duration provided by upstream that may come e.g. from a MPD file. */
13901 if (!qtdemux->upstream_format_is_time) {
13902 GstClockTime duration;
13903 /* set duration in the segment info */
13904 gst_qtdemux_get_duration (qtdemux, &duration);
13905 qtdemux->segment.duration = duration;
13906 /* also do not exceed duration; stop is set that way post seek anyway,
13907 * and segment activation falls back to duration,
13908 * whereas loop only checks stop, so let's align this here as well */
13909 qtdemux->segment.stop = duration;
13910 }
13911
13912 /* parse all traks */
13913 trak = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_trak);
13914 while (trak) {
13915 qtdemux_parse_trak (qtdemux, trak);
13916 /* iterate all siblings */
13917 trak = qtdemux_tree_get_sibling_by_type (trak, FOURCC_trak);
13918 }
13919
13920 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
13921
13922 /* find tags */
13923 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_udta);
13924 if (udta) {
13925 qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
13926 } else {
13927 GST_LOG_OBJECT (qtdemux, "No udta node found.");
13928 }
13929
13930 /* maybe also some tags in meta box */
13931 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_meta);
13932 if (udta) {
13933 GST_DEBUG_OBJECT (qtdemux, "Parsing meta box for tags.");
13934 qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
13935 } else {
13936 GST_LOG_OBJECT (qtdemux, "No meta node found.");
13937 }
13938
13939 /* parse any protection system info */
13940 pssh = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_pssh);
13941 while (pssh) {
13942 GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
13943 qtdemux_parse_pssh (qtdemux, pssh);
13944 pssh = qtdemux_tree_get_sibling_by_type (pssh, FOURCC_pssh);
13945 }
13946
13947 qtdemux->tag_list = qtdemux_add_container_format (qtdemux, qtdemux->tag_list);
13948
13949 return TRUE;
13950 }
13951
13952 /* taken from ffmpeg */
13953 static int
read_descr_size(guint8 * ptr,guint8 * end,guint8 ** end_out)13954 read_descr_size (guint8 * ptr, guint8 * end, guint8 ** end_out)
13955 {
13956 int count = 4;
13957 int len = 0;
13958
13959 while (count--) {
13960 int c;
13961
13962 if (ptr >= end)
13963 return -1;
13964
13965 c = *ptr++;
13966 len = (len << 7) | (c & 0x7f);
13967 if (!(c & 0x80))
13968 break;
13969 }
13970 *end_out = ptr;
13971 return len;
13972 }
13973
13974 static GList *
parse_xiph_stream_headers(GstQTDemux * qtdemux,gpointer codec_data,gsize codec_data_size)13975 parse_xiph_stream_headers (GstQTDemux * qtdemux, gpointer codec_data,
13976 gsize codec_data_size)
13977 {
13978 GList *list = NULL;
13979 guint8 *p = codec_data;
13980 gint i, offset, num_packets;
13981 guint *length, last;
13982
13983 GST_MEMDUMP_OBJECT (qtdemux, "xiph codec data", codec_data, codec_data_size);
13984
13985 if (codec_data == NULL || codec_data_size == 0)
13986 goto error;
13987
13988 /* start of the stream and vorbis audio or theora video, need to
13989 * send the codec_priv data as first three packets */
13990 num_packets = p[0] + 1;
13991 GST_DEBUG_OBJECT (qtdemux,
13992 "%u stream headers, total length=%" G_GSIZE_FORMAT " bytes",
13993 (guint) num_packets, codec_data_size);
13994
13995 /* Let's put some limits, Don't think there even is a xiph codec
13996 * with more than 3-4 headers */
13997 if (G_UNLIKELY (num_packets > 16)) {
13998 GST_WARNING_OBJECT (qtdemux,
13999 "Unlikely number of xiph headers, most likely not valid");
14000 goto error;
14001 }
14002
14003 length = g_alloca (num_packets * sizeof (guint));
14004 last = 0;
14005 offset = 1;
14006
14007 /* first packets, read length values */
14008 for (i = 0; i < num_packets - 1; i++) {
14009 length[i] = 0;
14010 while (offset < codec_data_size) {
14011 length[i] += p[offset];
14012 if (p[offset++] != 0xff)
14013 break;
14014 }
14015 last += length[i];
14016 }
14017 if (offset + last > codec_data_size)
14018 goto error;
14019
14020 /* last packet is the remaining size */
14021 length[i] = codec_data_size - offset - last;
14022
14023 for (i = 0; i < num_packets; i++) {
14024 GstBuffer *hdr;
14025
14026 GST_DEBUG_OBJECT (qtdemux, "buffer %d: %u bytes", i, (guint) length[i]);
14027
14028 if (offset + length[i] > codec_data_size)
14029 goto error;
14030
14031 hdr = gst_buffer_new_memdup (p + offset, length[i]);
14032 list = g_list_append (list, hdr);
14033
14034 offset += length[i];
14035 }
14036
14037 return list;
14038
14039 /* ERRORS */
14040 error:
14041 {
14042 if (list != NULL)
14043 g_list_free_full (list, (GDestroyNotify) gst_buffer_unref);
14044 return NULL;
14045 }
14046
14047 }
14048
14049 /* this can change the codec originally present in @list */
14050 static void
gst_qtdemux_handle_esds(GstQTDemux * qtdemux,QtDemuxStream * stream,QtDemuxStreamStsdEntry * entry,GNode * esds,GstTagList * list)14051 gst_qtdemux_handle_esds (GstQTDemux * qtdemux, QtDemuxStream * stream,
14052 QtDemuxStreamStsdEntry * entry, GNode * esds, GstTagList * list)
14053 {
14054 int len = QT_UINT32 (esds->data);
14055 guint8 *ptr = esds->data;
14056 guint8 *end = ptr + len;
14057 int tag;
14058 guint8 *data_ptr = NULL;
14059 int data_len = 0;
14060 guint8 object_type_id = 0;
14061 guint8 stream_type = 0;
14062 const char *codec_name = NULL;
14063 GstCaps *caps = NULL;
14064
14065 GST_MEMDUMP_OBJECT (qtdemux, "esds", ptr, len);
14066 ptr += 8;
14067 GST_DEBUG_OBJECT (qtdemux, "version/flags = %08x", QT_UINT32 (ptr));
14068 ptr += 4;
14069 while (ptr + 1 < end) {
14070 tag = QT_UINT8 (ptr);
14071 GST_DEBUG_OBJECT (qtdemux, "tag = %02x", tag);
14072 ptr++;
14073 len = read_descr_size (ptr, end, &ptr);
14074 GST_DEBUG_OBJECT (qtdemux, "len = %d", len);
14075
14076 /* Check the stated amount of data is available for reading */
14077 if (len < 0 || ptr + len > end)
14078 break;
14079
14080 switch (tag) {
14081 case ES_DESCRIPTOR_TAG:
14082 GST_DEBUG_OBJECT (qtdemux, "ID 0x%04x", QT_UINT16 (ptr));
14083 GST_DEBUG_OBJECT (qtdemux, "priority 0x%04x", QT_UINT8 (ptr + 2));
14084 ptr += 3;
14085 break;
14086 case DECODER_CONFIG_DESC_TAG:{
14087 guint max_bitrate, avg_bitrate;
14088
14089 object_type_id = QT_UINT8 (ptr);
14090 stream_type = QT_UINT8 (ptr + 1) >> 2;
14091 max_bitrate = QT_UINT32 (ptr + 5);
14092 avg_bitrate = QT_UINT32 (ptr + 9);
14093 GST_DEBUG_OBJECT (qtdemux, "object_type_id %02x", object_type_id);
14094 GST_DEBUG_OBJECT (qtdemux, "stream_type %02x", stream_type);
14095 GST_DEBUG_OBJECT (qtdemux, "buffer_size_db %02x", QT_UINT24 (ptr + 2));
14096 GST_DEBUG_OBJECT (qtdemux, "max bitrate %u", max_bitrate);
14097 GST_DEBUG_OBJECT (qtdemux, "avg bitrate %u", avg_bitrate);
14098 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
14099 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
14100 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
14101 }
14102 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
14103 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
14104 avg_bitrate, NULL);
14105 }
14106 ptr += 13;
14107 break;
14108 }
14109 case DECODER_SPECIFIC_INFO_TAG:
14110 GST_MEMDUMP_OBJECT (qtdemux, "data", ptr, len);
14111 if (object_type_id == 0xe0 && len == 0x40) {
14112 guint8 *data;
14113 GstStructure *s;
14114 guint32 clut[16];
14115 gint i;
14116
14117 GST_DEBUG_OBJECT (qtdemux,
14118 "Have VOBSUB palette. Creating palette event");
14119 /* move to decConfigDescr data and read palette */
14120 data = ptr;
14121 for (i = 0; i < 16; i++) {
14122 clut[i] = QT_UINT32 (data);
14123 data += 4;
14124 }
14125
14126 s = gst_structure_new ("application/x-gst-dvd", "event",
14127 G_TYPE_STRING, "dvd-spu-clut-change",
14128 "clut00", G_TYPE_INT, clut[0], "clut01", G_TYPE_INT, clut[1],
14129 "clut02", G_TYPE_INT, clut[2], "clut03", G_TYPE_INT, clut[3],
14130 "clut04", G_TYPE_INT, clut[4], "clut05", G_TYPE_INT, clut[5],
14131 "clut06", G_TYPE_INT, clut[6], "clut07", G_TYPE_INT, clut[7],
14132 "clut08", G_TYPE_INT, clut[8], "clut09", G_TYPE_INT, clut[9],
14133 "clut10", G_TYPE_INT, clut[10], "clut11", G_TYPE_INT, clut[11],
14134 "clut12", G_TYPE_INT, clut[12], "clut13", G_TYPE_INT, clut[13],
14135 "clut14", G_TYPE_INT, clut[14], "clut15", G_TYPE_INT, clut[15],
14136 NULL);
14137
14138 /* store event and trigger custom processing */
14139 stream->pending_event =
14140 gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s);
14141 } else {
14142 /* Generic codec_data handler puts it on the caps */
14143 data_ptr = ptr;
14144 data_len = len;
14145 }
14146
14147 ptr += len;
14148 break;
14149 case SL_CONFIG_DESC_TAG:
14150 GST_DEBUG_OBJECT (qtdemux, "data %02x", QT_UINT8 (ptr));
14151 ptr += 1;
14152 break;
14153 default:
14154 GST_DEBUG_OBJECT (qtdemux, "Unknown/unhandled descriptor tag %02x",
14155 tag);
14156 GST_MEMDUMP_OBJECT (qtdemux, "descriptor data", ptr, len);
14157 ptr += len;
14158 break;
14159 }
14160 }
14161
14162 /* object_type_id in the esds atom in mp4a and mp4v tells us which codec is
14163 * in use, and should also be used to override some other parameters for some
14164 * codecs. */
14165 switch (object_type_id) {
14166 case 0x20: /* MPEG-4 */
14167 /* 4 bytes for the visual_object_sequence_start_code and 1 byte for the
14168 * profile_and_level_indication */
14169 if (data_ptr != NULL && data_len >= 5 &&
14170 GST_READ_UINT32_BE (data_ptr) == 0x000001b0) {
14171 gst_codec_utils_mpeg4video_caps_set_level_and_profile (entry->caps,
14172 data_ptr + 4, data_len - 4);
14173 }
14174 break; /* Nothing special needed here */
14175 case 0x21: /* H.264 */
14176 codec_name = "H.264 / AVC";
14177 caps = gst_caps_new_simple ("video/x-h264",
14178 "stream-format", G_TYPE_STRING, "avc",
14179 "alignment", G_TYPE_STRING, "au", NULL);
14180 break;
14181 case 0x40: /* AAC (any) */
14182 case 0x66: /* AAC Main */
14183 case 0x67: /* AAC LC */
14184 case 0x68: /* AAC SSR */
14185 /* Override channels and rate based on the codec_data, as it's often
14186 * wrong. */
14187 /* Only do so for basic setup without HE-AAC extension */
14188 #ifdef OHOS_OPT_COMPAT
14189 /*
14190 * ohos.opt.compat.0030
14191 * sampling rate is get wrong, in special code flow
14192 */
14193 if (data_ptr && data_len >= 2) {
14194 #else
14195 if (data_ptr && data_len == 2) {
14196 #endif
14197 guint channels, rate;
14198
14199 channels = gst_codec_utils_aac_get_channels (data_ptr, data_len);
14200 if (channels > 0)
14201 entry->n_channels = channels;
14202
14203 rate = gst_codec_utils_aac_get_sample_rate (data_ptr, data_len);
14204 if (rate > 0)
14205 entry->rate = rate;
14206 }
14207
14208 /* Set level and profile if possible */
14209 if (data_ptr != NULL && data_len >= 2) {
14210 gst_codec_utils_aac_caps_set_level_and_profile (entry->caps,
14211 data_ptr, data_len);
14212 } else {
14213 const gchar *profile_str = NULL;
14214 GstBuffer *buffer;
14215 GstMapInfo map;
14216 guint8 *codec_data;
14217 gint rate_idx, profile;
14218
14219 /* No codec_data, let's invent something.
14220 * FIXME: This is wrong for SBR! */
14221
14222 GST_WARNING_OBJECT (qtdemux, "No codec_data for AAC available");
14223
14224 buffer = gst_buffer_new_and_alloc (2);
14225 gst_buffer_map (buffer, &map, GST_MAP_WRITE);
14226 codec_data = map.data;
14227
14228 rate_idx =
14229 gst_codec_utils_aac_get_index_from_sample_rate (CUR_STREAM
14230 (stream)->rate);
14231
14232 switch (object_type_id) {
14233 case 0x66:
14234 profile_str = "main";
14235 profile = 0;
14236 break;
14237 case 0x67:
14238 profile_str = "lc";
14239 profile = 1;
14240 break;
14241 case 0x68:
14242 profile_str = "ssr";
14243 profile = 2;
14244 break;
14245 default:
14246 profile = 3;
14247 break;
14248 }
14249
14250 codec_data[0] = ((profile + 1) << 3) | ((rate_idx & 0xE) >> 1);
14251 codec_data[1] =
14252 ((rate_idx & 0x1) << 7) | (CUR_STREAM (stream)->n_channels << 3);
14253
14254 gst_buffer_unmap (buffer, &map);
14255 gst_caps_set_simple (CUR_STREAM (stream)->caps, "codec_data",
14256 GST_TYPE_BUFFER, buffer, NULL);
14257 gst_buffer_unref (buffer);
14258
14259 if (profile_str) {
14260 gst_caps_set_simple (CUR_STREAM (stream)->caps, "profile",
14261 G_TYPE_STRING, profile_str, NULL);
14262 }
14263 }
14264 break;
14265 case 0x60: /* MPEG-2, various profiles */
14266 case 0x61:
14267 case 0x62:
14268 case 0x63:
14269 case 0x64:
14270 case 0x65:
14271 codec_name = "MPEG-2 video";
14272 caps = gst_caps_new_simple ("video/mpeg",
14273 "mpegversion", G_TYPE_INT, 2,
14274 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14275 break;
14276 case 0x69: /* MPEG-2 BC audio */
14277 case 0x6B: /* MPEG-1 audio */
14278 caps = gst_caps_new_simple ("audio/mpeg",
14279 "mpegversion", G_TYPE_INT, 1, NULL);
14280 codec_name = "MPEG-1 audio";
14281 break;
14282 case 0x6A: /* MPEG-1 */
14283 codec_name = "MPEG-1 video";
14284 caps = gst_caps_new_simple ("video/mpeg",
14285 "mpegversion", G_TYPE_INT, 1,
14286 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14287 break;
14288 case 0x6C: /* MJPEG */
14289 caps =
14290 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
14291 NULL);
14292 codec_name = "Motion-JPEG";
14293 break;
14294 case 0x6D: /* PNG */
14295 caps =
14296 gst_caps_new_simple ("image/png", "parsed", G_TYPE_BOOLEAN, TRUE,
14297 NULL);
14298 codec_name = "PNG still images";
14299 break;
14300 case 0x6E: /* JPEG2000 */
14301 codec_name = "JPEG-2000";
14302 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
14303 break;
14304 case 0xA4: /* Dirac */
14305 codec_name = "Dirac";
14306 caps = gst_caps_new_empty_simple ("video/x-dirac");
14307 break;
14308 case 0xA5: /* AC3 */
14309 codec_name = "AC-3 audio";
14310 caps = gst_caps_new_simple ("audio/x-ac3",
14311 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14312 break;
14313 case 0xA9: /* AC3 */
14314 codec_name = "DTS audio";
14315 caps = gst_caps_new_simple ("audio/x-dts",
14316 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14317 break;
14318 case 0xDD:
14319 if (stream_type == 0x05 && data_ptr) {
14320 GList *headers =
14321 parse_xiph_stream_headers (qtdemux, data_ptr, data_len);
14322 if (headers) {
14323 GList *tmp;
14324 GValue arr_val = G_VALUE_INIT;
14325 GValue buf_val = G_VALUE_INIT;
14326 GstStructure *s;
14327
14328 /* Let's assume it's vorbis if it's an audio stream of type 0xdd and we have codec data that extracts properly */
14329 codec_name = "Vorbis";
14330 caps = gst_caps_new_empty_simple ("audio/x-vorbis");
14331 #ifdef OHOS_OPT_COMPAT
14332 // ohos.opt.compat.0031. adapter for avdec_vorbis
14333 GstBuffer *codec_data = gst_buffer_new_allocate (NULL, data_len, NULL);
14334 if (codec_data != NULL) {
14335 gst_buffer_fill (codec_data, 0, data_ptr, data_len);
14336 gst_caps_set_simple (caps, "codec_data", GST_TYPE_BUFFER, codec_data, NULL);
14337 gst_buffer_unref (codec_data);
14338 } else {
14339 GST_ERROR_OBJECT (qtdemux, "gst_buffer_new_wrapped failed");
14340 }
14341 #endif
14342 g_value_init (&arr_val, GST_TYPE_ARRAY);
14343 g_value_init (&buf_val, GST_TYPE_BUFFER);
14344 for (tmp = headers; tmp; tmp = tmp->next) {
14345 g_value_set_boxed (&buf_val, (GstBuffer *) tmp->data);
14346 gst_value_array_append_value (&arr_val, &buf_val);
14347 }
14348 s = gst_caps_get_structure (caps, 0);
14349 gst_structure_take_value (s, "streamheader", &arr_val);
14350 g_value_unset (&buf_val);
14351 g_list_free (headers);
14352
14353 data_ptr = NULL;
14354 data_len = 0;
14355 }
14356 }
14357 break;
14358 case 0xE1: /* QCELP */
14359 /* QCELP, the codec_data is a riff tag (little endian) with
14360 * 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). */
14361 caps = gst_caps_new_empty_simple ("audio/qcelp");
14362 codec_name = "QCELP";
14363 break;
14364 default:
14365 break;
14366 }
14367
14368 /* If we have a replacement caps, then change our caps for this stream */
14369 if (caps) {
14370 gst_caps_unref (entry->caps);
14371 entry->caps = caps;
14372 }
14373
14374 if (codec_name && list)
14375 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
14376 GST_TAG_AUDIO_CODEC, codec_name, NULL);
14377
14378 /* Add the codec_data attribute to caps, if we have it */
14379 if (data_ptr) {
14380 GstBuffer *buffer;
14381
14382 buffer = gst_buffer_new_and_alloc (data_len);
14383 gst_buffer_fill (buffer, 0, data_ptr, data_len);
14384
14385 GST_DEBUG_OBJECT (qtdemux, "setting codec_data from esds");
14386 GST_MEMDUMP_OBJECT (qtdemux, "codec_data from esds", data_ptr, data_len);
14387
14388 gst_caps_set_simple (entry->caps, "codec_data", GST_TYPE_BUFFER,
14389 buffer, NULL);
14390 gst_buffer_unref (buffer);
14391 }
14392
14393 }
14394
14395 static inline GstCaps *
14396 _get_unknown_codec_name (const gchar * type, guint32 fourcc)
14397 {
14398 GstCaps *caps;
14399 guint i;
14400 char *s, fourstr[5];
14401
14402 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
14403 for (i = 0; i < 4; i++) {
14404 if (!g_ascii_isalnum (fourstr[i]))
14405 fourstr[i] = '_';
14406 }
14407 s = g_strdup_printf ("%s/x-gst-fourcc-%s", type, g_strstrip (fourstr));
14408 caps = gst_caps_new_empty_simple (s);
14409 g_free (s);
14410 return caps;
14411 }
14412
14413 #define _codec(name) \
14414 do { \
14415 if (codec_name) { \
14416 *codec_name = g_strdup (name); \
14417 } \
14418 } while (0)
14419
14420 static GstCaps *
14421 qtdemux_video_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
14422 QtDemuxStreamStsdEntry * entry, guint32 fourcc,
14423 const guint8 * stsd_entry_data, gchar ** codec_name)
14424 {
14425 GstCaps *caps = NULL;
14426 GstVideoFormat format = GST_VIDEO_FORMAT_UNKNOWN;
14427
14428 switch (fourcc) {
14429 case FOURCC_png:
14430 _codec ("PNG still images");
14431 caps = gst_caps_new_empty_simple ("image/png");
14432 break;
14433 case FOURCC_jpeg:
14434 _codec ("JPEG still images");
14435 caps =
14436 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
14437 NULL);
14438 break;
14439 case GST_MAKE_FOURCC ('m', 'j', 'p', 'a'):
14440 case GST_MAKE_FOURCC ('A', 'V', 'D', 'J'):
14441 case GST_MAKE_FOURCC ('M', 'J', 'P', 'G'):
14442 case GST_MAKE_FOURCC ('d', 'm', 'b', '1'):
14443 _codec ("Motion-JPEG");
14444 caps =
14445 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
14446 NULL);
14447 break;
14448 case GST_MAKE_FOURCC ('m', 'j', 'p', 'b'):
14449 _codec ("Motion-JPEG format B");
14450 caps = gst_caps_new_empty_simple ("video/x-mjpeg-b");
14451 break;
14452 case FOURCC_mjp2:
14453 _codec ("JPEG-2000");
14454 /* override to what it should be according to spec, avoid palette_data */
14455 entry->bits_per_sample = 24;
14456 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
14457 break;
14458 case FOURCC_SVQ3:
14459 _codec ("Sorensen video v.3");
14460 caps = gst_caps_new_simple ("video/x-svq",
14461 "svqversion", G_TYPE_INT, 3, NULL);
14462 break;
14463 case GST_MAKE_FOURCC ('s', 'v', 'q', 'i'):
14464 case GST_MAKE_FOURCC ('S', 'V', 'Q', '1'):
14465 _codec ("Sorensen video v.1");
14466 caps = gst_caps_new_simple ("video/x-svq",
14467 "svqversion", G_TYPE_INT, 1, NULL);
14468 break;
14469 case GST_MAKE_FOURCC ('W', 'R', 'A', 'W'):
14470 caps = gst_caps_new_empty_simple ("video/x-raw");
14471 gst_caps_set_simple (caps, "format", G_TYPE_STRING, "RGB8P", NULL);
14472 _codec ("Windows Raw RGB");
14473 stream->alignment = 32;
14474 break;
14475 case FOURCC_raw_:
14476 {
14477 guint16 bps;
14478
14479 bps = QT_UINT16 (stsd_entry_data + 82);
14480 switch (bps) {
14481 case 15:
14482 format = GST_VIDEO_FORMAT_RGB15;
14483 break;
14484 case 16:
14485 format = GST_VIDEO_FORMAT_RGB16;
14486 break;
14487 case 24:
14488 format = GST_VIDEO_FORMAT_RGB;
14489 break;
14490 case 32:
14491 format = GST_VIDEO_FORMAT_ARGB;
14492 break;
14493 default:
14494 /* unknown */
14495 break;
14496 }
14497 break;
14498 }
14499 case GST_MAKE_FOURCC ('y', 'v', '1', '2'):
14500 format = GST_VIDEO_FORMAT_I420;
14501 break;
14502 case GST_MAKE_FOURCC ('y', 'u', 'v', '2'):
14503 case GST_MAKE_FOURCC ('Y', 'u', 'v', '2'):
14504 format = GST_VIDEO_FORMAT_I420;
14505 break;
14506 case FOURCC_2vuy:
14507 case GST_MAKE_FOURCC ('2', 'V', 'u', 'y'):
14508 format = GST_VIDEO_FORMAT_UYVY;
14509 break;
14510 case GST_MAKE_FOURCC ('v', '3', '0', '8'):
14511 format = GST_VIDEO_FORMAT_v308;
14512 break;
14513 case GST_MAKE_FOURCC ('v', '2', '1', '6'):
14514 format = GST_VIDEO_FORMAT_v216;
14515 break;
14516 case FOURCC_v210:
14517 format = GST_VIDEO_FORMAT_v210;
14518 break;
14519 case GST_MAKE_FOURCC ('r', '2', '1', '0'):
14520 format = GST_VIDEO_FORMAT_r210;
14521 break;
14522 /* Packed YUV 4:4:4 10 bit in 32 bits, complex
14523 case GST_MAKE_FOURCC ('v', '4', '1', '0'):
14524 format = GST_VIDEO_FORMAT_v410;
14525 break;
14526 */
14527 /* Packed YUV 4:4:4:4 8 bit in 32 bits
14528 * but different order than AYUV
14529 case GST_MAKE_FOURCC ('v', '4', '0', '8'):
14530 format = GST_VIDEO_FORMAT_v408;
14531 break;
14532 */
14533 case GST_MAKE_FOURCC ('m', 'p', 'e', 'g'):
14534 case GST_MAKE_FOURCC ('m', 'p', 'g', '1'):
14535 _codec ("MPEG-1 video");
14536 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
14537 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14538 break;
14539 case GST_MAKE_FOURCC ('h', 'd', 'v', '1'): /* HDV 720p30 */
14540 case GST_MAKE_FOURCC ('h', 'd', 'v', '2'): /* HDV 1080i60 */
14541 case GST_MAKE_FOURCC ('h', 'd', 'v', '3'): /* HDV 1080i50 */
14542 case GST_MAKE_FOURCC ('h', 'd', 'v', '4'): /* HDV 720p24 */
14543 case GST_MAKE_FOURCC ('h', 'd', 'v', '5'): /* HDV 720p25 */
14544 case GST_MAKE_FOURCC ('h', 'd', 'v', '6'): /* HDV 1080p24 */
14545 case GST_MAKE_FOURCC ('h', 'd', 'v', '7'): /* HDV 1080p25 */
14546 case GST_MAKE_FOURCC ('h', 'd', 'v', '8'): /* HDV 1080p30 */
14547 case GST_MAKE_FOURCC ('h', 'd', 'v', '9'): /* HDV 720p60 */
14548 case GST_MAKE_FOURCC ('h', 'd', 'v', 'a'): /* HDV 720p50 */
14549 case GST_MAKE_FOURCC ('m', 'x', '5', 'n'): /* MPEG2 IMX NTSC 525/60 50mb/s produced by FCP */
14550 case GST_MAKE_FOURCC ('m', 'x', '5', 'p'): /* MPEG2 IMX PAL 625/60 50mb/s produced by FCP */
14551 case GST_MAKE_FOURCC ('m', 'x', '4', 'n'): /* MPEG2 IMX NTSC 525/60 40mb/s produced by FCP */
14552 case GST_MAKE_FOURCC ('m', 'x', '4', 'p'): /* MPEG2 IMX PAL 625/60 40mb/s produced by FCP */
14553 case GST_MAKE_FOURCC ('m', 'x', '3', 'n'): /* MPEG2 IMX NTSC 525/60 30mb/s produced by FCP */
14554 case GST_MAKE_FOURCC ('m', 'x', '3', 'p'): /* MPEG2 IMX PAL 625/50 30mb/s produced by FCP */
14555 case GST_MAKE_FOURCC ('x', 'd', 'v', '1'): /* XDCAM HD 720p30 35Mb/s */
14556 case GST_MAKE_FOURCC ('x', 'd', 'v', '2'): /* XDCAM HD 1080i60 35Mb/s */
14557 case GST_MAKE_FOURCC ('x', 'd', 'v', '3'): /* XDCAM HD 1080i50 35Mb/s */
14558 case GST_MAKE_FOURCC ('x', 'd', 'v', '4'): /* XDCAM HD 720p24 35Mb/s */
14559 case GST_MAKE_FOURCC ('x', 'd', 'v', '5'): /* XDCAM HD 720p25 35Mb/s */
14560 case GST_MAKE_FOURCC ('x', 'd', 'v', '6'): /* XDCAM HD 1080p24 35Mb/s */
14561 case GST_MAKE_FOURCC ('x', 'd', 'v', '7'): /* XDCAM HD 1080p25 35Mb/s */
14562 case GST_MAKE_FOURCC ('x', 'd', 'v', '8'): /* XDCAM HD 1080p30 35Mb/s */
14563 case GST_MAKE_FOURCC ('x', 'd', 'v', '9'): /* XDCAM HD 720p60 35Mb/s */
14564 case GST_MAKE_FOURCC ('x', 'd', 'v', 'a'): /* XDCAM HD 720p50 35Mb/s */
14565 case GST_MAKE_FOURCC ('x', 'd', 'v', 'b'): /* XDCAM EX 1080i60 50Mb/s CBR */
14566 case GST_MAKE_FOURCC ('x', 'd', 'v', 'c'): /* XDCAM EX 1080i50 50Mb/s CBR */
14567 case GST_MAKE_FOURCC ('x', 'd', 'v', 'd'): /* XDCAM HD 1080p24 50Mb/s CBR */
14568 case GST_MAKE_FOURCC ('x', 'd', 'v', 'e'): /* XDCAM HD 1080p25 50Mb/s CBR */
14569 case GST_MAKE_FOURCC ('x', 'd', 'v', 'f'): /* XDCAM HD 1080p30 50Mb/s CBR */
14570 case GST_MAKE_FOURCC ('x', 'd', '5', '1'): /* XDCAM HD422 720p30 50Mb/s CBR */
14571 case GST_MAKE_FOURCC ('x', 'd', '5', '4'): /* XDCAM HD422 720p24 50Mb/s CBR */
14572 case GST_MAKE_FOURCC ('x', 'd', '5', '5'): /* XDCAM HD422 720p25 50Mb/s CBR */
14573 case GST_MAKE_FOURCC ('x', 'd', '5', '9'): /* XDCAM HD422 720p60 50Mb/s CBR */
14574 case GST_MAKE_FOURCC ('x', 'd', '5', 'a'): /* XDCAM HD422 720p50 50Mb/s CBR */
14575 case GST_MAKE_FOURCC ('x', 'd', '5', 'b'): /* XDCAM HD422 1080i50 50Mb/s CBR */
14576 case GST_MAKE_FOURCC ('x', 'd', '5', 'c'): /* XDCAM HD422 1080i50 50Mb/s CBR */
14577 case GST_MAKE_FOURCC ('x', 'd', '5', 'd'): /* XDCAM HD422 1080p24 50Mb/s CBR */
14578 case GST_MAKE_FOURCC ('x', 'd', '5', 'e'): /* XDCAM HD422 1080p25 50Mb/s CBR */
14579 case GST_MAKE_FOURCC ('x', 'd', '5', 'f'): /* XDCAM HD422 1080p30 50Mb/s CBR */
14580 case GST_MAKE_FOURCC ('x', 'd', 'h', 'd'): /* XDCAM HD 540p */
14581 case GST_MAKE_FOURCC ('x', 'd', 'h', '2'): /* XDCAM HD422 540p */
14582 case GST_MAKE_FOURCC ('A', 'V', 'm', 'p'): /* AVID IMX PAL */
14583 case GST_MAKE_FOURCC ('m', 'p', 'g', '2'): /* AVID IMX PAL */
14584 case GST_MAKE_FOURCC ('m', 'p', '2', 'v'): /* AVID IMX PAL */
14585 case GST_MAKE_FOURCC ('m', '2', 'v', '1'):
14586 _codec ("MPEG-2 video");
14587 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 2,
14588 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14589 break;
14590 case GST_MAKE_FOURCC ('g', 'i', 'f', ' '):
14591 _codec ("GIF still images");
14592 caps = gst_caps_new_empty_simple ("image/gif");
14593 break;
14594 case FOURCC_h263:
14595 case GST_MAKE_FOURCC ('H', '2', '6', '3'):
14596 case FOURCC_s263:
14597 case GST_MAKE_FOURCC ('U', '2', '6', '3'):
14598 _codec ("H.263");
14599 /* ffmpeg uses the height/width props, don't know why */
14600 caps = gst_caps_new_simple ("video/x-h263",
14601 "variant", G_TYPE_STRING, "itu", NULL);
14602 break;
14603 case FOURCC_mp4v:
14604 case FOURCC_MP4V:
14605 _codec ("MPEG-4 video");
14606 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
14607 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14608 break;
14609 case GST_MAKE_FOURCC ('3', 'i', 'v', 'd'):
14610 case GST_MAKE_FOURCC ('3', 'I', 'V', 'D'):
14611 _codec ("Microsoft MPEG-4 4.3"); /* FIXME? */
14612 caps = gst_caps_new_simple ("video/x-msmpeg",
14613 "msmpegversion", G_TYPE_INT, 43, NULL);
14614 break;
14615 case GST_MAKE_FOURCC ('D', 'I', 'V', '3'):
14616 _codec ("DivX 3");
14617 caps = gst_caps_new_simple ("video/x-divx",
14618 "divxversion", G_TYPE_INT, 3, NULL);
14619 break;
14620 case GST_MAKE_FOURCC ('D', 'I', 'V', 'X'):
14621 case GST_MAKE_FOURCC ('d', 'i', 'v', 'x'):
14622 _codec ("DivX 4");
14623 caps = gst_caps_new_simple ("video/x-divx",
14624 "divxversion", G_TYPE_INT, 4, NULL);
14625 break;
14626 case GST_MAKE_FOURCC ('D', 'X', '5', '0'):
14627 _codec ("DivX 5");
14628 caps = gst_caps_new_simple ("video/x-divx",
14629 "divxversion", G_TYPE_INT, 5, NULL);
14630 break;
14631
14632 case GST_MAKE_FOURCC ('F', 'F', 'V', '1'):
14633 _codec ("FFV1");
14634 caps = gst_caps_new_simple ("video/x-ffv",
14635 "ffvversion", G_TYPE_INT, 1, NULL);
14636 break;
14637
14638 case GST_MAKE_FOURCC ('3', 'I', 'V', '1'):
14639 case GST_MAKE_FOURCC ('3', 'I', 'V', '2'):
14640 case FOURCC_XVID:
14641 case FOURCC_xvid:
14642 case FOURCC_FMP4:
14643 case FOURCC_fmp4:
14644 case GST_MAKE_FOURCC ('U', 'M', 'P', '4'):
14645 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
14646 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14647 _codec ("MPEG-4");
14648 break;
14649
14650 case GST_MAKE_FOURCC ('c', 'v', 'i', 'd'):
14651 _codec ("Cinepak");
14652 caps = gst_caps_new_empty_simple ("video/x-cinepak");
14653 break;
14654 case GST_MAKE_FOURCC ('q', 'd', 'r', 'w'):
14655 _codec ("Apple QuickDraw");
14656 caps = gst_caps_new_empty_simple ("video/x-qdrw");
14657 break;
14658 case GST_MAKE_FOURCC ('r', 'p', 'z', 'a'):
14659 _codec ("Apple video");
14660 caps = gst_caps_new_empty_simple ("video/x-apple-video");
14661 break;
14662 case FOURCC_H264:
14663 case FOURCC_avc1:
14664 case FOURCC_dva1:
14665 _codec ("H.264 / AVC");
14666 caps = gst_caps_new_simple ("video/x-h264",
14667 "stream-format", G_TYPE_STRING, "avc",
14668 "alignment", G_TYPE_STRING, "au", NULL);
14669 break;
14670 case FOURCC_avc3:
14671 case FOURCC_dvav:
14672 _codec ("H.264 / AVC");
14673 caps = gst_caps_new_simple ("video/x-h264",
14674 "stream-format", G_TYPE_STRING, "avc3",
14675 "alignment", G_TYPE_STRING, "au", NULL);
14676 break;
14677 case FOURCC_H265:
14678 case FOURCC_hvc1:
14679 case FOURCC_dvh1:
14680 _codec ("H.265 / HEVC");
14681 caps = gst_caps_new_simple ("video/x-h265",
14682 "stream-format", G_TYPE_STRING, "hvc1",
14683 "alignment", G_TYPE_STRING, "au", NULL);
14684 break;
14685 case FOURCC_hev1:
14686 case FOURCC_dvhe:
14687 _codec ("H.265 / HEVC");
14688 caps = gst_caps_new_simple ("video/x-h265",
14689 "stream-format", G_TYPE_STRING, "hev1",
14690 "alignment", G_TYPE_STRING, "au", NULL);
14691 break;
14692 case FOURCC_rle_:
14693 _codec ("Run-length encoding");
14694 caps = gst_caps_new_simple ("video/x-rle",
14695 "layout", G_TYPE_STRING, "quicktime", NULL);
14696 break;
14697 case FOURCC_WRLE:
14698 _codec ("Run-length encoding");
14699 caps = gst_caps_new_simple ("video/x-rle",
14700 "layout", G_TYPE_STRING, "microsoft", NULL);
14701 break;
14702 case GST_MAKE_FOURCC ('I', 'V', '3', '2'):
14703 case GST_MAKE_FOURCC ('i', 'v', '3', '2'):
14704 _codec ("Indeo Video 3");
14705 caps = gst_caps_new_simple ("video/x-indeo",
14706 "indeoversion", G_TYPE_INT, 3, NULL);
14707 break;
14708 case GST_MAKE_FOURCC ('I', 'V', '4', '1'):
14709 case GST_MAKE_FOURCC ('i', 'v', '4', '1'):
14710 _codec ("Intel Video 4");
14711 caps = gst_caps_new_simple ("video/x-indeo",
14712 "indeoversion", G_TYPE_INT, 4, NULL);
14713 break;
14714 case FOURCC_dvcp:
14715 case FOURCC_dvc_:
14716 case GST_MAKE_FOURCC ('d', 'v', 's', 'd'):
14717 case GST_MAKE_FOURCC ('D', 'V', 'S', 'D'):
14718 case GST_MAKE_FOURCC ('d', 'v', 'c', 's'):
14719 case GST_MAKE_FOURCC ('D', 'V', 'C', 'S'):
14720 case GST_MAKE_FOURCC ('d', 'v', '2', '5'):
14721 case GST_MAKE_FOURCC ('d', 'v', 'p', 'p'):
14722 _codec ("DV Video");
14723 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 25,
14724 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14725 break;
14726 case FOURCC_dv5n: /* DVCPRO50 NTSC */
14727 case FOURCC_dv5p: /* DVCPRO50 PAL */
14728 _codec ("DVCPro50 Video");
14729 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 50,
14730 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14731 break;
14732 case GST_MAKE_FOURCC ('d', 'v', 'h', '5'): /* DVCPRO HD 50i produced by FCP */
14733 case GST_MAKE_FOURCC ('d', 'v', 'h', '6'): /* DVCPRO HD 60i produced by FCP */
14734 _codec ("DVCProHD Video");
14735 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 100,
14736 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14737 break;
14738 case GST_MAKE_FOURCC ('s', 'm', 'c', ' '):
14739 _codec ("Apple Graphics (SMC)");
14740 caps = gst_caps_new_empty_simple ("video/x-smc");
14741 break;
14742 case GST_MAKE_FOURCC ('V', 'P', '3', '1'):
14743 _codec ("VP3");
14744 caps = gst_caps_new_empty_simple ("video/x-vp3");
14745 break;
14746 case GST_MAKE_FOURCC ('V', 'P', '6', 'F'):
14747 _codec ("VP6 Flash");
14748 caps = gst_caps_new_empty_simple ("video/x-vp6-flash");
14749 break;
14750 case FOURCC_XiTh:
14751 _codec ("Theora");
14752 caps = gst_caps_new_empty_simple ("video/x-theora");
14753 /* theora uses one byte of padding in the data stream because it does not
14754 * allow 0 sized packets while theora does */
14755 entry->padding = 1;
14756 break;
14757 case FOURCC_drac:
14758 _codec ("Dirac");
14759 caps = gst_caps_new_empty_simple ("video/x-dirac");
14760 break;
14761 case GST_MAKE_FOURCC ('t', 'i', 'f', 'f'):
14762 _codec ("TIFF still images");
14763 caps = gst_caps_new_empty_simple ("image/tiff");
14764 break;
14765 case GST_MAKE_FOURCC ('i', 'c', 'o', 'd'):
14766 _codec ("Apple Intermediate Codec");
14767 caps = gst_caps_from_string ("video/x-apple-intermediate-codec");
14768 break;
14769 case GST_MAKE_FOURCC ('A', 'V', 'd', 'n'):
14770 _codec ("AVID DNxHD");
14771 caps = gst_caps_from_string ("video/x-dnxhd");
14772 break;
14773 case FOURCC_VP80:
14774 case FOURCC_vp08:
14775 _codec ("On2 VP8");
14776 caps = gst_caps_from_string ("video/x-vp8");
14777 break;
14778 case FOURCC_vp09:
14779 _codec ("Google VP9");
14780 caps = gst_caps_from_string ("video/x-vp9");
14781 break;
14782 case FOURCC_apcs:
14783 _codec ("Apple ProRes LT");
14784 caps =
14785 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "lt",
14786 NULL);
14787 break;
14788 case FOURCC_apch:
14789 _codec ("Apple ProRes HQ");
14790 caps =
14791 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "hq",
14792 NULL);
14793 break;
14794 case FOURCC_apcn:
14795 _codec ("Apple ProRes");
14796 caps =
14797 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14798 "standard", NULL);
14799 break;
14800 case FOURCC_apco:
14801 _codec ("Apple ProRes Proxy");
14802 caps =
14803 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14804 "proxy", NULL);
14805 break;
14806 case FOURCC_ap4h:
14807 _codec ("Apple ProRes 4444");
14808 caps =
14809 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14810 "4444", NULL);
14811
14812 /* 24 bits per sample = an alpha channel is coded but image is always opaque */
14813 if (entry->bits_per_sample > 0) {
14814 gst_caps_set_simple (caps, "depth", G_TYPE_INT, entry->bits_per_sample,
14815 NULL);
14816 }
14817 break;
14818 case FOURCC_ap4x:
14819 _codec ("Apple ProRes 4444 XQ");
14820 caps =
14821 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14822 "4444xq", NULL);
14823
14824 /* 24 bits per sample = an alpha channel is coded but image is always opaque */
14825 if (entry->bits_per_sample > 0) {
14826 gst_caps_set_simple (caps, "depth", G_TYPE_INT, entry->bits_per_sample,
14827 NULL);
14828 }
14829 break;
14830 case FOURCC_cfhd:
14831 _codec ("GoPro CineForm");
14832 caps = gst_caps_from_string ("video/x-cineform");
14833 break;
14834 case FOURCC_vc_1:
14835 case FOURCC_ovc1:
14836 _codec ("VC-1");
14837 caps = gst_caps_new_simple ("video/x-wmv",
14838 "wmvversion", G_TYPE_INT, 3, "format", G_TYPE_STRING, "WVC1", NULL);
14839 break;
14840 case FOURCC_av01:
14841 _codec ("AV1");
14842 caps = gst_caps_new_empty_simple ("video/x-av1");
14843 break;
14844 case GST_MAKE_FOURCC ('k', 'p', 'c', 'd'):
14845 default:
14846 {
14847 caps = _get_unknown_codec_name ("video", fourcc);
14848 break;
14849 }
14850 }
14851
14852 if (format != GST_VIDEO_FORMAT_UNKNOWN) {
14853 GstVideoInfo info;
14854
14855 gst_video_info_init (&info);
14856 gst_video_info_set_format (&info, format, entry->width, entry->height);
14857
14858 caps = gst_video_info_to_caps (&info);
14859 *codec_name = gst_pb_utils_get_codec_description (caps);
14860
14861 /* enable clipping for raw video streams */
14862 stream->need_clip = TRUE;
14863 stream->alignment = 32;
14864 }
14865
14866 return caps;
14867 }
14868
14869 static guint
14870 round_up_pow2 (guint n)
14871 {
14872 n = n - 1;
14873 n = n | (n >> 1);
14874 n = n | (n >> 2);
14875 n = n | (n >> 4);
14876 n = n | (n >> 8);
14877 n = n | (n >> 16);
14878 return n + 1;
14879 }
14880
14881 static GstCaps *
14882 qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
14883 QtDemuxStreamStsdEntry * entry, guint32 fourcc, const guint8 * data,
14884 int len, gchar ** codec_name)
14885 {
14886 GstCaps *caps;
14887 const GstStructure *s;
14888 const gchar *name;
14889 gint endian = 0;
14890 GstAudioFormat format = 0;
14891 gint depth;
14892
14893 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
14894
14895 depth = entry->bytes_per_packet * 8;
14896
14897 switch (fourcc) {
14898 case GST_MAKE_FOURCC ('N', 'O', 'N', 'E'):
14899 case FOURCC_raw_:
14900 /* 8-bit audio is unsigned */
14901 if (depth == 8)
14902 format = GST_AUDIO_FORMAT_U8;
14903 /* otherwise it's signed and big-endian just like 'twos' */
14904 case FOURCC_twos:
14905 endian = G_BIG_ENDIAN;
14906 /* fall-through */
14907 case FOURCC_sowt:
14908 {
14909 gchar *str;
14910
14911 if (!endian)
14912 endian = G_LITTLE_ENDIAN;
14913
14914 if (!format)
14915 format = gst_audio_format_build_integer (TRUE, endian, depth, depth);
14916
14917 str = g_strdup_printf ("Raw %d-bit PCM audio", depth);
14918 _codec (str);
14919 g_free (str);
14920
14921 caps = gst_caps_new_simple ("audio/x-raw",
14922 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
14923 "layout", G_TYPE_STRING, "interleaved", NULL);
14924 stream->alignment = GST_ROUND_UP_8 (depth);
14925 stream->alignment = round_up_pow2 (stream->alignment);
14926 break;
14927 }
14928 case FOURCC_fl64:
14929 _codec ("Raw 64-bit floating-point audio");
14930 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
14931 * endian later */
14932 caps = gst_caps_new_simple ("audio/x-raw",
14933 "format", G_TYPE_STRING, "F64BE",
14934 "layout", G_TYPE_STRING, "interleaved", NULL);
14935 stream->alignment = 8;
14936 break;
14937 case FOURCC_fl32:
14938 _codec ("Raw 32-bit floating-point audio");
14939 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
14940 * endian later */
14941 caps = gst_caps_new_simple ("audio/x-raw",
14942 "format", G_TYPE_STRING, "F32BE",
14943 "layout", G_TYPE_STRING, "interleaved", NULL);
14944 stream->alignment = 4;
14945 break;
14946 case FOURCC_in24:
14947 _codec ("Raw 24-bit PCM audio");
14948 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
14949 * endian later */
14950 caps = gst_caps_new_simple ("audio/x-raw",
14951 "format", G_TYPE_STRING, "S24BE",
14952 "layout", G_TYPE_STRING, "interleaved", NULL);
14953 stream->alignment = 4;
14954 break;
14955 case FOURCC_in32:
14956 _codec ("Raw 32-bit PCM audio");
14957 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
14958 * endian later */
14959 caps = gst_caps_new_simple ("audio/x-raw",
14960 "format", G_TYPE_STRING, "S32BE",
14961 "layout", G_TYPE_STRING, "interleaved", NULL);
14962 stream->alignment = 4;
14963 break;
14964 case FOURCC_s16l:
14965 _codec ("Raw 16-bit PCM audio");
14966 caps = gst_caps_new_simple ("audio/x-raw",
14967 "format", G_TYPE_STRING, "S16LE",
14968 "layout", G_TYPE_STRING, "interleaved", NULL);
14969 stream->alignment = 2;
14970 break;
14971 case FOURCC_ulaw:
14972 _codec ("Mu-law audio");
14973 caps = gst_caps_new_empty_simple ("audio/x-mulaw");
14974 break;
14975 case FOURCC_alaw:
14976 _codec ("A-law audio");
14977 caps = gst_caps_new_empty_simple ("audio/x-alaw");
14978 break;
14979 case 0x0200736d:
14980 case 0x6d730002:
14981 _codec ("Microsoft ADPCM");
14982 /* Microsoft ADPCM-ACM code 2 */
14983 caps = gst_caps_new_simple ("audio/x-adpcm",
14984 "layout", G_TYPE_STRING, "microsoft", NULL);
14985 break;
14986 case 0x1100736d:
14987 case 0x6d730011:
14988 _codec ("DVI/IMA ADPCM");
14989 caps = gst_caps_new_simple ("audio/x-adpcm",
14990 "layout", G_TYPE_STRING, "dvi", NULL);
14991 break;
14992 case 0x1700736d:
14993 case 0x6d730017:
14994 _codec ("DVI/Intel IMA ADPCM");
14995 /* FIXME DVI/Intel IMA ADPCM/ACM code 17 */
14996 caps = gst_caps_new_simple ("audio/x-adpcm",
14997 "layout", G_TYPE_STRING, "quicktime", NULL);
14998 break;
14999 case 0x5500736d:
15000 case 0x6d730055:
15001 /* MPEG layer 3, CBR only (pre QT4.1) */
15002 case FOURCC__mp3:
15003 case FOURCC_mp3_:
15004 _codec ("MPEG-1 layer 3");
15005 /* MPEG layer 3, CBR & VBR (QT4.1 and later) */
15006 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 3,
15007 "mpegversion", G_TYPE_INT, 1, NULL);
15008 break;
15009 case GST_MAKE_FOURCC ('.', 'm', 'p', '2'):
15010 _codec ("MPEG-1 layer 2");
15011 /* MPEG layer 2 */
15012 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 2,
15013 "mpegversion", G_TYPE_INT, 1, NULL);
15014 break;
15015 case 0x20736d:
15016 case GST_MAKE_FOURCC ('e', 'c', '-', '3'):
15017 _codec ("EAC-3 audio");
15018 caps = gst_caps_new_simple ("audio/x-eac3",
15019 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
15020 entry->sampled = TRUE;
15021 break;
15022 case GST_MAKE_FOURCC ('s', 'a', 'c', '3'): // Nero Recode
15023 case FOURCC_ac_3:
15024 _codec ("AC-3 audio");
15025 caps = gst_caps_new_simple ("audio/x-ac3",
15026 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
15027 entry->sampled = TRUE;
15028 break;
15029 case GST_MAKE_FOURCC ('d', 't', 's', 'c'):
15030 case GST_MAKE_FOURCC ('D', 'T', 'S', ' '):
15031 _codec ("DTS audio");
15032 caps = gst_caps_new_simple ("audio/x-dts",
15033 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
15034 entry->sampled = TRUE;
15035 break;
15036 case GST_MAKE_FOURCC ('d', 't', 's', 'h'): // DTS-HD
15037 case GST_MAKE_FOURCC ('d', 't', 's', 'l'): // DTS-HD Lossless
15038 _codec ("DTS-HD audio");
15039 caps = gst_caps_new_simple ("audio/x-dts",
15040 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
15041 entry->sampled = TRUE;
15042 break;
15043 case FOURCC_MAC3:
15044 _codec ("MACE-3");
15045 caps = gst_caps_new_simple ("audio/x-mace",
15046 "maceversion", G_TYPE_INT, 3, NULL);
15047 break;
15048 case FOURCC_MAC6:
15049 _codec ("MACE-6");
15050 caps = gst_caps_new_simple ("audio/x-mace",
15051 "maceversion", G_TYPE_INT, 6, NULL);
15052 break;
15053 case GST_MAKE_FOURCC ('O', 'g', 'g', 'V'):
15054 /* ogg/vorbis */
15055 caps = gst_caps_new_empty_simple ("application/ogg");
15056 break;
15057 case GST_MAKE_FOURCC ('d', 'v', 'c', 'a'):
15058 _codec ("DV audio");
15059 caps = gst_caps_new_empty_simple ("audio/x-dv");
15060 break;
15061 case FOURCC_mp4a:
15062 _codec ("MPEG-4 AAC audio");
15063 caps = gst_caps_new_simple ("audio/mpeg",
15064 "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE,
15065 "stream-format", G_TYPE_STRING, "raw", NULL);
15066 break;
15067 case GST_MAKE_FOURCC ('Q', 'D', 'M', 'C'):
15068 _codec ("QDesign Music");
15069 caps = gst_caps_new_empty_simple ("audio/x-qdm");
15070 break;
15071 case FOURCC_QDM2:
15072 _codec ("QDesign Music v.2");
15073 /* FIXME: QDesign music version 2 (no constant) */
15074 if (FALSE && data) {
15075 caps = gst_caps_new_simple ("audio/x-qdm2",
15076 "framesize", G_TYPE_INT, QT_UINT32 (data + 52),
15077 "bitrate", G_TYPE_INT, QT_UINT32 (data + 40),
15078 "blocksize", G_TYPE_INT, QT_UINT32 (data + 44), NULL);
15079 } else {
15080 caps = gst_caps_new_empty_simple ("audio/x-qdm2");
15081 }
15082 break;
15083 case FOURCC_agsm:
15084 _codec ("GSM audio");
15085 caps = gst_caps_new_empty_simple ("audio/x-gsm");
15086 break;
15087 case FOURCC_samr:
15088 _codec ("AMR audio");
15089 caps = gst_caps_new_empty_simple ("audio/AMR");
15090 break;
15091 case FOURCC_sawb:
15092 _codec ("AMR-WB audio");
15093 caps = gst_caps_new_empty_simple ("audio/AMR-WB");
15094 break;
15095 case FOURCC_ima4:
15096 _codec ("Quicktime IMA ADPCM");
15097 caps = gst_caps_new_simple ("audio/x-adpcm",
15098 "layout", G_TYPE_STRING, "quicktime", NULL);
15099 break;
15100 case FOURCC_alac:
15101 _codec ("Apple lossless audio");
15102 caps = gst_caps_new_empty_simple ("audio/x-alac");
15103 break;
15104 case FOURCC_fLaC:
15105 _codec ("Free Lossless Audio Codec");
15106 caps = gst_caps_new_simple ("audio/x-flac",
15107 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
15108 break;
15109 case GST_MAKE_FOURCC ('Q', 'c', 'l', 'p'):
15110 _codec ("QualComm PureVoice");
15111 caps = gst_caps_from_string ("audio/qcelp");
15112 break;
15113 case FOURCC_wma_:
15114 case FOURCC_owma:
15115 _codec ("WMA");
15116 caps = gst_caps_new_empty_simple ("audio/x-wma");
15117 break;
15118 case FOURCC_opus:
15119 _codec ("Opus");
15120 caps = gst_caps_new_empty_simple ("audio/x-opus");
15121 break;
15122 case FOURCC_lpcm:
15123 {
15124 guint32 flags = 0;
15125 guint32 depth = 0;
15126 guint32 width = 0;
15127 GstAudioFormat format;
15128 enum
15129 {
15130 FLAG_IS_FLOAT = 0x1,
15131 FLAG_IS_BIG_ENDIAN = 0x2,
15132 FLAG_IS_SIGNED = 0x4,
15133 FLAG_IS_PACKED = 0x8,
15134 FLAG_IS_ALIGNED_HIGH = 0x10,
15135 FLAG_IS_NON_INTERLEAVED = 0x20
15136 };
15137 _codec ("Raw LPCM audio");
15138
15139 if (data && len >= 36) {
15140 depth = QT_UINT32 (data + 24);
15141 flags = QT_UINT32 (data + 28);
15142 width = QT_UINT32 (data + 32) * 8 / entry->n_channels;
15143 }
15144 if ((flags & FLAG_IS_FLOAT) == 0) {
15145 if (depth == 0)
15146 depth = 16;
15147 if (width == 0)
15148 width = 16;
15149 if ((flags & FLAG_IS_ALIGNED_HIGH))
15150 depth = width;
15151
15152 format = gst_audio_format_build_integer ((flags & FLAG_IS_SIGNED) ?
15153 TRUE : FALSE, (flags & FLAG_IS_BIG_ENDIAN) ?
15154 G_BIG_ENDIAN : G_LITTLE_ENDIAN, width, depth);
15155 caps = gst_caps_new_simple ("audio/x-raw",
15156 "format", G_TYPE_STRING,
15157 format !=
15158 GST_AUDIO_FORMAT_UNKNOWN ? gst_audio_format_to_string (format) :
15159 "UNKNOWN", "layout", G_TYPE_STRING,
15160 (flags & FLAG_IS_NON_INTERLEAVED) ? "non-interleaved" :
15161 "interleaved", NULL);
15162 stream->alignment = GST_ROUND_UP_8 (depth);
15163 stream->alignment = round_up_pow2 (stream->alignment);
15164 } else {
15165 if (width == 0)
15166 width = 32;
15167 if (width == 64) {
15168 if (flags & FLAG_IS_BIG_ENDIAN)
15169 format = GST_AUDIO_FORMAT_F64BE;
15170 else
15171 format = GST_AUDIO_FORMAT_F64LE;
15172 } else {
15173 if (flags & FLAG_IS_BIG_ENDIAN)
15174 format = GST_AUDIO_FORMAT_F32BE;
15175 else
15176 format = GST_AUDIO_FORMAT_F32LE;
15177 }
15178 caps = gst_caps_new_simple ("audio/x-raw",
15179 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
15180 "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
15181 "non-interleaved" : "interleaved", NULL);
15182 stream->alignment = width / 8;
15183 }
15184 break;
15185 }
15186 case GST_MAKE_FOURCC ('a', 'c', '-', '4'):
15187 {
15188 _codec ("AC4");
15189 caps = gst_caps_new_empty_simple ("audio/x-ac4");
15190 break;
15191 }
15192 case GST_MAKE_FOURCC ('q', 't', 'v', 'r'):
15193 /* ? */
15194 default:
15195 {
15196 caps = _get_unknown_codec_name ("audio", fourcc);
15197 break;
15198 }
15199 }
15200
15201 if (caps) {
15202 GstCaps *templ_caps =
15203 gst_static_pad_template_get_caps (&gst_qtdemux_audiosrc_template);
15204 GstCaps *intersection = gst_caps_intersect (caps, templ_caps);
15205 gst_caps_unref (caps);
15206 gst_caps_unref (templ_caps);
15207 caps = intersection;
15208 }
15209
15210 /* enable clipping for raw audio streams */
15211 s = gst_caps_get_structure (caps, 0);
15212 name = gst_structure_get_name (s);
15213 if (g_str_has_prefix (name, "audio/x-raw")) {
15214 stream->need_clip = TRUE;
15215 stream->min_buffer_size = 1024 * entry->bytes_per_frame;
15216 stream->max_buffer_size = 4096 * entry->bytes_per_frame;
15217 GST_DEBUG ("setting min/max buffer sizes to %d/%d", stream->min_buffer_size,
15218 stream->max_buffer_size);
15219 }
15220 return caps;
15221 }
15222
15223 static GstCaps *
15224 qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
15225 QtDemuxStreamStsdEntry * entry, guint32 fourcc,
15226 const guint8 * stsd_entry_data, gchar ** codec_name)
15227 {
15228 GstCaps *caps;
15229
15230 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
15231
15232 switch (fourcc) {
15233 case FOURCC_mp4s:
15234 _codec ("DVD subtitle");
15235 caps = gst_caps_new_empty_simple ("subpicture/x-dvd");
15236 stream->process_func = gst_qtdemux_process_buffer_dvd;
15237 break;
15238 case FOURCC_text:
15239 _codec ("Quicktime timed text");
15240 goto text;
15241 case FOURCC_tx3g:
15242 _codec ("3GPP timed text");
15243 text:
15244 caps = gst_caps_new_simple ("text/x-raw", "format", G_TYPE_STRING,
15245 "utf8", NULL);
15246 /* actual text piece needs to be extracted */
15247 stream->process_func = gst_qtdemux_process_buffer_text;
15248 break;
15249 case FOURCC_stpp:
15250 _codec ("XML subtitles");
15251 caps = gst_caps_new_empty_simple ("application/ttml+xml");
15252 break;
15253 case FOURCC_wvtt:
15254 {
15255 GstBuffer *buffer;
15256 const gchar *buf = "WEBVTT\n\n";
15257
15258 _codec ("WebVTT subtitles");
15259 caps = gst_caps_new_empty_simple ("application/x-subtitle-vtt");
15260 stream->process_func = gst_qtdemux_process_buffer_wvtt;
15261
15262 /* FIXME: Parse the vttC atom and get the entire WEBVTT header */
15263 buffer = gst_buffer_new_and_alloc (8);
15264 gst_buffer_fill (buffer, 0, buf, 8);
15265 stream->buffers = g_slist_append (stream->buffers, buffer);
15266
15267 break;
15268 }
15269 case FOURCC_c608:
15270 _codec ("CEA 608 Closed Caption");
15271 caps =
15272 gst_caps_new_simple ("closedcaption/x-cea-608", "format",
15273 G_TYPE_STRING, "s334-1a", NULL);
15274 stream->process_func = gst_qtdemux_process_buffer_clcp;
15275 stream->need_split = TRUE;
15276 break;
15277 case FOURCC_c708:
15278 _codec ("CEA 708 Closed Caption");
15279 caps =
15280 gst_caps_new_simple ("closedcaption/x-cea-708", "format",
15281 G_TYPE_STRING, "cdp", NULL);
15282 stream->process_func = gst_qtdemux_process_buffer_clcp;
15283 break;
15284
15285 default:
15286 {
15287 caps = _get_unknown_codec_name ("text", fourcc);
15288 break;
15289 }
15290 }
15291 return caps;
15292 }
15293
15294 static GstCaps *
15295 qtdemux_generic_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
15296 QtDemuxStreamStsdEntry * entry, guint32 fourcc,
15297 const guint8 * stsd_entry_data, gchar ** codec_name)
15298 {
15299 GstCaps *caps;
15300
15301 switch (fourcc) {
15302 case FOURCC_m1v:
15303 _codec ("MPEG 1 video");
15304 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
15305 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
15306 break;
15307 default:
15308 caps = NULL;
15309 break;
15310 }
15311 return caps;
15312 }
15313
15314 static void
15315 gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux,
15316 const gchar * system_id)
15317 {
15318 gint i;
15319
15320 if (!qtdemux->protection_system_ids)
15321 qtdemux->protection_system_ids =
15322 g_ptr_array_new_with_free_func ((GDestroyNotify) g_free);
15323 /* Check whether we already have an entry for this system ID. */
15324 for (i = 0; i < qtdemux->protection_system_ids->len; ++i) {
15325 const gchar *id = g_ptr_array_index (qtdemux->protection_system_ids, i);
15326 if (g_ascii_strcasecmp (system_id, id) == 0) {
15327 return;
15328 }
15329 }
15330 GST_DEBUG_OBJECT (qtdemux, "Adding cenc protection system ID %s", system_id);
15331 g_ptr_array_add (qtdemux->protection_system_ids, g_ascii_strdown (system_id,
15332 -1));
15333 }
15334